def post_precompiled_letter_notification(): if 'content' not in (request.get_json() or {}): return post_notification(LETTER_TYPE) form = validate(request.get_json(), post_precompiled_letter_request) # Check both permission to send letters and permission to send pre-compiled PDFs check_service_has_permission(LETTER_TYPE, authenticated_service.permissions) check_service_has_permission(PRECOMPILED_LETTER, authenticated_service.permissions) check_rate_limiting(authenticated_service, api_user) template = get_precompiled_letter_template(authenticated_service.id) form['personalisation'] = { 'address_line_1': form['reference'] } reply_to = get_reply_to_text(LETTER_TYPE, form, template) notification = process_letter_notification( letter_data=form, api_key=api_user, template=template, reply_to_text=reply_to, precompiled=True ) resp = { 'id': notification.id, 'reference': notification.client_reference } return jsonify(resp), 201
def process_document_uploads(personalisation_data, service, simulated=False): file_keys = [ k for k, v in (personalisation_data or {}).items() if isinstance(v, dict) and 'file' in v ] if not file_keys: return personalisation_data personalisation_data = personalisation_data.copy() check_service_has_permission(UPLOAD_DOCUMENT, authenticated_service.permissions) for key in file_keys: if simulated: personalisation_data[ key] = document_download_client.get_upload_url( service.id) + '/test-document' else: try: personalisation_data[ key] = document_download_client.upload_document( service.id, personalisation_data[key]['file']) except DocumentDownloadError as e: raise BadRequestError(message=e.message, status_code=e.status_code) return personalisation_data
def process_document_uploads(personalisation_data, service, simulated, template_id): file_keys = [k for k, v in (personalisation_data or {}).items() if isinstance(v, dict) and "file" in v] if not file_keys: return personalisation_data personalisation_data = personalisation_data.copy() check_service_has_permission(UPLOAD_DOCUMENT, authenticated_service.permissions) for key in file_keys: if simulated: personalisation_data[key] = document_download_client.get_upload_url(service.id) + "/test-document" else: try: personalisation_data[key] = document_download_client.upload_document(service.id, personalisation_data[key]) except DocumentDownloadError as e: raise BadRequestError(message=e.message, status_code=e.status_code) if not simulated: save_stats_for_attachments( [v for k, v in personalisation_data.items() if k in file_keys], service.id, template_id, ) return personalisation_data
def post_precompiled_letter_notification(): if "content" not in (request.get_json() or {}): return post_notification(LETTER_TYPE) form = validate(request.get_json(), post_precompiled_letter_request) # Check permission to send letters check_service_has_permission(LETTER_TYPE, authenticated_service.permissions) check_rate_limiting(authenticated_service, api_user) template = get_precompiled_letter_template(authenticated_service.id) form["personalisation"] = {"address_line_1": form["reference"]} reply_to = get_reply_to_text(LETTER_TYPE, form, template) notification = process_letter_notification( letter_data=form, api_key=api_user, template=template, reply_to_text=reply_to, precompiled=True, ) resp = { "id": notification.id, "reference": notification.client_reference, "postage": notification.postage, } return jsonify(resp), 201
def post_precompiled_letter_notification(): request_json = get_valid_json() if 'content' not in (request_json or {}): return post_notification(LETTER_TYPE) form = validate(request_json, post_precompiled_letter_request) # Check permission to send letters check_service_has_permission(LETTER_TYPE, authenticated_service.permissions) check_rate_limiting(authenticated_service, api_user) template = get_precompiled_letter_template(authenticated_service.id) # For precompiled letters the to field will be set to Provided as PDF until the validation passes, # then the address of the letter will be set as the to field form['personalisation'] = {'address_line_1': 'Provided as PDF'} reply_to = get_reply_to_text(LETTER_TYPE, form, template) notification = process_letter_notification(letter_data=form, api_key=api_user, template=template, reply_to_text=reply_to, precompiled=True) resp = { 'id': notification.id, 'reference': notification.client_reference, 'postage': notification.postage } return jsonify(resp), 201
def post_precompiled_letter_notification(): request_json = get_valid_json() if 'content' not in (request_json or {}): return post_notification(LETTER_TYPE) form = validate(request_json, post_precompiled_letter_request) # Check permission to send letters check_service_has_permission(LETTER_TYPE, authenticated_service.permissions) check_rate_limiting(authenticated_service, api_user) template = get_precompiled_letter_template(authenticated_service.id) # For precompiled letters the to field will be set to Provided as PDF until the validation passes, # then the address of the letter will be set as the to field form['personalisation'] = {'address_line_1': 'Provided as PDF'} notification = process_letter_notification( letter_data=form, api_key=api_user, service=authenticated_service, template=template, template_with_content=None, # not required for precompiled reply_to_text='', # not required for precompiled precompiled=True) return jsonify(notification), 201
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
def send_pdf_letter_notification(service_id, post_data): service = dao_fetch_service_by_id(service_id) check_service_has_permission(LETTER_TYPE, service.permissions) check_service_has_permission(UPLOAD_LETTERS, service.permissions) check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service) validate_created_by(service, post_data["created_by"]) template = get_precompiled_letter_template(service.id) file_location = "service-{}/{}.pdf".format(service.id, post_data["file_id"]) try: letter = utils_s3download(current_app.config["TRANSIENT_UPLOADED_LETTERS"], file_location) except S3ObjectNotFound as e: current_app.logger.exception( "Letter {}.pdf not in transient {} bucket".format( post_data["file_id"], current_app.config["TRANSIENT_UPLOADED_LETTERS"] ) ) raise e # Getting the page count won't raise an error since admin has already checked the PDF is valid billable_units = get_page_count(letter.read()) personalisation = {"address_line_1": post_data["filename"]} # TODO: stop hard-coding postage as 'second' once we get postage from the admin notification = persist_notification( notification_id=post_data["file_id"], template_id=template.id, template_version=template.version, template_postage=template.postage, recipient=post_data["filename"], service=service, personalisation=personalisation, notification_type=LETTER_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reference=create_one_off_reference(LETTER_TYPE), client_reference=post_data["filename"], created_by_id=post_data["created_by"], billable_units=billable_units, postage="second", ) upload_filename = get_letter_pdf_filename( notification.reference, notification.service.crown, is_scan_letter=False, postage=notification.postage, ) move_uploaded_pdf_to_letters_bucket(file_location, upload_filename) return {"id": str(notification.id)}
def post_notification(notification_type): with POST_NOTIFICATION_JSON_PARSE_DURATION_SECONDS.time(): request_json = get_valid_json() if notification_type == EMAIL_TYPE: form = validate(request_json, post_email_request) elif notification_type == SMS_TYPE: form = validate(request_json, post_sms_request) elif notification_type == LETTER_TYPE: form = validate(request_json, post_letter_request) else: abort(404) check_service_has_permission(notification_type, authenticated_service.permissions) check_rate_limiting(authenticated_service, api_user) template, template_with_content = validate_template(form['template_id'], form.get( 'personalisation', {}), authenticated_service, notification_type, check_char_count=False) reply_to = get_reply_to_text(notification_type, form, template) if notification_type == LETTER_TYPE: notification = process_letter_notification( letter_data=form, api_key=api_user, service=authenticated_service, template=template, template_with_content=template_with_content, reply_to_text=reply_to) else: notification = process_sms_or_email_notification( form=form, notification_type=notification_type, template=template, template_with_content=template_with_content, template_process_type=template.process_type, service=authenticated_service, reply_to_text=reply_to) return jsonify(notification), 201
def post_bulk(): try: request_json = request.get_json() except werkzeug.exceptions.BadRequest as e: raise BadRequestError(message=f"Error decoding arguments: {e.description}", status_code=400) max_rows = current_app.config["CSV_MAX_ROWS"] form = validate(request_json, post_bulk_request(max_rows)) if len([source for source in [form.get("rows"), form.get("csv")] if source]) != 1: raise BadRequestError(message="You should specify either rows or csv", status_code=400) template = validate_template_exists(form["template_id"], authenticated_service) check_service_has_permission(template.template_type, authenticated_service.permissions) remaining_messages = authenticated_service.message_limit - fetch_todays_total_message_count(authenticated_service.id) form["validated_sender_id"] = validate_sender_id(template, form.get("reply_to_id")) try: if form.get("rows"): output = StringIO() writer = csv.writer(output) writer.writerows(form["rows"]) file_data = output.getvalue() else: file_data = form["csv"] recipient_csv = RecipientCSV( file_data, template_type=template.template_type, placeholders=template._as_utils_template().placeholders, max_rows=max_rows, safelist=safelisted_members(authenticated_service, api_user.key_type), remaining_messages=remaining_messages, ) except csv.Error as e: raise BadRequestError(message=f"Error converting to CSV: {str(e)}", status_code=400) check_for_csv_errors(recipient_csv, max_rows, remaining_messages) job = create_bulk_job(authenticated_service, api_user, template, form, recipient_csv) return jsonify(data=job_schema.dump(job).data), 201
def send_pdf_letter_notification(service_id, post_data): service = dao_fetch_service_by_id(service_id) check_service_has_permission(LETTER_TYPE, [p.permission for p in service.permissions]) check_service_over_daily_message_limit(KEY_TYPE_NORMAL, service) validate_created_by(service, post_data['created_by']) validate_and_format_recipient( send_to=post_data['recipient_address'], key_type=KEY_TYPE_NORMAL, service=service, notification_type=LETTER_TYPE, allow_guest_list_recipients=False, ) template = get_precompiled_letter_template(service.id) file_location = 'service-{}/{}.pdf'.format(service.id, post_data['file_id']) try: letter = utils_s3download( current_app.config['TRANSIENT_UPLOADED_LETTERS'], file_location) except S3ObjectNotFound as e: current_app.logger.exception( 'Letter {}.pdf not in transient {} bucket'.format( post_data['file_id'], current_app.config['TRANSIENT_UPLOADED_LETTERS'])) raise e # Getting the page count won't raise an error since admin has already checked the PDF is valid page_count = get_page_count(letter.read()) billable_units = get_billable_units_for_letter_page_count(page_count) personalisation = {'address_line_1': post_data['filename']} notification = persist_notification( notification_id=post_data['file_id'], template_id=template.id, template_version=template.version, recipient=urllib.parse.unquote(post_data['recipient_address']), service=service, personalisation=personalisation, notification_type=LETTER_TYPE, api_key_id=None, key_type=KEY_TYPE_NORMAL, reference=create_one_off_reference(LETTER_TYPE), client_reference=post_data['filename'], created_by_id=post_data['created_by'], billable_units=billable_units, postage=post_data['postage'] or template.postage, ) upload_filename = get_letter_pdf_filename( reference=notification.reference, crown=notification.service.crown, created_at=notification.created_at, ignore_folder=False, postage=notification.postage) move_uploaded_pdf_to_letters_bucket(file_location, upload_filename) return {'id': str(notification.id)}
def post_notification(notification_type): try: request_json = request.get_json() except werkzeug.exceptions.BadRequest as e: raise BadRequestError(message="Error decoding arguments: {}".format(e.description), status_code=400) if notification_type == EMAIL_TYPE: form = validate(request_json, post_email_request) elif notification_type == SMS_TYPE: form = validate(request_json, post_sms_request) elif notification_type == LETTER_TYPE: form = validate(request_json, post_letter_request) else: abort(404) check_service_has_permission(notification_type, authenticated_service.permissions) scheduled_for = form.get("scheduled_for", None) check_service_can_schedule_notification(authenticated_service.permissions, scheduled_for) check_rate_limiting(authenticated_service, api_user) template, template_with_content = validate_template( form['template_id'], form.get('personalisation', {}), authenticated_service, notification_type, ) reply_to = get_reply_to_text(notification_type, form, template) if notification_type == LETTER_TYPE: notification = process_letter_notification( letter_data=form, api_key=api_user, template=template, reply_to_text=reply_to ) else: notification = process_sms_or_email_notification( form=form, notification_type=notification_type, api_key=api_user, template=template, service=authenticated_service, reply_to_text=reply_to ) template_with_content.values = notification.personalisation if notification_type == SMS_TYPE: create_resp_partial = functools.partial( create_post_sms_response_from_notification, from_number=reply_to ) elif notification_type == EMAIL_TYPE: create_resp_partial = functools.partial( create_post_email_response_from_notification, subject=template_with_content.subject, email_from='{}@{}'.format(authenticated_service.email_from, current_app.config['NOTIFY_EMAIL_DOMAIN']) ) elif notification_type == LETTER_TYPE: create_resp_partial = functools.partial( create_post_letter_response_from_notification, subject=template_with_content.subject, ) resp = create_resp_partial( notification=notification, content=str(template_with_content), url_root=request.url_root, scheduled_for=scheduled_for ) return jsonify(resp), 201
def post_notification(notification_type): request_json = get_valid_json() if notification_type == EMAIL_TYPE: form = validate(request_json, post_email_request) elif notification_type == SMS_TYPE: form = validate(request_json, post_sms_request) elif notification_type == LETTER_TYPE: form = validate(request_json, post_letter_request) else: abort(404) check_service_has_permission(notification_type, authenticated_service.permissions) scheduled_for = form.get("scheduled_for", None) check_service_can_schedule_notification(authenticated_service.permissions, scheduled_for) check_rate_limiting(authenticated_service, api_user) template, template_with_content = validate_template( form['template_id'], form.get('personalisation', {}), authenticated_service, notification_type, ) reply_to = get_reply_to_text(notification_type, form, template) if notification_type == LETTER_TYPE: notification = process_letter_notification(letter_data=form, api_key=api_user, template=template, reply_to_text=reply_to) else: notification = process_sms_or_email_notification( form=form, notification_type=notification_type, api_key=api_user, template=template, service=authenticated_service, reply_to_text=reply_to) template_with_content.values = notification.personalisation if notification_type == SMS_TYPE: create_resp_partial = functools.partial( create_post_sms_response_from_notification, from_number=reply_to, ) elif notification_type == EMAIL_TYPE: create_resp_partial = functools.partial( create_post_email_response_from_notification, subject=template_with_content.subject, email_from='{}@{}'.format( authenticated_service.email_from, current_app.config['NOTIFY_EMAIL_DOMAIN']), ) elif notification_type == LETTER_TYPE: create_resp_partial = functools.partial( create_post_letter_response_from_notification, subject=template_with_content.subject, ) resp = create_resp_partial( notification=notification, url_root=request.url_root, scheduled_for=scheduled_for, content=template_with_content.content_with_placeholders_filled_in, ) return jsonify(resp), 201
def post_notification(notification_type): try: request_json = request.get_json() except werkzeug.exceptions.BadRequest as e: raise BadRequestError(message="Error decoding arguments: {}".format( e.description), status_code=400) if notification_type == EMAIL_TYPE: form = validate(request_json, post_email_request) elif notification_type == SMS_TYPE: form = validate(request_json, post_sms_request) elif notification_type == LETTER_TYPE: form = validate(request_json, post_letter_request) else: abort(404) check_service_has_permission(notification_type, authenticated_service.permissions) scheduled_for = form.get("scheduled_for", None) check_service_can_schedule_notification(authenticated_service.permissions, scheduled_for) check_rate_limiting(authenticated_service, api_user) template, template_with_content = validate_template( form['template_id'], form.get('personalisation', {}), authenticated_service, notification_type, ) reply_to = get_reply_to_text(notification_type, form, template) if notification_type == LETTER_TYPE: notification = process_letter_notification(letter_data=form, api_key=api_user, template=template, reply_to_text=reply_to) else: if 'email_address' in form or 'phone_number' in form: notification = process_sms_or_email_notification( form=form, notification_type=notification_type, api_key=api_user, template=template, service=authenticated_service, reply_to_text=reply_to) else: if accept_recipient_identifiers_enabled(): notification = process_notification_with_recipient_identifier( form=form, notification_type=notification_type, api_key=api_user, template=template, service=authenticated_service, reply_to_text=reply_to) else: current_app.logger.debug( "Sending a notification without contact information is not implemented." ) return jsonify(result='error', message="Not Implemented"), 501 template_with_content.values = notification.personalisation if notification_type == SMS_TYPE: create_resp_partial = functools.partial( create_post_sms_response_from_notification, from_number=reply_to) elif notification_type == EMAIL_TYPE: create_resp_partial = functools.partial( create_post_email_response_from_notification, subject=template_with_content.subject) elif notification_type == LETTER_TYPE: create_resp_partial = functools.partial( create_post_letter_response_from_notification, subject=template_with_content.subject, ) resp = create_resp_partial(notification=notification, content=str(template_with_content), url_root=request.url_root, scheduled_for=scheduled_for) return jsonify(resp), 201