mirror of
https://github.com/GSA/notifications-api.git
synced 2026-09-11 10:28:55 -04:00
Merge branch 'notify-api-869' into aanand-sqlalchemy-version-update
This commit is contained in:
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
environment: demo
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Terraform format
|
||||
id: format
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
environment: production
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Terraform format
|
||||
id: format
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
environment: staging
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Terraform format
|
||||
id: format
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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():
|
||||
"""
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
"Click this link to create an account on Notify.gov:",
|
||||
"",
|
||||
"[Join Service](((url)))",
|
||||
"If you’re 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",
|
||||
|
||||
@@ -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
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
@@ -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,
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user