mirror of
https://github.com/simple-login/app.git
synced 2024-09-20 15:05:59 +08:00
reduce subdomain/directory quota when user create/delete subdomain/directory
This commit is contained in:
parent
85c6e791bc
commit
38ecb227b0
|
@ -114,7 +114,7 @@ def directory():
|
||||||
flash("Only premium plan can add directory", "warning")
|
flash("Only premium plan can add directory", "warning")
|
||||||
return redirect(url_for("dashboard.directory"))
|
return redirect(url_for("dashboard.directory"))
|
||||||
|
|
||||||
if current_user.nb_directory() >= MAX_NB_DIRECTORY:
|
if current_user.directory_quota <= 0:
|
||||||
flash(
|
flash(
|
||||||
f"You cannot have more than {MAX_NB_DIRECTORY} directories",
|
f"You cannot have more than {MAX_NB_DIRECTORY} directories",
|
||||||
"warning",
|
"warning",
|
||||||
|
|
|
@ -28,7 +28,7 @@ def subdomain_route():
|
||||||
flash("Only premium plan can add subdomain", "warning")
|
flash("Only premium plan can add subdomain", "warning")
|
||||||
return redirect(request.url)
|
return redirect(request.url)
|
||||||
|
|
||||||
if len(subdomains) >= MAX_NB_SUBDOMAIN:
|
if current_user.subdomain_quota <= 0:
|
||||||
flash(
|
flash(
|
||||||
f"You can't create more than {MAX_NB_SUBDOMAIN} subdomains", "error"
|
f"You can't create more than {MAX_NB_SUBDOMAIN} subdomains", "error"
|
||||||
)
|
)
|
||||||
|
@ -88,5 +88,4 @@ def subdomain_route():
|
||||||
sl_domains=sl_domains,
|
sl_domains=sl_domains,
|
||||||
errors=errors,
|
errors=errors,
|
||||||
subdomains=subdomains,
|
subdomains=subdomains,
|
||||||
can_create=len(subdomains) < MAX_NB_SUBDOMAIN,
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -2016,6 +2016,11 @@ class CustomDomain(Base, ModelMixin):
|
||||||
domain.ownership_txt_token = random_string(30)
|
domain.ownership_txt_token = random_string(30)
|
||||||
Session.commit()
|
Session.commit()
|
||||||
|
|
||||||
|
if domain.is_sl_subdomain:
|
||||||
|
user = domain.user
|
||||||
|
user._subdomain_quota -= 1
|
||||||
|
Session.flush()
|
||||||
|
|
||||||
return domain
|
return domain
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -2024,6 +2029,10 @@ class CustomDomain(Base, ModelMixin):
|
||||||
if obj.is_sl_subdomain:
|
if obj.is_sl_subdomain:
|
||||||
DeletedSubdomain.create(domain=obj.domain)
|
DeletedSubdomain.create(domain=obj.domain)
|
||||||
|
|
||||||
|
user = obj.user
|
||||||
|
user._subdomain_quota -= 1
|
||||||
|
Session.flush()
|
||||||
|
|
||||||
return super(CustomDomain, cls).delete(obj_id)
|
return super(CustomDomain, cls).delete(obj_id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -2166,7 +2175,14 @@ class Directory(Base, ModelMixin):
|
||||||
if DeletedDirectory.get_by(name=name):
|
if DeletedDirectory.get_by(name=name):
|
||||||
raise DirectoryInTrashError
|
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
|
@classmethod
|
||||||
def delete(cls, obj_id):
|
def delete(cls, obj_id):
|
||||||
|
@ -2180,6 +2196,10 @@ class Directory(Base, ModelMixin):
|
||||||
|
|
||||||
DeletedDirectory.create(name=obj.name)
|
DeletedDirectory.create(name=obj.name)
|
||||||
cls.filter(cls.id == obj_id).delete()
|
cls.filter(cls.id == obj_id).delete()
|
||||||
|
|
||||||
|
user = obj.user
|
||||||
|
user._directory_quota -= 1
|
||||||
|
|
||||||
Session.commit()
|
Session.commit()
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
|
@ -139,7 +139,7 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row">
|
<div class="row {% if current_user.directory_quota <= 0 %} disabled-content {% endif %}">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
@ -148,7 +148,10 @@
|
||||||
{{ new_dir_form.csrf_token }}
|
{{ new_dir_form.csrf_token }}
|
||||||
<input type="hidden" name="form-name" value="create">
|
<input type="hidden" name="form-name" value="create">
|
||||||
|
|
||||||
<h2 class="h4">New Directory</h2>
|
<h2 class="h4 mb-1">New Directory</h2>
|
||||||
|
<div class="small-text mb-4">
|
||||||
|
You can create up to {{ current_user.directory_quota }} directories.
|
||||||
|
</div>
|
||||||
|
|
||||||
{{ new_dir_form.name(class="form-control", placeholder="my-directory",
|
{{ new_dir_form.name(class="form-control", placeholder="my-directory",
|
||||||
pattern="[0-9a-z-_]{3,}",
|
pattern="[0-9a-z-_]{3,}",
|
||||||
|
@ -195,7 +198,8 @@
|
||||||
let directory = $(this).parent().find(".dir-name").val();
|
let directory = $(this).parent().find(".dir-name").val();
|
||||||
|
|
||||||
let that = $(this);
|
let that = $(this);
|
||||||
let message = `All aliases associated with <b>${directory}</b> directory will also be deleted, ` +
|
let message = `All aliases associated with <b>${directory}</b> directory will also be deleted. ` +
|
||||||
|
`Your directory quota will be {{ current_user.directory_quota - 1 }} after the deletion, ` +
|
||||||
" please confirm.";
|
" please confirm.";
|
||||||
|
|
||||||
bootbox.confirm({
|
bootbox.confirm({
|
||||||
|
|
|
@ -128,11 +128,24 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
<h3 class="mb-1">Delete Domain</h3>
|
<h3 class="mb-1">
|
||||||
|
{% if custom_domain.is_sl_subdomain %}
|
||||||
|
Delete Subdomain
|
||||||
|
{% else %}
|
||||||
|
Delete Domain
|
||||||
|
{% endif %}
|
||||||
|
</h3>
|
||||||
|
|
||||||
<div class="mb-3">This operation is <b>irreversible</b>.
|
<div class="mb-3">This operation is <b>irreversible</b>.
|
||||||
All aliases associated with this domain will be deleted.
|
All aliases associated with this domain will be deleted.
|
||||||
|
{% if custom_domain.is_sl_subdomain %}
|
||||||
|
<br>
|
||||||
|
After deletion, your subdomain quota will be {{ current_user.subdomain_quota - 1 }}.
|
||||||
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<input type="hidden" name="form-name" value="delete">
|
<input type="hidden" name="form-name" value="delete">
|
||||||
<span class="delete-custom-domain btn btn-danger">Delete domain</span>
|
<span class="delete-custom-domain btn btn-danger">Delete domain</span>
|
||||||
|
|
|
@ -29,7 +29,8 @@
|
||||||
|
|
||||||
<div class="alert alert-primary collapse {% if not subdomains %} show {% endif %}" id="howtouse" role="alert">
|
<div class="alert alert-primary collapse {% if not subdomains %} show {% endif %}" id="howtouse" role="alert">
|
||||||
You can use subdomain to quickly create email aliases without opening SimpleLogin app. <br>
|
You can use subdomain to quickly create email aliases without opening SimpleLogin app. <br>
|
||||||
Handy when you need to quickly give out an email address, for example on a phone call, in a meeting or just anywhere you want. <br>
|
Handy when you need to quickly give out an email address, for example on a phone call, in a meeting or just
|
||||||
|
anywhere you want. <br>
|
||||||
After choosing a subdomain, simply use <b>anything@my-subdomain.simplelogin.co</b>
|
After choosing a subdomain, simply use <b>anything@my-subdomain.simplelogin.co</b>
|
||||||
next time you need an alias:
|
next time you need an alias:
|
||||||
it'll be <b>automatically created</b> the first time it receives an email. <br>
|
it'll be <b>automatically created</b> the first time it receives an email. <br>
|
||||||
|
@ -61,12 +62,15 @@
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="row {% if not can_create %} disabled-content {% endif %}" id="new-subdomain" >
|
<div class="row {% if current_user.subdomain_quota <= 0 %} disabled-content {% endif %}" id="new-subdomain">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
|
|
||||||
<h2 class="h4">New Subdomain</h2>
|
<h2 class="h4 mb-1">New Subdomain</h2>
|
||||||
|
<div class="small-text mb-4">
|
||||||
|
You can create up to {{ current_user.subdomain_quota }} subdomains.
|
||||||
|
</div>
|
||||||
|
|
||||||
<form method="post" class="mt-2" data-parsley-validate>
|
<form method="post" class="mt-2" data-parsley-validate>
|
||||||
<input type="hidden" name="form-name" value="create">
|
<input type="hidden" name="form-name" value="create">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
|
||||||
|
from app.config import MAX_NB_DIRECTORY
|
||||||
from app.models import Directory
|
from app.models import Directory
|
||||||
from tests.utils import login
|
from tests.utils import login
|
||||||
|
|
||||||
|
@ -56,3 +57,21 @@ def test_create_directory_in_trash(flask_client):
|
||||||
|
|
||||||
assert r.status_code == 200
|
assert r.status_code == 200
|
||||||
assert "test has been used before and cannot be reused" in r.data.decode()
|
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
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
|
||||||
|
from app.config import MAX_NB_SUBDOMAIN
|
||||||
from app.db import Session
|
from app.db import Session
|
||||||
from app.models import SLDomain, CustomDomain, Job
|
from app.models import SLDomain, CustomDomain, Job
|
||||||
from tests.utils import login
|
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"
|
f"test.{sl_domain.domain} has been used before and cannot be reused"
|
||||||
in r.data.decode()
|
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
|
||||||
|
|
Loading…
Reference in a new issue