Example #1
0
def create_template(service_id):
    fetched_service = dao_fetch_service_by_id(service_id=service_id)
    # permissions needs to be placed here otherwise marshmallow will intefere with versioning
    permissions = fetched_service.permissions
    new_template = template_schema.load(request.get_json()).data

    if not service_has_permission(new_template.template_type, permissions):
        message = "Creating {} templates is not allowed".format(
            get_public_notify_type_text(new_template.template_type))
        errors = {'template_type': [message]}
        raise InvalidRequest(errors, 403)

    new_template.service = fetched_service
    over_limit = _content_count_greater_than_limit(new_template.content,
                                                   new_template.template_type)
    if over_limit:
        char_count_limit = SMS_CHAR_COUNT_LIMIT
        message = 'Content has a character count greater than the limit of {}'.format(
            char_count_limit)
        errors = {'content': [message]}
        raise InvalidRequest(errors, status_code=400)

    check_reply_to(service_id, new_template.reply_to,
                   new_template.template_type)

    dao_create_template(new_template)
    return jsonify(data=template_schema.dump(new_template).data), 201
Example #2
0
def cancel_notification_for_service(service_id, notification_id):
    notification = notifications_dao.get_notification_by_id(
        notification_id, service_id)

    if not notification:
        raise InvalidRequest('Notification not found', status_code=404)
    elif notification.notification_type != LETTER_TYPE:
        raise InvalidRequest(
            'Notification cannot be cancelled - only letters can be cancelled',
            status_code=400)
    elif not letter_can_be_cancelled(notification.status,
                                     notification.created_at):
        print_day = letter_print_day(notification.created_at)

        raise InvalidRequest(
            "It’s too late to cancel this letter. Printing started {} at 5.30pm"
            .format(print_day),
            status_code=400)

    updated_notification = notifications_dao.update_notification_status_by_id(
        notification_id,
        NOTIFICATION_CANCELLED,
    )

    return jsonify(
        notification_with_template_schema.dump(updated_notification).data), 200
Example #3
0
def _update_broadcast_message(broadcast_message, new_status, updating_user):
    if updating_user not in broadcast_message.service.users:
        raise InvalidRequest(
            f'User {updating_user.id} cannot approve broadcast_message {broadcast_message.id} from other service',
            status_code=400)

    if new_status not in BroadcastStatusType.ALLOWED_STATUS_TRANSITIONS[
            broadcast_message.status]:
        raise InvalidRequest(
            f'Cannot move broadcast_message {broadcast_message.id} from {broadcast_message.status} to {new_status}',
            status_code=400)

    if new_status == BroadcastStatusType.BROADCASTING:
        # TODO: Remove this platform admin shortcut when the feature goes live
        if updating_user == broadcast_message.created_by and not (
                # platform admins and trial mode services can approve their own broadcasts
                updating_user.platform_admin
                or broadcast_message.service.restricted):
            raise InvalidRequest(
                f'User {updating_user.id} cannot approve their own broadcast_message {broadcast_message.id}',
                status_code=400)
        else:
            broadcast_message.approved_at = datetime.utcnow()
            broadcast_message.approved_by = updating_user

    if new_status == BroadcastStatusType.CANCELLED:
        broadcast_message.cancelled_at = datetime.utcnow()
        broadcast_message.cancelled_by = updating_user

    current_app.logger.info(
        f'broadcast_message {broadcast_message.id} moving from {broadcast_message.status} to {new_status}'
    )
    broadcast_message.status = new_status
def process_sinch_response():
    client_name = 'Sinch'

    data = json.loads(request.data)
    errors = validate_callback_data(
        data=data,
        fields=['id', 'from', 'to', 'body', 'received_at'],
        client_name=client_name)

    if errors:
        raise InvalidRequest(errors, status_code=400)

    short_number = data.get('to')

    service = fetch_potential_service(short_number, 'sinch')
    if not service:
        return jsonify({"status": "ok"}), 200

    success, errors = process_shortnumber_keyword_client_response(
        service=service,
        short_number=short_number,
        from_number=data.get('from'),
        body=data.get('body'),
        received_at=data.get('received_at'),
        provider_ref=data.get('id'),
        client_name=client_name)

    redacted_data = dict(data.items())
    current_app.logger.debug(
        "Keyword shortnumber acknowledge from {} \n{}".format(
            client_name, redacted_data))
    if errors:
        raise InvalidRequest(errors, status_code=400)
    else:
        return jsonify(result='success', message=success), 200
Example #5
0
def get_template_statistics_for_service_by_day(service_id):
    whole_days = request.args.get('whole_days',
                                  request.args.get('limit_days', ''))
    try:
        whole_days = int(whole_days)
    except ValueError:
        error = '{} is not an integer'.format(whole_days)
        message = {'whole_days': [error]}
        raise InvalidRequest(message, status_code=400)

    if whole_days < 0 or whole_days > 7:
        raise InvalidRequest(
            {'whole_days': ['whole_days must be between 0 and 7']},
            status_code=400)
    data = fetch_notification_status_for_service_for_today_and_7_previous_days(
        service_id, by_template=True, limit_days=whole_days)

    return jsonify(data=[{
        'count': row.count,
        'template_id': str(row.template_id),
        'template_name': row.template_name,
        'template_type': row.notification_type,
        'is_precompiled_letter': row.is_precompiled_letter,
        'status': row.status
    } for row in data])
def process_telstra_response(notification_id):
    client_name = 'telstra'
    data = request.json

    errors = validate_callback_data(data=data,
                                    fields=['messageId', 'deliveryStatus'],
                                    client_name=client_name)

    if errors:
        raise InvalidRequest(errors, status_code=400)

    success, errors = process_sms_client_response(
        status=str(data.get('deliveryStatus')),
        provider_reference=notification_id,
        client_name=client_name)

    redacted_data = data.copy()
    redacted_data.pop("to")
    current_app.logger.debug(
        "Full delivery response from {} for notification: {}\n{}".format(
            client_name, notification_id, redacted_data))

    if errors:
        raise InvalidRequest(errors, status_code=400)

    return jsonify(result='success', message=success), 200
Example #7
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 sns_callback_handler():
    message_type = request.headers.get('x-amz-sns-message-type')
    try:
        verify_message_type(message_type)
    except InvalidMessageTypeException:
        raise InvalidRequest("SES-SNS callback failed: invalid message type",
                             400)

    try:
        message = json.loads(request.data)
    except json.decoder.JSONDecodeError:
        raise InvalidRequest("SES-SNS callback failed: invalid JSON given",
                             400)

    try:
        validatesns.validate(message, get_certificate=get_certificate)
    except validatesns.ValidationError:
        raise InvalidRequest("SES-SNS callback failed: validation failed", 400)

    if autoconfirm_subscription(message):
        return jsonify(result="success",
                       message="SES-SNS auto-confirm callback succeeded"), 200

    ok, retry = process_ses_results(message)

    if ok:
        return jsonify(result="success",
                       message="SES-SNS callback succeeded"), 200

    if retry:
        raise InvalidRequest("SES callback failed, should retry", 500)

    raise InvalidRequest("SES-SNS callback failed", 400)
Example #9
0
def verify_user_code(user_id):
    data = request.get_json()
    validate(data, post_verify_code_schema)

    user_to_verify = get_user_by_id(user_id=user_id)

    code = get_user_code(user_to_verify, data['code'], data['code_type'])

    if(verify_within_time(user_to_verify) >= 2):
        raise InvalidRequest("Code already sent", status_code=400)

    if user_to_verify.failed_login_count >= current_app.config.get('MAX_VERIFY_CODE_COUNT'):
        raise InvalidRequest("Code not found", status_code=404)
    if not code:
        increment_failed_login_count(user_to_verify)
        raise InvalidRequest("Code not found", status_code=404)
    if datetime.utcnow() > code.expiry_datetime:
        # sms and email
        increment_failed_login_count(user_to_verify)
        raise InvalidRequest("Code has expired", status_code=400)
    if code.code_used:
        increment_failed_login_count(user_to_verify)
        raise InvalidRequest("Code has already been used", status_code=400)

    user_to_verify.current_session_id = str(uuid.uuid4())
    user_to_verify.logged_in_at = datetime.utcnow()
    user_to_verify.failed_login_count = 0
    save_model_user(user_to_verify)

    use_user_code(code.id)
    return jsonify({}), 204
Example #10
0
def _update_broadcast_message(broadcast_message, new_status, updating_user):
    if updating_user not in broadcast_message.service.users:
        raise InvalidRequest(
            f'User {updating_user.id} cannot approve broadcast_message {broadcast_message.id} from other service',
            status_code=400)

    if new_status not in BroadcastStatusType.ALLOWED_STATUS_TRANSITIONS[
            broadcast_message.status]:
        raise InvalidRequest(
            f'Cannot move broadcast_message {broadcast_message.id} from {broadcast_message.status} to {new_status}',
            status_code=400)

    if new_status == BroadcastStatusType.BROADCASTING:
        # training mode services can approve their own broadcasts
        if updating_user == broadcast_message.created_by and not broadcast_message.service.restricted:
            raise InvalidRequest(
                f'User {updating_user.id} cannot approve their own broadcast_message {broadcast_message.id}',
                status_code=400)
        elif len(broadcast_message.areas['simple_polygons']) == 0:
            raise InvalidRequest(
                f'broadcast_message {broadcast_message.id} has no selected areas and so cannot be broadcasted.',
                status_code=400)
        else:
            broadcast_message.approved_at = datetime.utcnow()
            broadcast_message.approved_by = updating_user

    if new_status == BroadcastStatusType.CANCELLED:
        broadcast_message.cancelled_at = datetime.utcnow()
        broadcast_message.cancelled_by = updating_user

    current_app.logger.info(
        f'broadcast_message {broadcast_message.id} moving from {broadcast_message.status} to {new_status}'
    )
    broadcast_message.status = new_status
Example #11
0
def create_template(service_id):
    fetched_service = dao_fetch_service_by_id(service_id=service_id)
    # permissions needs to be placed here otherwise marshmallow will interfere with versioning
    permissions = [p.permission for p in fetched_service.permissions]
    template_json = validate(request.get_json(), post_create_template_schema)
    folder = validate_parent_folder(template_json=template_json)
    new_template = Template.from_json(template_json, folder)

    if not service_has_permission(new_template.template_type, permissions):
        message = "Creating {} templates is not allowed".format(
            get_public_notify_type_text(new_template.template_type))
        errors = {'template_type': [message]}
        raise InvalidRequest(errors, 403)

    if not new_template.postage and new_template.template_type == LETTER_TYPE:
        new_template.postage = SECOND_CLASS

    new_template.service = fetched_service

    over_limit = _content_count_greater_than_limit(new_template.content,
                                                   new_template.template_type)
    if over_limit:
        message = 'Content has a character count greater than the limit of {}'.format(
            SMS_CHAR_COUNT_LIMIT)
        errors = {'content': [message]}
        raise InvalidRequest(errors, status_code=400)

    check_reply_to(service_id, new_template.reply_to,
                   new_template.template_type)

    dao_create_template(new_template)

    return jsonify(data=template_schema.dump(new_template).data), 201
Example #12
0
def get_template_statistics_for_service_by_day(service_id):
    whole_days = request.args.get("whole_days", request.args.get("limit_days", ""))
    try:
        whole_days = int(whole_days)
    except ValueError:
        error = "{} is not an integer".format(whole_days)
        message = {"whole_days": [error]}
        raise InvalidRequest(message, status_code=400)

    if whole_days < 0 or whole_days > 7:
        raise InvalidRequest({"whole_days": ["whole_days must be between 0 and 7"]}, status_code=400)
    data = fetch_notification_status_for_service_for_today_and_7_previous_days(
        service_id, by_template=True, limit_days=whole_days
    )

    return jsonify(
        data=[
            {
                "count": row.count,
                "template_id": str(row.template_id),
                "template_name": row.template_name,
                "template_type": row.notification_type,
                "is_precompiled_letter": row.is_precompiled_letter,
                "status": row.status,
            }
            for row in data
        ]
    )
Example #13
0
def process_twilio_response(notification_id):
    client_name = 'Twilio'

    data = request.values
    errors = validate_callback_data(data=data,
                                    fields=['MessageStatus', 'MessageSid'],
                                    client_name=client_name)

    if errors:
        raise InvalidRequest(errors, status_code=400)

    success, errors = process_sms_client_response(
        status=data.get('MessageStatus'),
        provider_reference=notification_id,
        client_name=client_name)

    redacted_data = dict(data.items())
    redacted_data.pop('To', None)
    current_app.logger.debug(
        "Full delivery response from {} for notification: {}\n{}".format(
            client_name, notification_id, redacted_data))
    if errors:
        raise InvalidRequest(errors, status_code=400)
    else:
        return jsonify(result='success', message=success), 200
Example #14
0
def create_user():
    data = request.get_json(force=True)

    validate(data, post_create_user_schema)

    current_app.logger.info('Creating user {}'.format(data['email']))

    if data['email'].split('@')[1] != current_app.config['EMAIL_DOMAIN']:
        raise InvalidRequest("{} not in correct domain".format(data['email']), 400)

    if data['email'] in current_app.config['ADMIN_USERS']:
        data['access_area'] = USER_ADMIN
    elif data.get('access_area'):
        for area in data['access_area'].split(','):
            if area and area not in ACCESS_AREAS:
                raise InvalidRequest("{} not supported access area".format(area), 400)

    data['active'] = True

    user = User(**data)

    dao_create_user(user)

    current_app.logger.info('Created user {}'.format(user.email))

    return jsonify(user.serialize()), 201
Example #15
0
def dao_create_email(email):
    if email.email_type == EVENT:
        try:
            event = dao_get_event_by_id(email.event_id)
            email.subject = u"{}: {}".format(event.event_type.event_type,
                                             event.title)
            if not email.send_starts_at:
                email.send_starts_at = datetime.strptime(
                    event.get_first_event_date(),
                    "%Y-%m-%d") - timedelta(weeks=2)
            if not email.expires:
                email.expires = event.get_last_event_date()
        except NoResultFound:
            raise InvalidRequest('event not found: {}'.format(email.event_id),
                                 400)
    elif email.email_type == MAGAZINE and not email.old_id:
        if email.magazine_id:
            try:
                magazine = dao_get_magazine_by_id(email.magazine_id)
                email.subject = u"New Acropolis bi-monthly magazine: {}".format(
                    magazine.title)
                if not email.send_starts_at:
                    email.send_starts_at = _get_nearest_bi_monthly_send_date()
                    email.expires = email.send_starts_at + timedelta(weeks=2)
            except NoResultFound:
                raise InvalidRequest(
                    'magazine not found: {}'.format(email.event_id), 400)
        else:
            current_app.logger.info('No magazine id for email')
            return

    db.session.add(email)
    return True
Example #16
0
def validate_invitation_token(invitation_type, token):

    max_age_seconds = 60 * 60 * 24 * current_app.config[
        "INVITATION_EXPIRATION_DAYS"]

    try:
        invited_user_id = check_token(
            token,
            current_app.config["SECRET_KEY"],
            current_app.config["DANGEROUS_SALT"],
            max_age_seconds,
        )
    except SignatureExpired:
        errors = {"invitation": "invitation expired"}
        raise InvalidRequest(errors, status_code=400)
    except BadData:
        errors = {"invitation": "bad invitation link"}
        raise InvalidRequest(errors, status_code=400)

    if invitation_type == "service":
        invited_user = get_invited_user_by_id(invited_user_id)
        return jsonify(data=invited_user_schema.dump(invited_user).data), 200
    elif invitation_type == "organisation":
        invited_user = dao_get_invited_organisation_user(invited_user_id)
        return jsonify(data=invited_user.serialize()), 200
    else:
        raise InvalidRequest(
            "Unrecognised invitation type: {}".format(invitation_type))
Example #17
0
def validate_invitation_token(invitation_type, token):

    max_age_seconds = 60 * 60 * 24 * current_app.config[
        'INVITATION_EXPIRATION_DAYS']

    try:
        invited_user_id = check_token(token, current_app.config['SECRET_KEY'],
                                      current_app.config['DANGEROUS_SALT'],
                                      max_age_seconds)
    except SignatureExpired:
        errors = {
            'invitation':
            'Your invitation to GOV.UK Notify has expired. '
            'Please ask the person that invited you to send you another one'
        }
        raise InvalidRequest(errors, status_code=400)
    except BadData:
        errors = {
            'invitation':
            'Something’s wrong with this link. Make sure you’ve copied the whole thing.'
        }
        raise InvalidRequest(errors, status_code=400)

    if invitation_type == 'service':
        invited_user = get_invited_user_by_id(invited_user_id)
        return jsonify(data=invited_user_schema.dump(invited_user).data), 200
    elif invitation_type == 'organisation':
        invited_user = dao_get_invited_organisation_user(invited_user_id)
        return jsonify(data=invited_user.serialize()), 200
    else:
        raise InvalidRequest(
            "Unrecognised invitation type: {}".format(invitation_type))
Example #18
0
def isValidGUID(organisation_id):
    valid = False
    try:
        # Regex to check valid
        # GUID (Globally Unique Identifier)
        regex = "^[{]?[0-9a-fA-F]{8}" + "-([0-9a-fA-F]{4}-)" + "{3}[0-9a-fA-F]{12}[}]?$"

        # Compile the ReGex
        p = re.compile(regex)

        # Return if the string
        # matched the ReGex
        if (organisation_id is None or not organisation_id
                or re.search(p, organisation_id)):
            valid = True
        else:
            valid = False

    except ValueError:
        raise InvalidRequest(
            message="You must choose an organisation from the list",
            status_code=400)

    if not valid:
        raise InvalidRequest(
            message="You must choose an organisation from the list",
            status_code=400)

    return organisation_id
Example #19
0
def _validate_folder_move(target_template_folder, target_template_folder_id,
                          template_folder, template_folder_id):
    if str(target_template_folder_id) == str(template_folder_id):
        msg = 'You cannot move a folder to itself'
        raise InvalidRequest(msg, status_code=400)
    if target_template_folder and template_folder.is_parent_of(
            target_template_folder):
        msg = 'You cannot move a folder to one of its subfolders'
        raise InvalidRequest(msg, status_code=400)
Example #20
0
def create_user():
    user_to_create, errors = create_user_schema.load(request.get_json())
    req_json = request.get_json()
    if not req_json.get('password', None):
        errors.update({'password': ['Missing data for required field.']})
        raise InvalidRequest(errors, status_code=400)
    if req_json.get('platform_admin'):
        errors.update({'platform_admin': ['Unknown field name.']})
        raise InvalidRequest(errors, status_code=400)
    save_model_user(user_to_create, pwd=req_json.get('password'))
    result = user_to_create.serialize()
    return jsonify(data=result), 201
Example #21
0
def remove_user_from_service(service_id, user_id):
    service = dao_fetch_service_by_id(service_id)
    user = get_user_by_id(user_id=user_id)
    if user not in service.users:
        error = 'User not found'
        raise InvalidRequest(error, status_code=404)

    elif len(service.users) == 1:
        error = 'You cannot remove the only user for a service'
        raise InvalidRequest(error, status_code=400)

    dao_remove_user_from_service(service, user)
    return jsonify({}), 204
Example #22
0
def create_job(service_id):
    service = dao_fetch_service_by_id(service_id)
    if not service.active:
        raise InvalidRequest("Create job is not allowed: service is inactive ",
                             403)

    data = request.get_json()

    data.update({"service": service_id})
    try:
        data.update(**get_job_metadata_from_s3(service_id, data['id']))
    except KeyError:
        raise InvalidRequest({'id': ['Missing data for required field.']},
                             status_code=400)

    data['template'] = data.pop('template_id')
    template = dao_get_template_by_id(data['template'])

    if template.template_type == LETTER_TYPE and service.restricted:
        raise InvalidRequest(
            "Create letter job is not allowed for service in trial mode ", 403)

    if data.get('valid') != 'True':
        raise InvalidRequest("File is not valid, can't create job", 400)

    errors = unarchived_template_schema.validate(
        {'archived': template.archived})

    if errors:
        raise InvalidRequest(errors, status_code=400)

    data.update({"template_version": template.version})

    job = job_schema.load(data).data

    if job.scheduled_for:
        job.job_status = JOB_STATUS_SCHEDULED

    dao_create_job(job)

    sender_id = data.get('sender_id')

    if job.job_status == JOB_STATUS_PENDING:
        process_job.apply_async([str(job.id)], {'sender_id': sender_id},
                                queue=QueueNames.JOBS)

    job_json = job_schema.dump(job).data
    job_json['statistics'] = []

    return jsonify(data=job_json), 201
Example #23
0
def event_handler():
    old_id = request.args.get('eventid')

    try:
        int(old_id)
    except:
        raise InvalidRequest('invalid event old_id: {}'.format(old_id), 400)

    event = dao_get_event_by_old_id(old_id)

    if not event:
        raise InvalidRequest('event not found for old_id: {}'.format(old_id),
                             404)

    return jsonify(event.serialize())
Example #24
0
def create_template_object_for_notification(template, personalisation):
    template_object = get_template_instance(template.__dict__, personalisation)

    if template_object.missing_data:
        message = "Missing personalisation: {}".format(", ".join(
            template_object.missing_data))
        errors = {"template": [message]}
        raise InvalidRequest(errors, status_code=400)

    if template_object.template_type == SMS_TYPE and template_object.content_count > SMS_CHAR_COUNT_LIMIT:
        message = "Content has a character count greater than the limit of {}".format(
            SMS_CHAR_COUNT_LIMIT)
        errors = {"content": [message]}
        raise InvalidRequest(errors, status_code=400)
    return template_object
Example #25
0
def update_template(service_id, template_id):
    fetched_template = dao_get_template_by_id_and_service_id(
        template_id=template_id, service_id=service_id)

    if not service_has_permission(
            fetched_template.template_type,
        [p.permission for p in fetched_template.service.permissions]):
        message = "Updating {} templates is not allowed".format(
            get_public_notify_type_text(fetched_template.template_type))
        errors = {'template_type': [message]}

        raise InvalidRequest(errors, 403)

    data = request.get_json()
    validate(data, post_update_template_schema)

    # if redacting, don't update anything else
    if data.get('redact_personalisation') is True:
        return redact_template(fetched_template, data)

    if "reply_to" in data:
        check_reply_to(service_id, data.get("reply_to"),
                       fetched_template.template_type)
        updated = dao_update_template_reply_to(template_id=template_id,
                                               reply_to=data.get("reply_to"))
        return jsonify(data=template_schema.dump(updated).data), 200

    current_data = dict(template_schema.dump(fetched_template).data.items())
    updated_template = dict(
        template_schema.dump(fetched_template).data.items())
    updated_template.update(data)

    # Check if there is a change to make.
    if _template_has_not_changed(current_data, updated_template):
        return jsonify(data=updated_template), 200

    over_limit = _content_count_greater_than_limit(
        updated_template['content'], fetched_template.template_type)
    if over_limit:
        message = 'Content has a character count greater than the limit of {}'.format(
            SMS_CHAR_COUNT_LIMIT)
        errors = {'content': [message]}
        raise InvalidRequest(errors, status_code=400)

    update_dict = template_schema.load(updated_template).data

    dao_update_template(update_dict)
    return jsonify(data=template_schema.dump(update_dict).data), 200
Example #26
0
def get_monthly_template_usage(service_id):
    try:
        start_date, end_date = get_financial_year(int(request.args.get('year', 'NaN')))
        data = fetch_monthly_template_usage_for_service(
            start_date=start_date,
            end_date=end_date,
            service_id=service_id
        )
        stats = list()
        for i in data:
            stats.append(
                {
                    'template_id': str(i.template_id),
                    'name': i.name,
                    'type': i.template_type,
                    'month': i.month,
                    'year': i.year,
                    'count': i.count,
                    'is_precompiled_letter': i.is_precompiled_letter
                }
            )

        return jsonify(stats=stats), 200
    except ValueError:
        raise InvalidRequest('Year must be a number', status_code=400)
Example #27
0
def check_if_reply_to_address_already_in_use(service_id, email_address):
    existing_reply_to_addresses = dao_get_reply_to_by_service_id(service_id)
    if email_address in [i.email_address for i in existing_reply_to_addresses]:
        raise InvalidRequest(
            "Your service already uses ‘{}’ as an email reply-to address.".
            format(email_address),
            status_code=400)
Example #28
0
def get_free_sms_fragment_limit(service_id):

    financial_year_start = request.args.get('financial_year_start')

    annual_billing = dao_get_free_sms_fragment_limit_for_year(
        service_id, financial_year_start)

    if annual_billing is None:
        # An entry does not exist in annual_billing table for that service and year. If it is a past year,
        # we return the oldest entry.
        # If it is the current or future years, we create an entry in the db table using the newest record,
        # and return that number.  If all fails, we return InvalidRequest.
        sms_list = dao_get_all_free_sms_fragment_limit(service_id)

        if not sms_list:
            raise InvalidRequest(
                'no free-sms-fragment-limit entry for service {} in DB'.format(
                    service_id), 404)
        else:
            if financial_year_start is None:
                financial_year_start = get_current_financial_year_start_year()

            if int(financial_year_start
                   ) < get_current_financial_year_start_year():
                # return the earliest historical entry
                annual_billing = sms_list[0]  # The oldest entry
            else:
                annual_billing = sms_list[-1]  # The newest entry

                annual_billing = dao_create_or_update_annual_billing_for_year(
                    service_id, annual_billing.free_sms_fragment_limit,
                    financial_year_start)

    return jsonify(annual_billing.serialize_free_sms_items()), 200
Example #29
0
def send_user_confirm_new_email(user_id):
    user_to_send_to = get_user_by_id(user_id=user_id)
    email, errors = email_data_request_schema.load(request.get_json())
    if errors:
        raise InvalidRequest(message=errors, status_code=400)

    template = dao_get_template_by_id(current_app.config['CHANGE_EMAIL_CONFIRMATION_TEMPLATE_ID'])
    service = Service.query.get(current_app.config['NOTIFY_SERVICE_ID'])

    saved_notification = persist_notification(
        template_id=template.id,
        template_version=template.version,
        recipient=email['email'],
        service=service,
        personalisation={
            'name': user_to_send_to.name,
            'url': _create_confirmation_url(user=user_to_send_to, email_address=email['email']),
            'feedback_url': current_app.config['ADMIN_BASE_URL'] + '/support/ask-question-give-feedback'
        },
        notification_type=template.template_type,
        api_key_id=None,
        key_type=KEY_TYPE_NORMAL,
        reply_to_text=service.get_default_reply_to_email_address()
    )

    send_notification_to_queue(saved_notification, False, queue=QueueNames.NOTIFY)
    return jsonify({}), 204
Example #30
0
def _get_png_preview_or_overlaid_pdf(url, data, notification_id, json=True):
    if json:
        resp = requests_post(
            url,
            json=data,
            headers={
                'Authorization':
                'Token {}'.format(
                    current_app.config['TEMPLATE_PREVIEW_API_KEY'])
            })
    else:
        resp = requests_post(
            url,
            data=data,
            headers={
                'Authorization':
                'Token {}'.format(
                    current_app.config['TEMPLATE_PREVIEW_API_KEY'])
            })

    if resp.status_code != 200:
        raise InvalidRequest(
            'Error generating preview letter for {} Status code: {} {}'.format(
                notification_id, resp.status_code, resp.content),
            status_code=500)

    return base64.b64encode(resp.content).decode('utf-8')