def log_connection_events(sender, signal_type, obj, **kwargs): from common.tz_support import utc_now from django.core.urlresolvers import reverse from google.appengine.api.taskqueue import taskqueue from analytics.models import AnalyticsEvent from common.util import log_event, EventType, notify_by_email from ordering.signals import SignalType from ordering.station_connection_manager import ALERT_DELTA, handle_dead_workstations last_event_qs = AnalyticsEvent.objects.filter(work_station=obj, type__in=[EventType.WORKSTATION_UP, EventType.WORKSTATION_DOWN]).order_by('-create_date')[:1] station = obj.station if signal_type == SignalType.WORKSTATION_ONLINE: if last_event_qs: # send workstation reconnect mail last_event = last_event_qs[0] if last_event.type == EventType.WORKSTATION_DOWN and (utc_now() - last_event.create_date) >= ALERT_DELTA and station.show_on_list: msg = u"Workstation is up again:\n\tid = %d station = %s" % (obj.id, obj.dn_station_name) notify_by_email(u"Workstation Reconnected", msg=msg) elif station.show_on_list: # send "new workstation" mail msg = u"A new workstation just connected: id = %d station = %s" % (obj.id, obj.dn_station_name) notify_by_email(u"New Workstation", msg=msg) log_event(EventType.WORKSTATION_UP, station=station, work_station=obj) elif signal_type == SignalType.WORKSTATION_OFFLINE: log_event(EventType.WORKSTATION_DOWN, station=station, work_station=obj) if station.show_on_list: # add task to check if workstation is still dead after ALERT_DELTA task = taskqueue.Task(url=reverse(handle_dead_workstations), countdown=ALERT_DELTA.seconds + 1, params={"workstation_id": obj.id}) taskqueue.Queue('log-events').add(task)
def handle_dead_workstations(request): ws_id = request.POST.get("workstation_id") workstation = None try: workstation = WorkStation.objects.get(id=ws_id) except WorkStation.DoesNotExist: logging.error("handle_dead_workstations: invalid workstation_id '%s" % ws_id) if workstation: last_event = AnalyticsEvent.objects.filter( work_station=workstation, type__in=[EventType.WORKSTATION_UP, EventType.WORKSTATION_DOWN]).order_by('-create_date')[:1] if last_event: last_event = last_event[0] if last_event.type == EventType.WORKSTATION_DOWN and ( utc_now() - last_event.create_date) >= ALERT_DELTA: # send station down mail msg = u"Workstation has been down for the last %d minutes:\n\tid = %d station = %s" % ( ALERT_DELTA.seconds / 60, workstation.id, workstation.dn_station_name) notify_by_email(u"Workstation down", msg) return HttpResponse("OK")
def google_directions_request(start_lat, start_lng, end_lat, end_lng, output="json", alternatives=False, sensor=False, departure_time=None): # see https://developers.google.com/maps/documentation/directions/ params = { 'origin': '%s,%s' % (start_lat, start_lng), 'destination': '%s,%s' % (end_lat, end_lng), 'sensor': simplejson.dumps(sensor), 'alternatives': simplejson.dumps(alternatives), 'departure_time': unix_time(departure_time) if departure_time else unix_time(utc_now()) } url = "http://maps.googleapis.com/maps/api/directions/%s" % output logging.info("google_direction_request: %s" % url) response = sign_and_fetch(url, params) return response
def book_order(request): """ Book an order: send it to the dispatcher to get an order assignment, then pass the assignment to the station manager. """ order_id = int(request.POST["order_id"]) logging.info("book_order_task: %d" % order_id) order = get_object_or_404(Order, id=order_id) passenger = order.passenger # if this is the first order of this passenger, connect him with the station that originated the order if order.originating_station and passenger.orders.count() == 1: logging.info("assigning passenger %s to station %s" % (passenger, order.originating_station)) passenger.originating_station = order.originating_station if not passenger.default_station: passenger.default_station = order.originating_station passenger.save() sorry_msg = ugettext_noop("We're sorry, but we could not find a taxi for you") # use dummy ugettext for makemessages) # check if dispatching should stop and return an answer to the user if (utc_now() - order.create_date).seconds > ORDER_HANDLE_TIMEOUT: try: order.change_status(new_status=TIMED_OUT) send_msg_to_passenger(passenger, translate_to_lang(sorry_msg, order.language_code)) logging.warning("order time out: %d" % order_id) response = HttpResponse(ORDER_TIMEOUT) except UpdateStatusError: logging.error("book_order failed: cannot set order [%d] status to %s" % (order.id, "TIME_OUT")) else: try: # choose an assignment for the order and push it to the relevant workstation order_assignment = dispatcher.assign_order(order) push_order(order_assignment) enqueue_redispatch_orders(order_assignment, ORDER_TEASER_TIMEOUT, redispatch_pending_orders) response = HttpResponse(ORDER_HANDLED) except NoWorkStationFoundError: try: order.change_status(new_status=FAILED) send_msg_to_passenger(passenger, translate_to_lang(sorry_msg, order.language_code)) # use dummy ugettext for makemessages log_event(EventType.ORDER_FAILED, order=order, passenger=order.passenger) logging.warning("no matching workstation found for: %d" % order_id) response = HttpResponse(NO_MATCHING_WORKSTATIONS_FOUND) except UpdateStatusError: logging.error("book_order failed: cannot set order [%d] status to %s" % (order.id, "FAILED")) except Exception, e: try: order.change_status(new_status=ERROR) send_msg_to_passenger(passenger, translate_to_lang(ugettext_noop("We're sorry, but we have encountered an error while handling your request") , order.language_code)) # use dummy ugettext for makemessages log_event(EventType.ORDER_ERROR, order=order, passenger=order.passenger) logging.error("book_order: OrderError: %d" % order_id) raise # handle exception in decorator except UpdateStatusError: logging.error("book_order failed: cannot set order [%d] status to %s" % (order.id, "ERROR"))
def google_directions_request(start_lat, start_lng, end_lat, end_lng, output="json", alternatives=False, sensor=False, departure_time=None): # see https://developers.google.com/maps/documentation/directions/ params = { 'origin': '%s,%s' % (start_lat, start_lng), 'destination' : '%s,%s' % (end_lat, end_lng), 'sensor': simplejson.dumps(sensor) , 'alternatives': simplejson.dumps(alternatives), 'departure_time': unix_time(departure_time) if departure_time else unix_time(utc_now()) } url = "http://maps.googleapis.com/maps/api/directions/%s" % output logging.info("google_direction_request: %s" % url) response = sign_and_fetch(url, params) return response
def handle_dead_workstations(request): ws_id = request.POST.get("workstation_id") workstation = None try: workstation = WorkStation.objects.get(id=ws_id) except WorkStation.DoesNotExist: logging.error("handle_dead_workstations: invalid workstation_id '%s" % ws_id) if workstation: last_event = AnalyticsEvent.objects.filter(work_station=workstation, type__in=[EventType.WORKSTATION_UP, EventType.WORKSTATION_DOWN]).order_by('-create_date')[:1] if last_event: last_event = last_event[0] if last_event.type == EventType.WORKSTATION_DOWN and (utc_now() - last_event.create_date) >= ALERT_DELTA: # send station down mail msg = u"Workstation has been down for the last %d minutes:\n\tid = %d station = %s" % (ALERT_DELTA.seconds / 60, workstation.id, workstation.dn_station_name) notify_by_email(u"Workstation down", msg) return HttpResponse("OK")
def get_previous_rides(request, passenger): data = [] orders = passenger.orders.filter(depart_time__lt=utc_now(), status__in=ORDER_SUCCESS_STATUS).order_by('-depart_time') orders = orders.filter(type__in=[OrderType.PRIVATE, OrderType.SHARED])[:PREVIOUS_RIDES_TO_DISPLAY] seen_rides = [] for order in orders: ride = order.ride if not ride: logging.error("order [%s] not valid for previous rides (order.ride is None" % order.id) continue if ride in seen_rides: continue # skip duplicates (in case ride has multiple orders by same passenger) seen_rides.append(ride) ride_orders = ride.orders.all() ride_mates_orders = filter(lambda o: o != order, ride_orders) ride_mates = [{'name': mate_order.passenger.name, 'picture_url': mate_order.passenger.picture_url} for mate_order in ride_mates_orders for seat in range(order.num_seats)] dispatching_event = first(lambda e: e.taxi_id, ride.events.all()) ride_data = { "order_id": order.id, "pickup_time": to_js_date(order.pickup_point.stop_time), "passengers": ride_mates, "seats_left": MAX_SEATS - sum([o.num_seats for o in ride_orders]), "your_seats": order.num_seats, "taxi_number": dispatching_event.taxi_id if dispatching_event else None, "station_name": ride.station.name if ride.station else WAYBETTER_STATION_NAME, "price": order.get_billing_amount(), "price_alone": order.price_alone, "billing_status": ugettext_lazy(order.get_status_display().title()), "pickup": order.from_raw, "dropoff": order.to_raw, "is_private": order.type == OrderType.PRIVATE, "comment": "" } data.append(ride_data) return JSONResponse(data)
def log_connection_events(sender, signal_type, obj, **kwargs): from common.tz_support import utc_now from django.core.urlresolvers import reverse from google.appengine.api.taskqueue import taskqueue from analytics.models import AnalyticsEvent from common.util import log_event, EventType, notify_by_email from ordering.signals import SignalType from ordering.station_connection_manager import ALERT_DELTA, handle_dead_workstations last_event_qs = AnalyticsEvent.objects.filter( work_station=obj, type__in=[EventType.WORKSTATION_UP, EventType.WORKSTATION_DOWN]).order_by('-create_date')[:1] station = obj.station if signal_type == SignalType.WORKSTATION_ONLINE: if last_event_qs: # send workstation reconnect mail last_event = last_event_qs[0] if last_event.type == EventType.WORKSTATION_DOWN and ( utc_now() - last_event.create_date ) >= ALERT_DELTA and station.show_on_list: msg = u"Workstation is up again:\n\tid = %d station = %s" % ( obj.id, obj.dn_station_name) notify_by_email(u"Workstation Reconnected", msg=msg) elif station.show_on_list: # send "new workstation" mail msg = u"A new workstation just connected: id = %d station = %s" % ( obj.id, obj.dn_station_name) notify_by_email(u"New Workstation", msg=msg) log_event(EventType.WORKSTATION_UP, station=station, work_station=obj) elif signal_type == SignalType.WORKSTATION_OFFLINE: log_event(EventType.WORKSTATION_DOWN, station=station, work_station=obj) if station.show_on_list: # add task to check if workstation is still dead after ALERT_DELTA task = taskqueue.Task(url=reverse(handle_dead_workstations), countdown=ALERT_DELTA.seconds + 1, params={"workstation_id": obj.id}) taskqueue.Queue('log-events').add(task)
def show_order(order_id, work_station): """ raises ShowOrderError """ try: order_assignment = OrderAssignment.objects.get(order=order_id, work_station=work_station, status=PENDING) order_assignment.change_status(PENDING, ASSIGNED) # except MultipleObjectsReturned: # OrderAssignment.objects.filter(order=order_id, work_station=work_station, status=PENDING).delete() except OrderAssignment.DoesNotExist: logging.warning("No PENDING assignment for order %d in work station %d" % (order_id, work_station.id)) raise ShowOrderError() except UpdateStatusError: raise ShowOrderError() order_assignment.show_date = utc_now() order_assignment.save() enqueue_redispatch_orders(order_assignment, ORDER_ASSIGNMENT_TIMEOUT, redispatch_ignored_orders) return order_assignment
def show_order(order_id, work_station): """ raises ShowOrderError """ try: order_assignment = OrderAssignment.objects.get( order=order_id, work_station=work_station, status=PENDING) order_assignment.change_status(PENDING, ASSIGNED) # except MultipleObjectsReturned: # OrderAssignment.objects.filter(order=order_id, work_station=work_station, status=PENDING).delete() except OrderAssignment.DoesNotExist: logging.warning( "No PENDING assignment for order %d in work station %d" % (order_id, work_station.id)) raise ShowOrderError() except UpdateStatusError: raise ShowOrderError() order_assignment.show_date = utc_now() order_assignment.save() enqueue_redispatch_orders(order_assignment, ORDER_ASSIGNMENT_TIMEOUT, redispatch_ignored_orders) return order_assignment
def get_future_orders_for(passenger): future_order_qs = passenger.orders.filter( depart_time__gte=utc_now(), status__in=ORDER_SUCCESS_STATUS, type__in=[OrderType.PRIVATE, OrderType.SHARED]).order_by('-depart_time') return list(future_order_qs)
def book_order(request): """ Book an order: send it to the dispatcher to get an order assignment, then pass the assignment to the station manager. """ order_id = int(request.POST["order_id"]) logging.info("book_order_task: %d" % order_id) order = get_object_or_404(Order, id=order_id) passenger = order.passenger # if this is the first order of this passenger, connect him with the station that originated the order if order.originating_station and passenger.orders.count() == 1: logging.info("assigning passenger %s to station %s" % (passenger, order.originating_station)) passenger.originating_station = order.originating_station if not passenger.default_station: passenger.default_station = order.originating_station passenger.save() sorry_msg = ugettext_noop( "We're sorry, but we could not find a taxi for you" ) # use dummy ugettext for makemessages) # check if dispatching should stop and return an answer to the user if (utc_now() - order.create_date).seconds > ORDER_HANDLE_TIMEOUT: try: order.change_status(new_status=TIMED_OUT) send_msg_to_passenger( passenger, translate_to_lang(sorry_msg, order.language_code)) logging.warning("order time out: %d" % order_id) response = HttpResponse(ORDER_TIMEOUT) except UpdateStatusError: logging.error( "book_order failed: cannot set order [%d] status to %s" % (order.id, "TIME_OUT")) else: try: # choose an assignment for the order and push it to the relevant workstation order_assignment = dispatcher.assign_order(order) push_order(order_assignment) enqueue_redispatch_orders(order_assignment, ORDER_TEASER_TIMEOUT, redispatch_pending_orders) response = HttpResponse(ORDER_HANDLED) except NoWorkStationFoundError: try: order.change_status(new_status=FAILED) send_msg_to_passenger(passenger, translate_to_lang( sorry_msg, order.language_code) ) # use dummy ugettext for makemessages log_event(EventType.ORDER_FAILED, order=order, passenger=order.passenger) logging.warning("no matching workstation found for: %d" % order_id) response = HttpResponse(NO_MATCHING_WORKSTATIONS_FOUND) except UpdateStatusError: logging.error( "book_order failed: cannot set order [%d] status to %s" % (order.id, "FAILED")) except Exception, e: try: order.change_status(new_status=ERROR) send_msg_to_passenger( passenger, translate_to_lang( ugettext_noop( "We're sorry, but we have encountered an error while handling your request" ), order.language_code )) # use dummy ugettext for makemessages log_event(EventType.ORDER_ERROR, order=order, passenger=order.passenger) logging.error("book_order: OrderError: %d" % order_id) raise # handle exception in decorator except UpdateStatusError: logging.error( "book_order failed: cannot set order [%d] status to %s" % (order.id, "ERROR"))
getattr(order, "%s_raw" % order_type)) res = None return res form_data = request.POST if passenger.business and request.POST.get("business_order"): form_data = get_business_order_form_data(request, passenger) form = OrderForm(data=form_data, passenger=passenger) if form.is_valid(): if passenger.orders.all()[:1]: last_order = passenger.orders.order_by("-create_date")[0] interval = BUSINESS_ORDERING_INTERVAL if passenger.business else ORDERING_INTERVAL if (utc_now() - last_order.create_date).seconds < interval: return error_response( _("Ordering is not allowed so soon after another order")) app_udid = request.POST.get("APP_UDID") installed_app = None if app_udid: # this came from a device that sends app specific id installed_app = InstalledApp.by_app_udid(app_udid) if not installed_app: return error_response( _("Please register before attempting to order")) if installed_app.blocked: return error_response( _("Your account has been suspended. Please contact [email protected]" ))
logging.warning("Could not fix missing house number: %s" % getattr(order, "%s_raw" % order_type)) res = None return res form_data = request.POST if passenger.business and request.POST.get("business_order"): form_data = get_business_order_form_data(request, passenger) form = OrderForm(data=form_data, passenger=passenger) if form.is_valid(): if passenger.orders.all()[:1]: last_order = passenger.orders.order_by("-create_date")[0] interval = BUSINESS_ORDERING_INTERVAL if passenger.business else ORDERING_INTERVAL if (utc_now() - last_order.create_date).seconds < interval: return error_response(_("Ordering is not allowed so soon after another order")) app_udid = request.POST.get("APP_UDID") installed_app = None if app_udid: # this came from a device that sends app specific id installed_app = InstalledApp.by_app_udid(app_udid) if not installed_app: return error_response(_("Please register before attempting to order")) if installed_app.blocked: return error_response(_("Your account has been suspended. Please contact [email protected]")) order = form.save(commit=False) order.language_code = request.POST.get("language_code", get_language_from_request(request)) order.debug = settings.DEV order.passenger = passenger