def write_ride(ride_id, team=None): """ Takes the specified ride_id and merges together the V1 and V2 API data into model objects and writes them to the database. :param ride_id: The ride that should be filled in and written to DB. :type ride_id: int :param team: The team club entity. :type team: :class:`stravatools.bafs.model.Club` :return: The written Ride object. """ v1sess = V1ServerProxy() v2sess = V2ServerProxy() v1data = v1sess.get_ride(ride_id) v2data = v2sess.get_ride(ride_id) # logger().info(repr(v2data)) if v2data["start_latlng"]: (lat, lon) = v2data["start_latlng"] start_geo = WKTSpatialElement("POINT({lat} {lon})".format(lat=lat, lon=lon)) else: start_geo = None if v2data["end_latlng"]: (lat, lon) = v2data["end_latlng"] end_geo = WKTSpatialElement("POINT({lat} {lon})".format(lat=lat, lon=lon)) else: end_geo = None athlete_id = v1data["athlete"]["id"] # In the BAFS model, an athlete only belongs to a single team club (at most - there are a few unclubbed riders) athlete = Athlete(id=athlete_id, team=team, name=v1data["athlete"]["name"]) db.session.merge(athlete) # @UndefinedVariable db.session.commit() # @UndefinedVariable if start_geo is not None or end_geo is not None: ride_geo = RideGeo() ride_geo.start_geo = start_geo ride_geo.end_geo = end_geo ride_geo.ride_id = v2data["id"] db.session.merge(ride_geo) # @UndefinedVariable try: ride = Ride( id=v2data["id"], athlete=athlete, name=v2data["name"], start_date=parser.parse(v2data["start_date_local"]).replace(tzinfo=None), distance=units.meters_to_miles(v2data["distance"]), average_speed=units.metersps_to_mph(v1data["averageSpeed"]), maximum_speed=units.kph_to_mph( v1data["maximumSpeed"] / 1000.0 ), # Not sure why this is in meters per hour ... !? elapsed_time=v2data["elapsed_time"], moving_time=v2data["moving_time"], location=v2data.get("location"), commute=v1data["commute"], trainer=v1data["trainer"], elevation_gain=units.meters_to_feet(v2data["elevation_gain"]), ) db.session.merge(ride) # @UndefinedVariable logger().debug( 'Writing ride: {athlete!r}: "{ride!r}" on {date}'.format( athlete=athlete.name, ride=ride.name, date=ride.start_date.strftime("%m/%d/%y") ) ) db.session.commit() # @UndefinedVariable except: logger().exception("Error adding ride: {0}".format(ride_id)) raise return ride
def write_ride(activity): """ Takes the specified activity and writes it to the database. :param activity: The Strava :class:`stravalib.model.Activity` object. :type activity: stravalib.model.Activity :return: A tuple including the written Ride model object, whether to resync segment efforts, and whether to resync photos. :rtype: bafs.model.Ride """ if activity.start_latlng: start_geo = WKTSpatialElement('POINT({lon} {lat})'.format(lat=activity.start_latlng.lat, lon=activity.start_latlng.lon)) else: start_geo = None if activity.end_latlng: end_geo = WKTSpatialElement('POINT({lon} {lat})'.format(lat=activity.end_latlng.lat, lon=activity.end_latlng.lon)) else: end_geo = None athlete_id = activity.athlete.id # Fail fast for invalid data (this can happen with manual-entry rides) assert activity.elapsed_time is not None assert activity.moving_time is not None assert activity.distance is not None # Find the model object for that athlete (or create if doesn't exist) athlete = db.session.query(Athlete).get(athlete_id) if not athlete: # The athlete has to exist since otherwise we wouldn't be able to query their rides raise ValueError("Somehow you are attempting to write rides for an athlete not found in the database.") if start_geo is not None or end_geo is not None: ride_geo = RideGeo() ride_geo.start_geo = start_geo ride_geo.end_geo = end_geo ride_geo.ride_id = activity.id db.session.merge(ride_geo) ride = db.session.query(Ride).get(activity.id) new_ride = (ride is None) if ride is None: ride = Ride(activity.id) # Check to see if we need to pull down efforts for this ride if new_ride: ride.detail_fetched = False # Just to be explicit if not activity.manual: ride.track_fetched = False # photo_count refers to instagram photos if activity.photo_count > 1: ride.photos_fetched = False else: ride.photos_fetched = None else: if round(ride.distance, 2) != round(float(unithelper.miles(activity.distance)), 2): log.info("Queing resync of details for activity {0!r}: distance mismatch ({1} != {2})".format(activity, ride.distance, unithelper.miles(activity.distance))) ride.detail_fetched = False ride.track_fetched = False ride.athlete = athlete update_ride_from_activity(strava_activity=activity, ride=ride) db.session.add(ride) return ride