def _create_agency_user_requests(request_id, agency_admins, guid_for_event): """ Creates user_requests entries for agency administrators. :param request_id: Request being created :param agency_users: List of Users :param guid_for_event: guid used to create request events :return: """ for admin in agency_admins: user_request = UserRequests( user_guid=admin.guid, request_user_type=user_type_request.AGENCY, request_id=request_id, permissions=Roles.query.filter_by( name=role.AGENCY_ADMIN).first().permissions) create_object(user_request) create_object( Events(request_id, guid_for_event, event_type.USER_ADDED, previous_value=None, new_value=user_request.val_for_events, response_id=None, timestamp=datetime.utcnow()))
def create_requests_search_set(requester, other_requester): """ Generate 216 unique requests. Every combination of title content, description content, agency description content, title privacy, agency description privacy, and requester is guaranteed to be unique. """ agency_eins = [ ein[0] for ein in Agencies.query.with_entities(Agencies.ein).all() ] for title_private, agency_request_summary_private, is_requester in product( range(2), repeat=3): for title, description, agency_request_summary in product( ("foo", "bar", "qux"), repeat=3): agency_ein = random.choice(agency_eins) date_created = get_random_date(datetime(2015, 1, 1), datetime(2016, 1, 1)) date_submitted = get_following_date(date_created) # TODO: use rf = RequestsFactory() request = Requests(generate_request_id(agency_ein), title=title, description=description, agency_ein=agency_ein, date_created=date_created, date_submitted=date_submitted, due_date=get_due_date(date_submitted, ACKNOWLEDGMENT_DAYS_DUE, 'US/Eastern'), submission=submission_methods.DIRECT_INPUT, status=random.choice( (request_status.OPEN, request_status.CLOSED, request_status.OVERDUE, request_status.IN_PROGRESS, request_status.DUE_SOON)), privacy={ 'title': bool(title_private), 'agency_request_summary': bool(agency_request_summary_private) }) request.agency_request_summary = agency_request_summary create_object(request) user_request = UserRequests( user_guid=(requester.guid if is_requester else other_requester.guid), auth_user_type=(requester.auth_user_type if is_requester else other_requester.auth_user_type), request_id=request.id, request_user_type=user_type_request.REQUESTER, permissions=11) create_object(user_request)
def __init__(self, request_id=None, clean=True): """ :param request_id: request FOIL id :param clean: reset data? """ self.clean = clean date_created = datetime.utcnow() date_submitted = get_following_date(date_created) agency_ein = '0860' self.request = Requests( request_id or generate_request_id(agency_ein), title="I would like my vital essence.", description="Someone has taken my vital essence " "and I would like it back.", agency_ein=agency_ein, date_created=date_created, date_submitted=date_submitted, due_date=get_due_date(date_submitted, ACKNOWLEDGMENT_DAYS_DUE), submission=submission_methods.DIRECT_INPUT, status=request_status.OPEN) create_object(self.request) self.requester = Users( guid=generate_user_guid(user_type_auth.PUBLIC_USER_NYC_ID), auth_user_type=user_type_auth.PUBLIC_USER_NYC_ID, agency_ein=agency_ein, first_name='Jane', last_name='Doe', email='*****@*****.**', email_validated=True, terms_of_use_accepted=True, title='The Janest') create_object(self.requester) self.user_request = UserRequests( user_guid=self.requester.guid, auth_user_type=self.requester.auth_user_type, request_id=self.request.id, request_user_type=user_type_request.REQUESTER, permissions=Roles.query.filter_by( name=PUBLIC_REQUESTER).first().permissions) create_object(self.user_request)
def add_user(self, user, permissions=None, role=None, agent=None): """ Assign user to request. If a role is not supplied, one will be provided and permissions will be set based on the user's status: anonymous role_name.ANONYMOUS public role_name.PUBLIC_REQUESTER agency admin role_name.AGENCY_ADMIN agency user role_name.AGENCY_OFFICER agency inactive role_name.AGENCY_HELPER :param user: user to add :param permissions: permissions to grant to user :param role: role from which to retrieve permissions to grant to user :param agent: user performing this action :return: created UserRequests object """ if role is None and permissions is None: if user.auth_user_type == user_type_auth.ANONYMOUS_USER: role = role_name.ANONYMOUS elif user.auth_user_type in user_type_auth.PUBLIC_USER_TYPES: role = role_name.PUBLIC_REQUESTER elif user.auth_user_type == user_type_auth.AGENCY_USER: if user.is_agency_active: role = role_name.AGENCY_ADMIN if user.is_agency_admin else role_name.AGENCY_OFFICER else: role = role_name.AGENCY_HELPER permissions = permissions or Roles.query.filter_by( name=role).one().permissions user_request = UserRequests( user_guid=user.guid, auth_user_type=user.auth_user_type, request_id=self.request.id, request_user_type=user_type_request.AGENCY if user.is_agency else user_type_request.REQUESTER, permissions=permissions) create_object(user_request) self.__create_event(event_type.USER_ADDED, user_request, agent) return user_request
def add_user_request(request_id, user_guid, permissions, point_of_contact): """ Create a users permissions entry for a request and notify all agency administrators and the user that the permissions have changed. :param request_id: FOIL request ID :param user_guid: string guid of the user being edited :param permissions: Updated permissions values {'permission': true} :param point_of_contact: boolean value to set user as point of contact or not """ user_request = UserRequests.query.filter_by(user_guid=user_guid, request_id=request_id).first() agency_name = Requests.query.filter_by(id=request_id).one().agency.name if user_request: raise UserRequestException(action="create", request_id=request_id, reason="UserRequest entry already exists.") user = Users.query.filter_by(guid=user_guid).one() agency_admin_emails = get_agency_emails(request_id, admins_only=True) added_permissions = [] for i, val in enumerate(permission.ALL): if i in permissions: added_permissions.append(val) # send email to agency administrators safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_added.html', request_id=request_id, name=user.name, agency_name=agency_name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)), added_permissions=[capability.label for capability in added_permissions], admin=True), 'User Added to Request {}'.format(request_id), to=agency_admin_emails) # send email to user being added safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_added.html', request_id=request_id, name=user.name, agency_name=agency_name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)), added_permissions=[capability.label for capability in added_permissions], ), 'User Added to Request {}'.format(request_id), to=[user.notification_email or user.email]) if point_of_contact and has_point_of_contact(request_id): remove_point_of_contact(request_id) user_request = UserRequests( user_guid=user.guid, request_id=request_id, request_user_type=user_type_request.AGENCY, permissions=0, point_of_contact=point_of_contact ) create_object(user_request) if added_permissions: user_request.add_permissions([capability.value for capability in added_permissions]) user_request.request.es_update() create_user_request_event(event_type.USER_ADDED, user_request)
def add_user_request(request_id, user_guid, permissions, point_of_contact): """ Create a users permissions entry for a request and notify all agency administrators and the user that the permissions have changed. :param request_id: FOIL request ID :param user_guid: string guid of the user being edited :param permissions: Updated permissions values {'permission': true} :param point_of_contact: boolean value to set user as point of contact or not """ user_request = UserRequests.query.filter_by(user_guid=user_guid, request_id=request_id).first() agency = Requests.query.filter_by(id=request_id).one().agency if user_request: raise UserRequestException(action="create", request_id=request_id, reason="UserRequest entry already exists.") user = Users.query.filter_by(guid=user_guid).one() agency_admin_emails = get_agency_admin_emails(agency) added_permissions = [] for i, val in enumerate(permission.ALL): if i in permissions: added_permissions.append(val) # send email to agency administrators safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_added.html', request_id=request_id, name=user.name, agency_name=agency.name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)), added_permissions=[ capability.label for capability in added_permissions ], admin=True), 'User Added to Request {}'.format(request_id), to=agency_admin_emails) # send email to user being added safely_send_and_add_email( request_id, render_template( 'email_templates/email_user_request_added.html', request_id=request_id, name=user.name, agency_name=agency.name, page=urljoin(flask_request.host_url, url_for('request.view', request_id=request_id)), added_permissions=[ capability.label for capability in added_permissions ], ), 'User Added to Request {}'.format(request_id), to=[user.notification_email or user.email]) if point_of_contact and has_point_of_contact(request_id): remove_point_of_contact(request_id) user_request = UserRequests(user_guid=user.guid, request_id=request_id, request_user_type=user_type_request.AGENCY, permissions=0, point_of_contact=point_of_contact) create_object(user_request) if added_permissions: user_request.add_permissions( [capability.value for capability in added_permissions]) user_request.request.es_update() create_user_request_event(event_type.USER_ADDED, user_request)
def create_request(title, description, category, tz_name, agency_ein=None, first_name=None, last_name=None, submission=DIRECT_INPUT, agency_date_submitted_local=None, email=None, user_title=None, organization=None, phone=None, fax=None, address=None, upload_path=None, custom_metadata=None): """ Creates a new FOIL Request and associated Users, UserRequests, and Events. :param title: request title :param description: detailed description of the request :param tz_name: client's timezone name :param agency_ein: agency_ein selected for the request :param first_name: first name of the requester :param last_name: last name of the requester :param submission: request submission method :param agency_date_submitted_local: submission date chosen by agency :param email: requester's email address :param user_title: requester's organizational title :param organization: requester's organization :param phone: requester's phone number :param fax: requester's fax number :param address: requester's mailing address :param upload_path: file path of the validated upload :param custom_metadata: JSON containing all data from custom request forms """ # 1. Generate the request id request_id = generate_request_id(agency_ein) # 2a. Generate Email Notification Text for Agency # agency_email = generate_email_template('agency_acknowledgment.html', request_id=request_id) # 2b. Generate Email Notification Text for Requester # 3a. Send Email Notification Text for Agency # 3b. Send Email Notification Text for Requester # 4a. Calculate Request Submitted Date (Round to next business day) date_created_local = utc_to_local(datetime.utcnow(), tz_name) if current_user.is_agency: date_submitted_local = agency_date_submitted_local else: date_submitted_local = date_created_local # 4b. Calculate Request Due Date (month day year but time is always 5PM, 5 Days after submitted date) due_date = get_due_date(date_submitted_local, ACKNOWLEDGMENT_PERIOD_LENGTH, tz_name) date_created = local_to_utc(date_created_local, tz_name) date_submitted = local_to_utc(date_submitted_local, tz_name) # 5. Create Request request = Requests(id=request_id, title=title, agency_ein=agency_ein, category=category, description=description, date_created=date_created, date_submitted=date_submitted, due_date=due_date, submission=submission, custom_metadata=custom_metadata) create_object(request) guid_for_event = current_user.guid if not current_user.is_anonymous else None # 6. Get or Create User if current_user.is_public: user = current_user else: user = Users(guid=generate_guid(), email=email, first_name=first_name, last_name=last_name, title=user_title or None, organization=organization or None, email_validated=False, terms_of_use_accepted=False, phone_number=phone, fax_number=fax, mailing_address=address, is_anonymous_requester=True) create_object(user) # user created event create_object( Events(request_id, guid_for_event, event_type.USER_CREATED, previous_value=None, new_value=user.val_for_events, response_id=None, timestamp=datetime.utcnow())) if upload_path is not None: # 7. Move file to upload directory upload_path = _move_validated_upload(request_id, upload_path) # 8. Create response object filename = os.path.basename(upload_path) response = Files(request_id, RELEASE_AND_PRIVATE, filename, filename, fu.get_mime_type(upload_path), fu.getsize(upload_path), fu.get_hash(upload_path), is_editable=False) create_object(obj=response) # 8. Create upload Event upload_event = Events(user_guid=user.guid, response_id=response.id, request_id=request_id, type_=event_type.FILE_ADDED, timestamp=datetime.utcnow(), new_value=response.val_for_events) create_object(upload_event) # Create response token if requester is anonymous if current_user.is_anonymous or current_user.is_agency: create_object(ResponseTokens(response.id)) role_to_user = { role.PUBLIC_REQUESTER: user.is_public, role.ANONYMOUS: user.is_anonymous_requester, } role_name = [k for (k, v) in role_to_user.items() if v][0] # (key for "truthy" value) # 9. Create Event timestamp = datetime.utcnow() event = Events(user_guid=user.guid if current_user.is_anonymous else current_user.guid, request_id=request_id, type_=event_type.REQ_CREATED, timestamp=timestamp, new_value=request.val_for_events) create_object(event) if current_user.is_agency: agency_event = Events(user_guid=current_user.guid, request_id=request.id, type_=event_type.AGENCY_REQ_CREATED, timestamp=timestamp) create_object(agency_event) # 10. Create UserRequest for requester user_request = UserRequests( user_guid=user.guid, request_user_type=user_type_request.REQUESTER, request_id=request_id, permissions=Roles.query.filter_by(name=role_name).first().permissions) create_object(user_request) create_object( Events(request_id, guid_for_event, event_type.USER_ADDED, previous_value=None, new_value=user_request.val_for_events, response_id=None, timestamp=datetime.utcnow())) # 11. Create the elasticsearch request doc only if agency has been onboarded agency = Agencies.query.filter_by(ein=agency_ein).one() # 12. Add all agency administrators to the request. if agency.administrators: # b. Store all agency users objects in the UserRequests table as Agency users with Agency Administrator # privileges _create_agency_user_requests(request_id=request_id, agency_admins=agency.administrators, guid_for_event=guid_for_event) # 13. Add all parent agency administrators to the request. if agency != agency.parent: if (agency.parent.agency_features is not None and agency_ein in agency.parent.agency_features.get( 'monitor_agency_requests', []) and agency.parent.is_active and agency.parent.administrators): _create_agency_user_requests( request_id=request_id, agency_admins=agency.parent.administrators, guid_for_event=guid_for_event) # (Now that we can associate the request with its requester AND agency users.) if current_app.config['ELASTICSEARCH_ENABLED'] and agency.is_active: request.es_create() return request_id
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