diff --git a/.travis.yml b/.travis.yml index 50eecec26..030da3e0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,6 +41,27 @@ deploy: deployment_group: notifications_admin_deployment_group region: eu-west-1 on: *2 +- provider: s3 + access_key_id: AKIAJ5MKF6G3P2JQP4QQ + secret_access_key: &1 + secure: xfjg4kNBvU0B9xhRETr14mB0bCpVonlAKqGnKL2AoqpnF19yihqGNA8sv/pOGUFpeWZO3cW2GA3anyL2gGG1X0K3f81649mneVJkSHaZ2fiG/S1eKtS0Ws5XblSqLmKTPC7H9ndUxT8r+r2wLg62netBE5g8tAxw2QwN/gVz2fK/68owiyeD/jl6gw/iQ47F+mmGdAY/eFe8sUuGR4Oxj2xNAYARaDQOmHpQF/IG3M69FO5uOJtck8fUWnpd0rWxsyWBOVwwIRQHL6cWOyodeIK7YvLmzviCi1GojBPKQwQbjJu89LHfMJJTW1625drj5CNounuENTFte0Pip8zp90bg090VA8OlTXNWcyFjBQD1vNIE59vyQ/hCh90NK1nlTXdnNOwL0VZTMxQ/zYulXoMqwDLfDozhQbmnkXmexJl6BF4/dz+XmwDu7st5A/PI6U5zCK86ST/6g3MklGSseFi5Rkt6kmJrdlRIhiLnoaab8YgI0FPWjzHBC6B98ZtgIUiUk7Ng5ZTM8Sjq1HCC7mUDrDL0c7aerZA5bq2hQiKGhvjBXFU17iHZ0eEDZ8kO+jumeMwmpW6NbjlS0PuDx+lHywMSG7r+YVmkjxq5gwrTVl3evRxhHe8H/lU18y2dOKpIyX5UEZpXRq9kAWuQruCDBwoDe3Y3QP+Rg7HVGBU= + local_dir: dpl_cd_upload + skip_cleanup: true + on: &2 + repo: alphagov/notifications-admin + branch: live + bucket: live-notifications-api-codedeploy + region: eu-west-1 +- provider: codedeploy + access_key_id: AKIAJ5MKF6G3P2JQP4QQ + secret_access_key: *1 + bucket: live-notifications-api-codedeploy + key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip + bundle_type: zip + application: notifications-admin + deployment_group: live_notifications_admin_deployment_group + region: eu-west-1 + on: *2 - provider: s3 access_key_id: AKIAJQPPNM6P6V53SWKA secret_access_key: &1 diff --git a/app.py b/app.py index 445f95cd5..1710069ca 100644 --- a/app.py +++ b/app.py @@ -3,7 +3,7 @@ from flask.ext.script import Manager, Server from app import create_app -application = create_app(os.getenv('NOTIFICATIONS_ADMIN_ENVIRONMENT') or 'development') +application = create_app() manager = Manager(application) port = int(os.environ.get('PORT', 6012)) manager.add_command("runserver", Server(host='0.0.0.0', port=port)) diff --git a/app/__init__.py b/app/__init__.py index 3255f7b5b..17df9f221 100644 --- a/app/__init__.py +++ b/app/__init__.py @@ -20,11 +20,11 @@ from app.notify_client.job_api_client import JobApiClient from app.notify_client.notification_api_client import NotificationApiClient from app.notify_client.status_api_client import StatusApiClient from app.notify_client.invite_api_client import InviteApiClient +from app.notify_client.statistics_api_client import StatisticsApiClient from app.its_dangerous_session import ItsdangerousSessionInterface from app.asset_fingerprinter import AssetFingerprinter from utils.recipients import validate_phone_number, InvalidPhoneError import app.proxy_fix -from config import configs from utils import logging login_manager = LoginManager() @@ -37,15 +37,16 @@ job_api_client = JobApiClient() notification_api_client = NotificationApiClient() status_api_client = StatusApiClient() invite_api_client = InviteApiClient() +statistics_api_client = StatisticsApiClient() asset_fingerprinter = AssetFingerprinter() -def create_app(config_name, config_overrides=None): +def create_app(): application = Flask(__name__) - application.config['NOTIFY_ADMIN_ENVIRONMENT'] = config_name - application.config.from_object(configs[config_name]) - init_app(application, config_overrides) + application.config.from_object(os.environ['NOTIFY_ADMIN_ENVIRONMENT']) + + init_app(application) logging.init_app(application) init_csrf(application) @@ -56,6 +57,7 @@ def create_app(config_name, config_overrides=None): notification_api_client.init_app(application) status_api_client.init_app(application) invite_api_client.init_app(application) + statistics_api_client.init_app(application) login_manager.init_app(application) login_manager.login_view = 'main.sign_in' @@ -103,22 +105,12 @@ def init_csrf(application): abort(400, reason) -def init_app(app, config_overrides): - - if config_overrides: - for key in app.config.keys(): - if key in config_overrides: - app.config[key] = config_overrides[key] - - for key, value in app.config.items(): - if key in os.environ: - app.config[key] = convert_to_boolean(os.environ[key]) - - @app.context_processor +def init_app(application): + @application.context_processor def inject_global_template_variables(): return { 'asset_path': '/static/', - 'header_colour': app.config['HEADER_COLOUR'], + 'header_colour': application.config['HEADER_COLOUR'], 'asset_url': asset_fingerprinter.get_url } diff --git a/app/assets/images/tick-black.png b/app/assets/images/tick-black.png new file mode 100644 index 000000000..dd050c6c7 Binary files /dev/null and b/app/assets/images/tick-black.png differ diff --git a/app/assets/stylesheets/_grids.scss b/app/assets/stylesheets/_grids.scss index 490f4d01d..f0008d51e 100644 --- a/app/assets/stylesheets/_grids.scss +++ b/app/assets/stylesheets/_grids.scss @@ -2,6 +2,10 @@ @include grid-column(3/4); } +.column-one-sixth { + @include grid-column(1/6); +} + .column-one-eighth { @include grid-column(1/8); } @@ -16,7 +20,7 @@ } .bottom-gutter-2-3 { - margin-bottom: $gutter * 2/3; + margin-bottom: $gutter-two-thirds; } .align-with-heading { @@ -26,3 +30,19 @@ padding-left: 2px; padding-right: 2px; } + +.global-cookie-message { + p { + @extend %site-width-container; + } +} + +.footer-nav { + @include copy-16; + margin-bottom: $gutter-two-thirds; + + a { + display: inline-block; + margin-right: $gutter-half; + } +} diff --git a/app/assets/stylesheets/app.scss b/app/assets/stylesheets/app.scss index d7eeacb62..d2d7fb838 100644 --- a/app/assets/stylesheets/app.scss +++ b/app/assets/stylesheets/app.scss @@ -80,3 +80,11 @@ a { } } + +td { + vertical-align: top; +} + +.heading-xlarge { + margin-bottom: 20px; +} diff --git a/app/assets/stylesheets/components/banner.scss b/app/assets/stylesheets/components/banner.scss index 884523bdd..540ce1e38 100644 --- a/app/assets/stylesheets/components/banner.scss +++ b/app/assets/stylesheets/components/banner.scss @@ -26,9 +26,8 @@ } -.banner-with-tick, -.banner-default-with-tick { - @extend %banner; +%banner-with-tick, +.banner-with-tick { padding: $gutter-half ($gutter + $gutter-half); background-image: file-url('tick-white.png'); background-size: 19px; @@ -37,6 +36,11 @@ font-weight: bold; } +.banner-default-with-tick { + @extend %banner; + @extend %banner-with-tick; +} + .banner-dangerous { @extend %banner; @@ -54,13 +58,15 @@ } +%banner-tip, .banner-tip { @extend %banner; - background: $yellow; + @include bold-19; + background-color: $yellow; color: $text-colour; text-align: left; - font-weight: bold; + margin-top: 0; a { &:link, @@ -76,6 +82,12 @@ } +.banner-tip-with-tick { + @extend %banner-with-tick; + @extend %banner-tip; + background-image: file-url('tick-black.png'); +} + .banner-info, .banner-important { @extend %banner; @@ -91,3 +103,40 @@ .banner-info { background-image: file-url('icon-information-2x.png'); } + +.banner-mode { + + @extend %banner; + background: $govuk-blue; + color: $white; + margin-top: $gutter; + + .heading-medium { + margin: 0 0 10px 0; + } + + a { + + &:link, + &:visited { + color: $white; + } + + &:hover, + &:active { + color: $light-blue-25; + } + + } + + .big-number { + + margin-top: 10px; + + &-label { + padding-bottom: 0; + } + + } + +} diff --git a/app/assets/stylesheets/components/big-number.scss b/app/assets/stylesheets/components/big-number.scss index 0bce53b25..a14f30d9b 100644 --- a/app/assets/stylesheets/components/big-number.scss +++ b/app/assets/stylesheets/components/big-number.scss @@ -1,3 +1,4 @@ +%big-number, .big-number { @include bold-48($tabular-numbers: true); @@ -5,6 +6,62 @@ &-label { @include core-19; display: block; + padding-bottom: $gutter-half; + } + +} + +.big-number-with-status { + + @extend %big-number; + background: $text-colour; + color: $white; + + .big-number { + padding: 15px; + } + + .big-number-label { + padding-bottom: 0; + } + + .big-number-status { + + display: block; + background: $green; + position: relative; + + &-error-percentage { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: $error-colour; + z-index: 1; + } + + a { + + &:link, + &:visited, + &:active, + &:hover { + color: $white; + } + + } + + .big-number { + @include bold-19; + position: relative; + z-index: 2; + } + + .big-number-label { + display: inline; + } + } } diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index f681faa45..6fc17c49c 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -8,7 +8,7 @@ from flask_login import login_required from app.main import main from app.main.dao.services_dao import get_service_by_id from app.main.dao import templates_dao -from app import job_api_client +from app import job_api_client, statistics_api_client @main.route("/services//dashboard") @@ -27,11 +27,37 @@ def service_dashboard(service_id): message = 'You have successfully accepted your invitation and been added to {}'.format(service_name) flash(message, 'default_with_tick') + statistics = statistics_api_client.get_statistics_for_service(service_id)['data'] + return render_template( - 'views/service_dashboard.html', + 'views/dashboard/dashboard.html', jobs=jobs[:5], more_jobs_to_show=(len(jobs) > 5), free_text_messages_remaining='250,000', spent_this_month='0.00', - template_count=len(templates), + service=service['data'], + statistics=expand_statistics(statistics), + templates=templates, service_id=str(service_id)) + + +def expand_statistics(statistics, danger_zone=25): + + if not statistics or not statistics[0]: + return {} + + today = statistics[0] + + today.update({ + 'emails_failure_rate': + int(today['emails_error'] / today['emails_requested'] * 100) if today['emails_requested'] else 0, + 'sms_failure_rate': + int(today['sms_error'] / today['sms_requested'] * 100) if today['sms_requested'] else 0 + }) + + today.update({ + 'emails_percentage_of_danger_zone': min(today['emails_failure_rate'] / (danger_zone / 100), 100), + 'sms_percentage_of_danger_zone': min(today['sms_failure_rate'] / (danger_zone / 100), 100) + }) + + return today diff --git a/app/main/views/index.py b/app/main/views/index.py index 5f7d700df..47780a1e7 100644 --- a/app/main/views/index.py +++ b/app/main/views/index.py @@ -16,3 +16,13 @@ def index(): @login_required def verify_mobile(): return render_template('views/verify-mobile.html') + + +@main.route('/cookies') +def cookies(): + return render_template('views/cookies.html') + + +@main.route('/help') +def help(): + return render_template('views/help.html') diff --git a/app/notify_client/statistics_api_client.py b/app/notify_client/statistics_api_client.py new file mode 100644 index 000000000..9ef40bbd6 --- /dev/null +++ b/app/notify_client/statistics_api_client.py @@ -0,0 +1,18 @@ +from notifications_python_client.base import BaseAPIClient + + +class StatisticsApiClient(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 get_statistics_for_service(self, service_id): + return self.get( + url='/service/{}/notifications-statistics'.format(service_id), + ) diff --git a/app/templates/admin_template.html b/app/templates/admin_template.html index bd1eba398..666add0bb 100644 --- a/app/templates/admin_template.html +++ b/app/templates/admin_template.html @@ -24,6 +24,10 @@ {% endblock %} {% block cookie_message %} +

+ GOV.UK Notify uses cookies to make the site simpler. + Find out more about cookies +

{% endblock %} {% block inside_header %} @@ -68,6 +72,15 @@ {% endblock %} +{% block footer_support_links %} + +{% endblock %} + {% block body_end %} {% endblock %} diff --git a/app/templates/components/banner.html b/app/templates/components/banner.html index 0c0ef7abc..d008b5b57 100644 --- a/app/templates/components/banner.html +++ b/app/templates/components/banner.html @@ -1,19 +1,9 @@ {% macro banner(body, type=None, with_tick=False, delete_button=None, subhead=None) %}
- {% if subhead %} -
-
- {{ subhead }} -
-
- {% endif %} - + {% if subhead -%} + {{ subhead }}  + {%- endif -%} {{ body }} - - {% if subhead %} -
-
- {% endif %} {% if delete_button %}
diff --git a/app/templates/components/big-number.html b/app/templates/components/big-number.html index 089466c25..9ee6affb9 100644 --- a/app/templates/components/big-number.html +++ b/app/templates/components/big-number.html @@ -4,3 +4,14 @@ {{ label }}
{% endmacro %} + + +{% macro big_number_with_status(number, label, status_number, status_label, percentage_bad=0) %} +
+ {{ big_number(number, label) }} +
+
+ {{ big_number(status_number, status_label) }} +
+
+{% endmacro %} diff --git a/app/templates/views/choose-template.html b/app/templates/views/choose-template.html index a5d28fd88..e4c58e947 100644 --- a/app/templates/views/choose-template.html +++ b/app/templates/views/choose-template.html @@ -37,9 +37,9 @@ {% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters'], or_=True) %} {{ banner( """ - Send yourself a test message + Send yourself a test """, - subhead='Next step', + subhead='Next step:', type="tip" )}} {% endif %} diff --git a/app/templates/views/cookies.html b/app/templates/views/cookies.html new file mode 100644 index 000000000..6337c1f77 --- /dev/null +++ b/app/templates/views/cookies.html @@ -0,0 +1,81 @@ +{% extends "withoutnav_template.html" %} + +{% block page_title %} + Cookies – GOV.UK Notify +{% endblock %} + +{% block maincolumn_content %} + +
+
+

Cookies

+

+ GOV.UK Notify puts small files (known as ‘cookies’) + on to your computer. +

+

These cookies are used to remember you once you’ve logged in

+

+ Find out how to manage cookies. +

+ +

Session cookies

+

+ We store session cookies on your computer to help keep your information + secure while you use the service. +

+ + + + + + + + + + + + + + + +
NamePurposeExpires
+ notify_admin_session + + Used to keep you logged in + + 1 hour +
+ +

Introductory message cookie

+

+ When you first use the service, you may see a pop-up ‘welcome’ message. + Once you’ve seen the message, we store a cookie on your computer so it + knows not to show it again. +

+ + + + + + + + + + + + + + + +
NamePurposeExpires
+ seen_cookie_message + + Saves a message to let us know that you have seen our cookie + message + + 1 month +
+
+
+ +{% endblock %} diff --git a/app/templates/views/dashboard/dashboard.html b/app/templates/views/dashboard/dashboard.html new file mode 100644 index 000000000..67fb31a53 --- /dev/null +++ b/app/templates/views/dashboard/dashboard.html @@ -0,0 +1,20 @@ +{% extends "withnav_template.html" %} + +{% block page_title %} + {{ session.get('service_name', 'Dashboard') }} – GOV.UK Notify +{% endblock %} + +{% block maincolumn_content %} + + {% if service.restricted %} + {% include 'views/dashboard/trial-mode-banner.html' %} + {% endif %} + + {% if not jobs %} + {% include 'views/dashboard/get-started.html' %} + {% else %} + {% include 'views/dashboard/today.html' %} + {% include 'views/dashboard/jobs.html' %} + {% endif %} + +{% endblock %} diff --git a/app/templates/views/dashboard/get-started.html b/app/templates/views/dashboard/get-started.html new file mode 100644 index 000000000..d1b8adc01 --- /dev/null +++ b/app/templates/views/dashboard/get-started.html @@ -0,0 +1,19 @@ +{% from "components/banner.html" import banner_wrapper %} + +

Get started

+
    + {% if current_user.has_permissions(['manage_templates']) %} +
  1. + {% call banner_wrapper(type="tip", subhead='1.' if not templates else None, with_tick=templates|length) %} + Add a template + {% endcall %} +
  2. + {% endif %} + {% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %} +
  3. + {% call banner_wrapper(type="tip", subhead='2.') %} + Send yourself a message + {% endcall %} +
  4. + {% endif %} +
diff --git a/app/templates/views/dashboard/jobs.html b/app/templates/views/dashboard/jobs.html new file mode 100644 index 000000000..941bb51cc --- /dev/null +++ b/app/templates/views/dashboard/jobs.html @@ -0,0 +1,28 @@ +{% from "components/table.html" import list_table, field, right_aligned_field_heading, hidden_field_heading %} + +{% call(item) list_table( + jobs, + caption="Recent batch jobs", + empty_message='You haven’t sent any text messages yet', + field_headings=['File', 'Started', right_aligned_field_heading('Rows'), right_aligned_field_heading('Sent')] +) %} + {% call field() %} + {{ item.original_file_name }} + {% endcall %} + {% call field() %} + {{ item.created_at|format_datetime }} + {% endcall %} + {% call field(align='right') %} + {{ item.notification_count }} + {% endcall %} + {% call field(align='right') %} + {{ item.notifications_sent }} + {% endcall %} +{% endcall %} +{% if more_jobs_to_show %} + {% if current_user.has_permissions(['send_texts', 'send_emails', 'send_letters']) %} + + {% endif %} +{% endif %} diff --git a/app/templates/views/dashboard/today.html b/app/templates/views/dashboard/today.html new file mode 100644 index 000000000..bc1d13abf --- /dev/null +++ b/app/templates/views/dashboard/today.html @@ -0,0 +1,25 @@ +{% from "components/big-number.html" import big_number_with_status %} + +

+ Sent today +

+
+
+ {{ big_number_with_status( + statistics.get('emails_requested', 0), + 'email' if statistics.get('emails_requested') == 1 else 'emails', + '{}%'.format(statistics.get('emails_failure_rate', 0)), + 'failed', + statistics.get('emails_percentage_of_danger_zone', 0) + ) }} +
+
+ {{ big_number_with_status( + statistics.get('sms_requested', 0), + 'text message' if statistics.get('sms_requested') == 1 else 'text messages', + '{}%'.format(statistics.get('sms_failure_rate', 0)), + 'failed', + statistics.get('sms_percentage_of_danger_zone', 0) + ) }} +
+
diff --git a/app/templates/views/dashboard/trial-mode-banner.html b/app/templates/views/dashboard/trial-mode-banner.html new file mode 100644 index 000000000..3a3c34829 --- /dev/null +++ b/app/templates/views/dashboard/trial-mode-banner.html @@ -0,0 +1,25 @@ +{% from "components/banner.html" import banner_wrapper %} +{% from "components/big-number.html" import big_number %} + +{% call banner_wrapper(type="mode") %} + +

Trial mode

+
+
+

+ We’ll only deliver messages to you and members of your team +
+ Find out more +

+
+
+   +
+
+ {{ big_number( + service.limit - statistics.get('emails_requested', 0) - statistics.get('sms_requested', 0), + 'messages left today' + ) }} +
+
+{% endcall %} diff --git a/app/templates/views/help.html b/app/templates/views/help.html new file mode 100644 index 000000000..72ef617b3 --- /dev/null +++ b/app/templates/views/help.html @@ -0,0 +1,79 @@ +{% extends "withoutnav_template.html" %} + +{% block page_title %} + Cookies – GOV.UK Notify +{% endblock %} + +{% block maincolumn_content %} + +
+
+

Help

+ +

Trial mode

+ +

+ When you create a service on GOV.UK Notify, you start off in trial + mode. This means: +

+
    +
  • + you can only send messages to yourself and your team members +
  • +
  • + you can only send 50 messages per day +
  • +
+ +

+ Anyone working in central government can create an account on + GOV.UK Notify and try it out. So it’s important that you start off + with some restrictions in place. +

+ +

To remove these restrictions

+ +

+ You need to request to go live: +

+
    +
  • + You’ll need to agree to our terms of use +
  • +
  • + If you plan to send more than 250,000 text messages per year, you’ll + need to agree to pay for what you use – take a look at our pricing +
  • +
  • + We’ll check your templates to make sure they’re consistent with our + design patterns, style guide and information security principles +
  • +
+ +

+ All other aspects of GOV.UK Notify are exactly the same +

+ +

+ You can still: +

+
    +
  • + upload a batch of recipients +
  • +
  • + do an API integration +
  • +
+ +

+ We’ll send the messages you have permission to send. The messages you + don’t have permission to send will still be listed on your + GOV.UK Notify dashboard but won’t actually get sent. This means you + can check that everything is fully working without accidentally sending + hundreds of text messages or emails. +

+
+
+ +{% endblock %} diff --git a/config.py b/config.py index 019917aa4..579ec4bef 100644 --- a/config.py +++ b/config.py @@ -28,8 +28,6 @@ class Config(object): REMEMBER_COOKIE_SECURE = True API_HOST_NAME = os.getenv('API_HOST_NAME') - NOTIFY_API_SECRET = os.getenv('NOTIFY_API_SECRET', "dev-secret") - NOTIFY_API_CLIENT = os.getenv('NOTIFY_API_CLIENT', "admin") ADMIN_CLIENT_USER_NAME = os.getenv('ADMIN_CLIENT_USER_NAME') ADMIN_CLIENT_SECRET = os.getenv('ADMIN_CLIENT_SECRET') @@ -73,18 +71,10 @@ class Preview(Config): HEADER_COLOUR = '#F47738' # $orange -class Staging(Preview): - SHOW_STYLEGUIDE = False - - -class Live(Staging): - HEADER_COLOUR = '#B10E1E' # $red - - configs = { - 'development': Development, - 'test': Test, - 'preview': Preview, - 'staging': Staging, - 'live': Live + 'development': 'config.Development', + 'test': 'config.Test', + 'preview': 'config.Preview', + 'staging': 'config_staging.Staging', + 'live': 'config_live.Live' } diff --git a/config_live.py b/config_live.py new file mode 100644 index 000000000..5a3b64116 --- /dev/null +++ b/config_live.py @@ -0,0 +1,12 @@ +import os +from config import Config + + +class Live(Config): + SHOW_STYLEGUIDE = False + HEADER_COLOUR = '#B10E1E' # $red + HTTP_PROTOCOL = 'https' + API_HOST_NAME = os.getenv('LIVE_API_HOST_NAME') + ADMIN_CLIENT_SECRET = os.getenv('LIVE_ADMIN_CLIENT_SECRET') + SECRET_KEY = os.getenv('LIVE_SECRET_KEY') + DANGEROUS_SALT = os.getenv('LIVE_DANGEROUS_SALT') diff --git a/config_staging.py b/config_staging.py new file mode 100644 index 000000000..5ce68b304 --- /dev/null +++ b/config_staging.py @@ -0,0 +1,11 @@ +import os +from config import Config + + +class Staging(Config): + SHOW_STYLEGUIDE = False + HTTP_PROTOCOL = 'https' + API_HOST_NAME = os.getenv('STAGING_API_HOST_NAME') + ADMIN_CLIENT_SECRET = os.getenv('STAGING_ADMIN_CLIENT_SECRET') + SECRET_KEY = os.getenv('STAGING_SECRET_KEY') + DANGEROUS_SALT = os.getenv('STAGING_DANGEROUS_SALT') diff --git a/scripts/run_app.sh b/scripts/run_app.sh index 96947cc19..9236e8642 100755 --- a/scripts/run_app.sh +++ b/scripts/run_app.sh @@ -1,3 +1,4 @@ #!/bin/bash +export NOTIFY_ADMIN_ENVIRONMENT='config.Development' python3 app.py runserver diff --git a/scripts/run_tests.sh b/scripts/run_tests.sh index af5971aa8..bc80a179e 100755 --- a/scripts/run_tests.sh +++ b/scripts/run_tests.sh @@ -32,5 +32,6 @@ display_result $? 2 "Front end code style check" #py.test --cov=app tests/ #display_result $? 3 "Code coverage" +export NOTIFY_ADMIN_ENVIRONMENT='config.Test' py.test -v display_result $? 4 "Unit tests" diff --git a/tests/app/main/notify_client/test_statistics_client.py b/tests/app/main/notify_client/test_statistics_client.py new file mode 100644 index 000000000..3dc24c16a --- /dev/null +++ b/tests/app/main/notify_client/test_statistics_client.py @@ -0,0 +1,13 @@ +from app.notify_client.statistics_api_client import StatisticsApiClient + + +def test_client_uses_correct_find_by_email(mocker, api_user_active): + + expected_url = '/service/a1b2c3d4/notifications-statistics' + + client = StatisticsApiClient() + mock_get = mocker.patch('app.notify_client.statistics_api_client.StatisticsApiClient.get') + + client.get_statistics_for_service('a1b2c3d4') + + mock_get.assert_called_once_with(url=expected_url) diff --git a/tests/app/main/views/test_accept_invite.py b/tests/app/main/views/test_accept_invite.py index e38f150ec..cb2133f38 100644 --- a/tests/app/main/views/test_accept_invite.py +++ b/tests/app/main/views/test_accept_invite.py @@ -175,7 +175,7 @@ def test_new_user_accept_invite_calls_api_and_views_registration_page(app_, page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser') assert page.h1.string.strip() == 'Create an account' - email_in_page = page.find('p') + email_in_page = page.find('main').find('p') assert email_in_page.text.strip() == 'Your account will be created with this email: invited_user@test.gov.uk' # noqa form = page.find('form') @@ -275,6 +275,7 @@ def test_new_invited_user_verifies_and_added_to_service(app_, mock_accept_invite, mock_get_service, mock_get_service_templates, + mock_get_service_statistics, mock_get_jobs): with app_.test_request_context(): diff --git a/tests/app/main/views/test_dashboard.py b/tests/app/main/views/test_dashboard.py index 0902f6293..9594f0072 100644 --- a/tests/app/main/views/test_dashboard.py +++ b/tests/app/main/views/test_dashboard.py @@ -6,6 +6,7 @@ def test_should_show_recent_jobs_on_dashboard(app_, api_user_active, mock_get_service, mock_get_service_templates, + mock_get_service_statistics, mock_get_user, mock_get_user_by_email, mock_login, @@ -34,6 +35,7 @@ def _test_dashboard_menu(mocker, app_, usr, service, permissions): mocker.patch('app.user_api_client.get_user', return_value=usr) mocker.patch('app.user_api_client.get_user_by_email', return_value=usr) mocker.patch('app.notifications_api_client.get_service', return_value={'data': service}) + mocker.patch('app.statistics_api_client.get_statistics_for_service', return_value={'data': [{}]}) client.login(usr) return client.get(url_for('main.service_dashboard', service_id=service['id'])) diff --git a/tests/app/main/views/test_sign_out.py b/tests/app/main/views/test_sign_out.py index a6b8e5fcb..1d4860a71 100644 --- a/tests/app/main/views/test_sign_out.py +++ b/tests/app/main/views/test_sign_out.py @@ -16,6 +16,7 @@ def test_sign_out_user(app_, mock_get_user, mock_get_user_by_email, mock_get_service_templates, + mock_get_service_statistics, mock_login, mock_get_jobs): with app_.test_request_context(): diff --git a/tests/conftest.py b/tests/conftest.py index f9693fe2c..e9fa4173f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -24,7 +24,7 @@ from notifications_python_client.errors import HTTPError @pytest.fixture(scope='session') def app_(request): - app = create_app('test') + app = create_app() ctx = app.app_context() ctx.push() @@ -154,6 +154,15 @@ def mock_delete_service(mocker, mock_get_service): 'app.notifications_api_client.delete_service', side_effect=_delete) +@pytest.fixture(scope='function') +def mock_get_service_statistics(mocker): + def _create(service_id): + return {'data': [{}]} + + return mocker.patch( + 'app.statistics_api_client.get_statistics_for_service', side_effect=_create) + + @pytest.fixture(scope='function') def mock_get_service_template(mocker): def _create(service_id, template_id): diff --git a/wsgi.py b/wsgi.py index fd773b3e0..dd2db3d10 100644 --- a/wsgi.py +++ b/wsgi.py @@ -1,17 +1,24 @@ -from app import create_app from credstash import getAllSecrets import os -config = 'live' default_env_file = '/home/ubuntu/environment' +environment = 'live' if os.path.isfile(default_env_file): - environment = open(default_env_file, 'r') - config = environment.readline().strip() + with open(default_env_file, 'r') as environment_file: + environment = environment_file.readline().strip() -secrets = getAllSecrets(region="eu-west-1") -application = create_app(config, secrets) +# on aws get secrets and export to env +os.environ.update(getAllSecrets(region="eu-west-1")) + +from config import configs + +os.environ['NOTIFY_ADMIN_ENVIRONMENT'] = configs[environment] + +from app import create_app + +application = create_app() if __name__ == "__main__": application.run()