diff --git a/app/dashboard/views/directory.py b/app/dashboard/views/directory.py index 47c1589f..cb130f5a 100644 --- a/app/dashboard/views/directory.py +++ b/app/dashboard/views/directory.py @@ -114,7 +114,7 @@ def directory(): flash("Only premium plan can add directory", "warning") return redirect(url_for("dashboard.directory")) - if current_user.nb_directory() >= MAX_NB_DIRECTORY: + if current_user.directory_quota <= 0: flash( f"You cannot have more than {MAX_NB_DIRECTORY} directories", "warning", diff --git a/app/dashboard/views/subdomain.py b/app/dashboard/views/subdomain.py index 54e97a06..7a926ae8 100644 --- a/app/dashboard/views/subdomain.py +++ b/app/dashboard/views/subdomain.py @@ -28,7 +28,7 @@ def subdomain_route(): flash("Only premium plan can add subdomain", "warning") return redirect(request.url) - if len(subdomains) >= MAX_NB_SUBDOMAIN: + if current_user.subdomain_quota <= 0: flash( f"You can't create more than {MAX_NB_SUBDOMAIN} subdomains", "error" ) @@ -88,5 +88,4 @@ def subdomain_route(): sl_domains=sl_domains, errors=errors, subdomains=subdomains, - can_create=len(subdomains) < MAX_NB_SUBDOMAIN, ) diff --git a/app/models.py b/app/models.py index e081a707..46ad2240 100644 --- a/app/models.py +++ b/app/models.py @@ -2016,6 +2016,11 @@ class CustomDomain(Base, ModelMixin): domain.ownership_txt_token = random_string(30) Session.commit() + if domain.is_sl_subdomain: + user = domain.user + user._subdomain_quota -= 1 + Session.flush() + return domain @classmethod @@ -2024,6 +2029,10 @@ class CustomDomain(Base, ModelMixin): if obj.is_sl_subdomain: DeletedSubdomain.create(domain=obj.domain) + user = obj.user + user._subdomain_quota -= 1 + Session.flush() + return super(CustomDomain, cls).delete(obj_id) @property @@ -2166,7 +2175,14 @@ class Directory(Base, ModelMixin): if DeletedDirectory.get_by(name=name): raise DirectoryInTrashError - return super(Directory, cls).create(*args, **kwargs) + directory = super(Directory, cls).create(*args, **kwargs) + Session.flush() + + user = directory.user + user._directory_quota -= 1 + + Session.flush() + return directory @classmethod def delete(cls, obj_id): @@ -2180,6 +2196,10 @@ class Directory(Base, ModelMixin): DeletedDirectory.create(name=obj.name) cls.filter(cls.id == obj_id).delete() + + user = obj.user + user._directory_quota -= 1 + Session.commit() def __repr__(self): diff --git a/templates/dashboard/directory.html b/templates/dashboard/directory.html index 34860a95..21e78da2 100644 --- a/templates/dashboard/directory.html +++ b/templates/dashboard/directory.html @@ -139,7 +139,7 @@ {% endfor %} -
+
@@ -148,7 +148,10 @@ {{ new_dir_form.csrf_token }} -

New Directory

+

New Directory

+
+ You can create up to {{ current_user.directory_quota }} directories. +
{{ new_dir_form.name(class="form-control", placeholder="my-directory", pattern="[0-9a-z-_]{3,}", @@ -195,7 +198,8 @@ let directory = $(this).parent().find(".dir-name").val(); let that = $(this); - let message = `All aliases associated with ${directory} directory will also be deleted, ` + + let message = `All aliases associated with ${directory} directory will also be deleted. ` + + `Your directory quota will be {{ current_user.directory_quota - 1 }} after the deletion, ` + " please confirm."; bootbox.confirm({ diff --git a/templates/dashboard/domain_detail/info.html b/templates/dashboard/domain_detail/info.html index 5d860010..c92bcdca 100644 --- a/templates/dashboard/domain_detail/info.html +++ b/templates/dashboard/domain_detail/info.html @@ -128,11 +128,24 @@

-

Delete Domain

+

+ {% if custom_domain.is_sl_subdomain %} + Delete Subdomain + {% else %} + Delete Domain + {% endif %} +

+
This operation is irreversible. All aliases associated with this domain will be deleted. + {% if custom_domain.is_sl_subdomain %} +
+ After deletion, your subdomain quota will be {{ current_user.subdomain_quota - 1 }}. + {% endif %}
+ +
Delete domain diff --git a/templates/dashboard/subdomain.html b/templates/dashboard/subdomain.html index e72f1f21..9238cab6 100644 --- a/templates/dashboard/subdomain.html +++ b/templates/dashboard/subdomain.html @@ -29,7 +29,8 @@ -
+
-

New Subdomain

+

New Subdomain

+
+ You can create up to {{ current_user.subdomain_quota }} subdomains. +
diff --git a/tests/dashboard/test_directory.py b/tests/dashboard/test_directory.py index 153f5454..15aeb829 100644 --- a/tests/dashboard/test_directory.py +++ b/tests/dashboard/test_directory.py @@ -1,5 +1,6 @@ from flask import url_for +from app.config import MAX_NB_DIRECTORY from app.models import Directory from tests.utils import login @@ -56,3 +57,21 @@ def test_create_directory_in_trash(flask_client): assert r.status_code == 200 assert "test has been used before and cannot be reused" in r.data.decode() + + +def test_create_directory_out_of_quota(flask_client): + user = login(flask_client) + + for i in range(MAX_NB_DIRECTORY): + Directory.create(name=f"test{i}", user_id=user.id, commit=True) + + assert Directory.count() == MAX_NB_DIRECTORY + + flask_client.post( + url_for("dashboard.directory"), + data={"form-name": "create", "name": "test"}, + follow_redirects=True, + ) + + # no new directory is created + assert Directory.count() == MAX_NB_DIRECTORY diff --git a/tests/dashboard/test_subdomain.py b/tests/dashboard/test_subdomain.py index 4ed253fe..aa10e237 100644 --- a/tests/dashboard/test_subdomain.py +++ b/tests/dashboard/test_subdomain.py @@ -1,5 +1,6 @@ from flask import url_for +from app.config import MAX_NB_SUBDOMAIN from app.db import Session from app.models import SLDomain, CustomDomain, Job from tests.utils import login @@ -81,3 +82,27 @@ def test_create_subdomain_in_trash(flask_client): f"test.{sl_domain.domain} has been used before and cannot be reused" in r.data.decode() ) + + +def test_create_subdomain_out_of_quota(flask_client): + user = login(flask_client) + sl_domain = setup_sl_domain() + + for i in range(MAX_NB_SUBDOMAIN): + CustomDomain.create( + domain=f"test{i}.{sl_domain.domain}", + user_id=user.id, + is_sl_subdomain=True, + commit=True, + ) + + assert CustomDomain.count() == MAX_NB_SUBDOMAIN + + r = flask_client.post( + url_for("dashboard.subdomain_route"), + data={"form-name": "create", "subdomain": "test", "domain": sl_domain.domain}, + follow_redirects=True, + ) + + # no new subdomain is created + assert CustomDomain.count() == MAX_NB_SUBDOMAIN