Esempio n. 1
0
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
Esempio n. 2
0
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
Esempio n. 3
0
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
Esempio n. 4
0
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
Esempio n. 5
0
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
Esempio n. 6
0
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
Esempio n. 7
0
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)
Esempio n. 8
0
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'))
Esempio n. 9
0
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'))
Esempio n. 10
0
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