def add_rider(rider_name): ''' Adds a new rider. :param rider_name: Unique name of rider to be added. :type rider_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of added rider. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'add_rider' try: check = api_utils.check_if_found(Rider, method, rider_name) if check != True: return check rider = Rider.objects.create(name=rider_name) # TODO: Add rider as Django user in rider group logger.info('%s: %s' % (method, rider.name)) result = ApiResult(method, ok=True, data=rider) # TODO: Broadcast result return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def remove_session(track_name, session_name): ''' Removes a session, including all lap data. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of removed session. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'remove_session' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check if not Session.objects.filter(name=session_name, track__name=track_name).exists(): error = 'Session not found' return ApiResult(method, ok=False, data=error) session = Session.objects.get(name=session_name, track__name=track_name) session.delete() logger.info('%s: %s' % (method, session_name)) result = ApiResult(method, ok=True, data=session_name) # TODO: Broadcast return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def change_track(track_name, new_track_name=None, new_track_distance=None, new_lap_timeout=None, new_unit_of_measurement=None): ''' Changes track details. :param track_name: Current name of track. :type track_name: str :param new_track_name: New unique name of track. :type new_track_name: str :param new_track_distance: Total track distance. :type new_track_distance: float :param new_lap_timeout: Maximum number of seconds before a lap times out.. :type new_lap_timeout: integer :param new_unit_of_measurement: Unit of measurement, either Metric or Imperial. :type new_unit_of_measurement: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of changed track. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'change_track' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check if new_track_name == None and new_track_distance == None \ and new_lap_timeout == None and new_unit_of_measurement == None: error = 'At least one new track detail is required' # TODO: i18n return ApiResult(method, ok=False, data=error) if new_unit_of_measurement != None \ and new_unit_of_measurement not in dict(settings.UNIT_OF_MEASUREMENT): error = 'Invalid unit of measurement' # TODO: i18n return ApiResult(method, ok=False, data=error) if new_track_name != None: check = api_utils.check_if_found(Track, method, new_track_name) if check != True: return check track = Track.objects.get(name=track_name) if new_track_name != None: track.name = new_track_name if new_track_distance != None: track.distance = new_track_distance if new_lap_timeout != None: track.timeout = new_lap_timeout if new_unit_of_measurement != None: track.unit_of_measurement = new_unit_of_measurement track.save() logger.info('%s: %s' % (method, track.name)) result = ApiResult(method, ok=True, data=track) # TODO: Broadcast result return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def add_session(track_name, session_name): ''' Adds a new session. Session name must be unique for track. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of new session. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'add_session' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check track = Track.objects.get(name=track_name) if Session.objects.filter(track=track, name=session_name).exists(): error = 'Session already exists' return ApiResult(method, ok=False, data=error) session = Session.objects.create(track_id=track.id, name=session_name) logger.info('%s: %s' % (method, session.name)) result = ApiResult(method, ok=True, data=session) # TODO: Broadcast return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def get_incomplete_laps(track_name, session_name): ''' Gets incomplete laps for a track session. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :authorization: Administrators, riders and spectators. :returns: Details of incomplete laps. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'get_incomplete_laps' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check check = api_utils.check_if_not_found(Session, method, session_name) if check != True: return check session = Session.objects.get(name=session_name, track__name=track_name) laps = Lap.objects.filter(session=session, finish__isnull=True) logger.info('%s: %s' % (method, data)) return ApiResult(method, ok=True, data=laps) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def server_poweroff(cancel_unfinished_laps, reboot): ''' Powers off the server. :param cancel_unfinished_laps: Cancel any unfinished laps before shutdown. :type cancel_unfinished_laps: Boolean :param reboot: Denoting whether server should be rebooted after shutdown. :type reboot: Boolean :authorization: Administrators. :broadcast: Administrators, riders, spectators and sensors. :returns: Details of impending shutdown. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'server_poweroff' try: data = 'TODO: Shutting down server...' logger.info('%s: %s' % (method, data)) # TODO: Broadcast to everyone # TODO: Shutdown/Reboot return ApiResult(method, ok=True, data=data) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def remove_rider(rider_name): ''' Removes a rider, including all track, session and lap data. :param rider_name: Name of rider to be removed. :type rider_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of removed rider. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'remove_rider' try: check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check rider = Rider.objects.get(name=rider_name) rider.delete() logger.info('%s: %s' % (method, rider_name)) result = ApiResult(method, ok=True, data=rider_name) # TODO: Broadcast result return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def change_rider(rider_name, new_rider_name): ''' Changes the riders name. :param rider_name: Current name of rider. :type rider_name: str :param new_rider_name: New unique name of rider. :type new_rider_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of changed rider. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'change_rider' try: check = api_utils.check_if_found(Rider, method, new_rider_name) if check != True: return check check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check rider = Rider.objects.get(name=rider_name) rider.name = new_rider_name rider.save() logger.info('%s: %s' % (method, rider.name)) result = ApiResult(method, ok=True, data=rider) # TODO: Broadcast result return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def _verify_type(self, server, actual, expected, call): match = isinstance(actual, expected) if not match: error = "Method must return %s, error in: %s" % (expected.__name__, call) logger.error(error) result = ApiResult(call, ok=False, data=error) server.sendMessage(result.toJSON()) return match
def onMessage(self, msg, binary): if binary: return try: self._handler.process(self, msg) except Exception as e: logger.error('Unhandled exception: %s' % e) error = type(e).__name__ + ' from message: ' + msg result = ApiResult('Unknown', ok=False, data=error) self.sendMessage(result.toJSON())
def _load_data(self, server, msg): if 'call' not in msg: error = "Message missing 'call': %s" % msg logger.error(error) result = ApiResult(call=None, ok=False, data=error) server.sendMessage(result.toJSON()) return data = json.loads(msg) if 'args' not in data: data['args'] = {} return data
def change_session(track_name, session_name, new_session_name=None, new_track_name=None): ''' Changes the session or track name. :param track_name: Name of track. :type track_name: str :param session_name: Current session name. Must exist for track. :type session_name: str :param session_name: New unique session name. :type session_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of changed session. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'change_session' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check if not Session.objects.filter(track__name=track_name, name=session_name).exists(): error = 'Session not found' return ApiResult(method, ok=False, data=error) if new_session_name == None and new_track_name == None: error = 'New session or track name is required' # TODO: i18n return ApiResult(method, ok=False, data=error) if new_track_name != None: check = api_utils.check_if_not_found(Track, method, new_track_name) if check != True: return check session = Session.objects.get(name=session_name) if new_session_name != None: if Session.objects.filter(track=session.track, name=new_session_name).exists(): error = 'Session already exists' return ApiResult(method, ok=False, data=error) session.name = new_session_name if new_track_name != None: session.track = Track.objects.get(name=new_track_name) session.save() logger.info('%s: %s' % (method, session.name)) result = ApiResult(method, ok=True, data=session) # TODO: Broadcast return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def change_rider_for_lap(track_name, session_name, rider_name, start_time, new_rider_name): ''' Changes the rider associated with a lap and its sensor events. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :param rider_name: Name of current rider for lap. :type rider_name: str :param start_time: Start time of lap. :type time: datetime :param new_rider_name: Name of new rider for lap. :type new_rider_name: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of changed lap. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'change_rider_for_lap' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check check = api_utils.check_if_not_found(Session, method, session_name) if check != True: return check check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check check = api_utils.check_if_not_found(Rider, method, new_rider_name) if check != True: return check session = Session.objects.get(name=session_name, track__name=track_name) rider = Rider.objects.get(name=rider_name) new_rider = Rider.objects.get(name=new_rider_name) lap = Lap.objects.get(session=session, rider=rider, \ start__time=start_time) lap.rider = new_rider lap.save() logger.info( 'Changed rider for lap starting: %s from: %s to: %s in session: %s' \ % (start_time, rider_name, new_rider_name, session_name)) return ApiResult(method, ok=True, data=lap) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def _add_sensor_event_start(method, session, rider, sensor, time): if Lap.objects.filter(session=session, rider=rider, \ finish__isnull=True).exists(): error = 'Unable to start lap as an incomplete lap for rider %s in ' \ 'session %s already exists' % (rider.name, session.name) # TODO: i18n return ApiResult(method, ok=False, data=error) lap = Lap.objects.create(session=session, rider=rider) lap.save() sensor_event = SensorEvent.objects.create(lap=lap, sensor=sensor, time=time) sensor_event.save() lap.start = sensor_event lap.save() logger.info('Lap started: %s rider: %s' % (timezone.localtime(time), rider.name)) return ApiResult(method, ok=True, data=lap)
def get_riders(): ''' Gets all riders. :authorization: Administrators, riders and spectators. :returns: Details of riders. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'get_riders' try: riders = Rider.objects.all() logger.info('%s: %s' % (method, riders)) return ApiResult(method, ok=True, data=riders) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def _get_api_method(self, server, call): if 'lap' in call: method = getattr(api_lap, call) elif 'rider' in call: method = getattr(api_rider, call) elif 'session' in call: method = getattr(api_session, call) elif 'track' in call: method = getattr(api_track, call) else: method = getattr(api, call) if not method: error = "Method not implemented in API: %s" % call logger.error(error) result = ApiResult(call, ok=False, data=error) server.sendMessage(result.toJSON()) return return method
def remove_lap(track_name, session_name, rider_name, start_time): ''' Removes a lap and associated sensor events. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :param rider_name: Name of rider. :type rider_name: str :param start_time: Start time of lap. :type time: datetime :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of removed lap. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'remove_lap' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check check = api_utils.check_if_not_found(Session, method, session_name) if check != True: return check check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check session = Session.objects.get(name=session_name, track__name=track_name) rider = Rider.objects.get(name=rider_name) lap = Lap.objects.get(session=session, rider=rider, \ start__time=start_time) lap.delete() events = SensorEvent.objects.filter(lap=lap) events.delete() logger.info('Removed lap starting: %s for rider: %s in session: %s' \ % (start_time, rider_name, session_name)) return ApiResult(method, ok=True, data=lap) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def remove_incomplete_laps(track_name, session_name, rider_name): ''' Removes incomplete laps. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :param rider_name: Name of rider. :type rider_name: str :authorization: Administrators. :broadcast: Administrators, riders, spectators and sensors. :returns: Details of incomplete laps removed. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' # TODO: Role enforcement - admin or current rider only method = 'remove_incomplete_laps' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check check = api_utils.check_if_not_found(Session, method, session_name) if check != True: return check check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check session = Session.objects.get(name=session_name, track__name=track_name) rider = Rider.objects.get(name=rider_name) laps = Lap.objects.filter(session=session, rider=rider, \ finish__isnull=True) count = laps.count() laps.delete() logger.info( 'Cancelled %s incomplete laps for rider: %s in session: %s' \ % (count, rider_name, session_name)) return ApiResult(method, ok=True, data=laps) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def check_if_found(calling_object, calling_method, name): ''' Checks to ensure that an object with specified name doesn't already exist in the database. If the calling Django object does exists, method returns a failed ApiResult with error message, otherwise returns True. ''' if calling_object.objects.filter(name=name).exists(): error = '%s already exists' % calling_object.__name__ # TODO: i18n return ApiResult(calling_method, ok=False, data=error) return True
def get_all_data(modified=None): ''' Gets all data and settings. :param modified: Only data modified on or after this time is returned. :type modified: datetime :authorization: Administrators. :returns: Relevant data. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'get_all_data' try: data='TODO: Data goes here...' logger.info('%s: %s' % (method, data)) return ApiResult(method, ok=True, data=data) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def _add_sensor_event_finish(method, session, rider, sensor, time): if not Lap.objects.filter(session=session, rider=rider, \ finish__isnull=True).exists(): error = 'Unable to finish lap as no incomplete lap was found for ' \ 'rider %s in session %s' % (rider.name, session.name) # TODO: i18n return ApiResult(method, ok=False, data=error) laps = Lap.objects.filter(session=session, rider=rider, \ finish__isnull=True) if laps.count() > 1: error = 'Unable to finish lap as more than one incomplete lap was ' \ 'found for rider %s in session %s' % (rider.name, session.name) # TODO: i18n return ApiResult(method, ok=False, data=error) lap = laps[0] sensor_event = SensorEvent.objects.create(lap=lap, sensor=sensor, time=time) sensor_event.save() lap.finish = sensor_event lap.save() logger.info('Lap finished: %s rider: %s time: %s' % (timezone.localtime(time), rider.name, lap)) return ApiResult(method, ok=True, data=lap)
def add_track(track_name, track_distance, lap_timeout, unit_of_measurement): ''' Add a new track. :param track_name: Unique name of track. :type track_name: str :param track_distance: Total track distance. :type track_distance: float :param lap_timeout: Maximum number of seconds before a lap times out. :type lap_timeout: integer :param unit_of_measurement: Unit of measurement, either Metric or Imperial. :type unit_of_measurement: str :authorization: Administrators. :broadcast: Administrators, riders and spectators. :returns: Details of new track. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' # TODO: Role enforcement - admins only method = 'add_track' try: check = api_utils.check_if_found(Track, method, track_name) if check != True: return check if unit_of_measurement not in dict(settings.UNIT_OF_MEASUREMENT): error = 'Invalid unit of measurement' # TODO: i18n return ApiResult(method, ok=False, data=error) track = Track.objects.create(name=track_name, distance=track_distance, timeout=lap_timeout, unit_of_measurement=unit_of_measurement) logger.info('%s: %s' % (method, track.name)) result = ApiResult(method, ok=True, data=track) # TODO: Broadcast result return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def get_session_statistics(track_name, session_name): ''' Gets session statistics for all riders. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :authorization: Administrators, riders and spectators. :returns: Session statistics. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'get_session_statistics' try: stats = 'TODO: Get session statistics' logger.info('%s: %s' % (method, stats)) return ApiResult(method, ok=True, data=stats) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def get_sessions(track_name): ''' Gets all sessions for a track. :param track_name: Name of track. :type track_name: str :authorization: Administrators, riders and spectators. :returns: Details of track sessions. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'get_sessions' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check sessions = Session.objects.filter(track__name=track_name) logger.info('%s: %s' % (method, sessions)) return ApiResult(method, ok=True, data=sessions) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def get_rider(rider_name): ''' Gets a rider. :param rider_name: Name of rider. :type rider_name: str :authorization: Administrators, riders and spectators. :returns: Details of rider. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'get_rider' try: check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check rider = Rider.objects.get(name=rider_name) logger.info('%s: %s' % (method, rider_name)) return ApiResult(method, ok=True, data=rider) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def backup_to_cloud(modified=None): ''' Backup data to cloud. :param modified: Only data modified on or after this time is backed up. :type modified: datetime :authorization: Administrators. :broadcast: Administrators. :returns: Details of backup result. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' # TODO: Role enforcement - admins only method = 'backup_to_cloud' try: data='TODO: Cloud backup result...' logger.info('%s: %s' % (method, data)) # TODO: Backup # TODO: Broadcast return ApiResult(method, ok=True, data=data) except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)
def _add_sensor_event_sector(method, session, rider, sensor, time): error = 'Sector based sensors not currently supported' return ApiResult(method, ok=False, data=error)
def add_sensor_event(track_name, session_name, rider_name, sensor_name, time): ''' Adds a new sensor event. Depends on sensor position to determine if start, sector or finish time. :param track_name: Name of track. :type track_name: str :param session_name: Name of session. Must exist for track. :type session_name: str :param rider_name: Name of rider. :type rider_name: str :param sensor_name: Name of sensor. Must exist for track. :type sensor_name: str :param time: Local time of sensor event. :type time: datetime :authorization: Administrators and sensors. :broadcast: Administrators, riders, spectators and sensors. :returns: Details of sensor event. :rtype: Instance of :class:`laptimer.models.ApiResult`. ''' method = 'add_sensor_event' try: check = api_utils.check_if_not_found(Track, method, track_name) if check != True: return check check = api_utils.check_if_not_found(Session, method, session_name) if check != True: return check check = api_utils.check_if_not_found(Rider, method, rider_name) if check != True: return check check = api_utils.check_if_not_found(Sensor, method, sensor_name) if check != True: return check if time is None or type(time) is not datetime.datetime: error = 'Time must be valid datetime' # TODO: i18n return ApiResult(method, ok=False, data=error) session = Session.objects.get(name=session_name, track__name=track_name) rider = Rider.objects.get(name=rider_name) sensor = Sensor.objects.get(track__name=track_name, name=sensor_name) if sensor.sensor_pos == settings.SENSOR_POS_START: result = _add_sensor_event_start(method, session, rider, sensor, time) elif sensor.sensor_pos == settings.SENSOR_POS_FINISH: result = _add_sensor_event_finish(method, session, rider, sensor, time) elif sensor.sensor_pos == settings.SENSOR_POS_START_FINISH: result = _add_sensor_event_start_finish(method, session, rider, sensor, time) elif sensor.sensor_pos == settings.SENSOR_POS_SECTOR: result = _add_sensor_event_sector(method, session, rider, sensor, time) else: error = 'Unknown sensor position: %s' % sensor_pos # TODO: i18n result = ApiResult(method, ok=False, data=error) if result.ok: # TODO: Broadcast pass return result except Exception as e: logger.error('Exception caught in %s: %s' % (method, e)) error = type(e).__name__ return ApiResult(method, ok=False, data=error)