Merge branch 'notify-api-869' into aanand-sqlalchemy-version-update

This commit is contained in:
Aditi Anand
2024-04-24 16:11:03 -04:00
298 changed files with 1544 additions and 1152 deletions
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
run: exit 0
- name: checkout main branch
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: main
ssh-key: ${{ secrets.SSH_PRIVATE_KEY }}
+6 -6
View File
@@ -36,7 +36,7 @@ jobs:
- 5432:5432
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Install application dependencies
run: make bootstrap
@@ -68,7 +68,7 @@ jobs:
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Install poetry packages
run: poetry install
@@ -82,18 +82,18 @@ jobs:
pip-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
- uses: pypa/gh-action-pip-audit@v1.0.6
- uses: pypa/gh-action-pip-audit@v1.0.8
with:
inputs: requirements.txt
static-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Install bandit
run: pip install bandit
@@ -118,7 +118,7 @@ jobs:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Install application dependencies
run: make bootstrap
+3 -3
View File
@@ -23,7 +23,7 @@ jobs:
pip-audit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Create requirements.txt
run: poetry export --without-hashes --format=requirements.txt > requirements.txt
@@ -39,7 +39,7 @@ jobs:
static-scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Install bandit
run: pip install bandit
@@ -69,7 +69,7 @@ jobs:
# Maps tcp port 5432 on service container to the host
- 5432:5432
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- uses: ./.github/actions/setup-project
- name: Install application dependencies
run: make bootstrap
+12 -2
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
environment: demo
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 2
@@ -57,7 +57,7 @@ jobs:
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
LOGIN_DOT_GOV_REGISTRATION_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/set-up-your-profile&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop"
LOGIN_DOT_GOV_REGISTRATION_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://notify-demo.app.cloud.gov/set-up-your-profile&response_type=code&scope=openid+email&state=STATE"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
@@ -74,6 +74,16 @@ jobs:
--var NOTIFY_E2E_TEST_PASSWORD="$NOTIFY_E2E_TEST_PASSWORD"
--var LOGIN_DOT_GOV_REGISTRATION_URL="$LOGIN_DOT_GOV_REGISTRATION_URL"
- name: Check for changes to templates.json
id: changed-templates
uses: tj-actions/changed-files@v41
with:
files: |
app/config_files/templates.json
- name: Update templates
if: steps.changed-templates.outputs.any_changed == 'true'
run: cf run-task notify-api-demo --command "flask command update-templates"
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v41
+12 -2
View File
@@ -16,7 +16,7 @@ jobs:
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 2
@@ -61,7 +61,7 @@ jobs:
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
LOGIN_DOT_GOV_REGISTRATION_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://beta.notify.gov/set-up-your-profile&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop"
LOGIN_DOT_GOV_REGISTRATION_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://beta.notify.gov/set-up-your-profile&response_type=code&scope=openid+email&state=STATE"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
@@ -78,6 +78,16 @@ jobs:
--var NOTIFY_E2E_TEST_PASSWORD="$NOTIFY_E2E_TEST_PASSWORD"
--var LOGIN_DOT_GOV_REGISTRATION_URL="$LOGIN_DOT_GOV_REGISTRATION_URL"
- name: Check for changes to templates.json
id: changed-templates
uses: tj-actions/changed-files@v41
with:
files: |
app/config_files/templates.json
- name: Update templates
if: steps.changed-templates.outputs.any_changed == 'true'
run: cf run-task notify-api-production --command "flask command update-templates"
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v41
+12 -2
View File
@@ -17,7 +17,7 @@ jobs:
environment: staging
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 2
@@ -62,7 +62,7 @@ jobs:
NEW_RELIC_LICENSE_KEY: ${{ secrets.NEW_RELIC_LICENSE_KEY }}
NOTIFY_E2E_TEST_EMAIL: ${{ secrets.NOTIFY_E2E_TEST_EMAIL }}
NOTIFY_E2E_TEST_PASSWORD: ${{ secrets.NOTIFY_E2E_TEST_PASSWORD }}
LOGIN_DOT_GOV_REGISTRATION_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=01234567890123456789012345&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/set-up-your-profile&response_type=code&scope=openid+email&state=abcdefghijklmnopabcdefghijklmnop"
LOGIN_DOT_GOV_REGISTRATION_URL: "https://secure.login.gov/openid_connect/authorize?acr_values=http%3A%2F%2Fidmanagement.gov%2Fns%2Fassurance%2Fial%2F1&client_id=urn:gov:gsa:openidconnect.profiles:sp:sso:gsa:notify-gov&nonce=NONCE&prompt=select_account&redirect_uri=https://notify-staging.app.cloud.gov/set-up-your-profile&response_type=code&scope=openid+email&state=STATE"
with:
cf_username: ${{ secrets.CLOUDGOV_USERNAME }}
@@ -79,6 +79,16 @@ jobs:
--var NOTIFY_E2E_TEST_PASSWORD="$NOTIFY_E2E_TEST_PASSWORD"
--var LOGIN_DOT_GOV_REGISTRATION_URL="$LOGIN_DOT_GOV_REGISTRATION_URL"
- name: Check for changes to templates.json
id: changed-templates
uses: tj-actions/changed-files@v41
with:
files: |
app/config_files/templates.json
- name: Update templates
if: steps.changed-templates.outputs.any_changed == 'true'
run: cf run-task notify-api-staging --command "flask command update-templates"
- name: Check for changes to egress config
id: changed-egress-config
uses: tj-actions/changed-files@v41
+3 -3
View File
@@ -13,7 +13,7 @@ jobs:
environment: staging
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Check for drift
uses: dflook/terraform-check@v1
@@ -31,7 +31,7 @@ jobs:
environment: demo
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: 'production'
@@ -51,7 +51,7 @@ jobs:
environment: production
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: 'production'
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
environment: demo
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Terraform format
id: format
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
environment: production
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Terraform format
id: format
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
environment: staging
steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Terraform format
id: format
+2
View File
@@ -14,9 +14,11 @@ bootstrap: ## Set up everything to run the app
make generate-version-file
poetry self update
poetry self add poetry-dotenv-plugin
poetry lock --no-update
poetry install --sync --no-root
poetry run pre-commit install
createdb notification_api || true
createdb test_notification_api || true
(poetry run flask db upgrade) || true
.PHONY: bootstrap-with-docker
+3 -3
View File
@@ -359,9 +359,9 @@ def setup_sqlalchemy_events(app):
connection_record.info["request_data"] = {
"method": request.method,
"host": request.host,
"url_rule": request.url_rule.rule
if request.url_rule
else "No endpoint",
"url_rule": (
request.url_rule.rule if request.url_rule else "No endpoint"
),
}
# celery apps
elif current_task:
+6 -6
View File
@@ -214,12 +214,12 @@ def handle_complaint(ses_message):
complaint = Complaint(
notification_id=notification.id,
service_id=notification.service_id,
ses_feedback_id=ses_complaint.get("feedbackId", None)
if ses_complaint
else None,
complaint_type=ses_complaint.get("complaintFeedbackType", None)
if ses_complaint
else None,
ses_feedback_id=(
ses_complaint.get("feedbackId", None) if ses_complaint else None
),
complaint_type=(
ses_complaint.get("complaintFeedbackType", None) if ses_complaint else None
),
complaint_date=ses_complaint.get("timestamp", None) if ses_complaint else None,
)
save_complaint(complaint)
+2 -83
View File
@@ -1,4 +1,3 @@
import os
from datetime import datetime, timedelta
from flask import current_app
@@ -6,7 +5,7 @@ from notifications_utils.clients.zendesk.zendesk_client import NotifySupportTick
from sqlalchemy import between
from sqlalchemy.exc import SQLAlchemyError
from app import notify_celery, redis_store, zendesk_client
from app import notify_celery, zendesk_client
from app.celery.tasks import (
get_recipient_csv_and_template_and_sender_id,
process_incomplete_jobs,
@@ -24,16 +23,12 @@ from app.dao.jobs_dao import (
find_jobs_with_missing_rows,
find_missing_row_for_job,
)
from app.dao.notifications_dao import (
dao_get_failed_notification_count,
notifications_not_yet_sent,
)
from app.dao.notifications_dao import notifications_not_yet_sent
from app.dao.services_dao import (
dao_find_services_sending_to_tv_numbers,
dao_find_services_with_high_failure_rates,
)
from app.dao.users_dao import delete_codes_older_created_more_than_a_day_ago
from app.delivery.send_to_providers import provider_to_use
from app.enums import JobStatus, NotificationType
from app.models import Job
from app.notifications.process_notifications import send_notification_to_queue
@@ -92,82 +87,6 @@ def expire_or_delete_invitations():
raise
# TODO THIS IS ACTUALLY DEPRECATED, WE ARE REMOVING PHONE NUMBERS FROM THE DB
# SO THERE WILL BE NO REASON TO KEEP TRACK OF THIS COUNT
@notify_celery.task(name="check-db-notification-fails")
def check_db_notification_fails():
"""
We are going to use redis to keep track of the previous fail count.
If the number of fails is more than 100% of the limit, we want to send an alert every time this
runs, because it is urgent to fix it.
If the number is more than 25%, 50% or 75% of the limit, we only want to send an alert
on a breach. I.e., if the last number was at 23% and the current number is 27%, send an email.
But if the last number was 26% and the current is 27%, don't.
"""
last_value = redis_store.get("LAST_DB_NOTIFICATION_COUNT")
if not last_value:
last_value = 0
else:
last_value = int(last_value.decode("utf-8"))
failed_count = dao_get_failed_notification_count()
if failed_count > last_value:
redis_store.set("LAST_DB_NOTIFICATION_COUNT", failed_count)
message = ""
curr_env = os.getenv("ENVIRONMENT")
if failed_count >= MAX_NOTIFICATION_FAILS:
message = f"We are over 100% in the db for failed notifications on {curr_env}"
elif (
failed_count >= MAX_NOTIFICATION_FAILS * 0.9
and last_value < MAX_NOTIFICATION_FAILS * 0.9
):
message = (
"tts-notify-alerts@gsa.gov",
f"We crossed above 90% in the db for failed notifications on {curr_env}",
)
elif (
failed_count >= MAX_NOTIFICATION_FAILS * 0.75
and last_value < MAX_NOTIFICATION_FAILS * 0.75
):
message = (
"tts-notify-alerts@gsa.gov",
f"We crossed above 75% in the db for failed notifications on {curr_env}",
)
elif (
failed_count >= MAX_NOTIFICATION_FAILS * 0.5
and last_value < MAX_NOTIFICATION_FAILS * 0.5
):
message = (
"tts-notify-alerts@gsa.gov",
f"We crossed above 50% in the db for failed notifications on {curr_env}",
)
elif (
failed_count >= MAX_NOTIFICATION_FAILS * 0.25
and last_value < MAX_NOTIFICATION_FAILS * 0.25
):
message = (
"tts-notify-alerts@gsa.gov",
f"We crossed above 25% in the db for failed notifications on {curr_env}",
)
# suppress any spam coming from development tier
if message and curr_env != "development":
provider = provider_to_use(NotificationType.EMAIL, False)
from_address = '"{}" <{}@{}>'.format(
"Failed Notification Count Alert",
"test_sender",
current_app.config["NOTIFY_EMAIL_DOMAIN"],
)
provider.send_email(
from_address,
"tts-notify-alerts@gsa.gov",
"DB Notification Failures Level Breached",
body=str(message),
)
@notify_celery.task(name="check-job-status")
def check_job_status():
"""
+10 -6
View File
@@ -120,12 +120,16 @@ def create_delivery_status_callback_data(notification, service_callback_api):
"notification_status": notification.status,
"notification_provider_response": notification.provider_response, # TODO do we test for provider_response?
"notification_created_at": notification.created_at.strftime(DATETIME_FORMAT),
"notification_updated_at": notification.updated_at.strftime(DATETIME_FORMAT)
if notification.updated_at
else None,
"notification_sent_at": notification.sent_at.strftime(DATETIME_FORMAT)
if notification.sent_at
else None,
"notification_updated_at": (
notification.updated_at.strftime(DATETIME_FORMAT)
if notification.updated_at
else None
),
"notification_sent_at": (
notification.sent_at.strftime(DATETIME_FORMAT)
if notification.sent_at
else None
),
"notification_type": notification.notification_type,
"service_callback_api_url": service_callback_api.url,
"service_callback_api_bearer_token": service_callback_api.bearer_token,
+17 -3
View File
@@ -18,7 +18,7 @@ from sqlalchemy import and_, text
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm.exc import NoResultFound
from app import db
from app import db, redis_store
from app.aws import s3
from app.celery.nightly_tasks import cleanup_unfinished_jobs
from app.celery.tasks import process_row
@@ -723,8 +723,8 @@ def validate_mobile(ctx, param, value): # noqa
@click.option("-s", "--state", default="active")
@click.option("-d", "--admin", default=False, type=bool)
def create_test_user(name, email, mobile_number, password, auth_type, state, admin):
if getenv("NOTIFY_ENVIRONMENT", "") not in ["development", "test"]:
current_app.logger.error("Can only be run in development")
if getenv("NOTIFY_ENVIRONMENT", "") not in ["development", "test", "staging"]:
current_app.logger.error("Can only be run in development, test, staging")
return
data = {
@@ -801,6 +801,20 @@ def update_templates():
data = json.load(f)
for d in data:
_update_template(d["id"], d["name"], d["type"], d["content"], d["subject"])
_clear_templates_from_cache()
def _clear_templates_from_cache():
# When we update-templates in the db, we need to make sure to delete them
# from redis, otherwise the old versions will stick around forever.
CACHE_KEYS = [
"service-????????-????-????-????-????????????-templates",
"service-????????-????-????-????-????????????-template-????????-????-????-????-????????????-version-*", # noqa
"service-????????-????-????-????-????????????-template-????????-????-????-????-????????????-versions", # noqa
]
num_deleted = sum(redis_store.delete_by_pattern(pattern) for pattern in CACHE_KEYS)
current_app.logger.info(f"Number of templates deleted from cache {num_deleted}")
@notify_command(name="create-new-service")
-12
View File
@@ -199,11 +199,6 @@ class Config(object):
"schedule": timedelta(minutes=66),
"options": {"queue": QueueNames.PERIODIC},
},
"check-db-notification-fails": {
"task": "check-db-notification-fails",
"schedule": crontab(minute="18, 48"),
"options": {"queue": QueueNames.PERIODIC},
},
"check-job-status": {
"task": "check-job-status",
"schedule": crontab(),
@@ -294,11 +289,6 @@ class Config(object):
HIGH_VOLUME_SERVICE = json.loads(getenv("HIGH_VOLUME_SERVICE", "[]"))
TEMPLATE_PREVIEW_API_HOST = getenv(
"TEMPLATE_PREVIEW_API_HOST", "http://localhost:6013"
)
TEMPLATE_PREVIEW_API_KEY = getenv("TEMPLATE_PREVIEW_API_KEY", "my-secret-key")
DOCUMENT_DOWNLOAD_API_HOST = getenv(
"DOCUMENT_DOWNLOAD_API_HOST", "http://localhost:7000"
)
@@ -356,8 +346,6 @@ class Test(Development):
"broker_url": "you-forgot-to-mock-celery-in-your-tests://",
}
TEMPLATE_PREVIEW_API_HOST = "http://localhost:9999"
class Production(Config):
# buckets
+2 -1
View File
@@ -23,6 +23,7 @@
"Click this link to create an account on Notify.gov:",
"",
"[Join Service](((url)))",
"If youre new to Notify.gov you will first be directed to Login.gov create an account with us.",
"",
"",
"This invitation will stop working at midnight tomorrow. This is to keep ((service_name)) secure."
@@ -33,7 +34,7 @@
"name": "Notify SMS verify code",
"type": "sms",
"subject": "",
"content": ["((verify_code)) is your Notify.gov authentication code"]
"content": ["((verify_code)) is your Notify.gov authentication code."]
},
{
"id": "474e9242-823b-4f99-813d-ed392e7f1201",
+1
View File
@@ -14,6 +14,7 @@ Lastly when to create a version is done manually in dao_utils version decorator
session events.
"""
import datetime
from sqlalchemy import Column, ForeignKeyConstraint, Integer, Table, util
+8 -8
View File
@@ -90,6 +90,14 @@ def get_all_notifications_for_service_job(service_id, job_id):
notification.to = recipient
notification.normalised_to = recipient
for notification in paginated_notifications.items:
if notification.job_id is not None:
notification.personalisation = get_personalisation_from_s3(
notification.service_id,
notification.job_id,
notification.job_row_number,
)
notifications = None
if data.get("format_for_csv"):
notifications = [
@@ -101,14 +109,6 @@ def get_all_notifications_for_service_job(service_id, job_id):
paginated_notifications.items, many=True
)
for notification in paginated_notifications.items:
if notification.job_id is not None:
notification.personalisation = get_personalisation_from_s3(
notification.service_id,
notification.job_id,
notification.job_row_number,
)
return (
jsonify(
notifications=notifications,
+15 -15
View File
@@ -772,9 +772,9 @@ class ServiceSmsSender(db.Model):
"service_id": str(self.service_id),
"is_default": self.is_default,
"archived": self.archived,
"inbound_number_id": str(self.inbound_number_id)
if self.inbound_number_id
else None,
"inbound_number_id": (
str(self.inbound_number_id) if self.inbound_number_id else None
),
"created_at": self.created_at.strftime(DATETIME_FORMAT),
"updated_at": get_dt_string_or_none(self.updated_at),
}
@@ -1184,9 +1184,9 @@ class TemplateBase(db.Model):
"created_by": self.created_by.email_address,
"version": self.version,
"body": self.content,
"subject": self.subject
if self.template_type == TemplateType.EMAIL
else None,
"subject": (
self.subject if self.template_type == TemplateType.EMAIL else None
),
"name": self.name,
"personalisation": {
key: {
@@ -1690,9 +1690,9 @@ class Notification(db.Model):
def serialize_for_csv(self):
serialized = {
"row_number": ""
if self.job_row_number is None
else self.job_row_number + 1,
"row_number": (
"" if self.job_row_number is None else self.job_row_number + 1
),
"recipient": self.to,
"client_reference": self.client_reference or "",
"template_name": self.template.name,
@@ -1718,12 +1718,12 @@ class Notification(db.Model):
serialized = {
"id": self.id,
"reference": self.client_reference,
"email_address": self.to
if self.notification_type == NotificationType.EMAIL
else None,
"phone_number": self.to
if self.notification_type == NotificationType.SMS
else None,
"email_address": (
self.to if self.notification_type == NotificationType.EMAIL else None
),
"phone_number": (
self.to if self.notification_type == NotificationType.SMS else None
),
"line_1": None,
"line_2": None,
"line_3": None,
+10 -8
View File
@@ -28,7 +28,6 @@ from app.organization.organization_schema import (
post_update_invited_org_user_status_schema,
)
from app.schema_validation import validate
from app.utils import hilite
organization_invite_blueprint = Blueprint("organization_invite", __name__)
@@ -53,6 +52,15 @@ def invite_user_to_org(organization_id):
current_app.config["ORGANIZATION_INVITATION_EMAIL_TEMPLATE_ID"]
)
token = generate_token(
str(invited_org_user.email_address),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
url = os.environ["LOGIN_DOT_GOV_REGISTRATION_URL"]
url = url.replace("NONCE", token)
url = url.replace("STATE", token)
personalisation = {
"user_name": (
"The Notify.gov team"
@@ -60,7 +68,7 @@ def invite_user_to_org(organization_id):
else invited_org_user.invited_by.name
),
"organization_name": invited_org_user.organization.name,
"url": os.environ["LOGIN_DOT_GOV_REGISTRATION_URL"],
"url": url,
}
saved_notification = persist_notification(
template_id=template.id,
@@ -89,12 +97,6 @@ def invite_user_to_org(organization_id):
organization_id,
ex=3600 * 24,
)
current_app.logger.info(
hilite(f"STORING THIS ORGANIZATION ID IN REDIS {redis_store.get(redis_key)}")
)
current_app.logger.info(
hilite(f"URL: {os.environ['LOGIN_DOT_GOV_REGISTRATION_URL']}")
)
send_notification_to_queue(saved_notification, queue=QueueNames.NOTIFY)
return jsonify(data=invited_org_user.serialize()), 201
+6 -6
View File
@@ -180,12 +180,12 @@ def volumes_by_service_report():
{
"service_name": row.service_name,
"service_id": str(row.service_id),
"organization_name": row.organization_name
if row.organization_name
else "",
"organization_id": str(row.organization_id)
if row.organization_id
else "",
"organization_name": (
row.organization_name if row.organization_name else ""
),
"organization_id": (
str(row.organization_id) if row.organization_id else ""
),
"free_allowance": int(row.free_allowance),
"sms_notifications": int(row.sms_notifications),
"sms_chargeable_units": int(row.sms_chargeable_units),
+18 -10
View File
@@ -102,7 +102,7 @@ from app.service.service_senders_schema import (
)
from app.service.utils import get_guest_list_objects
from app.user.users_schema import post_set_permissions_schema
from app.utils import get_prev_next_pagination_links
from app.utils import get_prev_next_pagination_links, hilite
service_blueprint = Blueprint("service", __name__)
@@ -314,7 +314,9 @@ def get_users_for_service(service_id):
def add_user_to_service(service_id, user_id):
service = dao_fetch_service_by_id(service_id)
user = get_user_by_id(user_id=user_id)
# TODO REMOVE DEBUG
print(hilite(f"GOING TO ADD {user.name} to service {service.name}"))
# END DEBUG
if user in service.users:
error = "User id: {} already part of service id: {}".format(user_id, service_id)
raise InvalidRequest(error, status_code=400)
@@ -329,6 +331,10 @@ def add_user_to_service(service_id, user_id):
folder_permissions = data.get("folder_permissions", [])
dao_add_user_to_service(service, user, permissions, folder_permissions)
# TODO REMOVE DEBUG
print(hilite(f"ADDED {user.name} to service {service.name}"))
# END DEBUG
data = service_schema.dump(service)
return jsonify(data=data), 201
@@ -479,14 +485,16 @@ def get_all_notifications_for_service(service_id):
jsonify(
notifications=notifications,
page_size=page_size,
links=get_prev_next_pagination_links(
page,
len(next_page_of_pagination.items),
".get_all_notifications_for_service",
**kwargs,
)
if count_pages
else {},
links=(
get_prev_next_pagination_links(
page,
len(next_page_of_pagination.items),
".get_all_notifications_for_service",
**kwargs,
)
if count_pages
else {}
),
),
200,
)
+5 -3
View File
@@ -28,9 +28,11 @@ def send_notification_to_service_users(
notification = persist_notification(
template_id=template.id,
template_version=template.version,
recipient=user.email_address
if template.template_type == TemplateType.EMAIL
else user.mobile_number,
recipient=(
user.email_address
if template.template_type == TemplateType.EMAIL
else user.mobile_number
),
service=notify_service,
personalisation=personalisation,
notification_type=template.template_type,
+23 -6
View File
@@ -33,15 +33,29 @@ register_errors(service_invite)
def _create_service_invite(invited_user, invite_link_host):
# TODO REMOVE DEBUG
print(hilite("ENTER _create_service_invite"))
# END DEBUG
template_id = current_app.config["INVITATION_EMAIL_TEMPLATE_ID"]
template = dao_get_template_by_id(template_id)
service = Service.query.get(current_app.config["NOTIFY_SERVICE_ID"])
token = generate_token(
str(invited_user.email_address),
current_app.config["SECRET_KEY"],
current_app.config["DANGEROUS_SALT"],
)
url = os.environ["LOGIN_DOT_GOV_REGISTRATION_URL"]
url = url.replace("NONCE", token)
url = url.replace("STATE", token)
personalisation = {
"user_name": invited_user.from_user.name,
"service_name": invited_user.service.name,
"url": os.environ["LOGIN_DOT_GOV_REGISTRATION_URL"],
"url": url,
}
saved_notification = persist_notification(
@@ -76,14 +90,17 @@ def _create_service_invite(invited_user, invite_link_host):
# This is for the login.gov service invite on the
# "Set Up Your Profile" path.
redis_store.set(
f"service-invite-{invited_user.email_address}",
redis_key = f"service-invite-{invited_user.email_address}"
redis_store.raw_set(
redis_key,
json.dumps(data),
ex=3600 * 24,
)
current_app.logger.info(
hilite(f"STORING ALL THIS IN REDIS FOR SERVICE INVITE {json.dumps(data)}")
)
# TODO REMOVE DEBUG
print(hilite(f"Save this data {data} with this redis_key {redis_key}"))
did_we_save_it = redis_store.raw_get(redis_key)
print(hilite(f"Did we save the data successfully? {did_we_save_it}"))
# END DEBUG
send_notification_to_queue(saved_notification, queue=QueueNames.NOTIFY)
+5 -3
View File
@@ -59,7 +59,9 @@ def get_last_used_datetime_for_template(service_id, template_id):
)
return jsonify(
last_date_used=last_date_used.strftime(DATETIME_FORMAT)
if last_date_used
else last_date_used
last_date_used=(
last_date_used.strftime(DATETIME_FORMAT)
if last_date_used
else last_date_used
)
)
+5 -3
View File
@@ -38,9 +38,11 @@ def get_paginated_uploads(service_id, limit_days, page):
"id": upload.id,
"original_file_name": upload.original_file_name,
"notification_count": upload.notification_count,
"created_at": upload.scheduled_for.strftime("%Y-%m-%d %H:%M:%S")
if upload.scheduled_for
else upload.created_at.strftime("%Y-%m-%d %H:%M:%S"),
"created_at": (
upload.scheduled_for.strftime("%Y-%m-%d %H:%M:%S")
if upload.scheduled_for
else upload.created_at.strftime("%Y-%m-%d %H:%M:%S")
),
"upload_type": upload.upload_type,
"template_type": upload.template_type,
"recipient": upload.recipient,
+5 -3
View File
@@ -212,9 +212,11 @@ def save_email_or_sms_to_queue(
"id": notification_id,
"template_id": str(template.id),
"template_version": template.version,
"to": form["email_address"]
if notification_type == NotificationType.EMAIL
else form["phone_number"],
"to": (
form["email_address"]
if notification_type == NotificationType.EMAIL
else form["phone_number"]
),
"service_id": str(service_id),
"personalisation": personalisation,
"notification_type": notification_type,
+13
View File
@@ -254,6 +254,9 @@ We do not maintain any hooks in this repository.
# install dependencies, etc.
make bootstrap
# Create test database
createdb test_notification_api
make test
```
@@ -528,6 +531,16 @@ cf run-task CLOUD-GOV-APP --command "flask command update-templates" --name YOUR
[Here's more documentation](https://docs.cloudfoundry.org/devguide/using-tasks.html) about Cloud Foundry tasks.
# Commonly run commands
(Note: to obtain the CLOUD_GOV_APP name, run `cf apps` and find the name of the app for the tier you are targeting)
To promote a user to platform admin:
cf run-task <CLOUD_GOV_APP from cf apps see above> --command "flask command promote-user-to-platform-admin --user-email-address=<user email address>"
To update templates:
cf run-task <CLOUD_GOV_APP from cf apps see above> --command "flask command update-templates"
# Commands for test loading the local dev database
All commands use the `-g` or `--generate` to determine how many instances to load to the db. The `-g` or `--generate` option is required and will always defult to 1. An example: `flask command add-test-uses-to-db -g 6` will generate 6 random users and insert them into the db.
@@ -5,6 +5,7 @@ Revises: 0086_add_norm_to_notification
Create Date: 2017-05-15 12:50:20.041950
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0092_add_inbound_provider
Create Date: 2017-06-06 14:37:30.051647
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0097_notnull_inbound_provider
Create Date: 2017-06-13 15:02:33.609656
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0108_change_logo_not_nullable
Create Date: 2017-07-10 14:25:15.712055
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0111_drop_old_service_flags
Create Date: 2017-07-12 13:35:45.636618
"""
from datetime import datetime
import sqlalchemy as sa
@@ -5,6 +5,7 @@ Revises: 0113_job_created_by_nullable
Create Date: 2017-07-27 13:36:37.304344
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0118_service_sms_senders
Create Date: 2017-09-07 15:29:49.087143
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0119_add_email_reply_to
Create Date: 2017-09-18 14:18:49.087143
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0120_add_org_banner_branding
Create Date: 2017-09-20 11:00:20.415523
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0121_nullable_logos
Create Date: 2017-09-21 12:16:02.975120
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0122_add_service_letter_contact
Create Date: 2017-09-27 09:42:39.412731
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0123_add_noti_to_email_reply
Create Date: 2017-10-10 11:30:16.225980
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0124_add_free_sms_fragment_limit
Create Date: 2017-10-05 14:03:00.248005
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0125_add_organisation_type
Create Date: 2017-10-19 11:38:32.849573
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0126_add_annual_billing
Create Date: 2017-10-17 16:47:37.826333
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0127_remove_unique_constraint
Create Date: 2017-10-26 15:17:00.752706
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0128_noti_to_sms_sender
Create Date: 2017-10-26 14:33:41.336861
"""
from alembic import op
revision = "0129_add_email_auth_permission"
@@ -5,6 +5,7 @@ Revises: 0130_service_email_reply_to_row
Create Date: 2017-10-27 16:19:51.458863
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0131_user_auth_types
Create Date: 2017-11-03 11:07:40.537006
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0133_set_services_sms_prefix
Create Date: 2017-11-03 13:52:59.715203
"""
from datetime import datetime
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0134_add_email_2fa_template
Create Date: 2017-11-07 14:35:04.798561
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0135_stats_template_usage
Create Date: 2017-11-08 11:49:05.773974
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0136_user_mobile_nullable
Create Date: 2017-11-08 10:15:07.039227
"""
from alembic import op
revision = "0137_notification_template_hist"
@@ -5,6 +5,7 @@ Revises: 0137_notification_template_hist
Create Date: 2017-11-06 15:44:59.471977
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0138_sms_sender_nullable.py
Create Date: 2017-11-10 21:42:59.715203
"""
import uuid
from datetime import datetime
@@ -5,6 +5,7 @@ Revises: 0139_migrate_sms_allowance_data
Create Date: 2017-11-07 13:04:04.077142
"""
import sqlalchemy as sa
from alembic import op
from flask import current_app
@@ -5,6 +5,7 @@ Revises: 0140_sms_prefix_non_nullable
Create Date: 2017-11-20 11:35:24.402021
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0141_remove_unused
Create Date: 2017-11-15 14:39:13.657666
"""
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0142_validate_constraint
Create Date: 2017-11-21 10:42:25.045444
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0143_remove_reply_to
Create Date: 2017-11-17 15:42:16.401229
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0144_template_service_letter
Create Date: 2017-11-22 14:23:48.806781
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0145_add_notification_reply_to
Create Date: 2017-11-28 15:13:48.730554
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0146_add_service_callback_api
Create Date: 2017-11-30 15:48:44.588438
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0148_add_letters_as_pdf_svc_perm
Create Date: 2017-12-04 12:13:35.268712
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0149_add_crown_to_services
Create Date: 2017-12-01 16:49:51.178455
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0152_kill_service_free_fragments
Create Date: 2018-01-05 17:04:20.596271
"""
from alembic import op
revision = "0156_set_temp_letter_contact"
@@ -5,6 +5,7 @@ Revises: 0156_set_temp_letter_contact
Create Date: 2018-01-08 16:13:25.733336
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0157_add_rate_limit_to_service
Create Date: 2018-01-09 14:33:08.313893
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0159_add_historical_redact
Create Date: 2018-01-30 15:35:12.016574
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
+1
View File
@@ -5,6 +5,7 @@ Revises: 0161_email_branding
Create Date: 2018-02-06 17:08:11.879844
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0162_remove_org
Create Date: 2018-02-07 14:03:00.804849
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0163_add_new_org_model
Create Date: 2018-02-09 17:58:34.617206
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0164_add_organisation_to_service
Create Date: 2018-02-14 17:25:11.747996
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0167_add_precomp_letter_svc_perm
Create Date: 2018-02-21 14:05:04.448977
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0168_hidden_templates
Create Date: 2018-02-21 14:05:04.448977
"""
from alembic import op
revision = "0169_hidden_templates_nullable"
@@ -5,6 +5,7 @@ Revises: 0169_hidden_templates_nullable
Create Date: 2018-02-21 14:05:04.448977
"""
from alembic import op
revision = "0170_hidden_non_nullable"
@@ -5,6 +5,7 @@ Revises: 0170_hidden_non_nullable
Create Date: 2018-02-16 14:16:43.618062
"""
from datetime import datetime
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0171_add_org_invite_template
Create Date: 2018-02-28 17:09:56.619803
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0172_deprioritise_examples
Create Date: 2018-03-01 11:53:32.964256
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0173_create_daily_sorted_letter
Create Date: 2018-03-07 12:21:53.098887
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0174_add_billing_facts
Create Date: 2018-03-12 10:27:09.050837
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0175_drop_job_statistics_table
Create Date: 2018-03-12 16:54:30.663897
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0176_alter_billing_columns
Create Date: 2018-02-21 14:05:04.448977
"""
from alembic import op
revision = "0177_add_virus_scan_statuses"
+1
View File
@@ -5,6 +5,7 @@ Revises: 0177_add_virus_scan_statuses
Create Date: 2018-03-14 16:15:01.886998
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0178_add_filename
Create Date: 2018-03-13 14:52:40.413474
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0179_billing_primary_const
Create Date: 2018-03-21 13:41:26.203712
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0182_add_upload_document_perm
Create Date: 2018-03-25 21:23:32.403212
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0183_alter_primary_key
Create Date: 2018-03-28 16:05:54.648645
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0184_alter_primary_key_1
Create Date: 2018-04-10 16:35:41.824981
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0185_add_is_active_to_reply_tos
Create Date: 2018-04-27 16:35:41.824981
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0186_rename_is_active_columns
Create Date: 2018-05-03 10:10:41.824981
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0188_add_ft_notification_status
Create Date: 2018-05-10 14:57:52.589773
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0189_ft_billing_data
Create Date: 2018-05-21 14:24:27.229511
"""
from alembic import op
revision = "0191_ft_billing_pkey"
@@ -5,6 +5,7 @@ Revises: 0191_ft_billing_pkey
Create Date: 2018-05-21 15:18:43.871256
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0192_drop_provider_statistics
Create Date: 2018-05-22 10:23:21.937262
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0193_add_ft_billing_timestamps
Create Date: 2018-05-22 14:34:27.852096
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0194_ft_billing_created_at
Create Date: 2018-05-22 16:01:53.269137
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0195_ft_notification_timestamps
Create Date: 2018-05-31 14:31:36.649544
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql
@@ -5,6 +5,7 @@ Revises: 0196_complaints_table
Create Date: 2018-05-31 15:01:32.977620
"""
import sqlalchemy as sa
from alembic import op
@@ -5,6 +5,7 @@ Revises: 0203_fix_old_incomplete_jobs
Create Date: 2018-07-10 11:22:01.761829
"""
import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql

Some files were not shown because too many files have changed in this diff Show More