diff --git a/app/__init__.py b/app/__init__.py index bfefe5705..5a233110a 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -359,6 +359,11 @@ def init_app(application): def _attach_current_user(): return {"current_user": current_user} + @application.context_processor + def _attach_enums(): + from app.enums import ServicePermission + return {"ServicePermission": ServicePermission} + @application.context_processor def _nav_selected(): return navigation diff --git a/app/enums.py b/app/enums.py index 405c28cdf..b420cf3cc 100644 --- a/app/enums.py +++ b/app/enums.py @@ -34,6 +34,11 @@ class JobStatus(StrEnum): SENT_TO_DVLA = "sent to dvla" +class ServicePermission(StrEnum): + SEND_MESSAGES = "send_messages" + MANAGE_SERVICE = "manage_service" + + class InvitedUserStatus(StrEnum): ACCEPTED = "accepted" CANCELLED = "cancelled" @@ -53,17 +58,3 @@ class VerificationStatus(StrEnum): class AuthType(StrEnum): EMAIL_AUTH = "email_auth" SMS_AUTH = "sms_auth" - - -# TODO: -# class UserRole(StrEnum): -# ADMIN = "admin" -# USER = "user" -# GUEST = "guest" - - -# TODO: -# class NotificationType(StrEnum): -# EMAIL = "email" -# SMS = "sms" -# PUSH = "push" diff --git a/app/main/views/conversation.py b/app/main/views/conversation.py index 35d82fe09..9df6bf5c9 100644 --- a/app/main/views/conversation.py +++ b/app/main/views/conversation.py @@ -2,6 +2,7 @@ from flask import jsonify, redirect, render_template, session, url_for from flask_login import current_user from app import current_service, notification_api_client, service_api_client +from app.enums import ServicePermission from app.main import main from app.main.forms import SearchByNameForm from app.models.template_list import TemplateList @@ -45,7 +46,7 @@ def conversation_updates(service_id, notification_id): @main.route( "/services//conversation//reply-with/from-folder/" ) -@user_has_permissions("send_messages") +@user_has_permissions(ServicePermission.SEND_MESSAGES) def conversation_reply( service_id, notification_id, @@ -69,7 +70,7 @@ def conversation_reply( @main.route( "/services//conversation//reply-with/" ) -@user_has_permissions("send_messages") +@user_has_permissions(ServicePermission.SEND_MESSAGES) def conversation_reply_with_template( service_id, notification_id, diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 3d8adde61..ec611a991 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -14,6 +14,7 @@ from app import ( service_api_client, template_statistics_client, ) +from app.enums import ServicePermission from app.main import main from app.main.views.user_profile import set_timezone from app.statistics_utils import get_formatted_percentage @@ -23,7 +24,7 @@ from app.utils.user import user_has_permissions @main.route("/services//dashboard") -@user_has_permissions("view_activity", "send_messages") +@user_has_permissions("view_activity", ServicePermission.SEND_MESSAGES) def old_service_dashboard(service_id): return redirect(url_for(".service_dashboard", service_id=service_id)) @@ -202,7 +203,7 @@ def template_usage(service_id): @main.route("/services//usage") -@user_has_permissions("manage_service", allow_org_user=True) +@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True) def usage(service_id): year, current_financial_year = requested_and_current_financial_year(request) diff --git a/app/main/views/history.py b/app/main/views/history.py index f2911e478..6995c2830 100644 --- a/app/main/views/history.py +++ b/app/main/views/history.py @@ -4,13 +4,14 @@ from operator import attrgetter from flask import render_template, request from app import current_service, format_date_numeric +from app.enums import ServicePermission from app.main import main from app.models.event import APIKeyEvent, APIKeyEvents, ServiceEvents from app.utils.user import user_has_permissions @main.route("/services//history") -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def history(service_id): events = _get_events(current_service.id, request.args.get("selected")) diff --git a/app/main/views/jobs.py b/app/main/views/jobs.py index d9e282122..4dd990ce2 100644 --- a/app/main/views/jobs.py +++ b/app/main/views/jobs.py @@ -23,7 +23,7 @@ from app import ( notification_api_client, service_api_client, ) -from app.enums import JobStatus +from app.enums import JobStatus, ServicePermission from app.formatters import get_time_left, message_count_noun from app.main import main from app.main.forms import SearchNotificationsForm @@ -106,7 +106,7 @@ def view_job_csv(service_id, job_id): @main.route("/services//jobs/", methods=["POST"]) -@user_has_permissions("send_messages") +@user_has_permissions(ServicePermission.SEND_MESSAGES) def cancel_job(service_id, job_id): Job.from_id(job_id, service_id=service_id).cancel() return redirect(url_for("main.service_dashboard", service_id=service_id)) diff --git a/app/main/views/manage_users.py b/app/main/views/manage_users.py index 81571fcc2..96e168f20 100644 --- a/app/main/views/manage_users.py +++ b/app/main/views/manage_users.py @@ -2,6 +2,7 @@ from flask import abort, flash, redirect, render_template, request, session, url from flask_login import current_user from app import current_service, service_api_client +from app.enums import ServicePermission from app.event_handlers import ( create_cancel_user_invite_to_service_event, create_email_change_event, @@ -43,7 +44,7 @@ def manage_users(service_id): @main.route( "/services//users/invite/", methods=["GET", "POST"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def invite_user(service_id, user_id=None): form_class = InviteUserForm form = form_class( @@ -113,7 +114,7 @@ def invite_user(service_id, user_id=None): @main.route("/services//users/", methods=["GET", "POST"]) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def edit_user_permissions(service_id, user_id): service_has_email_auth = current_service.has_permission("email_auth") user = current_service.get_team_member(user_id) @@ -164,7 +165,7 @@ def edit_user_permissions(service_id, user_id): @main.route("/services//users//delete", methods=["POST"]) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def remove_user_from_service(service_id, user_id): try: service_api_client.remove_user_from_service(service_id, user_id) @@ -187,7 +188,7 @@ def remove_user_from_service(service_id, user_id): "/services//users//edit-email", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def edit_user_email(service_id, user_id): user = current_service.get_team_member(user_id) user_email = user.email_address @@ -220,7 +221,7 @@ def edit_user_email(service_id, user_id): "/services//users//edit-email/confirm", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def confirm_edit_user_email(service_id, user_id): user = current_service.get_team_member(user_id) session_key = "team_member_email_change-{}".format(user_id) @@ -258,7 +259,7 @@ def confirm_edit_user_email(service_id, user_id): "/services//users//edit-mobile-number", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def edit_user_mobile_number(service_id, user_id): user = current_service.get_team_member(user_id) user_mobile_number = redact_mobile_number(user.mobile_number) @@ -288,7 +289,7 @@ def edit_user_mobile_number(service_id, user_id): "/services//users//edit-mobile-number/confirm", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def confirm_edit_user_mobile_number(service_id, user_id): user = current_service.get_team_member(user_id) if "team_member_mobile_change" in session: @@ -326,7 +327,7 @@ def confirm_edit_user_mobile_number(service_id, user_id): "/services//cancel-invited-user/", methods=["GET"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def cancel_invited_user(service_id, invited_user_id): current_service.cancel_invite(invited_user_id) @@ -345,7 +346,7 @@ def cancel_invited_user(service_id, invited_user_id): "/services//resend-invite/", methods=["GET"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def resend_invite(service_id, invited_user_id): current_service.resend_invite(invited_user_id) diff --git a/app/main/views/notifications.py b/app/main/views/notifications.py index e41708b8c..bd02a81a2 100644 --- a/app/main/views/notifications.py +++ b/app/main/views/notifications.py @@ -12,6 +12,7 @@ from flask import ( ) from app import current_service, job_api_client, notification_api_client +from app.enums import ServicePermission from app.main import main from app.notify_client.api_key_api_client import KEY_TYPE_TEST from app.utils import ( @@ -27,7 +28,7 @@ from app.utils.user import user_has_permissions @main.route("/services//notification/") -@user_has_permissions("view_activity", "send_messages") +@user_has_permissions("view_activity", ServicePermission.SEND_MESSAGES) def view_notification(service_id, notification_id, error_message=None): if error_message: flash(error_message) @@ -100,7 +101,7 @@ def view_notification(service_id, notification_id, error_message=None): @main.route("/services//notification/.json") -@user_has_permissions("view_activity", "send_messages") +@user_has_permissions("view_activity", ServicePermission.SEND_MESSAGES) def view_notification_updates(service_id, notification_id): return jsonify( **get_single_notification_partials( diff --git a/app/main/views/send.py b/app/main/views/send.py index 8de4663fe..2d2620683 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -27,6 +27,7 @@ from app import ( notification_api_client, service_api_client, ) +from app.enums import ServicePermission from app.main import main from app.main.forms import ( ChooseTimeForm, @@ -94,7 +95,7 @@ def get_example_csv_rows(template, use_example_as_example=True, submitted_fields @main.route( "/services//send//csv", methods=["GET", "POST"] ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def send_messages(service_id, template_id): notification_count = service_api_client.get_notification_count(service_id) remaining_messages = current_service.message_limit - notification_count @@ -189,7 +190,7 @@ def send_messages(service_id, template_id): @main.route("/services//send/.csv", methods=["GET"]) -@user_has_permissions("send_messages", "manage_templates") +@user_has_permissions(ServicePermission.SEND_MESSAGES, "manage_templates") def get_example_csv(service_id, template_id): template = get_template( service_api_client.get_service_template(service_id, template_id)["data"], @@ -214,7 +215,7 @@ def get_example_csv(service_id, template_id): "/services//send//set-sender", methods=["GET", "POST"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def set_sender(service_id, template_id): session["sender_id"] = None redirect_to_one_off = redirect( @@ -343,7 +344,7 @@ def get_sender_details(service_id, template_type): @main.route("/services//send//one-off") -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def send_one_off(service_id, template_id): session["recipient"] = None session["placeholders"] = {} @@ -387,7 +388,7 @@ def get_notification_check_endpoint(service_id, template): "/services//send//one-off/step-", methods=["GET", "POST"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def send_one_off_step(service_id, template_id, step_index): if {"recipient", "placeholders"} - set(session.keys()): return redirect( @@ -647,7 +648,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row, **kwargs): "/services///check//row-", methods=["GET"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def check_messages(service_id, template_id, upload_id, row_index=2): data = _check_messages(service_id, template_id, upload_id, row_index) data["allowed_file_extensions"] = Spreadsheet.ALLOWED_FILE_EXTENSIONS @@ -691,7 +692,7 @@ def check_messages(service_id, template_id, upload_id, row_index=2): "/services///check//preview/row-", methods=["POST"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def preview_job(service_id, template_id, upload_id, row_index=2): session["scheduled_for"] = request.form.get("scheduled_for", "") data = _check_messages( @@ -706,7 +707,7 @@ def preview_job(service_id, template_id, upload_id, row_index=2): @main.route("/services//start-job/", methods=["POST"]) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def start_job(service_id, upload_id): scheduled_for = session.pop("scheduled_for", None) job_api_client.create_job( @@ -843,7 +844,9 @@ def get_skip_link(step_index, template): and step_index == 0 and template.template_type in ("sms", "email") and not (template.template_type == "sms" and current_user.mobile_number is None) - and current_user.has_permissions("manage_templates", "manage_service") + and current_user.has_permissions( + "manage_templates", ServicePermission.MANAGE_SERVICE + ) ): return ( "Use my {}".format(first_column_headings[template.template_type][0]), @@ -859,7 +862,7 @@ def get_skip_link(step_index, template): "/services//template//one-off/send-to-myself", methods=["GET"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def send_one_off_to_myself(service_id, template_id): current_app.logger.info("Send one off to myself") try: @@ -896,7 +899,7 @@ def send_one_off_to_myself(service_id, template_id): "/services//template//notification/check", methods=["GET"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def check_notification(service_id, template_id): return render_template( "views/notifications/check.html", @@ -978,7 +981,7 @@ def get_template_error_dict(exception): "/services//template//notification/check/preview", methods=["POST"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def preview_notification(service_id, template_id): recipient = get_recipient() if not recipient: @@ -1010,7 +1013,7 @@ def preview_notification(service_id, template_id): "/services//template//notification/check", methods=["POST"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def send_notification(service_id, template_id): recipient = get_recipient() diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index 5615df690..bd51d3f0e 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -21,7 +21,7 @@ from app import ( organizations_client, service_api_client, ) -from app.enums import VerificationStatus +from app.enums import ServicePermission, VerificationStatus from app.event_handlers import ( create_archive_service_event, create_resume_service_event, @@ -70,7 +70,7 @@ PLATFORM_ADMIN_SERVICE_PERMISSIONS = OrderedDict( @main.route("/services//service-settings") -@user_has_permissions("manage_service", "manage_api_keys") +@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys") def service_settings(service_id): return render_template( "views/service-settings.html", @@ -81,7 +81,7 @@ def service_settings(service_id): @main.route( "/services//service-settings/name", methods=["GET", "POST"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_name_change(service_id): form = RenameServiceForm(name=current_service.name) @@ -195,7 +195,7 @@ def service_set_permission(service_id, permission): @main.route( "/services//service-settings/archive", methods=["GET", "POST"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def archive_service(service_id): if not current_service.active or not ( current_service.trial_mode or current_user.platform_admin @@ -268,7 +268,7 @@ def resume_service(service_id): "/services//service-settings/send-files-by-email", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def send_files_by_email_contact_details(service_id): form = ServiceContactDetailsForm() contact_details = None @@ -298,7 +298,7 @@ def send_files_by_email_contact_details(service_id): @main.route( "/services//service-settings/set-reply-to-email", methods=["GET"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_reply_to_email(service_id): return redirect(url_for(".service_email_reply_to", service_id=service_id)) @@ -306,7 +306,7 @@ def service_set_reply_to_email(service_id): @main.route( "/services//service-settings/email-reply-to", methods=["GET"] ) -@user_has_permissions("manage_service", "manage_api_keys") +@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys") def service_email_reply_to(service_id): return render_template("views/service-settings/email_reply_to.html") @@ -315,7 +315,7 @@ def service_email_reply_to(service_id): "/services//service-settings/email-reply-to/add", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_add_email_reply_to(service_id): form = ServiceReplyToEmailForm() first_email_address = current_service.count_email_reply_to_addresses == 0 @@ -359,7 +359,7 @@ def service_add_email_reply_to(service_id): "/services//service-settings/email-reply-to//verify", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_verify_reply_to_address(service_id, notification_id): replace = request.args.get("replace", False) is_default = request.args.get("is_default", False) @@ -379,7 +379,7 @@ def service_verify_reply_to_address(service_id, notification_id): @main.route( "/services//service-settings/email-reply-to//verify.json" ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_verify_reply_to_address_updates(service_id, notification_id): return jsonify( **get_service_verify_reply_to_address_partials(service_id, notification_id) @@ -456,7 +456,7 @@ def get_service_verify_reply_to_address_partials(service_id, notification_id): methods=["GET"], endpoint="service_confirm_delete_email_reply_to", ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_edit_email_reply_to(service_id, reply_to_email_id): form = ServiceReplyToEmailForm() reply_to_email_address = current_service.get_email_reply_to_address( @@ -525,7 +525,7 @@ def service_edit_email_reply_to(service_id, reply_to_email_id): "/services//service-settings/email-reply-to//delete", methods=["POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_delete_email_reply_to(service_id, reply_to_email_id): service_api_client.delete_reply_to_email_address( service_id=current_service.id, @@ -538,7 +538,7 @@ def service_delete_email_reply_to(service_id, reply_to_email_id): "/services//service-settings/set-inbound-number", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_inbound_number(service_id): available_inbound_numbers = ( inbound_number_client.get_available_inbound_sms_numbers() @@ -571,7 +571,7 @@ def service_set_inbound_number(service_id): @main.route( "/services//service-settings/sms-prefix", methods=["GET", "POST"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_sms_prefix(service_id): form = SMSPrefixForm(enabled=current_service.prefix_sms) @@ -590,7 +590,7 @@ def service_set_sms_prefix(service_id): "/services//service-settings/set-international-sms", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_international_sms(service_id): form = ServiceOnOffSettingForm( "Send text messages to international phone numbers", @@ -611,7 +611,7 @@ def service_set_international_sms(service_id): @main.route( "/services//service-settings/set-inbound-sms", methods=["GET"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_inbound_sms(service_id): return render_template( "views/service-settings/set-inbound-sms.html", @@ -622,7 +622,7 @@ def service_set_inbound_sms(service_id): "/services//service-settings/set-", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_channel(service_id, channel): if channel not in {"email", "sms"}: abort(404) @@ -647,7 +647,7 @@ def service_set_channel(service_id, channel): @main.route( "/services//service-settings/set-auth-type", methods=["GET"] ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_set_auth_type(service_id): return render_template( "views/service-settings/set-auth-type.html", @@ -655,7 +655,7 @@ def service_set_auth_type(service_id): @main.route("/services//service-settings/sms-sender", methods=["GET"]) -@user_has_permissions("manage_service", "manage_api_keys") +@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys") def service_sms_senders(service_id): return render_template( "views/service-settings/sms-senders.html", @@ -666,7 +666,7 @@ def service_sms_senders(service_id): "/services//service-settings/sms-sender/add", methods=["GET", "POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_add_sms_sender(service_id): form = ServiceSmsSenderForm() first_sms_sender = current_service.count_sms_senders == 0 @@ -694,7 +694,7 @@ def service_add_sms_sender(service_id): methods=["GET"], endpoint="service_confirm_delete_sms_sender", ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_edit_sms_sender(service_id, sms_sender_id): sms_sender = current_service.get_sms_sender(sms_sender_id) is_inbound_number = sms_sender["inbound_number_id"] @@ -732,7 +732,7 @@ def service_edit_sms_sender(service_id, sms_sender_id): "/services//service-settings/sms-sender//delete", methods=["POST"], ) -@user_has_permissions("manage_service") +@user_has_permissions(ServicePermission.MANAGE_SERVICE) def service_delete_sms_sender(service_id, sms_sender_id): service_api_client.delete_sms_sender( service_id=current_service.id, diff --git a/app/main/views/templates.py b/app/main/views/templates.py index bb82c6d38..03daa4ebc 100644 --- a/app/main/views/templates.py +++ b/app/main/views/templates.py @@ -12,6 +12,7 @@ from app import ( template_folder_api_client, template_statistics_client, ) +from app.enums import ServicePermission from app.formatters import character_count, message_count from app.main import main from app.main.forms import ( @@ -117,7 +118,7 @@ def choose_template(service_id, template_type="all", template_folder_id=None): single_notification_channel = notification_channels[0] if request.method == "POST" and templates_and_folders_form.validate_on_submit(): - if not current_user.has_permissions("manage_templates"): + if not current_user.has_permissions(ServicePermission.MANAGE_TEMPLATES): abort(403) try: return process_folder_management_form( @@ -266,7 +267,7 @@ def _add_template_by_type(template_type, template_folder_id): @main.route( "/services//templates/copy/from-service//from-folder/" ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def choose_template_to_copy( service_id, from_service=None, @@ -298,7 +299,7 @@ def choose_template_to_copy( "/services//templates/copy/", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def copy_template(service_id, template_id): from_service = request.args.get("from_service") @@ -355,7 +356,7 @@ def _get_template_copy_name(template, existing_templates): "//" ) ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def action_blocked(service_id, notification_type, return_to, template_id=None): back_link = { "add_new_template": partial( @@ -387,7 +388,7 @@ def action_blocked(service_id, notification_type, return_to, template_id=None): "/services//templates/folders//manage", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def manage_template_folder(service_id, template_folder_id): template_folder = current_service.get_template_folder_with_user_permission_or_403( template_folder_id, current_user @@ -401,7 +402,7 @@ def manage_template_folder(service_id, template_folder_id): ) if form.validate_on_submit(): if ( - current_user.has_permissions("manage_service") + current_user.has_permissions(ServicePermission.MANAGE_SERVICE) and form.users_with_permission.all_service_users ): users_with_permission = form.users_with_permission.data + [current_user.id] @@ -437,7 +438,7 @@ def manage_template_folder(service_id, template_folder_id): "/services//templates/folders//delete", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def delete_template_folder(service_id, template_folder_id): template_folder = current_service.get_template_folder_with_user_permission_or_403( template_folder_id, current_user @@ -502,7 +503,7 @@ def delete_template_folder(service_id, template_folder_id): "/services//templates/folders//add-", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def add_service_template(service_id, template_type, template_folder_id=None): if template_type not in current_service.available_template_types: return redirect( @@ -566,7 +567,7 @@ def abort_403_if_not_admin_user(): "/services//templates//edit", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def edit_service_template(service_id, template_id): template = current_service.get_template_with_user_permission_or_403( template_id, current_user @@ -724,7 +725,7 @@ def _get_content_count_error_and_message_for_template(template): "/services//templates//delete", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def delete_service_template(service_id, template_id): template = current_service.get_template_with_user_permission_or_403( template_id, current_user @@ -782,7 +783,7 @@ def delete_service_template(service_id, template_id): @main.route( "/services//templates//redact", methods=["GET"] ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def confirm_redact_template(service_id, template_id): template = current_service.get_template_with_user_permission_or_403( template_id, current_user @@ -803,7 +804,7 @@ def confirm_redact_template(service_id, template_id): @main.route( "/services//templates//redact", methods=["POST"] ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def redact_template(service_id, template_id): service_api_client.redact_service_template(service_id, template_id) @@ -842,7 +843,7 @@ def view_template_versions(service_id, template_id): "/services//templates//set-template-sender", methods=["GET", "POST"], ) -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def set_template_sender(service_id, template_id): template = current_service.get_template_with_user_permission_or_403( template_id, current_user diff --git a/app/main/views/tour.py b/app/main/views/tour.py index d42ff1edf..b23ca1720 100644 --- a/app/main/views/tour.py +++ b/app/main/views/tour.py @@ -1,6 +1,7 @@ from flask import abort, redirect, render_template, session from app import current_service, current_user, service_api_client, url_for +from app.enums import ServicePermission from app.main import main from app.main.views.send import ( all_placeholders_in_session, @@ -14,7 +15,7 @@ from app.utils.user import user_has_permissions @main.route("/services//tour/") -@user_has_permissions("send_messages") +@user_has_permissions(ServicePermission.SEND_MESSAGES) def begin_tour(service_id, template_id): db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user @@ -47,7 +48,7 @@ def begin_tour(service_id, template_id): "/services//tour//step-", methods=["GET", "POST"], ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def tour_step(service_id, template_id, step_index): db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user @@ -166,7 +167,7 @@ def _get_tour_step_back_link(service_id, template_id, step_index): @main.route( "/services//tour//check", methods=["GET"] ) -@user_has_permissions("send_messages", restrict_admin_usage=True) +@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) def check_tour_notification(service_id, template_id): db_template = current_service.get_template_with_user_permission_or_403( template_id, current_user @@ -223,7 +224,7 @@ def check_tour_notification(service_id, template_id): @main.route("/services//end-tour/") -@user_has_permissions("manage_templates") +@user_has_permissions(ServicePermission.MANAGE_TEMPLATES) def go_to_dashboard_after_tour(service_id, example_template_id): service_api_client.delete_service_template(service_id, example_template_id) diff --git a/app/models/service.py b/app/models/service.py index e9bcf8a7d..9c2ac17e1 100644 --- a/app/models/service.py +++ b/app/models/service.py @@ -1,6 +1,7 @@ from flask import abort, current_app from werkzeug.utils import cached_property +from app.enums import ServicePermission from app.models import JSONModel, SortByNameMixin from app.models.job import ImmediateJobs, PaginatedJobs, PaginatedUploads, ScheduledJobs from app.models.organization import Organization @@ -175,7 +176,7 @@ class Service(JSONModel, SortByNameMixin): [ user for user in self.team_members - if user.has_permission_for_service(self.id, "manage_service") + if user.has_permission_for_service(self.id, ServicePermission.MANAGE_SERVICE) ] ) > 1 diff --git a/app/navigation.py b/app/navigation.py index cab2091f9..a76af7b00 100644 --- a/app/navigation.py +++ b/app/navigation.py @@ -2,6 +2,8 @@ from itertools import chain from flask import request +from app.enums import ServicePermission + class Navigation: mapping = {} @@ -74,7 +76,7 @@ class HeaderNavigation(Navigation): "delete_service_template", "edit_service_template", "manage_template_folder", - "send_messages", + ServicePermission.SEND_MESSAGES, "send_one_off", "send_one_off_step", "send_one_off_to_myself", @@ -177,7 +179,7 @@ class MainNavigation(Navigation): "delete_service_template", "edit_service_template", "manage_template_folder", - "send_messages", + ServicePermission.SEND_MESSAGES, "send_one_off", "send_one_off_step", "send_one_off_to_myself", diff --git a/app/templates/components/header.html b/app/templates/components/header.html index 30e4c7dbe..830a84cea 100644 --- a/app/templates/components/header.html +++ b/app/templates/components/header.html @@ -12,7 +12,7 @@ {% endif %} {% if current_service %} - {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %} {% set secondaryNavigation = [ {"href": url_for('main.service_settings', service_id=current_service.id), "text": "Settings", "active": secondary_navigation.is_selected('settings')}, {"href": url_for('main.sign_out'), "text": "Sign out"} diff --git a/app/templates/views/conversations/conversation.html b/app/templates/views/conversations/conversation.html index 81525298e..79022dec4 100644 --- a/app/templates/views/conversations/conversation.html +++ b/app/templates/views/conversations/conversation.html @@ -27,7 +27,7 @@ 'messages', ) }} - {% if current_user.has_permissions('send_messages') %} + {% if current_user.has_permissions(ServicePermission.SEND_MESSAGES) %} diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html index 6cc0e4345..3720c9218 100644 --- a/app/templates/views/dashboard/dashboard.html +++ b/app/templates/views/dashboard/dashboard.html @@ -43,7 +43,7 @@ Dashboard
{% include 'views/dashboard/activity-table.html' %} - {% if current_user.has_permissions('manage_service') %}{% endif %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %}{% endif %} {% include 'views/dashboard/most-used-templates.html' %} diff --git a/app/templates/views/manage-users.html b/app/templates/views/manage-users.html index 8d4771ad6..8415adc56 100644 --- a/app/templates/views/manage-users.html +++ b/app/templates/views/manage-users.html @@ -19,7 +19,7 @@

Team members

- {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %} {{ usaButton({ "element": "a", "text": "Invite a team member", @@ -108,7 +108,7 @@ - {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %} {% if user.status == 'pending' or user.status == 'expired' %} Cancel invitation for {{ user.email_address }} diff --git a/app/templates/views/notifications/notification.html b/app/templates/views/notifications/notification.html index cf61250ed..b5e9fc944 100644 --- a/app/templates/views/notifications/notification.html +++ b/app/templates/views/notifications/notification.html @@ -50,7 +50,7 @@ {{ ajax_block(partials, updates_url, 'status', finished=finished) }} {% endif %} - {% if current_user.has_permissions('send_messages') and current_user.has_permissions('view_activity') and template.template_type == 'sms' and can_receive_inbound %} + {% if current_user.has_permissions(ServicePermission.SEND_MESSAGES) and current_user.has_permissions('view_activity') and template.template_type == 'sms' and can_receive_inbound %}

See all text messages sent to this phone number

diff --git a/app/templates/views/service-settings.html b/app/templates/views/service-settings.html index d00d8aae5..bfcb1d188 100644 --- a/app/templates/views/service-settings.html +++ b/app/templates/views/service-settings.html @@ -30,7 +30,7 @@ {{ edit_field( 'Change', url_for('.service_name_change', service_id=current_service.id), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='service name', ) }} @@ -46,7 +46,7 @@ service_id=current_service.id, channel='sms' ), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='your settings for sending text messages', )}} #} {% endcall %} @@ -65,7 +65,7 @@ {{ edit_field( 'Manage', url_for('.service_sms_senders', service_id=current_service.id), - permissions=['manage_service','manage_api_keys'], + permissions=[ServicePermission.MANAGE_SERVICE,'manage_api_keys'], suffix='text message senders', ) }} @@ -78,7 +78,7 @@ {{ edit_field( 'Change', url_for('.service_set_sms_prefix', service_id=current_service.id), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='your settings for starting text messages with service name', ) }} @@ -91,7 +91,7 @@ {{ edit_field( 'Change', url_for('.service_set_international_sms', service_id=current_service.id), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='your settings for sending international text messages', ) }} @@ -104,7 +104,7 @@ {{ edit_field( 'Change', url_for('.service_set_inbound_sms', service_id=current_service.id), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='your settings for receiving text messages', ) }} @@ -128,7 +128,7 @@ channel='email', service_id=current_service.id ), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='your settings for sending emails', )}} {% endcall %} @@ -146,7 +146,7 @@ {{ edit_field( 'Manage', url_for('.service_email_reply_to', service_id=current_service.id), - permissions=['manage_service','manage_api_keys'], + permissions=[ServicePermission.MANAGE_SERVICE,'manage_api_keys'], suffix='reply-to email addresses', ) }} @@ -158,7 +158,7 @@ {{ edit_field( 'Manage', url_for('.send_files_by_email_contact_details', service_id=current_service.id), - permissions=['manage_service'], + permissions=[ServicePermission.MANAGE_SERVICE], suffix='sending files by email', )}} {% endcall %} @@ -178,7 +178,7 @@

- {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %} To remove these restrictions, you can send us a request to go live. {% else %} diff --git a/app/templates/views/service-settings/email_reply_to.html b/app/templates/views/service-settings/email_reply_to.html index 3e4a1450d..fb6d1ba02 100644 --- a/app/templates/views/service-settings/email_reply_to.html +++ b/app/templates/views/service-settings/email_reply_to.html @@ -36,7 +36,7 @@

- {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %} Change {{ item.email_address }} @@ -55,7 +55,7 @@
- {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %}
{{ usaButton({ "element": "a", diff --git a/app/templates/views/service-settings/sms-senders.html b/app/templates/views/service-settings/sms-senders.html index 98d00b2e9..dc23ce7bc 100644 --- a/app/templates/views/service-settings/sms-senders.html +++ b/app/templates/views/service-settings/sms-senders.html @@ -38,7 +38,7 @@
- {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %} Change {{ item.sms_sender }} @@ -52,7 +52,7 @@ {% endfor %}
- {% if current_user.has_permissions('manage_service') %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) %}
{{ usaButton({ diff --git a/app/templates/views/templates/_template.html b/app/templates/views/templates/_template.html index 73c94a9bc..1faddd5c1 100644 --- a/app/templates/views/templates/_template.html +++ b/app/templates/views/templates/_template.html @@ -8,7 +8,7 @@

This template was deleted {{ template._template.updated_at|format_datetime_relative }}.

- {% elif not current_user.has_permissions('send_messages', 'manage_api_keys', 'manage_templates', 'manage_service') or not user_has_template_permission %} + {% elif not current_user.has_permissions(ServicePermission.SEND_MESSAGES, 'manage_api_keys', 'manage_templates', ServicePermission.MANAGE_SERVICE) or not user_has_template_permission %}

If you need to send this {{ 1|message_count_label(template.template_type, suffix='') }} @@ -17,7 +17,7 @@ {% else %}

- {% if current_user.has_permissions('send_messages', restrict_admin_usage=True) %} + {% if current_user.has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) %} Use this template diff --git a/app/templates/views/templates/manage-template-folder.html b/app/templates/views/templates/manage-template-folder.html index 42a3cbf7c..b72760e5d 100644 --- a/app/templates/views/templates/manage-template-folder.html +++ b/app/templates/views/templates/manage-template-folder.html @@ -25,7 +25,7 @@ {{ form.name(param_extensions={ "classes": "" }) }} - {% if current_user.has_permissions("manage_service") and form.users_with_permission.all_service_users %} + {% if current_user.has_permissions(ServicePermission.MANAGE_SERVICE) and form.users_with_permission.all_service_users %} {{ form.users_with_permission }} {% endif %} diff --git a/app/utils/__init__.py b/app/utils/__init__.py index b9aaaaa88..e70441b04 100644 --- a/app/utils/__init__.py +++ b/app/utils/__init__.py @@ -7,7 +7,7 @@ from ordered_set import OrderedSet from werkzeug.datastructures import MultiDict from werkzeug.routing import RequestRedirect -from app.enums import NotificationStatus +from app.enums import NotificationStatus, ServicePermission from notifications_utils.field import Field SENDING_STATUSES = [ @@ -83,7 +83,7 @@ def unicode_truncate(s, length): def should_skip_template_page(db_template): return ( - current_user.has_permissions("send_messages") + current_user.has_permissions(ServicePermission.SEND_MESSAGES) and not current_user.has_permissions("manage_templates", "manage_api_keys") and not db_template["archived"] ) diff --git a/app/utils/user_permissions.py b/app/utils/user_permissions.py index 6f86813f2..546163d93 100644 --- a/app/utils/user_permissions.py +++ b/app/utils/user_permissions.py @@ -1,10 +1,12 @@ from itertools import chain +from app.enums import ServicePermission + permission_mappings = { # TODO: consider turning off email-sending permissions during SMS pilot - "send_messages": ["send_texts", "send_emails"], + ServicePermission.SEND_MESSAGES: ["send_texts", "send_emails"], "manage_templates": ["manage_templates"], - "manage_service": ["manage_users", "manage_settings"], + ServicePermission.MANAGE_SERVICE: ["manage_users", "manage_settings"], "manage_api_keys": ["manage_api_keys"], "view_activity": ["view_activity"], } @@ -14,9 +16,9 @@ all_db_permissions = set(chain(*permission_mappings.values())) permission_options = ( ("view_activity", "See dashboard"), - ("send_messages", "Send messages"), + (ServicePermission.SEND_MESSAGES, "Send messages"), ("manage_templates", "Add and edit templates"), - ("manage_service", "Manage settings, team and usage"), + (ServicePermission.MANAGE_SERVICE, "Manage settings, team and usage"), )