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