diff --git a/Taskfile.yml b/Taskfile.yml index 74f3e9c7c..2c67784b9 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -5,16 +5,66 @@ tasks: create-network: desc: Create the external network cmds: - - docker network create external-net + - (docker network create external-net) || true init-backend: desc: Initialize the backend project dir: tdrs-backend cmds: + - task: create-network - docker-compose -f docker-compose.yml up -d --build - docker-compose -f docker-compose.yml exec web sh -c "python ./manage.py makemigrations" - docker-compose -f docker-compose.yml exec web sh -c "python ./manage.py migrate" - docker-compose -f docker-compose.yml down + - task: sentry-down + + clone-sentry-repo: + desc: Clone the sentry repo + dir: sentry + cmds: + - git clone https://github.com/getsentry/self-hosted.git || true + + + create-sentry: + desc: Create Sentry service + dir: sentry + cmds: + # limiting the memory to 2GB and CPU to only one cpu @0, for faster response, you can remove the limittask : --cpuset-cpus 0 + - (docker run --privileged -p 9001:9000 -d --memory="8g" --memory-swap="8g" --name sentry docker:dind) || true + - docker exec sentry sh -c "git clone https://github.com/getsentry/self-hosted.git || true" + + # need sleep 10 for docker to start + # there is a bug with other version of self-hosted. looks like they are trying to upgrade to Django 5.0 (July 2024) + - docker exec sentry sh -c "cd self-hosted && sleep 10 && git checkout tags/23.10.1" + + # add bash + - docker exec sentry sh -c "apk add bash" + - docker cp docker-compose.yml sentry:/self-hosted/docker-compose.yml + - docker cp .env sentry:/self-hosted/.env + - docker exec sentry bash -c "cd self-hosted && ./install.sh --skip-user-creation --no-report-self-hosted-issues" + # create a new user + - docker exec sentry bash -c "cd self-hosted && docker-compose run --rm web createuser --email admin@tanf.com --password admin --superuser" + # copy backup.json file to sentry + - docker cp backup.json sentry:/self-hosted/sentry/backup.json + # restore backup + - docker exec sentry bash -c "cd self-hosted && docker compose up -d" + - docker exec sentry bash -c "docker cp /self-hosted/sentry/backup.json sentry-self-hosted-web-1:/home/sentry/backup.json" + - docker exec sentry bash -c "docker exec sentry-self-hosted-web-1 bash -c 'sentry import /home/sentry/backup.json'" + - docker exec sentry bash -c "cd self-hosted && docker compose down" + - docker exec sentry bash -c "cd self-hosted && docker compose up -d" + + + sentry-up: + desc: Start sentry service + dir: sentry + cmds: + - docker exec sentry bash -c "cd self-hosted && docker-compose up -d" + + sentry-down: + desc: Stop sentry service + dir: sentry + cmds: + - docker exec sentry bash -c "cd self-hosted && docker-compose down" drop-db: desc: Drop the backend database @@ -45,7 +95,7 @@ tasks: desc: Restart backend web server dir: tdrs-backend cmds: - - docker-compose -f docker-compose.yml restart -d + - docker-compose -f docker-compose.yml restart backend-bash: desc: Open a shell in the backend container @@ -78,6 +128,7 @@ tasks: desc: Run flake8 in the backend container dir: tdrs-backend cmds: + - task backend-up - docker-compose -f docker-compose.yml exec web sh -c "flake8 . && if [ $? -eq 0 ]; then echo 'Flake8 linter found no issues'; fi" backend-pip-lock: @@ -85,6 +136,7 @@ tasks: desc: Lock the pip dependencies dir: tdrs-backend cmds: + - task: backend-up - docker-compose -f docker-compose.yml exec web sh -c "pipenv lock" psql: @@ -99,9 +151,10 @@ tasks: clean: desc: Remove all containers, networks, and volumes cmds: - - docker-compose -f tdrs-backend/docker-compose.yml down -v - - docker-compose -f tdrs-frontend/docker-compose.yml down -v - - docker system prune -f -a + - docker stop $(docker ps -aq) || true + - docker rm $(docker ps -aq) || true + - docker rmi $(docker images -q) || true + - docker volume rm $(docker volume ls -q) || true clamav-up: desc: Start clamav service @@ -125,7 +178,7 @@ tasks: desc: Restart frontend web server dir: tdrs-frontend cmds: - - docker-compose -f docker-compose.yml restart -d + - docker-compose -f docker-compose.yml restart frontend-av: desc: Start frontend with optional clamav service diff --git a/docs/Sprint-Review/sprint-105-summary.md b/docs/Sprint-Review/sprint-105-summary.md new file mode 100644 index 000000000..b9b57f9ef --- /dev/null +++ b/docs/Sprint-Review/sprint-105-summary.md @@ -0,0 +1,92 @@ +# sprint-105-summary + +7/31/2024 - 8/14/2024 + +### Priority Setting + +* Reparsing + * Tickets: + * \#3064 — Re-parse Meta Model + * \#3113 — As tech lead, I need the validation on the header update indicator revised to unblock parsing + * \#3073 — \[bug] TDP is raising cat 4 error on TANF/SSP closed case files that is not present +* System Monitoring +* DIGIT Work + +### Sprint Goal + +**Dev:** + +_**Plain Language Error Messaging and Application Health Monitoring work, improved dev tooling, and fixing bugs**_ + +* \#2792 — \[Error Audit] Category 3 error messages clean-up +* \#2965 — As tech lead, I want a database seed implemented for testing +* \#3064 — Re-parse Meta Model +* \#3113 — As tech lead, I need the validation on the header update indicator revised to unblock parsing +* \#3073 — \[bug] TDP is raising cat 4 error on TANF/SSP closed case files that is not present +* \#3062 — bug: ES docker image for non-dev spaces stored in personal dockerhub +* \#1646 — \[A11y Fix] Correct TDP home : aria label mismatch + +**DevOps:** + +_**Successful deployments across environments and pipeline stability investments**_ + +* \#2458 — Integrate Nexus into CircleCI + +**Design:** + +_**Support reviews, Complete Research Synthesis, Continue Error Audit (Cat 4)**_ + +* \#3078 — DIGIT Admin Experience Synthesis +* \#3114 — \[Design Spike] In-app banner for submission history pages +* \#2968 — \[Design Deliverable] Update Error Audit for Cat 4 / QA + +## Tickets + +### Completed/Merged + +* [#1621 As a TDP user, I'd like to see a descriptive error message page if authentication source is unavailable.](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/1621) +* [#1646 \[A11y Fix\] Correct TDP home : aria label mismatch](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/1646) +* [#3033 As tech lead, I need the sections 3 and 4 calendar quarter logic updated](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3033) +* [#3055 Service timeout blocks parsing completion](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3055) +* [#3057 \[Design Deliverable\] Spec for light-lift fiscal quarter / calendar quarter explainer in TDP](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3057) +* [#3113 As tech lead, I need the validation on the header update indicator revised to unblock parsing ](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3113) + +### Submitted (QASP Review, OCIO Review) + +* [#2954 Extend SESSION\_COOKIE\_AGE](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2954) +* [#3061 \[a11y fix\] Django multi-select filter ](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3061) +* [#3079 DB Backup Script Fix](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3079) +* [#2883 Pre-Made Reporting Dashboards on Kibana](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2883) +* [#2985 \[Design Deliverable\] Email spec for Admin Notification for stuck files](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2985) +* [#2996 Add dynamic field name to cat4 error messages](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2996) +* [#2993 Kibana Dashboard MVP](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2993) + +### Ready to Merge + +* [#3058 \[Design Deliverable\] Release notes email template](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3058) +* [#3062 bug: ES docker image for non-dev spaces stored in personal dockerhub](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3062) +* [#3073 \[bug\] TDP is raising cat 4 error on TANF/SSP closed case files that is not present](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3073) +* [#3107 \[Re-parse command\] Retain original submission date when command runs](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3107) + +### Closed (Not Merged) + +* [#1355 Research questions around DIGIT teams query usage for parsed data](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/1355) + +### Moved to Next Sprint + +**In Progress** + +* [#2965 As tech lead, I want a database seed implemented for testing](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2965) + +#### Blocked + +* [#2458 Integrate Nexus into CircleCI](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2458) + +**Raft Review** + +* [#3043 Sentry: Local environment for Debugging](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3043) +* [#3064 Re-parse Meta Model](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3064) +* [#3065 Spike - Guarantee Sequential Execution of Re-parse Command](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3065) +* [#3078 \[Research Synthesis\] DIGIT Admin Experience Improvements](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3078) +* [#3087 Admin By Newest Filter Enhancements for Data Files Page](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3087) +* [#2792 \[Error Audit\] Category 3 error messages clean-up](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2792) diff --git a/docs/Sprint-Review/sprint-106-summary.md b/docs/Sprint-Review/sprint-106-summary.md new file mode 100644 index 000000000..6d211ed81 --- /dev/null +++ b/docs/Sprint-Review/sprint-106-summary.md @@ -0,0 +1,97 @@ +# sprint-106-summary + +8/14/202 - 8/27/2024 + +### Priority Setting + +* Reparsing + * Reasoning: OFA has ability to reparse and the data process with latest system logic which will enable STTs to get error reports that are meaningful and relevant and OFA gets the needed data. System, as a whole, will be more flexible with data flow (able to hot fix and hit reparse). Additionally, we want to avoid missing data and be able to repopulate the database after cleaning the data. +* Data Access Strategy + * Reasoning: Creating daily blockers +* Admin Console Improvements + * Reasoning: Trigger has been met to refine tickets (Research Synthesis) +* Improved Dev Tooling + * improve test\_parse.py 2641 + * separate celery 2592 + * Reasoning: Developing / refining tickets to support the above priorities – These tickets will enhance capabilities while the above are being flushed out + +### Sprint Goal + +**Dev:** + +_**Reparsing, Admin Console Improvements, Application Health Monitoring work, and Improved Dev Tooling**_ + +* \#2965 — As tech lead, I want a database seed implemented for testing +* \#3102 — Admin Exp: Django Implement Multi-Select Fiscal Period Dropdown For Data Export +* \#2561 — As a sys admin, I need TDP to automatically deactivate accounts that are inactive for 180 days +* \#3110 — Spike - Investigate Custom Filter Integration +* \#3137 — \[bug] OFA unable to export data to csv by record type and fiscal period +* \#3074 — TDP Data Files page permissions for DIGIT & Sys Admin user groups +* \#3076 — Admin Filter Enhancements for Data Files Page + +**DevOps:** + +_**Successful deployments across environments and pipeline stability investments**_ + +* + +**Design:** + +_**Support reviews, In-app banner to support parsed data, Continue Error Audit (Cat 4)**_ + +* \#2968 — \[Design Deliverable] Update Error Audit for Cat 4 / QA +* \#3114 — \[Design Spike] In-app banner for submission history pages w/ data parsed before May 2024 +* \#3143 — August release notes — Knowledge Center & Email Template + + + +## Tickets + +### Completed/Merged + +* [#2985 \[Design Deliverable\] Email spec for Admin Notification for stuck files](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2985) +* [#2996 Add dynamic field name to cat4 error messages](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2996) +* [#3143 August release notes — Knowledge Center & Email Template](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3143) +* [#3061 \[a11y fix\] Django multi-select filter ](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3061) +* [#2954 Extend SESSION\_COOKIE\_AGE](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2954) +* [#3079 DB Backup Script Fix](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3079) + +### Submitted (QASP Review, OCIO Review) + +* [#3064 Re-parse Meta Model](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3064) +* [#3065 Spike - Guarantee Sequential Execution of Re-parse Command](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3065) +* [#2792 \[Error Audit\] Category 3 error messages clean-up](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2792) +* [#2883 Pre-Made Reporting Dashboards on Kibana](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2883) +* [#2561 As a sys admin, I need TDP to automatically deactivate accounts that are inactive for 180 days](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2561) +* [#3078 \[Research Synthesis\] DIGIT Admin Experience Improvements](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3078) + +### Ready to Merge + +### Closed (Not Merged) + +* [#3147 S3 buckets contain fewer datafiles than DAC](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3147) + +### Moved to Next Sprint + +**In Progress** + +* [#2965 As tech lead, I want a database seed implemented for testing](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2965) +* [#2458 Integrate Nexus into CircleCI](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2458) +* [#3137 \[bug\] OFA unable to export data to csv by record type and fiscal period](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3137) +* [#2968 \[Design Deliverable\] Update Error Audit for Cat 4 / QA](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/2968) +* [#3060 As a TDP user, I need to stay logged in when I'm actively using the system](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3060) +* [#3074 TDP Data Files page permissions for DIGIT & Sys Admin user groups](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3074) +* [#3114 \[Design Spike\] In-app banner for submission history pages w/ data parsed before May 2024](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3114) +* [#3142 \[Research Spike\] Get more detail about Yun & DIGIT's data workflow and use cases](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3142) + +#### Blocked + +* + +**Raft Review** + +* [#3043 Sentry: Local environment for Debugging](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3043) +* [#3110 Spike - Investigate Custom Filter Integration](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3110) +* [#3102 Admin Exp: Django Implement Multi-Select Fiscal Period Dropdown For Data Export ](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3102) +* [#3087 Admin By Newest Filter Enhancements for Data Files Page](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3087) +* [#3076 Admin Filter Enhancements for Data Files Page ](https://app.zenhub.com/workspaces/sprint-board-5f18ab06dfd91c000f7e682e/issues/gh/raft-tech/tanf-app/3076) diff --git a/sentry/.env b/sentry/.env new file mode 100644 index 000000000..a3d4f1b11 --- /dev/null +++ b/sentry/.env @@ -0,0 +1,35 @@ +COMPOSE_PROJECT_NAME=sentry-self-hosted +COMPOSE_PROFILES=feature-complete +SENTRY_EVENT_RETENTION_DAYS=90 +# You can either use a port number or an IP:PORT combo for SENTRY_BIND +# See https://docs.docker.com/compose/compose-file/#ports for more +SENTRY_BIND=9000 +# Set SENTRY_MAIL_HOST to a valid FQDN (host/domain name) to be able to send emails! +# SENTRY_MAIL_HOST=example.com + + +# https://hub.docker.com/r/getsentry/sentry/tags?page=1205&page_size=&ordering=&name= +SENTRY_IMAGE=getsentry/sentry:23.10.1 + + +# https://hub.docker.com/r/getsentry/snuba/tags?page=105&page_size=&name=&ordering= +SNUBA_IMAGE=getsentry/snuba:23.10.1 + +# https://hub.docker.com/r/getsentry/relay/tags?page=100&page_size=&name=&ordering= +RELAY_IMAGE=getsentry/relay:23.10.1 + + +#https://hub.docker.com/r/getsentry/symbolicator/tags?page=15&page_size=&name=&ordering= +SYMBOLICATOR_IMAGE=getsentry/symbolicator:23.10.1 + +# https://hub.docker.com/r/getsentry/vroom/tags?page=15&page_size=&name=&ordering= +VROOM_IMAGE=getsentry/vroom:23.10.1 + + +WAL2JSON_VERSION=latest +HEALTHCHECK_INTERVAL=30s +HEALTHCHECK_TIMEOUT=1m30s +HEALTHCHECK_RETRIES=10 +# Caution: Raising max connections of postgres increases CPU and RAM usage +# see https://github.com/getsentry/self-hosted/pull/2740 for more information +POSTGRES_MAX_CONNECTIONS=100 \ No newline at end of file diff --git a/sentry/backup.json b/sentry/backup.json new file mode 100644 index 000000000..e83f7b874 --- /dev/null +++ b/sentry/backup.json @@ -0,0 +1,503 @@ +[ +{ + "model": "sites.site", + "pk": 1, + "fields": { + "domain": "example.com", + "name": "example.com" + } +}, +{ + "model": "sentry.option", + "pk": 1, + "fields": { + "key": "sentry:last_worker_ping", + "last_updated": "2024-08-01T13:53:00.189Z", + "last_updated_by": "unknown", + "value": 1722520380.1114867 + } +}, +{ + "model": "sentry.option", + "pk": 2, + "fields": { + "key": "sentry:last_worker_version", + "last_updated": "2024-08-01T13:53:00.238Z", + "last_updated_by": "unknown", + "value": "\"23.7.0.dev0\"" + } +}, +{ + "model": "sentry.option", + "pk": 3, + "fields": { + "key": "system.url-prefix", + "last_updated": "2024-08-01T13:50:36.841Z", + "last_updated_by": "unknown", + "value": "\"http://localhost:9001\"" + } +}, +{ + "model": "sentry.option", + "pk": 4, + "fields": { + "key": "system.admin-email", + "last_updated": "2024-08-01T13:50:36.854Z", + "last_updated_by": "unknown", + "value": "\"admin@tanf.com\"" + } +}, +{ + "model": "sentry.option", + "pk": 5, + "fields": { + "key": "mail.port", + "last_updated": "2024-08-01T13:50:36.860Z", + "last_updated_by": "unknown", + "value": 25 + } +}, +{ + "model": "sentry.option", + "pk": 6, + "fields": { + "key": "mail.username", + "last_updated": "2024-08-01T13:50:36.866Z", + "last_updated_by": "unknown", + "value": "\"\"" + } +}, +{ + "model": "sentry.option", + "pk": 7, + "fields": { + "key": "mail.password", + "last_updated": "2024-08-01T13:50:36.870Z", + "last_updated_by": "unknown", + "value": "\"\"" + } +}, +{ + "model": "sentry.option", + "pk": 8, + "fields": { + "key": "mail.use-tls", + "last_updated": "2024-08-01T13:50:36.873Z", + "last_updated_by": "unknown", + "value": false + } +}, +{ + "model": "sentry.option", + "pk": 9, + "fields": { + "key": "mail.use-ssl", + "last_updated": "2024-08-01T13:50:36.876Z", + "last_updated_by": "unknown", + "value": false + } +}, +{ + "model": "sentry.option", + "pk": 10, + "fields": { + "key": "auth.allow-registration", + "last_updated": "2024-08-01T13:50:36.883Z", + "last_updated_by": "unknown", + "value": false + } +}, +{ + "model": "sentry.option", + "pk": 11, + "fields": { + "key": "sentry:version-configured", + "last_updated": "2024-08-01T13:50:36.889Z", + "last_updated_by": "unknown", + "value": "\"23.7.0.dev0.dd25c26bcece07936bb6401f6fa9c89b96a2118e\"" + } +}, +{ + "model": "sentry.actor", + "pk": 1, + "fields": { + "type": 0, + "user_id": null, + "team": 1 + } +}, +{ + "model": "sentry.actor", + "pk": 2, + "fields": { + "type": 1, + "user_id": 1, + "team": null + } +}, +{ + "model": "sentry.email", + "pk": 1, + "fields": { + "email": "admin@tanf.com", + "date_added": "2024-08-01T13:46:16.066Z" + } +}, +{ + "model": "sentry.organization", + "pk": 1, + "fields": { + "name": "Sentry", + "slug": "sentry", + "status": 0, + "date_added": "2024-08-01T13:44:41.175Z", + "default_role": "member", + "is_test": false, + "flags": "1" + } +}, +{ + "model": "sentry.user", + "pk": 1, + "fields": { + "password": "pbkdf2_sha256$150000$hhBadj48lYdN$XnnczKcFZPnOXsw6KLgbOdg+9Ff8oIFCzKBFuLPh7M4=", + "last_login": "2024-08-01T13:50:33.020Z", + "username": "admin@tanf.com", + "name": "", + "email": "admin@tanf.com", + "is_staff": true, + "is_active": true, + "is_superuser": true, + "is_managed": false, + "is_sentry_app": null, + "is_password_expired": false, + "last_password_change": "2024-08-01T13:46:16.183Z", + "flags": "0", + "session_nonce": null, + "date_joined": "2024-08-01T13:46:16.058Z", + "last_active": "2024-08-01T13:51:16.376Z", + "avatar_type": 0, + "avatar_url": null + } +}, +{ + "model": "sentry.organizationmapping", + "pk": 1, + "fields": { + "organization_id": 1, + "slug": "sentry", + "name": "Sentry", + "date_created": "2024-08-01T13:44:41.239Z", + "customer_id": null, + "verified": false, + "idempotency_key": "", + "region_name": "--monolith--", + "status": 0 + } +}, +{ + "model": "sentry.relayusage", + "pk": 1, + "fields": { + "relay_id": "6d26be62-e8e3-4604-a148-656227d9769f", + "version": "23.6.1", + "first_seen": "2024-08-01T13:48:32.374Z", + "last_seen": "2024-08-01T13:48:32.374Z", + "public_key": "VGxPbAyvOjbRdVdaIF8PmuCq-0YCjRqT9Q0dKhxYg_A" + } +}, +{ + "model": "sentry.relay", + "pk": 1, + "fields": { + "relay_id": "6d26be62-e8e3-4604-a148-656227d9769f", + "public_key": "VGxPbAyvOjbRdVdaIF8PmuCq-0YCjRqT9Q0dKhxYg_A", + "first_seen": null, + "last_seen": null, + "is_internal": true + } +}, +{ + "model": "sentry.useremail", + "pk": 1, + "fields": { + "user": [ + "admin@tanf.com" + ], + "email": "admin@tanf.com", + "validation_hash": "PFGHXGxhV2oGjQI9tZDOLjx6Q1qZWtKN", + "date_hash_added": "2024-08-01T13:46:16.064Z", + "is_verified": false + } +}, +{ + "model": "sentry.userip", + "pk": 1, + "fields": { + "user": [ + "admin@tanf.com" + ], + "ip_address": "192.168.65.1", + "country_code": null, + "region_code": null, + "first_seen": "2024-08-01T13:49:08.204Z", + "last_seen": "2024-08-01T13:49:08.193Z" + } +}, +{ + "model": "sentry.userrole", + "pk": 1, + "fields": { + "date_updated": "2024-08-01T13:44:41.170Z", + "date_added": "2024-08-01T13:44:41.170Z", + "name": "Super Admin", + "permissions": "['broadcasts.admin', 'users.admin', 'options.admin']" + } +}, +{ + "model": "sentry.userroleuser", + "pk": 1, + "fields": { + "date_updated": "2024-08-01T13:46:16.196Z", + "date_added": "2024-08-01T13:46:16.196Z", + "user": [ + "admin@tanf.com" + ], + "role": 1 + } +}, +{ + "model": "sentry.team", + "pk": 1, + "fields": { + "organization": 1, + "slug": "sentry", + "name": "Sentry", + "status": 0, + "actor": 1, + "idp_provisioned": false, + "date_added": "2024-08-01T13:44:41.185Z", + "org_role": null + } +}, +{ + "model": "sentry.organizationmember", + "pk": 1, + "fields": { + "organization": 1, + "user_id": 1, + "email": null, + "role": "owner", + "flags": "0", + "token": null, + "date_added": "2024-08-01T13:46:16.073Z", + "token_expires_at": null, + "has_global_access": true, + "inviter_id": null, + "invite_status": 0, + "type": 50, + "user_is_active": true, + "user_email": "admin@tanf.com" + } +}, +{ + "model": "sentry.project", + "pk": 1, + "fields": { + "slug": "internal", + "name": "Internal", + "forced_color": null, + "organization": 1, + "public": false, + "date_added": "2024-08-01T13:44:41.191Z", + "status": 0, + "first_event": null, + "flags": "10", + "platform": null + } +}, +{ + "model": "sentry.project", + "pk": 2, + "fields": { + "slug": "python-django", + "name": "python-django", + "forced_color": null, + "organization": 1, + "public": false, + "date_added": "2024-08-01T13:50:58.893Z", + "status": 0, + "first_event": null, + "flags": "10", + "platform": "python-django" + } +}, +{ + "model": "sentry.projectkey", + "pk": 1, + "fields": { + "project": 1, + "label": "Default", + "public_key": "20835f66e30e4e19ac9c98c83bbd951f", + "secret_key": "50b61843dabe4b78886b6817421dc6a1", + "roles": "1", + "status": 0, + "date_added": "2024-08-01T13:44:41.205Z", + "rate_limit_count": null, + "rate_limit_window": null, + "data": { + "dynamicSdkLoaderOptions": { + "hasPerformance": true, + "hasReplay": true + } + } + } +}, +{ + "model": "sentry.projectkey", + "pk": 2, + "fields": { + "project": 2, + "label": "Default", + "public_key": "43ebf8abe1434ec6aea2c7b92c465a0e", + "secret_key": "c62d7709665848f88bbe09082e019f75", + "roles": "1", + "status": 0, + "date_added": "2024-08-01T13:50:59.103Z", + "rate_limit_count": null, + "rate_limit_window": null, + "data": { + "dynamicSdkLoaderOptions": { + "hasPerformance": true, + "hasReplay": true + } + } + } +}, +{ + "model": "sentry.rule", + "pk": 1, + "fields": { + "project": 1, + "environment_id": null, + "label": "Send a notification for new issues", + "data": "{\"match\":\"all\",\"conditions\":[{\"id\":\"sentry.rules.conditions.first_seen_event.FirstSeenEventCondition\"}],\"actions\":[{\"id\":\"sentry.mail.actions.NotifyEmailAction\",\"targetType\":\"IssueOwners\",\"targetIdentifier\":null,\"fallthroughType\":\"ActiveMembers\"}]}", + "status": 0, + "source": 0, + "owner": null, + "date_added": "2024-08-01T13:44:41.213Z" + } +}, +{ + "model": "sentry.rule", + "pk": 2, + "fields": { + "project": 2, + "environment_id": null, + "label": "Send a notification for new issues", + "data": "{\"match\":\"all\",\"conditions\":[{\"id\":\"sentry.rules.conditions.first_seen_event.FirstSeenEventCondition\"}],\"actions\":[{\"id\":\"sentry.mail.actions.NotifyEmailAction\",\"targetType\":\"IssueOwners\",\"targetIdentifier\":null,\"fallthroughType\":\"ActiveMembers\"}]}", + "status": 0, + "source": 0, + "owner": null, + "date_added": "2024-08-01T13:50:59.204Z" + } +}, +{ + "model": "sentry.projectteam", + "pk": 1, + "fields": { + "project": 1, + "team": 1 + } +}, +{ + "model": "sentry.projectteam", + "pk": 2, + "fields": { + "project": 2, + "team": 1 + } +}, +{ + "model": "sentry.organizationmemberteam", + "pk": 1, + "fields": { + "team": 1, + "organizationmember": 1, + "is_active": true, + "role": null + } +}, +{ + "model": "sentry.projectoption", + "pk": 1, + "fields": { + "project": 1, + "key": "sentry:relay-rev", + "value": "\"124b064568394513a93c1cf6b96fa531\"" + } +}, +{ + "model": "sentry.projectoption", + "pk": 2, + "fields": { + "project": 1, + "key": "sentry:relay-rev-lastchange", + "value": "\"2024-08-01T13:44:41.228498Z\"" + } +}, +{ + "model": "sentry.projectoption", + "pk": 3, + "fields": { + "project": 1, + "key": "sentry:option-epoch", + "value": 11 + } +}, +{ + "model": "sentry.projectoption", + "pk": 4, + "fields": { + "project": 1, + "key": "sentry:origins", + "value": "[\"*\"]" + } +}, +{ + "model": "sentry.projectoption", + "pk": 5, + "fields": { + "project": 2, + "key": "sentry:relay-rev", + "value": "\"c588a54b4537446c8ca91477867aeddd\"" + } +}, +{ + "model": "sentry.projectoption", + "pk": 6, + "fields": { + "project": 2, + "key": "sentry:relay-rev-lastchange", + "value": "\"2024-08-01T13:51:01.098125Z\"" + } +}, +{ + "model": "sentry.projectoption", + "pk": 7, + "fields": { + "project": 2, + "key": "sentry:option-epoch", + "value": 11 + } +}, +{ + "model": "sentry.projectoption", + "pk": 8, + "fields": { + "project": 2, + "key": "sentry:token", + "value": "\"164d36a4500d11ef938f0242ac130024\"" + } +} +] diff --git a/sentry/docker-compose.yml b/sentry/docker-compose.yml new file mode 100644 index 000000000..86ecb3615 --- /dev/null +++ b/sentry/docker-compose.yml @@ -0,0 +1,496 @@ +x-restart-policy: &restart_policy + restart: unless-stopped +x-depends_on-healthy: &depends_on-healthy + condition: service_healthy +x-depends_on-default: &depends_on-default + condition: service_started +x-healthcheck-defaults: &healthcheck_defaults + # Avoid setting the interval too small, as docker uses much more CPU than one would expect. + # Related issues: + # https://github.com/moby/moby/issues/39102 + # https://github.com/moby/moby/issues/39388 + # https://github.com/getsentry/self-hosted/issues/1000 + interval: "$HEALTHCHECK_INTERVAL" + timeout: "$HEALTHCHECK_TIMEOUT" + retries: $HEALTHCHECK_RETRIES + start_period: 10s +x-sentry-defaults: &sentry_defaults + <<: *restart_policy + image: sentry-self-hosted-local + # Set the platform to build for linux/arm64 when needed on Apple silicon Macs. + platform: ${DOCKER_PLATFORM:-} + build: + context: ./sentry + args: + - SENTRY_IMAGE + depends_on: + redis: + <<: *depends_on-healthy + kafka: + <<: *depends_on-healthy + postgres: + <<: *depends_on-healthy + memcached: + <<: *depends_on-default + smtp: + <<: *depends_on-default + snuba-api: + <<: *depends_on-default + snuba-consumer: + <<: *depends_on-default + snuba-outcomes-consumer: + <<: *depends_on-default + snuba-transactions-consumer: + <<: *depends_on-default + snuba-subscription-consumer-events: + <<: *depends_on-default + snuba-subscription-consumer-transactions: + <<: *depends_on-default + snuba-replacer: + <<: *depends_on-default + symbolicator: + <<: *depends_on-default + vroom: + <<: *depends_on-default + entrypoint: "/etc/sentry/entrypoint.sh" + command: ["run", "web"] + environment: + PYTHONUSERBASE: "/data/custom-packages" + SENTRY_CONF: "/etc/sentry" + SNUBA: "http://snuba-api:1218" + VROOM: "http://vroom:8085" + # Force everything to use the system CA bundle + # This is mostly needed to support installing custom CA certs + # This one is used by botocore + DEFAULT_CA_BUNDLE: &ca_bundle "/etc/ssl/certs/ca-certificates.crt" + # This one is used by requests + REQUESTS_CA_BUNDLE: *ca_bundle + # This one is used by grpc/google modules + GRPC_DEFAULT_SSL_ROOTS_FILE_PATH_ENV_VAR: *ca_bundle + # Leaving the value empty to just pass whatever is set + # on the host system (or in the .env file) + SENTRY_EVENT_RETENTION_DAYS: + SENTRY_MAIL_HOST: + SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE: + # Set this value if you plan on using the Suggested Fix Feature + OPENAI_API_KEY: + volumes: + - "sentry-data:/data" + - "./sentry:/etc/sentry" + - "./geoip:/geoip:ro" + - "./certificates:/usr/local/share/ca-certificates:ro" +x-snuba-defaults: &snuba_defaults + <<: *restart_policy + depends_on: + clickhouse: + <<: *depends_on-healthy + kafka: + <<: *depends_on-healthy + redis: + <<: *depends_on-healthy + image: "$SNUBA_IMAGE" + environment: + SNUBA_SETTINGS: self_hosted + CLICKHOUSE_HOST: clickhouse + DEFAULT_BROKERS: "kafka:9092" + REDIS_HOST: redis + UWSGI_MAX_REQUESTS: "10000" + UWSGI_DISABLE_LOGGING: "true" + # Leaving the value empty to just pass whatever is set + # on the host system (or in the .env file) + SENTRY_EVENT_RETENTION_DAYS: +services: + smtp: + <<: *restart_policy + platform: linux/amd64 + image: tianon/exim4 + hostname: "${SENTRY_MAIL_HOST:-}" + volumes: + - "sentry-smtp:/var/spool/exim4" + - "sentry-smtp-log:/var/log/exim4" + memcached: + <<: *restart_policy + image: "memcached:1.6.21-alpine" + command: ["-I", "${SENTRY_MAX_EXTERNAL_SOURCEMAP_SIZE:-1M}"] + healthcheck: + <<: *healthcheck_defaults + # From: https://stackoverflow.com/a/31877626/5155484 + test: echo stats | nc 127.0.0.1 11211 + redis: + <<: *restart_policy + image: "redis:6.2.13-alpine" + healthcheck: + <<: *healthcheck_defaults + test: redis-cli ping + volumes: + - "sentry-redis:/data" + ulimits: + nofile: + soft: 10032 + hard: 10032 + postgres: + <<: *restart_policy + # Using the same postgres version as Sentry dev for consistency purposes + image: "postgres:14.5" + healthcheck: + <<: *healthcheck_defaults + # Using default user "postgres" from sentry/sentry.conf.example.py or value of POSTGRES_USER if provided + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-postgres}"] + command: + [ + "postgres", + "-c", + "wal_level=logical", + "-c", + "max_replication_slots=1", + "-c", + "max_wal_senders=1", + ] + environment: + POSTGRES_HOST_AUTH_METHOD: "trust" + entrypoint: /opt/sentry/postgres-entrypoint.sh + volumes: + - "sentry-postgres:/var/lib/postgresql/data" + - type: bind + read_only: true + source: ./postgres/ + target: /opt/sentry/ + zookeeper: + <<: *restart_policy + image: "confluentinc/cp-zookeeper:5.5.7" + environment: + ZOOKEEPER_CLIENT_PORT: "2181" + CONFLUENT_SUPPORT_METRICS_ENABLE: "false" + ZOOKEEPER_LOG4J_ROOT_LOGLEVEL: "WARN" + ZOOKEEPER_TOOLS_LOG4J_LOGLEVEL: "WARN" + KAFKA_OPTS: "-Dzookeeper.4lw.commands.whitelist=ruok" + ulimits: + nofile: + soft: 4096 + hard: 4096 + volumes: + - "sentry-zookeeper:/var/lib/zookeeper/data" + - "sentry-zookeeper-log:/var/lib/zookeeper/log" + - "sentry-secrets:/etc/zookeeper/secrets" + healthcheck: + <<: *healthcheck_defaults + test: + ["CMD-SHELL", 'echo "ruok" | nc -w 2 localhost 2181 | grep imok'] + kafka: + <<: *restart_policy + depends_on: + zookeeper: + <<: *depends_on-healthy + image: "confluentinc/cp-kafka:5.5.7" + environment: + KAFKA_ZOOKEEPER_CONNECT: "zookeeper:2181" + KAFKA_ADVERTISED_LISTENERS: "PLAINTEXT://kafka:9092" + KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: "1" + KAFKA_OFFSETS_TOPIC_NUM_PARTITIONS: "1" + KAFKA_LOG_RETENTION_HOURS: "24" + KAFKA_MESSAGE_MAX_BYTES: "50000000" #50MB or bust + KAFKA_MAX_REQUEST_SIZE: "50000000" #50MB on requests apparently too + KAFKA_HEAP_OPTS: "-Xmx500M -Xms500M" + CONFLUENT_SUPPORT_METRICS_ENABLE: "false" + KAFKA_LOG4J_LOGGERS: "kafka.cluster=WARN,kafka.controller=WARN,kafka.coordinator=WARN,kafka.log=WARN,kafka.server=WARN,kafka.zookeeper=WARN,state.change.logger=WARN" + KAFKA_LOG4J_ROOT_LOGLEVEL: "WARN" + KAFKA_TOOLS_LOG4J_LOGLEVEL: "WARN" + ulimits: + nofile: + soft: 4096 + hard: 4096 + volumes: + - "sentry-kafka:/var/lib/kafka/data" + - "sentry-kafka-log:/var/lib/kafka/log" + - "sentry-secrets:/etc/kafka/secrets" + healthcheck: + <<: *healthcheck_defaults + test: ["CMD-SHELL", "/usr/bin/kafka-topics --bootstrap-server kafka:9092 --list"] + interval: 10s + timeout: 10s + retries: 30 + clickhouse: + <<: *restart_policy + image: clickhouse-self-hosted-local + build: + context: ./clickhouse + args: + BASE_IMAGE: "${CLICKHOUSE_IMAGE:-}" + ulimits: + nofile: + soft: 262144 + hard: 262144 + volumes: + - "sentry-clickhouse:/var/lib/clickhouse" + - "sentry-clickhouse-log:/var/log/clickhouse-server" + - type: bind + read_only: true + source: ./clickhouse/config.xml + target: /etc/clickhouse-server/config.d/sentry.xml + environment: + # This limits Clickhouse's memory to 30% of the host memory + # If you have high volume and your search return incomplete results + # You might want to change this to a higher value (and ensure your host has enough memory) + MAX_MEMORY_USAGE_RATIO: 0.3 + healthcheck: + test: [ + "CMD-SHELL", + # Manually override any http_proxy envvar that might be set, because + # this wget does not support no_proxy. See: + # https://github.com/getsentry/self-hosted/issues/1537 + "http_proxy='' wget -nv -t1 --spider 'http://localhost:8123/' || exit 1", + ] + interval: 10s + timeout: 10s + retries: 30 + geoipupdate: + image: "ghcr.io/maxmind/geoipupdate:v6.0.0" + # Override the entrypoint in order to avoid using envvars for config. + # Futz with settings so we can keep mmdb and conf in same dir on host + # (image looks for them in separate dirs by default). + entrypoint: ["/usr/bin/geoipupdate", "-d", "/sentry", "-f", "/sentry/GeoIP.conf"] + volumes: + - "./geoip:/sentry" + snuba-api: + <<: *snuba_defaults + # Kafka consumer responsible for feeding events into Clickhouse + snuba-consumer: + <<: *snuba_defaults + command: consumer --storage errors --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + # Kafka consumer responsible for feeding outcomes into Clickhouse + # Use --auto-offset-reset=earliest to recover up to 7 days of TSDB data + # since we did not do a proper migration + snuba-outcomes-consumer: + <<: *snuba_defaults + command: consumer --storage outcomes_raw --auto-offset-reset=earliest --max-batch-time-ms 750 --no-strict-offset-reset + # Kafka consumer responsible for feeding transactions data into Clickhouse + snuba-transactions-consumer: + <<: *snuba_defaults + command: consumer --storage transactions --consumer-group transactions_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-replays-consumer: + <<: *snuba_defaults + command: consumer --storage replays --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-issue-occurrence-consumer: + <<: *snuba_defaults + command: consumer --storage search_issues --consumer-group generic_events_group --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-metrics-consumer: + <<: *snuba_defaults + command: consumer --storage metrics_raw --consumer-group snuba-metrics-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-generic-metrics-distributions-consumer: + <<: *snuba_defaults + command: consumer --storage generic_metrics_distributions_raw --consumer-group snuba-gen-metrics-distributions-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-generic-metrics-sets-consumer: + <<: *snuba_defaults + command: consumer --storage generic_metrics_sets_raw --consumer-group snuba-gen-metrics-sets-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-generic-metrics-counters-consumer: + <<: *snuba_defaults + command: consumer --storage generic_metrics_counters_raw --consumer-group snuba-gen-metrics-counters-consumers --auto-offset-reset=latest --max-batch-time-ms 750 --no-strict-offset-reset + snuba-replacer: + <<: *snuba_defaults + command: replacer --storage errors --auto-offset-reset=latest --no-strict-offset-reset + snuba-subscription-consumer-events: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset events --entity events --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-events-subscriptions-consumers --followed-consumer-group=snuba-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + snuba-subscription-consumer-transactions: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset transactions --entity transactions --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-transactions-subscriptions-consumers --followed-consumer-group=transactions_group --schedule-ttl=60 --stale-threshold-seconds=900 + snuba-subscription-consumer-metrics: + <<: *snuba_defaults + command: subscriptions-scheduler-executor --dataset metrics --entity metrics_sets --entity metrics_counters --auto-offset-reset=latest --no-strict-offset-reset --consumer-group=snuba-metrics-subscriptions-consumers --followed-consumer-group=snuba-metrics-consumers --schedule-ttl=60 --stale-threshold-seconds=900 + snuba-profiling-profiles-consumer: + <<: *snuba_defaults + command: consumer --storage profiles --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + snuba-profiling-functions-consumer: + <<: *snuba_defaults + command: consumer --storage functions_raw --auto-offset-reset=latest --max-batch-time-ms 1000 --no-strict-offset-reset + symbolicator: + <<: *restart_policy + image: "$SYMBOLICATOR_IMAGE" + volumes: + - "sentry-symbolicator:/data" + - type: bind + read_only: true + source: ./symbolicator + target: /etc/symbolicator + command: run -c /etc/symbolicator/config.yml + symbolicator-cleanup: + <<: *restart_policy + image: symbolicator-cleanup-self-hosted-local + build: + context: ./cron + args: + BASE_IMAGE: "$SYMBOLICATOR_IMAGE" + command: '"55 23 * * * gosu symbolicator symbolicator cleanup"' + volumes: + - "sentry-symbolicator:/data" + web: + <<: *sentry_defaults + ulimits: + nofile: + soft: 4096 + hard: 4096 + healthcheck: + <<: *healthcheck_defaults + test: + - "CMD" + - "/bin/bash" + - "-c" + # Courtesy of https://unix.stackexchange.com/a/234089/108960 + - 'exec 3<>/dev/tcp/127.0.0.1/9000 && echo -e "GET /_health/ HTTP/1.1\r\nhost: 127.0.0.1\r\n\r\n" >&3 && grep ok -s -m 1 <&3' + cron: + <<: *sentry_defaults + command: run cron + worker: + <<: *sentry_defaults + command: run worker + events-consumer: + <<: *sentry_defaults + command: run consumer ingest-events --consumer-group ingest-consumer + attachments-consumer: + <<: *sentry_defaults + command: run consumer ingest-attachments --consumer-group ingest-consumer + transactions-consumer: + <<: *sentry_defaults + command: run consumer ingest-transactions --consumer-group ingest-consumer + metrics-consumer: + <<: *sentry_defaults + command: run consumer ingest-metrics --consumer-group metrics-consumer + generic-metrics-consumer: + <<: *sentry_defaults + command: run consumer ingest-generic-metrics --consumer-group generic-metrics-consumer + billing-metrics-consumer: + <<: *sentry_defaults + command: run consumer billing-metrics-consumer --consumer-group billing-metrics-consumer + ingest-replay-recordings: + <<: *sentry_defaults + command: run consumer ingest-replay-recordings --consumer-group ingest-replay-recordings + ingest-occurrences: + <<: *sentry_defaults + command: run consumer ingest-occurrences --consumer-group ingest-occurrences + ingest-profiles: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset ingest-profiles --consumer-group ingest-profiles + ingest-monitors: + <<: *sentry_defaults + command: run consumer --no-strict-offset-reset ingest-monitors --consumer-group ingest-monitors + post-process-forwarder-errors: + <<: *sentry_defaults + command: run consumer post-process-forwarder-errors --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-commit-log --synchronize-commit-group=snuba-consumers + post-process-forwarder-transactions: + <<: *sentry_defaults + command: run consumer post-process-forwarder-transactions --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-transactions-commit-log --synchronize-commit-group transactions_group + post-process-forwarder-issue-platform: + <<: *sentry_defaults + command: run consumer post-process-forwarder-issue-platform --consumer-group post-process-forwarder --synchronize-commit-log-topic=snuba-generic-events-commit-log --synchronize-commit-group generic_events_group + subscription-consumer-events: + <<: *sentry_defaults + command: run consumer events-subscription-results --consumer-group query-subscription-consumer + subscription-consumer-transactions: + <<: *sentry_defaults + command: run consumer transactions-subscription-results --consumer-group query-subscription-consumer + subscription-consumer-metrics: + <<: *sentry_defaults + command: run consumer metrics-subscription-results --consumer-group query-subscription-consumer + subscription-consumer-generic-metrics: + <<: *sentry_defaults + command: run consumer generic-metrics-subscription-results --consumer-group query-subscription-consumer + sentry-cleanup: + <<: *sentry_defaults + image: sentry-cleanup-self-hosted-local + build: + context: ./cron + args: + BASE_IMAGE: sentry-self-hosted-local + entrypoint: "/entrypoint.sh" + command: '"0 0 * * * gosu sentry sentry cleanup --days $SENTRY_EVENT_RETENTION_DAYS"' + nginx: + <<: *restart_policy + ports: + - "$SENTRY_BIND:80/tcp" + image: "nginx:1.25.2-alpine" + volumes: + - type: bind + read_only: true + source: ./nginx + target: /etc/nginx + - sentry-nginx-cache:/var/cache/nginx + depends_on: + - web + - relay + relay: + <<: *restart_policy + image: "$RELAY_IMAGE" + volumes: + - type: bind + read_only: true + source: ./relay + target: /work/.relay + - type: bind + read_only: true + source: ./geoip + target: /geoip + depends_on: + kafka: + <<: *depends_on-healthy + redis: + <<: *depends_on-healthy + web: + <<: *depends_on-healthy + vroom: + <<: *restart_policy + image: "$VROOM_IMAGE" + environment: + SENTRY_KAFKA_BROKERS_PROFILING: "kafka:9092" + SENTRY_KAFKA_BROKERS_OCCURRENCES: "kafka:9092" + SENTRY_BUCKET_PROFILES: file://localhost//var/lib/sentry-profiles + SENTRY_SNUBA_HOST: "http://snuba-api:1218" + volumes: + - sentry-vroom:/var/lib/sentry-profiles + depends_on: + kafka: + <<: *depends_on-healthy + vroom-cleanup: + <<: *restart_policy + image: vroom-cleanup-self-hosted-local + build: + context: ./cron + args: + BASE_IMAGE: "$VROOM_IMAGE" + entrypoint: "/entrypoint.sh" + environment: + # Leaving the value empty to just pass whatever is set + # on the host system (or in the .env file) + SENTRY_EVENT_RETENTION_DAYS: + command: '"0 0 * * * find /var/lib/sentry-profiles -type f -mtime +$SENTRY_EVENT_RETENTION_DAYS -delete"' + volumes: + - sentry-vroom:/var/lib/sentry-profiles + +volumes: + # These store application data that should persist across restarts. + sentry-data: + external: true + sentry-postgres: + external: true + sentry-redis: + external: true + sentry-zookeeper: + external: true + sentry-kafka: + external: true + sentry-clickhouse: + external: true + sentry-symbolicator: + external: true + # This volume stores profiles and should be persisted. + # Not being external will still persist data across restarts. + # It won't persist if someone does a docker compose down -v. + sentry-vroom: + # These store ephemeral data that needn't persist across restarts. + # That said, volumes will be persisted across restarts until they are deleted. + sentry-secrets: + sentry-smtp: + sentry-nginx-cache: + sentry-zookeeper-log: + sentry-kafka-log: + sentry-smtp-log: + sentry-clickhouse-log: diff --git a/tdrs-backend/Pipfile b/tdrs-backend/Pipfile index 6e3775877..a46415b51 100644 --- a/tdrs-backend/Pipfile +++ b/tdrs-backend/Pipfile @@ -39,7 +39,6 @@ django-csp = "==3.7" djangorestframework = "==3.13.1" drf-yasg = "==1.20.0" gunicorn = "==20.1.0" -ipdb = "==0.13.9" jwcrypto = "==1.3.1" markdown = "==3.3.7" psycopg2 = "==2.9.9" @@ -59,6 +58,7 @@ cerberus = "==1.3.4" xlsxwriter = "==3.1.9" openpyxl = "==3.1.2" sendgrid = "==6.10.0" +sentry-sdk = "==2.11.0" [requires] python_version = "3.10.8" diff --git a/tdrs-backend/Pipfile.lock b/tdrs-backend/Pipfile.lock index 2ee644558..1ce6d4773 100644 --- a/tdrs-backend/Pipfile.lock +++ b/tdrs-backend/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "80bf15489b1a4a07f3711904a66fe19188e49eaa58dbd920d20bf4432dcd5518" + "sha256": "3cc4c598cd727b0e161a34560e9efa1e43a3d4d137d6983b2b059947707dee05" }, "pipfile-spec": 6, "requires": { @@ -32,13 +32,6 @@ "markers": "python_version >= '3.8'", "version": "==3.8.1" }, - "asttokens": { - "hashes": [ - "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24", - "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0" - ], - "version": "==2.4.1" - }, "billiard": { "hashes": [ "sha256:299de5a8da28a783d51b197d496bef4f1595dd023a93a4f59dde1886ae905547", @@ -91,76 +84,76 @@ }, "cffi": { "hashes": [ - "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", - "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", - "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1", - "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", - "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", - "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", - "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8", - "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36", - "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", - "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", - "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc", - "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", - "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", - "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", - "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", - "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", - "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", - "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", - "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", - "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b", - "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", - "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", - "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c", - "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", - "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", - "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", - "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8", - "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1", - "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", - "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", - "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", - "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595", - "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0", - "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", - "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", - "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", - "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", - "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", - "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", - "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16", - "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", - "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e", - "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", - "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964", - "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", - "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576", - "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", - "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3", - "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662", - "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", - "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", - "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", - "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", - "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", - "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", - "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", - "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", - "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9", - "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7", - "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", - "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a", - "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", - "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", - "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", - "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", - "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87", - "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b" + "sha256:011aff3524d578a9412c8b3cfaa50f2c0bd78e03eb7af7aa5e0df59b158efb2f", + "sha256:0a048d4f6630113e54bb4b77e315e1ba32a5a31512c31a273807d0027a7e69ab", + "sha256:0bb15e7acf8ab35ca8b24b90af52c8b391690ef5c4aec3d31f38f0d37d2cc499", + "sha256:0d46ee4764b88b91f16661a8befc6bfb24806d885e27436fdc292ed7e6f6d058", + "sha256:0e60821d312f99d3e1569202518dddf10ae547e799d75aef3bca3a2d9e8ee693", + "sha256:0fdacad9e0d9fc23e519efd5ea24a70348305e8d7d85ecbb1a5fa66dc834e7fb", + "sha256:14b9cbc8f7ac98a739558eb86fabc283d4d564dafed50216e7f7ee62d0d25377", + "sha256:17c6d6d3260c7f2d94f657e6872591fe8733872a86ed1345bda872cfc8c74885", + "sha256:1a2ddbac59dc3716bc79f27906c010406155031a1c801410f1bafff17ea304d2", + "sha256:2404f3de742f47cb62d023f0ba7c5a916c9c653d5b368cc966382ae4e57da401", + "sha256:24658baf6224d8f280e827f0a50c46ad819ec8ba380a42448e24459daf809cf4", + "sha256:24aa705a5f5bd3a8bcfa4d123f03413de5d86e497435693b638cbffb7d5d8a1b", + "sha256:2770bb0d5e3cc0e31e7318db06efcbcdb7b31bcb1a70086d3177692a02256f59", + "sha256:331ad15c39c9fe9186ceaf87203a9ecf5ae0ba2538c9e898e3a6967e8ad3db6f", + "sha256:3aa9d43b02a0c681f0bfbc12d476d47b2b2b6a3f9287f11ee42989a268a1833c", + "sha256:41f4915e09218744d8bae14759f983e466ab69b178de38066f7579892ff2a555", + "sha256:4304d4416ff032ed50ad6bb87416d802e67139e31c0bde4628f36a47a3164bfa", + "sha256:435a22d00ec7d7ea533db494da8581b05977f9c37338c80bc86314bec2619424", + "sha256:45f7cd36186db767d803b1473b3c659d57a23b5fa491ad83c6d40f2af58e4dbb", + "sha256:48b389b1fd5144603d61d752afd7167dfd205973a43151ae5045b35793232aa2", + "sha256:4e67d26532bfd8b7f7c05d5a766d6f437b362c1bf203a3a5ce3593a645e870b8", + "sha256:516a405f174fd3b88829eabfe4bb296ac602d6a0f68e0d64d5ac9456194a5b7e", + "sha256:5ba5c243f4004c750836f81606a9fcb7841f8874ad8f3bf204ff5e56332b72b9", + "sha256:5bdc0f1f610d067c70aa3737ed06e2726fd9d6f7bfee4a351f4c40b6831f4e82", + "sha256:6107e445faf057c118d5050560695e46d272e5301feffda3c41849641222a828", + "sha256:6327b572f5770293fc062a7ec04160e89741e8552bf1c358d1a23eba68166759", + "sha256:669b29a9eca6146465cc574659058ed949748f0809a2582d1f1a324eb91054dc", + "sha256:6ce01337d23884b21c03869d2f68c5523d43174d4fc405490eb0091057943118", + "sha256:6d872186c1617d143969defeadac5a904e6e374183e07977eedef9c07c8953bf", + "sha256:6f76a90c345796c01d85e6332e81cab6d70de83b829cf1d9762d0a3da59c7932", + "sha256:70d2aa9fb00cf52034feac4b913181a6e10356019b18ef89bc7c12a283bf5f5a", + "sha256:7cbc78dc018596315d4e7841c8c3a7ae31cc4d638c9b627f87d52e8abaaf2d29", + "sha256:856bf0924d24e7f93b8aee12a3a1095c34085600aa805693fb7f5d1962393206", + "sha256:8a98748ed1a1df4ee1d6f927e151ed6c1a09d5ec21684de879c7ea6aa96f58f2", + "sha256:93a7350f6706b31f457c1457d3a3259ff9071a66f312ae64dc024f049055f72c", + "sha256:964823b2fc77b55355999ade496c54dde161c621cb1f6eac61dc30ed1b63cd4c", + "sha256:a003ac9edc22d99ae1286b0875c460351f4e101f8c9d9d2576e78d7e048f64e0", + "sha256:a0ce71725cacc9ebf839630772b07eeec220cbb5f03be1399e0457a1464f8e1a", + "sha256:a47eef975d2b8b721775a0fa286f50eab535b9d56c70a6e62842134cf7841195", + "sha256:a8b5b9712783415695663bd463990e2f00c6750562e6ad1d28e072a611c5f2a6", + "sha256:a9015f5b8af1bb6837a3fcb0cdf3b874fe3385ff6274e8b7925d81ccaec3c5c9", + "sha256:aec510255ce690d240f7cb23d7114f6b351c733a74c279a84def763660a2c3bc", + "sha256:b00e7bcd71caa0282cbe3c90966f738e2db91e64092a877c3ff7f19a1628fdcb", + "sha256:b50aaac7d05c2c26dfd50c3321199f019ba76bb650e346a6ef3616306eed67b0", + "sha256:b7b6ea9e36d32582cda3465f54c4b454f62f23cb083ebc7a94e2ca6ef011c3a7", + "sha256:bb9333f58fc3a2296fb1d54576138d4cf5d496a2cc118422bd77835e6ae0b9cb", + "sha256:c1c13185b90bbd3f8b5963cd8ce7ad4ff441924c31e23c975cb150e27c2bf67a", + "sha256:c3b8bd3133cd50f6b637bb4322822c94c5ce4bf0d724ed5ae70afce62187c492", + "sha256:c5d97162c196ce54af6700949ddf9409e9833ef1003b4741c2b39ef46f1d9720", + "sha256:c815270206f983309915a6844fe994b2fa47e5d05c4c4cef267c3b30e34dbe42", + "sha256:cab2eba3830bf4f6d91e2d6718e0e1c14a2f5ad1af68a89d24ace0c6b17cced7", + "sha256:d1df34588123fcc88c872f5acb6f74ae59e9d182a2707097f9e28275ec26a12d", + "sha256:d6bdcd415ba87846fd317bee0774e412e8792832e7805938987e4ede1d13046d", + "sha256:db9a30ec064129d605d0f1aedc93e00894b9334ec74ba9c6bdd08147434b33eb", + "sha256:dbc183e7bef690c9abe5ea67b7b60fdbca81aa8da43468287dae7b5c046107d4", + "sha256:dca802c8db0720ce1c49cce1149ff7b06e91ba15fa84b1d59144fef1a1bc7ac2", + "sha256:dec6b307ce928e8e112a6bb9921a1cb00a0e14979bf28b98e084a4b8a742bd9b", + "sha256:df8bb0010fdd0a743b7542589223a2816bdde4d94bb5ad67884348fa2c1c67e8", + "sha256:e4094c7b464cf0a858e75cd14b03509e84789abf7b79f8537e6a72152109c76e", + "sha256:e4760a68cab57bfaa628938e9c2971137e05ce48e762a9cb53b76c9b569f1204", + "sha256:eb09b82377233b902d4c3fbeeb7ad731cdab579c6c6fda1f763cd779139e47c3", + "sha256:eb862356ee9391dc5a0b3cbc00f416b48c1b9a52d252d898e5b7696a5f9fe150", + "sha256:ef9528915df81b8f4c7612b19b8628214c65c9b7f74db2e34a646a0a2a0da2d4", + "sha256:f3157624b7558b914cb039fd1af735e5e8049a87c817cc215109ad1c8779df76", + "sha256:f3e0992f23bbb0be00a921eae5363329253c3b86287db27092461c887b791e5e", + "sha256:f9338cc05451f1942d0d8203ec2c346c830f8e86469903d5126c1f0a13a2bcbb", + "sha256:ffef8fd58a36fb5f1196919638f73dd3ae0db1a878982b27a9a5a176ede4ba91" ], "markers": "python_version >= '3.8'", - "version": "==1.17.1" + "version": "==1.17.0" }, "charset-normalizer": { "hashes": [ @@ -236,14 +229,6 @@ "markers": "python_version >= '3.6'", "version": "==3.4.7" }, - "decorator": { - "hashes": [ - "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330", - "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186" - ], - "markers": "python_version >= '3.7'", - "version": "==5.1.1" - }, "deprecated": { "hashes": [ "sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c", @@ -456,22 +441,6 @@ "markers": "python_version >= '3.6'", "version": "==1.1.0" }, - "exceptiongroup": { - "hashes": [ - "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b", - "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc" - ], - "markers": "python_version < '3.11'", - "version": "==1.2.2" - }, - "executing": { - "hashes": [ - "sha256:8d63781349375b5ebccc3142f4b30350c0cd9c79f921cde38be2be4637e98eaf", - "sha256:8ea27ddd260da8150fa5a708269c4a10e76161e2496ec3e587da9e3c0fe4b9ab" - ], - "markers": "python_version >= '3.8'", - "version": "==2.1.0" - }, "flower": { "hashes": [ "sha256:77be4bece7330893703e8cca3f3baddba356a0019186594a961e3968289da7ec", @@ -513,22 +482,6 @@ "markers": "python_version >= '3.5'", "version": "==0.5.1" }, - "ipdb": { - "hashes": [ - "sha256:951bd9a64731c444fd907a5ce268543020086a697f6be08f7cc2c9a752a278c5" - ], - "index": "pypi", - "markers": "python_version >= '2.7'", - "version": "==0.13.9" - }, - "ipython": { - "hashes": [ - "sha256:0b99a2dc9f15fd68692e898e5568725c6d49c527d36a9fb5960ffbdeaa82ff7e", - "sha256:f68b3cb8bde357a5d7adc9598d57e22a45dfbea19eb6b98286fa3b288c9cd55c" - ], - "markers": "python_version >= '3.7'", - "version": "==8.27.0" - }, "itypes": { "hashes": [ "sha256:03da6872ca89d29aef62773672b2d408f490f80db48b23079a4b194c86dd04c6", @@ -536,14 +489,6 @@ ], "version": "==1.2.0" }, - "jedi": { - "hashes": [ - "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd", - "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0" - ], - "markers": "python_version >= '3.6'", - "version": "==0.19.1" - }, "jinja2": { "hashes": [ "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369", @@ -651,14 +596,6 @@ "markers": "python_version >= '3.7'", "version": "==2.1.5" }, - "matplotlib-inline": { - "hashes": [ - "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90", - "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca" - ], - "markers": "python_version >= '3.8'", - "version": "==0.1.7" - }, "openpyxl": { "hashes": [ "sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184", @@ -676,22 +613,6 @@ "markers": "python_version >= '3.8'", "version": "==24.1" }, - "parso": { - "hashes": [ - "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18", - "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d" - ], - "markers": "python_version >= '3.6'", - "version": "==0.8.4" - }, - "pexpect": { - "hashes": [ - "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523", - "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f" - ], - "markers": "sys_platform != 'win32' and sys_platform != 'emscripten'", - "version": "==4.9.0" - }, "pillow": { "hashes": [ "sha256:02a2be69f9c9b8c1e97cf2713e789d4e398c751ecfd9967c18d0ce304efbf885", @@ -814,20 +735,6 @@ "markers": "python_version >= '3.7'", "version": "==2.9.9" }, - "ptyprocess": { - "hashes": [ - "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35", - "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220" - ], - "version": "==0.7.0" - }, - "pure-eval": { - "hashes": [ - "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0", - "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42" - ], - "version": "==0.2.3" - }, "pycparser": { "hashes": [ "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", @@ -836,14 +743,6 @@ "markers": "python_version >= '3.8'", "version": "==2.22" }, - "pygments": { - "hashes": [ - "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199", - "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a" - ], - "markers": "python_version >= '3.8'", - "version": "==2.18.0" - }, "pyjwt": { "hashes": [ "sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf", @@ -999,13 +898,22 @@ "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", "version": "==6.10.0" }, + "sentry-sdk": { + "hashes": [ + "sha256:4ca16e9f5c7c6bc2fb2d5c956219f4926b148e511fffdbbde711dc94f1e0468f", + "sha256:d964710e2dbe015d9dc4ff0ad16225d68c3b36936b742a6fe0504565b760a3b7" + ], + "index": "pypi", + "markers": "python_version >= '3.6'", + "version": "==2.11.0" + }, "setuptools": { "hashes": [ - "sha256:5f4c08aa4d3ebcb57a50c33b1b07e94315d7fc7230f7115e47fc99776c8ce308", - "sha256:95b40ed940a1c67eb70fc099094bd6e99c6ee7c23aa2306f4d2697ba7916f9c6" + "sha256:2353af060c06388be1cecbf5953dcdb1f38362f87a2356c480b6b4d5fcfc8847", + "sha256:fc91b5f89e392ef5b77fe143b17e32f65d3024744fba66dc3afe07201684d766" ], "markers": "python_version >= '3.8'", - "version": "==74.1.2" + "version": "==74.1.1" }, "six": { "hashes": [ @@ -1023,27 +931,12 @@ "markers": "python_version >= '3.8'", "version": "==0.5.1" }, - "stack-data": { - "hashes": [ - "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9", - "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695" - ], - "version": "==0.6.3" - }, "starkbank-ecdsa": { "hashes": [ "sha256:9399c3371b899d4a235b68a1ed7919d202fbf024bd2c863ae8ebdad343c2a63a" ], "version": "==2.2.0" }, - "toml": { - "hashes": [ - "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b", - "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f" - ], - "markers": "python_version >= '3.7'", - "version": "==0.10.2" - }, "tornado": { "hashes": [ "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8", @@ -1061,14 +954,6 @@ "markers": "python_version >= '3.8'", "version": "==6.4.1" }, - "traitlets": { - "hashes": [ - "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7", - "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f" - ], - "markers": "python_version >= '3.8'", - "version": "==5.14.3" - }, "typing-extensions": { "hashes": [ "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d", @@ -1362,11 +1247,11 @@ }, "faker": { "hashes": [ - "sha256:4294d169255a045990720d6f3fa4134b764a4cdf46ef0d3c7553d2506f1adaa1", - "sha256:e59c01d1e8b8e20a83255ab8232c143cb2af3b4f5ab6a3f5ce495f385ad8ab4c" + "sha256:b17d69312ef6485a720e21bffa997668c88876a5298b278e903ba706243c9c6b", + "sha256:bc460a0e6020966410d0b276043879abca0fac51890f3324bc254bb0a383ee3a" ], "markers": "python_version >= '3.8'", - "version": "==28.4.1" + "version": "==28.1.0" }, "flake8": { "hashes": [ @@ -1782,39 +1667,39 @@ }, "watchdog": { "hashes": [ - "sha256:14dd4ed023d79d1f670aa659f449bcd2733c33a35c8ffd88689d9d243885198b", - "sha256:29e4a2607bd407d9552c502d38b45a05ec26a8e40cc7e94db9bb48f861fa5abc", - "sha256:3960136b2b619510569b90f0cd96408591d6c251a75c97690f4553ca88889769", - "sha256:3e8d5ff39f0a9968952cce548e8e08f849141a4fcc1290b1c17c032ba697b9d7", - "sha256:53ed1bf71fcb8475dd0ef4912ab139c294c87b903724b6f4a8bd98e026862e6d", - "sha256:5597c051587f8757798216f2485e85eac583c3b343e9aa09127a3a6f82c65ee8", - "sha256:638bcca3d5b1885c6ec47be67bf712b00a9ab3d4b22ec0881f4889ad870bc7e8", - "sha256:6bec703ad90b35a848e05e1b40bf0050da7ca28ead7ac4be724ae5ac2653a1a0", - "sha256:726eef8f8c634ac6584f86c9c53353a010d9f311f6c15a034f3800a7a891d941", - "sha256:72990192cb63872c47d5e5fefe230a401b87fd59d257ee577d61c9e5564c62e5", - "sha256:7d1aa7e4bb0f0c65a1a91ba37c10e19dabf7eaaa282c5787e51371f090748f4b", - "sha256:8c47150aa12f775e22efff1eee9f0f6beee542a7aa1a985c271b1997d340184f", - "sha256:901ee48c23f70193d1a7bc2d9ee297df66081dd5f46f0ca011be4f70dec80dab", - "sha256:963f7c4c91e3f51c998eeff1b3fb24a52a8a34da4f956e470f4b068bb47b78ee", - "sha256:9814adb768c23727a27792c77812cf4e2fd9853cd280eafa2bcfa62a99e8bd6e", - "sha256:aa9cd6e24126d4afb3752a3e70fce39f92d0e1a58a236ddf6ee823ff7dba28ee", - "sha256:b6dc8f1d770a8280997e4beae7b9a75a33b268c59e033e72c8a10990097e5fde", - "sha256:b84bff0391ad4abe25c2740c7aec0e3de316fdf7764007f41e248422a7760a7f", - "sha256:ba32efcccfe2c58f4d01115440d1672b4eb26cdd6fc5b5818f1fb41f7c3e1889", - "sha256:bda40c57115684d0216556671875e008279dea2dc00fcd3dde126ac8e0d7a2fb", - "sha256:c4a440f725f3b99133de610bfec93d570b13826f89616377715b9cd60424db6e", - "sha256:d010be060c996db725fbce7e3ef14687cdcc76f4ca0e4339a68cc4532c382a73", - "sha256:d2ab34adc9bf1489452965cdb16a924e97d4452fcf88a50b21859068b50b5c3b", - "sha256:d7594a6d32cda2b49df3fd9abf9b37c8d2f3eab5df45c24056b4a671ac661619", - "sha256:d961f4123bb3c447d9fcdcb67e1530c366f10ab3a0c7d1c0c9943050936d4877", - "sha256:dae7a1879918f6544201d33666909b040a46421054a50e0f773e0d870ed7438d", - "sha256:dcebf7e475001d2cdeb020be630dc5b687e9acdd60d16fea6bb4508e7b94cf76", - "sha256:f627c5bf5759fdd90195b0c0431f99cff4867d212a67b384442c51136a098ed7", - "sha256:f8b2918c19e0d48f5f20df458c84692e2a054f02d9df25e6c3c930063eca64c1", - "sha256:fb223456db6e5f7bd9bbd5cd969f05aae82ae21acc00643b60d81c770abd402b" + "sha256:1e8ca9b7f5f03d2f0556a43db1e9adf1e5af6adf52e0890f781324514b67a612", + "sha256:20a28c8b0b3edf4ea2b27fb3527fc0a348e983f22a4317d316bb561524391932", + "sha256:2b8cd627b76194e725ed6f48d9524b1ad93a51a0dc3bd0225c56023716245091", + "sha256:39e828c4270452b966bc9d814911a3c7e24c62d726d2a3245f5841664ff56b5e", + "sha256:39f0de161a822402f0f00c68b82349a4d71c9814e749148ca2b083a25606dbf9", + "sha256:4eaebff2f938f5325788cef26521891b2d8ecc8e7852aa123a9b458815f93875", + "sha256:5541a8765c4090decb4dba55d3dceb57724748a717ceaba8dc4f213edb0026e0", + "sha256:59ec6111f3750772badae3403ef17263489ed6f27ac01ec50c0244b2afa258fb", + "sha256:664917cd513538728875a42d5654584b533da88cf06680452c98e73b45466968", + "sha256:6bb68d9adb9c45f0dc1c2b12f4fb6eab0463a8f9741e371e4ede6769064e0785", + "sha256:6fbb4dd5ace074a2969825fde10034b35b31efcb6973defb22eb945b1d3acc37", + "sha256:70e30116849f4ec52240eb1fad83d27e525eae179bfe1c09b3bf120163d731b6", + "sha256:72dbdffe4aa0c36c59f4a5190bceeb7fdfdf849ab98a562b3a783a64cc6dacdd", + "sha256:753c6a4c1eea9d3b96cd58159b49103e66cb288216a414ab9ad234ccc7642ec2", + "sha256:763c6f82bb65504b47d4aea268462b2fb662676676356e04787f332a11f03eb0", + "sha256:8ba1472b5fa7c644e49641f70d7ccc567f70b54d776defa5d6f755dc2edc3fbb", + "sha256:9b1b32f89f95162f09aea6e15d9384f6e0490152f10d7ed241f8a85cddc50658", + "sha256:a03a6ccb846ead406a25a0b702d0a6b88fdfa77becaf907cfcfce7737ebbda1f", + "sha256:a1cd7c919940b15f253db8279a579fb81e4e4e434b39b11a1cb7f54fe3fa46a6", + "sha256:a6b8c6c82ada78479a0df568d27d69aa07105aba9301ac66d1ae162645f4ba34", + "sha256:a791dfc050ed24b82f7f100ae794192594fe863a7e9bdafcdfa5c6e405a981e5", + "sha256:b21e6601efe8453514c2fc21aca57fb5413c3d8b157bfe520b05b57b1788a167", + "sha256:b2d56425dfa0c1e6f8a510f21d3d54ef7fe50bbc29638943c2cb1394b7b49156", + "sha256:c4ae0b3e95455fa9d959aa3b253c87845ad454ef188a4bf5a69cab287c131216", + "sha256:c92812a358eabebe92b12b9290d16dc95c8003654658f6b2676c9a2103a73ceb", + "sha256:c93aa24899cb4e8a51492c7ccc420bea45ced502fe9ef2e83f9ab1107e5a13b5", + "sha256:e321f1561adea30e447130882efe451af519646178d04189d6ba91a8cd7d88a5", + "sha256:f0180e84e6493ef7c82e051334e8c9b00ffd89fa9de5e0613d3c267f6ccf2d38", + "sha256:f3006361dba2005552cc8aa49c44d16a10e0a1939bb3286e888a14f722122808", + "sha256:f66df2c152edf5a2fe472bb2f8a5d562165bcf6cf9686cee5d75e524c21ca895" ], "markers": "python_version >= '3.9'", - "version": "==5.0.2" + "version": "==5.0.1" } } } diff --git a/tdrs-backend/tdpservice/email/email_enums.py b/tdrs-backend/tdpservice/email/email_enums.py index 3b7028681..4527b6016 100644 --- a/tdrs-backend/tdpservice/email/email_enums.py +++ b/tdrs-backend/tdpservice/email/email_enums.py @@ -13,4 +13,5 @@ class EmailType(Enum): REQUEST_DENIED = 'request-denied.html' DEACTIVATION_WARNING = 'account-deactivation-warning.html' ACCOUNT_DEACTIVATED = 'account-deactivated.html' + ACCOUNT_DEACTIVATED_ADMIN = 'account-deactivated-admin.html' UPCOMING_SUBMISSION_DEADLINE = 'upcoming-submission-deadline.html' diff --git a/tdrs-backend/tdpservice/email/helpers/account_deactivation_warning.py b/tdrs-backend/tdpservice/email/helpers/account_deactivation_warning.py index 75af0a4ef..9851c155c 100644 --- a/tdrs-backend/tdpservice/email/helpers/account_deactivation_warning.py +++ b/tdrs-backend/tdpservice/email/helpers/account_deactivation_warning.py @@ -3,12 +3,10 @@ from tdpservice.email.email import automated_email from datetime import datetime, timedelta, timezone from django.conf import settings - +from tdpservice.users.models import User def send_deactivation_warning_email(users, days): """Send an email to users that are about to be deactivated.""" - from tdpservice.users.models import User - template_path = EmailType.DEACTIVATION_WARNING.value text_message = f'Your account will be deactivated in {days} days.' subject = f'Account Deactivation Warning: {days} days remaining' diff --git a/tdrs-backend/tdpservice/email/helpers/admin_notifications.py b/tdrs-backend/tdpservice/email/helpers/admin_notifications.py new file mode 100644 index 000000000..594e48710 --- /dev/null +++ b/tdrs-backend/tdpservice/email/helpers/admin_notifications.py @@ -0,0 +1,35 @@ +"""helper functions to administer user accounts.""" + +def email_admin_deactivated_user(user): + """Send an email to OFA Admins when a user is deactivated.""" + from tdpservice.users.models import User + from tdpservice.email.email_enums import EmailType + from tdpservice.email.email import automated_email, log + from tdpservice.email.tasks import get_ofa_admin_user_emails + + recipient_emails = get_ofa_admin_user_emails() + logger_context = { + 'user_id': user.id, + 'object_id': user.id, + 'object_repr': user.username, + 'content_type': User, + } + + template_path = EmailType.ACCOUNT_DEACTIVATED_ADMIN.value + text_message = 'A user account has been deactivated.' + subject = ' TDP User Account Deactivated due to Inactivity' + context = { + 'user': user, + } + + log(f"Preparing email to OFA Admins for deactivated user {user.username}", logger_context=logger_context) + + for recipient_email in recipient_emails: + automated_email( + email_path=template_path, + recipient_email=recipient_email, + subject=subject, + email_context=context, + text_message=text_message, + logger_context=logger_context + ) diff --git a/tdrs-backend/tdpservice/email/tasks.py b/tdrs-backend/tdpservice/email/tasks.py index 089ea4e8d..179eeed86 100644 --- a/tdrs-backend/tdpservice/email/tasks.py +++ b/tdrs-backend/tdpservice/email/tasks.py @@ -16,10 +16,35 @@ from tdpservice.email.email import automated_email, log from tdpservice.email.email_enums import EmailType from tdpservice.parsers.util import calendar_to_fiscal +from tdpservice.email.helpers.admin_notifications import email_admin_deactivated_user logger = logging.getLogger(__name__) +@shared_task +def deactivate_users(): + """Deactivate users that have not logged in in the last 180 days.""" + users_to_deactivate = User.objects.filter( + last_login__lte=datetime.now(tz=timezone.utc) - timedelta(days=180), + account_approval_status=AccountApprovalStatusChoices.APPROVED, + ) + + for user in users_to_deactivate: + user.account_approval_status = AccountApprovalStatusChoices.DEACTIVATED + user.groups.clear() + user.save() + + logger_context = { + 'user_id': user.id, + 'object_id': user.id, + 'object_repr': user.username, + } + email_admin_deactivated_user(user) + log( + f"Deactivated user {user.username} for inactivity.", + logger_context=logger_context if not settings.DEBUG else None + ) + @shared_task def check_for_accounts_needing_deactivation_warning(): diff --git a/tdrs-backend/tdpservice/email/templates/account-deactivated-admin.html b/tdrs-backend/tdpservice/email/templates/account-deactivated-admin.html new file mode 100644 index 000000000..d8b5130fa --- /dev/null +++ b/tdrs-backend/tdpservice/email/templates/account-deactivated-admin.html @@ -0,0 +1,18 @@ +{% extends 'base.html' %} +{% block content %} + +

+ +

The following user account for the TANF Data Portal (TDP) has been deactivated.

+ +

Account Information:

+ + +

Thank you,

+ TDP Team +

+{% endblock %} \ No newline at end of file diff --git a/tdrs-backend/tdpservice/scheduling/test/test_user_deactivation_warning.py b/tdrs-backend/tdpservice/scheduling/test/test_user_deactivation_warning.py index 369688d1a..1f4c2caf7 100644 --- a/tdrs-backend/tdpservice/scheduling/test/test_user_deactivation_warning.py +++ b/tdrs-backend/tdpservice/scheduling/test/test_user_deactivation_warning.py @@ -30,6 +30,22 @@ def test_deactivation_email_10_days(user, mocker): assert tdpservice.email.helpers.account_deactivation_warning.send_deactivation_warning_email.called_once_with( users=[user], days=10) +@pytest.mark.django_db +def test_deactivate_users(user, mocker): + """Test that the deactivate_users task runs.""" + mocker.patch( + 'tdpservice.email.helpers.admin_notifications.email_admin_deactivated_user', + return_value=None + ) + user.groups.add() + user.last_login = datetime.now(tz=timezone.utc) - timedelta(days=181) + user.account_approval_status = AccountApprovalStatusChoices.APPROVED + user.save() + tdpservice.email.tasks.deactivate_users() + assert user.groups.count() == 0 + assert tdpservice.email.helpers.admin_notifications.email_admin_deactivated_user.called_once_with(user) + + @pytest.mark.django_db def test_deactivation_email_3_days(user, mocker): """Test that the check_for_accounts_needing_deactivation_warning task runs.""" diff --git a/tdrs-backend/tdpservice/settings/common.py b/tdrs-backend/tdpservice/settings/common.py index 7a7baad72..89acbe10c 100644 --- a/tdrs-backend/tdpservice/settings/common.py +++ b/tdrs-backend/tdpservice/settings/common.py @@ -475,6 +475,13 @@ class Common(Configuration): 'expires': 15.0, }, }, + 'Deactivate Users': { + 'task': 'tdpservice.email.tasks.deactivate_users', + 'schedule': crontab(day_of_week='*', hour='13', minute='0'), # Every day at 1pm UTC (9am EST) + 'options': { + 'expires': 15.0, + }, + }, 'Email Admin Number of Access Requests' : { 'task': 'tdpservice.email.tasks.email_admin_num_access_requests', 'schedule': crontab(minute='0', hour='1', day_of_week='*', day_of_month='*', month_of_year='*'), # Every day at 1am UTC (9pm EST) diff --git a/tdrs-backend/tdpservice/settings/local.py b/tdrs-backend/tdpservice/settings/local.py index 171608fe5..bffbddd66 100644 --- a/tdrs-backend/tdpservice/settings/local.py +++ b/tdrs-backend/tdpservice/settings/local.py @@ -1,5 +1,8 @@ """Define configuration settings for local environment.""" import os +import logging +import django + from distutils.util import strtobool from .common import Common @@ -43,3 +46,28 @@ class Local(Common): } REDIS_SERVER_LOCAL = bool(strtobool(os.getenv("REDIS_SERVER_LOCAL", "TRUE"))) + + if os.getenv("ENABLE_SENTRY", "no") == "yes": + # SENTRY + import sentry_sdk + from sentry_sdk.integrations.django import DjangoIntegration + from sentry_sdk.integrations.logging import LoggingIntegration + sentry_sdk.init( + dsn="http://43ebf8abe1434ec6aea2c7b92c465a0e@host.docker.internal:9001/2", + # Set traces_sample_rate to 1.0 to capture 100% + # of transactions for performance monitoring. + integrations=[ + DjangoIntegration( + transaction_style='url', + middleware_spans=True, + signals_spans=True, + signals_denylist=[ + django.db.models.signals.pre_init, + django.db.models.signals.post_init, + ], + cache_spans=False, + ), + LoggingIntegration(level=logging.DEBUG, event_level=logging.DEBUG) + ], + traces_sample_rate=1.0, + ) diff --git a/tdrs-backend/tdpservice/users/migrations/0041_users_digit_group_add_datafile_permission.py b/tdrs-backend/tdpservice/users/migrations/0041_users_digit_group_add_datafile_permission.py new file mode 100644 index 000000000..67dbd70ab --- /dev/null +++ b/tdrs-backend/tdpservice/users/migrations/0041_users_digit_group_add_datafile_permission.py @@ -0,0 +1,58 @@ +# Generated by Django 3.2.5 on 2021-08-16 14:10 +from django.contrib.auth.models import Group +from django.db import migrations + +from tdpservice.users.permissions import ( + add_permissions_q, + get_permission_ids_for_model, + view_permissions_q +) + + +def set_digit_team_permissions(apps, schema_editor): + """Set relevant Group Permissions for DIGIT Team group.""" + digit = ( + apps.get_model('auth', 'Group').objects.get(name='DIGIT Team') + ) + + stt_permissions = get_permission_ids_for_model( + 'stts', + 'stt', + filters=[view_permissions_q] + ) + + + datafile_permissions = get_permission_ids_for_model( + 'data_files', + 'datafile', + filters=[view_permissions_q, add_permissions_q] + ) + + # Assign model permissions + digit.permissions.add(*datafile_permissions, *stt_permissions) + +def unset_digit_team_permissions(apps, schema_editor): + """Remove all Group Permissions added to DIGIT Team.""" + digit = ( + apps.get_model('auth', 'Group').objects.get(name='DIGIT Team') + ) + datafile_permissions = get_permission_ids_for_model( + 'data_files', + 'datafile', + filters=[view_permissions_q, add_permissions_q] + ) + digit.permissions.remove(*datafile_permissions) + +class Migration(migrations.Migration): + + dependencies = [ + ('auth', '__latest__'), + ('users', '0040_users_digit_group_permissions'), + ] + + operations = [ + migrations.RunPython( + set_digit_team_permissions, + reverse_code=unset_digit_team_permissions + ) + ] diff --git a/tdrs-backend/tdpservice/users/test/test_permissions.py b/tdrs-backend/tdpservice/users/test/test_permissions.py index 608305131..ae53b3cda 100644 --- a/tdrs-backend/tdpservice/users/test/test_permissions.py +++ b/tdrs-backend/tdpservice/users/test/test_permissions.py @@ -180,6 +180,8 @@ def test_digit_team_permissions(digit_team): expected_permissions = {'parsers.view_parsererror', 'parsers.view_datafilesummary', 'data_files.view_datafile', + 'data_files.add_datafile', + 'stts.view_stt', 'search_indexes.view_ssp_m3', 'search_indexes.view_tribal_tanf_t5', 'search_indexes.view_tribal_tanf_t3', @@ -200,7 +202,7 @@ def test_digit_team_permissions(digit_team): 'search_indexes.view_tanf_t4', 'search_indexes.view_ssp_m6', 'search_indexes.view_tribal_tanf_t2', - 'search_indexes.view_tanf_t6' + 'search_indexes.view_tanf_t6', } group_permissions = digit_team.get_group_permissions() assert group_permissions == expected_permissions diff --git a/tdrs-frontend/src/components/Reports/Reports.jsx b/tdrs-frontend/src/components/Reports/Reports.jsx index 1f00df2c2..82e161e37 100644 --- a/tdrs-frontend/src/components/Reports/Reports.jsx +++ b/tdrs-frontend/src/components/Reports/Reports.jsx @@ -38,6 +38,9 @@ function Reports() { // The logged in user saved in our redux `auth` state object const user = useSelector((state) => state.auth.user) const isOFAAdmin = useSelector(selectPrimaryUserRole)?.name === 'OFA Admin' + const isDIGITTeam = useSelector(selectPrimaryUserRole)?.name === 'DIGIT Team' + const isSystemAdmin = + useSelector(selectPrimaryUserRole)?.name === 'OFA System Admin' const sttList = useSelector((state) => state?.stts?.sttList) const [errorModalVisible, setErrorModalVisible] = useState(false) @@ -59,7 +62,8 @@ function Reports() { Q4: 'Quarter 4 (July - September)', } - const currentStt = isOFAAdmin ? selectedStt : userProfileStt + const currentStt = + isOFAAdmin || isDIGITTeam || isSystemAdmin ? selectedStt : userProfileStt const stt = sttList?.find((stt) => stt?.name === currentStt) @@ -68,7 +72,8 @@ function Reports() { const errorsCount = formValidation.errors - const missingStt = !isOFAAdmin && !currentStt + const missingStt = + !isOFAAdmin && !isDIGITTeam && !isSystemAdmin && !currentStt const errorsRef = useRef(null) @@ -194,7 +199,7 @@ function Reports() { ) const touchedFields = Object.keys(touched).length - const expected_fields = isOFAAdmin ? 3 : 2 + const expected_fields = isOFAAdmin || isDIGITTeam || isSystemAdmin ? 3 : 2 const errors = touchedFields === 3 ? expected_fields - form.length : 0 @@ -215,6 +220,8 @@ function Reports() { setFormValidationState, touched, isOFAAdmin, + isDIGITTeam, + isSystemAdmin, ]) return ( @@ -237,7 +244,7 @@ function Reports() { )}
- {isOFAAdmin && ( + {(isOFAAdmin || isDIGITTeam || isSystemAdmin) && (