From 5b073341a09d8e5bffb48475e1c9e4df6252b393 Mon Sep 17 00:00:00 2001 From: Chris Hill-Scott Date: Thu, 3 Mar 2016 07:41:53 +0000 Subject: [PATCH 1/3] Add frontend install and build to bootstrap script MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Now you don’t need to remember what the two commands are and when you need to run them, you can just run the bootstrap script instead. Makes sense to have them here since the `pip install` is also in here. --- README.md | 43 +++++++++++++++++-------------------------- scripts/bootstrap.sh | 2 ++ 2 files changed, 19 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index 6e0f3b741..23dd3de7a 100644 --- a/README.md +++ b/README.md @@ -4,52 +4,49 @@ # notifications-admin -Application to handle the admin functions of the notifications application. +GOV.UK Notify admin application. ## Features of this application - - Register users - - Register services - - Download CSV for an email or SMS batch + - Register and manage users + - Create and manage services + - Send batch emails and SMS by uploading a CSV - Show history of notifications - - Reports ## First-time setup -You need [Node](http://nodejs.org/) which will also get you [NPM](npmjs.org), -Node's package management tool. +Languages needed +- Python 3 +- [Node](http://nodejs.org/) 5.0.0 or greater ```shell brew install node ``` -n is a tool for managing different versions of node. The following installs n -and uses the latest version of node. +[NPM](npmjs.org) is Node's package management tool. `n` is a tool for managing +different versions of Node. The following installs `n` and uses the latest +version of Node. ```shell npm install -g n n latest npm rebuild node-sass ``` -The frontend dependencies are managed using NPM and Bower. To install or update -*all the things*, run -```shell - npm install - npm run build -``` - The app runs within a virtual environment. To [install virtualenv](https://virtualenv.readthedocs.org/en/latest/installation.html), run ```shell [sudo] pip install virtualenv ``` -To make a virtualenv for this app, run +Make a virtual environment for this app: ```shell mkvirtualenv -p /usr/local/bin/python3 notifications-admin - pip install -r requirements.txt +``` + +Install dependencies and build the frontend assets: +```shell ./scripts/bootstrap.sh ``` -## Building the frontend +## Rebuilding the frontend assets If you want the front end assets to re-compile on changes, leave this running in a separate terminal from the app @@ -64,10 +61,4 @@ in a separate terminal from the app ./scripts/run_app.sh ``` -Then visit [localhost:6012](localhost:6012) - -## Domain model - -All the domain models are defined in the -[models.py](https://github.com/alphagov/notifications-admin/blob/master/app/models.py) -file. +Then visit [localhost:6012](http://localhost:6012) diff --git a/scripts/bootstrap.sh b/scripts/bootstrap.sh index cd3ffb715..82274e091 100755 --- a/scripts/bootstrap.sh +++ b/scripts/bootstrap.sh @@ -27,3 +27,5 @@ fi # Install Python development dependencies pip3 install -r requirements_for_test.txt + +npm install && npm run build From 1f2fe2a1e4b1b0a8baca73d7b8db7ec9355cc469 Mon Sep 17 00:00:00 2001 From: Nicholas Staples Date: Thu, 3 Mar 2016 10:24:49 +0000 Subject: [PATCH 2/3] Fixed up client for permission setting. All tests passing. --- app/__init__.py | 3 --- app/notify_client/permission_api_client.py | 25 ---------------------- app/notify_client/user_api_client.py | 5 +++++ 3 files changed, 5 insertions(+), 28 deletions(-) delete mode 100644 app/notify_client/permission_api_client.py diff --git a/app/__init__.py b/app/__init__.py index b9e070318..f7f98a97b 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -15,7 +15,6 @@ from app.notify_client.api_key_api_client import ApiKeyApiClient from app.notify_client.user_api_client import UserApiClient from app.notify_client.job_api_client import JobApiClient from app.notify_client.status_api_client import StatusApiClient -from app.notify_client.permission_api_client import PermissionApiClient from app.notify_client.invite_api_client import InviteApiClient from app.its_dangerous_session import ItsdangerousSessionInterface from app.asset_fingerprinter import AssetFingerprinter @@ -34,7 +33,6 @@ job_api_client = JobApiClient() status_api_client = StatusApiClient() invite_api_client = InviteApiClient() asset_fingerprinter = AssetFingerprinter() -permission_api_client = PermissionApiClient() def create_app(config_name, config_overrides=None): @@ -51,7 +49,6 @@ def create_app(config_name, config_overrides=None): api_key_api_client.init_app(application) job_api_client.init_app(application) status_api_client.init_app(application) - permission_api_client.init_app(application) invite_api_client.init_app(application) login_manager.init_app(application) diff --git a/app/notify_client/permission_api_client.py b/app/notify_client/permission_api_client.py deleted file mode 100644 index a112251af..000000000 --- a/app/notify_client/permission_api_client.py +++ /dev/null @@ -1,25 +0,0 @@ -import uuid - -from notifications_python_client.base import BaseAPIClient - - -class PermissionApiClient(BaseAPIClient): - def __init__(self, base_url=None, client_id=None, secret=None): - super(self.__class__, self).__init__(base_url=base_url or 'base_url', - client_id=client_id or 'client_id', - secret=secret or 'secret') - - def init_app(self, app): - self.base_url = app.config['API_HOST_NAME'] - self.client_id = app.config['ADMIN_CLIENT_USER_NAME'] - self.secret = app.config['ADMIN_CLIENT_SECRET'] - - def delete_permission(self, permission_id): - return self.delete(url='/permission/{}'.format(permission_id))['data'] - - def create_permission(self, permission, user_id, service_id): - return self.post( - url='/permission', - data={'permission': permission, - 'user': user_id, - 'service': service_id})['data'] diff --git a/app/notify_client/user_api_client.py b/app/notify_client/user_api_client.py index 6b3450503..d825f079f 100644 --- a/app/notify_client/user_api_client.py +++ b/app/notify_client/user_api_client.py @@ -98,3 +98,8 @@ class UserApiClient(BaseAPIClient): endpoint = '/service/{}/users/{}'.format(service_id, user_id) resp = self.post(endpoint, data={}) return User(resp['data'], max_failed_login_count=self.max_failed_login_count) + + def set_user_permissions(self, user_id, service_id, permissions): + data = [{'permission': x} for x in permissions] + endpoint = '/user/{}/service/{}/permission'.format(user_id, service_id) + resp = self.post(endpoint, data=data) From 8287e1bad1fc010bb3a4c66997dd07fd364597e9 Mon Sep 17 00:00:00 2001 From: Nicholas Staples Date: Thu, 3 Mar 2016 12:15:24 +0000 Subject: [PATCH 3/3] Fix permission names, all tests passing. --- app/main/views/send.py | 17 +++++++++-------- app/main/views/service_settings.py | 16 ++++++++-------- app/templates/main_nav.html | 6 +++--- app/templates/views/choose-template.html | 4 ++-- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/app/main/views/send.py b/app/main/views/send.py index b622d526a..8f7aa93e9 100644 --- a/app/main/views/send.py +++ b/app/main/views/send.py @@ -31,7 +31,7 @@ from app.utils import ( from utils.process_csv import first_column_heading -manage_service_page_headings = { +send_messages_page_headings = { 'email': 'Send emails', 'sms': 'Send text messages' } @@ -44,8 +44,9 @@ manage_templates_page_headings = { def get_page_headings(template_type): - if current_user.has_permissions(['manage_service']): - return manage_service_page_headings[template_type] + # User has manage_service role + if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']): + return send_messages_page_headings[template_type] else: return manage_templates_page_headings[template_type] @@ -59,7 +60,7 @@ def letters_stub(service_id): @main.route("/services//send/", methods=['GET']) @login_required -@user_has_permissions('send_messages', 'manage_templates', or_=True) +@user_has_permissions('send_texts', 'send_emails', 'send_letters', 'manage_templates', or_=True) def choose_template(service_id, template_type): service = services_dao.get_service_by_id_or_404(service_id) @@ -92,7 +93,7 @@ def choose_template(service_id, template_type): @main.route("/services//send/", methods=['GET', 'POST']) @login_required -@user_has_permissions('send_messages') +@user_has_permissions('send_texts', 'send_emails', 'send_letters') def send_messages(service_id, template_id): form = CsvUploadForm() @@ -130,7 +131,7 @@ def send_messages(service_id, template_id): @main.route("/services//send/.csv", methods=['GET']) @login_required -@user_has_permissions('send_messages', 'manage_templates', or_=True) +@user_has_permissions('send_texts', 'send_emails', 'send_letters', 'manage_templates', or_=True) def get_example_csv(service_id, template_id): template = Template(templates_dao.get_service_template_or_404(service_id, template_id)['data']) output = io.StringIO() @@ -150,7 +151,7 @@ def get_example_csv(service_id, template_id): @main.route("/services//send//to-self", methods=['GET']) @login_required -@user_has_permissions('send_messages') +@user_has_permissions('send_texts', 'send_emails', 'send_letters') def send_message_to_self(service_id, template_id): template = Template(templates_dao.get_service_template_or_404(service_id, template_id)['data']) output = io.StringIO() @@ -186,7 +187,7 @@ def send_message_to_self(service_id, template_id): @main.route("/services//check/", methods=['GET', 'POST']) @login_required -@user_has_permissions('send_messages') +@user_has_permissions('send_texts', 'send_emails', 'send_letters') def check_messages(service_id, upload_id): upload_data = session['upload_data'] diff --git a/app/main/views/service_settings.py b/app/main/views/service_settings.py index df2b1f2f7..b813b4f5a 100644 --- a/app/main/views/service_settings.py +++ b/app/main/views/service_settings.py @@ -13,7 +13,7 @@ from notifications_python_client.errors import HTTPError @main.route("/services//service-settings") @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_settings(service_id): try: service = get_service_by_id(service_id)['data'] @@ -31,7 +31,7 @@ def service_settings(service_id): @main.route("/services//service-settings/name", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_name_change(service_id): try: service = get_service_by_id(service_id)['data'] @@ -56,7 +56,7 @@ def service_name_change(service_id): @main.route("/services//service-settings/name/confirm", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_name_change_confirm(service_id): try: service = get_service_by_id(service_id)['data'] @@ -86,7 +86,7 @@ def service_name_change_confirm(service_id): @main.route("/services//service-settings/request-to-go-live", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_request_to_go_live(service_id): try: service = get_service_by_id(service_id)['data'] @@ -109,7 +109,7 @@ def service_request_to_go_live(service_id): @main.route("/services//service-settings/status", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_status_change(service_id): try: service = get_service_by_id(service_id)['data'] @@ -131,7 +131,7 @@ def service_status_change(service_id): @main.route("/services//service-settings/status/confirm", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_status_change_confirm(service_id): try: service = get_service_by_id(service_id)['data'] @@ -160,7 +160,7 @@ def service_status_change_confirm(service_id): @main.route("/services//service-settings/delete", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_delete(service_id): try: service = get_service_by_id(service_id)['data'] @@ -182,7 +182,7 @@ def service_delete(service_id): @main.route("/services//service-settings/delete/confirm", methods=['GET', 'POST']) @login_required -@user_has_permissions('manage_service') +@user_has_permissions('manage_settings') def service_delete_confirm(service_id): try: service = get_service_by_id(service_id)['data'] diff --git a/app/templates/main_nav.html b/app/templates/main_nav.html index 96a360727..3f2727e40 100644 --- a/app/templates/main_nav.html +++ b/app/templates/main_nav.html @@ -2,7 +2,7 @@ - {% if current_user.has_permissions(['send_messages']) %} + {% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %} {% endif %} - {% if current_user.has_permissions(['manage_service']) %} + {% if current_user.has_permissions(['manage_users', 'manage_settings']) %} {% endif %} - {% if current_user.has_permissions(['manage_api_keys']) %} + {% if current_user.has_permissions(['manage_api_keys', 'access_developer_docs']) %}
  • API keys
  • Developer documentation
  • diff --git a/app/templates/views/choose-template.html b/app/templates/views/choose-template.html index bf6f08f12..00b4cbc2f 100644 --- a/app/templates/views/choose-template.html +++ b/app/templates/views/choose-template.html @@ -16,7 +16,7 @@ {% if templates %} {% if not has_jobs %} - {% if current_user.has_permissions(['manage_service']) %} + {% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters'], or_=True) %} {{ banner( """ Send yourself a test message @@ -41,7 +41,7 @@