diff --git a/src/apps/api/tests/test_datasets.py b/src/apps/api/tests/test_datasets.py index 944981757..5071a5555 100644 --- a/src/apps/api/tests/test_datasets.py +++ b/src/apps/api/tests/test_datasets.py @@ -3,7 +3,7 @@ from rest_framework.test import APITestCase from datasets.models import Data from factories import UserFactory, DataFactory -from utils.data import pretty_bytes +from utils.data import pretty_bytes, gb_to_bytes faker = Factory.create() @@ -50,10 +50,19 @@ def test_dataset_api_checks_for_authentication(self): def test_dataset_api_check_quota(self): self.client.login(username='creator', password='creator') + # User quota is in GB quota = float(self.creator.quota) + # Convert to bytes to compute available space + quota = gb_to_bytes(quota) + # Used storage is in bytes storage_used = float(self.creator.get_used_storage_space()) + available_space = quota - storage_used - file_size = 1024 * 1024 * 1024 * 1024 + + # 1 GB = 1,000,000,000 Bytes + # 1 TB = 1,000 GB = 1,000,000,000,000 Bytes + # Using a big file size of 1 TB to run the test + file_size = 1000 * 1000 * 1000 * 1000 # Fake upload a very big dataset resp = self.client.post(reverse("data-list"), { @@ -68,7 +77,7 @@ def test_dataset_api_check_quota(self): assert resp.data["data_file"][0] == f'Insufficient space. Your available space is {pretty_bytes(available_space)}. The file size is {pretty_bytes(file_size)}. Please free up some space and try again. You can manage your files in the Resources page.' # Fake upload a small file - file_size = available_space - 1024 + file_size = available_space - 1000 resp = self.client.post(reverse("data-list"), { 'name': 'new-file-test', 'type': Data.COMPETITION_BUNDLE, diff --git a/src/apps/api/views/datasets.py b/src/apps/api/views/datasets.py index c3c48c6ef..dade6bff9 100644 --- a/src/apps/api/views/datasets.py +++ b/src/apps/api/views/datasets.py @@ -14,7 +14,7 @@ from api.serializers import datasets as serializers from datasets.models import Data, DataGroup from competitions.models import CompetitionCreationTaskStatus -from utils.data import make_url_sassy, pretty_bytes +from utils.data import make_url_sassy, pretty_bytes, gb_to_bytes class DataViewSet(ModelViewSet): @@ -90,6 +90,7 @@ def create(self, request, *args, **kwargs): # Check User quota storage_used = float(request.user.get_used_storage_space()) quota = float(request.user.quota) + quota = gb_to_bytes(quota) file_size = float(request.data['file_size']) if storage_used + file_size > quota: available_space = pretty_bytes(quota - storage_used) diff --git a/src/apps/api/views/tasks.py b/src/apps/api/views/tasks.py index 16479a701..31a3b027c 100644 --- a/src/apps/api/views/tasks.py +++ b/src/apps/api/views/tasks.py @@ -19,7 +19,7 @@ from profiles.models import User from tasks.models import Task from datasets.models import Data -from utils.data import pretty_bytes +from utils.data import pretty_bytes, gb_to_bytes # TODO:// TaskViewSimple uses simple serializer from tasks, which exists purely for the use of Select2 on phase modal @@ -210,7 +210,10 @@ def upload_task(self, request): # Check if user has enough quota to proceed storage_used = float(request.user.get_used_storage_space()) + # User quota is in GB quota = float(request.user.quota) + # Convert user quota to bytes + quota = gb_to_bytes(quota) file_size = uploaded_file.size if storage_used + file_size > quota: file_size = pretty_bytes(file_size) diff --git a/src/apps/profiles/models.py b/src/apps/profiles/models.py index d66be9804..fe0252ec7 100644 --- a/src/apps/profiles/models.py +++ b/src/apps/profiles/models.py @@ -154,6 +154,10 @@ def get_chahub_is_valid(self): return True def get_used_storage_space(self, binary=False): + """ + Function to calculate storage used by a user + Returns in bytes + """ factor = 1024 if binary else 1000 from datasets.models import Data diff --git a/src/apps/profiles/quota.py b/src/apps/profiles/quota.py new file mode 100644 index 000000000..3a2e06571 --- /dev/null +++ b/src/apps/profiles/quota.py @@ -0,0 +1,17 @@ +import logging +from .models import User + +logger = logging.getLogger() + + +def reset_all_users_quota_to_gb(): + """ + Converts user quota from bytes to GB if it's stored in bytes. + Skips users whose quota is already in GB. + """ + users = User.objects.all() + for user in users: + # If quota is in bytes (greater than 1 GB in bytes) + if user.quota > 1000 * 1000 * 1000: + user.quota = user.quota / 1e9 # Convert to GB + user.save() diff --git a/src/settings/base.py b/src/settings/base.py index a8e297519..7fc4ab41b 100644 --- a/src/settings/base.py +++ b/src/settings/base.py @@ -420,7 +420,7 @@ GS_BUCKET_NAME = GS_PUBLIC_BUCKET_NAME # Default bucket set to public bucket # Quota -DEFAULT_USER_QUOTA = 15 * 1000 * 1000 * 1000 # 15GB +DEFAULT_USER_QUOTA = 15 # 15GB # ============================================================================= diff --git a/src/static/riot/quota_management.tag b/src/static/riot/quota_management.tag index b10da25f4..fb3dca8ad 100644 --- a/src/static/riot/quota_management.tag +++ b/src/static/riot/quota_management.tag @@ -7,7 +7,7 @@
- Quota: {formatSize(storage_used)} / {formatSize(quota)} + Quota: {formatSize(storage_used)} / {quota} GB
diff --git a/src/utils/data.py b/src/utils/data.py index b321d0a6a..bb344c47e 100644 --- a/src/utils/data.py +++ b/src/utils/data.py @@ -131,3 +131,8 @@ def pretty_bytes(bytes, decimal_places=1, suffix="B", binary=False): bytes /= factor return f"{bytes:.{decimal_places}f}{units[-1]}{suffix}" + + +def gb_to_bytes(gb, binary=False): + factor = 1024**3 if binary else 1000**3 + return gb * factor