def _submit_data(user): answer_store = get_answer_store(user) if answer_store.answers: metadata = get_metadata(user) schema = load_schema_from_metadata(metadata) routing_path = PathFinder(schema, answer_store, metadata).get_routing_path() message = convert_answers(metadata, schema, answer_store, routing_path, flushed=True) message = current_app.eq['encrypter'].encrypt(message) sent = current_app.eq['submitter'].send_message( message, current_app.config['EQ_RABBITMQ_QUEUE_NAME'], metadata["tx_id"]) if not sent: raise SubmissionFailedException() get_questionnaire_store(user.user_id, user.user_ik).delete() return True else: return False
def get_referenced_offset_value(answer_min_or_max, answer_store, metadata, group_instance=0): """ Gets value of the referenced date type, whether it is a value, id of an answer or a meta date. Then adds/subtracts offset from that value and returns the new offset value :param answer_min_or_max: The minimum or maximum object which contains the referenced value. :param answer_store: The current answer store :param metadata: metadata for reference meta dates :return: date value """ value = None if 'value' in answer_min_or_max: if answer_min_or_max['value'] == 'now': value = datetime.utcnow().strftime('%Y-%m-%d') else: value = answer_min_or_max['value'] elif 'meta' in answer_min_or_max: value = get_metadata_value(metadata, answer_min_or_max['meta']) elif 'answer_id' in answer_min_or_max: schema = load_schema_from_metadata(metadata) value = get_answer_store_value(answer_min_or_max['answer_id'], answer_store, schema, group_instance=group_instance) value = convert_to_datetime(value) if 'offset_by' in answer_min_or_max: offset = answer_min_or_max['offset_by'] value += relativedelta(years=offset.get('years', 0), months=offset.get('months', 0), days=offset.get('days', 0)) return value
def _submit_data(user): answer_store = get_answer_store(user) if answer_store.answers: metadata = get_metadata(user) collection_metadata = get_collection_metadata(user) schema = load_schema_from_metadata(metadata) completed_blocks = get_completed_blocks(user) routing_path = PathFinder(schema, answer_store, metadata, completed_blocks).get_full_routing_path() message = convert_answers(metadata, collection_metadata, schema, answer_store, routing_path, flushed=True) encrypted_message = encrypt(message, current_app.eq['key_store'], KEY_PURPOSE_SUBMISSION) sent = current_app.eq['submitter'].send_message( encrypted_message, current_app.config['EQ_RABBITMQ_QUEUE_NAME'], metadata['tx_id']) if not sent: raise SubmissionFailedException() get_questionnaire_store(user.user_id, user.user_ik).delete() return True return False
def login(): """ Initial url processing - expects a token parameter and then will authenticate this token. Once authenticated it will be placed in the users session :return: a 302 redirect to the next location for the user """ # logging in again clears any session state if cookie_session: cookie_session.clear() decrypted_token = decrypt_token(request.args.get("token")) validate_jti(decrypted_token) try: runner_claims = validate_runner_claims(decrypted_token) except ValidationError as e: raise InvalidTokenException("Invalid runner claims") from e g.schema = load_schema_from_metadata(runner_claims) schema_metadata = g.schema.json["metadata"] try: questionnaire_claims = validate_questionnaire_claims( decrypted_token, schema_metadata) except ValidationError as e: raise InvalidTokenException("Invalid questionnaire claims") from e claims = {**runner_claims, **questionnaire_claims} schema_name = claims["schema_name"] tx_id = claims["tx_id"] ru_ref = claims["ru_ref"] case_id = claims["case_id"] logger.bind( schema_name=schema_name, tx_id=tx_id, ru_ref=ru_ref, case_id=case_id, ) logger.info("decrypted token and parsed metadata") store_session(claims) cookie_session["theme"] = g.schema.json["theme"] cookie_session["survey_title"] = g.schema.json["title"] cookie_session["expires_in"] = get_session_timeout_in_seconds(g.schema) if claims.get("account_service_url"): cookie_session["account_service_url"] = claims.get( "account_service_url") if claims.get("account_service_log_out_url"): cookie_session["account_service_log_out_url"] = claims.get( "account_service_log_out_url") return redirect(url_for("questionnaire.get_questionnaire"))
def test_load_schema_from_metadata_with_survey_url(): load_schema_from_url.cache_clear() metadata = {"survey_url": TEST_SCHEMA_URL, "language_code": "cy"} mock_schema = QuestionnaireSchema({}, language_code="cy") responses.add(responses.GET, TEST_SCHEMA_URL, json=mock_schema.json, status=200) loaded_schema = load_schema_from_metadata(metadata=metadata) assert loaded_schema.json == mock_schema.json assert loaded_schema.language_code == mock_schema.language_code
def setUp(self): super().setUp() # Schema is loaded through metadata self.metadata = { 'eq_id': 'census', 'form_type': 'household', } self.schema = load_schema_from_metadata(self.metadata) self.block_json = self.schema.get_block('household-composition')
def dump_submission(): answer_store = get_answer_store(current_user) metadata = get_metadata(current_user) schema = load_schema_from_metadata(metadata) routing_path = PathFinder(schema, answer_store, metadata).get_routing_path() response = { 'submission': convert_answers(metadata, schema, answer_store, routing_path) } return jsonify(response), 200
def _submit_data(user): answer_store = get_answer_store(user) if answer_store: questionnaire_store = get_questionnaire_store(user.user_id, user.user_ik) answer_store = questionnaire_store.answer_store metadata = questionnaire_store.metadata response_metadata = questionnaire_store.response_metadata progress_store = questionnaire_store.progress_store list_store = questionnaire_store.list_store submitted_at = datetime.now(timezone.utc) schema = load_schema_from_metadata(metadata) router = Router( schema, answer_store, list_store, progress_store, metadata, response_metadata, ) full_routing_path = router.full_routing_path() message = json_dumps( convert_answers( schema, questionnaire_store, full_routing_path, submitted_at, flushed=True, )) encrypted_message = encrypt(message, current_app.eq["key_store"], KEY_PURPOSE_SUBMISSION) sent = current_app.eq["submitter"].send_message( encrypted_message, tx_id=metadata.get("tx_id"), case_id=metadata["case_id"], ) if not sent: raise SubmissionFailedException() get_questionnaire_store(user.user_id, user.user_ik).delete() logger.info("successfully flushed answers") return True logger.info("no answers found to flush") return False
def get_schema_value(self, schema_element): if isinstance(schema_element["value"], dict): if schema_element["value"]["source"] == "metadata": identifier = schema_element["value"].get("identifier") return self.metadata.get(identifier) if schema_element["value"]["source"] == "answers": schema = load_schema_from_metadata(self.metadata) answer_id = schema_element["value"].get("identifier") list_item_id = self.location.list_item_id if self.location else None return get_answer_value( answer_id, self.answer_store, schema, list_item_id=list_item_id ) return schema_element["value"]
def before_request(): values = request.view_args logger.info('questionnaire request', eq_id=values['eq_id'], form_type=values['form_type'], ce_id=values['collection_id'], method=request.method, url_path=request.full_path) metadata = get_metadata(current_user) if metadata: logger.bind(tx_id=metadata['tx_id']) g.schema_json = load_schema_from_metadata(metadata) _check_same_survey(values['eq_id'], values['form_type'], values['collection_id'])
def login(): """ Initial url processing - expects a token parameter and then will authenticate this token. Once authenticated it will be placed in the users session :return: a 302 redirect to the next location for the user """ # logging in again clears any session state if cookie_session: cookie_session.clear() decrypted_token = decrypt_token(request.args.get('token')) validate_jti(decrypted_token) claims = parse_runner_claims(decrypted_token) g.schema = load_schema_from_metadata(claims) schema_metadata = g.schema.json['metadata'] validate_metadata(claims, schema_metadata) eq_id = claims['eq_id'] form_type = claims['form_type'] tx_id = claims['tx_id'] ru_ref = claims['ru_ref'] logger.bind(eq_id=eq_id, form_type=form_type, tx_id=tx_id, ru_ref=ru_ref) logger.info('decrypted token and parsed metadata') store_session(claims) cookie_session['theme'] = g.schema.json['theme'] cookie_session['survey_title'] = g.schema.json['title'] cookie_session['expires_in'] = get_session_timeout_in_seconds(g.schema) if claims.get('account_service_url'): cookie_session['account_service_url'] = claims.get( 'account_service_url') if claims.get('account_service_log_out_url'): cookie_session['account_service_log_out_url'] = claims.get( 'account_service_log_out_url') routing_path = path_finder.get_full_routing_path() completeness = get_completeness(current_user) router = Router(g.schema, routing_path, completeness) next_location = router.get_next_location() return redirect(next_location.url(claims))
def get_questionnaire_store(user_id, user_ik): from app.storage.encrypted_questionnaire_storage import EncryptedQuestionnaireStorage from app.utilities.schema import load_schema_from_metadata # Sets up a single QuestionnaireStore instance per request. store = g.get('_questionnaire_store') if store is None: pepper = current_app.eq['secret_store'].get_secret_by_name( 'EQ_SERVER_SIDE_STORAGE_ENCRYPTION_USER_PEPPER') storage = EncryptedQuestionnaireStorage(user_id, user_ik, pepper) store = g._questionnaire_store = QuestionnaireStore(storage) if store.metadata: # When creating the questionnaire storage, there is no metadata for upgrading schema = load_schema_from_metadata(store.metadata) store.ensure_latest_version(schema) return store
def build_metadata_context(metadata): """ Builds the metadata context using eq claims and schema defined metadata :param metadata: token metadata :return: metadata context """ eq_context = { 'eq_id': json_and_html_safe(metadata['eq_id']), 'collection_id': json_and_html_safe(metadata['collection_exercise_sid']), 'form_type': json_and_html_safe(metadata['form_type']), 'ru_ref': json_and_html_safe(metadata['ru_ref']), 'tx_id': json_and_html_safe(metadata['tx_id']), } schema = load_schema_from_metadata(metadata) eq_context.update(build_schema_metadata(metadata, schema)) return eq_context
def login(): """ Initial url processing - expects a token parameter and then will authenticate this token. Once authenticated it will be placed in the users session :return: a 302 redirect to the next location for the user """ decrypted_token = decrypt_token(request.args.get('token')) metadata = parse_metadata(decrypted_token) eq_id = metadata["eq_id"] form_type = metadata["form_type"] tx_id = metadata["tx_id"] ru_ref = metadata["ru_ref"] logger.bind(eq_id=eq_id, form_type=form_type, tx_id=tx_id, ru_ref=ru_ref) logger.info("decrypted token and parsed metadata") if not eq_id or not form_type: logger.error("missing eq id or form type in jwt") raise NotFound # logging in again clears any session state if session: session.clear() jti_claim = metadata.get('jti') if jti_claim is None: logger.debug('jti claim not provided') else: try: jti_claim_storage = JtiClaimStorage(current_app.eq['database']) jti_claim_storage.use_jti_claim(jti_claim) except JtiTokenUsed as e: raise Unauthorized from e store_session(metadata) json = load_schema_from_metadata(metadata) navigator = PathFinder(json, get_answer_store(current_user), metadata) current_location = navigator.get_latest_location(get_completed_blocks(current_user)) return redirect(current_location.url(metadata))
def test_load_schema_from_metadata_raises_exception_when_no_schema_found( self): metadata = {"eq_id": "123", "form_type": "456"} with self.assertRaises(FileNotFoundError): load_schema_from_metadata(metadata)