def get_volunteer_mission( uuid: pydantic.UUID4, db: Session = Depends(get_db), volunteer: models.Volunteer = Depends(get_current_active_volunteer)): mission = crud.get_mission_by_uuid(db, uuid) if not mission: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="No such mission") volunteer_mission_statuses = crud.get_all_volunteer_mission_statuses( db, mission) if any(s == models.VolunteerMissionState.accepted for s in volunteer_mission_statuses): check_volunteer_mission(db, mission, volunteer, in_state=models.VolunteerMissionState.accepted) else: check_volunteer_mission(db, mission, volunteer) if mission.state.name == models.MissionState.approved.name: return schemas.SlimMissionResponse( **mission.__dict__, distance=utils.distance_to_string( volunteer.calculate_distance_from(mission.elder_address))) elif mission.state.name in { models.MissionState.acquired.name, models.MissionState.started.name }: return schemas.VolunteerMission(**mission.to_dict()) else: raise HTTPException(status.HTTP_403_FORBIDDEN, detail="Mission is not longer required volunteer")
def complete_mission( uuid: pydantic.UUID4, db: Session = Depends(get_db), volunteer: models.Volunteer = Depends(get_current_active_volunteer)): mission = crud.get_mission_by_uuid(db, uuid) check_volunteer_mission(db, mission, volunteer) crud.set_mission_state(db, mission, models.MissionState.completed)
def change_mission_state(state_request: schemas.ChangeMissionStateRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db), volunteer: models.Volunteer = Depends(get_current_active_volunteer)): mission = crud.get_mission_by_uuid(db, _uuid=state_request.mission_id) if not mission: raise HTTPException(status.HTTP_404_NOT_FOUND, detail=schemas.MissionNotFound.description()) if not has_role_or_above(volunteer, models.VolunteerRole.coordinator) \ and volunteer.role != models.VolunteerRole.call_center: crud.check_volunteer_mission(db, mission, volunteer, models.VolunteerMissionState.accepted) handle_mission_state_changed(db, mission, state_request.mission_state, state_request.error_state, background_tasks, state_before_changed=mission.state)
def schedule_mission(request: schemas.ScheduleMissionRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db), volunteer: models.Volunteer = Depends(get_current_active_volunteer)): mission = crud.get_mission_by_uuid(db, _uuid=request.mission_id) if not mission: raise HTTPException(status.HTTP_404_NOT_FOUND, detail=schemas.MissionNotFound.description()) if not has_role_or_above(volunteer, models.VolunteerRole.coordinator): check_volunteer_mission(db, mission, volunteer, VolunteerMissionState.accepted) crud.set_mission_schedule(db, mission, request.schedule_date, request.preferred_hours) background_tasks.add_task(crud.set_mission_approved_task, mission.uuid) return mission.to_dict()
def update_mission(update_mission_request: schemas.UpdateMission, background_tasks: BackgroundTasks, db: Session = Depends(get_db), coordinator: models.Volunteer = Depends(get_current_active_coordinator_volunteer)): mission_before_update = crud.get_mission_by_uuid(db, _uuid=update_mission_request.uuid) mission_state_before_update: models.MissionState = mission_before_update.state if update_mission_request.owner_id: coordinator = crud.get_volunteer_by_id(db, update_mission_request.owner_id) crud.update_mission(db, update_mission_request, coordinator) handle_mission_state_changed(db, mission_before_update, update_mission_request.state, update_mission_request.error_state, background_tasks, state_before_changed=mission_state_before_update)
def decline_mission( uuid: pydantic.UUID4, decline_request: schemas.DeclineMissionRequest, background_tasks: BackgroundTasks, db: Session = Depends(get_db), volunteer: models.Volunteer = Depends(get_current_active_volunteer)): mission: models.Mission = crud.get_mission_by_uuid(db, uuid) if not mission: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="No such mission") crud.handle_decline_mission(db, mission.uuid, volunteer.id, decline_request.reason, background_tasks) return schemas.SlimMissionResponse(**mission.to_dict(), distance=utils.distance_to_string( volunteer.calculate_distance_from( mission.elder_address)))
def event_loop(): while True: logger.info('Starting worker Iteration') timesleep.sleep(config.WORKER_INTERVAL_SECONDS) tasks: List[models.ScheduledTasks] = pull_tasks() logger.info(f'Pulled {len(tasks)} tasks') for task in tasks: # TODO: Format safer task.executed_at = models.get_utc_now() # Get mission id from endpoint column mission_uuid = task.endpoint.split('/')[3].split('?')[0] mission: models.Mission = crud.get_mission_by_uuid( db, mission_uuid) # Don't do anything if mission state is not approved if mission.state != models.MissionState.approved: logger.info( f'mission {mission.uuid} status is not approved and was changed to {mission.state.name}' ) task.failure_description = f'{mission.uuid} is not in state approved' continue if number_of_completed_tasks( task) < config.MAX_SEARCHING_VOLUNTEERS_ATTEMPTS: add_next_task_time(task) # Set the MissionErrorState to no volunteers found else: crud.set_mission_error( db, mission, models.MissionErrorState.no_volunteers_found) continue request_url = f'http://localhost{config.API_V1_STR}{task.endpoint}' logger.info(f'Running {request_url}') response = requests.get(url=request_url) # Valid response if response.status_code == status.HTTP_200_OK: task.completed_at = models.get_utc_now() # Error occurred else: task.failed_at = models.get_utc_now() task.failure_description = f'{response.status_code}: {response.text}' db.commit() logger.info('Iteration is finished')
def verify_mission(mission_uuid: UUID4, internal_token: str, db: Session = Depends(get_db)): if internal_token != config.INTERNAL_API_TOKEN: raise HTTPException(status.HTTP_401_UNAUTHORIZED, detail="Not allowed to call this API") try: mission: models.Mission = crud.get_mission_by_uuid(db, mission_uuid) # If mission doesn't exists any more raise exception if not mission: raise HTTPException( status.HTTP_404_NOT_FOUND, detail=f"Mission {mission_uuid} no longer exists.") # If mission state is not approved (approved meaning it's waiting for volunteers) we want to return if mission.state != models.MissionState.approved: return f"Mission state ({mission.state.name}) doesn't need more volunteers lookup" # Ask for the second group since if we came here the first group doesn't respond return search.search_and_notify_nearby_volunteers(db, mission) except Exception as e: raise HTTPException( status.HTTP_400_BAD_REQUEST, detail=f"Exception raised while handling this task: {str(e)}")
def accept_mission( uuid: pydantic.UUID4, db: Session = Depends(get_db), volunteer: models.Volunteer = Depends(get_current_active_volunteer)): mission = crud.get_mission_by_uuid(db, uuid) if not mission: raise HTTPException(status.HTTP_404_NOT_FOUND, detail="No such mission") try: crud.accept_mission_for_volunteer(db, volunteer, mission) except MissionAlreadyAccepted: raise HTTPException( status.HTTP_405_METHOD_NOT_ALLOWED, detail="Mission was already accepted by another volunteer") except Exception as e: raise HTTPException(status.HTTP_500_INTERNAL_SERVER_ERROR) db.refresh(volunteer) db.refresh(mission) return schemas.MissionStartedResponse( **mission.__dict__, elder_address=dict(address_str=mission.elder_address_str, address_lat=mission.elder_address_lat, address_lng=mission.elder_address_lng))