Merge branch 'master' into remove-stats-from-send
82
.travis.yml
@@ -5,7 +5,7 @@ cache:
|
|||||||
directories:
|
directories:
|
||||||
- node_modules
|
- node_modules
|
||||||
python:
|
python:
|
||||||
- '3.4.3'
|
- 3.4.3
|
||||||
env:
|
env:
|
||||||
secure: jT9BIioqBMkOdLZhU+WJNdnRJ+06G7qUx4QqEVldp96dJwmWpPEvA0XbitdnQt/WXYkpMlDbgSApvvGj2ZNvdpowRRe5HFX8D2Udhi2g9+cXgKrQxH6zv0evJyQLOjCINW6KtgMCJ5wkYR3qQ4BQawlDt6ecpmeboKTmvs2W8jZ09aV4IKKvdd7BwFon10QVPF5ny10G83unLtKnKgRMjSSLnaEiA78pE/LSUkekK4mhmtl+yfQf60cIuQGcN9NCYIt5PrdYYyMkbUaht9ykwL2C11sp5JYPClI9k6lrlpGJCdL9wbJwejGhR/pEqwJ4tKK8Zv+mngmkbzE6fd5ehuRMnIUAifG4t3p6WbhKwY5pJsdVyPgWcRSPXOJA7yEcAeTAvWcC++6mCIFBeMxt/yQNw02jkFHeNKRh2twTRvr4xWZHq9FsVxTEVz89OOuue3IkkyDNmVusGJ9+AVRIn9Oa+U/r3bDnrs7jz+meSwb82GZUBzFpUe2pe8qeBE572Ay7yHB73VHUgp/2A1qkZ4SnTjTpMbnS5RdXTgwtMkOs5MLZgteCVxFL3sHcr9e/B3UIUnzKUSPXXOjHyDxBwrABWo81V9Vp2IPV7P9Ofv8zroudjQxK5MOcbmiPQF+eEB9L4DvkUBNsGxtJ/nmPp6tmN0Xjo0xXVdZCEVj29Og=
|
secure: jT9BIioqBMkOdLZhU+WJNdnRJ+06G7qUx4QqEVldp96dJwmWpPEvA0XbitdnQt/WXYkpMlDbgSApvvGj2ZNvdpowRRe5HFX8D2Udhi2g9+cXgKrQxH6zv0evJyQLOjCINW6KtgMCJ5wkYR3qQ4BQawlDt6ecpmeboKTmvs2W8jZ09aV4IKKvdd7BwFon10QVPF5ny10G83unLtKnKgRMjSSLnaEiA78pE/LSUkekK4mhmtl+yfQf60cIuQGcN9NCYIt5PrdYYyMkbUaht9ykwL2C11sp5JYPClI9k6lrlpGJCdL9wbJwejGhR/pEqwJ4tKK8Zv+mngmkbzE6fd5ehuRMnIUAifG4t3p6WbhKwY5pJsdVyPgWcRSPXOJA7yEcAeTAvWcC++6mCIFBeMxt/yQNw02jkFHeNKRh2twTRvr4xWZHq9FsVxTEVz89OOuue3IkkyDNmVusGJ9+AVRIn9Oa+U/r3bDnrs7jz+meSwb82GZUBzFpUe2pe8qeBE572Ay7yHB73VHUgp/2A1qkZ4SnTjTpMbnS5RdXTgwtMkOs5MLZgteCVxFL3sHcr9e/B3UIUnzKUSPXXOjHyDxBwrABWo81V9Vp2IPV7P9Ofv8zroudjQxK5MOcbmiPQF+eEB9L4DvkUBNsGxtJ/nmPp6tmN0Xjo0xXVdZCEVj29Og=
|
||||||
before_install:
|
before_install:
|
||||||
@@ -26,70 +26,70 @@ notifications:
|
|||||||
secure: A6n6Gdz3dsE+KQcOd1nWTvdjOF2YbgItT1E40r25poG6p04WHd8qWtC4T2FuZaxPN/TQdKr/dKa/WCkmiEdxT5O0SOwAnAD3u6Fn2nthoI4M5916UrK1ZrqupvnFPSQc8Ivh51PGkcmB4wrb0ylRhMB94RmLcUZcVuXLDx57GO8bPFyLC3E9bgcVVFWaX45sKs74sBSQWi9EBbzHIuduLdjIpW7wX07dA++HlY14W5WgiurmiYohfP11VdAMmMxJs2WdWk16O/qy0HZXaldNIsSnuDBkhAZOMeSrcvp+62yOiN8jK0nSa1IRr3IoUkITdC9YGys3xFJb8gyIQE9T3hUnTYAKCcgsgpVFS6UzsRN42JUAJ8rFTgK9/J299yTk4lqL8uWzcV1QcKXIPNoG0QfqkmlB9B1fKbXuE/KkPEXPCKAcVQpCzEon09FgTCrlVZqJ6HxQonnLcPlIpVzWHAFokLZVHLAFMKYJnGBcZ6zaRK5pdc1babcOXMIPBC8j028G5bhBaCviDvZlimxOsUK1sJTpjzMU0tBQZa8lI+0O5otvMKiX8jPyaedjVvUmsftF2O5FH5nz2ofJC7BThb76/Tac2pNTCn0pWiVz9wi/YXALOMdIzkYgHnyZdEqAjRlpFwZuOrzR6MuvivBebPxjYaRWzCjOeC1uIwz+48E=
|
secure: A6n6Gdz3dsE+KQcOd1nWTvdjOF2YbgItT1E40r25poG6p04WHd8qWtC4T2FuZaxPN/TQdKr/dKa/WCkmiEdxT5O0SOwAnAD3u6Fn2nthoI4M5916UrK1ZrqupvnFPSQc8Ivh51PGkcmB4wrb0ylRhMB94RmLcUZcVuXLDx57GO8bPFyLC3E9bgcVVFWaX45sKs74sBSQWi9EBbzHIuduLdjIpW7wX07dA++HlY14W5WgiurmiYohfP11VdAMmMxJs2WdWk16O/qy0HZXaldNIsSnuDBkhAZOMeSrcvp+62yOiN8jK0nSa1IRr3IoUkITdC9YGys3xFJb8gyIQE9T3hUnTYAKCcgsgpVFS6UzsRN42JUAJ8rFTgK9/J299yTk4lqL8uWzcV1QcKXIPNoG0QfqkmlB9B1fKbXuE/KkPEXPCKAcVQpCzEon09FgTCrlVZqJ6HxQonnLcPlIpVzWHAFokLZVHLAFMKYJnGBcZ6zaRK5pdc1babcOXMIPBC8j028G5bhBaCviDvZlimxOsUK1sJTpjzMU0tBQZa8lI+0O5otvMKiX8jPyaedjVvUmsftF2O5FH5nz2ofJC7BThb76/Tac2pNTCn0pWiVz9wi/YXALOMdIzkYgHnyZdEqAjRlpFwZuOrzR6MuvivBebPxjYaRWzCjOeC1uIwz+48E=
|
||||||
deploy:
|
deploy:
|
||||||
- provider: s3
|
- provider: s3
|
||||||
access_key_id: AKIAJ5MKF6G3P2JQP4QQ
|
access_key_id: AKIAJLWYN4T4D5WU4APA
|
||||||
secret_access_key: &1
|
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=
|
secure: EUiC93M7BI563BTIZV8tR2PvA1iIVKliKIiiFOJ9F8MJDB4Eya0ZfMLC1hsopJ1gZPWv4CjcW04CWqHf62FQJHDDTFtERMXEhJjVGOTgCC+7fkGEKV5pBJCtVdSGlQwd8HjlcfUZ8M7qlnqwLMj2IcTSiMzCVr8RpuSNHM9DF88n3k0EEiF+h83wB1PSmA+4I+CRevFg6xK1ezjSxCZV9N4A9vd1mrX+BSsH0ikbUA66ccAPMGy0yVR3CtzrI9AObutc9mO8qzLXI0SuCYFvyFEHXdXqqcWw4XJ28hYsayHO4gEX1ndYSNzIcCJKXseJRs6idcE0xRpipigYyx83SqvbPtrBlga47MPHXpP8Xl8xTKtVLo9k+Itbx96t1pllrhFqoysHfV8yRrh+otmED2sziB1VTiecPP0IvlVlWGEzUHMepkQhZKfDmFUtcpa7BrJx0Fxzsu9mL9tKx5H7PVA9uMC67Tc6qI3PNSE5XsNfBUjSOzaSY7UFUdKmvINXRk9PIP+NXOsH0kzILl7EzvUoBIbFf8+/1EDmvMc88J5yg4QCmVnIhw5JqnC1uQyDUy41VOsdqgwVUHy7hJuXtKMnUSYuDOltP2fdkArLby0VFgcQgoT+N87I4xcjVzLjEvNgwlZ1nHuBf9v+aB0aD9e/LB03gIt23Nrucu9ON1M=
|
||||||
local_dir: dpl_cd_upload
|
local_dir: dpl_cd_upload
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
|
region: eu-west-1
|
||||||
|
on: &2
|
||||||
|
repo: alphagov/notifications-admin
|
||||||
|
bucket: notify.works-notifications-admin-codedeploy
|
||||||
|
- provider: codedeploy
|
||||||
|
access_key_id: AKIAJLWYN4T4D5WU4APA
|
||||||
|
secret_access_key: *1
|
||||||
|
bucket: notify.works-notifications-admin-codedeploy
|
||||||
|
key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
||||||
|
bundle_type: zip
|
||||||
|
application: admin
|
||||||
|
deployment_group: notifications_admin_deployment_group
|
||||||
|
region: eu-west-1
|
||||||
|
on: *2
|
||||||
|
- provider: s3
|
||||||
|
access_key_id: AKIAJCOSRR7IFXS2WJUA
|
||||||
|
secret_access_key: &1
|
||||||
|
secure: LBprDWBFawNvG9M0AVHJkS0txP4IapXG6K8OIzY6T3yDJP8vTnN6M34C++AprkZEqehzug36Vms5PVv9p2gkJOjZkwBKMRFZtjdxGXfRaZnbGQgcBbleMhdXsDWlGJm7RnMS/SX79tiezQ2h6GYyb96vBT0mdfyo/OPr5HJ6IWa/fblUXzZF1a5kCvP2uvR+nXKutsfNnP7lFzrFiH6efyeI1XPD18TU7Nuy6xOZDkDlX2RAvq+Qe5zX0o7VzXFkFdf7NfVT7AswoAEEVZeWNrm84oQJsH88QymDgpdLLzAlwmrWHDTGQtRCOQvXWhK6HvZMgP9n4EcWSIq4WMCjXMcnUqW6mvB+dBjJEe3I+oVgf1TWpdCSAWyffkJ805/xSF/BP92KHg8PAYJKlzrpHWuHaysf05a0QyKsFW09SzzQbpMrs0KLErqOLbG9NKZ5MaUepnsMyuKTr3shysNzlbcC5TghpGQO+D2yj/cJYmKp835Nx9tSU49woDbMDycdgF0rIczfwM8+OrywPw4fY6NAir6uAGx3aYrCx2BNEsGW4tjY7ab8EGCk4pgWpBw1/ERclA6D5sx7ppLI3wnVKsUyPUDvjOFjqdWkBrsONM4xHENRyaJupzQEuzJt/nxtHHGsayyKqYWT24+6ira8p4vJVqnJ+qBM3C7IYVIVXM8=
|
||||||
|
local_dir: dpl_cd_upload
|
||||||
|
skip_cleanup: true
|
||||||
|
region: eu-west-1
|
||||||
on: &2
|
on: &2
|
||||||
repo: alphagov/notifications-admin
|
repo: alphagov/notifications-admin
|
||||||
branch: staging
|
branch: staging
|
||||||
bucket: staging-notifications-admin-codedeploy
|
bucket: staging-notify.works-notifications-admin-codedeploy
|
||||||
region: eu-west-1
|
|
||||||
- provider: codedeploy
|
- provider: codedeploy
|
||||||
access_key_id: AKIAJ5MKF6G3P2JQP4QQ
|
access_key_id: AKIAJCOSRR7IFXS2WJUA
|
||||||
secret_access_key: *1
|
secret_access_key: *1
|
||||||
bucket: staging-notifications-admin-codedeploy
|
bucket: staging-notify.works-notifications-admin-codedeploy
|
||||||
key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
||||||
bundle_type: zip
|
bundle_type: zip
|
||||||
application: notifications-admin
|
application: admin
|
||||||
deployment_group: staging_admin_deployment_group
|
deployment_group: notifications_admin_deployment_group
|
||||||
region: eu-west-1
|
region: eu-west-1
|
||||||
on: *2
|
on: *2
|
||||||
- provider: s3
|
- provider: s3
|
||||||
access_key_id: AKIAJ5MKF6G3P2JQP4QQ
|
access_key_id: AKIAIFLN7IJIIQT6S37Q
|
||||||
secret_access_key: &1
|
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=
|
secure: Vt558KgvDIAUDWPLviRk24ZOzvNZ993rovMj4rmaZF9Dh1qEHH/tZ/yCkXUTLEMXUVCf5TKek9HfBZAiIrQn+VAe7RTDNHQUuI1EWmpCuqPCZcF6vP6Jz3KyGeCtsF8Ksr394sGbTc4clGxANin0HqWuBqWUV5QGhFJTgBEfCn+Zx1hLQoJisLUSxYaKbc7GGugYa+S3YDhAS7XPlYr4fTnRFp7VT0U2ofecS/skoGLuzb+HMY2MwXAeuBkCb1tIFFl30wbU1PwjLimSu5bWq9cLrRDiH3cDK3fYwAdbjhEM5Wg9i7YfjTcLasOmYNSsLih0FVo1k/G2xTKGU7nsCiSlEX7FpNgwOO3HGdcgb1Pp1X0iIVMh5gw1hlXJNPn/fSDkjLxwISGzI0XmEAilnIo8ovF/jvoEWj5kXrqtOuoH/moQttDCu+0iritfs40A8qBqv/6H3KSamqrDYC5pyRd1VlLo4aR9cH36pedNTnSH88bxm2We3iO/3m60KyEAfgAmJwINvRSuudyi3SeB1FXU0xf7qJ4wg2vWJCzOccFYhpqdk5wh5ZaeH1RdUbz0nNvs2uxDjWTsH/HFbAhgVgt4RtrwjsJUB5i2TWZKl6VykuIMet/y9BHcMbklwEHryPn74fpIs+7ui5zBOMNpEecEWXL5gwnh2fzUPm1+MlA=
|
||||||
local_dir: dpl_cd_upload
|
local_dir: dpl_cd_upload
|
||||||
skip_cleanup: true
|
skip_cleanup: true
|
||||||
|
region: eu-west-1
|
||||||
on: &2
|
on: &2
|
||||||
repo: alphagov/notifications-admin
|
repo: alphagov/notifications-admin
|
||||||
branch: live
|
branch: live
|
||||||
bucket: live-notifications-admin-codedeploy
|
bucket: notifications.service.gov.uk-notifications-admin-codedeploy
|
||||||
region: eu-west-1
|
|
||||||
- provider: codedeploy
|
- provider: codedeploy
|
||||||
access_key_id: AKIAJ5MKF6G3P2JQP4QQ
|
access_key_id: AKIAIFLN7IJIIQT6S37Q
|
||||||
secret_access_key: *1
|
secret_access_key: *1
|
||||||
bucket: live-notifications-admin-codedeploy
|
bucket: notifications.service.gov.uk-notifications-admin-codedeploy
|
||||||
key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
||||||
bundle_type: zip
|
bundle_type: zip
|
||||||
application: notifications-admin
|
application: admin
|
||||||
deployment_group: live_admin_deployment_group
|
|
||||||
region: eu-west-1
|
|
||||||
on: *2
|
|
||||||
- provider: s3
|
|
||||||
access_key_id: AKIAJQPPNM6P6V53SWKA
|
|
||||||
secret_access_key: &1
|
|
||||||
secure: 7qVw4gmn7zMCaam9PqIfqwC1z82gXxa+rT/VakoMDY7u62BXA8/fWGFn7yU4qyPSrTWttYdDXmdwrgoEDjGIzLXSpufRqhmXc3xBoRktFSRQAFVom49mWo7WDKgX6gZ3GcuVR8HQ1XpojlkLH/a6cKV9jreDiGHy3sHulBkJRXGIGkTNCiVNVbUsFeiOj/YGaIdZ6ZLjDBSOTwLkLsnzZm7S+xcRd0kxT3VJrV0B3x14igK2Rchv9LteT+fafELURO2asASgLPHy5ny3yGF7vVz6tLBrTpy2N7xxpaDkP/LQi38PRGhZkYPHdqgMfq7fFwN2oJF66zxeQ6kzR9lIwVZnqNYwgAapJAx7TrfX2UaR0zoZgs/TBhFijqJ2CK8fIQ7TKW0wEd84rd5FS8ocHmAsiJSLOSXn665m/nUPrWrUi7mK7/9/85rLiZihw862BhwIn83VQcahK4QEDFkK0PC7JqGvLiH3prjlibsA7ONDbFi8NPtvf3bFaofb6a3NO3qjgSvdftIujw86ZmVBAkQXghyZBlgCPiseOphrxZ4Thl54fo86cbiEqAs8c6DCHtPEiAHZ++sK1aitMtepdGORC1SrLICWO4vFAl6oLptzvY+j9+BhOK28JnRUXpQS7DjkrahqcgE/LbCN55lu1UhWWGY0q20QeKgGnsRuOAU=
|
|
||||||
local_dir: dpl_cd_upload
|
|
||||||
skip_cleanup: true
|
|
||||||
on: &2
|
|
||||||
repo: alphagov/notifications-admin
|
|
||||||
bucket: notifications-admin-codedeploy
|
|
||||||
region: eu-west-1
|
|
||||||
- provider: codedeploy
|
|
||||||
access_key_id: AKIAJQPPNM6P6V53SWKA
|
|
||||||
secret_access_key: *1
|
|
||||||
bucket: notifications-admin-codedeploy
|
|
||||||
key: notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
|
||||||
bundle_type: zip
|
|
||||||
application: notifications-admin
|
|
||||||
deployment_group: notifications_admin_deployment_group
|
deployment_group: notifications_admin_deployment_group
|
||||||
region: eu-west-1
|
region: eu-west-1
|
||||||
on: *2
|
on: *2
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- ./scripts/update_version_file.sh
|
- ./scripts/update_version_file.sh
|
||||||
- rm -rf node_modules bower_components app/assets
|
- rm -rf node_modules bower_components app/assets
|
||||||
- zip -r --exclude=*__pycache__* notifications-admin *
|
- zip -r --exclude=*__pycache__* notifications-admin *
|
||||||
- mkdir -p dpl_cd_upload
|
- mkdir -p dpl_cd_upload
|
||||||
- mv notifications-admin.zip dpl_cd_upload/notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
- mv notifications-admin.zip dpl_cd_upload/notifications-admin-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER-$TRAVIS_COMMIT.zip
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ in a separate terminal from the app
|
|||||||
|
|
||||||
```
|
```
|
||||||
echo "
|
echo "
|
||||||
export NOTIFY_ADMIN_ENVIRONMENT='config.Development'
|
export NOTIFY_ENVIRONMENT='development'
|
||||||
export ADMIN_CLIENT_SECRET='dev-notify-secret-key'
|
export ADMIN_CLIENT_SECRET='dev-notify-secret-key'
|
||||||
export ADMIN_CLIENT_USER_NAME='dev-notify-admin'
|
export ADMIN_CLIENT_USER_NAME='dev-notify-admin'
|
||||||
export API_HOST_NAME='http://localhost:6011'
|
export API_HOST_NAME='http://localhost:6011'
|
||||||
@@ -69,7 +69,6 @@ export DANGEROUS_SALT='dev-notify-salt'
|
|||||||
export SECRET_KEY='dev-notify-secret-key'
|
export SECRET_KEY='dev-notify-secret-key'
|
||||||
export DESKPRO_API_HOST=""
|
export DESKPRO_API_HOST=""
|
||||||
export DESKPRO_API_KEY=""
|
export DESKPRO_API_KEY=""
|
||||||
export DESKPRO_PERSON_EMAIL=""
|
|
||||||
export DESKPRO_DEPT_ID=""
|
export DESKPRO_DEPT_ID=""
|
||||||
export DESKPRO_ASSIGNED_AGENT_TEAM_ID=""
|
export DESKPRO_ASSIGNED_AGENT_TEAM_ID=""
|
||||||
"> environment.sh
|
"> environment.sh
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ from flask import (
|
|||||||
current_app,
|
current_app,
|
||||||
request,
|
request,
|
||||||
g,
|
g,
|
||||||
url_for
|
url_for)
|
||||||
)
|
|
||||||
from flask._compat import string_types
|
from flask._compat import string_types
|
||||||
from flask.globals import _lookup_req_object
|
from flask.globals import _lookup_req_object
|
||||||
from flask_login import LoginManager
|
from flask_login import LoginManager
|
||||||
@@ -67,9 +67,11 @@ current_service = LocalProxy(partial(_lookup_req_object, 'service'))
|
|||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
|
from config import configs
|
||||||
|
|
||||||
application = Flask(__name__)
|
application = Flask(__name__)
|
||||||
|
|
||||||
application.config.from_object(os.environ['NOTIFY_ADMIN_ENVIRONMENT'])
|
application.config.from_object(configs[os.environ['NOTIFY_ENVIRONMENT']])
|
||||||
|
|
||||||
init_app(application)
|
init_app(application)
|
||||||
logging.init_app(application)
|
logging.init_app(application)
|
||||||
@@ -241,7 +243,8 @@ def format_notification_status(status, template_type):
|
|||||||
'temporary-failure': 'Inbox not accepting messages right now',
|
'temporary-failure': 'Inbox not accepting messages right now',
|
||||||
'permanent-failure': 'Email address doesn’t exist',
|
'permanent-failure': 'Email address doesn’t exist',
|
||||||
'delivered': 'Delivered',
|
'delivered': 'Delivered',
|
||||||
'sending': 'Sending'
|
'sending': 'Sending',
|
||||||
|
'created': 'Sending'
|
||||||
},
|
},
|
||||||
'sms': {
|
'sms': {
|
||||||
'failed': 'Failed',
|
'failed': 'Failed',
|
||||||
@@ -249,7 +252,8 @@ def format_notification_status(status, template_type):
|
|||||||
'temporary-failure': 'Phone not accepting messages right now',
|
'temporary-failure': 'Phone not accepting messages right now',
|
||||||
'permanent-failure': 'Phone number doesn’t exist',
|
'permanent-failure': 'Phone number doesn’t exist',
|
||||||
'delivered': 'Delivered',
|
'delivered': 'Delivered',
|
||||||
'sending': 'Sending'
|
'sending': 'Sending',
|
||||||
|
'created': 'Sending'
|
||||||
}
|
}
|
||||||
}.get(template_type).get(status, status)
|
}.get(template_type).get(status, status)
|
||||||
|
|
||||||
@@ -261,7 +265,8 @@ def format_notification_status_as_field_status(status):
|
|||||||
'temporary-failure': 'error',
|
'temporary-failure': 'error',
|
||||||
'permanent-failure': 'error',
|
'permanent-failure': 'error',
|
||||||
'delivered': None,
|
'delivered': None,
|
||||||
'sending': 'default'
|
'sending': 'default',
|
||||||
|
'created': 'default'
|
||||||
}.get(status, 'error')
|
}.get(status, 'error')
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
BIN
app/assets/images/email-template/crests/bis_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 4.1 KiB |
BIN
app/assets/images/email-template/crests/coastguard_27px_x2.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
app/assets/images/email-template/crests/hmrc_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
app/assets/images/email-template/crests/ho_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 7.8 KiB |
BIN
app/assets/images/email-template/crests/mod_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
app/assets/images/email-template/crests/org_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
app/assets/images/email-template/crests/portcullis_27px_x2.png
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
app/assets/images/email-template/crests/so_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
BIN
app/assets/images/email-template/crests/ukaea_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 9.7 KiB |
BIN
app/assets/images/email-template/crests/ukho_27px_x2.png
Normal file
|
After Width: | Height: | Size: 9.0 KiB |
BIN
app/assets/images/email-template/crests/wales_crest_27px_x2.png
Normal file
|
After Width: | Height: | Size: 8.1 KiB |
BIN
app/assets/images/email-template/spacer.png
Normal file
|
After Width: | Height: | Size: 95 B |
@@ -31,6 +31,10 @@
|
|||||||
margin-bottom: $gutter-two-thirds;
|
margin-bottom: $gutter-two-thirds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom-gutter-1-2 {
|
||||||
|
margin-bottom: $gutter-half;
|
||||||
|
}
|
||||||
|
|
||||||
.align-with-heading {
|
.align-with-heading {
|
||||||
display: block;
|
display: block;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
from datetime import datetime, date, timedelta
|
from datetime import datetime, timedelta
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
|
|
||||||
|
import dateutil
|
||||||
from flask import (
|
from flask import (
|
||||||
render_template,
|
render_template,
|
||||||
url_for,
|
url_for,
|
||||||
@@ -9,13 +10,11 @@ from flask import (
|
|||||||
jsonify,
|
jsonify,
|
||||||
current_app
|
current_app
|
||||||
)
|
)
|
||||||
|
|
||||||
from flask_login import login_required
|
from flask_login import login_required
|
||||||
|
|
||||||
from app.main import main
|
from app.main import main
|
||||||
from app import (
|
from app import (
|
||||||
job_api_client,
|
job_api_client,
|
||||||
statistics_api_client,
|
|
||||||
service_api_client,
|
service_api_client,
|
||||||
template_statistics_client
|
template_statistics_client
|
||||||
)
|
)
|
||||||
@@ -90,20 +89,10 @@ def usage(service_id):
|
|||||||
@login_required
|
@login_required
|
||||||
@user_has_permissions('manage_settings', admin_override=True)
|
@user_has_permissions('manage_settings', admin_override=True)
|
||||||
def weekly(service_id):
|
def weekly(service_id):
|
||||||
|
stats = service_api_client.get_weekly_notification_stats(service_id)['data']
|
||||||
earliest_date = date(2016, 4, 1) # start of tax year
|
|
||||||
while earliest_date.weekday() != 0: # 0 for monday
|
|
||||||
earliest_date -= timedelta(days=1)
|
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'views/weekly.html',
|
'views/weekly.html',
|
||||||
days=(
|
days=format_weekly_stats_to_list(stats),
|
||||||
add_rates_to(day) for day in
|
|
||||||
statistics_api_client.get_7_day_aggregate_for_service(
|
|
||||||
service_id,
|
|
||||||
date_from=earliest_date
|
|
||||||
)['data']
|
|
||||||
),
|
|
||||||
now=datetime.utcnow()
|
now=datetime.utcnow()
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -199,3 +188,21 @@ def calculate_usage(usage):
|
|||||||
'sms_chargeable': max(0, sms_sent - sms_free_allowance),
|
'sms_chargeable': max(0, sms_sent - sms_free_allowance),
|
||||||
'sms_rate': sms_rate
|
'sms_rate': sms_rate
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def format_weekly_stats_to_list(historical_stats):
|
||||||
|
out = []
|
||||||
|
for week, weekly_stats in historical_stats.items():
|
||||||
|
for stats in weekly_stats.values():
|
||||||
|
stats['failure_rate'] = get_formatted_percentage(stats['failed'], stats['requested'])
|
||||||
|
|
||||||
|
week_start = dateutil.parser.parse(week)
|
||||||
|
week_end = week_start + timedelta(days=6)
|
||||||
|
weekly_stats.update({
|
||||||
|
'week_start': week,
|
||||||
|
'week_end': week_end.date().isoformat(),
|
||||||
|
'week_end_datetime': week_end,
|
||||||
|
})
|
||||||
|
out.append(weekly_stats)
|
||||||
|
|
||||||
|
return sorted(out, key=lambda x: x['week_start'], reverse=True)
|
||||||
|
|||||||
@@ -8,17 +8,19 @@ from app.main.forms import Feedback
|
|||||||
def feedback():
|
def feedback():
|
||||||
form = Feedback()
|
form = Feedback()
|
||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
|
user_supplied_email = form.email_address.data != ''
|
||||||
|
feedback_msg = 'Environment: {}\n{}\n{}'.format(
|
||||||
|
url_for('main.index', _external=True),
|
||||||
|
'' if user_supplied_email else '{} (no email address supplied)'.format(form.name.data),
|
||||||
|
form.feedback.data
|
||||||
|
)
|
||||||
data = {
|
data = {
|
||||||
'person_email': current_app.config.get('DESKPRO_PERSON_EMAIL'),
|
'person_email': form.email_address.data or current_app.config.get('DESKPRO_PERSON_EMAIL'),
|
||||||
|
'person_name': form.name.data or None,
|
||||||
'department_id': current_app.config.get('DESKPRO_DEPT_ID'),
|
'department_id': current_app.config.get('DESKPRO_DEPT_ID'),
|
||||||
'agent_team_id': current_app.config.get('DESKPRO_ASSIGNED_AGENT_TEAM_ID'),
|
'agent_team_id': current_app.config.get('DESKPRO_ASSIGNED_AGENT_TEAM_ID'),
|
||||||
'subject': 'Notify feedback',
|
'subject': 'Notify feedback',
|
||||||
'message': 'Environment: {}\n\n{}\n{}\n{}'.format(
|
'message': feedback_msg
|
||||||
url_for('main.index', _external=True),
|
|
||||||
form.name.data,
|
|
||||||
form.email_address.data,
|
|
||||||
form.feedback.data
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
headers = {
|
headers = {
|
||||||
"X-DeskPRO-API-Key": current_app.config.get('DESKPRO_API_KEY'),
|
"X-DeskPRO-API-Key": current_app.config.get('DESKPRO_API_KEY'),
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import ago
|
||||||
import time
|
import time
|
||||||
import dateutil
|
import dateutil
|
||||||
|
from orderedset import OrderedSet
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
import ago
|
from itertools import chain
|
||||||
|
|
||||||
from flask import (
|
from flask import (
|
||||||
render_template,
|
render_template,
|
||||||
@@ -47,15 +49,14 @@ def _parse_filter_args(filter_dict):
|
|||||||
|
|
||||||
|
|
||||||
def _set_status_filters(filter_args):
|
def _set_status_filters(filter_args):
|
||||||
|
status_filters = filter_args.get('status', [])
|
||||||
all_failure_statuses = ['failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
all_failure_statuses = ['failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
||||||
all_statuses = ['sending', 'delivered'] + all_failure_statuses
|
all_sending_statuses = ['created', 'sending']
|
||||||
if filter_args.get('status'):
|
return list(OrderedSet(chain(
|
||||||
if 'processed' in filter_args.get('status') or not filter_args.get('status'):
|
(status_filters or all_sending_statuses + ['delivered'] + all_failure_statuses),
|
||||||
filter_args['status'] = all_statuses
|
all_sending_statuses if 'sending' in status_filters else [],
|
||||||
elif 'failed' in filter_args.get('status'):
|
all_failure_statuses if 'failed' in status_filters else []
|
||||||
filter_args['status'].extend(all_failure_statuses[1:])
|
)))
|
||||||
else:
|
|
||||||
filter_args['status'] = all_statuses
|
|
||||||
|
|
||||||
|
|
||||||
@main.route("/services/<service_id>/jobs")
|
@main.route("/services/<service_id>/jobs")
|
||||||
@@ -75,7 +76,7 @@ def view_job(service_id, job_id):
|
|||||||
|
|
||||||
job = job_api_client.get_job(service_id, job_id)['data']
|
job = job_api_client.get_job(service_id, job_id)['data']
|
||||||
filter_args = _parse_filter_args(request.args)
|
filter_args = _parse_filter_args(request.args)
|
||||||
_set_status_filters(filter_args)
|
filter_args['status'] = _set_status_filters(filter_args)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
'views/jobs/job.html',
|
'views/jobs/job.html',
|
||||||
@@ -117,7 +118,7 @@ def view_job_csv(service_id, job_id):
|
|||||||
version=job['template_version']
|
version=job['template_version']
|
||||||
)['data']
|
)['data']
|
||||||
filter_args = _parse_filter_args(request.args)
|
filter_args = _parse_filter_args(request.args)
|
||||||
_set_status_filters(filter_args)
|
filter_args['status'] = _set_status_filters(filter_args)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
generate_notifications_csv(
|
generate_notifications_csv(
|
||||||
@@ -161,7 +162,7 @@ def view_notifications(service_id, message_type):
|
|||||||
abort(404)
|
abort(404)
|
||||||
|
|
||||||
filter_args = _parse_filter_args(request.args)
|
filter_args = _parse_filter_args(request.args)
|
||||||
_set_status_filters(filter_args)
|
filter_args['status'] = _set_status_filters(filter_args)
|
||||||
|
|
||||||
notifications = notification_api_client.get_notifications_for_service(
|
notifications = notification_api_client.get_notifications_for_service(
|
||||||
service_id=service_id,
|
service_id=service_id,
|
||||||
@@ -210,7 +211,7 @@ def view_notifications(service_id, message_type):
|
|||||||
page=page,
|
page=page,
|
||||||
prev_page=prev_page,
|
prev_page=prev_page,
|
||||||
next_page=next_page,
|
next_page=next_page,
|
||||||
request_args=request.args,
|
status=request.args.get('status'),
|
||||||
message_type=message_type,
|
message_type=message_type,
|
||||||
download_link=url_for(
|
download_link=url_for(
|
||||||
'.view_notifications_csv',
|
'.view_notifications_csv',
|
||||||
@@ -250,7 +251,7 @@ def get_status_filters(service, message_type, statistics):
|
|||||||
|
|
||||||
filters = [
|
filters = [
|
||||||
# key, label, option
|
# key, label, option
|
||||||
('requested', 'processed', 'sending,delivered,failed'),
|
('requested', 'total', 'sending,delivered,failed'),
|
||||||
('sending', 'sending', 'sending'),
|
('sending', 'sending', 'sending'),
|
||||||
('delivered', 'delivered', 'delivered'),
|
('delivered', 'delivered', 'delivered'),
|
||||||
('failed', 'failed', 'failed'),
|
('failed', 'failed', 'failed'),
|
||||||
@@ -287,24 +288,22 @@ def _get_job_counts(job, help_argument):
|
|||||||
count
|
count
|
||||||
) for label, query_param, count in [
|
) for label, query_param, count in [
|
||||||
[
|
[
|
||||||
'Processed', '',
|
'total', '',
|
||||||
job.get('notifications_sent', 0)
|
job.get('notification_count', 0)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Sending', 'sending',
|
'sending', 'sending',
|
||||||
(
|
job.get('notification_count', 0) -
|
||||||
job.get('notifications_sent', 0) -
|
job.get('notifications_delivered', 0) -
|
||||||
job.get('notifications_delivered', 0) -
|
job.get('notifications_failed', 0)
|
||||||
job.get('notifications_failed', 0)
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Delivered', 'delivered',
|
'delivered', 'delivered',
|
||||||
job.get('notifications_delivered', 0)
|
job.get('notifications_delivered', 0)
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
'Failed', 'failed',
|
'failed', 'failed',
|
||||||
job.get('notifications_failed')
|
job.get('notifications_failed', 0)
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@@ -312,24 +311,27 @@ def _get_job_counts(job, help_argument):
|
|||||||
|
|
||||||
def get_job_partials(job):
|
def get_job_partials(job):
|
||||||
filter_args = _parse_filter_args(request.args)
|
filter_args = _parse_filter_args(request.args)
|
||||||
_set_status_filters(filter_args)
|
filter_args['status'] = _set_status_filters(filter_args)
|
||||||
|
notifications = notification_api_client.get_notifications_for_service(
|
||||||
|
job['service'], job['id'], status=filter_args['status']
|
||||||
|
)
|
||||||
return {
|
return {
|
||||||
'counts': render_template(
|
'counts': render_template(
|
||||||
'partials/jobs/count.html',
|
'partials/jobs/count.html',
|
||||||
job=job,
|
job=job,
|
||||||
counts=_get_job_counts(job, request.args.get('help', 0)),
|
counts=_get_job_counts(job, request.args.get('help', 0)),
|
||||||
status=request.args.get('status', '')
|
status=filter_args['status']
|
||||||
),
|
),
|
||||||
'notifications': render_template(
|
'notifications': render_template(
|
||||||
'partials/jobs/notifications.html',
|
'partials/jobs/notifications.html',
|
||||||
notifications=notification_api_client.get_notifications_for_service(
|
notifications=notifications['notifications'],
|
||||||
job['service'], job['id'], status=filter_args.get('status')
|
more_than_one_page=bool(notifications.get('links', {}).get('next')),
|
||||||
)['notifications'],
|
percentage_complete=(job['notifications_sent'] / job['notification_count'] * 100),
|
||||||
download_link=url_for(
|
download_link=url_for(
|
||||||
'.view_job_csv',
|
'.view_job_csv',
|
||||||
service_id=current_service['id'],
|
service_id=current_service['id'],
|
||||||
job_id=job['id'],
|
job_id=job['id'],
|
||||||
status=request.args.get('status', '')
|
status=request.args.get('status')
|
||||||
),
|
),
|
||||||
help=get_help_argument(),
|
help=get_help_argument(),
|
||||||
time_left=get_time_left(job['created_at'])
|
time_left=get_time_left(job['created_at'])
|
||||||
|
|||||||
@@ -103,13 +103,12 @@ def service_request_to_go_live(service_id):
|
|||||||
if form.validate_on_submit():
|
if form.validate_on_submit():
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'person_email': current_app.config.get('DESKPRO_PERSON_EMAIL'),
|
'person_email': current_user.email_address,
|
||||||
|
'person_name': current_user.name,
|
||||||
'department_id': current_app.config.get('DESKPRO_DEPT_ID'),
|
'department_id': current_app.config.get('DESKPRO_DEPT_ID'),
|
||||||
'agent_team_id': current_app.config.get('DESKPRO_ASSIGNED_AGENT_TEAM_ID'),
|
'agent_team_id': current_app.config.get('DESKPRO_ASSIGNED_AGENT_TEAM_ID'),
|
||||||
'subject': 'Request to go live',
|
'subject': 'Request to go live',
|
||||||
'message': "From {} <{}> on behalf of {} ({})\n\nUsage estimate\n---\n\n{}".format(
|
'message': "On behalf of {} ({})\n\nUsage estimate\n---\n\n{}".format(
|
||||||
current_user.name,
|
|
||||||
current_user.email_address,
|
|
||||||
current_service['name'],
|
current_service['name'],
|
||||||
url_for('main.service_dashboard', service_id=current_service['id'], _external=True),
|
url_for('main.service_dashboard', service_id=current_service['id'], _external=True),
|
||||||
form.usage.data
|
form.usage.data
|
||||||
|
|||||||
@@ -204,6 +204,9 @@ class ServiceAPIClient(NotificationsAPIClient):
|
|||||||
def get_service_usage(self, service_id):
|
def get_service_usage(self, service_id):
|
||||||
return self.get('/service/{0}/fragment/aggregate_statistics'.format(service_id))
|
return self.get('/service/{0}/fragment/aggregate_statistics'.format(service_id))
|
||||||
|
|
||||||
|
def get_weekly_notification_stats(self, service_id):
|
||||||
|
return self.get(url='/service/{}/notifications/weekly'.format(service_id))
|
||||||
|
|
||||||
|
|
||||||
class ServicesBrowsableItem(BrowsableItem):
|
class ServicesBrowsableItem(BrowsableItem):
|
||||||
@property
|
@property
|
||||||
|
|||||||
@@ -12,16 +12,15 @@ class StatisticsApiClient(BaseAPIClient):
|
|||||||
self.client_id = app.config['ADMIN_CLIENT_USER_NAME']
|
self.client_id = app.config['ADMIN_CLIENT_USER_NAME']
|
||||||
self.secret = app.config['ADMIN_CLIENT_SECRET']
|
self.secret = app.config['ADMIN_CLIENT_SECRET']
|
||||||
|
|
||||||
def get_7_day_aggregate_for_service(self, service_id, date_from=None, week_count=None):
|
def get_statistics_for_service_for_day(self, service_id, day):
|
||||||
params = {}
|
url = '/service/{}/notifications-statistics/day/{}'.format(service_id, day)
|
||||||
if date_from is not None:
|
try:
|
||||||
params['date_from'] = date_from
|
return self.get(url=url)['data']
|
||||||
if week_count is not None:
|
except HTTPError as e:
|
||||||
params['week_count'] = week_count
|
if e.status_code == 404:
|
||||||
return self.get(
|
return None
|
||||||
url='/service/{}/notifications-statistics/seven_day_aggregate'.format(service_id),
|
else:
|
||||||
params=params
|
raise e
|
||||||
)
|
|
||||||
|
|
||||||
def get_statistics_for_all_services_for_day(self, day):
|
def get_statistics_for_all_services_for_day(self, day):
|
||||||
params = {
|
params = {
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
{% if not expanded %}
|
{% if not expanded %}
|
||||||
<div class="email-message-body-wrapper">
|
<div class="email-message-body-wrapper">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{{ body|nl2br }}
|
{{ body }}
|
||||||
{% if not expanded %}
|
{% if not expanded %}
|
||||||
</div>
|
</div>
|
||||||
<div class='toggle' tabindex='0'>...<span class='visually-hidden'>show full email</span></div>
|
<div class='toggle' tabindex='0'>...<span class='visually-hidden'>show full email</span></div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
{% if help %}
|
{% if help %}
|
||||||
{% call banner_wrapper(type='tour') %}
|
{% call banner_wrapper(type='tour') %}
|
||||||
<p class="heading-medium">Try this example</p>
|
<p class="heading-medium">Try sending yourself this example</p>
|
||||||
<div class="grid-row bottom-gutter" {% if help != '1' %}style="opacity: 0.6"{% endif %}>
|
<div class="grid-row bottom-gutter" {% if help != '1' %}style="opacity: 0.6"{% endif %}>
|
||||||
<div class="column-one-sixth">
|
<div class="column-one-sixth">
|
||||||
<p class="heading-large" style="float: left;">1.</p>
|
<p class="heading-large" style="float: left;">1.</p>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{% from "components/pill.html" import pill %}
|
{% from "components/pill.html" import pill %}
|
||||||
|
|
||||||
<div class="bottom-gutter">
|
<div class="bottom-gutter">
|
||||||
{{ pill('Status', counts, status) }}
|
{{ pill('Status', counts, request.args.get('status', '')) }}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,12 +4,18 @@
|
|||||||
<div class="dashboard-table">
|
<div class="dashboard-table">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if notifications and not help %}
|
{% if not help %}
|
||||||
<p class="bottom-gutter">
|
{% if percentage_complete < 100 %}
|
||||||
<a href="{{ download_link }}" download="download" class="heading-small">Download this report</a>
|
<p class="bottom-gutter-1-2 hint">
|
||||||
 
|
Report is {{ "{:.0f}%".format(percentage_complete) }} complete…
|
||||||
<span id="time-left">{{ time_left }}</span>
|
</p>
|
||||||
</p>
|
{% elif notifications %}
|
||||||
|
<p class="bottom-gutter-1-2">
|
||||||
|
<a href="{{ download_link }}" download="download" class="heading-small">Download this report</a>
|
||||||
|
 
|
||||||
|
<span id="time-left">{{ time_left }}</span>
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% call(item, row_number) list_table(
|
{% call(item, row_number) list_table(
|
||||||
@@ -44,6 +50,12 @@
|
|||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
|
{% if more_than_one_page %}
|
||||||
|
<p class="table-show-more-link">
|
||||||
|
Only showing the first 50 rows
|
||||||
|
</p>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
{% if notifications %}
|
{% if notifications %}
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
<details>
|
<h2 class="heading-medium">Message length</h2>
|
||||||
<summary class="button tertiary-button">Message length</summary>
|
<p>
|
||||||
<div id="guidance-personalisation">
|
If your message is long then it will
|
||||||
<p>
|
cost more.
|
||||||
If your message is long then it will
|
</p>
|
||||||
cost more.
|
<p>
|
||||||
</p>
|
See <a href="{{ url_for('.pricing') }}">pricing</a> for details.
|
||||||
<p>
|
</p>
|
||||||
See <a href="{{ url_for('.pricing') }}">pricing</a> for details.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|||||||
27
app/templates/partials/templates/guidance-formatting.html
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<h2 class="heading-medium">Formatting</h2>
|
||||||
|
<p>
|
||||||
|
To put a title in your template, use a hash:
|
||||||
|
</p>
|
||||||
|
<div class="panel panel-border-wide">
|
||||||
|
<p>
|
||||||
|
# This is a title
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
To make bullet points, use asterisks:
|
||||||
|
</p>
|
||||||
|
<div class="panel panel-border-wide">
|
||||||
|
<p>
|
||||||
|
* point 1<br/>
|
||||||
|
* point 2<br/>
|
||||||
|
* point 3<br/>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<p>
|
||||||
|
To add a callout, use a caret:
|
||||||
|
</p>
|
||||||
|
<div class="panel panel-border-wide">
|
||||||
|
<p>
|
||||||
|
^ You must tell us if your circumstances change
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
<details>
|
<h2 class="heading-medium">Links and URLs</h2>
|
||||||
<summary class="button tertiary-button">Links and URLs</summary>
|
<p>
|
||||||
<div id="guidance-personalisation">
|
Always use full URLs, starting with https://
|
||||||
<p>
|
</p>
|
||||||
Always use full URLs, starting with https://
|
<div class="panel panel-border-wide">
|
||||||
</p>
|
<p>
|
||||||
</div>
|
Apply now at https://www.gov.uk/example
|
||||||
</details>
|
</p>
|
||||||
|
</div>
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
<details>
|
<h2 class="heading-medium">
|
||||||
<summary class="button tertiary-button">Personalisation</summary>
|
Personalisation
|
||||||
<div id="guidance-personalisation">
|
</h2>
|
||||||
<p>
|
<p>
|
||||||
Use double brackets to add personalisation.
|
Use double brackets to personalise your message:
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<div class="panel panel-border-wide">
|
||||||
Correct: ((name))
|
<p>
|
||||||
</p>
|
Hello ((first name)), your reference is ((ref number))
|
||||||
<p>
|
</p>
|
||||||
Incorrect: ((Helen))
|
</div>
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</details>
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call field() %}
|
{% call field() %}
|
||||||
{{ big_number(
|
{{ big_number(
|
||||||
item.get('notifications_sent', 0) - item.get('notifications_delivered', 0) - item.get('notifications_failed', 0),
|
item.get('notification_count', 0) - item.get('notifications_delivered', 0) - item.get('notifications_failed', 0),
|
||||||
smallest=True
|
smallest=True
|
||||||
) }}
|
) }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
{% if not templates %}
|
{% if not templates %}
|
||||||
{% include 'views/dashboard/write-first-messages.html' %}
|
{% include 'views/dashboard/write-first-messages.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% elif not current_user.has_permissions(['send_texts', 'send_emails', 'send_letters'], any_=True) %}
|
{% elif not current_user.has_permissions(['send_texts', 'send_emails', 'send_letters', 'manage_api_keys'], any_=True) %}
|
||||||
{% include 'views/dashboard/no-permissions-banner.html' %}
|
{% include 'views/dashboard/no-permissions-banner.html' %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -14,11 +14,11 @@
|
|||||||
|
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<div class="grid-row">
|
<div class="grid-row">
|
||||||
<div class="column-two-thirds">
|
<div class="column-three-quarters">
|
||||||
{{ textbox(form.name, width='1-1', hint='Your recipients won’t see this', rows=10) }}
|
{{ textbox(form.name, width='1-1', hint='Your recipients won’t see this', rows=10) }}
|
||||||
{{ textbox(form.subject, width='1-1', highlight_tags=True, rows=2) }}
|
{{ textbox(form.subject, width='1-1', highlight_tags=True, rows=2) }}
|
||||||
</div>
|
</div>
|
||||||
<div class="column-two-thirds">
|
<div class="column-three-quarters">
|
||||||
{{ textbox(form.template_content, highlight_tags=True, width='1-1', rows=8) }}
|
{{ textbox(form.template_content, highlight_tags=True, width='1-1', rows=8) }}
|
||||||
{{ page_footer(
|
{{ page_footer(
|
||||||
'Save',
|
'Save',
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
delete_link_text='Delete this template'
|
delete_link_text='Delete this template'
|
||||||
) }}
|
) }}
|
||||||
</div>
|
</div>
|
||||||
<aside class="column-one-third">
|
<aside class="column-whole">
|
||||||
<h2 style="margin: 0 0 5px 0;">Help</h2>
|
{% include "partials/templates/guidance-formatting.html" %}
|
||||||
{% include "partials/templates/guidance-personalisation.html" %}
|
{% include "partials/templates/guidance-personalisation.html" %}
|
||||||
{% include "partials/templates/guidance-links.html" %}
|
{% include "partials/templates/guidance-links.html" %}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -25,8 +25,7 @@
|
|||||||
delete_link_text='Delete this template'
|
delete_link_text='Delete this template'
|
||||||
) }}
|
) }}
|
||||||
</div>
|
</div>
|
||||||
<aside class="column-one-third">
|
<aside class="column-whole">
|
||||||
<h2 style="margin: 0 0 5px 0;">Help</h2>
|
|
||||||
{% include "partials/templates/guidance-personalisation.html" %}
|
{% include "partials/templates/guidance-personalisation.html" %}
|
||||||
{% include "partials/templates/guidance-links.html" %}
|
{% include "partials/templates/guidance-links.html" %}
|
||||||
{% include "partials/templates/guidance-character-count.html" %}
|
{% include "partials/templates/guidance-character-count.html" %}
|
||||||
|
|||||||
@@ -14,9 +14,9 @@
|
|||||||
<h1 class="heading-large">
|
<h1 class="heading-large">
|
||||||
|
|
||||||
<span class="visually-hidden">
|
<span class="visually-hidden">
|
||||||
{%- if request_args.get('status') != 'delivered,failed' -%}
|
{%- if status != 'delivered,failed' -%}
|
||||||
{%- for label, option, _, _ in status_filters -%}
|
{%- for label, option, _, _ in status_filters -%}
|
||||||
{%- if request_args.get('status', 'delivered,failed') == option -%}{{label}} {% endif -%}
|
{%- if status == option -%}{{label}} {% endif -%}
|
||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{%- endif -%}
|
{%- endif -%}
|
||||||
</span>
|
</span>
|
||||||
@@ -29,15 +29,15 @@
|
|||||||
{{ pill(
|
{{ pill(
|
||||||
'Status',
|
'Status',
|
||||||
status_filters,
|
status_filters,
|
||||||
request_args.get('status', '')
|
status
|
||||||
) }}
|
) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if notifications %}
|
{% if notifications %}
|
||||||
<p class="bottom-gutter">
|
<p class="bottom-gutter-1-2">
|
||||||
<a href="{{ download_link }}" download="download" class="heading-small">Download as a CSV file</a>
|
<a href="{{ download_link }}" download="download" class="heading-small">Download this report</a>
|
||||||
 
|
 
|
||||||
Delivery information is available for 7 days
|
Data available for 7 days
|
||||||
</p>
|
</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
{% extends "withnav_template.html" %}
|
{% extends "withnav_template.html" %}
|
||||||
|
|
||||||
{% block page_title %}
|
{% block page_title %}
|
||||||
Daily – GOV.UK Notify
|
Previous weeks – GOV.UK Notify
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
{% block maincolumn_content %}
|
{% block maincolumn_content %}
|
||||||
@@ -33,16 +33,16 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call field(align='right') %}
|
{% call field(align='right') %}
|
||||||
{{ item.emails_requested }}
|
{{ item.email.requested }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call field(align='right') %}
|
{% call field(align='right') %}
|
||||||
{{ item.emails_failure_rate }}%
|
{{ item.email.failure_rate }}%
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call field(align='right') %}
|
{% call field(align='right') %}
|
||||||
{{ item.sms_requested }}
|
{{ item.sms.requested }}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% call field(align='right') %}
|
{% call field(align='right') %}
|
||||||
{{ item.sms_failure_rate }}%
|
{{ item.sms.failure_rate }}%
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,3 @@
|
|||||||
__travis_commit__ = "dev"
|
__travis_commit__ = ""
|
||||||
__time__ = "dev"
|
__time__ = "2016-07-05:14:44:52"
|
||||||
__travis_job_number__ = "dev"
|
__travis_job_number__ = ""
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
---
|
---
|
||||||
files:
|
files:
|
||||||
-
|
-
|
||||||
destination: /home/ubuntu/notifications-admin
|
destination: /home/notify-app/notifications-admin
|
||||||
source: /
|
source: /
|
||||||
hooks:
|
hooks:
|
||||||
AfterInstall:
|
AfterInstall:
|
||||||
|
|||||||
27
config.py
@@ -3,7 +3,6 @@ from datetime import timedelta
|
|||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
|
||||||
DEBUG = False
|
DEBUG = False
|
||||||
ADMIN_CLIENT_SECRET = os.environ['ADMIN_CLIENT_SECRET']
|
ADMIN_CLIENT_SECRET = os.environ['ADMIN_CLIENT_SECRET']
|
||||||
ADMIN_CLIENT_USER_NAME = os.environ['ADMIN_CLIENT_USER_NAME']
|
ADMIN_CLIENT_USER_NAME = os.environ['ADMIN_CLIENT_USER_NAME']
|
||||||
@@ -36,7 +35,7 @@ class Config(object):
|
|||||||
CSV_UPLOAD_BUCKET_NAME = 'local-notifications-csv-upload'
|
CSV_UPLOAD_BUCKET_NAME = 'local-notifications-csv-upload'
|
||||||
DESKPRO_API_HOST = os.environ['DESKPRO_API_HOST']
|
DESKPRO_API_HOST = os.environ['DESKPRO_API_HOST']
|
||||||
DESKPRO_API_KEY = os.environ['DESKPRO_API_KEY']
|
DESKPRO_API_KEY = os.environ['DESKPRO_API_KEY']
|
||||||
DESKPRO_PERSON_EMAIL = os.environ['DESKPRO_PERSON_EMAIL']
|
DESKPRO_PERSON_EMAIL = 'donotreply@notifications.service.gov.uk'
|
||||||
DESKPRO_DEPT_ID = os.environ['DESKPRO_DEPT_ID']
|
DESKPRO_DEPT_ID = os.environ['DESKPRO_DEPT_ID']
|
||||||
DESKPRO_ASSIGNED_AGENT_TEAM_ID = os.environ['DESKPRO_ASSIGNED_AGENT_TEAM_ID']
|
DESKPRO_ASSIGNED_AGENT_TEAM_ID = os.environ['DESKPRO_ASSIGNED_AGENT_TEAM_ID']
|
||||||
ACTIVITY_STATS_LIMIT_DAYS = 7
|
ACTIVITY_STATS_LIMIT_DAYS = 7
|
||||||
@@ -78,10 +77,24 @@ class Preview(Config):
|
|||||||
CSV_UPLOAD_BUCKET_NAME = 'preview-notifications-csv-upload'
|
CSV_UPLOAD_BUCKET_NAME = 'preview-notifications-csv-upload'
|
||||||
|
|
||||||
|
|
||||||
|
class Staging(Config):
|
||||||
|
SHOW_STYLEGUIDE = False
|
||||||
|
HTTP_PROTOCOL = 'https'
|
||||||
|
HEADER_COLOUR = '#F47738' # $orange
|
||||||
|
CSV_UPLOAD_BUCKET_NAME = 'staging-notify-csv-upload'
|
||||||
|
|
||||||
|
|
||||||
|
class Live(Config):
|
||||||
|
SHOW_STYLEGUIDE = False
|
||||||
|
HEADER_COLOUR = '#B10E1E' # $red
|
||||||
|
HTTP_PROTOCOL = 'https'
|
||||||
|
CSV_UPLOAD_BUCKET_NAME = 'live-notifications-csv-upload'
|
||||||
|
|
||||||
|
|
||||||
configs = {
|
configs = {
|
||||||
'development': 'config.Development',
|
'development': Development,
|
||||||
'test': 'config.Test',
|
'test': Test,
|
||||||
'preview': 'config.Preview',
|
'preview': Preview,
|
||||||
'staging': 'config_staging.Staging',
|
'staging': Staging,
|
||||||
'live': 'config_live.Live'
|
'live': Live
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,17 +0,0 @@
|
|||||||
import os
|
|
||||||
from config import Config
|
|
||||||
|
|
||||||
|
|
||||||
class Live(Config):
|
|
||||||
SHOW_STYLEGUIDE = False
|
|
||||||
HEADER_COLOUR = '#B10E1E' # $red
|
|
||||||
HTTP_PROTOCOL = 'https'
|
|
||||||
API_HOST_NAME = os.environ['LIVE_API_HOST_NAME']
|
|
||||||
ADMIN_CLIENT_SECRET = os.environ['LIVE_ADMIN_CLIENT_SECRET']
|
|
||||||
SECRET_KEY = os.environ['LIVE_SECRET_KEY']
|
|
||||||
DANGEROUS_SALT = os.environ['LIVE_DANGEROUS_SALT']
|
|
||||||
CSV_UPLOAD_BUCKET_NAME = 'live-notifications-csv-upload'
|
|
||||||
DESKPRO_API_KEY = os.environ['LIVE_DESKPRO_API_KEY']
|
|
||||||
DESKPRO_DEPT_ID = os.environ['LIVE_DESKPRO_DEPT_ID']
|
|
||||||
DESKPRO_ASSIGNED_AGENT_TEAM_ID = os.environ['LIVE_DESKPRO_ASSIGNED_AGENT_TEAM_ID']
|
|
||||||
HEADER_COLOUR = '#B10E1E' # $red
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
import os
|
|
||||||
from config import Config
|
|
||||||
|
|
||||||
|
|
||||||
class Staging(Config):
|
|
||||||
SHOW_STYLEGUIDE = False
|
|
||||||
HTTP_PROTOCOL = 'https'
|
|
||||||
API_HOST_NAME = os.environ['STAGING_API_HOST_NAME']
|
|
||||||
ADMIN_CLIENT_SECRET = os.environ['STAGING_ADMIN_CLIENT_SECRET']
|
|
||||||
SECRET_KEY = os.environ['STAGING_SECRET_KEY']
|
|
||||||
DANGEROUS_SALT = os.environ['STAGING_DANGEROUS_SALT']
|
|
||||||
CSV_UPLOAD_BUCKET_NAME = 'staging-notifications-csv-upload'
|
|
||||||
DESKPRO_API_KEY = os.environ['STAGING_DESKPRO_API_KEY']
|
|
||||||
DESKPRO_DEPT_ID = os.environ['STAGING_DESKPRO_DEPT_ID']
|
|
||||||
DESKPRO_ASSIGNED_AGENT_TEAM_ID = os.environ['STAGING_DESKPRO_ASSIGNED_AGENT_TEAM_ID']
|
|
||||||
HEADER_COLOUR = '#F47738' # $orange
|
|
||||||
@@ -42,7 +42,7 @@ To create JSON Web Tokens you need:
|
|||||||
* your Service ID – identifies your service
|
* your Service ID – identifies your service
|
||||||
* your API key (in JSON Web Token terms this is called the client ID) – used to sign tokens during requests for API resources
|
* your API key (in JSON Web Token terms this is called the client ID) – used to sign tokens during requests for API resources
|
||||||
|
|
||||||
To find your Service ID and create or revoke API keys, click on **API keys** in the [GOV.UK Notify](https://www.notifications.service.gov.uk/) web application.
|
To find your Service ID and create or revoke API keys, click on **API integration** in the [GOV.UK Notify](https://www.notifications.service.gov.uk/) web application.
|
||||||
|
|
||||||
<h3 id="JWT_claims">JSON Web Tokens: claims</h3>
|
<h3 id="JWT_claims">JSON Web Tokens: claims</h3>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
export NOTIFY_ADMIN_ENVIRONMENT='config.Test'
|
export NOTIFY_ENVIRONMENT='test'
|
||||||
export ADMIN_CLIENT_SECRET='dev-notify-secret-key'
|
export ADMIN_CLIENT_SECRET='dev-notify-secret-key'
|
||||||
export ADMIN_CLIENT_USER_NAME='dev-notify-admin'
|
export ADMIN_CLIENT_USER_NAME='dev-notify-admin'
|
||||||
export API_HOST_NAME=''
|
export API_HOST_NAME=''
|
||||||
@@ -6,6 +6,5 @@ export DANGEROUS_SALT='dev-notify-salt'
|
|||||||
export SECRET_KEY='dev-notify-secret-key'
|
export SECRET_KEY='dev-notify-secret-key'
|
||||||
export DESKPRO_API_HOST=""
|
export DESKPRO_API_HOST=""
|
||||||
export DESKPRO_API_KEY=""
|
export DESKPRO_API_KEY=""
|
||||||
export DESKPRO_PERSON_EMAIL=""
|
|
||||||
export DESKPRO_DEPT_ID=""
|
export DESKPRO_DEPT_ID=""
|
||||||
export DESKPRO_ASSIGNED_AGENT_TEAM_ID=""
|
export DESKPRO_ASSIGNED_AGENT_TEAM_ID=""
|
||||||
|
|||||||
@@ -19,4 +19,4 @@ pytz==2016.4
|
|||||||
|
|
||||||
git+https://github.com/alphagov/notifications-python-client.git@1.0.0#egg=notifications-python-client==1.0.0
|
git+https://github.com/alphagov/notifications-python-client.git@1.0.0#egg=notifications-python-client==1.0.0
|
||||||
|
|
||||||
git+https://github.com/alphagov/notifications-utils.git@8.7.1#egg=notifications-utils==8.7.1
|
git+https://github.com/alphagov/notifications-utils.git@8.7.2#egg=notifications-utils==8.7.2
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "Chown application to be owned by ubuntu"
|
echo "Chown application to be owned by ubuntu"
|
||||||
cd /home/ubuntu/;
|
cd /home/notify-app/;
|
||||||
chown -R ubuntu:ubuntu notifications-admin
|
chown -R notify-app:govuk-notify-applications notifications-admin
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "Install dependencies"
|
echo "Install dependencies"
|
||||||
cd /home/ubuntu/notifications-admin;
|
cd /home/notify-app/notifications-admin;
|
||||||
pip3 install -r /home/ubuntu/notifications-admin/requirements.txt
|
pip3 install -r /home/notify-app/notifications-admin/requirements.txt
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
echo "Starting application"
|
echo "Starting application"
|
||||||
cd ~/notifications-admin/;
|
|
||||||
sudo service notifications-admin start
|
sudo service notifications-admin start
|
||||||
@@ -101,7 +101,7 @@ reset_waiter_timeout() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Base register/deregister action may take up to about 30 seconds
|
# Base register/deregister action may take up to about 30 seconds
|
||||||
timeout=$((timeout + 30))
|
timeout=$((timeout + 60))
|
||||||
|
|
||||||
WAITER_ATTEMPTS=$((timeout / WAITER_INTERVAL))
|
WAITER_ATTEMPTS=$((timeout / WAITER_INTERVAL))
|
||||||
}
|
}
|
||||||
@@ -183,7 +183,7 @@ get_instance_health_elb() {
|
|||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
msg "Instance '$instance_id' not part of ELB '$elb_name'"
|
msg "Instance '$instance_id' not part of ELB '$elb_name'"
|
||||||
return 1
|
return 0
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ display_result $? 1 "Code style check"
|
|||||||
npm test
|
npm test
|
||||||
display_result $? 2 "Front end code style check"
|
display_result $? 2 "Front end code style check"
|
||||||
|
|
||||||
export NOTIFY_ADMIN_ENVIRONMENT='config.Test'
|
|
||||||
|
|
||||||
## Code coverage
|
## Code coverage
|
||||||
py.test -n2 --cov=app --cov-report=term-missing tests/
|
py.test -n2 --cov=app --cov-report=term-missing tests/
|
||||||
display_result $? 3 "Code coverage"
|
display_result $? 3 "Code coverage"
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from datetime import datetime
|
||||||
import copy
|
import copy
|
||||||
from flask import url_for
|
from flask import url_for
|
||||||
|
|
||||||
@@ -5,7 +6,7 @@ import pytest
|
|||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from app.main.views.dashboard import get_dashboard_totals
|
from app.main.views.dashboard import get_dashboard_totals, format_weekly_stats_to_list
|
||||||
|
|
||||||
from tests import validate_route_permission
|
from tests import validate_route_permission
|
||||||
from tests.conftest import SERVICE_ONE_ID
|
from tests.conftest import SERVICE_ONE_ID
|
||||||
@@ -65,7 +66,6 @@ def test_get_started(
|
|||||||
api_user_active,
|
api_user_active,
|
||||||
mock_get_service,
|
mock_get_service,
|
||||||
mock_get_service_templates_when_no_templates_exist,
|
mock_get_service_templates_when_no_templates_exist,
|
||||||
mock_get_aggregate_service_statistics,
|
|
||||||
mock_get_user,
|
mock_get_user,
|
||||||
mock_get_user_by_email,
|
mock_get_user_by_email,
|
||||||
mock_login,
|
mock_login,
|
||||||
@@ -94,7 +94,6 @@ def test_get_started_is_hidden_once_templates_exist(
|
|||||||
api_user_active,
|
api_user_active,
|
||||||
mock_get_service,
|
mock_get_service,
|
||||||
mock_get_service_templates,
|
mock_get_service_templates,
|
||||||
mock_get_aggregate_service_statistics,
|
|
||||||
mock_get_user,
|
mock_get_user,
|
||||||
mock_get_user_by_email,
|
mock_get_user_by_email,
|
||||||
mock_login,
|
mock_login,
|
||||||
@@ -119,7 +118,6 @@ def test_should_show_recent_templates_on_dashboard(app_,
|
|||||||
api_user_active,
|
api_user_active,
|
||||||
mock_get_service,
|
mock_get_service,
|
||||||
mock_get_service_templates,
|
mock_get_service_templates,
|
||||||
mock_get_aggregate_service_statistics,
|
|
||||||
mock_get_user,
|
mock_get_user,
|
||||||
mock_get_user_by_email,
|
mock_get_user_by_email,
|
||||||
mock_login,
|
mock_login,
|
||||||
@@ -204,7 +202,6 @@ def test_should_show_recent_jobs_on_dashboard(
|
|||||||
api_user_active,
|
api_user_active,
|
||||||
mock_get_service,
|
mock_get_service,
|
||||||
mock_get_service_templates,
|
mock_get_service_templates,
|
||||||
mock_get_aggregate_service_statistics,
|
|
||||||
mock_get_user,
|
mock_get_user,
|
||||||
mock_get_user_by_email,
|
mock_get_user_by_email,
|
||||||
mock_login,
|
mock_login,
|
||||||
@@ -482,3 +479,46 @@ def test_get_dashboard_totals_adds_warning(failures, expected):
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert get_dashboard_totals(stats)['sms']['show_warning'] == expected
|
assert get_dashboard_totals(stats)['sms']['show_warning'] == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_weekly_stats_to_list_empty_case():
|
||||||
|
assert format_weekly_stats_to_list({}) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_weekly_stats_to_list_sorts_by_week():
|
||||||
|
stats = {
|
||||||
|
'2016-07-04': {},
|
||||||
|
'2016-07-11': {},
|
||||||
|
'2016-07-18': {},
|
||||||
|
'2016-07-25': {}
|
||||||
|
}
|
||||||
|
resp = format_weekly_stats_to_list(stats)
|
||||||
|
assert resp[0]['week_start'] == '2016-07-25'
|
||||||
|
assert resp[1]['week_start'] == '2016-07-18'
|
||||||
|
assert resp[2]['week_start'] == '2016-07-11'
|
||||||
|
assert resp[3]['week_start'] == '2016-07-04'
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_weekly_stats_to_list_includes_datetime_for_comparison():
|
||||||
|
stats = {
|
||||||
|
'2016-07-25': {}
|
||||||
|
}
|
||||||
|
resp = format_weekly_stats_to_list(stats)
|
||||||
|
assert resp == [{
|
||||||
|
'week_start': '2016-07-25',
|
||||||
|
'week_end': '2016-07-31',
|
||||||
|
'week_end_datetime': datetime(2016, 7, 31, 0, 0, 0)
|
||||||
|
}]
|
||||||
|
|
||||||
|
|
||||||
|
def test_format_weekly_stats_to_list_has_stats_with_failure_rate():
|
||||||
|
stats = {
|
||||||
|
'2016-07-25': {'sms': _stats(3, 1, 2)}
|
||||||
|
}
|
||||||
|
resp = format_weekly_stats_to_list(stats)
|
||||||
|
assert resp[0]['sms']['failure_rate'] == '66.7'
|
||||||
|
assert resp[0]['sms']['requested'] == 3
|
||||||
|
|
||||||
|
|
||||||
|
def _stats(requested, delivered, failed):
|
||||||
|
return {'requested': requested, 'delivered': delivered, 'failed': failed}
|
||||||
|
|||||||
@@ -26,17 +26,27 @@ def test_get_feedback_page(app_):
|
|||||||
assert resp.status_code == 200
|
assert resp.status_code == 200
|
||||||
|
|
||||||
|
|
||||||
def test_post_feedback_with_no_name_email(app_, mocker):
|
def test_post_feedback_with_name_but_no_email(app_, mocker):
|
||||||
mock_post = mocker.patch(
|
mock_post = mocker.patch(
|
||||||
'app.main.views.feedback.requests.post',
|
'app.main.views.feedback.requests.post',
|
||||||
return_value=Mock(status_code=201))
|
return_value=Mock(status_code=201))
|
||||||
with app_.test_request_context():
|
with app_.test_request_context():
|
||||||
with app_.test_client() as client:
|
with app_.test_client() as client:
|
||||||
resp = client.post(url_for('main.feedback'), data={'feedback': "blah"})
|
resp = client.post(url_for('main.feedback'), data={'feedback': "blah", 'name': 'Fred'})
|
||||||
assert resp.status_code == 302
|
assert resp.status_code == 302
|
||||||
|
mock_post.assert_called_with(
|
||||||
|
ANY,
|
||||||
|
data={
|
||||||
|
'department_id': ANY,
|
||||||
|
'agent_team_id': ANY,
|
||||||
|
'subject': 'Notify feedback',
|
||||||
|
'message': 'Environment: http://localhost/\nFred (no email address supplied)\nblah',
|
||||||
|
'person_email': app_.config['DESKPRO_PERSON_EMAIL'],
|
||||||
|
'person_name': 'Fred'},
|
||||||
|
headers=ANY)
|
||||||
|
|
||||||
|
|
||||||
def test_post_feedback_with_no_name_email(app_, mocker):
|
def test_post_feedback_with_no_name_or_email(app_, mocker):
|
||||||
mock_post = mocker.patch(
|
mock_post = mocker.patch(
|
||||||
'app.main.views.feedback.requests.post',
|
'app.main.views.feedback.requests.post',
|
||||||
return_value=Mock(status_code=201))
|
return_value=Mock(status_code=201))
|
||||||
@@ -50,8 +60,9 @@ def test_post_feedback_with_no_name_email(app_, mocker):
|
|||||||
'department_id': ANY,
|
'department_id': ANY,
|
||||||
'agent_team_id': ANY,
|
'agent_team_id': ANY,
|
||||||
'subject': 'Notify feedback',
|
'subject': 'Notify feedback',
|
||||||
'message': 'Environment: http://localhost/\n\n\n\nblah',
|
'message': 'Environment: http://localhost/\n (no email address supplied)\nblah',
|
||||||
'person_email': ANY},
|
'person_email': app_.config['DESKPRO_PERSON_EMAIL'],
|
||||||
|
'person_name': None},
|
||||||
headers=ANY)
|
headers=ANY)
|
||||||
|
|
||||||
|
|
||||||
@@ -71,8 +82,9 @@ def test_post_feedback_with_name_email(app_, mocker):
|
|||||||
'subject': 'Notify feedback',
|
'subject': 'Notify feedback',
|
||||||
'department_id': ANY,
|
'department_id': ANY,
|
||||||
'agent_team_id': ANY,
|
'agent_team_id': ANY,
|
||||||
'message': 'Environment: http://localhost/\n\nSteve Irwin\nrip@gmail.com\nblah',
|
'message': 'Environment: http://localhost/\n\nblah',
|
||||||
'person_email': ANY},
|
'person_name': 'Steve Irwin',
|
||||||
|
'person_email': 'rip@gmail.com'},
|
||||||
headers=ANY)
|
headers=ANY)
|
||||||
|
|
||||||
|
|
||||||
@@ -91,14 +103,6 @@ def test_log_error_on_post(app_, mocker):
|
|||||||
resp = client.post(
|
resp = client.post(
|
||||||
url_for('main.feedback'),
|
url_for('main.feedback'),
|
||||||
data={'feedback': "blah", 'name': "Steve Irwin", 'email_address': 'rip@gmail.com'})
|
data={'feedback': "blah", 'name': "Steve Irwin", 'email_address': 'rip@gmail.com'})
|
||||||
mock_post.assert_called_with(
|
assert mock_post.called
|
||||||
ANY,
|
|
||||||
data={
|
|
||||||
'subject': 'Notify feedback',
|
|
||||||
'department_id': ANY,
|
|
||||||
'agent_team_id': ANY,
|
|
||||||
'message': 'Environment: http://localhost/\n\nSteve Irwin\nrip@gmail.com\nblah',
|
|
||||||
'person_email': ANY},
|
|
||||||
headers=ANY)
|
|
||||||
mock_logger.assert_called_with(
|
mock_logger.assert_called_with(
|
||||||
"Deskpro create ticket request failed with {} '{}'".format(mock_post().status_code, mock_post().json()))
|
"Deskpro create ticket request failed with {} '{}'".format(mock_post().status_code, mock_post().json()))
|
||||||
|
|||||||
@@ -32,15 +32,11 @@ def test_should_return_list_of_all_jobs(app_,
|
|||||||
"status_argument, expected_api_call", [
|
"status_argument, expected_api_call", [
|
||||||
(
|
(
|
||||||
'',
|
'',
|
||||||
['sending', 'delivered', 'failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
['created', 'sending', 'delivered', 'failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
||||||
),
|
|
||||||
(
|
|
||||||
'processed',
|
|
||||||
['sending', 'delivered', 'failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'sending',
|
'sending',
|
||||||
['sending']
|
['sending', 'created']
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'delivered',
|
'delivered',
|
||||||
@@ -99,6 +95,7 @@ def test_should_show_page_for_one_job(
|
|||||||
)
|
)
|
||||||
assert csv_link.text == 'Download this report'
|
assert csv_link.text == 'Download this report'
|
||||||
assert page.find('span', {'id': 'time-left'}).text == 'Data available for 7 days'
|
assert page.find('span', {'id': 'time-left'}).text == 'Data available for 7 days'
|
||||||
|
assert page.find('p', {'class': 'table-show-more-link'}).text.strip() == 'Only showing the first 50 rows'
|
||||||
mock_get_notifications.assert_called_with(
|
mock_get_notifications.assert_called_with(
|
||||||
service_one['id'],
|
service_one['id'],
|
||||||
fake_uuid,
|
fake_uuid,
|
||||||
@@ -106,6 +103,29 @@ def test_should_show_page_for_one_job(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_should_show_job_in_progress(
|
||||||
|
app_,
|
||||||
|
service_one,
|
||||||
|
active_user_with_permissions,
|
||||||
|
mock_get_service_template,
|
||||||
|
mock_get_job_in_progress,
|
||||||
|
mocker,
|
||||||
|
mock_get_notifications,
|
||||||
|
fake_uuid
|
||||||
|
):
|
||||||
|
with app_.test_request_context(), app_.test_client() as client:
|
||||||
|
client.login(active_user_with_permissions, mocker, service_one)
|
||||||
|
response = client.get(url_for(
|
||||||
|
'main.view_job',
|
||||||
|
service_id=service_one['id'],
|
||||||
|
job_id=fake_uuid
|
||||||
|
))
|
||||||
|
|
||||||
|
assert response.status_code == 200
|
||||||
|
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||||
|
assert page.find('p', {'class': 'hint'}).text.strip() == 'Report is 50% complete…'
|
||||||
|
|
||||||
|
|
||||||
def test_should_show_not_show_csv_download_in_tour(
|
def test_should_show_not_show_csv_download_in_tour(
|
||||||
app_,
|
app_,
|
||||||
service_one,
|
service_one,
|
||||||
@@ -179,12 +199,12 @@ def test_should_show_updates_for_one_job_as_json(
|
|||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"status_argument, expected_api_call", [
|
"status_argument, expected_api_call", [
|
||||||
(
|
(
|
||||||
'processed',
|
'',
|
||||||
['sending', 'delivered', 'failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
['created', 'sending', 'delivered', 'failed', 'temporary-failure', 'permanent-failure', 'technical-failure']
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'sending',
|
'sending',
|
||||||
['sending']
|
['sending', 'created']
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
'delivered',
|
'delivered',
|
||||||
@@ -275,10 +295,21 @@ def test_should_show_notifications_for_a_service_with_next_previous(
|
|||||||
))
|
))
|
||||||
assert response.status_code == 200
|
assert response.status_code == 200
|
||||||
content = response.get_data(as_text=True)
|
content = response.get_data(as_text=True)
|
||||||
assert url_for('main.view_notifications', service_id=service_one['id'], message_type='sms', page=3) in content
|
page = BeautifulSoup(response.data.decode('utf-8'), 'html.parser')
|
||||||
assert url_for('main.view_notifications', service_id=service_one['id'], message_type='sms', page=1) in content
|
next_page_link = page.find('a', {'rel': 'next'})
|
||||||
assert 'Previous page' in content
|
prev_page_link = page.find('a', {'rel': 'previous'})
|
||||||
assert 'Next page' in content
|
assert (
|
||||||
|
url_for('main.view_notifications', service_id=service_one['id'], message_type='sms', page=3) in
|
||||||
|
next_page_link['href']
|
||||||
|
)
|
||||||
|
assert 'Next page' in next_page_link.text.strip()
|
||||||
|
assert 'page 3' in next_page_link.text.strip()
|
||||||
|
assert (
|
||||||
|
url_for('main.view_notifications', service_id=service_one['id'], message_type='sms', page=1) in
|
||||||
|
prev_page_link['href']
|
||||||
|
)
|
||||||
|
assert 'Previous page' in prev_page_link.text.strip()
|
||||||
|
assert 'page 1' in prev_page_link.text.strip()
|
||||||
|
|
||||||
|
|
||||||
@freeze_time("2016-01-01 11:09:00.061258")
|
@freeze_time("2016-01-01 11:09:00.061258")
|
||||||
@@ -335,7 +366,7 @@ def test_get_status_filters_calculates_stats(app_):
|
|||||||
ret = get_status_filters({'id': 'foo'}, 'sms', STATISTICS)
|
ret = get_status_filters({'id': 'foo'}, 'sms', STATISTICS)
|
||||||
|
|
||||||
assert {label: count for label, _option, _link, count in ret} == {
|
assert {label: count for label, _option, _link, count in ret} == {
|
||||||
'processed': 6,
|
'total': 6,
|
||||||
'sending': 3,
|
'sending': 3,
|
||||||
'failed': 2,
|
'failed': 2,
|
||||||
'delivered': 1
|
'delivered': 1
|
||||||
@@ -347,7 +378,7 @@ def test_get_status_filters_in_right_order(app_):
|
|||||||
ret = get_status_filters({'id': 'foo'}, 'sms', STATISTICS)
|
ret = get_status_filters({'id': 'foo'}, 'sms', STATISTICS)
|
||||||
|
|
||||||
assert [label for label, _option, _link, _count in ret] == [
|
assert [label for label, _option, _link, _count in ret] == [
|
||||||
'processed', 'sending', 'delivered', 'failed'
|
'total', 'sending', 'delivered', 'failed'
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -241,10 +241,9 @@ def test_should_redirect_after_request_to_go_live(
|
|||||||
'subject': 'Request to go live',
|
'subject': 'Request to go live',
|
||||||
'department_id': ANY,
|
'department_id': ANY,
|
||||||
'agent_team_id': ANY,
|
'agent_team_id': ANY,
|
||||||
'message': 'From Test User <test@user.gov.uk> on behalf of Test Service (http://localhost/services/6ce466d0-fd6a-11e5-82f5-e0accb9d11a6/dashboard)\n\nUsage estimate\n---\n\nOne million messages', # noqa
|
'message': 'On behalf of Test Service (http://localhost/services/6ce466d0-fd6a-11e5-82f5-e0accb9d11a6/dashboard)\n\nUsage estimate\n---\n\nOne million messages', # noqa
|
||||||
# noqa
|
'person_name': api_user_active.name,
|
||||||
# noqa
|
'person_email': api_user_active.email_address
|
||||||
'person_email': ANY
|
|
||||||
},
|
},
|
||||||
headers=ANY
|
headers=ANY
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -217,12 +217,23 @@ def mock_delete_service(mocker, mock_get_service):
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def mock_get_aggregate_service_statistics(mocker):
|
def mock_get_service_statistics_for_day(mocker):
|
||||||
def _create(service_id, limit_days=None):
|
|
||||||
return {'data': [{}]}
|
stats = {'day': datetime.today().date().strftime('%Y-%m-%d'),
|
||||||
|
'emails_delivered': 0,
|
||||||
|
'sms_requested': 0,
|
||||||
|
'sms_delivered': 0,
|
||||||
|
'sms_failed': 0,
|
||||||
|
'emails_requested': 0,
|
||||||
|
'emails_failed': 0,
|
||||||
|
'service': fake_uuid,
|
||||||
|
'id': fake_uuid}
|
||||||
|
|
||||||
|
def _stats(service_id, day):
|
||||||
|
return {'data': stats}
|
||||||
|
|
||||||
return mocker.patch(
|
return mocker.patch(
|
||||||
'app.statistics_api_client.get_7_day_aggregate_for_service', side_effect=_create)
|
'app.statistics_api_client.get_statistics_for_service_for_day', side_effect=_stats)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
@@ -854,6 +865,18 @@ def mock_get_job(mocker, api_user_active):
|
|||||||
return mocker.patch('app.job_api_client.get_job', side_effect=_get_job)
|
return mocker.patch('app.job_api_client.get_job', side_effect=_get_job)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope='function')
|
||||||
|
def mock_get_job_in_progress(mocker, api_user_active):
|
||||||
|
def _get_job(service_id, job_id):
|
||||||
|
return {"data": job_json(
|
||||||
|
service_id, api_user_active, job_id=job_id,
|
||||||
|
notification_count=10,
|
||||||
|
notifications_sent=5
|
||||||
|
)}
|
||||||
|
|
||||||
|
return mocker.patch('app.job_api_client.get_job', side_effect=_get_job)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
def mock_get_jobs(mocker, api_user_active):
|
def mock_get_jobs(mocker, api_user_active):
|
||||||
def _get_jobs(service_id, limit_days=None):
|
def _get_jobs(service_id, limit_days=None):
|
||||||
@@ -894,14 +917,16 @@ def mock_get_notifications(mocker, api_user_active):
|
|||||||
template={'template_type': set_template_type, 'name': 'name', 'id': 'id', 'version': 1},
|
template={'template_type': set_template_type, 'name': 'name', 'id': 'id', 'version': 1},
|
||||||
rows=rows,
|
rows=rows,
|
||||||
status=set_status,
|
status=set_status,
|
||||||
job=job
|
job=job,
|
||||||
|
with_links=True
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
return notification_json(
|
return notification_json(
|
||||||
service_id,
|
service_id,
|
||||||
rows=rows,
|
rows=rows,
|
||||||
status=set_status,
|
status=set_status,
|
||||||
job=job
|
job=job,
|
||||||
|
with_links=True
|
||||||
)
|
)
|
||||||
|
|
||||||
return mocker.patch(
|
return mocker.patch(
|
||||||
|
|||||||
12
wsgi.py
@@ -1,21 +1,9 @@
|
|||||||
from credstash import getAllSecrets
|
from credstash import getAllSecrets
|
||||||
import os
|
import os
|
||||||
|
|
||||||
default_env_file = '/home/ubuntu/environment'
|
|
||||||
environment = 'live'
|
|
||||||
|
|
||||||
if os.path.isfile(default_env_file):
|
|
||||||
with open(default_env_file, 'r') as environment_file:
|
|
||||||
environment = environment_file.readline().strip()
|
|
||||||
|
|
||||||
|
|
||||||
# on aws get secrets and export to env
|
# on aws get secrets and export to env
|
||||||
os.environ.update(getAllSecrets(region="eu-west-1"))
|
os.environ.update(getAllSecrets(region="eu-west-1"))
|
||||||
|
|
||||||
from config import configs # noqa
|
|
||||||
|
|
||||||
os.environ['NOTIFY_ADMIN_ENVIRONMENT'] = configs[environment]
|
|
||||||
|
|
||||||
from app import create_app # noqa
|
from app import create_app # noqa
|
||||||
|
|
||||||
application = create_app()
|
application = create_app()
|
||||||
|
|||||||