def get(): if not (jwt.requires_roles(User.EDITOR) or jwt.requires_roles(User.APPROVER)): return jsonify({ "message": "Error: You do not have access to the Name Request queue." }), 403 try: user = User.find_by_jwtToken(g.jwt_oidc_token_info) current_app.logger.debug('find user') if not user: user = User.create_from_jwtToken(g.jwt_oidc_token_info) nr = RequestDAO.get_queued_oldest(user) except SQLAlchemyError as err: # TODO should put some span trace on the error message current_app.logger.error(err.with_traceback(None)) return jsonify({ 'message': 'An error occurred getting the next Name Request.' }), 500 except AttributeError as err: current_app.logger.error(err) return jsonify( {'message': 'There are no Name Requests to work on.'}), 404 return jsonify(nameRequest='{}'.format(nr)), 200
def patch(nr, choice, *args, **kwargs): json_data = request.get_json() if not json_data: return jsonify({'message': 'No input data provided'}), 400 errors = names_schema.validate(json_data, partial=True) if errors: return jsonify(errors), 400 nrd, nrd_name, msg, code = NRNames.common(nr, choice) if not nrd: return msg, code user = User.find_by_jwtToken(g.jwt_oidc_token_info) if not check_ownership(nrd, user): return jsonify({ "message": "You must be the active editor and it must be INPROGRESS" }), 403 names_schema.load(json_data, instance=nrd_name, partial=True) nrd_name.save_to_db() return jsonify( {"message": "Patched {nr} - {json}".format(nr=nr, json=json_data)}), 200
def get_or_create_user_by_jwt(jwt_oidc_token): # GET existing or CREATE new user based on the JWT info try: user = User.find_by_jwtToken(jwt_oidc_token) current_app.logger.debug('finding user: {}'.format(jwt_oidc_token)) if not user: current_app.logger.debug( 'didnt find user, attempting to create new user from the JWT info:{}'.format(jwt_oidc_token)) user = User.create_from_jwtToken(jwt_oidc_token) return user except Exception as err: current_app.logger.error(err.with_traceback(None)) raise ServicesError('unable_to_get_or_create_user', '{"code": "unable_to_get_or_create_user",' '"description": "Unable to get or create user from the JWT, ABORT"}' )
def put(): try: # GET existing or CREATE new user based on the JWT info user = User.find_by_jwtToken(g.jwt_oidc_token_info) if not user: return jsonify({'message': 'Could not find existing user to update settings for.'}), 400 json_input = request.get_json() if not json_input or not json_input.get('searchColumns'): return jsonify({'message': 'Invalid user settings provided in payload.'}), 400 search_columns = '' for column in json_input.get('searchColumns'): if search_columns != '': search_columns += ',' + column else: search_columns += column user.searchColumns = search_columns user.save_to_db() return {}, 204 except Exception as err: current_app.logger.error(f'unable to update user settings: {err.with_traceback(None)}') return jsonify({'message': f'Error updating user settings.'}), 500
def put(nr, *args, **kwargs): # do the cheap check first before the more expensive ones json_input = request.get_json() if not json_input: return jsonify(message='No input data provided'), 400 current_app.logger.debug(json_input) nr_num = json_input.get('nrNum', None) if nr_num and nr_num != nr: return jsonify( message='Data contains a different NR# than this resource' ), 400 state = json_input.get('state', None) if not state: return jsonify({"message": "state not set"}), 406 if state not in State.VALID_STATES: return jsonify({"message": "not a valid state"}), 406 #check user scopes if not (jwt.requires_roles(User.EDITOR) or jwt.requires_roles(User.APPROVER)): raise AuthError( { "code": "Unauthorized", "description": "You don't have access to this resource." }, 403) if (state in (State.APPROVED, State.REJECTED, State.CONDITIONAL))\ and not jwt.requires_roles(User.APPROVER): return jsonify(message='Only Names Examiners can set state: {}'. format(state)), 428 try: nr_d = RequestDAO.find_by_nr(nr) if not nr_d: return jsonify(message='NR not found'), 404 user = User.find_by_jwtToken(g.jwt_oidc_token_info) if not user: user = User.create_from_jwtToken(g.jwt_oidc_token_info) #NR is in a final state, but maybe the user wants to pull it back for corrections if nr_d.stateCd in State.COMPLETED_STATE: if not jwt.requires_roles(User.APPROVER): return jsonify( message= 'Only Names Examiners can alter completed Requests' ), 401 if nr_d.furnished == RequestDAO.REQUEST_FURNISHED: return jsonify( message= 'Request has already been furnished and cannot be altered' ), 409 if state != State.INPROGRESS: return jsonify( message= 'Completed unfurnished Requests can only be set to an INPROGRESS state' ), 400 elif state in State.RELEASE_STATES: if nr_d.userId != user.id or nr_d.stateCd != State.INPROGRESS: return jsonify( message= 'The Request must be INPROGRESS and assigned to you before you can change it.' ), 401 elif nr_d.userId != user.id or nr_d.stateCd != State.INPROGRESS: return jsonify( message= 'The Request must be INPROGRESS and assigned to you before you can change it.' ), 401 # update request header request_header_schema.load(json_input, instance=nr_d, partial=True) nr_d.stateCd = state nr_d.userId = user.id # update applicants applicants_d = nr_d.applicants.one_or_none() if applicants_d: appl = json_input.get('applicants', None) if appl: errm = applicant_schema.validate(appl, partial=False) if errm: return jsonify(errm) applicant_schema.load(appl, instance=applicants_d, partial=False) else: applicants_d.delete_from_db() ### NAMES ### for nrd_name in nr_d.names.all(): for in_name in json_input['names']: if nrd_name.choice == in_name['choice']: errors = names_schema.validate(in_name, partial=False) if errors: return jsonify(errors), 400 names_schema.load(in_name, instance=nrd_name, partial=False) ### END names ### ### COMMENTS ### # we only add new comments, we do not change existing comments # - we can find new comments in json as those with no ID for in_comment in json_input['comments']: is_new_comment = False try: if in_comment['id'] is None or in_comment['id'] == 0: is_new_comment = True except KeyError: is_new_comment = True if is_new_comment and in_comment['comment'] is not None: new_comment = Comment() new_comment.comment = in_comment['comment'] new_comment.examiner = user new_comment.nrId = nr_d.id ### END comments ### ### NWPTA ### for nrd_nwpta in nr_d.partnerNS.all(): for in_nwpta in json_input['nwpta']: if nrd_nwpta.partnerJurisdictionTypeCd == in_nwpta[ 'partnerJurisdictionTypeCd']: errors = nwpta_schema.validate(in_nwpta, partial=False) if errors: return jsonify(errors), 400 nwpta_schema.load(in_nwpta, instance=nrd_nwpta, partial=False) ### END nwpta ### ### Finally save the entire graph nr_d.save_to_db() except ValidationError as ve: return jsonify(ve.messages) except NoResultFound as nrf: # not an error we need to track in the log return jsonify(message='Request:{} not found'.format(nr)), 404 except Exception as err: current_app.logger.error( "Error when replacing NR:{0} Err:{1}".format(nr, err)) return jsonify(message='NR had an internal error'), 500 current_app.logger.debug(nr_d.json()) return jsonify(nr_d.json()), 200
def patch(nr, *args, **kwargs): """ Patches the NR, only STATE can be changed with some business rules around roles/scopes :param nr (str): NameRequest Number in the format of 'NR 000000000' :param args: __futures__ :param kwargs: __futures__ :return: 200 - success; 40X for errors :HEADER: Valid JWT Bearer Token for a valid REALM :JWT Scopes: - USER.APPROVER, USER.EDITOR, USER.VIEWONLY APPROVERS: Can change from almost any state, other than CANCELLED, EXPIRED and ( COMPLETED not yet furnished ) EDITOR: Can't change to a COMPLETED state (ACCEPTED, REJECTED, CONDITION) VIEWONLY: Can't change anything, so that are bounced """ # do the cheap check first before the more expensive ones #check states json_input = request.get_json() if not json_input: return jsonify({'message': 'No input data provided'}), 400 # Currently only state changes are supported by patching # all these checks to get removed to marshmallow state = json_input.get('state', None) if not state: return jsonify({"message": "state not set"}), 406 if state not in State.VALID_STATES: return jsonify({"message": "not a valid state"}), 406 #check user scopes if not (jwt.requires_roles(User.EDITOR) or jwt.requires_roles(User.APPROVER)): raise AuthError( { "code": "Unauthorized", "description": "You don't have access to this resource." }, 403) if (state in (State.APPROVED, State.REJECTED, State.CONDITIONAL))\ and not jwt.requires_roles(User.APPROVER): return jsonify({ "message": "Only Names Examiners can set state: {}".format(state) }), 428 try: nrd = RequestDAO.find_by_nr(nr) if not nrd: return jsonify({"message": "NR not found"}), 404 user = User.find_by_jwtToken(g.jwt_oidc_token_info) if not user: user = User.create_from_jwtToken(g.jwt_oidc_token_info) #NR is in a final state, but maybe the user wants to pull it back for corrections if nrd.stateCd in State.COMPLETED_STATE: if not jwt.requires_roles(User.APPROVER): return jsonify({ "message": "Only Names Examiners can alter completed Requests" }), 401 if nrd.furnished == RequestDAO.REQUEST_FURNISHED: return jsonify({ "message": "Request has already been furnished and cannot be altered" }), 409 if state != State.INPROGRESS: return jsonify({ "message": "Completed unfurnished Requests can only be set to an INPROGRESS state" }), 400 elif state in State.RELEASE_STATES: if nrd.userId != user.id or nrd.stateCd != State.INPROGRESS: return jsonify({ "message": "The Request must be INPROGRESS and assigned to you before you can change it." }), 401 existing_nr = RequestDAO.get_inprogress(user) if existing_nr: existing_nr.stateCd = State.HOLD existing_nr.save_to_db() nrd.stateCd = state nrd.userId = user.id nrd.save_to_db() except NoResultFound as nrf: # not an error we need to track in the log return jsonify({"message": "Request:{} not found".format(nr)}), 404 except Exception as err: current_app.logger.error( "Error when patching NR:{0} Err:{1}".format(nr, err)) return jsonify({"message": "NR had an internal error"}), 404 return jsonify({'message': 'Request:{} - patched'.format(nr)}), 200