def form(): data = MultiDict() data.update(request.args) data.update(request.form) form_name = data.get('_form_name') redirect_url = data.get('_redirect_url') body = [] for key, val in data.items(): body.append('%s: %s' % (key, val)) body.append('') body.append('') body.append('--') body.append('sent form former2 by Ondrej Sika') body.append('https://github.com/former2/former2') if form_name: subject = '[former2] Submit notification from %s' % form_name else: subject = '[former2] Submit notification' message = Message(subject, sender=args.smtp_email, recipients=args.notify_to.split(',')) message.body = '\n'.join(body) mail.send(message) if redirect_url: return redirect(redirect_url) else: return message.body.replace('\n', '\n<br>')
def authorship(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: """Handle the authorship assertion view.""" submitter, client = user_and_client_from_session(session) # Will raise NotFound if there is no such submission. submission, submission_events = load_submission(submission_id) # The form should be prepopulated based on the current state of the # submission. if method == 'GET': # Update form data based on the current state of the submission. if submission.submitter_is_author is not None: if submission.submitter_is_author: params['authorship'] = AuthorshipForm.YES else: params['authorship'] = AuthorshipForm.NO if submission.submitter_is_author is False: params['proxy'] = True form = AuthorshipForm(params) response_data = { 'submission_id': submission_id, 'form': form, 'submission': submission, 'submitter': submitter, 'client': client, } if method == 'POST': if not form.validate(): raise BadRequest(response_data) value = (form.authorship.data == form.YES) # No need to do this more than once. if submission.submitter_is_author != value: command = ConfirmAuthorship(creator=submitter, client=client, submitter_is_author=value) if not validate_command(form, command, submission, 'authorship'): raise BadRequest(response_data) try: # Create ConfirmAuthorship event submission, _ = save(command, submission_id=submission_id) response_data['submission'] = submission except SaveError as e: logger.error('Could not save command: %s', e) raise InternalServerError(response_data) from e if params.get('action') in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} return response_data, status.OK, {}
def _post_upload(params: MultiDict, files: MultiDict, session: Session, submission: Submission, rdata: Dict[str, Any], token: str) \ -> Response: """ Compose POST request handling for the file upload endpoint. See the :attr:`Submission.source_content` attribute, which is set using :class:`SetUploadPackage`. Parameters ---------- params : :class:`MultiDict` The form data from the request. files : :class:`MultiDict` File data in the multipart request. Values should be :class:`FileStorage` instances. session : :class:`Session` The authenticated session for the request. submission : :class:`Submission` The submission for which the request is being made. Returns ------- dict Response data, to render in template. int HTTP status code. This should be ``303``, unless something goes wrong. dict Extra headers to add/update on the response. This should include the `Location` header for use in the 303 redirect response. """ try: # Make sure that we have a file to work with. pointer = files['file'] except KeyError: # User is going back, saving/exiting, or next step. pointer = None if not pointer: # Don't flash a message if the user is just trying to go back to the # previous page. logger.debug('No files on request') action = params.get('action', None) if action: logger.debug('User is navigating away from upload UI') return {}, status.SEE_OTHER, {} if submission.source_content is None: # New upload package. logger.debug('New upload package') return _new_upload(params, pointer, session, submission, rdata, token) logger.debug('Adding additional files') return _new_file(params, pointer, session, submission, rdata, token)
def classification(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: """Handle primary classification requests.""" submitter, client = user_and_client_from_session(session) submission, submission_events = load_submission(submission_id) if method == 'GET': # Prepopulate the form based on the state of the submission. if submission.primary_classification \ and submission.primary_classification.category: params['category'] = submission.primary_classification.category # Use the user's default category as the default for the form. params.setdefault('category', session.user.profile.default_category) params['operation'] = PrimaryClassificationForm.ADD form = PrimaryClassificationForm(params) form.filter_choices(submission, session) response_data = { 'submission_id': submission_id, 'submission': submission, 'submitter': submitter, 'client': client, 'form': form } if method == 'POST': if not form.validate(): raise BadRequest(response_data) command = SetPrimaryClassification(category=form.category.data, creator=submitter, client=client) if not validate_command(form, command, submission, 'category'): raise BadRequest(response_data) try: submission, _ = save(command, submission_id=submission_id) response_data['submission'] = submission except SaveError as e: logger.error('Could not save command: %s', e) raise InternalServerError(response_data) from e if params.get('action') in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} return response_data, status.OK, {}
def license(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: """Convert license form data into a `SetLicense` event.""" submitter, client = user_and_client_from_session(session) logger.debug(f'method: {method}, submission: {submission_id}. {params}') # Will raise NotFound if there is no such submission. submission, submission_events = load_submission(submission_id) if method == 'GET' and submission.license: # The form should be prepopulated based on the current state of the # submission. params['license'] = submission.license.uri form = LicenseForm(params) response_data = { 'submission_id': submission_id, 'form': form, 'submission': submission } if method == 'POST': if form.validate(): logger.debug('Form is valid, with data: %s', str(form.data)) license_uri = form.license.data # If already selected, nothing more to do. if not submission.license or submission.license.uri != license_uri: command = SetLicense(creator=submitter, client=client, license_uri=license_uri) if not validate_command(form, command, submission, 'license'): raise BadRequest(response_data) try: # Create SetLicense event submission, _ = save(command, submission_id=submission_id) except SaveError as e: raise InternalServerError(response_data) from e else: # Form data were invalid. raise BadRequest(response_data) if params.get('action') in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} return response_data, status.OK, {}
def metadata(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: """Update metadata on the submission.""" submitter, client = user_and_client_from_session(session) logger.debug(f'method: {method}, submission: {submission_id}. {params}') # Will raise NotFound if there is no such submission. submission, submission_events = load_submission(submission_id) # The form should be prepopulated based on the current state of the # submission. if method == 'GET': params = _data_from_submission(params, submission, CoreMetadataForm) form = CoreMetadataForm(params) response_data = { 'submission_id': submission_id, 'form': form, 'submission': submission } if method == 'POST': if not form.validate(): raise BadRequest(response_data) logger.debug('Form is valid, with data: %s', str(form.data)) commands, valid = _commands(form, submission, submitter, client) # We only want to apply an UpdateMetadata if the metadata has # actually changed. if commands: # Metadata has changed. if not all(valid): logger.debug('Not all commands are valid') response_data['form'] = form raise BadRequest(response_data) try: # Save the events created during form validation. submission, _ = save(*commands, submission_id=submission_id) except SaveError as e: raise InternalServerError(response_data) from e response_data['submission'] = submission if params.get('action') in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} return response_data, status.OK, {}
def finalize(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: submitter, client = user_and_client_from_session(session) logger.debug(f'method: {method}, submission: {submission_id}. {params}') submission, submission_events = load_submission(submission_id) form = FinalizationForm(params) # The abs preview macro expects a specific struct for submission history. submission_history = [{ 'submitted_date': s.created, 'version': s.version } for s in submission.versions] response_data = { 'submission_id': submission_id, 'form': form, 'submission': submission, 'submission_history': submission_history } if method == 'POST': if form.validate(): logger.debug('Form is valid, with data: %s', str(form.data)) proofread_confirmed = form.proceed.data if proofread_confirmed: command = FinalizeSubmission(creator=submitter) if not validate_command(form, command, submission): raise BadRequest(response_data) try: # Create ConfirmPolicy event submission, stack = save( # pylint: disable=W0612 command, submission_id=submission_id) except SaveError as e: logger.error('Could not save primary event') raise InternalServerError(response_data) from e if params.get('action') in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} else: # Form data were invalid. raise BadRequest(response_data) return response_data, status.OK, {}
def file_process(method: str, params: MultiDict, session: Session, submission_id: int, token: str, **kwargs) -> Response: """ Process the file compilation project. Parameters ---------- method : str ``GET`` or ``POST`` session : :class:`Session` The authenticated session for the request. submission_id : int The identifier of the submission for which the upload is being made. token : str The original (encrypted) auth token on the request. Used to perform subrequests to the file management service. Returns ------- dict Response data, to render in template. int HTTP status code. This should be ``200`` or ``303``, unless something goes wrong. dict Extra headers to add/update on the response. This should include the `Location` header for use in the 303 redirect response, if applicable. """ logger.debug("%s: %s, %s, %s, %s", method, params, session, submission_id, token) if method == "GET": return compile_status(params, session, submission_id, token) elif method == "POST": if params.get('action') in ['previous', 'next', 'save_exit']: _check_status(params, session, submission_id, token) # User is not actually trying to process anything; let flow control # in the routes handle the response. return {}, status.SEE_OTHER, {} return start_compilation(params, session, submission_id, token) raise MethodNotAllowed('Unsupported request')
def policy(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: """Convert policy form data into an `ConfirmPolicy` event.""" submitter, client = user_and_client_from_session(session) logger.debug(f'method: {method}, submission: {submission_id}. {params}') submission, submission_events = load_submission(submission_id) if method == 'GET' and submission.submitter_accepts_policy: params['policy'] = 'true' form = PolicyForm(params) response_data = { 'submission_id': submission_id, 'form': form, 'submission': submission } if method == 'POST': if not form.validate(): raise BadRequest(response_data) logger.debug('Form is valid, with data: %s', str(form.data)) accept_policy = form.policy.data if accept_policy and not submission.submitter_accepts_policy: command = ConfirmPolicy(creator=submitter, client=client) if not validate_command(form, command, submission, 'policy'): raise BadRequest(response_data) try: submission, _ = save(command, submission_id=submission_id) except SaveError as e: raise InternalServerError(response_data) from e response_data['submission'] = submission if params.get('action') in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} return response_data, status.OK, {}
def cross_list(method: str, params: MultiDict, session: Session, submission_id: int, **kwargs) -> Response: submitter, client = user_and_client_from_session(session) submission, submission_events = load_submission(submission_id) form = ClassificationForm(params) form.operation._value = lambda: form.operation.data form.filter_choices(submission, session) # Create a formset to render removal option. # # We need forms for existing secondaries, to generate removal requests. # When the forms in the formset are submitted, they are handled as the # primary form in the POST request to this controller. formset = ClassificationForm.formset(submission) _primary_category = submission.primary_classification.category _primary = taxonomy.CATEGORIES[_primary_category] response_data = { 'submission_id': submission_id, 'submission': submission, 'submitter': submitter, 'client': client, 'form': form, 'formset': formset, 'primary': { 'id': submission.primary_classification.category, 'name': _primary['name'] }, } if method == 'POST': # Make sure that the user is not attempting to move to a different # step. # # Since the interface provides an "add" button to add cross-list # categories, we only want to handle the form data if the user is not # attempting to move to a different step. action = params.get('action') if not action: if not form.validate(): raise BadRequest(response_data) if form.operation.data == form.REMOVE: command_type = RemoveSecondaryClassification else: command_type = AddSecondaryClassification command = command_type(category=form.category.data, creator=submitter, client=client) if not validate_command(form, command, submission, 'category'): raise BadRequest(response_data) try: submission, _ = save(command, submission_id=submission_id) response_data['submission'] = submission except SaveError as e: raise InternalServerError(response_data) from e # Re-build the formset to reflect changes that we just made, and # generate a fresh form for adding another secondary. The POSTed # data should now be reflected in the formset. response_data['formset'] = ClassificationForm.formset(submission) form = ClassificationForm() form.operation._value = lambda: form.operation.data form.filter_choices(submission, session) response_data['form'] = form # Warn the user if they have too many secondaries. if len(submission.secondary_categories) > 3: alerts.flash_warning( Markup( 'Adding more than three cross-list classifications will' ' result in a delay in the acceptance of your submission.' )) if action in ['previous', 'save_exit', 'next']: return response_data, status.SEE_OTHER, {} return response_data, status.OK, {}
def compile(request_data: MultiDict, token: str, session: Session, is_authorized: Callable = lambda task: True) -> Response: """ Start compilation of an upload workspace. Parameters ---------- request_data : :class:`.MultiDict` Data payload from the request. token : str Auth token to be used for subrequests (e.g. to file management service). Returns ------- dict Response data. int HTTP status code. dict Headers to add to response. """ # Since these may originate from a JSON payload, values may be deserialized # as int; cast to str to ensure that we are passing the correct type. source_id = _validate_source_id(str(request_data.get('source_id', ''))) checksum = _validate_checksum(str(request_data.get('checksum', ''))) product_format = _validate_output_format( request_data.get('output_format', Format.PDF.value)) # We don't want to compile the same source package twice. force = request_data.get('force', False) # Support label and link for PS/PDF Stamping # Test stamp_label: Optional[str] = request_data.get('stamp_label', None) stamp_link: Optional[str] = request_data.get('stamp_link', None) logger.debug('%s: request compilation with %s', __name__, request_data) # Unless we are forcing recompilation, we do not want to compile the same # source twice. So we check our storage for a compilation (successful or # not) corresponding to the requested source package. if not force: info = _status_from_store(source_id, checksum, product_format) if info is not None: if not is_authorized(info): raise Forbidden('Not authorized to compile this resource') logger.debug('compilation exists, redirecting') return _redirect_to_status(source_id, checksum, product_format) owner = _get_owner(source_id, checksum, token) try: compiler.start_compilation(source_id, checksum, stamp_label, stamp_link, product_format, token=token, owner=owner) except compiler.TaskCreationFailed as e: logger.error('Failed to start compilation: %s', e) raise InternalServerError('Failed to start compilation') from e return _redirect_to_status(source_id, checksum, product_format, status.ACCEPTED)