From 417f7b92b029f0df170ea8027014b57624863787 Mon Sep 17 00:00:00 2001 From: Son Date: Wed, 17 Nov 2021 17:02:31 +0100 Subject: [PATCH] make sure a deleted directory can't be recreated --- app/dashboard/views/directory.py | 60 ++++++++++++++++++------------- app/errors.py | 6 ++++ app/models.py | 11 +++++- tests/dashboard/test_directory.py | 58 ++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 26 deletions(-) create mode 100644 tests/dashboard/test_directory.py diff --git a/app/dashboard/views/directory.py b/app/dashboard/views/directory.py index 41d26b67..47c1589f 100644 --- a/app/dashboard/views/directory.py +++ b/app/dashboard/views/directory.py @@ -11,6 +11,7 @@ from app.config import ( ) from app.dashboard.base import dashboard_bp from app.db import Session +from app.errors import DirectoryInTrashError from app.models import Directory, Mailbox, DirectoryMailbox @@ -138,33 +139,42 @@ def directory(): "warning", ) else: - new_dir = Directory.create( - name=new_dir_name, user_id=current_user.id - ) - Session.commit() - mailbox_ids = request.form.getlist("mailbox_ids") - if mailbox_ids: - # check if mailbox is not tempered with - mailboxes = [] - for mailbox_id in mailbox_ids: - mailbox = Mailbox.get(mailbox_id) - if ( - not mailbox - or mailbox.user_id != current_user.id - or not mailbox.verified - ): - flash("Something went wrong, please retry", "warning") - return redirect(url_for("dashboard.directory")) - mailboxes.append(mailbox) - - for mailbox in mailboxes: - DirectoryMailbox.create( - directory_id=new_dir.id, mailbox_id=mailbox.id - ) - + try: + new_dir = Directory.create( + name=new_dir_name, user_id=current_user.id + ) + except DirectoryInTrashError: + flash( + f"{new_dir_name} has been used before and cannot be reused", + "error", + ) + else: Session.commit() + mailbox_ids = request.form.getlist("mailbox_ids") + if mailbox_ids: + # check if mailbox is not tempered with + mailboxes = [] + for mailbox_id in mailbox_ids: + mailbox = Mailbox.get(mailbox_id) + if ( + not mailbox + or mailbox.user_id != current_user.id + or not mailbox.verified + ): + flash( + "Something went wrong, please retry", "warning" + ) + return redirect(url_for("dashboard.directory")) + mailboxes.append(mailbox) - flash(f"Directory {new_dir.name} is created", "success") + for mailbox in mailboxes: + DirectoryMailbox.create( + directory_id=new_dir.id, mailbox_id=mailbox.id + ) + + Session.commit() + + flash(f"Directory {new_dir.name} is created", "success") return redirect(url_for("dashboard.directory")) diff --git a/app/errors.py b/app/errors.py index 15de010e..de22c865 100644 --- a/app/errors.py +++ b/app/errors.py @@ -2,3 +2,9 @@ class AliasInTrashError(Exception): """raised when alias is deleted before """ pass + + +class DirectoryInTrashError(Exception): + """raised when a directory is deleted before """ + + pass diff --git a/app/models.py b/app/models.py index 3f2558aa..f4c6f59c 100644 --- a/app/models.py +++ b/app/models.py @@ -32,7 +32,7 @@ from app.config import ( ALIAS_RANDOM_SUFFIX_LENGTH, ) from app.db import Session -from app.errors import AliasInTrashError +from app.errors import AliasInTrashError, DirectoryInTrashError from app.log import LOG from app.oauth_models import Scope from app.pw_models import PasswordOracle @@ -2123,6 +2123,14 @@ class Directory(Base, ModelMixin): def nb_alias(self): return Alias.filter_by(directory_id=self.id).count() + @classmethod + def create(cls, *args, **kwargs): + name = kwargs.get("name") + if DeletedDirectory.get_by(name=name): + raise DirectoryInTrashError + + return super(Directory, cls).create(*args, **kwargs) + @classmethod def delete(cls, obj_id): obj: Directory = cls.get(obj_id) @@ -2133,6 +2141,7 @@ class Directory(Base, ModelMixin): alias_utils.delete_alias(alias, user) + DeletedDirectory.create(name=obj.name) cls.filter(cls.id == obj_id).delete() Session.commit() diff --git a/tests/dashboard/test_directory.py b/tests/dashboard/test_directory.py new file mode 100644 index 00000000..153f5454 --- /dev/null +++ b/tests/dashboard/test_directory.py @@ -0,0 +1,58 @@ +from flask import url_for + +from app.models import Directory +from tests.utils import login + + +def test_create_directory(flask_client): + login(flask_client) + + r = flask_client.post( + url_for("dashboard.directory"), + data={"form-name": "create", "name": "test"}, + follow_redirects=True, + ) + + assert r.status_code == 200 + assert f"Directory test is created" in r.data.decode() + assert Directory.get_by(name="test") is not None + + +def test_delete_directory(flask_client): + """cannot add domain if user personal email uses this domain""" + user = login(flask_client) + directory = Directory.create(name="test", user_id=user.id, commit=True) + + r = flask_client.post( + url_for("dashboard.directory"), + data={"form-name": "delete", "dir-id": directory.id}, + follow_redirects=True, + ) + + assert r.status_code == 200 + assert f"Directory test has been deleted" in r.data.decode() + assert Directory.get_by(name="test") is None + + +def test_create_directory_in_trash(flask_client): + user = login(flask_client) + + directory = Directory.create(name="test", user_id=user.id, commit=True) + + # delete the directory + r = flask_client.post( + url_for("dashboard.directory"), + data={"form-name": "delete", "dir-id": directory.id}, + follow_redirects=True, + ) + assert Directory.get_by(name="test") is None + + # try to recreate the directory + r = flask_client.post( + url_for("dashboard.directory"), + data={"form-name": "create", "name": "test"}, + follow_redirects=True, + ) + + assert r.status_code == 200 + assert "test has been used before and cannot be reused" in r.data.decode()