async def put_filing( filing_type: str, filing_id: str, payload: UpdateFilingInProgress, user: User = Depends(get_active_user), db_session: Session = Depends(get_db), ): try: if not is_uuid(filing_id): raise Http400("Filing ID must be UUID") print(payload.form) if payload.form['filing_id'] != filing_id: raise Http400("Filing ID mismatch.") if filing_type not in ['ec601', 'ec602', 'ec603', 'ec604', 'ec605']: raise Http400("Unknown filing type!") # user must be filer if user.account_type != 'filer': raise AccountPermissionException() filing = await get_filing_by_id(db_session, filing_id) if filing is None: raise Http400(detail="Filing not found") # user must be associated with this lobbying entity id entity = await get_lobbying_entity_by_id(db_session, filing.entity_id) if entity is None: raise EntityNotFoundException() filer = await get_lobbyist_filer_user(db_session, entity, user) if filer is None: raise AccountPermissionException() if filing.status not in ['new', 'in progress']: if filing.status == 'locked': raise Http400(detail="Filing is locked.") else: raise Http400(detail="Filing cannot be edited") if filing.filing_type != filing_type: raise Http400(detail="Filing doesn't match filing type.") await update_filing_in_progress(db_session, filing, payload) return {"success": True} except AccountPermissionException as e: # we don't log this raise except EntityNotFoundException as e: # we don't log this raise except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def create_filing( filing_type: str, payload: NewLobbyistFiling, user: User = Depends(get_active_user), db_session: Session = Depends(get_db), ): try: # user must be filer if user.account_type != 'filer': raise AccountPermissionException() if filing_type.strip() != payload.filing_type: raise Http400("Filing types in params and payload dont' match!") if payload.amends_id is not None: if not is_uuid(payload.amends_id): raise Http400(detail="Amends ID must be UUID or null.") filing = await get_filing_by_id(db_session, payload.amends_id) if filing is None: raise Http400(detail="Filing to be amended not found.") # user must be associated with this lobbying entity id entity = await get_lobbying_entity_by_id(db_session, payload.lobbying_entity_id) if entity is None: raise EntityNotFoundException() filer = await get_lobbyist_filer_user(db_session, entity, user) if filer is None: raise AccountPermissionException() # generate a unique id for this model filing_id = str(uuid.uuid4()) # at this point we have established that the account is authorized # further protections we need # no new 601/602 for a year in which a previous exists # no new 603/604/605 for a Q for which one exists # if a form belonging to a different lobbyist types is # filed, upon filing (not upon creating) the lobbyist becomes # also the new type res = await create_new_lobbyist_filing(db_session, filing_id, entity, filer, payload) return {"success": True, "filing_id": filing_id} except AccountPermissionException as e: # we don't log this raise except EntityNotFoundException as e: # we don't log this raise except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def filer_search( search_str: str, user: User = Depends(get_active_admin_user), db_session: Session = Depends(get_db), ): # ultimate: # last name, # org name # org id # filer id try: data = [] if len(search_str) > 1: # this is preliminary data = await get_all_filer_ids_by_start_of_last_name( db_session, search_str ) return {"success": True, "data": data} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def refresh(user: User = Depends(get_active_user_from_cookie), Authorize: AuthJWT = Depends()): try: # set the user group if user.account_type == 'admin': user_claims = {'admin': True} admin_logger.info(f"Admin refresh token: {user.email}") elif user.account_type == 'filer': user_claims = {'filer': True} user_logger.info(f"User refresh token: {user.email}") elif user.account_type == 'public': user_claims = {'public': True} user_logger.info(f"Public refresh token: {user.email}") access_token = Authorize.create_access_token(subject=user.email, user_claims=user_claims) refresh_token = Authorize.create_refresh_token(subject=user.email, user_claims=user_claims) Authorize.set_refresh_cookies(refresh_token) return {"success": True, "access_token": access_token} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def get_document_metadata( doc_id: str = None, filing_id: str = None, db_session: Session = Depends(get_db), ): try: if doc_id is None and filing_id is None: raise Http400("A document id or filing id must be provided.") if doc_id is not None: metadata = await get_metadata(db_session, doc_id) return {"success": "true", "data": metadata} else: # need to make this into its own function original_filing = await get_filing_by_id(db_session, filing_id) original_filing_json = jsonable_encoder(original_filing) if len(original_filing_json) == 0: raise Http404("Filing document was not found.") doc_id = original_filing_json["doc_public"] # up to here metadata = await get_metadata(db_session, doc_id) return {"success": "true", "data": metadata} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def admin_saml_metadata(): # the IDP may ask us about our metatadata try: return PlainTextResponse(SAML_SP_METADATA_FILER) except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def set_reset_password( payload: UserResetPassword, db_session: Session = Depends(get_db), ): try: res = await set_user_password(db_session, payload) return {"success": res} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def register_lobbyist_confirm_email( req: Request, token: Token, db_session: Session = Depends(get_db), ): try: res = await register_lobbyist_check_email_confirm(db_session, token) return res except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def get_open_tasks( user: User = Depends(get_active_admin_user), db_session: Session = Depends(get_db), ): try: res = await get_all_open_admin_tasks(db_session) res = jsonable_encoder(res) return {"success": True, "data": res} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def read_users_me( user: User = Depends(get_active_user), db_session: Session = Depends(get_db), ): try: user_dict = jsonable_encoder(user) del user_dict['password_hash'] return {"user": user_dict} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def filer_info(payload: FilerContactInfoSchema, user: User = Depends(get_active_user), db_session: Session = Depends(get_db)): try: # user must be filer if user.account_type != 'filer': raise AccountPermissionException() filer = await get_filer_by_user_id(db_session, user.id) if filer is None: raise AccountPermissionException() # get filer types ftypes = [x.filer_type for x in filer.filer_types] # blocker filer types blockers = ['candidate', 'campaign'] blocked = False for blocker in blockers: if blocker in ftypes: blocked = True break if blocked: raise Http400("Filer cannot change contact info. "\ "Please contact City Clerk's Office.") if payload.effective_date is None or not is_valid_date( payload.effective_date): payload.effective_date = today() res = await update_filer_contact_info(db_session, filer, payload) if res: user.first_name = payload.first_name user.last_name = payload.last_name user.middle_name = payload.middle_name db_session.commit() return {"success": res} except AccountPermissionException as e: # we don't log this raise except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e) return None
async def search( query: str, start_date: str = None, end_date: str = None, db_session: Session = Depends(get_db), ): try: if query is None: raise Http400("Search cannot be empty.") # get filers that match query by last name filings = await get_all_filings(db_session, query, start_date, end_date) lobbyist_filings = await get_all_lobbyist_filings( db_session, query, start_date, end_date) if len(filings) == 0 and len(lobbyist_filings) == 0: return {"success": "true", "data": []} for filing in filings: filing["description"] = ( FILING_TYPE_DESCRIPTION[filing["filing_type"]] + "; " + filing["filing_subtype"]) filing["filing_type"] = FILING_TYPE_MAPPING[filing["filing_type"]] if filing["doc_public"] == None: # filing not electronically filed filing["filing_type"] += "; Not electronically filed." filing["filer"] = filing["last_name"] + ", " + filing["first_name"] for lobbyist in lobbyist_filings: lobbyist["description"] = FILING_TYPE_DESCRIPTION[ lobbyist["filing_type"]] lobbyist["filing_type"] = FILING_TYPE_MAPPING[ lobbyist["filing_type"]] if lobbyist["doc_public"] == None: # filing not electronically filed lobbyist["filing_type"] += "; Not electronically filed." filings.extend(lobbyist_filings) await convert_amend_ids_to_efile_ids(db_session, filings) return {"success": "true", "data": filings} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def saml_sp_initiated(): try: saml_c = await saml_client(kind='admin') reqid, info = saml_c.prepare_for_authenticate() redirect_url = None redirect_url = dict(info['headers'])['Location'] if redirect_url is None: Http500(detail="Server error in SAML authentication.") return {"success": True, "url": redirect_url} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def finalize_filing( filing_type: str, filing_id: str, payload: UpdateFilingInProgress, user: User = Depends(get_active_user), db_session: Session = Depends(get_db), ): try: print("****", filing_id) if not is_uuid(filing_id): raise Http400("Filing ID must be UUID") if filing_id != payload.form['filing_id']: raise Http400("Filing IDs in route and body don't match.") # user must be filer if user.account_type != 'filer': raise AccountPermissionException() filing = await get_filing_by_id(db_session, filing_id) if filing is None: raise Http400(detail="Filing not found") # user must be associated with this lobbying entity id entity = await get_lobbying_entity_by_id(db_session, filing.entity_id) if entity is None: raise EntityNotFoundException() filer = await get_lobbyist_filer_user(db_session, entity, user) if filer is None: raise AccountPermissionException() if filing.status not in ['new', 'in progress', 'locked']: raise Http400(detail="Filing status invalid for this operation.") res = await finalize_lobbyist_filing(db_session, filing, filer, payload) return {"success": res} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def get_lobbyist( lobbying_entity_id: str, user: User = Depends(get_active_admin_user), db_session: Session = Depends(get_db), ): # check that we got a UUID if not check_uuid4(lobbying_entity_id): raise Http400(detail="Lobbying entity ID must be a valid UUID4.") try: res = await get_lobbying_entity_by_id(db_session, lobbying_entity_id) if res is None: raise Http400(detail="Lobbying entity does not exist.") lobbyist_types = [(x.lobbyist_type, LOBBYIST_TYPES[x.lobbyist_type]) for x in res.lobbyist_types] contact_info = [ jsonable_encoder(x) for x in res.contact_info if x.active ][0] # get associated filer users filer_users = [jsonable_encoder(x.user) for x in res.filers] res = jsonable_encoder(res) res['name'] = contact_info['name'] res['address1'] = contact_info['address1'] res['address2'] = contact_info['address2'] res['city'] = contact_info['city'] res['zipcode'] = contact_info['zipcode'] res['state'] = contact_info['state'] res['phone'] = contact_info['phone'] res['lobbyist_types'] = lobbyist_types del res['filers'] res['filer_users'] = filer_users return {"success": True, "data": res} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def register_lobbyist( req: Request, form: NewLobbyistRegistration, db_session: Session = Depends(get_db), ): try: xd = await req.json() res = await check_recaptcha_response(form.recaptcha) if ENFORCE_RECAPTCHA and res is False: Http400("Recaptcha validation failed.") res = await register_new_lobbyist(db_session, form) return {"success": True} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def post_update_lobbyist( lobbying_entity_id: str, body: UpdateLobbyingEntity, user: User = Depends(get_active_admin_user), db_session: Session = Depends(get_db), ): try: if lobbying_entity_id != body.entity_id: Http400("Lobbying entity ids don't match.") await update_lobbyist(db_session, body) return {"success": True} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def get_filing_fees( filing_type: str, filing_id: str, user: User = Depends(get_active_user), db_session: Session = Depends(get_db), ): try: if not is_uuid(filing_id): raise Http400("Filing ID must be UUID") if filing_type not in ['ec601', 'ec602']: raise Http400("Fees are assessed only on forms EC-601 and EC-602.") # user must be filer if user.account_type != 'filer': raise AccountPermissionException() filing = await get_filing_by_id(db_session, filing_id) if filing is None: raise Http400(detail="Filing not found") # user must be associated with this lobbying entity id entity = await get_lobbying_entity_by_id(db_session, filing.entity_id) if entity is None: raise EntityNotFoundException() filer = await get_lobbyist_filer_user(db_session, entity, user) if filer is None: raise AccountPermissionException() if filing.status not in ['new', 'in progress', 'locked']: raise Http400(detail="Filing status invalid for this operation.") res = await calculate_filing_fees(db_session, filing) return {"success": True, "data": res} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def reset_password_request( payload: ResetPasswordRequest, db_session: Session = Depends(get_db), ): try: res = await check_recaptcha_response(payload.recaptcha) if ENFORCE_RECAPTCHA and res is False: Http400(detail="Recaptcha validation failed.") res = await user_password_reset_request(db_session, payload) return {"success": True} except AccountException: raise except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def get_document( doc_id: str = None, filing_id: str = None, db_session: Session = Depends(get_db), ): try: if doc_id is None and filing_id is None: raise Http400("A document id or filing id must be provided.") if doc_id is not None: url = await get_filing_url_by_public_doc_id(db_session, doc_id) if url is None: raise Http404("Filing document was not found.") return {"success": "true", "data": {"url": url}} else: original_filing = await get_filing_by_id(db_session, filing_id) original_filing_json = jsonable_encoder(original_filing) if len(original_filing_json) == 0: raise Http404("Filing document was not found.") doc_id = original_filing_json["doc_public"] url = await get_filing_url_by_public_doc_id(db_session, doc_id) if url is None: raise Http404("Filing document was not found.") return {"success": "true", "data": {"url": url}} except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def filer_login(request: Request, form: Login, Authorize: AuthJWT = Depends(), db_session: Session = Depends(get_db)): try: user_logger.info(f"Login attempt: {form.username}") user = authenticate_filer_user(db_session, form.username, form.password) if user is None or not user: raise CREDENTIALS_EXCEPTION access_token = Authorize.create_access_token( subject=user.email, user_claims={'filer': True}) refresh_token = Authorize.create_refresh_token( subject=user.email, user_claims={'filer': True}) Authorize.set_refresh_cookies(refresh_token) user_logger.info(f"Login successful: {form.username}") return {"success": True, "access_token": access_token} except Exception as e: user_logger.info(f"Login failed: {form.username}") logger.exception(traceback.format_exc()) handle_exc(e)
async def filer_info(user: User = Depends(get_active_user), db_session: Session = Depends(get_db)): try: # user must be filer if user.account_type != 'filer': raise AccountPermissionException() filer = await get_filer_by_user_id(db_session, user.id) if filer is None: raise AccountPermissionException() # filer types # contact info # agencies # entities filer_types_raw = filer.filer_types filer_contact_info = get_most_recent_entry(filer.contact_infos) if filer_contact_info is None: filer_contact_info = {} else: filer_contact_info = jsonable_encoder(filer_contact_info) del filer_contact_info['filer_id'] del filer_contact_info['id'] del filer_contact_info['created'] del filer_contact_info['updated'] filer_types = [{ "key": x.filer_type, "value": FILER_TYPES[x.filer_type] } for x in filer_types_raw] # entities, at this point only lobbyist lobbying_entities = await get_lobbying_entities_by_filer_id( db_session, filer.filer_id) entity_list = [] for entity in lobbying_entities: # get most recent contact info contact_info = get_most_recent_entry(entity.contact_info) xtypes = [ LOBBYIST_TYPES[x.lobbyist_type] for x in entity.lobbyist_types ] xtypes = ", ".join(xtypes) xd = { "name": contact_info.name, "entity_type": xtypes, "entity_id": entity.entity_id, "role": "Filer", "active": entity.active, "url": None } if entity.active: url = FRONTEND_ROUTES['lobbying_entity_profile'] + "/" + \ entity.entity_id xd.update({"url": url}) entity_list.append(xd) entity_list.sort(key=lambda x: x['name']) res_dict = { "filer_id": filer.filer_id, "contact_info": filer_contact_info, "email": filer.email, "filer_types": filer_types, "entities": entity_list, "sei_agencies": [] } return {"success": True, "data": res_dict} except AccountPermissionException as e: # we don't log this raise except EntityNotFoundException as e: # we don't log this raise except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)
async def get_lobbying_entity_info(lobbying_entity_id: str, user: User = Depends(get_active_user), db_session: Session = Depends(get_db)): try: if not is_uuid(lobbying_entity_id): raise Http400("Lobbying entity ID must be UUID") # user must be filer if user.account_type != 'filer': raise AccountPermissionException() # user must be associated with this lobbying entity id entity = await get_lobbying_entity_by_id(db_session, lobbying_entity_id) if entity is None: raise EntityNotFoundException() filer = await get_lobbyist_filer_user(db_session, entity, user) if filer is None: raise AccountPermissionException() contact_info = jsonable_encoder( get_most_recent_entry(entity.contact_info)) del contact_info['id'] del contact_info['updated'] del contact_info['created'] lobbyist_types = [(x.lobbyist_type, LOBBYIST_TYPES[x.lobbyist_type]) for x in entity.lobbyist_types] filers = [] for filer in entity.filers: cinfo = jsonable_encoder(get_most_recent_entry( filer.contact_infos)) del cinfo['id'] del cinfo['updated'] del cinfo['created'] cinfo['active'] = filer.active filers.append(cinfo) filers.sort(key=lambda x: x['last_name']) return_dict = { "lobbyist_types": lobbyist_types, "contact_info": contact_info, "human_readable_id": "Not yet implemented", "status": [], "current_filings": [], "filers": filers } return {"success": True, "data": return_dict} except (AccountPermissionException, EntityNotFoundException) as e: pass except Exception as e: logger.exception(traceback.format_exc()) handle_exc(e)