From 42f1a6756347ccd902e5dfe7a632067bb1b37d6b Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Thu, 30 Jun 2022 12:29:47 +0200
Subject: [PATCH 01/12] add column active to motd table
---
dds_web/api/superadmin_only.py | 45 +++++++++++++++++--
dds_web/database/models.py | 3 +-
dds_web/templates/base.html | 4 +-
dds_web/utils.py | 4 +-
.../908382be548a_add_column_active_to_motd.py | 26 +++++++++++
5 files changed, 74 insertions(+), 8 deletions(-)
create mode 100644 migrations/versions/908382be548a_add_column_active_to_motd.py
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index ccb6cad33..e9da0f6d1 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -81,7 +81,7 @@ def post(self):
raise ddserr.DDSArgumentError(message="No MOTD specified.")
flask.current_app.logger.debug(motd)
- new_motd = models.MOTD(message=motd, date_created=curr_date)
+ new_motd = models.MOTD(message=motd)
db.session.add(new_motd)
db.session.commit()
@@ -89,9 +89,46 @@ def post(self):
@handle_db_error
def get(self):
- """Get the latest MOTD from database."""
- motd = utils.get_latest_motd()
- return {"message": motd}
+ """Return list of all active MOTDs to super admin."""
+ active_motds = models.MOTD.query.filter_by(active=True).all()
+ motd_info = [
+ {
+ "MOTD ID": m.id,
+ "Message": m.message,
+ "Created": m.date_created,
+ }
+ for m in active_motds
+ ]
+
+ return {
+ "motds": motd_info,
+ "keys": [
+ "MOTD ID",
+ "Message",
+ "Created",
+ ],
+ }
+
+ @auth.login_required(role=["Super Admin"])
+ @logging_bind_request
+ @json_required
+ @handle_db_error
+ def put(self):
+ """Deactivate MOTDs."""
+
+ json_input = flask.request.json
+ motd_id = json_input.get("motd_id")
+ if not motd_id:
+ raise ddserr.DDSArgumentError(message="No MOTD for deactivation specified.")
+
+ motd_to_deactivate = models.MOTD.query.filter_by(id=motd_id).first()
+ if motd_to_deactivate.active == True:
+ motd_to_deactivate.active = 0
+ db.session.commit()
+
+ return {"message": "The MOTD was successfully deactivated the database."}
+ else:
+ raise ddserr.DDSArgumentError(message=f"MOTD with id {motd_id} is not active.")
class FindUser(flask_restful.Resource):
diff --git a/dds_web/database/models.py b/dds_web/database/models.py
index a0f86026a..92f458303 100644
--- a/dds_web/database/models.py
+++ b/dds_web/database/models.py
@@ -987,7 +987,8 @@ class MOTD(db.Model):
# Columns
id = db.Column(db.Integer, primary_key=True, autoincrement=True)
message = db.Column(db.Text, nullable=False, default=None)
- date_created = db.Column(db.DateTime(), nullable=False, default=None)
+ date_created = db.Column(db.DateTime(), nullable=False, default=dds_web.utils.current_time())
+ active = db.Column(db.Boolean, nullable=False, default=True)
class Usage(db.Model):
diff --git a/dds_web/templates/base.html b/dds_web/templates/base.html
index f59f194fa..370901d76 100644
--- a/dds_web/templates/base.html
+++ b/dds_web/templates/base.html
@@ -21,7 +21,9 @@
{% if g.motd %}
Important Information
- {{ g.motd }}
+ {% for message in g.motd %}
+
{{ message.date_created.strftime("%Y-%m-%d %H:%M") }} - {{ message.message }}
+ {% endfor %}
{% endif %}
diff --git a/dds_web/utils.py b/dds_web/utils.py
index 0b8284d32..80c66355d 100644
--- a/dds_web/utils.py
+++ b/dds_web/utils.py
@@ -438,5 +438,5 @@ def bucket_is_valid(bucket_name):
def get_latest_motd():
"""Return latest MOTD."""
- motd_object = models.MOTD.query.order_by(models.MOTD.date_created.desc()).first()
- return motd_object.message if motd_object else ""
+ motd_object = models.MOTD.query.filter_by(active=True).order_by(models.MOTD.date_created.desc()).all()
+ return motd_object if motd_object else ""
diff --git a/migrations/versions/908382be548a_add_column_active_to_motd.py b/migrations/versions/908382be548a_add_column_active_to_motd.py
new file mode 100644
index 000000000..b70a6fdb0
--- /dev/null
+++ b/migrations/versions/908382be548a_add_column_active_to_motd.py
@@ -0,0 +1,26 @@
+"""add_column_active_to_motd
+Revision ID: 908382be548a
+Revises: cd1903e5f2b0
+Create Date: 2022-06-13 12:34:34.981373
+"""
+from alembic import op
+import sqlalchemy as sa
+from sqlalchemy.dialects import mysql
+
+# revision identifiers, used by Alembic.
+revision = "908382be548a"
+down_revision = "cd1903e5f2b0"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.add_column("motd", sa.Column("active", sa.Boolean(), nullable=False))
+ # ### end Alembic commands ###
+
+
+def downgrade():
+ # ### commands auto generated by Alembic - please adjust! ###
+ op.drop_column("motd", "active")
+ # ### end Alembic commands ###
\ No newline at end of file
From 0cd40e8083b4620b23c4f1516634221afe9d5a23 Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Thu, 30 Jun 2022 14:30:26 +0200
Subject: [PATCH 02/12] format the date
---
dds_web/api/superadmin_only.py | 35 ++++++++++++++++++----------------
1 file changed, 19 insertions(+), 16 deletions(-)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index e9da0f6d1..74c82b6ae 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -91,23 +91,26 @@ def post(self):
def get(self):
"""Return list of all active MOTDs to super admin."""
active_motds = models.MOTD.query.filter_by(active=True).all()
- motd_info = [
- {
- "MOTD ID": m.id,
- "Message": m.message,
- "Created": m.date_created,
+ if active_motds:
+ motd_info = [
+ {
+ "MOTD ID": m.id,
+ "Message": m.message,
+ "Created": m.date_created.strftime("%Y-%m-%d %H:%M"),
+ }
+ for m in active_motds
+ ]
+
+ return {
+ "motds": motd_info,
+ "keys": [
+ "MOTD ID",
+ "Message",
+ "Created",
+ ],
}
- for m in active_motds
- ]
-
- return {
- "motds": motd_info,
- "keys": [
- "MOTD ID",
- "Message",
- "Created",
- ],
- }
+ else:
+ return ""
@auth.login_required(role=["Super Admin"])
@logging_bind_request
From 0ad35e67bcb654a454d3a4314b6f0178484c8f51 Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Thu, 30 Jun 2022 15:54:04 +0200
Subject: [PATCH 03/12] black
---
dds_web/utils.py | 4 +++-
migrations/versions/908382be548a_add_column_active_to_motd.py | 2 +-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dds_web/utils.py b/dds_web/utils.py
index 80c66355d..7dfad1f76 100644
--- a/dds_web/utils.py
+++ b/dds_web/utils.py
@@ -438,5 +438,7 @@ def bucket_is_valid(bucket_name):
def get_latest_motd():
"""Return latest MOTD."""
- motd_object = models.MOTD.query.filter_by(active=True).order_by(models.MOTD.date_created.desc()).all()
+ motd_object = (
+ models.MOTD.query.filter_by(active=True).order_by(models.MOTD.date_created.desc()).all()
+ )
return motd_object if motd_object else ""
diff --git a/migrations/versions/908382be548a_add_column_active_to_motd.py b/migrations/versions/908382be548a_add_column_active_to_motd.py
index b70a6fdb0..dd0b797f3 100644
--- a/migrations/versions/908382be548a_add_column_active_to_motd.py
+++ b/migrations/versions/908382be548a_add_column_active_to_motd.py
@@ -23,4 +23,4 @@ def upgrade():
def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.drop_column("motd", "active")
- # ### end Alembic commands ###
\ No newline at end of file
+ # ### end Alembic commands ###
From 604701e99c0d3ac5f9e3d2bba816e5eb306251ef Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Fri, 1 Jul 2022 12:06:49 +0200
Subject: [PATCH 04/12] fix the message for no active motds
---
dds_web/api/superadmin_only.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index 74c82b6ae..b7695e2a2 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -110,7 +110,7 @@ def get(self):
],
}
else:
- return ""
+ return {"message": "There are no active MOTDs."}
@auth.login_required(role=["Super Admin"])
@logging_bind_request
From 5f665794f67a3d69de36e2d20d15ef95e45cdaa4 Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Mon, 4 Jul 2022 09:19:52 +0200
Subject: [PATCH 05/12] typo and fixed tests
---
dds_web/api/superadmin_only.py | 2 +-
tests/test_superadmin_only.py | 14 +++++++++++---
tests/test_utils.py | 18 ------------------
3 files changed, 12 insertions(+), 22 deletions(-)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index b7695e2a2..00865e892 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -129,7 +129,7 @@ def put(self):
motd_to_deactivate.active = 0
db.session.commit()
- return {"message": "The MOTD was successfully deactivated the database."}
+ return {"message": "The MOTD was successfully deactivated in the database."}
else:
raise ddserr.DDSArgumentError(message=f"MOTD with id {motd_id} is not active.")
diff --git a/tests/test_superadmin_only.py b/tests/test_superadmin_only.py
index afad2faf0..bab8eba65 100644
--- a/tests/test_superadmin_only.py
+++ b/tests/test_superadmin_only.py
@@ -126,7 +126,7 @@ def test_get_motd_no_message(client):
"""Get latest MOTD from database."""
response = client.get(tests.DDSEndpoint.MOTD, headers={"X-CLI-Version": "0.0.0"})
assert response.status_code == http.HTTPStatus.OK
- assert not response.json.get("message")
+ assert "There are no active MOTDs." in response.json.get("message")
def test_get_motd(client):
@@ -140,7 +140,8 @@ def test_get_motd(client):
# Get first message
response1 = client.get(tests.DDSEndpoint.MOTD, headers={"X-CLI-Version": "0.0.0"})
assert response1.status_code == http.HTTPStatus.OK
- assert "test" in response1.json.get("message")
+ assert isinstance(response1.json.get("motds"), list)
+ assert "test" in response1.json.get("motds")[0]["Message"]
time.sleep(5)
@@ -154,7 +155,14 @@ def test_get_motd(client):
# Check that new message is displayed
response3 = client.get(tests.DDSEndpoint.MOTD, headers={"X-CLI-Version": "0.0.0"})
assert response3.status_code == http.HTTPStatus.OK
- assert "something else" in response3.json.get("message")
+ assert "something else" in response3.json.get("motds")[1]["Message"]
+
+ # Deactivate message
+ response4 = client.put(tests.DDSEndpoint.MOTD, headers=token, json={"motd_id": 1})
+ assert response4.status_code == http.HTTPStatus.OK
+ assert "The MOTD was successfully deactivated in the database." in response4.json.get("message")
+ # assert isinstance(response4.json.get("motds"), list)
+ # assert len(response4.json.get("motds")) == 1
# FindUser
diff --git a/tests/test_utils.py b/tests/test_utils.py
index dadaf391c..36cad2940 100644
--- a/tests/test_utils.py
+++ b/tests/test_utils.py
@@ -774,21 +774,3 @@ def test_bucket_is_valid_ok():
valid, message = utils.bucket_is_valid(bucket_name="something-.")
assert valid
assert message == ""
-
-
-# get_latest_motd
-
-
-def test_get_latest_motd_no_motd(client: FlaskClient):
- motd = utils.get_latest_motd()
- assert not motd
-
-
-def test_get_latest_motd(client: FlaskClient):
- new_message: str = "test message"
- new_motd = models.MOTD(message=new_message, date_created=utils.current_time())
- db.session.add(new_motd)
- db.session.commit()
-
- motd = utils.get_latest_motd()
- assert motd == new_message
From 36c931b896d7fdd92852fa605a472aa24faa1abc Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Mon, 4 Jul 2022 10:11:00 +0200
Subject: [PATCH 06/12] adapt method in utils
---
dds_web/__init__.py | 4 ++--
dds_web/utils.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/dds_web/__init__.py b/dds_web/__init__.py
index 3066fb634..8c59ac94e 100644
--- a/dds_web/__init__.py
+++ b/dds_web/__init__.py
@@ -189,10 +189,10 @@ def create_app(testing=False, database_uri=None):
@app.before_request
def prepare():
"""Populate flask globals for template rendering"""
- from dds_web.utils import get_latest_motd
+ from dds_web.utils import get_active_motds
# Get message of the day
- flask.g.motd = get_latest_motd()
+ flask.g.motd = get_active_motds()
flask.g.current_user = None
flask.g.current_user_emails = None
diff --git a/dds_web/utils.py b/dds_web/utils.py
index 7dfad1f76..b7f2e119d 100644
--- a/dds_web/utils.py
+++ b/dds_web/utils.py
@@ -436,7 +436,7 @@ def bucket_is_valid(bucket_name):
return valid, message
-def get_latest_motd():
+def get_active_motds():
"""Return latest MOTD."""
motd_object = (
models.MOTD.query.filter_by(active=True).order_by(models.MOTD.date_created.desc()).all()
From 4de08478edc59477dd7b3683aacc17cdfc9dba9d Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Mon, 4 Jul 2022 12:33:29 +0200
Subject: [PATCH 07/12] add tests
---
tests/test_superadmin_only.py | 32 ++++++++++++++++++++++++++++++--
1 file changed, 30 insertions(+), 2 deletions(-)
diff --git a/tests/test_superadmin_only.py b/tests/test_superadmin_only.py
index bab8eba65..143695c5b 100644
--- a/tests/test_superadmin_only.py
+++ b/tests/test_superadmin_only.py
@@ -161,8 +161,36 @@ def test_get_motd(client):
response4 = client.put(tests.DDSEndpoint.MOTD, headers=token, json={"motd_id": 1})
assert response4.status_code == http.HTTPStatus.OK
assert "The MOTD was successfully deactivated in the database." in response4.json.get("message")
- # assert isinstance(response4.json.get("motds"), list)
- # assert len(response4.json.get("motds")) == 1
+
+ # Deactivate message that is not active
+ response5 = client.put(tests.DDSEndpoint.MOTD, headers=token, json={"motd_id": 1})
+ assert response5.status_code == http.HTTPStatus.BAD_REQUEST
+ assert "MOTD with id 1 is not active." in response5.json.get("message")
+
+
+def test_deactivate_motd_no_json(client):
+ token = get_token(username=users["Super Admin"], client=client)
+ response = client.put(tests.DDSEndpoint.MOTD, headers=token)
+ assert response.status_code == http.HTTPStatus.BAD_REQUEST
+ assert "Required data missing from request!" in response.json.get("message")
+
+
+def test_deactivate_motd_no_motd_id(client):
+ token = get_token(username=users["Super Admin"], client=client)
+ response = client.put(tests.DDSEndpoint.MOTD, headers=token, json={"test": "test"})
+ assert response.status_code == http.HTTPStatus.BAD_REQUEST
+ assert "No MOTD for deactivation specified." in response.json.get("message")
+
+
+def test_deactivate_motd_not_superadmin(client):
+ """Deactivate a message of the day, using everything but Super Admin access."""
+ no_access_users = users.copy()
+ no_access_users.pop("Super Admin")
+
+ for u in no_access_users:
+ token = get_token(username=users[u], client=client)
+ response = client.put(tests.DDSEndpoint.MOTD, headers=token)
+ assert response.status_code == http.HTTPStatus.FORBIDDEN
# FindUser
From fecea15001f2d96258f6fe6601436dc1d1fb7820 Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Mon, 4 Jul 2022 14:58:18 +0200
Subject: [PATCH 08/12] handle deactivating non-existing motd
---
dds_web/api/superadmin_only.py | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index 00865e892..fa5265ede 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -125,6 +125,10 @@ def put(self):
raise ddserr.DDSArgumentError(message="No MOTD for deactivation specified.")
motd_to_deactivate = models.MOTD.query.filter_by(id=motd_id).first()
+ if not motd_to_deactivate:
+ raise ddserr.DDSArgumentError(
+ message=f"MOTD with id {motd_id} does not exist in the database"
+ )
if motd_to_deactivate.active == True:
motd_to_deactivate.active = 0
db.session.commit()
From d74ff06a9724565f136718961ed01981802229d6 Mon Sep 17 00:00:00 2001
From: valyo <582646+valyo@users.noreply.github.com>
Date: Mon, 4 Jul 2022 15:17:32 +0200
Subject: [PATCH 09/12] add one more test
---
tests/test_superadmin_only.py | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tests/test_superadmin_only.py b/tests/test_superadmin_only.py
index 143695c5b..07e52ab9c 100644
--- a/tests/test_superadmin_only.py
+++ b/tests/test_superadmin_only.py
@@ -182,6 +182,13 @@ def test_deactivate_motd_no_motd_id(client):
assert "No MOTD for deactivation specified." in response.json.get("message")
+def test_deactivate_motd_no_such_motd(client):
+ token = get_token(username=users["Super Admin"], client=client)
+ response = client.put(tests.DDSEndpoint.MOTD, headers=token, json={"motd_id": 8})
+ assert response.status_code == http.HTTPStatus.BAD_REQUEST
+ assert "MOTD with id 8 does not exist in the database" in response.json.get("message")
+
+
def test_deactivate_motd_not_superadmin(client):
"""Deactivate a message of the day, using everything but Super Admin access."""
no_access_users = users.copy()
From 09128fca9905ce22f911c26c216d6c2ba9cc38ff Mon Sep 17 00:00:00 2001
From: Ina
Date: Mon, 1 Aug 2022 14:45:03 +0200
Subject: [PATCH 10/12] commends and small alterations
---
dds_web/api/superadmin_only.py | 18 +++++++++++-------
dds_web/utils.py | 4 ++--
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index fa5265ede..9e1037917 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -118,24 +118,28 @@ def get(self):
@handle_db_error
def put(self):
"""Deactivate MOTDs."""
-
+ # Get motd id
json_input = flask.request.json
motd_id = json_input.get("motd_id")
if not motd_id:
raise ddserr.DDSArgumentError(message="No MOTD for deactivation specified.")
-
+
+ # Get motd row from db
motd_to_deactivate = models.MOTD.query.filter_by(id=motd_id).first()
if not motd_to_deactivate:
raise ddserr.DDSArgumentError(
message=f"MOTD with id {motd_id} does not exist in the database"
)
- if motd_to_deactivate.active == True:
- motd_to_deactivate.active = 0
- db.session.commit()
- return {"message": "The MOTD was successfully deactivated in the database."}
- else:
+ # Check if motd is active
+ if not motd_to_deactivate.active:
raise ddserr.DDSArgumentError(message=f"MOTD with id {motd_id} is not active.")
+
+ motd_to_deactivate.active = False
+ db.session.commit()
+
+ return {"message": "The MOTD was successfully deactivated in the database."}
+
class FindUser(flask_restful.Resource):
diff --git a/dds_web/utils.py b/dds_web/utils.py
index b7f2e119d..237e53571 100644
--- a/dds_web/utils.py
+++ b/dds_web/utils.py
@@ -438,7 +438,7 @@ def bucket_is_valid(bucket_name):
def get_active_motds():
"""Return latest MOTD."""
- motd_object = (
+ motds_active = (
models.MOTD.query.filter_by(active=True).order_by(models.MOTD.date_created.desc()).all()
)
- return motd_object if motd_object else ""
+ return motds_active or None
From ac11dfe00244b611b4070b16712900a622966996 Mon Sep 17 00:00:00 2001
From: Ina
Date: Tue, 2 Aug 2022 08:58:28 +0200
Subject: [PATCH 11/12] black
---
dds_web/api/superadmin_only.py | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index 9e1037917..a90a780d4 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -123,7 +123,7 @@ def put(self):
motd_id = json_input.get("motd_id")
if not motd_id:
raise ddserr.DDSArgumentError(message="No MOTD for deactivation specified.")
-
+
# Get motd row from db
motd_to_deactivate = models.MOTD.query.filter_by(id=motd_id).first()
if not motd_to_deactivate:
@@ -134,12 +134,11 @@ def put(self):
# Check if motd is active
if not motd_to_deactivate.active:
raise ddserr.DDSArgumentError(message=f"MOTD with id {motd_id} is not active.")
-
+
motd_to_deactivate.active = False
db.session.commit()
return {"message": "The MOTD was successfully deactivated in the database."}
-
class FindUser(flask_restful.Resource):
From d2f5dda317b7e50f261e6bf643a046b39cb06621 Mon Sep 17 00:00:00 2001
From: Ina
Date: Thu, 4 Aug 2022 16:33:54 +0200
Subject: [PATCH 12/12] slight refactoring of get motds
---
dds_web/api/superadmin_only.py | 31 ++++++++++++-------------------
1 file changed, 12 insertions(+), 19 deletions(-)
diff --git a/dds_web/api/superadmin_only.py b/dds_web/api/superadmin_only.py
index a90a780d4..c6aa179dc 100644
--- a/dds_web/api/superadmin_only.py
+++ b/dds_web/api/superadmin_only.py
@@ -91,27 +91,20 @@ def post(self):
def get(self):
"""Return list of all active MOTDs to super admin."""
active_motds = models.MOTD.query.filter_by(active=True).all()
- if active_motds:
- motd_info = [
- {
- "MOTD ID": m.id,
- "Message": m.message,
- "Created": m.date_created.strftime("%Y-%m-%d %H:%M"),
- }
- for m in active_motds
- ]
-
- return {
- "motds": motd_info,
- "keys": [
- "MOTD ID",
- "Message",
- "Created",
- ],
- }
- else:
+ if not active_motds:
return {"message": "There are no active MOTDs."}
+ motd_info = [
+ {
+ "MOTD ID": m.id,
+ "Message": m.message,
+ "Created": m.date_created.strftime("%Y-%m-%d %H:%M"),
+ }
+ for m in active_motds
+ ]
+
+ return {"motds": motd_info, "keys": ["MOTD ID", "Message", "Created"]}
+
@auth.login_required(role=["Super Admin"])
@logging_bind_request
@json_required