mirror of
https://github.com/GSA/notifications-api.git
synced 2026-09-10 18:23:01 -04:00
Merge pull request #3067 from alphagov/fix-cancel-broadcast
Fix cancel broadcast by converting reference date to string
This commit is contained in:
@@ -31,10 +31,6 @@ from app.clients.sms.firetext import FiretextClient
|
|||||||
from app.clients.sms.mmg import MMGClient
|
from app.clients.sms.mmg import MMGClient
|
||||||
from app.clients.performance_platform.performance_platform_client import PerformancePlatformClient
|
from app.clients.performance_platform.performance_platform_client import PerformancePlatformClient
|
||||||
|
|
||||||
DATETIME_FORMAT_NO_TIMEZONE = "%Y-%m-%d %H:%M:%S.%f"
|
|
||||||
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
|
|
||||||
DATE_FORMAT = "%Y-%m-%d"
|
|
||||||
|
|
||||||
|
|
||||||
class SQLAlchemy(_SQLAlchemy):
|
class SQLAlchemy(_SQLAlchemy):
|
||||||
"""We need to subclass SQLAlchemy in order to override create_engine options"""
|
"""We need to subclass SQLAlchemy in order to override create_engine options"""
|
||||||
|
|||||||
@@ -8,11 +8,9 @@ from requests import (
|
|||||||
RequestException
|
RequestException
|
||||||
)
|
)
|
||||||
|
|
||||||
from app import (
|
from app import encryption, notify_celery
|
||||||
notify_celery,
|
|
||||||
encryption
|
|
||||||
)
|
|
||||||
from app.config import QueueNames
|
from app.config import QueueNames
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
|
|
||||||
|
|
||||||
@notify_celery.task(bind=True, name="send-delivery-status", max_retries=5, default_retry_delay=300)
|
@notify_celery.task(bind=True, name="send-delivery-status", max_retries=5, default_retry_delay=300)
|
||||||
@@ -115,7 +113,6 @@ def _send_data_to_service_callback_api(self, data, service_callback_url, token,
|
|||||||
|
|
||||||
|
|
||||||
def create_delivery_status_callback_data(notification, service_callback_api):
|
def create_delivery_status_callback_data(notification, service_callback_api):
|
||||||
from app import DATETIME_FORMAT, encryption
|
|
||||||
data = {
|
data = {
|
||||||
"notification_id": str(notification.id),
|
"notification_id": str(notification.id),
|
||||||
"notification_client_reference": notification.client_reference,
|
"notification_client_reference": notification.client_reference,
|
||||||
@@ -133,7 +130,6 @@ def create_delivery_status_callback_data(notification, service_callback_api):
|
|||||||
|
|
||||||
|
|
||||||
def create_complaint_callback_data(complaint, notification, service_callback_api, recipient):
|
def create_complaint_callback_data(complaint, notification, service_callback_api, recipient):
|
||||||
from app import DATETIME_FORMAT, encryption
|
|
||||||
data = {
|
data = {
|
||||||
"complaint_id": str(complaint.id),
|
"complaint_id": str(complaint.id),
|
||||||
"notification_id": str(notification.id),
|
"notification_id": str(notification.id),
|
||||||
|
|||||||
+1
-1
@@ -18,7 +18,6 @@ from sqlalchemy.exc import SQLAlchemyError, IntegrityError
|
|||||||
from app import (
|
from app import (
|
||||||
create_uuid,
|
create_uuid,
|
||||||
create_random_identifier,
|
create_random_identifier,
|
||||||
DATETIME_FORMAT,
|
|
||||||
encryption,
|
encryption,
|
||||||
notify_celery,
|
notify_celery,
|
||||||
)
|
)
|
||||||
@@ -66,6 +65,7 @@ from app.models import (
|
|||||||
)
|
)
|
||||||
from app.notifications.process_notifications import persist_notification
|
from app.notifications.process_notifications import persist_notification
|
||||||
from app.service.utils import service_allowed_to_send_to
|
from app.service.utils import service_allowed_to_send_to
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
|
|
||||||
|
|
||||||
@notify_celery.task(name="process-job")
|
@notify_celery.task(name="process-job")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import boto3
|
|||||||
from flask import current_app
|
from flask import current_app
|
||||||
|
|
||||||
from app.config import BroadcastProvider
|
from app.config import BroadcastProvider
|
||||||
|
from app.utils import DATETIME_FORMAT, format_sequential_number
|
||||||
|
|
||||||
# The variable names in this file have specific meaning in a CAP message
|
# The variable names in this file have specific meaning in a CAP message
|
||||||
#
|
#
|
||||||
@@ -170,7 +171,10 @@ class CBCProxyEE(CBCProxyClientBase):
|
|||||||
'identifier': identifier,
|
'identifier': identifier,
|
||||||
'message_format': 'cap',
|
'message_format': 'cap',
|
||||||
"references": [
|
"references": [
|
||||||
{"message_id": str(message.id), "sent": message.created_at} for message in previous_provider_messages
|
{
|
||||||
|
"message_id": str(message.id),
|
||||||
|
"sent": message.created_at.strftime(DATETIME_FORMAT)
|
||||||
|
} for message in previous_provider_messages
|
||||||
],
|
],
|
||||||
'sent': sent,
|
'sent': sent,
|
||||||
}
|
}
|
||||||
@@ -217,8 +221,6 @@ class CBCProxyVodafone(CBCProxyClientBase):
|
|||||||
def cancel_broadcast(
|
def cancel_broadcast(
|
||||||
self, identifier, previous_provider_messages, sent, message_number
|
self, identifier, previous_provider_messages, sent, message_number
|
||||||
):
|
):
|
||||||
# avoid cyclical import
|
|
||||||
from app.utils import format_sequential_number
|
|
||||||
|
|
||||||
payload = {
|
payload = {
|
||||||
'message_type': 'cancel',
|
'message_type': 'cancel',
|
||||||
@@ -229,7 +231,7 @@ class CBCProxyVodafone(CBCProxyClientBase):
|
|||||||
{
|
{
|
||||||
"message_id": str(message.id),
|
"message_id": str(message.id),
|
||||||
"message_number": format_sequential_number(message.message_number),
|
"message_number": format_sequential_number(message.message_number),
|
||||||
"sent": message.created_at
|
"sent": message.created_at.strftime(DATETIME_FORMAT)
|
||||||
} for message in previous_provider_messages
|
} for message in previous_provider_messages
|
||||||
],
|
],
|
||||||
'sent': sent,
|
'sent': sent,
|
||||||
|
|||||||
+2
-2
@@ -15,7 +15,7 @@ from sqlalchemy.exc import IntegrityError
|
|||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
from notifications_utils.statsd_decorators import statsd
|
from notifications_utils.statsd_decorators import statsd
|
||||||
|
|
||||||
from app import db, DATETIME_FORMAT, encryption
|
from app import db, encryption
|
||||||
from app.aws import s3
|
from app.aws import s3
|
||||||
from app.celery.tasks import record_daily_sorted_counts, process_row
|
from app.celery.tasks import record_daily_sorted_counts, process_row
|
||||||
from app.celery.nightly_tasks import send_total_sent_notifications_to_performance_platform
|
from app.celery.nightly_tasks import send_total_sent_notifications_to_performance_platform
|
||||||
@@ -60,7 +60,7 @@ from app.models import (
|
|||||||
LetterBranding,
|
LetterBranding,
|
||||||
)
|
)
|
||||||
from app.performance_platform.processing_time import send_processing_time_for_start_and_end
|
from app.performance_platform.processing_time import send_processing_time_for_start_and_end
|
||||||
from app.utils import get_london_midnight_in_utc, get_midnight_for_day_before
|
from app.utils import DATETIME_FORMAT, get_london_midnight_in_utc, get_midnight_for_day_before
|
||||||
|
|
||||||
|
|
||||||
@click.group(name='command', help='Additional commands')
|
@click.group(name='command', help='Additional commands')
|
||||||
|
|||||||
+2
-6
@@ -35,12 +35,8 @@ from app.hashing import (
|
|||||||
hashpw,
|
hashpw,
|
||||||
check_hash
|
check_hash
|
||||||
)
|
)
|
||||||
from app import (
|
from app import db, encryption
|
||||||
db,
|
from app.utils import DATETIME_FORMAT, DATETIME_FORMAT_NO_TIMEZONE, get_dt_string_or_none
|
||||||
encryption,
|
|
||||||
DATETIME_FORMAT,
|
|
||||||
DATETIME_FORMAT_NO_TIMEZONE)
|
|
||||||
from app.utils import get_dt_string_or_none
|
|
||||||
|
|
||||||
from app.history_meta import Versioned
|
from app.history_meta import Versioned
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -23,11 +23,11 @@ from notifications_utils.recipients import (
|
|||||||
validate_and_format_phone_number
|
validate_and_format_phone_number
|
||||||
)
|
)
|
||||||
|
|
||||||
from app import ma, DATETIME_FORMAT_NO_TIMEZONE
|
from app import ma
|
||||||
from app import models
|
from app import models
|
||||||
from app.models import ServicePermission
|
from app.models import ServicePermission
|
||||||
from app.dao.permissions_dao import permission_dao
|
from app.dao.permissions_dao import permission_dao
|
||||||
from app.utils import get_template_instance
|
from app.utils import DATETIME_FORMAT_NO_TIMEZONE, get_template_instance
|
||||||
|
|
||||||
|
|
||||||
def _validate_positive_number(value, msg="Not a positive integer"):
|
def _validate_positive_number(value, msg="Not a positive integer"):
|
||||||
|
|||||||
+1
-2
@@ -12,7 +12,6 @@ from notifications_utils.timezones import convert_utc_to_bst
|
|||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
|
|
||||||
from app import DATE_FORMAT, DATETIME_FORMAT_NO_TIMEZONE
|
|
||||||
from app.aws import s3
|
from app.aws import s3
|
||||||
from app.config import QueueNames
|
from app.config import QueueNames
|
||||||
from app.dao import fact_notification_status_dao, notifications_dao
|
from app.dao import fact_notification_status_dao, notifications_dao
|
||||||
@@ -131,7 +130,7 @@ from app.schemas import (
|
|||||||
email_data_request_schema
|
email_data_request_schema
|
||||||
)
|
)
|
||||||
from app.user.users_schema import post_set_permissions_schema
|
from app.user.users_schema import post_set_permissions_schema
|
||||||
from app.utils import midnight_n_days_ago, pagination_links
|
from app.utils import DATE_FORMAT, DATETIME_FORMAT_NO_TIMEZONE, midnight_n_days_ago, pagination_links
|
||||||
|
|
||||||
service_blueprint = Blueprint('service', __name__)
|
service_blueprint = Blueprint('service', __name__)
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
from flask import Blueprint, jsonify, request
|
from flask import Blueprint, jsonify, request
|
||||||
|
|
||||||
from app import DATETIME_FORMAT
|
|
||||||
from app.dao.notifications_dao import dao_get_last_date_template_was_used
|
from app.dao.notifications_dao import dao_get_last_date_template_was_used
|
||||||
from app.dao.templates_dao import dao_get_template_by_id_and_service_id
|
from app.dao.templates_dao import dao_get_template_by_id_and_service_id
|
||||||
from app.dao.fact_notification_status_dao import fetch_notification_status_for_service_for_today_and_7_previous_days
|
from app.dao.fact_notification_status_dao import fetch_notification_status_for_service_for_today_and_7_previous_days
|
||||||
|
|
||||||
from app.errors import register_errors, InvalidRequest
|
from app.errors import register_errors, InvalidRequest
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
|
|
||||||
template_statistics = Blueprint('template_statistics',
|
template_statistics = Blueprint('template_statistics',
|
||||||
__name__,
|
__name__,
|
||||||
|
|||||||
+3
-1
@@ -11,8 +11,10 @@ from notifications_utils.template import (
|
|||||||
BroadcastMessageTemplate,
|
BroadcastMessageTemplate,
|
||||||
)
|
)
|
||||||
|
|
||||||
from app import DATETIME_FORMAT
|
|
||||||
|
|
||||||
|
DATETIME_FORMAT_NO_TIMEZONE = "%Y-%m-%d %H:%M:%S.%f"
|
||||||
|
DATETIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%fZ"
|
||||||
|
DATE_FORMAT = "%Y-%m-%d"
|
||||||
local_timezone = pytz.timezone("Europe/London")
|
local_timezone = pytz.timezone("Europe/London")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ from app import (
|
|||||||
notify_celery,
|
notify_celery,
|
||||||
document_download_client,
|
document_download_client,
|
||||||
encryption,
|
encryption,
|
||||||
DATETIME_FORMAT
|
|
||||||
)
|
)
|
||||||
from app.celery.letters_pdf_tasks import get_pdf_for_templated_letter, sanitise_letter
|
from app.celery.letters_pdf_tasks import get_pdf_for_templated_letter, sanitise_letter
|
||||||
from app.celery.research_mode_tasks import create_fake_letter_response_file
|
from app.celery.research_mode_tasks import create_fake_letter_response_file
|
||||||
@@ -54,6 +53,7 @@ from app.notifications.validators import (
|
|||||||
validate_template,
|
validate_template,
|
||||||
check_is_message_too_long)
|
check_is_message_too_long)
|
||||||
from app.schema_validation import validate
|
from app.schema_validation import validate
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
from app.v2.errors import BadRequestError
|
from app.v2.errors import BadRequestError
|
||||||
from app.v2.notifications.create_response import (
|
from app.v2.notifications.create_response import (
|
||||||
create_post_email_response_from_notification,
|
create_post_email_response_from_notification,
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import pytest
|
|||||||
import requests_mock
|
import requests_mock
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from app import (DATETIME_FORMAT, encryption)
|
from app import encryption
|
||||||
from app.celery.service_callback_tasks import send_delivery_status_to_service, send_complaint_to_service
|
from app.celery.service_callback_tasks import send_delivery_status_to_service, send_complaint_to_service
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
from tests.app.db import (
|
from tests.app.db import (
|
||||||
create_complaint,
|
create_complaint,
|
||||||
create_notification,
|
create_notification,
|
||||||
|
|||||||
@@ -16,10 +16,7 @@ from notifications_utils.template import (
|
|||||||
)
|
)
|
||||||
from notifications_utils.columns import Row
|
from notifications_utils.columns import Row
|
||||||
|
|
||||||
from app import (
|
from app import encryption
|
||||||
DATETIME_FORMAT,
|
|
||||||
encryption
|
|
||||||
)
|
|
||||||
from app.celery import provider_tasks
|
from app.celery import provider_tasks
|
||||||
from app.celery import tasks
|
from app.celery import tasks
|
||||||
from app.celery.tasks import (
|
from app.celery.tasks import (
|
||||||
@@ -52,6 +49,7 @@ from app.models import (
|
|||||||
SMS_TYPE,
|
SMS_TYPE,
|
||||||
ReturnedLetter,
|
ReturnedLetter,
|
||||||
NOTIFICATION_CREATED)
|
NOTIFICATION_CREATED)
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
|
|
||||||
from tests.app import load_example_csv
|
from tests.app import load_example_csv
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import json
|
import json
|
||||||
import uuid
|
import uuid
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
|
from datetime import datetime
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from app.clients.cbc_proxy import CBCProxyClient, CBCProxyException, CBCProxyEE, CBCProxyCanary
|
from app.clients.cbc_proxy import CBCProxyClient, CBCProxyException, CBCProxyEE, CBCProxyCanary
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope='function')
|
@pytest.fixture(scope='function')
|
||||||
@@ -119,13 +121,15 @@ def test_cbc_proxy_ee_create_and_send_invokes_function(mocker, cbc_proxy_ee):
|
|||||||
|
|
||||||
def test_cbc_proxy_ee_cancel_invokes_function(mocker, cbc_proxy_ee):
|
def test_cbc_proxy_ee_cancel_invokes_function(mocker, cbc_proxy_ee):
|
||||||
identifier = 'my-identifier'
|
identifier = 'my-identifier'
|
||||||
MockProviderMessage = namedtuple('BroadcastProviderMessage', ['id', 'message_number', 'created_at'])
|
MockProviderMessage = namedtuple(
|
||||||
|
'BroadcastProviderMessage', ['id', 'message_number', 'created_at']
|
||||||
|
)
|
||||||
|
|
||||||
provider_messages = [
|
provider_messages = [
|
||||||
MockProviderMessage(uuid.uuid4(), '0000007b', '2020-12-10 11:19:44.130585'),
|
MockProviderMessage(uuid.uuid4(), '0000007b', datetime(2020, 12, 16)),
|
||||||
MockProviderMessage(uuid.uuid4(), '0000004e', '2020-12-10 12:19:44.130585')
|
MockProviderMessage(uuid.uuid4(), '0000004e', datetime(2020, 12, 17))
|
||||||
]
|
]
|
||||||
sent = '2020-12-10 14:19:44.130585'
|
sent = '2020-12-17 14:19:44.130585'
|
||||||
|
|
||||||
ld_client_mock = mocker.patch.object(
|
ld_client_mock = mocker.patch.object(
|
||||||
cbc_proxy_ee,
|
cbc_proxy_ee,
|
||||||
@@ -161,11 +165,11 @@ def test_cbc_proxy_ee_cancel_invokes_function(mocker, cbc_proxy_ee):
|
|||||||
assert payload['references'] == [
|
assert payload['references'] == [
|
||||||
{
|
{
|
||||||
"message_id": str(provider_messages[0].id),
|
"message_id": str(provider_messages[0].id),
|
||||||
"sent": provider_messages[0].created_at
|
"sent": provider_messages[0].created_at.strftime(DATETIME_FORMAT)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"message_id": str(provider_messages[1].id),
|
"message_id": str(provider_messages[1].id),
|
||||||
"sent": provider_messages[1].created_at
|
"sent": provider_messages[1].created_at.strftime(DATETIME_FORMAT)
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
assert payload['sent'] == sent
|
assert payload['sent'] == sent
|
||||||
@@ -233,13 +237,16 @@ def test_cbc_proxy_vodafone_create_and_send_invokes_function(mocker, cbc_proxy_v
|
|||||||
|
|
||||||
def test_cbc_proxy_vodafone_cancel_invokes_function(mocker, cbc_proxy_vodafone):
|
def test_cbc_proxy_vodafone_cancel_invokes_function(mocker, cbc_proxy_vodafone):
|
||||||
identifier = 'my-identifier'
|
identifier = 'my-identifier'
|
||||||
MockProviderMessage = namedtuple('BroadcastProviderMessage', ['id', 'message_number', 'created_at'])
|
MockProviderMessage = namedtuple(
|
||||||
|
'BroadcastProviderMessage',
|
||||||
|
['id', 'message_number', 'created_at']
|
||||||
|
)
|
||||||
|
|
||||||
provider_messages = [
|
provider_messages = [
|
||||||
MockProviderMessage(uuid.uuid4(), 78, '2020-12-10 11:19:44.130585'),
|
MockProviderMessage(uuid.uuid4(), 78, datetime(2020, 12, 16)),
|
||||||
MockProviderMessage(uuid.uuid4(), 123, '2020-12-10 12:19:44.130585')
|
MockProviderMessage(uuid.uuid4(), 123, datetime(2020, 12, 17))
|
||||||
]
|
]
|
||||||
sent = '2020-12-10 14:19:44.130585'
|
sent = '2020-12-18 14:19:44.130585'
|
||||||
|
|
||||||
ld_client_mock = mocker.patch.object(
|
ld_client_mock = mocker.patch.object(
|
||||||
cbc_proxy_vodafone,
|
cbc_proxy_vodafone,
|
||||||
@@ -276,12 +283,12 @@ def test_cbc_proxy_vodafone_cancel_invokes_function(mocker, cbc_proxy_vodafone):
|
|||||||
{
|
{
|
||||||
"message_id": str(provider_messages[0].id),
|
"message_id": str(provider_messages[0].id),
|
||||||
"message_number": '0000004e',
|
"message_number": '0000004e',
|
||||||
"sent": provider_messages[0].created_at
|
"sent": provider_messages[0].created_at.strftime(DATETIME_FORMAT)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"message_id": str(provider_messages[1].id),
|
"message_id": str(provider_messages[1].id),
|
||||||
"message_number": '0000007b',
|
"message_number": '0000007b',
|
||||||
"sent": provider_messages[1].created_at
|
"sent": provider_messages[1].created_at.strftime(DATETIME_FORMAT)
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
assert payload['sent'] == sent
|
assert payload['sent'] == sent
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from unittest.mock import Mock
|
|||||||
import pytest
|
import pytest
|
||||||
from freezegun import freeze_time
|
from freezegun import freeze_time
|
||||||
|
|
||||||
from app import DATETIME_FORMAT
|
from app.utils import DATETIME_FORMAT
|
||||||
from tests.app.db import create_ft_notification_status, create_notification
|
from tests.app.db import create_ft_notification_status, create_notification
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import datetime
|
|||||||
import pytest
|
import pytest
|
||||||
from flask import json, url_for
|
from flask import json, url_for
|
||||||
|
|
||||||
from app import DATETIME_FORMAT
|
from app.utils import DATETIME_FORMAT
|
||||||
from tests import create_authorization_header
|
from tests import create_authorization_header
|
||||||
from tests.app.db import (
|
from tests.app.db import (
|
||||||
create_notification,
|
create_notification,
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import pytest
|
|||||||
|
|
||||||
from flask import json
|
from flask import json
|
||||||
|
|
||||||
from app import DATETIME_FORMAT
|
|
||||||
from app.models import (TEMPLATE_TYPES, EMAIL_TYPE, SMS_TYPE, LETTER_TYPE,)
|
from app.models import (TEMPLATE_TYPES, EMAIL_TYPE, SMS_TYPE, LETTER_TYPE,)
|
||||||
|
from app.utils import DATETIME_FORMAT
|
||||||
from tests import create_authorization_header
|
from tests import create_authorization_header
|
||||||
from tests.app.db import create_template, create_letter_contact
|
from tests.app.db import create_template, create_letter_contact
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user