def contact(): if request.method == 'POST': name = request.form.get('name') email = request.form.get('email') subject = request.form.get('subject') message = request.form.get('message') if all((name, email, subject, message)): body = "Name: {}\n\nEmail: {}\n\nSubject: {}\n\nMessage:\n{}".format( name, email, subject, message) create_object( Emails( request_id=None, privacy=PRIVATE, to=OPENRECORDS_DL_EMAIL, cc=None, bcc=None, subject=subject, body=body, )) send_contact_email(subject, [OPENRECORDS_DL_EMAIL], body, email) flash('Your message has been sent. We will get back to you.', category='success') else: flash('Cannot send email.', category='danger') error_id = request.args.get('error_id', '') return render_template('main/contact.html', error_id=error_id)
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 remove_point_of_contact(request_id): """ Remove the current point of contact from a given request :param request_id: FOIL request ID """ point_of_contact = get_current_point_of_contact(request_id) set_point_of_contact(request_id, point_of_contact, False) create_object( Events( request_id, current_user.guid, current_user.auth_user_type, event_type.REQ_POINT_OF_CONTACT_REMOVED, previous_value={ "user_guid": point_of_contact.user_guid, "auth_user_type": point_of_contact.auth_user_type, "point_of_contact": "True" }, new_value={ "user_guid": point_of_contact.user_guid, "auth_user_type": point_of_contact.auth_user_type, "point_of_contact": "False" }, timestamp=datetime.utcnow(), ))
def test_get_content_with_token(self): rf = RequestsFactory(self.request_id) response = rf.add_file() valid_token = ResponseTokens(response.id) expired_token = ResponseTokens(response.id, expiration_date=datetime.utcnow()) create_object(valid_token) create_object(expired_token) path = '/response/' + str(response.id) # invalid token (400) resp = self.client.get(path, query_string={'token': 'not_a_real_token'}) self.assertEqual(resp.status_code, 400) # expired token (400) resp = self.client.get(path, query_string={'token': expired_token.token}) self.assertEqual(resp.status_code, 400) self.assertTrue( ResponseTokens.query.filter_by(token=expired_token.token).first() is None) # assert response token has been deleted # valid token (success) resp = self.client.get(path, query_string={'token': valid_token.token}) self.assert_file_sent(resp, rf.request.id, response.name)
def add_file(self, filepath=None, mime_type='text/plain', contents=None, title=None): if filepath is None: filename = str(uuid.uuid4()) filepath = os.path.join(current_app.config['UPLOAD_DIRECTORY'], self.request.id, filename) else: filename = os.path.basename(filepath) self.filepaths.append(filepath) # create an empty file if the specified path does not exist if not fu.exists(filepath): fu.makedirs(os.path.dirname(filepath), exist_ok=True) with open(filepath, 'w') as fp: fp.write(contents or ''.join( random.choice(ascii_letters) for _ in range(random.randrange(100, 500)))) response = Files(self.request.id, PRIVATE, title or filename, filename, mime_type, fu.getsize(filepath), fu.get_hash(filepath)) # TODO: add Events FILE_ADDED create_object(response) return response
def technical_support(): if request.method == 'POST': name = request.form.get('name') email = request.form.get('email') subject = request.form.get('subject') message = request.form.get('message') if all((name, email, subject, message)): body = "Name: {}\n\nEmail: {}\n\nSubject: {}\n\nMessage:\n{}".format( name, email, subject, message) create_object( Emails( request_id=None, privacy=PRIVATE, to=OPENRECORDS_DL_EMAIL, cc=None, bcc=None, subject=subject, body=body, ) ) if current_user.is_agency: send_contact_email(subject, [current_app.config['OPENRECORDS_AGENCY_SUPPORT_DL']], body, email) else: send_contact_email(subject, [OPENRECORDS_DL_EMAIL], body, email) flash('Your message has been sent. We will get back to you.', category='success') else: flash('Cannot send email.', category='danger') error_id = request.args.get('error_id', '') return render_template('main/contact.html', error_id=error_id)
def add_file( self, title=None, filepath=None, name=None, # will be ignored if filepath supplied privacy=response_privacy.PRIVATE, user=None): if filepath is None: filename = name or fake.file_name(extension='txt') filepath = os.path.join(current_app.config["UPLOAD_DIRECTORY"], self.request.id, filename) else: filename = os.path.basename(filepath) if not fu.exists(filepath): fu.makedirs(os.path.dirname(filepath), exist_ok=True) with open(filepath, "w") as fp: fp.write(fake.file_content()) self.__files.append(filepath) response = Files( self.request.id, privacy=privacy, title=title or fake.title(), name=filename, mime_type=fu.get_mime_type(filepath), size=fu.getsize(filepath), hash_=fu.get_hash(filepath), ) create_object(response) self.__create_event(event_type.FILE_ADDED, response, user) return response
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 add_note(self, content=None): response = Notes(self.request.id, PRIVATE, content=content or ''.join( random.choice(ascii_letters) for _ in range(random.randrange(10, 50)))) # TODO: add Events NOTE_ADDED create_object(response) return response
def add_instructions(self, content=None, privacy=response_privacy.PRIVATE, user=None): response = Instructions(self.request.id, privacy, content=content or fake.paragraph()) create_object(response) self.__create_event(event_type.INSTRUCTIONS_ADDED, response, user) return response
def add_note(self, content=None, privacy=response_privacy.PRIVATE, user=None): response = Notes(self.request.id, privacy, content=content or fake.paragraph()) create_object(response) self.__create_event(event_type.NOTE_ADDED, response, user) return response
def test_request_es_doc_not_created(self, es_create_patch): create_object( Requests('FOIL-COT', title="Where's my money Denny?", description="Oh Hi!", agency_ein=54, date_created=datetime.utcnow(), date_submitted=datetime.utcnow(), due_date=datetime.utcnow(), submission=IN_PERSON, status=OVERDUE)) self.assertFalse(es_create_patch.called)
def add_link(self, title=None, url=None, privacy=response_privacy.PRIVATE, user=None): response = Links(self.request.id, privacy, title=title or fake.title(), url=url or fake.url()) create_object(response) self.__create_event(event_type.LINK_ADDED, response, user) return response
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 create_request_info_event(request_id, type_, previous_value, new_value): """ Create and store events object for updating the request information into database. :param request_id: request ID :param type_: event type :param previous_value: previous value :param new_value: new value """ event = Events(request_id=request_id, user_guid=current_user.guid, type_=type_, previous_value=previous_value, new_value=new_value) create_object(event)
def __extend(self, extend_type, new_due_date, user, request_update_data=None, reason=None): assert new_due_date > self.request.due_date request_update_data["due_date"] = new_due_date self.__update(request_update_data) response = Determinations(self.request.id, response_privacy.RELEASE_AND_PUBLIC, extend_type, reason, new_due_date) create_object(response) self.__create_event(extend_type, response, user) return response
def fix_anonymous_requesters(): """ Ensures there is only one anonymous requester per request by creating a new anonymous requester (User) for every User Requests record with a duplicate anonymous requester guid and updates the User Requests record. The new user will be identical to the existing one with the exception of the guid. """ from app.constants import user_type_request from app.request.utils import generate_guid from app.lib.db_utils import create_object, update_object guids = db.engine.execute(""" SELECT user_requests.user_guid AS "GUID" FROM user_requests JOIN users ON user_requests.user_guid = users.guid AND user_requests.auth_user_type = users.auth_user_type WHERE user_requests.request_user_type = 'requester' GROUP BY user_requests.user_guid HAVING COUNT(user_requests.request_id) > 1; """) for guid, in guids: # get all User Requests with dups, excluding the first (since we need to change all but 1) for ur in UserRequests.query.filter_by( user_guid=guid, request_user_type=user_type_request.REQUESTER).offset(1): user = Users.query.filter_by( guid=guid, auth_user_type=user_type_auth.ANONYMOUS_USER).one() new_guid = generate_guid() print("{} -> {}".format(guid, new_guid)) # create new anonymous requester with new guid create_object( Users(guid=new_guid, auth_user_type=user_type_auth.ANONYMOUS_USER, email=user.email, first_name=user.first_name, last_name=user.last_name, title=user.title, organization=user.organization, email_validated=False, terms_of_use_accepted=False, phone_number=user.phone_number, fax_number=user.fax_number, mailing_address=user.mailing_address)) # update user request with new guid update_object({"user_guid": new_guid}, UserRequests, (ur.user_guid, ur.auth_user_type, ur.request_id))
def create_contact_record(request, first_name, last_name, email, subject, message): """ Creates Users, Emails, and Events entries for a contact submission for a request. Sends email with message to all agency users associated with the request. :param request: request object :param first_name: sender's first name :param last_name: sender's last name :param email: sender's email :param subject: subject of email :param message: email body """ if current_user == request.requester: user = current_user else: user = Users(guid=generate_guid(), email=email, first_name=first_name, last_name=last_name, email_validated=False, terms_of_use_accepted=False, is_anonymous_requester=True) create_object(user) create_object( Events(request_id=request.id, user_guid=None, type_=event_type.USER_CREATED, new_value=user.val_for_events)) body = "Name: {} {}\n\nEmail: {}\n\nSubject: {}\n\nMessage:\n{}".format( first_name, last_name, email, subject, message) agency_emails = get_assigned_users_emails(request.id) email_obj = Emails(request.id, PRIVATE, to=','.join([ email.replace('{', '').replace('}', '') for email in agency_emails ]), cc=None, bcc=None, subject=subject, body=body) create_object(email_obj) create_object( Events(request_id=request.id, user_guid=user.guid, type_=event_type.CONTACT_EMAIL_SENT, response_id=email_obj.id, new_value=email_obj.val_for_events)) send_contact_email(subject, agency_emails, message, email)
def remove_point_of_contact(request_id): """ Remove the current point of contact from a given request :param request_id: FOIL request ID """ point_of_contact = get_current_point_of_contact(request_id) set_point_of_contact(request_id, point_of_contact, False) create_object(Events( request_id, current_user.guid, event_type.REQ_POINT_OF_CONTACT_REMOVED, previous_value={"user_guid": point_of_contact.user_guid, "point_of_contact": "True"}, new_value={"user_guid": point_of_contact.user_guid, "point_of_contact": "False"}, timestamp=datetime.utcnow(), ))
def test_get_content_with_token(self): rf = RequestsFactory(self.request_id) response = rf.add_file() valid_token = ResponseTokens(response.id) expired_token = ResponseTokens(response) create_object(valid_token) create_object(expired_token) path = '/response/' + str(response.id) # invalid token (400) resp = self.client.get(path, query_string={'token': 'not_a_real_token'}) self.assertEqual(resp.status_code, 400) # valid token (success) resp = self.client.get(path, query_string={'token': valid_token.token}) self.assert_file_sent(resp, rf.request.id, response.name)
def create_user_request_event(events_type, user_request, old_permissions=None): """ Create an Event for the addition, removal, or updating of a UserRequest """ if old_permissions is not None: previous_value = {"permissions": old_permissions} else: previous_value = None create_object( Events( user_request.request_id, current_user.guid, current_user.auth_user_type, events_type, previous_value=previous_value, new_value=user_request.val_for_events, timestamp=datetime.utcnow(), ))
def create_auth_event(auth_event_type: str, user_guid: str, new_value: dict): """ Create and store event object for given response. Args: auth_event_type (str): one of app.constants.event_type user_guid (Users): Users object performing the authentication event new_value (dict): Value to be stored in events table """ event = Events(request_id=None, user_guid=user_guid, type_=auth_event_type, timestamp=datetime.utcnow(), response_id=None, previous_value=None, new_value=new_value) # store event object create_object(event)
def create_user_request_event(events_type, user_request, old_permissions=None, old_point_of_contact=None, user=current_user): """ Create an Event for the addition, removal, or updating of a UserRequest and insert into the database. Args: events_type (str): event type from the constants defined in constants.event_type. user_request (UserRequests): UserRequests object. old_permissions (int): Value of permissions for the request. user (Users): Users object that represents the user being modified. Returns: Events: The event object representing the change made to the user. """ event = create_user_request_event_object(events_type, user_request, old_permissions, old_point_of_contact, user) create_object( event )
def create_user(self, auth_type, guid=None, agency_ein=None, email=None, first_name=None, last_name=None, title=None, organization=None, phone_number=None, fax_number=None, mailing_address=None, email_validated=True, terms_of_use_accepted=True, is_agency_active=False, is_agency_admin=False): if auth_type == user_type_auth.AGENCY_USER: assert agency_ein is not None else: assert all((agency_ein is None, not is_agency_active, not is_agency_admin)) if auth_type == user_type_auth.ANONYMOUS_USER: email_validated, terms_of_use_accepted = False, False user = Users( guid=guid or self.generate_user_guid(auth_type), auth_user_type=auth_type, agency_ein=agency_ein, email=email or fake.email(), first_name=first_name or fake.first_name(), last_name=last_name or fake.last_name(), title=title or fake.user_title(), organization=organization or fake.organization(), phone_number=phone_number or fake.phone_number(), fax_number=fax_number or fake.fax_number(), mailing_address=mailing_address or fake.mailing_address(), email_validated=email_validated, terms_of_use_accepted=terms_of_use_accepted, is_agency_active=is_agency_active, is_agency_admin=is_agency_admin, ) create_object(user) return user
def create_user_request_event(events_type, user_request, old_permissions=None, user=current_user): """ Create an Event for the addition, removal, or updating of a UserRequest and insert into the database. Args: events_type (str): event type from the constants defined in constants.event_type. user_request (UserRequests): UserRequests object. old_permissions (int): Value of permissions for the request. user (Users): Users object that represents the user being modified. Returns: Events: The event object representing the change made to the user. """ event = create_user_request_event_object(events_type, user_request, old_permissions, user) create_object(event)
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 create_user(auth_type=user_type_auth.PUBLIC_USER_NYC_ID): """ :param auth_type: one of app.constants.user_type_auth """ len_firstname = random.randrange(3, 8) len_lastname = random.randrange(3, 15) firstname = ''.join( random.choice(ascii_lowercase) for _ in range(len_firstname)).title() lastname = ''.join( random.choice(ascii_lowercase) for _ in range(len_lastname)).title() user = Users( guid=generate_user_guid(auth_type), auth_user_type=auth_type, agency_ein=(random.choice([ ein[0] for ein in Agencies.query.with_entities(Agencies.ein).all() ]) if auth_type == user_type_auth.AGENCY_USER else None), first_name=firstname, last_name=lastname, email='{}{}@email.com'.format(firstname[0].lower(), lastname.lower()), email_validated=True, terms_of_use_accepted=True) create_object(user) return user
def patch(agency_ein): """ Only accessible by Super Users Currently only changes: is_active """ if not current_user.is_anonymous and current_user.is_super: is_active = request.form.get('is_active') if is_active is not None and Agencies.query.filter_by( ein=agency_ein).first() is not None: update_object({'is_active': eval_request_bool(is_active)}, Agencies, agency_ein) create_object( Events(request_id=None, user_guid=current_user.guid, auth_user_type=current_user.auth_user_type, type_=AGENCY_ACTIVATED, new_value={"ein": agency_ein}, timestamp=datetime.utcnow())) return '', 200 return '', 400 return '', 403
def __close(self, close_type, user, reason_ids=None): if reason_ids is None: reasons = "|".join( (r.content for r in Reasons.query.filter_by(type=close_type).order_by( func.random()).limit(random.randrange(1, 6)).all())) else: reasons = format_determination_reasons(reason_ids) self.__update({ "status": request_status.CLOSED, "agency_request_summary_release_date": calendar.addbusdays(datetime.utcnow(), RELEASE_PUBLIC_DAYS) }) response = Determinations( self.request.id, response_privacy.RELEASE_AND_PUBLIC, close_type, reasons, ) create_object(response) self.__create_event(event_type.REQ_CLOSED, response, user) return response
def __set_due_soon_or_overdue(self, status, new_due_date, shift_dates): data = {"status": status} if shift_dates: shift = new_due_date - self.request.due_date data.update({ "due_date": new_due_date, "date_submitted": self.request.date_submitted + shift, "date_created": self.request.date_created + shift, "agency_request_summary_release_date": (self.request.agency_request_summary_release_date + shift if self.request.agency_request_summary_release_date else None) }) create_object( Events(self.request.id, user_guid=None, auth_user_type=None, type_=event_type.REQ_STATUS_CHANGED, previous_value={"status": self.request.status}, new_value={"status": status}, response_id=None)) self.__update(data)
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_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 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 update_agency_active_status(agency_ein, is_active): """ Update the active status of an agency. :param agency_ein: String identifier for agency (4 characters) :param is_active: Boolean value for agency active status (True = Active) :return: Boolean value (True if successfully changed active status) """ agency = Agencies.query.filter_by(ein=agency_ein).first() is_valid_agency = agency is not None activate_agency = eval_request_bool(is_active) if is_active is not None and is_valid_agency: update_object( {'is_active': activate_agency}, Agencies, agency_ein ) if activate_agency: create_object( Events( request_id=None, user_guid=current_user.guid, type_=AGENCY_ACTIVATED, previous_value={"ein": agency_ein, "is_active": "False"}, new_value={"ein": agency_ein, "is_active": "True"}, timestamp=datetime.utcnow() ) ) # create request documents for request in agency.requests: request.es_create() return True else: create_object( Events( request_id=None, user_guid=current_user.guid, type_=AGENCY_DEACTIVATED, previous_value={"ein": agency_ein, "is_active": "True"}, new_value={"ein": agency_ein, "is_active": "False"}, timestamp=datetime.utcnow() ) ) # remove requests from index for request in agency.requests: request.es_delete() # deactivate agency users for user in agency.active_users: update_object( {"is_agency_active": "False", "is_agency_admin": "False"}, AgencyUsers, (user.guid, agency_ein) ) create_object( Events( request_id=None, user_guid=current_user.guid, type_=AGENCY_USER_DEACTIVATED, previous_value={"user_guid": user.guid, "ein": agency_ein, "is_active": "True"}, new_value={"user_guid": user.guid, "ein": agency_ein, "is_active": "False"}, timestamp=datetime.utcnow() ) ) return True return False
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 """ # Anonymous users cannot access endpoint if current_user.is_anonymous: return jsonify({'error': 'Anonymous users cannot access this endpoint'}), 403 # Public users cannot access endpoint if current_user.is_public: return jsonify({'error': 'Public users cannot access this endpoint'}), 403 # Unauthenticated users cannot access endpoint if not current_user.is_authenticated: return jsonify({'error': 'User must be authenticated to access endpoint'}), 403 # Retrieve the user user_ = Users.query.filter_by(guid=user_id).one_or_none() # If the user does not exist, return 404 - Not Found if not user_: return jsonify({'error': 'Specified user does not exist.'}), 404 # Gather Form details is_agency_admin = eval_request_bool(request.form.get('is_agency_admin')) if request.form.get('is_agency_admin', None) else None is_agency_active = eval_request_bool(request.form.get('is_agency_active')) if request.form.get('is_agency_active', None) else None is_super = eval_request_bool(request.form.get('is_super')) if request.form.get('is_super', None) else None agency_ein = request.form.get('agency_ein', None) # Checks that apply if user is changing their own profile changing_self = current_user == user_ # Agency User Restrictions (applies to Admins and Regular Users) if user_.is_agency: # Endpoint can only be used for a specific agency if not agency_ein: return jsonify({'error': 'agency_ein must be provided to modify an agency user'}), 400 # Agency must exist and be active to modify users agency = Agencies.query.filter_by(ein=agency_ein).one_or_none() if not agency and agency.is_active: return jsonify({'error': 'Agency must exist in the database and be active'}), 400 if not current_user.is_super: # Current user must belong to agency specified by agency_ein current_user_is_agency_admin = current_user.is_agency_admin(agency.ein) if not current_user_is_agency_admin: return jsonify({'error': 'Current user must belong to agency specified by agency_ein'}), 400 user_in_agency = AgencyUsers.query.filter(AgencyUsers.user_guid == user_.guid, AgencyUsers.agency_ein == agency_ein).one_or_none() if user_in_agency is None: return jsonify({'error': 'User to be modified must belong to agency specified by agency_ein'}), 400 # Non-Agency Admins cannot access endpoint to modify other agency_users if not current_user.is_super and not current_user.is_agency_admin(agency_ein): return jsonify({'error': 'User must be agency admin to modify users'}), 403 # Cannot modify super status when changing agency active or agency admin status if (is_agency_admin or is_agency_active) and is_super: return jsonify({ 'error': 'Cannot modify super status when changing agency active or agency admin status'}), 400 if changing_self: # Super users cannot change their own is_super value if current_user.is_super and is_super: return jsonify({'error': 'Super users cannot change their own `super` status'}), 400 if is_agency_admin: return jsonify({'error': 'Agency Administrators cannot change their administrator permissions'}), 400 elif user_.is_public: if current_user != user_: return jsonify({'error': 'Public user attributes cannot be modified by agency users.'}), 400 elif user_.is_anonymous_requester: ur = current_user.user_requests.filter_by(request_id=user_.anonymous_request.id).one_or_none() if not ur: return jsonify({ 'error': 'Agency users can only modify anonymous requesters for requests where they are assigned.'}), 403 if not ur.has_permission(permission.EDIT_REQUESTER_INFO): return jsonify({'error': 'Current user does not have EDIT_REQUESTER_INFO permission'}), 403 # Gather User Fields user_editable_fields = user_attrs.UserEditableFieldsDict( 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'), address_one=request.form.get('address_one'), address_two=request.form.get('address_two'), zip=request.form.get('zipcode'), city=request.form.get('city'), ) status_field_val = user_attrs.UserStatusDict( 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') ) if changing_self: if not user_editable_fields.is_valid: return jsonify({"error": "Missing contact information."}), 400 else: if user_.is_agency and not status_field_val.is_valid: return jsonify({"error": "User status values invalid"}), 400 # Status Values for Events old_status = {} new_status = {} # User Attributes for Events old_user_attrs = {'_mailing_address': {}} new_user_attrs = {'_mailing_address': {}} for key, value in status_field_val.items(): if value is not None: if key == 'is_agency_admin': cur_val = user_.is_agency_admin(agency_ein) elif key == 'is_agency_active': cur_val = user_.is_agency_active(agency_ein) else: cur_val = getattr(user_, key) new_val = eval_request_bool(status_field_val[key]) if cur_val != new_val: old_status[key] = cur_val new_status[key] = new_val for key, value in user_editable_fields.items(): # Address is a dictionary and needs to be handled separately if key == 'address': for address_key, address_value in value.items(): cur_val = (user_.mailing_address.get(address_key) if user_.mailing_address else None) new_val = address_value if cur_val != new_val: old_user_attrs['_mailing_address'][address_key] = cur_val new_user_attrs['_mailing_address'][address_key] = new_val continue if value is not None: cur_val = getattr(user_, key) new_val = user_editable_fields[key] if cur_val != new_val: old_user_attrs[key] = cur_val new_user_attrs[key] = new_val # Update the Users object if new_user_attrs is not None (empty dict) if new_user_attrs and new_user_attrs.get('_mailing_address') and old_user_attrs: update_object( new_user_attrs, Users, user_id ) # GUID is added to the 'new' value in events to identify the user that was changed new_user_attrs['user_guid'] = user_.guid # 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, 'timestamp': datetime.utcnow() } create_object(Events( type_=(event_type.REQUESTER_INFO_EDITED if user_.is_anonymous_requester else event_type.USER_INFO_EDITED), previous_value=old_user_attrs, new_value=new_user_attrs, **event_kwargs )) if new_status: redis_key = "{current_user_guid}-{update_user_guid}-{agency_ein}-{timestamp}".format( current_user_guid=current_user.guid, update_user_guid=user_.guid, agency_ein=agency_ein, timestamp=datetime.now()) old_status['user_guid'] = user_.guid new_status['user_guid'] = user_.guid old_status['agency_ein'] = agency_ein new_status['agency_ein'] = agency_ein # Update agency active status and create associated event. Occurs first because a user can be # activated / deactivated with admin status set to True. if is_agency_active is not None: update_object( new_status, AgencyUsers, (user_.guid, agency_ein) ) event_kwargs = { 'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None, 'response_id': None, 'user_guid': current_user.guid, 'timestamp': datetime.utcnow() } if is_agency_active: create_object(Events( type_=event_type.AGENCY_USER_ACTIVATED, previous_value=old_status, new_value=new_status, **event_kwargs )) if is_agency_admin is not None and is_agency_admin: make_user_admin.apply_async(args=(user_.guid, current_user.guid, agency_ein), task_id=redis_key) return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200 else: create_object(Events( type_=event_type.AGENCY_USER_DEACTIVATED, previous_value=old_status, new_value=new_status, **event_kwargs )) remove_user_permissions.apply_async( args=(user_.guid, current_user.guid, agency_ein, event_type.AGENCY_USER_DEACTIVATED), task_id=redis_key) return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200 return jsonify({'status': 'success', 'message': 'Agency user successfully updated'}), 200 # Update agency admin status and create associated event. elif is_agency_admin is not None: new_status['agency_ein'] = agency_ein update_object( new_status, AgencyUsers, (user_.guid, agency_ein) ) event_kwargs = { 'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None, 'response_id': None, 'user_guid': current_user.guid, 'timestamp': datetime.utcnow() } if is_agency_admin: create_object(Events( type_=event_type.USER_MADE_AGENCY_ADMIN, previous_value=old_status, new_value=new_status, **event_kwargs )) make_user_admin.apply_async(args=(user_.guid, current_user.guid, agency_ein), task_id=redis_key) return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200 else: create_object(Events( type_=event_type.USER_MADE_AGENCY_USER, previous_value=old_status, new_value=new_status, **event_kwargs )) remove_user_permissions.apply_async( args=(user_.guid, current_user.guid, agency_ein, event_type.USER_MADE_AGENCY_USER), task_id=redis_key) return jsonify({'status': 'success', 'message': 'Update task has been scheduled.'}), 200 # Update user super status and create associated event. elif is_super is not None: new_status['agency_ein'] = agency_ein update_object( new_status, AgencyUsers, (user_.guid, agency_ein) ) event_kwargs = { 'request_id': user_.anonymous_request.id if user_.is_anonymous_requester else None, 'response_id': None, 'user_guid': current_user.guid, 'timestamp': datetime.utcnow() } if is_super: create_object(Events( type_=event_type.USER_MADE_SUPER_USER, previous_value=old_status, new_value=new_status, **event_kwargs )) else: create_object(Events( type_=event_type.USER_REMOVED_FROM_SUPER, previous_value=old_status, new_value=new_status, **event_kwargs )) return jsonify({'status': 'success', 'message': 'Agency user successfully updated'}), 200 # Always returns 200 so that we can use the data from the response in the client side javascript return jsonify({'status': 'Not Modified', 'message': 'No changes detected'}), 200
def _process_user_data(guid, email, first_name, middle_initial, last_name, email_validated, is_nyc_employee, has_nyc_account, active, terms_of_use_accepted, is_anonymous_requester): """ Create or Update an OpenRecords User based on the data received from the SAML Assertion. If no first_name is provided, the mailbox portion of the email will be used e.g. [email protected] -> first_name: jdoe If a user cannot be found using the specified guid and user_type, a second attempt is made with the specified email. NOTE: A user's agency is not determined here. After login, a user's agency supervisor must email us requesting that user be added to the agency. TODO (@joelbcastillo): Add endpoint to add user by email to the Agency on the Agency Administration Page Args: guid (str): The users unique identifier email (str): The users email address first_name (str): The users' first name. If None, then the mailbox part of the email address will be used middle_initial (str): The users' middle initial. Can be None last_name (str): The users' last name. Required. email_validated (bool): Determines whether the users' email has been validated. is_nyc_employee (bool): Determines has_nyc_account, active, terms_of_use_accepted, is_anonymous_requester Returns: Users: The user that was pulled from the database (and updated) or the new user) """ mailbox, _ = email.split('@') if first_name is None: first_name = mailbox user = Users.query.filter_by(guid=guid).first() if user is None: user = find_user_by_email(email) # update or create user if user is not None: _update_user_data( user, guid, email, first_name, middle_initial, last_name, email_validated, is_nyc_employee, has_nyc_account, active, terms_of_use_accepted, is_anonymous_requester ) else: user = Users( guid=guid, email=email, first_name=first_name, middle_initial=middle_initial, last_name=last_name, email_validated=email_validated, is_nyc_employee=is_nyc_employee, has_nyc_account=has_nyc_account, active=active, terms_of_use_accepted=terms_of_use_accepted, is_anonymous_requester=is_anonymous_requester ) create_object(user) return user
def create_contact_record(request, first_name, last_name, email, subject, message): """ Creates Users, Emails, and Events entries for a contact submission for a request. Sends email with message to all agency users associated with the request. :param request: request object :param first_name: sender's first name :param last_name: sender's last name :param email: sender's email :param subject: subject of email :param message: email body """ if current_user == request.requester: user = current_user else: user = Users( guid=generate_guid(), email=email, first_name=first_name, last_name=last_name, email_validated=False, terms_of_use_accepted=False, is_anonymous_requester=True ) create_object(user) create_object(Events( request_id=request.id, user_guid=None, type_=event_type.USER_CREATED, new_value=user.val_for_events )) body = "Name: {} {}\n\nEmail: {}\n\nSubject: {}\n\nMessage:\n{}".format( first_name, last_name, email, subject, message) agency_emails = get_agency_emails(request.id) email_obj = Emails( request.id, PRIVATE, to=','.join([email.replace('{', '').replace('}', '') for email in agency_emails]), cc=None, bcc=None, subject=subject, body=body ) create_object(email_obj) create_object(Events( request_id=request.id, user_guid=user.guid, type_=event_type.CONTACT_EMAIL_SENT, response_id=email_obj.id, new_value=email_obj.val_for_events )) send_contact_email( subject, agency_emails, message, email )
def _update_request_statuses(): """ Update statuses for all requests that are now Due Soon or Overdue and send a notification email to agency admins listing the requests. """ now = datetime.utcnow() due_soon_date = calendar.addbusdays( now, current_app.config['DUE_SOON_DAYS_THRESHOLD'] ).replace(hour=23, minute=59, second=59) # the entire day agencies = Agencies.query.with_entities(Agencies.ein).filter_by(is_active=True).all() for agency_ein, in agencies: requests_overdue = Requests.query.filter( Requests.due_date < now, Requests.status != request_status.CLOSED, Requests.agency_ein == agency_ein ).order_by( Requests.due_date.asc() ).all() requests_due_soon = Requests.query.filter( Requests.due_date > now, Requests.due_date <= due_soon_date, Requests.status != request_status.CLOSED, Requests.agency_ein == agency_ein ).order_by( Requests.due_date.asc() ).all() if not requests_overdue and not requests_due_soon: continue agency_requests_overdue = [] agency_acknowledgments_overdue = [] agency_requests_due_soon = [] agency_acknowledgments_due_soon = [] # OVERDUE for request in requests_overdue: if request.was_acknowledged: agency_requests_overdue.append(request) else: agency_acknowledgments_overdue.append(request) if request.status != request_status.OVERDUE: create_object( Events( request.id, user_guid=None, type_=REQ_STATUS_CHANGED, previous_value={"status": request.status}, new_value={"status": request_status.OVERDUE}, response_id=None, ) ) update_object( {"status": request_status.OVERDUE}, Requests, request.id) # DUE SOON for request in requests_due_soon: if request.was_acknowledged: agency_requests_due_soon.append(request) else: agency_acknowledgments_due_soon.append(request) if request.status != request_status.DUE_SOON: create_object( Events( request.id, user_guid=None, type_=REQ_STATUS_CHANGED, previous_value={"status": request.status}, new_value={"status": request_status.DUE_SOON}, response_id=None, ) ) update_object( {"status": request_status.DUE_SOON}, Requests, request.id) # mail to agency admins for each agency user_emails = list(set(admin.notification_email or admin.email for admin in Agencies.query.filter_by(ein=agency_ein).one().administrators)) send_email( STATUSES_EMAIL_SUBJECT, to=user_emails, template=STATUSES_EMAIL_TEMPLATE, requests_overdue=agency_requests_overdue, acknowledgments_overdue=agency_acknowledgments_overdue, requests_due_soon=agency_requests_due_soon, acknowledgments_due_soon=agency_acknowledgments_due_soon ) email = Emails( request.id, PRIVATE, to=','.join(user_emails), cc=None, bcc=None, subject=STATUSES_EMAIL_SUBJECT, body=render_template( STATUSES_EMAIL_TEMPLATE + ".html", requests_overdue=agency_requests_overdue, acknowledgments_overdue=agency_acknowledgments_overdue, requests_due_soon=agency_requests_due_soon, acknowledgments_due_soon=agency_acknowledgments_due_soon ) ) create_object(email) create_object( Events( request.id, user_guid=None, type_=EMAIL_NOTIFICATION_SENT, previous_value=None, new_value=email.val_for_events, response_id=None, timestamp=datetime.utcnow() ) )
def update_request_statuses(): """ Update statuses for all requests that are now Due Soon or Overdue and send a notification email to agency admins listing the requests. """ with scheduler.app.app_context(): now = datetime.utcnow() due_soon_date = calendar.addbusdays( now, current_app.config['DUE_SOON_DAYS_THRESHOLD']).replace( hour=23, minute=59, second=59) # the entire day requests_overdue = Requests.query.filter( Requests.due_date < now, Requests.status != request_status.CLOSED).order_by( Requests.due_date.asc()).all() requests_due_soon = Requests.query.filter( Requests.due_date > now, Requests.due_date <= due_soon_date, Requests.status != request_status.CLOSED).order_by( Requests.due_date.asc()).all() agencies_to_requests_overdue = {} agencies_to_acknowledgments_overdue = {} agencies_to_requests_due_soon = {} agencies_to_acknowledgments_due_soon = {} def add_to_agencies_to_request_dict(req, agencies_to_request_dict): if req.agency.ein not in agencies_to_request_dict: agencies_to_request_dict[req.agency.ein] = [req] else: agencies_to_request_dict[req.agency.ein].append(req) # OVERDUE for request in requests_overdue: if request.was_acknowledged: add_to_agencies_to_request_dict(request, agencies_to_requests_overdue) else: add_to_agencies_to_request_dict( request, agencies_to_acknowledgments_overdue) if request.status != request_status.OVERDUE: update_object({"status": request_status.OVERDUE}, Requests, request.id) # DUE SOON for request in requests_due_soon: if request.was_acknowledged: add_to_agencies_to_request_dict(request, agencies_to_requests_due_soon) else: add_to_agencies_to_request_dict( request, agencies_to_acknowledgments_due_soon) if request.status != request_status.DUE_SOON: update_object({"status": request_status.DUE_SOON}, Requests, request.id) # get all possible agencies to email agency_eins = set( list(agencies_to_requests_overdue) + list(agencies_to_acknowledgments_overdue) + list(agencies_to_requests_due_soon) + list(agencies_to_acknowledgments_due_soon)) # mail to agency admins for each agency for agency_ein in agency_eins: agency_requests_overdue = agencies_to_requests_overdue.get( agency_ein, []) agency_acknowledgments_overdue = agencies_to_acknowledgments_overdue.get( agency_ein, []) agency_requests_due_soon = agencies_to_requests_due_soon.get( agency_ein, []) agency_acknowledgments_due_soon = agencies_to_acknowledgments_due_soon.get( agency_ein, []) user_emails = list( set(admin.notification_email or admin.email for admin in Agencies.query.filter_by( ein=agency_ein).one().administrators)) send_email( STATUSES_EMAIL_SUBJECT, to=user_emails, template=STATUSES_EMAIL_TEMPLATE, requests_overdue=agency_requests_overdue, acknowledgments_overdue=agency_acknowledgments_overdue, requests_due_soon=agency_requests_due_soon, acknowledgments_due_soon=agency_acknowledgments_due_soon) email = Emails( request.id, PRIVATE, to=','.join(user_emails), cc=None, bcc=None, subject=STATUSES_EMAIL_SUBJECT, body=render_template( STATUSES_EMAIL_TEMPLATE + ".html", requests_overdue=agency_requests_overdue, acknowledgments_overdue=agency_acknowledgments_overdue, requests_due_soon=agency_requests_due_soon, acknowledgments_due_soon=agency_acknowledgments_due_soon)) create_object(email) create_object( Events(request.id, user_guid=None, auth_user_type=None, type_=EMAIL_NOTIFICATION_SENT, previous_value=None, new_value=email.val_for_events, response_id=None, timestamp=datetime.utcnow()))