def remove_user(self, user, agent=None): """ Un-assign user from request. :param user: user to remove :param agent: user performing this action """ user_request = UserRequests.query.filter_by( user_guid=user.guid, auth_user_type=user.auth_user_type, request_id=self.request.id).one() self.__create_event(event_type.USER_REMOVED, user_request, agent) delete_object(user_request)
def remove_user_request(request_id, user_guid): """ Remove user from request and sends email to all agency administrators and to user being removed. Delete row from UserRequests table and stores event object into Events. :param request_id: FOIL request ID :param user_guid: string guid of user being removed """ user_request = UserRequests.query.options(joinedload( UserRequests.user)).filter_by(user_guid=user_guid, request_id=request_id).one() agency_admin_emails = get_agency_emails(request_id, admins_only=True) request = Requests.query.filter_by(id=request_id).one() agency_name = request.agency.name # send email to agency administrators tmp = safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_removed.html', request_id=request_id, name=' '.join( [user_request.user.first_name, user_request.user.last_name]), agency_name=agency_name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)), admin=True), 'User Removed from Request {}'.format(request_id), to=agency_admin_emails) # send email to user being removed tmp = safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_removed.html', request_id=request_id, name=' '.join( [user_request.user.first_name, user_request.user.last_name]), agency_name=agency_name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id))), 'User Removed from Request {}'.format(request_id), to=[user_request.user.email]) old_permissions = user_request.permissions old_point_of_contact = user_request.point_of_contact create_user_request_event(event_type.USER_REMOVED, user_request, old_permissions, old_point_of_contact) delete_object(user_request) request.es_update()
def remove_user_request(request_id, user_guid): """ Remove user from request and sends email to all agency administrators and to user being removed. Delete row from UserRequests table and stores event object into Events. :param request_id: FOIL request ID :param user_guid: string guid of user being removed """ user_request = UserRequests.query.filter_by(user_guid=user_guid, request_id=request_id).first() agency_admin_emails = get_agency_emails(request_id, admins_only=True) request = Requests.query.filter_by(id=request_id).one() agency_name = request.agency.name # send email to agency administrators tmp = safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_removed.html', request_id=request_id, name=' '.join([user_request.user.first_name, user_request.user.last_name]), agency_name=agency_name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)), admin=True), 'User Removed from Request {}'.format(request_id), to=agency_admin_emails) # send email to user being removed tmp = safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_removed.html', request_id=request_id, name=' '.join([user_request.user.first_name, user_request.user.last_name]), agency_name=agency_name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id))), 'User Removed from Request {}'.format(request_id), to=[user_request.user.email]) old_permissions = user_request.permissions old_point_of_contact = user_request.point_of_contact create_user_request_event(event_type.USER_REMOVED, user_request, old_permissions, old_point_of_contact) delete_object(user_request) request.es_update()
def get_response_content(response_id): """ Currently only supports File Responses. Request Parameters: - token: (optional) ephemeral access token :return: response file contents or redirect to login if user not authenticated and no token provided or 400 error if response/file not found """ response_ = Responses.query.filter_by(id=response_id, deleted=False).one() if response_ is not None and response_.type == FILE: upload_path = os.path.join( current_app.config["UPLOAD_DIRECTORY"], response_.request_id ) filepath_parts = ( upload_path, response_.name ) filepath = os.path.join(*filepath_parts) serving_path = os.path.join( current_app.config['UPLOAD_SERVING_DIRECTORY'], response_.request_id, response_.name ) token = flask_request.args.get('token') if fu.exists(filepath): if response_.is_public: # then we just serve the file, anyone can view it @after_this_request def remove(resp): os.remove(serving_path) return resp return fu.send_file(*filepath_parts, as_attachment=True) else: # check presence of token in url if token is not None: resptok = ResponseTokens.query.filter_by( token=token, response_id=response_id).first() if resptok is not None: if response_.privacy != PRIVATE: @after_this_request def remove(resp): os.remove(serving_path) return resp return fu.send_file(*filepath_parts, as_attachment=True) else: delete_object(resptok) # if token not included, nonexistent, or is expired, but user is logged in if current_user.is_authenticated: # user is agency or is public and response is not private if (((current_user.is_public and response_.privacy != PRIVATE) or current_user.is_agency) # user is associated with request and UserRequests.query.filter_by( request_id=response_.request_id, user_guid=current_user.guid ).first() is not None): @after_this_request def remove(resp): os.remove(serving_path) return resp return fu.send_file(*filepath_parts, as_attachment=True) # user does not have permission to view file return abort(403) else: # redirect to login return redirect(login_url( login_manager.login_view, next_url=url_for('request.view', request_id=response_.request_id) )) return abort(404) # file does not exist
def get_response_content(response_id): """ Currently only supports File Responses. Request Parameters: - token: (optional) ephemeral access token :return: response file contents or redirect to login if user not authenticated and no token provided or 400 error if response/file not found """ response_ = Responses.query.filter_by(id=response_id, deleted=False).one() # if ((current_user.is_authenticated # and current_user not in response_.request.agency_users # and response_.request.requester != current_user) # or flask_request.args.get('token') is None): # return abort(403) if response_ is not None and response_.type == FILE: upload_path = os.path.join( current_app.config["UPLOAD_DIRECTORY"], response_.request_id ) filepath_parts = ( upload_path, response_.name ) filepath = os.path.join(*filepath_parts) serving_path = os.path.join( current_app.config['UPLOAD_SERVING_DIRECTORY'], response_.request_id, response_.name ) token = flask_request.args.get('token') if fu.exists(filepath): if token is not None: resptok = ResponseTokens.query.filter_by( token=token, response_id=response_id).first() if resptok is not None: if (datetime.utcnow() < resptok.expiration_date and response_.privacy != PRIVATE): @after_this_request def remove(resp): os.remove(serving_path) return resp return fu.send_file(*filepath_parts, as_attachment=True) else: delete_object(resptok) else: if current_user.is_authenticated: # user is agency or is public and response is not private if (((current_user.is_public and response_.privacy != PRIVATE) or current_user.is_agency) # user is associated with request and UserRequests.query.filter_by( request_id=response_.request_id, user_guid=current_user.guid, auth_user_type=current_user.auth_user_type ).first() is not None): @after_this_request def remove(resp): os.remove(serving_path) return resp return fu.send_file(*filepath_parts, as_attachment=True) return abort(403) else: # response is release and public # TODO: Responses.is_release_public property if (response_.privacy == RELEASE_AND_PUBLIC and response_.release_date is not None and datetime.utcnow() > response_.release_date): @after_this_request def remove(resp): os.remove(serving_path) return resp return fu.send_file(*filepath_parts, as_attachment=True) else: return redirect(url_for( 'auth.login', return_to_url=url_for('request.view', request_id=response_.request_id) )) # TODO: restore after saml/oauth implementation # return redirect(url_for( # 'auth.index', # sso2=True, # return_to=flask_request.base_url)) return abort(404)
def patch(user_id): """ Request Parameters: - title - organization - email - phone_number - fax_number - mailing_address - is_super - is_agency_active - is_agency_admin (Mailing Address) - zip - city - state - address_one - address_two Restrictions: - Anonymous Users - cannot access this endpoint - Agency Administrators - cannot change their agency status - can only update the agency status of users within their agency - cannot change any super user status - Super Users - cannot change their super user status - Agency Users - cannot change any user except for themselves or *anonymous* requesters for requests they are assigned to - cannot change super user or agency status - Public Users - can only update themselves - cannot change super user or agency status """ if not current_user.is_anonymous: # attempt to parse user_id and find user try: guid, auth_type = user_id.split(USER_ID_DELIMITER) user_ = Users.query.filter_by(guid=guid, auth_user_type=auth_type).one() except (ValueError, NoResultFound, MultipleResultsFound): return jsonify({}), 404 agency_ein = request.form.get('agency_ein', None) if agency_ein is None and not (auth_type == user_type_auth.ANONYMOUS_USER or 'is_super' in request.form): return jsonify({}), 404 updating_self = current_user == user_ current_user_is_agency_user = ( current_user.is_agency and not current_user.is_super and not current_user.is_agency_admin(agency_ein) and current_user.is_agency_active(agency_ein)) current_user_is_agency_admin = ( current_user.is_agency and not current_user.is_super and current_user.is_agency_admin(agency_ein) and current_user.is_agency_active(agency_ein)) same_agency = agency_ein in [ agency.ein for agency in current_user.agencies.all() ] associated_anonymous_requester = ( user_.is_anonymous_requester and current_user.user_requests.filter_by( request_id=user_.anonymous_request.id).first() is None) is_agency_admin = request.form.get('is_agency_admin') is_agency_active = request.form.get('is_agency_active') is_super = request.form.get('is_super') changing_status = any((is_agency_active, is_agency_admin, is_super)) rform_copy = dict(request.form) try: rform_copy.pop('is_agency_admin') rform_copy.pop('is_agency_active') rform_copy.pop('agency_ein') changing_more_than_agency_status = len(rform_copy) != 0 except KeyError: changing_more_than_agency_status = False # VALIDATE if (( updating_self and ( # super user attempting to change their own super status (current_user.is_super and is_super is not None) or # agency admin or public user attempting to change their own agency/super status (changing_status and (current_user_is_agency_admin or current_user.is_public)))) or (not updating_self and ( # public user attempting to change another user current_user.is_public or # agency user attempting to change a agency/super status (current_user_is_agency_user and changing_status) or # agency user attempting to change a user that is not an anonymous requester # for a request they are assigned to (current_user_is_agency_user and (not user_.is_anonymous_requester or not associated_anonymous_requester)) or # agency admin attempting to change another user that is not in the same agency or # attempting to change more than just the agency status of a user (current_user_is_agency_admin and not (associated_anonymous_requester or user_.is_anonymous_requester) and (not same_agency or changing_more_than_agency_status)) or # agency admin attempting to change an anonymous requester for a request # they are not assigned to (current_user_is_agency_admin and associated_anonymous_requester)))): return jsonify({}), 403 # UPDATE user_fields = [ 'email', 'phone_number', 'fax_number', 'title', 'organization' ] status_fields = ['is_agency_admin', 'is_agency_active', 'is_super'] address_fields = ['zip', 'city', 'state', 'address_one', 'address_two'] user_field_val = { 'email': request.form.get('email'), 'phone_number': request.form.get('phone'), 'fax_number': request.form.get('fax'), 'title': request.form.get('title'), 'organization': request.form.get('organization'), } status_field_val = { 'is_agency_admin': request.form.get('is_agency_admin'), 'is_agency_active': request.form.get('is_agency_active'), 'is_super': request.form.get('is_super') } address_field_val = { 'address_one': request.form.get('address_one'), 'address_two': request.form.get('address_two'), 'zip': request.form.get('zipcode'), 'city': request.form.get('city'), 'state': request.form.get('state') } # check if missing contact information if (user_field_val['email'] == '' and user_field_val['phone_number'] == '' and user_field_val['fax_number'] == '' and (address_field_val['city'] == '' or address_field_val['zip'] == '' or address_field_val['state'] == '' or address_field_val['address_one'] == '')): return jsonify({"error": "Missing contact information."}), 400 old = {} old_address = {} new = {} new_address = {} for field in status_fields: if status_field_val[field] is not None: if field == 'is_agency_admin': cur_val = user_.is_agency_admin(agency_ein) elif field == 'is_agency_active': cur_val = user_.is_agency_active(agency_ein) else: cur_val = getattr(user_, field) new_val = eval_request_bool(status_field_val[field]) if cur_val != new_val: old[field] = cur_val new[field] = new_val for field in user_fields: val = user_field_val[field] if val is not None: if val == '': user_field_val[ field] = None # null in db, not empty string cur_val = getattr(user_, field) new_val = user_field_val[field] if cur_val != new_val: old[field] = cur_val new[field] = new_val for field in address_fields: val = address_field_val[field] if val is not None: if val == '': address_field_val[field] = None cur_val = (user_.mailing_address.get(field) if user_.mailing_address else None) new_val = address_field_val[field] if cur_val != new_val: old_address[field] = cur_val new_address[field] = new_val if new or new_address: # in spite of not changing, the guid and auth type of # the user being updated is added to Events.new_value # in order to identify this user new['user_guid'] = user_.guid new['auth_user_type'] = user_.auth_user_type if new_address: new['mailing_address'] = new_address if old_address: old['mailing_address'] = old_address if ('is_agency_admin' in new) or ('is_agency_active' in new): new['agency_ein'] = agency_ein update_object(new, AgencyUsers, (guid, auth_type, agency_ein)) else: update_object(new, Users, (guid, auth_type)) # create event(s) event_kwargs = { 'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None, 'response_id': None, 'user_guid': current_user.guid, 'auth_user_type': current_user.auth_user_type, 'timestamp': datetime.utcnow() } if changing_status: new_statuses = {} old_statuses = {} for field in status_fields: if new.get(field) is not None: new_statuses[field] = new.pop(field) old_statuses[field] = old.pop(field) # TODO: a better way to store user identifiers (than in the value columns) new_statuses['user_guid'] = user_.guid new_statuses['auth_user_type'] = user_.auth_user_type new_statuses['agency_ein'] = agency_ein is_agency_active = new_statuses.get('is_agency_active') is_agency_admin = new_statuses.get('is_agency_admin') if is_agency_active is not None and not is_agency_active: # remove ALL UserRequests for user_request in user_.user_requests.all(): create_user_request_event(event_type.USER_REMOVED, user_request) delete_object(user_request) elif is_agency_admin is not None: def set_permissions_and_create_event(user_req, perms): """ Set permissions for a user request and create a 'user_permissions_changed' Event. :param user_req: user request :param perms: permissions to set for user request """ old_permissions = user_req.permissions user_request.set_permissions(perms) create_user_request_event(event_type.USER_PERM_CHANGED, user_req, old_permissions) if is_agency_admin: permissions = Roles.query.filter_by( name=role_name.AGENCY_ADMIN).one().permissions # create UserRequests for ALL existing requests under user's agency where user is not assigned # for where the user *is* assigned, only change the permissions for req in user_.agencies.filter_by( ein=agency_ein).one().requests: user_request = UserRequests.query.filter_by( request_id=req.id, user_guid=user_.guid, auth_user_type=user_.auth_user_type).first() if user_request is None: user_request = UserRequests( user_guid=user_.guid, auth_user_type=user_.auth_user_type, request_id=req.id, request_user_type=user_type_request.AGENCY, permissions=permissions) create_object(user_request) create_user_request_event( event_type.USER_ADDED, user_request) else: set_permissions_and_create_event( user_request, permissions) else: # update ALL UserRequests (strip user of permissions) for user_request in user_.user_requests.all(): set_permissions_and_create_event( user_request, permission.NONE) # TODO: single email detailing user changes? create_object( Events(type_=event_type.USER_STATUS_CHANGED, previous_value=old_statuses, new_value=new_statuses, **event_kwargs)) if old: # something besides status changed ('new' holds user guid and auth type) create_object( Events(type_=(event_type.REQUESTER_INFO_EDITED if user_.is_anonymous_requester else event_type.USER_INFO_EDITED), previous_value=old, new_value=new, **event_kwargs)) return jsonify({}), 200 else: return jsonify({"message": "No changes detected."}), 200 return jsonify({}), 403