diff --git a/.gitignore b/.gitignore index 2ff4784bb..8d5a836e2 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,6 @@ app/templates/govuk_template.html npm-debug.log environment.sh +.envrc + +app/version.py diff --git a/.travis.yml b/.travis.yml index e353329e3..9a0a62f10 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,7 @@ after_success: - coveralls - ./scripts/trigger-dependent-build.sh script: +- make generate-version-file - npm run build - ./scripts/run_tests.sh notifications: @@ -88,7 +89,6 @@ deploy: region: eu-west-1 on: *2 before_deploy: - - ./scripts/update_version_file.sh - rm -rf node_modules bower_components app/assets - zip -r --exclude=*__pycache__* notifications-admin * - mkdir -p dpl_cd_upload diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..f046f9c04 --- /dev/null +++ b/Makefile @@ -0,0 +1,128 @@ +.DEFAULT_GOAL := help +SHELL := /bin/bash +DATE = $(shell date +%Y-%m-%d:%H:%M:%S) + +PIP_ACCEL_CACHE ?= ${CURDIR}/cache/pip-accel +APP_VERSION_FILE = app/version.py + +GIT_BRANCH = $(shell git symbolic-ref --short HEAD 2> /dev/null || echo "detached") +GIT_COMMIT ?= $(shell git rev-parse HEAD) + +DOCKER_BUILDER_IMAGE_NAME = govuk/notify-admin-builder + +BUILD_TAG ?= notifications-admin-manual +BUILD_NUMBER ?= 0 +DEPLOY_BUILD_NUMBER ?= ${BUILD_NUMBER} +BUILD_URL ?= + +DOCKER_CONTAINER_PREFIX = ${USER}-${BUILD_TAG} + +.PHONY: help +help: + @cat $(MAKEFILE_LIST) | grep -E '^[a-zA-Z_-]+:.*?## .*$$' | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: venv +venv: venv/bin/activate ## Create virtualenv if it does not exist + +venv/bin/activate: + test -d venv || virtualenv venv + ./venv/bin/pip install pip-accel + +.PHONY: check-env-vars +check-env-vars: ## Check mandatory environment variables + $(if ${DEPLOY_ENV},,$(error Must specify DEPLOY_ENV)) + $(if ${DNS_NAME},,$(error Must specify DNS_NAME)) + $(if ${AWS_ACCESS_KEY_ID},,$(error Must specify AWS_ACCESS_KEY_ID)) + $(if ${AWS_SECRET_ACCESS_KEY},,$(error Must specify AWS_SECRET_ACCESS_KEY)) + +.PHONY: development +development: ## Set environment to development + $(eval export DEPLOY_ENV=development) + $(eval export DNS_NAME="notify.works") + @true + +.PHONY: staging +staging: ## Set environment to staging + $(eval export DEPLOY_ENV=staging) + $(eval export DNS_NAME="staging-notify.works") + @true + +.PHONY: production +production: ## Set environment to production + $(eval export DEPLOY_ENV=production) + $(eval export DNS_NAME="notifications.service.gov.uk") + @true + +.PHONY: dependencies +dependencies: venv ## Install build dependencies + npm set progress=false + npm install + npm rebuild node-sass + mkdir -p ${PIP_ACCEL_CACHE} + PIP_ACCEL_CACHE=${PIP_ACCEL_CACHE} ./venv/bin/pip-accel install -r requirements_for_test.txt + +.PHONY: generate-version-file +generate-version-file: ## Generates the app version file + @echo -e "__travis_commit__ = \"${GIT_COMMIT}\"\n__time__ = \"${DATE}\"\n__travis_job_number__ = \"${BUILD_NUMBER}\"\n__travis_job_url__ = \"${BUILD_URL}\"" > ${APP_VERSION_FILE} + +.PHONY: build +build: dependencies generate-version-file ## Build project + npm run build + +.PHONY: build-codedeploy-artifact +build-codedeploy-artifact: ## Build the deploy artifact for CodeDeploy + mkdir -p target + zip -r -x@deploy-exclude.lst target/notifications-admin.zip * + +.PHONY: upload-codedeploy-artifact ## Upload the deploy artifact for CodeDeploy +upload-codedeploy-artifact: check-env-vars + aws s3 cp --region eu-west-1 target/notifications-admin.zip s3://${DNS_NAME}-codedeploy/notifications-admin-${DEPLOY_BUILD_NUMBER}.zip + +.PHONY: test +test: venv ## Run tests + ./scripts/run_tests.sh + +.PHONY: deploy +deploy: check-env-vars ## Upload deploy artifacts to S3 and trigger CodeDeploy + aws deploy create-deployment --application-name notify-admin --deployment-config-name CodeDeployDefault.OneAtATime --deployment-group-name notify-admin --s3-location bucket=${DNS_NAME}-codedeploy,key=notifications-admin-${DEPLOY_BUILD_NUMBER}.zip,bundleType=zip --region eu-west-1 + +.PHONY: coverage +coverage: venv ## Create coverage report + ./venv/bin/coveralls + +.PHONY: prepare-docker-build-image +prepare-docker-build-image: ## Prepare the Docker builder image + mkdir -p ${PIP_ACCEL_CACHE} + make -C docker build-build-image + +.PHONY: build-with-docker +build-with-docker: prepare-docker-build-image ## Build inside a Docker container + docker run -i --rm \ + --name "${DOCKER_CONTAINER_PREFIX}-build" \ + -v `pwd`:/var/project \ + -v ${PIP_ACCEL_CACHE}:/var/project/cache/pip-accel \ + ${DOCKER_BUILDER_IMAGE_NAME} \ + make build + +.PHONY: test-with-docker +test-with-docker: prepare-docker-build-image ## Run tests inside a Docker container + docker run -i --rm \ + --name "${DOCKER_CONTAINER_PREFIX}-test" \ + -v `pwd`:/var/project \ + ${DOCKER_BUILDER_IMAGE_NAME} \ + make test + +.PHONY: coverage-with-docker +coverage-with-docker: prepare-docker-build-image ## Generates coverage report inside a Docker container + docker run -i --rm \ + --name "${DOCKER_CONTAINER_PREFIX}-coverage" \ + -v `pwd`:/var/project \ + ${DOCKER_BUILDER_IMAGE_NAME} \ + make coverage + +.PHONY: clean-docker-containers +clean-docker-containers: ## Clean up any remaining docker containers + docker rm -f $(shell docker ps -q -f "name=${DOCKER_CONTAINER_PREFIX}") 2> /dev/null || true + +clean: + rm -rf node_modules cache target venv .coverage diff --git a/app/main/forms.py b/app/main/forms.py index c1f50a089..820d47c9c 100644 --- a/app/main/forms.py +++ b/app/main/forms.py @@ -337,7 +337,7 @@ class ServiceSmsSender(Form): def validate_sms_sender(form, field): import re if field.data and not re.match('^[a-zA-Z0-9\s]+$', field.data): - raise ValidationError('Sms text message sender can only contain alpha-numeric characters') + raise ValidationError('Text message sender can only contain alpha-numeric characters') class ServiceBrandingOrg(Form): diff --git a/app/main/views/dashboard.py b/app/main/views/dashboard.py index 67588672a..7ce396923 100644 --- a/app/main/views/dashboard.py +++ b/app/main/views/dashboard.py @@ -66,11 +66,12 @@ def template_history(service_id): template_statistics = aggregate_usage( template_statistics_client.get_template_statistics_for_service(service_id) ) + return render_template( 'views/dashboard/all-template-statistics.html', template_statistics=template_statistics, most_used_template_count=max( - [row['usage_count'] for row in template_statistics] or [0] + [row['count'] for row in template_statistics] or [0] ) ) @@ -98,31 +99,9 @@ def weekly(service_id): def aggregate_usage(template_statistics): - - immutable_template = namedtuple('Template', ['template_type', 'name', 'id']) - - # grouby requires the list to be sorted by template first - statistics_sorted_by_template = sorted( - ( - ( - immutable_template(**row['template']), - row['usage_count'] - ) - for row in template_statistics - ), - key=lambda items: items[0] - ) - - # then group and sort the result by usage return sorted( - ( - { - 'usage_count': sum(usage[1] for usage in usages), - 'template': template - } - for template, usages in groupby(statistics_sorted_by_template, lambda items: items[0]) - ), - key=lambda row: row['usage_count'], + template_statistics, + key=lambda template_statistic: template_statistic['count'], reverse=True ) @@ -149,7 +128,7 @@ def get_dashboard_partials(service_id): 'views/dashboard/template-statistics.html', template_statistics=template_statistics, most_used_template_count=max( - [row['usage_count'] for row in template_statistics] or [0] + [row['count'] for row in template_statistics] or [0] ), ), 'has_template_statistics': bool(template_statistics), diff --git a/app/notify_client/template_statistics_api_client.py b/app/notify_client/template_statistics_api_client.py index b0d54b22c..7829340d2 100644 --- a/app/notify_client/template_statistics_api_client.py +++ b/app/notify_client/template_statistics_api_client.py @@ -16,12 +16,14 @@ class TemplateStatisticsApiClient(BaseAPIClient): params = {} if limit_days is not None: params['limit_days'] = limit_days + return self.get( url='/service/{}/template-statistics'.format(service_id), params=params )['data'] def get_template_statistics_for_template(self, service_id, template_id): + return self.get( url='/service/{}/template-statistics/{}'.format(service_id, template_id) )['data'] diff --git a/app/templates/views/dashboard/all-template-statistics.html b/app/templates/views/dashboard/all-template-statistics.html index bb3a7d0dc..829d67d19 100644 --- a/app/templates/views/dashboard/all-template-statistics.html +++ b/app/templates/views/dashboard/all-template-statistics.html @@ -10,9 +10,6 @@

Templates sent

-
- 1 April 2016 to date -
{% include 'views/dashboard/template-statistics.html' %} diff --git a/app/templates/views/dashboard/template-statistics.html b/app/templates/views/dashboard/template-statistics.html index 819b759cd..11c7d677b 100644 --- a/app/templates/views/dashboard/template-statistics.html +++ b/app/templates/views/dashboard/template-statistics.html @@ -17,18 +17,18 @@ ) %} {% call row_heading() %} - {{ item.template.name }} + {{ item.template_name }} - {{ message_count_label(1, item.template.template_type, suffix='template')|capitalize }} + {{ message_count_label(1, item.template_type, suffix='template')|capitalize }} {% endcall %} {% call field() %} {% if template_statistics|length > 1 %} - + {{ big_number( - item.usage_count, + item.count, smallest=True ) }} @@ -36,7 +36,7 @@ {% else %} {{ big_number( - item.usage_count, + item.count, smallest=True ) }} diff --git a/app/templates/views/registration-continue.html b/app/templates/views/registration-continue.html index ab3e54275..e2d6e2be4 100644 --- a/app/templates/views/registration-continue.html +++ b/app/templates/views/registration-continue.html @@ -7,7 +7,7 @@ {% block maincolumn_content %}

Check your email​

-

We’ve sent an email to {{ session['user_details']['email'] }}.

+

An email has been sent to {{ session['user_details']['email'] }}.

Click the link in the email to continue your registration.

{% endblock %} diff --git a/app/templates/views/text-not-received-2.html b/app/templates/views/text-not-received-2.html index 4e10ac956..3a49f39a7 100644 --- a/app/templates/views/text-not-received-2.html +++ b/app/templates/views/text-not-received-2.html @@ -12,7 +12,7 @@ Check your mobile number – GOV.UK Notify

Check your mobile number

-

Check your mobile phone number is correct and then resend the confirmation code.

+

Check your mobile phone number is correct and then resend the security code.

@@ -21,7 +21,7 @@ Check your mobile number – GOV.UK Notify

- Resend confirmation code + Resend security code

diff --git a/app/templates/views/text-not-received.html b/app/templates/views/text-not-received.html index e6bab7546..4ee286f08 100644 --- a/app/templates/views/text-not-received.html +++ b/app/templates/views/text-not-received.html @@ -12,11 +12,11 @@ Check your mobile number – GOV.UK Notify

Check your mobile number

-

Check your mobile phone number is correct and then resend the confirmation code.

+

Check your mobile phone number is correct and then resend the security code.

{{ textbox(form.mobile_number) }} - {{ page_footer("Resend confirmation code") }} + {{ page_footer("Resend security code") }}
diff --git a/app/templates/views/user-profile/confirm.html b/app/templates/views/user-profile/confirm.html index 069fe0e7e..0a4d8db32 100644 --- a/app/templates/views/user-profile/confirm.html +++ b/app/templates/views/user-profile/confirm.html @@ -13,7 +13,7 @@ GOV.UK Notify | Service settings

- We’ve sent a code to your new {{ thing }}. + We’ve sent a security code to your new {{ thing }}.

{{ textbox(form_field) }} diff --git a/app/templates/views/verify-mobile.html b/app/templates/views/verify-mobile.html index 4cb7135a7..381268f5c 100644 --- a/app/templates/views/verify-mobile.html +++ b/app/templates/views/verify-mobile.html @@ -10,7 +10,7 @@ Confirm your mobile number – GOV.UK Notify

Confirm your mobile number

-

We’ve sent you a security code by text message.

+

We’ve sent you a security code by text message.