mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-09-04 21:38:26 -04:00
Production Release 12-8-25 (#3152)
* Update QA checklist * Bump cachetools from 6.2.1 to 6.2.2 (#3099) Bumps [cachetools](https://github.com/tkem/cachetools) from 6.2.1 to 6.2.2. - [Changelog](https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst) - [Commits](https://github.com/tkem/cachetools/compare/v6.2.1...v6.2.2) --- updated-dependencies: - dependency-name: cachetools dependency-version: 6.2.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump moto from 5.1.16 to 5.1.17 (#3104) Bumps [moto](https://github.com/getmoto/moto) from 5.1.16 to 5.1.17. - [Release notes](https://github.com/getmoto/moto/releases) - [Changelog](https://github.com/getmoto/moto/blob/master/CHANGELOG.md) - [Commits](https://github.com/getmoto/moto/compare/5.1.16...5.1.17) --- updated-dependencies: - dependency-name: moto dependency-version: 5.1.17 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump numpy from 2.3.4 to 2.3.5 (#3103) Bumps [numpy](https://github.com/numpy/numpy) from 2.3.4 to 2.3.5. - [Release notes](https://github.com/numpy/numpy/releases) - [Changelog](https://github.com/numpy/numpy/blob/main/doc/RELEASE_WALKTHROUGH.rst) - [Commits](https://github.com/numpy/numpy/compare/v2.3.4...v2.3.5) --- updated-dependencies: - dependency-name: numpy dependency-version: 2.3.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump hypothesis from 6.147.0 to 6.148.1 (#3101) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.147.0 to 6.148.1. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.147.0...hypothesis-python-6.148.1) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.148.1 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump js-yaml (#3100) Bumps and [js-yaml](https://github.com/nodeca/js-yaml). These dependencies needed to be updated together. Updates `js-yaml` from 4.1.0 to 4.1.1 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1) Updates `js-yaml` from 3.14.1 to 3.14.2 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 4.1.1 dependency-type: indirect - dependency-name: js-yaml dependency-version: 3.14.2 dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump click from 8.3.0 to 8.3.1 (#3102) Bumps [click](https://github.com/pallets/click) from 8.3.0 to 8.3.1. - [Release notes](https://github.com/pallets/click/releases) - [Changelog](https://github.com/pallets/click/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/click/compare/8.3.0...8.3.1) --- updated-dependencies: - dependency-name: click dependency-version: 8.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump coverage from 7.11.3 to 7.12.0 (#3109) Bumps [coverage](https://github.com/coveragepy/coveragepy) from 7.11.3 to 7.12.0. - [Release notes](https://github.com/coveragepy/coveragepy/releases) - [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst) - [Commits](https://github.com/coveragepy/coveragepy/compare/7.11.3...7.12.0) --- updated-dependencies: - dependency-name: coverage dependency-version: 7.12.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump hypothesis from 6.148.1 to 6.148.2 (#3108) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.148.1 to 6.148.2. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.148.1...hypothesis-python-6.148.2) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.148.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump webpack from 5.102.1 to 5.103.0 (#3107) Bumps [webpack](https://github.com/webpack/webpack) from 5.102.1 to 5.103.0. - [Release notes](https://github.com/webpack/webpack/releases) - [Commits](https://github.com/webpack/webpack/compare/v5.102.1...v5.103.0) --- updated-dependencies: - dependency-name: webpack dependency-version: 5.103.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump sass from 1.94.0 to 1.94.1 (#3106) Bumps [sass](https://github.com/sass/dart-sass) from 1.94.0 to 1.94.1. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.94.0...1.94.1) --- updated-dependencies: - dependency-name: sass dependency-version: 1.94.1 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump bandit from 1.8.6 to 1.9.1 (#3105) Bumps [bandit](https://github.com/PyCQA/bandit) from 1.8.6 to 1.9.1. - [Release notes](https://github.com/PyCQA/bandit/releases) - [Commits](https://github.com/PyCQA/bandit/compare/1.8.6...1.9.1) --- updated-dependencies: - dependency-name: bandit dependency-version: 1.9.1 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * improve test coverage * org test * test coverage * Bump sass from 1.94.1 to 1.94.2 (#3123) Bumps [sass](https://github.com/sass/dart-sass) from 1.94.1 to 1.94.2. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.94.1...1.94.2) --- updated-dependencies: - dependency-name: sass dependency-version: 1.94.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump redis from 7.0.1 to 7.1.0 (#3122) Bumps [redis](https://github.com/redis/redis-py) from 7.0.1 to 7.1.0. - [Release notes](https://github.com/redis/redis-py/releases) - [Changelog](https://github.com/redis/redis-py/blob/master/CHANGES) - [Commits](https://github.com/redis/redis-py/compare/v7.0.1...v7.1.0) --- updated-dependencies: - dependency-name: redis dependency-version: 7.1.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump phonenumbers from 9.0.18 to 9.0.19 (#3127) Bumps [phonenumbers](https://github.com/daviddrysdale/python-phonenumbers) from 9.0.18 to 9.0.19. - [Commits](https://github.com/daviddrysdale/python-phonenumbers/compare/v9.0.18...v9.0.19) --- updated-dependencies: - dependency-name: phonenumbers dependency-version: 9.0.19 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump exceptiongroup from 1.3.0 to 1.3.1 (#3128) Bumps [exceptiongroup](https://github.com/agronholm/exceptiongroup) from 1.3.0 to 1.3.1. - [Release notes](https://github.com/agronholm/exceptiongroup/releases) - [Changelog](https://github.com/agronholm/exceptiongroup/blob/main/CHANGES.rst) - [Commits](https://github.com/agronholm/exceptiongroup/compare/1.3.0...1.3.1) --- updated-dependencies: - dependency-name: exceptiongroup dependency-version: 1.3.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Security update (#3129) * Bump pytest-playwright from 0.7.1 to 0.7.2 (#3133) Bumps [pytest-playwright](https://github.com/microsoft/playwright-pytest) from 0.7.1 to 0.7.2. - [Release notes](https://github.com/microsoft/playwright-pytest/releases) - [Commits](https://github.com/microsoft/playwright-pytest/compare/v0.7.1...v0.7.2) --- updated-dependencies: - dependency-name: pytest-playwright dependency-version: 0.7.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump bandit from 1.9.1 to 1.9.2 (#3131) Bumps [bandit](https://github.com/PyCQA/bandit) from 1.9.1 to 1.9.2. - [Release notes](https://github.com/PyCQA/bandit/releases) - [Commits](https://github.com/PyCQA/bandit/compare/1.9.1...1.9.2) --- updated-dependencies: - dependency-name: bandit dependency-version: 1.9.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump pre-commit from 4.4.0 to 4.5.0 (#3132) Bumps [pre-commit](https://github.com/pre-commit/pre-commit) from 4.4.0 to 4.5.0. - [Release notes](https://github.com/pre-commit/pre-commit/releases) - [Changelog](https://github.com/pre-commit/pre-commit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pre-commit/pre-commit/compare/v4.4.0...v4.5.0) --- updated-dependencies: - dependency-name: pre-commit dependency-version: 4.5.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump pytest from 8.4.2 to 9.0.1 (#3130) Bumps [pytest](https://github.com/pytest-dev/pytest) from 8.4.2 to 9.0.1. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/8.4.2...9.0.1) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump playwright from 1.56.1 to 1.57.0 (#3134) Bumps [playwright](https://github.com/microsoft/playwright) from 1.56.1 to 1.57.0. - [Release notes](https://github.com/microsoft/playwright/releases) - [Commits](https://github.com/microsoft/playwright/compare/v1.56.1...v1.57.0) --- updated-dependencies: - dependency-name: playwright dependency-version: 1.57.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump hypothesis from 6.148.2 to 6.148.3 (#3136) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.148.2 to 6.148.3. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.148.2...hypothesis-python-6.148.3) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.148.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump werkzeug from 3.1.3 to 3.1.4 (#3143) Bumps [werkzeug](https://github.com/pallets/werkzeug) from 3.1.3 to 3.1.4. - [Release notes](https://github.com/pallets/werkzeug/releases) - [Changelog](https://github.com/pallets/werkzeug/blob/main/CHANGES.rst) - [Commits](https://github.com/pallets/werkzeug/compare/3.1.3...3.1.4) --- updated-dependencies: - dependency-name: werkzeug dependency-version: 3.1.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump hypothesis from 6.148.3 to 6.148.5 (#3138) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.148.3 to 6.148.5. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.148.3...hypothesis-python-6.148.5) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.148.5 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump flake8-bugbear from 25.10.21 to 25.11.29 (#3141) Bumps [flake8-bugbear](https://github.com/PyCQA/flake8-bugbear) from 25.10.21 to 25.11.29. - [Release notes](https://github.com/PyCQA/flake8-bugbear/releases) - [Commits](https://github.com/PyCQA/flake8-bugbear/compare/25.10.21...25.11.29) --- updated-dependencies: - dependency-name: flake8-bugbear dependency-version: 25.11.29 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump beautifulsoup4 from 4.14.2 to 4.14.3 (#3137) Bumps [beautifulsoup4](https://www.crummy.com/software/BeautifulSoup/bs4/) from 4.14.2 to 4.14.3. --- updated-dependencies: - dependency-name: beautifulsoup4 dependency-version: 4.14.3 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump hypothesis from 6.148.5 to 6.148.6 (#3145) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.148.5 to 6.148.6. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.148.5...hypothesis-python-6.148.6) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.148.6 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump urllib3 from 2.5.0 to 2.6.0 (#3146) Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.5.0 to 2.6.0. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.5.0...2.6.0) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.6.0 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump phonenumbers from 9.0.19 to 9.0.20 (#3149) Bumps [phonenumbers](https://github.com/daviddrysdale/python-phonenumbers) from 9.0.19 to 9.0.20. - [Commits](https://github.com/daviddrysdale/python-phonenumbers/compare/v9.0.19...v9.0.20) --- updated-dependencies: - dependency-name: phonenumbers dependency-version: 9.0.20 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump hypothesis from 6.148.6 to 6.148.7 (#3148) Bumps [hypothesis](https://github.com/HypothesisWorks/hypothesis) from 6.148.6 to 6.148.7. - [Release notes](https://github.com/HypothesisWorks/hypothesis/releases) - [Commits](https://github.com/HypothesisWorks/hypothesis/compare/hypothesis-python-6.148.6...hypothesis-python-6.148.7) --- updated-dependencies: - dependency-name: hypothesis dependency-version: 6.148.7 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Remove SMS Total Message Limit from Org Dash (#3144) * Remove SMS Total Message Limit from Org Dash * update text * pytest * Fix dependabot prs (#3151) * Bump terser-webpack-plugin from 5.3.14 to 5.3.15 Bumps [terser-webpack-plugin](https://github.com/webpack/terser-webpack-plugin) from 5.3.14 to 5.3.15. - [Release notes](https://github.com/webpack/terser-webpack-plugin/releases) - [Changelog](https://github.com/webpack/terser-webpack-plugin/blob/main/CHANGELOG.md) - [Commits](https://github.com/webpack/terser-webpack-plugin/compare/v5.3.14...v5.3.15) --- updated-dependencies: - dependency-name: terser-webpack-plugin dependency-version: 5.3.15 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump moto from 5.1.17 to 5.1.18 Bumps [moto](https://github.com/getmoto/moto) from 5.1.17 to 5.1.18. - [Release notes](https://github.com/getmoto/moto/releases) - [Changelog](https://github.com/getmoto/moto/blob/master/CHANGELOG.md) - [Commits](https://github.com/getmoto/moto/compare/5.1.17...5.1.18) --- updated-dependencies: - dependency-name: moto dependency-version: 5.1.18 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> * Bump pip-audit from 2.9.0 to 2.10.0 Bumps [pip-audit](https://github.com/pypa/pip-audit) from 2.9.0 to 2.10.0. - [Release notes](https://github.com/pypa/pip-audit/releases) - [Changelog](https://github.com/pypa/pip-audit/blob/main/CHANGELOG.md) - [Commits](https://github.com/pypa/pip-audit/compare/v2.9.0...v2.10.0) --- updated-dependencies: - dependency-name: pip-audit dependency-version: 2.10.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * 3110 dashboard design feedback & permission changes (#3142) * update org dashboard * allowing org admins to access serviecs within an org * fix test * Allow org admin to send messages within a service * Bump coverage from 7.12.0 to 7.13.0 (#3159) Bumps [coverage](https://github.com/coveragepy/coveragepy) from 7.12.0 to 7.13.0. - [Release notes](https://github.com/coveragepy/coveragepy/releases) - [Changelog](https://github.com/coveragepy/coveragepy/blob/main/CHANGES.rst) - [Commits](https://github.com/coveragepy/coveragepy/compare/7.12.0...7.13.0) --- updated-dependencies: - dependency-name: coverage dependency-version: 7.13.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump pytest from 9.0.1 to 9.0.2 (#3158) Bumps [pytest](https://github.com/pytest-dev/pytest) from 9.0.1 to 9.0.2. - [Release notes](https://github.com/pytest-dev/pytest/releases) - [Changelog](https://github.com/pytest-dev/pytest/blob/main/CHANGELOG.rst) - [Commits](https://github.com/pytest-dev/pytest/compare/9.0.1...9.0.2) --- updated-dependencies: - dependency-name: pytest dependency-version: 9.0.2 dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump sass from 1.94.2 to 1.95.0 (#3157) Bumps [sass](https://github.com/sass/dart-sass) from 1.94.2 to 1.95.0. - [Release notes](https://github.com/sass/dart-sass/releases) - [Changelog](https://github.com/sass/dart-sass/blob/main/CHANGELOG.md) - [Commits](https://github.com/sass/dart-sass/compare/1.94.2...1.95.0) --- updated-dependencies: - dependency-name: sass dependency-version: 1.95.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump black from 25.11.0 to 25.12.0 (#3155) Bumps [black](https://github.com/psf/black) from 25.11.0 to 25.12.0. - [Release notes](https://github.com/psf/black/releases) - [Changelog](https://github.com/psf/black/blob/main/CHANGES.md) - [Commits](https://github.com/psf/black/compare/25.11.0...25.12.0) --- updated-dependencies: - dependency-name: black dependency-version: 25.12.0 dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump urllib3 from 2.6.0 to 2.6.1 (#3156) Bumps [urllib3](https://github.com/urllib3/urllib3) from 2.6.0 to 2.6.1. - [Release notes](https://github.com/urllib3/urllib3/releases) - [Changelog](https://github.com/urllib3/urllib3/blob/main/CHANGES.rst) - [Commits](https://github.com/urllib3/urllib3/compare/2.6.0...2.6.1) --- updated-dependencies: - dependency-name: urllib3 dependency-version: 2.6.1 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: Beverly Nguyen <Beverly.Nguyen@gsa.gov> Co-authored-by: ccostino <ccostino@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Beverly Nguyen <53159604+heyitsmebev@users.noreply.github.com>
This commit is contained in:
@@ -123,7 +123,7 @@ def get_filtered_jobs(service_id, page):
|
||||
|
||||
|
||||
@main.route("/activity/services/<uuid:service_id>")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def all_jobs_activity(service_id):
|
||||
service_data_retention_days = 8
|
||||
page = get_page_from_request()
|
||||
|
||||
@@ -23,7 +23,7 @@ dummy_bearer_token = "bearer_token_set" # nosec B105 - this is not a real token
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/api")
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def api_integration(service_id):
|
||||
callbacks_link = (
|
||||
".api_callbacks"
|
||||
@@ -40,7 +40,7 @@ def api_integration(service_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/api/documentation")
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def api_documentation(service_id):
|
||||
return redirect(url_for(".documentation"), code=301)
|
||||
|
||||
@@ -51,7 +51,7 @@ def api_documentation(service_id):
|
||||
endpoint="old_guest_list",
|
||||
)
|
||||
@main.route("/services/<uuid:service_id>/api/guest-list", methods=["GET", "POST"])
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def guest_list(service_id):
|
||||
form = GuestList()
|
||||
if form.validate_on_submit():
|
||||
@@ -70,7 +70,7 @@ def guest_list(service_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/api/keys")
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def api_keys(service_id):
|
||||
return render_template(
|
||||
"views/api/keys.html",
|
||||
@@ -78,7 +78,7 @@ def api_keys(service_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/api/keys/create", methods=["GET", "POST"])
|
||||
@user_has_permissions("manage_api_keys", restrict_admin_usage=True)
|
||||
@user_has_permissions("manage_api_keys", restrict_admin_usage=True, allow_org_user=True)
|
||||
def create_api_key(service_id):
|
||||
form = CreateKeyForm(current_service.api_keys)
|
||||
form.key_type.choices = [
|
||||
@@ -118,7 +118,7 @@ def create_api_key(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/api/keys/revoke/<uuid:key_id>", methods=["GET", "POST"]
|
||||
)
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def revoke_api_key(service_id, key_id):
|
||||
key_name = current_service.get_api_key(key_id)["name"]
|
||||
if request.method == "GET":
|
||||
@@ -161,7 +161,7 @@ def check_token_against_dummy_bearer(token):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/api/callbacks", methods=["GET"])
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def api_callbacks(service_id):
|
||||
if not current_service.has_permission(ServicePermission.INBOUND_SMS):
|
||||
return redirect(url_for(".delivery_status_callback", service_id=service_id))
|
||||
@@ -192,7 +192,7 @@ def get_delivery_status_callback_details():
|
||||
"/services/<uuid:service_id>/api/callbacks/delivery-status-callback",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def delivery_status_callback(service_id):
|
||||
delivery_status_callback = get_delivery_status_callback_details()
|
||||
back_link = (
|
||||
@@ -259,7 +259,7 @@ def get_received_text_messages_callback():
|
||||
"/services/<uuid:service_id>/api/callbacks/received-text-messages-callback",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions("manage_api_keys")
|
||||
@user_has_permissions("manage_api_keys", allow_org_user=True)
|
||||
def received_text_messages_callback(service_id):
|
||||
if not current_service.has_permission(ServicePermission.INBOUND_SMS):
|
||||
return redirect(url_for(".api_integration", service_id=service_id))
|
||||
|
||||
@@ -13,7 +13,7 @@ from notifications_utils.template import SMSPreviewTemplate
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/conversation/<uuid:notification_id>")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def conversation(service_id, notification_id):
|
||||
user_number = get_user_number(service_id, notification_id)
|
||||
|
||||
@@ -31,7 +31,7 @@ def conversation(service_id, notification_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/conversation/<uuid:notification_id>.json")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def conversation_updates(service_id, notification_id):
|
||||
return jsonify(
|
||||
get_conversation_partials(
|
||||
@@ -46,7 +46,7 @@ def conversation_updates(service_id, notification_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/conversation/<uuid:notification_id>/reply-with/from-folder/<uuid:from_folder>"
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def conversation_reply(
|
||||
service_id,
|
||||
notification_id,
|
||||
@@ -70,7 +70,7 @@ def conversation_reply(
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/conversation/<uuid:notification_id>/reply-with/<uuid:template_id>"
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def conversation_reply_with_template(
|
||||
service_id,
|
||||
notification_id,
|
||||
|
||||
@@ -24,13 +24,13 @@ from app.utils.user import user_has_permissions
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/dashboard")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def old_service_dashboard(service_id):
|
||||
return redirect(url_for(".service_dashboard", service_id=service_id))
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def service_dashboard(service_id):
|
||||
|
||||
if session.get("invited_user_id"):
|
||||
@@ -84,7 +84,7 @@ def job_is_finished(job_dict):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/daily-stats.json")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def get_daily_stats(service_id):
|
||||
date_range = get_stats_date_range()
|
||||
days = date_range["days"]
|
||||
@@ -148,7 +148,7 @@ def get_local_daily_stats_for_last_x_days(stats_utc, user_timezone, days):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/daily-stats-by-user.json")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def get_daily_stats_by_user(service_id):
|
||||
date_range = get_stats_date_range()
|
||||
days = date_range["days"]
|
||||
@@ -166,7 +166,7 @@ def get_daily_stats_by_user(service_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/template-usage")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def template_usage(service_id):
|
||||
year, current_financial_year = requested_and_current_financial_year(request)
|
||||
stats = template_statistics_client.get_monthly_template_usage_for_service(
|
||||
|
||||
@@ -11,7 +11,7 @@ from app.utils.user import user_has_permissions
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/history")
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def history(service_id):
|
||||
events = _get_events(current_service.id, request.args.get("selected"))
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ from notifications_utils.template import EmailPreviewTemplate, SMSBodyPreviewTem
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def view_jobs(service_id):
|
||||
return redirect(
|
||||
url_for(
|
||||
@@ -37,7 +37,7 @@ def view_jobs(service_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def view_job(service_id, job_id):
|
||||
job = Job.from_id(job_id, service_id=current_service.id)
|
||||
if job.cancelled:
|
||||
@@ -83,7 +83,7 @@ def view_job(service_id, job_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>.csv")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def view_job_csv(service_id, job_id):
|
||||
job = Job.from_id(job_id, service_id=service_id)
|
||||
filter_args = parse_filter_args(request.args)
|
||||
@@ -111,14 +111,14 @@ def view_job_csv(service_id, job_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>", methods=["POST"])
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def cancel_job(service_id, job_id):
|
||||
Job.from_id(job_id, service_id=service_id).cancel()
|
||||
return redirect(url_for("main.service_dashboard", service_id=service_id))
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>/status.json")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def view_job_status_poll(service_id, job_id):
|
||||
from app.notify_client.job_api_client import job_api_client
|
||||
|
||||
@@ -147,7 +147,7 @@ def view_job_status_poll(service_id, job_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/jobs/<uuid:job_id>/notifications-table")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def view_job_notifications_table(service_id, job_id):
|
||||
"""Endpoint that returns only the notifications table HTML fragment."""
|
||||
job = Job.from_id(job_id, service_id=current_service.id)
|
||||
|
||||
@@ -44,7 +44,7 @@ def manage_users(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/users/invite/<uuid:user_id>", methods=["GET", "POST"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def invite_user(service_id, user_id=None):
|
||||
form_class = InviteUserForm
|
||||
form = form_class(
|
||||
@@ -116,7 +116,7 @@ def invite_user(service_id, user_id=None):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/users/<uuid:user_id>", methods=["GET", "POST"])
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def edit_user_permissions(service_id, user_id):
|
||||
service_has_email_auth = current_service.has_permission(
|
||||
ServicePermission.EMAIL_AUTH
|
||||
@@ -169,7 +169,7 @@ def edit_user_permissions(service_id, user_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/users/<uuid:user_id>/delete", methods=["POST"])
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def remove_user_from_service(service_id, user_id):
|
||||
try:
|
||||
service_api_client.remove_user_from_service(service_id, user_id)
|
||||
@@ -192,7 +192,7 @@ def remove_user_from_service(service_id, user_id):
|
||||
"/services/<uuid:service_id>/users/<uuid:user_id>/edit-email",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def edit_user_email(service_id, user_id):
|
||||
user = current_service.get_team_member(user_id)
|
||||
user_email = user.email_address
|
||||
@@ -225,7 +225,7 @@ def edit_user_email(service_id, user_id):
|
||||
"/services/<uuid:service_id>/users/<uuid:user_id>/edit-email/confirm",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def confirm_edit_user_email(service_id, user_id):
|
||||
user = current_service.get_team_member(user_id)
|
||||
session_key = "team_member_email_change-{}".format(user_id)
|
||||
@@ -263,7 +263,7 @@ def confirm_edit_user_email(service_id, user_id):
|
||||
"/services/<uuid:service_id>/users/<uuid:user_id>/edit-mobile-number",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def edit_user_mobile_number(service_id, user_id):
|
||||
user = current_service.get_team_member(user_id)
|
||||
user_mobile_number = redact_mobile_number(user.mobile_number)
|
||||
@@ -293,7 +293,7 @@ def edit_user_mobile_number(service_id, user_id):
|
||||
"/services/<uuid:service_id>/users/<uuid:user_id>/edit-mobile-number/confirm",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def confirm_edit_user_mobile_number(service_id, user_id):
|
||||
user = current_service.get_team_member(user_id)
|
||||
if "team_member_mobile_change" in session:
|
||||
@@ -331,7 +331,7 @@ def confirm_edit_user_mobile_number(service_id, user_id):
|
||||
"/services/<uuid:service_id>/cancel-invited-user/<uuid:invited_user_id>",
|
||||
methods=["GET"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def cancel_invited_user(service_id, invited_user_id):
|
||||
current_service.cancel_invite(invited_user_id)
|
||||
|
||||
@@ -350,7 +350,7 @@ def cancel_invited_user(service_id, invited_user_id):
|
||||
"/services/<uuid:service_id>/resend-invite/<uuid:invited_user_id>",
|
||||
methods=["GET"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def resend_invite(service_id, invited_user_id):
|
||||
current_service.resend_invite(invited_user_id)
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ from notifications_utils.s3 import S3ObjectNotFound
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/notification/<uuid:notification_id>")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def view_notification(service_id, notification_id, error_message=None):
|
||||
if error_message:
|
||||
flash(error_message)
|
||||
@@ -108,7 +108,7 @@ def view_notification(service_id, notification_id, error_message=None):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/notification/<uuid:notification_id>.json")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def view_notification_updates(service_id, notification_id):
|
||||
return jsonify(
|
||||
**get_single_notification_partials(
|
||||
@@ -149,7 +149,7 @@ PERIOD_TO_S3_FILENAME = {
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/download-notifications.csv")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def download_notifications_csv(service_id):
|
||||
set_timezone()
|
||||
filter_args = parse_filter_args(request.args)
|
||||
|
||||
@@ -87,18 +87,14 @@ def add_organization():
|
||||
return render_template("views/organizations/add-organization.html", form=form)
|
||||
|
||||
|
||||
def get_organization_message_allowance(org_id):
|
||||
def get_organization_messages_sent(org_id):
|
||||
try:
|
||||
message_usage = organizations_client.get_organization_message_usage(org_id)
|
||||
except Exception as e:
|
||||
current_app.logger.error(f"Error fetching organization message usage: {e}")
|
||||
message_usage = {}
|
||||
|
||||
return {
|
||||
"messages_sent": message_usage.get("messages_sent", 0),
|
||||
"messages_remaining": message_usage.get("messages_remaining", 0),
|
||||
"total_message_limit": message_usage.get("total_message_limit", 0),
|
||||
}
|
||||
return message_usage.get("messages_sent", 0)
|
||||
|
||||
|
||||
def _handle_create_service(org_id):
|
||||
@@ -210,9 +206,7 @@ def _handle_delete_service(org_id, service_id):
|
||||
cached_service_user_ids = [user.id for user in service.active_users]
|
||||
|
||||
service_api_client.archive_service(service_id, cached_service_user_ids)
|
||||
create_archive_service_event(
|
||||
service_id=service_id, archived_by_id=current_user.id
|
||||
)
|
||||
create_archive_service_event(service_id=service_id, archived_by_id=current_user.id)
|
||||
|
||||
cache.redis_client.delete("organizations")
|
||||
|
||||
@@ -247,10 +241,10 @@ def get_services_dashboard_data(organization, year):
|
||||
if sms_sent > 0 or sms_remainder > 0:
|
||||
if sms_cost > 0:
|
||||
usage_parts.append(
|
||||
f"{sms_sent:,} sms ({sms_remainder:,} remaining, ${sms_cost:,.2f})"
|
||||
f"{sms_sent:,} sms ({sms_remainder:,} message parts remaining, ${sms_cost:,.2f})"
|
||||
)
|
||||
else:
|
||||
usage_parts.append(f"{sms_sent:,} sms ({sms_remainder:,} remaining)")
|
||||
usage_parts.append(f"{sms_sent:,} sms ({sms_remainder:,} message parts remaining)")
|
||||
|
||||
service["usage"] = ", ".join(usage_parts) if usage_parts else "No usage"
|
||||
|
||||
@@ -292,7 +286,7 @@ def organization_dashboard(org_id):
|
||||
elif action == "delete-service" and service_id:
|
||||
return _handle_delete_service(org_id, service_id)
|
||||
|
||||
message_allowance = get_organization_message_allowance(org_id)
|
||||
messages_sent = get_organization_messages_sent(org_id)
|
||||
|
||||
return render_template(
|
||||
"views/organizations/organization/index.html",
|
||||
@@ -307,7 +301,7 @@ def organization_dashboard(org_id):
|
||||
edit_service_data=edit_service_data,
|
||||
new_service_id=session.pop("new_service_id", None),
|
||||
updated_service_id=session.pop("updated_service_id", None),
|
||||
**message_allowance,
|
||||
messages_sent=messages_sent,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ def get_example_csv_rows(template, use_example_as_example=True, submitted_fields
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/send/<uuid:template_id>/csv", methods=["GET", "POST"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def send_messages(service_id, template_id):
|
||||
notification_count = service_api_client.get_notification_count(service_id)
|
||||
remaining_messages = current_service.message_limit - notification_count
|
||||
@@ -189,7 +189,7 @@ def send_messages(service_id, template_id):
|
||||
|
||||
@main.route("/services/<uuid:service_id>/send/<uuid:template_id>.csv", methods=["GET"])
|
||||
@user_has_permissions(
|
||||
ServicePermission.SEND_MESSAGES, ServicePermission.MANAGE_TEMPLATES
|
||||
ServicePermission.SEND_MESSAGES, ServicePermission.MANAGE_TEMPLATES, allow_org_user=True
|
||||
)
|
||||
def get_example_csv(service_id, template_id):
|
||||
template = get_template(
|
||||
@@ -215,7 +215,7 @@ def get_example_csv(service_id, template_id):
|
||||
"/services/<uuid:service_id>/send/<uuid:template_id>/set-sender",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def set_sender(service_id, template_id):
|
||||
session["sender_id"] = None
|
||||
redirect_to_one_off = redirect(
|
||||
@@ -344,7 +344,7 @@ def get_sender_details(service_id, template_type):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/send/<uuid:template_id>/one-off")
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def send_one_off(service_id, template_id):
|
||||
session["recipient"] = None
|
||||
session["placeholders"] = {}
|
||||
@@ -388,7 +388,7 @@ def get_notification_check_endpoint(service_id, template):
|
||||
"/services/<uuid:service_id>/send/<uuid:template_id>/one-off/step-<int:step_index>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def send_one_off_step(service_id, template_id, step_index):
|
||||
if {"recipient", "placeholders"} - set(session.keys()):
|
||||
return redirect(
|
||||
@@ -650,7 +650,7 @@ def _check_messages(service_id, template_id, upload_id, preview_row, **kwargs):
|
||||
"/services/<uuid:service_id>/<uuid:template_id>/check/<uuid:upload_id>/row-<int:row_index>",
|
||||
methods=["GET"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def check_messages(service_id, template_id, upload_id, row_index=2):
|
||||
data = _check_messages(service_id, template_id, upload_id, row_index)
|
||||
data["allowed_file_extensions"] = Spreadsheet.ALLOWED_FILE_EXTENSIONS
|
||||
@@ -694,7 +694,7 @@ def check_messages(service_id, template_id, upload_id, row_index=2):
|
||||
"/services/<uuid:service_id>/<uuid:template_id>/check/<uuid:upload_id>/preview/row-<int:row_index>",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def preview_job(service_id, template_id, upload_id, row_index=2):
|
||||
session["scheduled_for"] = request.form.get("scheduled_for", "")
|
||||
data = _check_messages(
|
||||
@@ -709,7 +709,7 @@ def preview_job(service_id, template_id, upload_id, row_index=2):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/start-job/<uuid:upload_id>", methods=["POST"])
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def start_job(service_id, upload_id):
|
||||
scheduled_for = session.pop("scheduled_for", None)
|
||||
job_api_client.create_job(
|
||||
@@ -846,7 +846,7 @@ def get_skip_link(step_index, template):
|
||||
and step_index == 0
|
||||
and template.template_type in ("sms", "email")
|
||||
and not (template.template_type == "sms" and current_user.mobile_number is None)
|
||||
and current_user.has_permissions(ServicePermission.SEND_MESSAGES)
|
||||
and current_user.has_permissions(ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
):
|
||||
return (
|
||||
"Use my {}".format(first_column_headings[template.template_type][0]),
|
||||
@@ -862,7 +862,7 @@ def get_skip_link(step_index, template):
|
||||
"/services/<uuid:service_id>/template/<uuid:template_id>/one-off/send-to-myself",
|
||||
methods=["GET"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def send_one_off_to_myself(service_id, template_id):
|
||||
current_app.logger.info("Send one off to myself")
|
||||
try:
|
||||
@@ -899,7 +899,7 @@ def send_one_off_to_myself(service_id, template_id):
|
||||
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check",
|
||||
methods=["GET"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def check_notification(service_id, template_id):
|
||||
return render_template(
|
||||
"views/notifications/check.html",
|
||||
@@ -981,7 +981,7 @@ def get_template_error_dict(exception):
|
||||
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check/preview",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def preview_notification(service_id, template_id):
|
||||
recipient = get_recipient()
|
||||
if not recipient:
|
||||
@@ -1013,7 +1013,7 @@ def preview_notification(service_id, template_id):
|
||||
"/services/<uuid:service_id>/template/<uuid:template_id>/notification/check",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def send_notification(service_id, template_id):
|
||||
recipient = get_recipient()
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ PLATFORM_ADMIN_SERVICE_PERMISSIONS = OrderedDict(
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/service-settings")
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys")
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys", allow_org_user=True)
|
||||
def service_settings(service_id):
|
||||
return render_template(
|
||||
"views/service-settings.html",
|
||||
@@ -81,7 +81,7 @@ def service_settings(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/name", methods=["GET", "POST"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_name_change(service_id):
|
||||
form = RenameServiceForm(name=current_service.name)
|
||||
|
||||
@@ -195,7 +195,7 @@ def service_set_permission(service_id, permission):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/archive", methods=["GET", "POST"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def archive_service(service_id):
|
||||
if not current_service.active or not (
|
||||
current_service.trial_mode or current_user.platform_admin
|
||||
@@ -268,7 +268,7 @@ def resume_service(service_id):
|
||||
"/services/<uuid:service_id>/service-settings/send-files-by-email",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def send_files_by_email_contact_details(service_id):
|
||||
form = ServiceContactDetailsForm()
|
||||
contact_details = None
|
||||
@@ -298,7 +298,7 @@ def send_files_by_email_contact_details(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/set-reply-to-email", methods=["GET"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_reply_to_email(service_id):
|
||||
return redirect(url_for(".service_email_reply_to", service_id=service_id))
|
||||
|
||||
@@ -306,7 +306,7 @@ def service_set_reply_to_email(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/email-reply-to", methods=["GET"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys")
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys", allow_org_user=True)
|
||||
def service_email_reply_to(service_id):
|
||||
return render_template("views/service-settings/email_reply_to.html")
|
||||
|
||||
@@ -315,7 +315,7 @@ def service_email_reply_to(service_id):
|
||||
"/services/<uuid:service_id>/service-settings/email-reply-to/add",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_add_email_reply_to(service_id):
|
||||
form = ServiceReplyToEmailForm()
|
||||
first_email_address = current_service.count_email_reply_to_addresses == 0
|
||||
@@ -359,7 +359,7 @@ def service_add_email_reply_to(service_id):
|
||||
"/services/<uuid:service_id>/service-settings/email-reply-to/<uuid:notification_id>/verify",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_verify_reply_to_address(service_id, notification_id):
|
||||
replace = request.args.get("replace", False)
|
||||
is_default = request.args.get("is_default", False)
|
||||
@@ -379,7 +379,7 @@ def service_verify_reply_to_address(service_id, notification_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/email-reply-to/<uuid:notification_id>/verify.json"
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_verify_reply_to_address_updates(service_id, notification_id):
|
||||
return jsonify(
|
||||
**get_service_verify_reply_to_address_partials(service_id, notification_id)
|
||||
@@ -456,7 +456,7 @@ def get_service_verify_reply_to_address_partials(service_id, notification_id):
|
||||
methods=["GET"],
|
||||
endpoint="service_confirm_delete_email_reply_to",
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_edit_email_reply_to(service_id, reply_to_email_id):
|
||||
form = ServiceReplyToEmailForm()
|
||||
reply_to_email_address = current_service.get_email_reply_to_address(
|
||||
@@ -525,7 +525,7 @@ def service_edit_email_reply_to(service_id, reply_to_email_id):
|
||||
"/services/<uuid:service_id>/service-settings/email-reply-to/<uuid:reply_to_email_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_delete_email_reply_to(service_id, reply_to_email_id):
|
||||
service_api_client.delete_reply_to_email_address(
|
||||
service_id=current_service.id,
|
||||
@@ -538,7 +538,7 @@ def service_delete_email_reply_to(service_id, reply_to_email_id):
|
||||
"/services/<uuid:service_id>/service-settings/set-inbound-number",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_inbound_number(service_id):
|
||||
available_inbound_numbers = (
|
||||
inbound_number_client.get_available_inbound_sms_numbers()
|
||||
@@ -571,7 +571,7 @@ def service_set_inbound_number(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/sms-prefix", methods=["GET", "POST"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_sms_prefix(service_id):
|
||||
form = SMSPrefixForm(enabled=current_service.prefix_sms)
|
||||
|
||||
@@ -590,7 +590,7 @@ def service_set_sms_prefix(service_id):
|
||||
"/services/<uuid:service_id>/service-settings/set-international-sms",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_international_sms(service_id):
|
||||
form = ServiceOnOffSettingForm(
|
||||
"Send text messages to international phone numbers",
|
||||
@@ -611,7 +611,7 @@ def service_set_international_sms(service_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/set-inbound-sms", methods=["GET"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_inbound_sms(service_id):
|
||||
return render_template(
|
||||
"views/service-settings/set-inbound-sms.html",
|
||||
@@ -622,7 +622,7 @@ def service_set_inbound_sms(service_id):
|
||||
"/services/<uuid:service_id>/service-settings/set-<channel>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_channel(service_id, channel):
|
||||
if channel not in {"email", "sms"}:
|
||||
abort(404)
|
||||
@@ -647,7 +647,7 @@ def service_set_channel(service_id, channel):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/service-settings/set-auth-type", methods=["GET"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_set_auth_type(service_id):
|
||||
return render_template(
|
||||
"views/service-settings/set-auth-type.html",
|
||||
@@ -655,7 +655,7 @@ def service_set_auth_type(service_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/service-settings/sms-sender", methods=["GET"])
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys")
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, "manage_api_keys", allow_org_user=True)
|
||||
def service_sms_senders(service_id):
|
||||
return render_template(
|
||||
"views/service-settings/sms-senders.html",
|
||||
@@ -666,7 +666,7 @@ def service_sms_senders(service_id):
|
||||
"/services/<uuid:service_id>/service-settings/sms-sender/add",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_add_sms_sender(service_id):
|
||||
form = ServiceSmsSenderForm()
|
||||
first_sms_sender = current_service.count_sms_senders == 0
|
||||
@@ -694,7 +694,7 @@ def service_add_sms_sender(service_id):
|
||||
methods=["GET"],
|
||||
endpoint="service_confirm_delete_sms_sender",
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_edit_sms_sender(service_id, sms_sender_id):
|
||||
sms_sender = current_service.get_sms_sender(sms_sender_id)
|
||||
is_inbound_number = sms_sender["inbound_number_id"]
|
||||
@@ -732,7 +732,7 @@ def service_edit_sms_sender(service_id, sms_sender_id):
|
||||
"/services/<uuid:service_id>/service-settings/sms-sender/<uuid:sms_sender_id>/delete",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE)
|
||||
@user_has_permissions(ServicePermission.MANAGE_SERVICE, allow_org_user=True)
|
||||
def service_delete_sms_sender(service_id, sms_sender_id):
|
||||
service_api_client.delete_sms_sender(
|
||||
service_id=current_service.id,
|
||||
|
||||
@@ -40,7 +40,7 @@ form_objects = {
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/templates/<uuid:template_id>")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def view_template(service_id, template_id):
|
||||
template = current_service.get_template(template_id)
|
||||
template_folder = current_service.get_template_folder(template["folder"])
|
||||
@@ -82,7 +82,7 @@ def view_template(service_id, template_id):
|
||||
"/services/<uuid:service_id>/templates/<template_type:template_type>/folders/<uuid:template_folder_id>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def choose_template(service_id, template_type="all", template_folder_id=None):
|
||||
template_folder = current_service.get_template_folder(template_folder_id)
|
||||
|
||||
@@ -244,7 +244,7 @@ def _view_template_version(service_id, template_id, version):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/templates/<uuid:template_id>/version/<int:version>"
|
||||
)
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def view_template_version(service_id, template_id, version):
|
||||
return render_template(
|
||||
"views/templates/template_history.html",
|
||||
@@ -291,7 +291,7 @@ def _add_template_by_type(template_type, template_folder_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/templates/copy/from-service/<uuid:from_service>/from-folder/<uuid:from_folder>"
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def choose_template_to_copy(
|
||||
service_id,
|
||||
from_service=None,
|
||||
@@ -323,7 +323,7 @@ def choose_template_to_copy(
|
||||
"/services/<uuid:service_id>/templates/copy/<uuid:template_id>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def copy_template(service_id, template_id):
|
||||
from_service = request.args.get("from_service")
|
||||
|
||||
@@ -380,7 +380,7 @@ def _get_template_copy_name(template, existing_templates):
|
||||
"<template_type:notification_type>/<return_to>/<uuid:template_id>"
|
||||
)
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def action_blocked(service_id, notification_type, return_to, template_id=None):
|
||||
back_link = {
|
||||
"add_new_template": partial(
|
||||
@@ -412,7 +412,7 @@ def action_blocked(service_id, notification_type, return_to, template_id=None):
|
||||
"/services/<uuid:service_id>/templates/folders/<uuid:template_folder_id>/manage",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def manage_template_folder(service_id, template_folder_id):
|
||||
template_folder = current_service.get_template_folder_with_user_permission_or_403(
|
||||
template_folder_id, current_user
|
||||
@@ -462,7 +462,7 @@ def manage_template_folder(service_id, template_folder_id):
|
||||
"/services/<uuid:service_id>/templates/folders/<uuid:template_folder_id>/delete",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def delete_template_folder(service_id, template_folder_id):
|
||||
template_folder = current_service.get_template_folder_with_user_permission_or_403(
|
||||
template_folder_id, current_user
|
||||
@@ -527,7 +527,7 @@ def delete_template_folder(service_id, template_folder_id):
|
||||
"/services/<uuid:service_id>/templates/folders/<uuid:template_folder_id>/add-<template_type:template_type>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def add_service_template(service_id, template_type, template_folder_id=None):
|
||||
if template_type not in current_service.available_template_types:
|
||||
return redirect(
|
||||
@@ -591,7 +591,7 @@ def abort_403_if_not_admin_user():
|
||||
"/services/<uuid:service_id>/templates/<uuid:template_id>/edit",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def edit_service_template(service_id, template_id):
|
||||
template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
@@ -679,7 +679,7 @@ def edit_service_template(service_id, template_id):
|
||||
"/services/<uuid:service_id>/templates/count-<template_type:template_type>-length",
|
||||
methods=["POST"],
|
||||
)
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def count_content_length(service_id, template_type):
|
||||
if template_type not in {"sms"}:
|
||||
abort(404)
|
||||
@@ -749,7 +749,7 @@ def _get_content_count_error_and_message_for_template(template):
|
||||
"/services/<uuid:service_id>/templates/<uuid:template_id>/delete",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def delete_service_template(service_id, template_id):
|
||||
template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
@@ -807,7 +807,7 @@ def delete_service_template(service_id, template_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/templates/<uuid:template_id>/redact", methods=["GET"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def confirm_redact_template(service_id, template_id):
|
||||
template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
@@ -828,7 +828,7 @@ def confirm_redact_template(service_id, template_id):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/templates/<uuid:template_id>/redact", methods=["POST"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def redact_template(service_id, template_id):
|
||||
service_api_client.redact_service_template(service_id, template_id)
|
||||
|
||||
@@ -847,7 +847,7 @@ def redact_template(service_id, template_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/templates/<uuid:template_id>/versions")
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY)
|
||||
@user_has_permissions(ServicePermission.VIEW_ACTIVITY, allow_org_user=True)
|
||||
def view_template_versions(service_id, template_id):
|
||||
return render_template(
|
||||
"views/templates/choose_history.html",
|
||||
@@ -867,7 +867,7 @@ def view_template_versions(service_id, template_id):
|
||||
"/services/<uuid:service_id>/templates/<uuid:template_id>/set-template-sender",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def set_template_sender(service_id, template_id):
|
||||
template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
|
||||
@@ -15,7 +15,7 @@ from app.utils.user import user_has_permissions
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/tour/<uuid:template_id>")
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
def begin_tour(service_id, template_id):
|
||||
db_template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
@@ -48,7 +48,7 @@ def begin_tour(service_id, template_id):
|
||||
"/services/<uuid:service_id>/tour/<uuid:template_id>/step-<int:step_index>",
|
||||
methods=["GET", "POST"],
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def tour_step(service_id, template_id, step_index):
|
||||
db_template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
@@ -167,7 +167,7 @@ def _get_tour_step_back_link(service_id, template_id, step_index):
|
||||
@main.route(
|
||||
"/services/<uuid:service_id>/tour/<uuid:template_id>/check", methods=["GET"]
|
||||
)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True)
|
||||
@user_has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True)
|
||||
def check_tour_notification(service_id, template_id):
|
||||
db_template = current_service.get_template_with_user_permission_or_403(
|
||||
template_id, current_user
|
||||
@@ -224,7 +224,7 @@ def check_tour_notification(service_id, template_id):
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/end-tour/<uuid:example_template_id>")
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES)
|
||||
@user_has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True)
|
||||
def go_to_dashboard_after_tour(service_id, example_template_id):
|
||||
service_api_client.delete_service_template(service_id, example_template_id)
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ MAX_FILE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
|
||||
|
||||
|
||||
@main.route("/services/<uuid:service_id>/uploads")
|
||||
@user_has_permissions()
|
||||
@user_has_permissions(allow_org_user=True)
|
||||
def uploads(service_id):
|
||||
# No tests have been written, this has been quickly prepared for user research.
|
||||
# It's also very like that a new view will be created to show uploads.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<li class="usa-sidenav__item"><a class="usa-link {{ org_navigation.is_selected('dashboard') }}" href="{{ url_for('.organization_dashboard', org_id=current_org.id) }}">Dashboard</a></li>
|
||||
{% endif %}
|
||||
<li class="usa-sidenav__item"><a class="usa-link {{ org_navigation.is_selected('usage') }}" href="{{ url_for('.organization_usage', org_id=current_org.id) }}">Usage</a></li>
|
||||
<li class="usa-sidenav__item"><a class="usa-link {{ org_navigation.is_selected('team-members') }}" href="{{ url_for('.manage_org_users', org_id=current_org.id) }}">Team members</a></li>
|
||||
<li class="usa-sidenav__item"><a class="usa-link {{ org_navigation.is_selected('team-members') }}" href="{{ url_for('.manage_org_users', org_id=current_org.id) }}">Org admins</a></li>
|
||||
{% if current_user.platform_admin %}
|
||||
<li class="usa-sidenav__item"><a class="usa-link {{ org_navigation.is_selected('settings') }}" href="{{ url_for('.organization_settings', org_id=current_org.id) }}">Settings</a></li>
|
||||
<li class="usa-sidenav__item"><a class="usa-link {{ org_navigation.is_selected('trial-services') }}" href="{{ url_for('.organization_trial_mode_services', org_id=current_org.id) }}">Trial mode services</a></li>
|
||||
|
||||
@@ -9,23 +9,21 @@
|
||||
|
||||
{{ page_header('Organization Dashboard', size='large') }}
|
||||
|
||||
<div id="totalMessageChartContainer" data-messages-sent="{{ messages_sent|default(0) }}" data-messages-remaining="{{ messages_remaining|default(0) }}" data-total-message-limit="{{ total_message_limit|default(0) }}">
|
||||
<div class="margin-bottom-3">
|
||||
<div class="grid-row flex-align-center">
|
||||
<h2 id="chartTitle" class="margin-right-1 margin-y-0">Overall {{ selected_year }} Total Message Allowance</h2>
|
||||
<h2 id="chartTitle" class="margin-right-1 margin-y-0">Overall {{ selected_year }} Messages Sent</h2>
|
||||
<button
|
||||
type="button"
|
||||
class="usa-tooltip usa-tooltip__information margin-right-0"
|
||||
data-position="top"
|
||||
title="Combined totals across all services in {{ current_org.name }}: pending, failed, or delivered"
|
||||
title="Total messages sent across all services in {{ current_org.name }}"
|
||||
>
|
||||
<span class="usa-sr-only">More information</span>
|
||||
<img src="{{ asset_url('img/usa-icons/info.svg') }}" alt="" class="usa-icon" role="presentation" />
|
||||
</button>
|
||||
</div>
|
||||
<svg id="totalMessageChart"></svg>
|
||||
<div id="message"></div>
|
||||
<div class="font-sans-xl text-primary-darker margin-top-1">{{ "{:,}".format(messages_sent|default(0)) }} sent</div>
|
||||
</div>
|
||||
<div id="totalMessageTable" class="margin-bottom-3"></div>
|
||||
<div class="grid-row margin-bottom-3 maxw-tablet">
|
||||
<div class="grid-col-12 tablet:grid-col-6 margin-bottom-2 tablet:margin-bottom-0 tablet:padding-right-1">
|
||||
<div class="usa-summary-box height-full" role="region">
|
||||
@@ -39,7 +37,7 @@
|
||||
<div class="text-ink font-body-2xs line-height-sans-3">
|
||||
<span class="text-bold">{{ live_services }}</span> Live
|
||||
<span class="margin-left-1 text-bold">{{ trial_services }}</span> Trial
|
||||
<span class="margin-left-1 text-bold">{{ suspended_services }}</span> Suspended
|
||||
<span class="margin-left-1 text-bold">{{ suspended_services }}</span> Archived
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -142,6 +140,9 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
<div class="border-top-1px border-base-lighter margin-top-3 padding-top-3">
|
||||
<a href="{{ url_for('main.invite_user', service_id=edit_service_data.id) }}" class="usa-button usa-button--outline">Invite team member</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -238,7 +239,7 @@
|
||||
</h3>
|
||||
<div id="what-is-service-content" class="usa-accordion__content usa-prose" hidden>
|
||||
<p>
|
||||
When you join Notify, you're added to a service. This is your organization's workspace for sending text messages and emails. Within your service, you can:
|
||||
Services are your organization's workspaces for sending text messages and emails. If you have multiple teams using Notify for different purposes, it is helpful to set up a separate Service for each team, with its own managers and templates. There is no limit to the number of Services you can create, and messages sent by all of your Services contribute to your overall messaging usage. Within each Service, you can:
|
||||
</p>
|
||||
<ol class="usa-list">
|
||||
<li>Create and edit message templates</li>
|
||||
@@ -246,7 +247,8 @@
|
||||
<li>View message status and history</li>
|
||||
<li>Manage team members and permissions</li>
|
||||
<li>Track usage and delivery statistics</li>
|
||||
<li>If you work for multiple organizations, you may belong to multiple services and can switch between them.</li>
|
||||
<li>Service members can be added to multiple services and can switch between them</li>
|
||||
<li>Organizational administrators can always see all Services</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
@@ -275,7 +277,7 @@
|
||||
<td><a href="{{ url_for('main.service_dashboard', service_id=service.id) }}" class="usa-link">{{ service.name }}</a></td>
|
||||
<td>
|
||||
{% if not service.active %}
|
||||
Suspended
|
||||
Archived
|
||||
{% elif service.restricted %}
|
||||
Trial
|
||||
{% else %}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% from "components/components/button/macro.njk" import usaButton %}
|
||||
|
||||
{% block org_page_title %}
|
||||
Team members
|
||||
Organization administrators
|
||||
{% endblock %}
|
||||
|
||||
{% block maincolumn_content %}
|
||||
@@ -20,7 +20,7 @@
|
||||
{% endif %}
|
||||
|
||||
<h1 class="font-body-2xl">
|
||||
Team members
|
||||
Organization administrators
|
||||
</h1>
|
||||
|
||||
{% if show_search_box %}
|
||||
@@ -66,7 +66,7 @@
|
||||
<div class="js-stick-at-bottom-when-scrolling">
|
||||
{{ usaButton({
|
||||
"element": "a",
|
||||
"text": "Invite team member",
|
||||
"text": "Invite an organization administrator",
|
||||
"href": url_for('.invite_org_user', org_id=current_org.id),
|
||||
"classes": "usa-button"
|
||||
}) }}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
{% block maincolumn_content %}
|
||||
|
||||
{{ page_header("Invite a team member") }}
|
||||
{{ page_header("Invite an organization administrator") }}
|
||||
{% call form_wrapper() %}
|
||||
{{ form.email_address(
|
||||
param_extensions={
|
||||
@@ -26,11 +26,11 @@
|
||||
|
||||
<div class="margin-bottom-3">
|
||||
<p class="form-label">
|
||||
{{ current_org.name }} team members can:
|
||||
{{ current_org.name }} organization administrators can:
|
||||
</p>
|
||||
<ul class="list list-bullet">
|
||||
<li>see usage and team members for each service</li>
|
||||
<li>invite other team members</li>
|
||||
<li>access and manage all services</li>
|
||||
<li>invite or remove other organization administrators</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<p class="usa-hint">
|
||||
This template was deleted {{ template._template.updated_at|format_datetime_relative }}.
|
||||
</p>
|
||||
{% elif not current_user.has_permissions(ServicePermission.SEND_MESSAGES, 'manage_api_keys', ServicePermission.MANAGE_TEMPLATES, ServicePermission.MANAGE_SERVICE) or not user_has_template_permission %}
|
||||
{% elif not current_user.has_permissions(ServicePermission.SEND_MESSAGES, 'manage_api_keys', ServicePermission.MANAGE_TEMPLATES, ServicePermission.MANAGE_SERVICE, allow_org_user=True) or not user_has_template_permission %}
|
||||
<p class="top-gutter-1-3 {% if template.template_type != 'sms' %}margin-bottom-3{% endif %}">
|
||||
If you need to send this
|
||||
{{ 1|message_count_label(template.template_type, suffix='') }}
|
||||
@@ -17,12 +17,12 @@
|
||||
{% else %}
|
||||
<div class="grid-row margin-bottom-5">
|
||||
<div class="usa-button-group">
|
||||
{% if current_user.has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True) %}
|
||||
{% if current_user.has_permissions(ServicePermission.SEND_MESSAGES, restrict_admin_usage=True, allow_org_user=True) %}
|
||||
<a href="{{ url_for(".set_sender", service_id=current_service.id, template_id=template.id) }}" class="usa-button usa-pill-separate-item">
|
||||
Use this template
|
||||
</a>
|
||||
{% endif %}
|
||||
{% if current_user.has_permissions(ServicePermission.MANAGE_TEMPLATES) %}
|
||||
{% if current_user.has_permissions(ServicePermission.MANAGE_TEMPLATES, allow_org_user=True) %}
|
||||
<a href="{{ url_for(".edit_service_template", service_id=current_service.id, template_id=template.id) }}" class="usa-button usa-button--outline usa-pill-separate-item">
|
||||
Edit this template
|
||||
</a>
|
||||
|
||||
@@ -73,9 +73,9 @@ def unicode_truncate(s, length):
|
||||
|
||||
def should_skip_template_page(db_template):
|
||||
return (
|
||||
current_user.has_permissions(ServicePermission.SEND_MESSAGES)
|
||||
current_user.has_permissions(ServicePermission.SEND_MESSAGES, allow_org_user=True)
|
||||
and not current_user.has_permissions(
|
||||
ServicePermission.MANAGE_TEMPLATES, "manage_api_keys"
|
||||
ServicePermission.MANAGE_TEMPLATES, "manage_api_keys", allow_org_user=True
|
||||
)
|
||||
and not db_template["archived"]
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user