diff --git a/app/models/profile.py b/app/models/profile.py index 11adefee..d77d5932 100644 --- a/app/models/profile.py +++ b/app/models/profile.py @@ -24,8 +24,18 @@ class Profile(models.Model): return cached v = self.used_quota() - cache.set(k, v, 300) # 2 minutes + cache.set(k, v, 1800) # 30 minutes return v + + def has_exceeded_quota_cached(self): + if not self.has_quota(): + return False + + q = self.used_quota_cached() + return q > self.quota + + def clear_used_quota_cache(self): + cache.delete(f'used_quota_{self.user.id}') @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): diff --git a/app/models/task.py b/app/models/task.py index 79fb1da5..4235011c 100644 --- a/app/models/task.py +++ b/app/models/task.py @@ -434,6 +434,7 @@ class Task(models.Model): else: logger.warning("Task {} doesn't have folder, will skip copying".format(self)) + self.project.owner.profile.clear_used_quota_cache() return task except Exception as e: logger.warning("Cannot duplicate task: {}".format(str(e))) @@ -1037,6 +1038,8 @@ class Task(models.Model): except FileNotFoundError as e: logger.warning(e) + self.project.owner.profile.clear_used_quota_cache() + plugin_signals.task_removed.send_robust(sender=self.__class__, task_id=task_id) def set_failure(self, error_message): @@ -1175,5 +1178,7 @@ class Task(models.Model): total_bytes += os.path.getsize(fp) self.size = (total_bytes / 1024 / 1024) if commit: self.save() + + self.project.owner.profile.clear_used_quota_cache() except Exception as e: logger.warn("Cannot update size for task {}: {}".format(self, str(e))) diff --git a/app/templates/app/dashboard.html b/app/templates/app/dashboard.html index 1abb2f92..b6b28015 100644 --- a/app/templates/app/dashboard.html +++ b/app/templates/app/dashboard.html @@ -1,5 +1,6 @@ {% extends "app/logged_in_base.html" %} {% load i18n %} +{% load settings %} {% block content %} {% load render_bundle from webpack_loader %} @@ -39,6 +40,15 @@

{% endif %} + {% if user.profile.has_exceeded_quota_cached %} + {% with total=user.profile.quota|storage_size used=user.profile.used_quota_cached|storage_size %} + {% quota_exceeded_grace_period as hours %} +
+ {% blocktrans %}The current storage quota is being exceeded ({{ used }} of {{ total }} used). The most recent tasks will be automatically deleted within {{ hours }} hours, until usage falls below {{ total }}.{% endblocktrans %} +
+ {% endwith %} + {% endif %} +
{% endif %} diff --git a/app/templates/app/logged_in_base.html b/app/templates/app/logged_in_base.html index 2920cdfb..3abe707c 100644 --- a/app/templates/app/logged_in_base.html +++ b/app/templates/app/logged_in_base.html @@ -20,8 +20,7 @@ {% if user.profile.has_quota %}
  • - {% with tot_quota=user.profile.quota %} - {% with used_quota=user.profile.used_quota_cached %} + {% with tot_quota=user.profile.quota used_quota=user.profile.used_quota_cached %} {% percentage used_quota tot_quota as perc_quota %} {% percentage used_quota tot_quota 100 as bar_width %} @@ -38,7 +37,7 @@ - {% endwith %}{% endwith %} + {% endwith %} {% endif %}
  • {% trans 'Logout' %} diff --git a/app/templatetags/settings.py b/app/templatetags/settings.py index ae6e2c7c..3ab491da 100644 --- a/app/templatetags/settings.py +++ b/app/templatetags/settings.py @@ -28,6 +28,10 @@ def percentage(num, den, maximum=None): perc = min(perc, maximum) return perc +@register.simple_tag +def quota_exceeded_grace_period(): + return settings.QUOTA_EXCEEDED_GRACE_PERIOD + @register.simple_tag def is_single_user_mode(): return settings.SINGLE_USER_MODE diff --git a/app/views/app.py b/app/views/app.py index 58dbc907..f37266e2 100644 --- a/app/views/app.py +++ b/app/views/app.py @@ -38,9 +38,10 @@ def dashboard(request): return redirect(settings.PROCESSING_NODES_ONBOARDING) no_tasks = Task.objects.filter(project__owner=request.user).count() == 0 - + no_projects = Project.objects.filter(owner=request.user).count() == 0 + # Create first project automatically - if Project.objects.count() == 0: + if no_projects and request.user.has_perm('app.add_project'): Project.objects.create(owner=request.user, name=_("First Project")) return render(request, 'app/dashboard.html', {'title': _('Dashboard'), diff --git a/webodm/settings.py b/webodm/settings.py index 66bf8561..896b27e9 100644 --- a/webodm/settings.py +++ b/webodm/settings.py @@ -395,6 +395,11 @@ USE_EXTERNAL_AUTH = True # TODO: change EXTERNAL_AUTH_ENDPOINT = "http://192.168.2.253:5000/r/auth/login" # TODO: make these env vars? +# Number of hours before tasks are automatically deleted +# from an account that is exceeding a disk quota +QUOTA_EXCEEDED_GRACE_PERIOD = 8 + + if TESTING or FLUSHING: CELERY_TASK_ALWAYS_EAGER = True