def sml_import(xmlfile, user): filename = xmlfile.filename tree = objectify.parse(xmlfile).getroot() move = parse_move(tree) move.source = os.path.abspath(filename) move.import_module = __name__ device = parse_device(tree) persistent_device = Device.query.filter_by(serial_number=device.serial_number).scalar() if persistent_device: if not persistent_device.name: flash("update device name to '%s'" % device.name) persistent_device.name = device.name else: assert device.name == persistent_device.name device = persistent_device else: db.session.add(device) if Move.query.filter_by(user=user, date_time=move.date_time, device=device).scalar(): flash("%s at %s already exists" % (move.activity, move.date_time), 'warning') else: move.user = user move.device = device db.session.add(move) samples = tree.DeviceLog.Samples.iterchildren() for sample in parse_samples(samples, move): db.session.add(sample) postprocess_move(move) db.session.commit() return move
def sml_import(xmlfile, user, request_form): filename = xmlfile.name tree = objectify.parse(xmlfile).getroot() move = parse_move(tree) move.source = os.path.abspath(filename) move.import_module = __name__ device = parse_device(tree) persistent_device = Device.query.filter_by(serial_number=device.serial_number).scalar() if persistent_device: if not persistent_device.name: flash("update device name to '%s'" % device.name) persistent_device.name = device.name else: assert device.name == persistent_device.name device = persistent_device else: db.session.add(device) if Move.query.filter_by(user=user, date_time=move.date_time, device=device).scalar(): flash("%s at %s already exists" % (move.activity, move.date_time), 'warning') else: move.user = user move.device = device db.session.add(move) samples = tree.DeviceLog.Samples.iterchildren() for sample in parse_samples(samples, move): db.session.add(sample) postprocess_move(move) db.session.commit() return move
def gpx_import(xmlfile, user, request_form): # Get users options import_options = get_gpx_import_options(request_form) if import_options == None: return filename = xmlfile.filename try: tree = objectify.parse(xmlfile).getroot() except Exception as e: flash("Failed to parse the GPX file! %s" % e.msg) return for namespace in GPX_NAMESPACES.values(): if tree.tag.startswith(namespace): gpx_namespace = namespace break else: flash("Unsupported GPX format version: %s" % tree.tag) return device = create_device() persistent_device = Device.query.filter_by( serial_number=device.serial_number).scalar() if persistent_device: if not persistent_device.name: flash("update device name to '%s'" % device.name) persistent_device.name = device.name else: assert device.name == persistent_device.name device = persistent_device else: db.session.add(device) move = create_move() move.source = os.path.abspath(filename) move.import_module = __name__ # Parse samples all_samples = parse_samples(tree, move, gpx_namespace, import_options) derive_move_infos_from_samples(move, all_samples) if Move.query.filter_by(user=user, date_time=move.date_time, device=device).scalar(): flash("%s at %s already exists" % (move.activity, move.date_time), 'warning') else: move.user = user move.device = device db.session.add(move) for sample in all_samples: db.session.add(sample) postprocess_move(move) db.session.commit() return move
def gpx_import(xmlfile, user, request_form): # Get users options import_options = get_gpx_import_options(request_form) if import_options == None: return filename = xmlfile.filename try: tree = objectify.parse(xmlfile).getroot() except Exception as e: flash("Failed to parse the GPX file! %s" % e.msg) return for namespace in GPX_NAMESPACES.values(): if tree.tag.startswith(namespace): gpx_namespace = namespace break else: flash("Unsupported GPX format version: %s" % tree.tag) return device = create_device() persistent_device = Device.query.filter_by(serial_number=device.serial_number).scalar() if persistent_device: if not persistent_device.name: flash("update device name to '%s'" % device.name) persistent_device.name = device.name else: assert device.name == persistent_device.name device = persistent_device else: db.session.add(device) move = create_move() move.source = os.path.abspath(filename) move.import_module = __name__ # Parse samples all_samples = parse_samples(tree, move, gpx_namespace, import_options) derive_move_infos_from_samples(move, all_samples) if Move.query.filter_by(user=user, date_time=move.date_time, device=device).scalar(): flash("%s at %s already exists" % (move.activity, move.date_time), 'warning') else: move.user = user move.device = device db.session.add(move) for sample in all_samples: db.session.add(sample) postprocess_move(move) db.session.commit() return move
def old_xml_import(xmlfile, user, request_form): filename = xmlfile.filename data = xmlfile.readlines() if isinstance(data[0], bytes): data = [str(x.decode('utf-8')) for x in data] data[0] = data[0] + "<sml>" data.append("</sml>") filematch = re.match( r'log-([A-F0-9]{16})-\d{4}-\d{2}-\d{2}T\d{2}_\d{2}_\d{2}-\d+\.xml', filename) if not filematch: flash("illegal filename: '%s'" % filename, 'error') return serial_number = filematch.group(1) tree = objectify.fromstring("\n".join(data).encode('utf-8')) move = parse_move(tree) move.source = filename move.import_module = __name__ device = Device.query.filter_by(serial_number=serial_number).scalar() if not device: device = Device() device.serial_number = serial_number db.session.add(device) if Move.query.filter_by(user=user, date_time=move.date_time, device=device).scalar(): flash("%s at %s already exists" % (move.activity, move.date_time), 'warning') else: move.user = user move.device = device db.session.add(move) for sample in parse_samples(tree.Samples.iterchildren(), move): db.session.add(sample) postprocess_move(move) db.session.commit() return move
def old_xml_import(xmlfile, user, request_form): filename = xmlfile.filename data = xmlfile.readlines() if isinstance(data[0], bytes): data = [str(x.decode('utf-8')) for x in data] data[0] = data[0] + "<sml>" data.append("</sml>") filematch = re.match(r'log-([A-F0-9]{16})-\d{4}-\d{2}-\d{2}T\d{2}_\d{2}_\d{2}-\d+\.xml', filename) if not filematch: flash("illegal filename: '%s'" % filename, 'error') return serial_number = filematch.group(1) tree = objectify.fromstring("\n".join(data).encode('utf-8')) move = parse_move(tree) move.source = filename move.import_module = __name__ device = Device.query.filter_by(serial_number=serial_number).scalar() if not device: device = Device() device.serial_number = serial_number db.session.add(device) if Move.query.filter_by(user=user, date_time=move.date_time, device=device).scalar(): flash("%s at %s already exists" % (move.activity, move.date_time), 'warning') else: move.user = user move.device = device db.session.add(move) for sample in parse_samples(tree.Samples.iterchildren(), move): db.session.add(sample) postprocess_move(move) db.session.commit() return move
def move(id): move = Move.query.filter_by(id=id).first_or_404() if not move.public and move.user != current_user: return app.login_manager.unauthorized() samples = move.samples.order_by(Sample.time.asc()).all() events = [sample for sample in samples if sample.events] filtered_events = [] pauses = [] laps = [] pause_begin = None for sample in events: assert len(sample.events.keys()) == 1 if 'pause' in sample.events: state = sample.events['pause']['state'].lower() == 'true' if state: pause_begin = sample elif not state and pause_begin: pauses.append([pause_begin, sample]) elif 'lap' in sample.events: laps.append(sample) else: filtered_events.append(sample) model = { 'BING_MAPS_API_KEY': app.config['BING_MAPS_API_KEY'] if 'BING_MAPS_API_KEY' in app.config else None, 'move': move, 'samples': samples, 'events': filtered_events, 'pauses': pauses, 'laps': laps } gps_samples = [ sample for sample in samples if sample.sample_type and sample.sample_type.startswith('gps-') and sample.latitude ] model['gps_samples'] = gps_samples if gps_samples: if not move.location_address: postprocess_move(move) flash( "got %d GPS samples but no location. recalculated" % len(gps_samples), 'warning') db.session.commit() calculate_distances(model, move.samples) if 'swimming' in move.activity: swimming_events = [ sample for sample in filtered_events if 'swimming' in sample.events ] model['swimming_events'] = swimming_events model['swimming_style_changes'] = [ sample for sample in swimming_events if sample.events['swimming']['type'] == 'StyleChange' ] model['swimming_turns'] = [ sample for sample in swimming_events if sample.events['swimming']['type'] == 'Turn' ] swimming_strokes = [ sample for sample in swimming_events if sample.events['swimming']['type'] == 'Stroke' ] model['swimming_strokes'] = swimming_strokes pause_samples = list(itertools.chain.from_iterable(pauses)) model['swimming_strokes_and_pauses'] = sorted( swimming_strokes + pause_samples, key=lambda sample: sample.time) model['swim_pace'] = timedelta(seconds=move.duration.total_seconds() / move.distance) if move.stroke_count: assert len(model['swimming_strokes']) == move.stroke_count if current_user.is_authenticated: if current_user.has_strava() and move.strava_activity_id is not None: client = strava.get_strava_client(current_user) strava_activity = client.get_activity( activity_id=move.strava_activity_id) model['strava_activity_name'] = strava_activity.name # eg. 'Pool swimming' → 'pool_swimming' activity_name = move.activity.lower().replace(' ', '_') try: return render_template("move/%s.html" % activity_name, **model) except TemplateNotFound: # Fall-back to generic template return render_template("move/_move.html", **model)
def move(id): move = Move.query.filter_by(id=id).first_or_404() if not move.public and move.user != current_user: return app.login_manager.unauthorized() samples = move.samples.order_by(Sample.time.asc()).all() events = [sample for sample in samples if sample.events] filtered_events = [] pauses = [] laps = [] pause_begin = None for sample in events: assert len(sample.events.keys()) == 1 if 'pause' in sample.events: state = sample.events['pause']['state'].lower() == 'true' if state: pause_begin = sample elif not state and pause_begin: pauses.append([pause_begin, sample]) elif 'lap' in sample.events: laps.append(sample) else: filtered_events.append(sample) model = { 'BING_MAPS_API_KEY': app.config['BING_MAPS_API_KEY'] if 'BING_MAPS_API_KEY' in app.config else None, 'move': move, 'samples': samples, 'events': filtered_events, 'pauses': pauses, 'laps': laps } gps_samples = [sample for sample in samples if sample.sample_type and sample.sample_type.startswith('gps-')] model['gps_samples'] = gps_samples if gps_samples: if not move.location_address: postprocess_move(move) flash(u"got %d GPS samples but no location. recalculated" % len(gps_samples), u'warning') db.session.commit() calculate_distances(model, move.samples) if 'swimming' in move.activity: swimming_events = [sample for sample in filtered_events if 'swimming' in sample.events] model['swimming_events'] = swimming_events model['swimming_style_changes'] = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'StyleChange'] model['swimming_turns'] = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'Turn'] swimming_strokes = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'Stroke'] model['swimming_strokes'] = swimming_strokes pause_samples = list(itertools.chain.from_iterable(pauses)) model['swimming_strokes_and_pauses'] = sorted(swimming_strokes + pause_samples, key=lambda sample: sample.time) model['swim_pace'] = timedelta(seconds=move.duration.total_seconds() / move.distance) if move.stroke_count: assert len(model['swimming_strokes']) == move.stroke_count if current_user.is_authenticated: if current_user.has_strava() and move.strava_activity_id is not None: client = strava.get_strava_client(current_user) strava_activity = client.get_activity(activity_id=move.strava_activity_id) model['strava_activity_name'] = strava_activity.name # eg. 'Pool swimming' → 'pool_swimming' activity_name = move.activity.lower().replace(' ', '_') try: return render_template("move/%s.html" % activity_name, **model) except TemplateNotFound: # Fall-back to generic template return render_template("move/_move.html", **model) except Exception as e: if app.debug or app.testing: raise e else: flash("Failed to load move template of activity '%s'." % activity_name) return redirect(url_for('index'))
def move(id): move = _current_user_filtered(Move.query).filter_by(id=id).first_or_404() samples = move.samples.order_by('time asc').all() events = [sample for sample in samples if sample.events] filtered_events = [] pauses = [] laps = [] pause_begin = None for sample in events: assert len(sample.events.keys()) == 1 if 'pause' in sample.events: state = sample.events['pause']['state'].lower() == 'true' if state: pause_begin = sample elif not state and pause_begin: pauses.append([pause_begin, sample]) elif 'lap' in sample.events: laps.append(sample) else: filtered_events.append(sample) model = {} model['move'] = move model['samples'] = samples model['events'] = filtered_events model['pauses'] = pauses model['laps'] = laps gps_samples = [sample for sample in samples if sample.sample_type and sample.sample_type.startswith('gps-')] model['gps_samples'] = gps_samples if gps_samples: if not move.gps_center_max_distance: postprocess_move(move) flash(u"got %d GPS samples but no center. recalculated" % len(gps_samples), u'warning') db.session.commit() gps_center_max_distance = move.gps_center_max_distance # empirically determined values if gps_center_max_distance < 2000: map_zoom_level = 14 elif gps_center_max_distance < 4000: map_zoom_level = 13 elif gps_center_max_distance < 7500: map_zoom_level = 12 elif gps_center_max_distance < 10000: map_zoom_level = 11 else: map_zoom_level = 10 calculate_distances(model, move.samples) model['map_zoom_level'] = map_zoom_level if 'swimming' in move.activity: swimming_events = [sample for sample in filtered_events if 'swimming' in sample.events] model['swimming_events'] = swimming_events model['swimming_style_changes'] = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'StyleChange'] model['swimming_turns'] = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'Turn'] swimming_strokes = [sample for sample in swimming_events if sample.events['swimming']['type'] == 'Stroke'] model['swimming_strokes'] = swimming_strokes pause_samples = list(itertools.chain.from_iterable(pauses)) model['swimming_strokes_and_pauses'] = sorted(swimming_strokes + pause_samples, key=lambda sample: sample.time) model['swim_pace'] = timedelta(seconds=move.duration.total_seconds() / move.distance) if move.stroke_count: assert len(model['swimming_strokes']) == move.stroke_count # eg. 'Pool swimming' → 'pool_swimming' activity_name = move.activity.lower().replace(' ', '_') try: return render_template("move/%s.html" % activity_name, **model) except TemplateNotFound: # Fall-back to generic template return render_template("move/_move.html", **model) except Exception as e: if app.debug or app.testing: raise e else: flash("Failed to load move template of activity '%s'." % activity_name) return redirect(url_for('index'))
def strava_import(current_user, activity_id): client = get_strava_client(current_user) activity = client.get_activity(activity_id=activity_id) stream_types = [ 'time', 'distance', 'latlng', 'temp', 'heartrate', 'velocity_smooth', 'altitude' ] streams = client.get_activity_streams(activity_id, types=stream_types) activity_string = map_type(activity.type) result = db.session.query( Move.activity_type).filter(Move.activity == activity_string).first() if result: activity_type, = result else: activity_type = None device = find_device(current_user) move = Move() move.user = current_user move.duration = activity.elapsed_time move.ascent = float(activity.total_elevation_gain) move.speed_avg = float(activity.average_speed) move.hr_avg = heart_rate(activity.average_heartrate) move.temperature_avg = celcius_to_kelvin(activity.average_temp) move.device = device move.date_time = activity.start_date_local move.activity = activity_string move.activity_type = activity_type move.distance = float(activity.distance) move.import_date_time = datetime.now() move.import_module = __name__ move.strava_activity_id = activity_id move.public = False move.source = "Strava activity id=%d; external_id='%s'" % ( activity_id, activity.external_id) if streams: lengths = set([len(streams[stream].data) for stream in streams]) assert len(lengths) == 1 length, = lengths else: length = 0 move.speed_max = move.speed_avg all_samples = [] for i in range(0, length): time = timedelta(seconds=streams['time'].data[i]) distance = float(streams['distance'].data[i]) if 'heartrate' in streams: hr = float(streams['heartrate'].data[i]) else: hr = None if 'latlng' in streams: lat, lng = streams['latlng'].data[i] else: lat = None lng = None if 'altitude' in streams: altitude = float(streams['altitude'].data[i]) else: altitude = None if 'velocity_smooth' in streams: speed = float(streams['velocity_smooth'].data[i]) else: speed = None if 'temp' in streams: temperature = celcius_to_kelvin(streams['temp'].data[i]) else: temperature = None sample = Sample() sample.sample_type = SAMPLE_TYPE sample.move = move sample.time = time sample.utc = (activity.start_date + time).replace(tzinfo=None) sample.distance = distance sample.latitude = degree_to_radian(lat) sample.longitude = degree_to_radian(lng) sample.hr = heart_rate(hr) sample.temperature = temperature sample.speed = speed sample.altitude = altitude move.speed_max = max(move.speed_max, speed) all_samples.append(sample) derive_move_infos_from_samples(move, all_samples) db.session.add(move) db.session.flush() postprocess_move(move) db.session.commit() return move