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 %} {% 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