Beispiel #1
0
def update_broadcast_message(service_id, broadcast_message_id):
    data = request.get_json()

    validate(data, update_broadcast_message_schema)

    broadcast_message = dao_get_broadcast_message_by_id_and_service_id(broadcast_message_id, service_id)

    if broadcast_message.status not in BroadcastStatusType.PRE_BROADCAST_STATUSES:
        raise InvalidRequest(
            f'Cannot update broadcast_message {broadcast_message.id} while it has status {broadcast_message.status}',
            status_code=400
        )

    if ('areas' in data and 'simple_polygons' not in data) or ('areas' not in data and 'simple_polygons' in data):
        raise InvalidRequest(
            f'Cannot update broadcast_message {broadcast_message.id}, areas or polygons are missing.',
            status_code=400
        )

    if 'personalisation' in data:
        broadcast_message.personalisation = data['personalisation']
    if 'starts_at' in data:
        broadcast_message.starts_at = _parse_nullable_datetime(data['starts_at'])
    if 'finishes_at' in data:
        broadcast_message.finishes_at = _parse_nullable_datetime(data['finishes_at'])
    if 'areas' in data and 'simple_polygons' in data:
        broadcast_message.areas = {"areas": data["areas"], "simple_polygons": data["simple_polygons"]}

    dao_save_object(broadcast_message)

    return jsonify(broadcast_message.serialize()), 200
def create_broadcast_message(service_id):
    data = request.get_json()

    validate(data, create_broadcast_message_schema)
    service = dao_fetch_service_by_id(data['service_id'])
    user = get_user_by_id(data['created_by'])
    template = dao_get_template_by_id_and_service_id(data['template_id'], data['service_id'])

    personalisation = data.get('personalisation', {})
    broadcast_message = BroadcastMessage(
        service_id=service.id,
        template_id=template.id,
        template_version=template.version,
        personalisation=personalisation,
        areas={"areas": data.get("areas", []), "simple_polygons": data.get("simple_polygons", [])},
        status=BroadcastStatusType.DRAFT,
        starts_at=_parse_nullable_datetime(data.get('starts_at')),
        finishes_at=_parse_nullable_datetime(data.get('finishes_at')),
        created_by_id=user.id,
        content=template._as_utils_template_with_personalisation(
            personalisation
        ).content_with_placeholders_filled_in,
    )

    dao_save_object(broadcast_message)

    return jsonify(broadcast_message.serialize()), 201
Beispiel #3
0
def _create_broadcast_event(broadcast_message):
    """
    Creates a broadcast event, stores it in the database, and triggers the task to send the CAP XML off
    """
    msg_types = {
        BroadcastStatusType.BROADCASTING: BroadcastEventMessageType.ALERT,
        BroadcastStatusType.CANCELLED: BroadcastEventMessageType.CANCEL,
    }

    event = BroadcastEvent(
        service=broadcast_message.service,
        broadcast_message=broadcast_message,
        message_type=msg_types[broadcast_message.status],
        transmitted_content={"body": broadcast_message.content},
        transmitted_areas=broadcast_message.areas,
        # TODO: Probably move this somewhere more standalone too and imply that it shouldn't change. Should it include
        # a service based identifier too? eg "*****@*****.**" or similar
        transmitted_sender='notifications.service.gov.uk',

        # TODO: Should this be set to now? Or the original starts_at?
        transmitted_starts_at=broadcast_message.starts_at,
        transmitted_finishes_at=broadcast_message.finishes_at,
    )

    dao_save_object(event)

    if not broadcast_message.stubbed or current_app.config['NOTIFY_ENVIRONMENT'] in ['preview', 'development']:
        send_broadcast_event.apply_async(
            kwargs={'broadcast_event_id': str(event.id)},
            queue=QueueNames.BROADCASTS
        )
Beispiel #4
0
def create_broadcast():

    check_service_has_permission(
        BROADCAST_TYPE,
        authenticated_service.permissions,
    )

    if request.content_type != 'application/cap+xml':
        raise BadRequestError(
            message=f'Content type {request.content_type} not supported',
            status_code=415,
        )

    cap_xml = request.get_data()

    if not validate_xml(cap_xml, 'CAP-v1.2.xsd'):
        raise BadRequestError(
            message='Request data is not valid CAP XML',
            status_code=400,
        )

    broadcast_json = cap_xml_to_dict(cap_xml)

    validate(broadcast_json, post_broadcast_schema)

    polygons = Polygons(
        list(
            chain.from_iterable(
                (area['polygons'] for area in broadcast_json['areas']))))

    broadcast_message = BroadcastMessage(
        service_id=authenticated_service.id,
        content=broadcast_json['content'],
        reference=broadcast_json['reference'],
        areas={
            'areas': [area['name'] for area in broadcast_json['areas']],
            'simple_polygons':
            polygons.smooth.simplify.as_coordinate_pairs_long_lat,
        },
        status=BroadcastStatusType.PENDING_APPROVAL,
        api_key_id=api_user.id,
        stubbed=authenticated_service.restricted
        # The client may pass in broadcast_json['expires'] but it’s
        # simpler for now to ignore it and have the rules around expiry
        # for broadcasts created with the API match those created from
        # the admin app
    )

    dao_save_object(broadcast_message)

    current_app.logger.info(
        f'Broadcast message {broadcast_message.id} created for service '
        f'{authenticated_service.id} with reference {broadcast_json["reference"]}'
    )

    return jsonify(broadcast_message.serialize()), 201
Beispiel #5
0
def update_broadcast_message_status(service_id, broadcast_message_id):
    data = request.get_json()

    validate(data, update_broadcast_message_status_schema)
    broadcast_message = dao_get_broadcast_message_by_id_and_service_id(broadcast_message_id, service_id)

    new_status = data['status']
    updating_user = get_user_by_id(data['created_by'])

    _update_broadcast_message(broadcast_message, new_status, updating_user)
    dao_save_object(broadcast_message)

    if new_status in {BroadcastStatusType.BROADCASTING, BroadcastStatusType.CANCELLED}:
        _create_broadcast_event(broadcast_message)

    return jsonify(broadcast_message.serialize()), 200
def _create_broadcast_event(broadcast_message):
    """
    Creates a broadcast event, stores it in the database, and triggers the task to send the CAP XML off
    """
    msg_types = {
        BroadcastStatusType.BROADCASTING: BroadcastEventMessageType.ALERT,
        BroadcastStatusType.CANCELLED: BroadcastEventMessageType.CANCEL,
    }

    if broadcast_message.status == BroadcastStatusType.CANCELLED:
        transmitted_finishes_at = broadcast_message.cancelled_at
    else:
        transmitted_finishes_at = broadcast_message.finishes_at

    # TODO: Remove this if statement after broadcast message content is guaranteed to always be populated.
    if broadcast_message.content:
        content = broadcast_message.content
    else:
        content = broadcast_message.template._as_utils_template_with_personalisation(
            broadcast_message.personalisation
        ).content_with_placeholders_filled_in

    event = BroadcastEvent(
        service=broadcast_message.service,
        broadcast_message=broadcast_message,
        message_type=msg_types[broadcast_message.status],
        transmitted_content={"body": content},
        transmitted_areas=broadcast_message.areas,
        # TODO: Probably move this somewhere more standalone too and imply that it shouldn't change. Should it include
        # a service based identifier too? eg "*****@*****.**" or similar
        transmitted_sender='notifications.service.gov.uk',

        # TODO: Should this be set to now? Or the original starts_at?
        transmitted_starts_at=broadcast_message.starts_at,
        # TODO: When cancelling, do we need to set this to now? Or should we keep it as the original time.
        transmitted_finishes_at=transmitted_finishes_at,
    )

    dao_save_object(event)

    send_broadcast_event.apply_async(
        kwargs={'broadcast_event_id': str(event.id)},
        queue=QueueNames.NOTIFY
    )
Beispiel #7
0
def _create_broadcast_event(broadcast_message):
    """
    If the service is live and the broadcast message is not stubbed, creates a broadcast event, stores it in the
    database, and triggers the task to send the CAP XML off.
    """
    service = broadcast_message.service

    if not broadcast_message.stubbed and not service.restricted:
        msg_types = {
            BroadcastStatusType.BROADCASTING: BroadcastEventMessageType.ALERT,
            BroadcastStatusType.CANCELLED: BroadcastEventMessageType.CANCEL,
        }

        event = BroadcastEvent(
            service=service,
            broadcast_message=broadcast_message,
            message_type=msg_types[broadcast_message.status],
            transmitted_content={"body": broadcast_message.content},
            transmitted_areas=broadcast_message.areas,
            # TODO: Probably move this somewhere more standalone too and imply that it shouldn't change. Should it
            # include a service based identifier too? eg "*****@*****.**" or similar
            transmitted_sender='notifications.service.gov.uk',

            # TODO: Should this be set to now? Or the original starts_at?
            transmitted_starts_at=broadcast_message.starts_at,
            transmitted_finishes_at=broadcast_message.finishes_at,
        )

        dao_save_object(event)

        send_broadcast_event.apply_async(
            kwargs={'broadcast_event_id': str(event.id)},
            queue=QueueNames.BROADCASTS)
    elif broadcast_message.stubbed != service.restricted:
        # It's possible for a service to create a broadcast in trial mode, and then approve it after the
        # service is live (or vice versa). We don't think it's safe to send such broadcasts, as the service
        # has changed since they were created. Log an error instead.
        current_app.logger.error(
            f'Broadcast event not created. Stubbed status of broadcast message was {broadcast_message.stubbed}'
            f' but service was {"in trial mode" if service.restricted else "live"}'
        )
Beispiel #8
0
def create_broadcast_message(service_id):
    data = request.get_json()

    validate(data, create_broadcast_message_schema)
    service = dao_fetch_service_by_id(data['service_id'])
    user = get_user_by_id(data['created_by'])
    template = dao_get_template_by_id_and_service_id(data['template_id'],
                                                     data['service_id'])

    broadcast_message = BroadcastMessage(
        service_id=service.id,
        template_id=template.id,
        template_version=template.version,
        personalisation=data.get('personalisation', {}),
        areas=data.get('areas', []),
        status=BroadcastStatusType.DRAFT,
        starts_at=_parse_nullable_datetime(data.get('starts_at')),
        finishes_at=_parse_nullable_datetime(data.get('finishes_at')),
        created_by_id=user.id,
    )

    dao_save_object(broadcast_message)

    return jsonify(broadcast_message.serialize()), 201
Beispiel #9
0
def _create_broadcast_event(broadcast_message):
    """
    Creates a broadcast event, stores it in the database, and triggers the task to send the CAP XML off
    """
    msg_types = {
        BroadcastStatusType.BROADCASTING: BroadcastEventMessageType.ALERT,
        BroadcastStatusType.CANCELLED: BroadcastEventMessageType.CANCEL,
    }

    if broadcast_message.status == BroadcastStatusType.CANCELLED:
        transmitted_finishes_at = broadcast_message.cancelled_at
    else:
        transmitted_finishes_at = broadcast_message.finishes_at

    # TODO: This doesn't support placeholders yet. We shouldn't use BroadcastMessageTemplate when we add placeholders
    # as that just outputs XML, we need the raw text.
    event = BroadcastEvent(
        service=broadcast_message.service,
        broadcast_message=broadcast_message,
        message_type=msg_types[broadcast_message.status],
        transmitted_content={"body": broadcast_message.template.content},
        transmitted_areas=broadcast_message.areas,
        # TODO: Probably move this somewhere more standalone too and imply that it shouldn't change. Should it include
        # a service based identifier too? eg "*****@*****.**" or similar
        transmitted_sender='notifications.service.gov.uk',

        # TODO: Should this be set to now? Or the original starts_at?
        transmitted_starts_at=broadcast_message.starts_at,
        # TODO: When cancelling, do we need to set this to now? Or should we keep it as the original time.
        transmitted_finishes_at=transmitted_finishes_at,
    )

    dao_save_object(event)

    send_broadcast_event.apply_async(
        kwargs={'broadcast_event_id': str(event.id)}, queue=QueueNames.NOTIFY)