def delete(self, community_id, id): tour = TourModel.find_by_id(id) user = UserModel.find_by_username(get_jwt_identity()) if not tour: abort(404, message=TOUR_NOT_FOUND) if not user.id == tour.owner.id: abort(401, message=UNAUTHORIZED) try: TourModel.delete_by_id(id) except NoData: abort(404, message=TOUR_NOT_FOUND) return SimpleMessage(TOUR_DELETED), 200
def put(self, community_id, id): data = finish_tour_parser.parse_args() tour = TourModel.find_by_id(id) user = UserModel.find_by_username(get_jwt_identity()) community: CommunityModel = CommunityModel.find_by_id(community_id) community_member_ids = [m.id for m in community.users] if not tour: abort(404, message=TOUR_NOT_FOUND) if not user.id == tour.owner.id: abort(401, message=UNAUTHORIZED) if tour.end_km: abort(400, message=TOUR_HAS_ALREADY_BEEN_FINISHED) passengers = [] if data['passengers']: for passenger_id in set(data['passengers']): if passenger_id not in community_member_ids: abort(400, message=PASSENGERS_MUST_BE_COMMUNITY_MEMBERS) else: passengers.append([u for u in community.users if u.id == passenger_id][0]) tour.end_time = datetime.datetime.now(pytz.utc) tour.passengers = passengers tour.end_km = data['end_km'] tour.comment = data['comment'] tour.parking_position = data['parking_position'] tour.persist() create_km_triggered_task_instances(community_id, tour.end_km) return tour, 200
class RunningUserTours(Resource): @jwt_required @marshal_with(TourModel.get_marshaller()) def get(self): user = UserModel.find_by_username(get_jwt_identity()) return TourModel.find_running_by_user(user.id), 200
def get(self, community_id): user = UserModel.find_by_username(get_jwt_identity()) community = CommunityModel.find_by_id(community_id) if not community: abort(400, message=COMMUNIY_DOESNT_EXIST) if user.id not in [u.id for u in community.users]: abort(401, message=UNAUTHORIZED) return TourModel.find_running_by_community(community_id), 200
def get(self, community_id, id): tour = TourModel.find_by_id(id) user = UserModel.find_by_username(get_jwt_identity()) if not tour: abort(404, message=TOUR_NOT_FOUND) if user.id not in [u.id for u in tour.community.users]: abort(401, message=UNAUTHORIZED) return tour, 200
def set_km_to_next_instance(tasks): """ Sets the `km_to_next_instance` property on the given task or list of tasks. :param tasks: Task or list of tasks. """ is_list = isinstance(tasks, (list,)) if not is_list: tasks = [tasks] if len(tasks) > 0: latest_tour = TourModel.find_newest_tour_for_community(tasks[0].community.id) for task in tasks: if task.km_next_instance: task.km_to_next_instance = task.km_next_instance - latest_tour.end_km
def post(self, community_id): data = parser.parse_args() owner = UserModel.find_by_username(get_jwt_identity()) community: CommunityModel = CommunityModel.find_by_id(community_id) community_member_ids = [m.id for m in community.users] if not community: abort(400, message=COMMUNIY_DOESNT_EXIST) if owner.id not in community_member_ids: abort(401, message=UNAUTHORIZED) if TourModel.find_running_by_community(community_id): abort(400, message=CANT_START_TOUR_WHEN_HAVING_UNFINISHED_TOURS_IN_COMMUNITY) passengers = [] if data['passengers']: for passenger_id in set(data['passengers']): if passenger_id not in community_member_ids: abort(400, message=PASSENGERS_MUST_BE_COMMUNITY_MEMBERS) else: passengers.append([u for u in community.users if u.id == passenger_id][0]) new_tour = TourModel( owner=owner, community=community, start_time=datetime.datetime.now(pytz.utc), start_km=data['start_km'], passengers=passengers ) try: new_tour.persist() return new_tour, 201 except: abort(500, message=INTERNAL_SERVER_ERROR)
def get(self, community_id): user = UserModel.find_by_username(get_jwt_identity()) community = CommunityModel.find_by_id(community_id) if not community: abort(400, message=COMMUNIY_DOESNT_EXIST) if user.id not in [u.id for u in community.users]: abort(401, message=UNAUTHORIZED) tour = TourModel.find_newest_tour_for_community(community_id) if not tour: abort(400, message=NO_TOUR_EXISTING) return tour, 200
class RunningCommunityTours(Resource): @jwt_required @marshal_with(TourModel.get_marshaller()) def get(self, community_id): user = UserModel.find_by_username(get_jwt_identity()) community = CommunityModel.find_by_id(community_id) if not community: abort(400, message=COMMUNIY_DOESNT_EXIST) if user.id not in [u.id for u in community.users]: abort(401, message=UNAUTHORIZED) return TourModel.find_running_by_community(community_id), 200
def get_community_statistic(community_id, from_datetime, to_datetime): community: CommunityModel = CommunityModel.find_by_id(community_id) if not community: abort(404, message=COMMUNIY_DOESNT_EXIST) user = UserModel.find_by_username(get_jwt_identity()) community_member_ids = [m.id for m in community.users] if user.id not in community_member_ids: abort(401, message=UNAUTHORIZED) statistic = CommunityStatisticModel() statistic.community = community statistic.statistic_start = from_datetime statistic.statistic_end = to_datetime all_tours = TourModel.find_finished_by_community(community_id) all_costs = RefuelModel.find_by_community(community_id) km_per_user_dict = {} costs_per_user_dict = {} for user in community.users: km_per_user_dict[user.id] = KmPerUserModel() km_per_user_dict[user.id].user = user statistic.km_per_user.append(km_per_user_dict[user.id]) costs_per_user_dict[user.id] = CostsPerUserModel() costs_per_user_dict[user.id].user = user statistic.costs_per_user.append(costs_per_user_dict[user.id]) for tour in all_tours: if from_datetime <= tour.end_time.astimezone(pytz.utc) <= to_datetime: tour_km = tour.end_km - tour.start_km km_per_user_dict[tour.owner_id].km += tour_km # Divide km of passengers all_passengers_ids = [tour.owner_id] + [ passenger.id for passenger in tour.passengers ] for passenger_id in all_passengers_ids: km_per_user_dict[ passenger_id].km_accounted_for_passengers += tour_km / len( all_passengers_ids) for cost in all_costs: if from_datetime <= cost.time_created.astimezone( pytz.utc) <= to_datetime: costs_per_user_dict[cost.owner_id].costs += cost.costs return statistic
class ForceFinishTour(Resource): @jwt_required @marshal_with(TourModel.get_marshaller()) def put(self, community_id, id): data = finish_tour_parser.parse_args() tour = TourModel.find_by_id(id) user = UserModel.find_by_username(get_jwt_identity()) if not tour: abort(404, message=TOUR_NOT_FOUND) if user.id == tour.owner.id: abort(401, message=UNAUTHORIZED) if community_id != tour.community.id: abort(401, message=UNAUTHORIZED) if user.id not in [u.id for u in tour.community.users]: abort(401, message=UNAUTHORIZED) if tour.end_km: abort(400, message=TOUR_HAS_ALREADY_BEEN_FINISHED) if not data['passengers']: data['passengers'] = [] passengers_changed = np.setdiff1d(data['passengers'], [p.id for p in tour.passengers]) > 0 if len(data['passengers']) != len(tour.passengers) or passengers_changed: abort(400, message=PASSENGER_LIST_CANNOT_BE_CHANGED_WHEN_FORCE_FINISHING_A_TOUR) tour.end_time = datetime.datetime.now(pytz.utc) tour.end_km = data['end_km'] tour.comment = data['comment'] tour.parking_position = data['parking_position'] tour.is_force_finished = True tour.force_finished_by = user tour.persist() create_km_triggered_task_instances(community_id, tour.end_km) return tour, 200
class LatestTour(Resource): @jwt_required @marshal_with(TourModel.get_marshaller()) def get(self, community_id): user = UserModel.find_by_username(get_jwt_identity()) community = CommunityModel.find_by_id(community_id) if not community: abort(400, message=COMMUNIY_DOESNT_EXIST) if user.id not in [u.id for u in community.users]: abort(401, message=UNAUTHORIZED) tour = TourModel.find_newest_tour_for_community(community_id) if not tour: abort(400, message=NO_TOUR_EXISTING) return tour, 200
def put(self, community_id, id): data = edit_tour_parser.parse_args() tour = TourModel.find_by_id(id) user = UserModel.find_by_username(get_jwt_identity()) community: CommunityModel = CommunityModel.find_by_id(community_id) community_member_ids = [m.id for m in community.users] if not tour: abort(404, message=TOUR_NOT_FOUND) if not user.id == tour.owner.id: abort(401, message=UNAUTHORIZED) passengers = [] if data['passengers']: for passenger_id in set(data['passengers']): if passenger_id not in community_member_ids: abort(400, message=PASSENGERS_MUST_BE_COMMUNITY_MEMBERS) else: passengers.append([u for u in community.users if u.id == passenger_id][0]) tour.comment = data['comment'] tour.parking_position = data['parking_position'] if not tour.is_open: abort(400, message=CANNOT_UPDATE_SENSITIVE_TOUR_DATA_WHEN_TOUR_IS_ALREADY_PAYED_FOR) else: if data['end_km'] <= data['start_km']: abort(400, message=END_KM_MUST_BE_GREATER_START_KM) tour.end_km = data['end_km'] tour.start_km = data['start_km'] tour.passengers = passengers tour.persist() return tour, 200
def post(self, community_id): parser = reqparse.RequestParser() parser.add_argument('time_next_instance', type=moment, required=False) parser.add_argument('time_interval', type=int, required=False) parser.add_argument('name', type=str) parser.add_argument('description', type=str) parser.add_argument('km_interval', type=int, required=False) parser.add_argument('km_next_instance', type=float, required=False) parser.add_argument('is_reocurrent', type=bool, required=True) data = parser.parse_args() owner = UserModel.find_by_username(get_jwt_identity()) community: CommunityModel = CommunityModel.find_by_id(community_id) community_member_ids = [m.id for m in community.users] if not community: abort(400, message=COMMUNIY_DOESNT_EXIST) if owner.id not in community_member_ids: abort(401, message=UNAUTHORIZED) if data['is_reocurrent'] and ( not (data['time_next_instance'] and data['time_interval'] or data['km_interval'] and data[ 'km_next_instance']) or data['km_interval'] and (data['time_interval'] or data['time_next_instance']) or \ data['time_interval'] and (data['km_interval'] or data['km_next_instance'])): abort(400, message=TASK_MUST_BE_EITHER_TIME_OR_KM_TRIGGERED) newest_tour: TourModel = TourModel.find_newest_tour_for_community(community_id) if data['km_next_instance'] and data['km_next_instance'] < newest_tour.end_km: abort(400, message=TASK_KM_NEXT_INSTANCE_MUST_BE_HIGHER_THEN_CURRENT_KM) if data['time_next_instance'] and data['time_next_instance'] < datetime.now(pytz.timezone('Europe/Berlin')): abort(400, message=TASK_TIME_NEXT_INSTANCE_MUST_BE_HIGHER_THEN_CURRENT_TIME) time_interval = None if data['time_interval']: time_interval = timedelta(days=data['time_interval']) new_task = TaskModel( owner=owner, community=community, time_interval=time_interval, time_next_instance=data['time_next_instance'], km_interval=data['km_interval'], km_next_instance=data['km_next_instance'], name=data['name'], description=data['description'], is_reocurrent=data['is_reocurrent'] ) try: new_task.persist() set_km_to_next_instance(new_task) if not data['is_reocurrent']: new_task_instance = TaskInstanceModel( task=new_task, is_open=True, community=new_task.community ) new_task_instance.persist() return new_task, 201 except: abort(500, message=INTERNAL_SERVER_ERROR)
def get(self): user = UserModel.find_by_username(get_jwt_identity()) return TourModel.find_running_by_user(user.id), 200
def post(self, id): community = CommunityModel.find_by_id(id) user = UserModel.find_by_username(get_jwt_identity()) if not community: abort(404, message=COMMUNIY_DOESNT_EXIST) if user.id not in [u.id for u in community.users]: abort(401, message=UNAUTHORIZED) if TourModel.find_running_by_community(id): abort(400, message=CANT_CREATE_PAYOFF_WHEN_UNFINISHED_TOURS_EXIST) # tours: List[TourModel] = TourModel.find_finished_and_open_by_community(id) # refuels: List[RefuelModel] = RefuelModel.find_open_by_community(id) tours: List[TourModel] = TourModel.find_finished_by_community(id) refuels: List[RefuelModel] = RefuelModel.find_by_community(id) if not [t for t in tours if t.is_open ] and not [r for r in refuels if r.is_open]: abort(400, message=CANT_CREATE_PAYOFF_WITHOUT_NEW_REFUELS_AND_TOURS) # Calculate some basic statistics total_km = sum(map(lambda t: t.end_km - t.start_km, tours)) km_per_user = {} for tour in tours: involved_users = [tour.owner] + tour.passengers km_per_involved_user = (tour.end_km - tour.start_km) / len(involved_users) for involved_user in involved_users: if involved_user.id not in km_per_user: km_per_user[involved_user.id] = 0 km_per_user[involved_user.id] += km_per_involved_user # If there is a user from refuels missing, he has zero costs/kms for refuel in refuels: if refuel.owner.id not in km_per_user: km_per_user[refuel.owner.id] = 0 km_fraction_per_user = {} for user_id, km in km_per_user.items(): km_fraction_per_user[user_id] = km / total_km # Create reference user id to user dict user_dictionary = OrderedDict() for tour in tours: if tour.owner.id not in user_dictionary: user_dictionary[tour.owner.id] = tour.owner for passenger in tour.passengers: if passenger.id not in user_dictionary: user_dictionary[passenger.id] = passenger for refuel in refuels: if refuel.owner.id not in user_dictionary: user_dictionary[refuel.owner.id] = refuel.owner # Create debt matrix (debtee on y axis, recipient on x axis) debt_matrix = np.zeros((len(user_dictionary), len(user_dictionary))) for refuel in refuels: recipient_position = list(user_dictionary.keys()).index( refuel.owner.id) for user_id in user_dictionary.keys(): if user_id != refuel.owner.id: debtee_position = list( user_dictionary.keys()).index(user_id) debt_amount = refuel.costs * km_fraction_per_user[user_id] debt_matrix[debtee_position, recipient_position] += float(debt_amount) # Include already created debts from previous payoffs debts = DebtModel.find_by_community(id) for debt in debts: recipient_position = list(user_dictionary.keys()).index( debt.recepient_id) debtee_position = list(user_dictionary.keys()).index( debt.debtee_id) debt_matrix[debtee_position, recipient_position] -= float(debt.amount) # Simplify debt matrix debt_matrix = simplify_debt_matrix(debt_matrix) # Create and persist payoff payoff = PayoffModel() payoff.community_id = id payoff.persist() # Create and persist debt objects for i in range(debt_matrix.shape[0]): for j in range(debt_matrix.shape[0]): if debt_matrix[i, j] != 0: debt = DebtModel() debt.debtee = list(user_dictionary.values())[i] debt.recepient = list(user_dictionary.values())[j] debt.amount = round(debt_matrix[i, j], 2) debt.payoff_id = payoff.id debt.community_id = id debt.persist() # If there is no resulting debt in the payoff, the payoff is settled if not np.any(debt_matrix != 0): payoff.is_settled = True # Set open tours to non open and add payoff id for tour in tours: if tour.is_open: tour.is_open = False tour.payoff_id = payoff.id tour.persist() # Set open refuels to non open and add payoff id for refuel in refuels: if refuel.is_open: refuel.is_open = False refuel.payoff_id = payoff.id refuel.persist() return payoff, 201