def system_career_graph(id):
    system = System.query.filter_by(id=id).one()
    stations = system.stations
    limit = today_datetime()
    datasets = []
    CBS = CareerBatchSubmission
    # colors from https://htmlcolorcodes.com/color-chart/
    colors = '#cd6155 #9b59b6 #2980b9 #1abc9c #16a085 #f1c40f #f39c12 #7f8c8d #f1948a #85c1e9'.split(
        ' ')
    for idx, station in enumerate(stations):
        data = []
        q = CBS.query.filter(CBS.station_id == station.id,
                             CBS.when <= limit).order_by(CBS.when)
        for batch in q:
            if batch.factor:
                data.append({
                    'x': batch.when.strftime("%Y-%m-%dT%H:%M:%SZ"),
                    'y': batch.factor
                })
        if data:
            datasets.append({
                'label': station.name,
                'data': data,
                'backgroundColor': colors[idx],
            })
    ctx = {
        'system': system,
        'datasets': json.dumps(datasets),
        'systems': System.query.all()
    }
    return render_template('system_career_factor.html', **ctx)
Пример #2
0
def render_fuel_add_response(current_station, token):
    start_dt = now()
    reference_date = today_datetime()
    rows = []

    seen = set()

    for stat in FPS.query.filter(FPS.last_reading >= reference_date).order_by(
            FPS.last_price, FPS.station_name):
        station_name = stat.station_short_name or stat.station_name
        seen.add(station_name)
        diff = start_dt - stat.last_reading
        rows.append({
            'station_name': station_name,
            'is_current': stat.station_id == current_station.id,
            'price_per_g': stat.last_price,
            'age': gct_duration(start_dt - stat.last_reading),
        })
    # add estimations
    estimations = [
        e for e in FuelPriceEstimation.all_today()
        if e.station.short not in seen
    ]
    for e in estimations:
        rows.append({
            'station_name': e.station.short,
            'is_current': False,
            'price_per_g': e.price_per_g,
            'age': '(est.)',
        })
    rows.sort(key=lambda e: e['price_per_g'])

    return str(render_template('fuel_short_table.html', rows=rows,
                               token=token))
Пример #3
0
def system_fuel_price(id):
    system = System.query.filter_by(id=id).one()
    stations = system.stations
    limit = today_datetime()
    datasets = []
    colors = '#cd6155 #9b59b6 #2980b9 #1abc9c #16a085 #f1c40f #f39c12 #7f8c8d #f1948a #85c1e9'.split(
        ' ')
    FPR = FuelPriceReading
    for idx, station in enumerate(stations):
        data = []
        q = FPR.query.filter(FPR.station_id == station.id,
                             FPR.when < limit).order_by(FPR.when.asc())
        for reading in q.all():
            data.append({
                'x': reading.when.strftime("%Y-%m-%dT%H:%M:%SZ"),
                'y': reading.price_per_g
            })
        if data:
            datasets.append({
                'label': station.name,
                'data': data,
                'borderColor': colors[idx],
            })
    ctx = {
        'system': system,
        'datasets': json.dumps(datasets),
        'systems': System.query.all()
    }
    return render_template('system_fuel_price.html', **ctx)
Пример #4
0
def career_station_needs_update(system, station):
    try:
        st = get_station(system, station, create=False)
    except AssertionError:
        return jsonify({'needs_update': True})

    existing = CareerBatchSubmission.query.filter(CareerBatchSubmission.when > today_datetime()).filter_by(station_id=st.id) \
             .order_by(CareerBatchSubmission.when.desc()).first()
    result = existing is None

    return jsonify({'needs_update': result})
Пример #5
0
def fuel_lowest(token):
    token = Token.query.filter_by(token=token).first()
    assert token, 'Need valid token'
    compare = bool(request.args.get('cmp', False))
    n = now()
    limit = today_datetime()

    refuel = FPS.query.filter(FPS.last_reading > limit).order_by(
        FPS.last_price.asc())
    measured = {r.station_short_name: r.last_price for r in refuel}
    measured_ts = {r.station_short_name: r.last_reading for r in refuel}

    estimations = FuelPriceEstimation.today_as_dict()

    all_short_names = set(estimations.keys()) | set(measured.keys())

    rows = [{
        'station_short_name': short,
        'last_price': measured.get(short),
        'measured_timestamp': measured_ts.get(short),
        'estimated_price': estimations.get(short),
    } for short in all_short_names]
    if compare:
        for row in rows:
            if row['last_price'] and row['estimated_price']:
                error = 1000 * abs(row['last_price'] - row['estimated_price']
                                   ) / row['estimated_price']
                row['error'] = error
                if error < 5:
                    classification = 'good'
                elif error < 20:
                    classification = 'ok'
                else:
                    classification = 'bad'
                row['classification'] = classification
    rows.sort(key=lambda r: r['last_price'] or r['estimated_price'])

    return render_template('fuel_refuel.html', rows=rows, compare=compare)
Пример #6
0
def fuel_stats_json(token):
    token = Token.query.filter_by(token=token).first()
    assert token, 'Need valid token'
    n = now()

    estimations = FuelPriceEstimation.today_as_dict()
    ref_dt = today_datetime()

    def make_output_dict(r):
        has_current_reading = r.last_reading >= ref_dt
        common = {
            'station_short_name': r.station_short_name,
            'estimation': estimations.get(r.station_short_name),
            'station_name': r.station_name,
            'system_name': r.system_name,
            'min_price': r.min_price,
            'max_price': r.max_price,
        }
        if has_current_reading:
            return dict(
                **common,
                last_price=r.last_price,
                last_reading=r.last_reading.isoformat(),
            )
        elif common['estimation'] is not None:
            return common
        else:
            return None

    rows = []
    for r in FPS.query.order_by(FPS.last_price.asc()):
        d = make_output_dict(r)
        if d is not None:
            rows.append(d)
    rows.sort(key=lambda r: r.get('last_price') or r.get('estimation'))
    return jsonify({'stations': rows})
def career_task_add():
    payload = request.get_json(force=True)
    mandatory = set(('token', 'station', 'system', 'career', 'rank', 'tasks'))
    missing_attrs = [a for a in mandatory if not payload.get(a)]
    if missing_attrs:
        message = 'Missing attributes: ' + ', '.join(missing_attrs)
        return jsonify({
            'recorded': False,
            'missing': missing_attrs,
            message: message
        })

    station_name = payload['station']
    try:
        token = Token.verify(payload['token'])
        token.record_script_version(payload.get('script_version'))
    except InvalidTokenException:
        return jsonify({'recorded': False, 'message': 'Invalid token'})

    if token is None:
        return jsonify({'recorded': False, 'message': 'Invalid token'})
    if 'Confined to the' in station_name or 'Doing activity' in station_name:
        return jsonify({
            'recorded':
            False,
            'message':
            '{} does not look like a valid station name'.format(station_name)
        })
    station = get_station(payload['system'], station_name)

    batch = CareerBatchSubmission(
        token=token,
        character=token.character,
        station=station,
        career=payload['career'],
        rank=payload['rank'],
    )
    db.session.add(batch)

    response = {'character': token.character.name}

    factors = []

    for task, bonus in payload['tasks'].items():
        bonus = float(bonus)
        career_task = CareerTask.query.filter_by(name=task).first()
        if career_task is None:
            career_task = CareerTask(
                name=task,
                career=payload['career'],
                bonus_baseline=bonus,
            )
            db.session.add(career_task)
        elif career_task.bonus_baseline is None or career_task.bonus_baseline > bonus:
            career_task.bonus_baseline = bonus

        tr = CareerTaskReading(
            batch_submission=batch,
            career_task=career_task,
            bonus=bonus,
        )
        db.session.add(tr)
        f = tr.factor
        factors.append(f)
        if f > 2.1:
            print(
                'SUSPICIOUS READING of factor {}, station {}, task {}, token {}'
                .format(
                    f,
                    station_name,
                    task,
                    token.id,
                ))
    factor = max(factors)
    batch.factor = factor
    if factor:
        print('Recorded factor {} for station {}, {}'.format(
            factor, station.name, datetime.now()))

    response['recorded'] = True
    response['factor'] = factor

    # find factors for other stations in the system
    date_limit = today_datetime()
    stations = Station.query.filter_by(system_id=station.system_id)
    system_factors = {}

    cbs = CareerBatchSubmission
    for st in stations.all():
        if st.name == station_name:
            continue
        qry = cbs.query.filter(cbs.when > date_limit).filter_by(
            station_id=st.id).order_by(cbs.when.desc())
        bs = qry.first()
        if bs:
            factor = max(o.factor for o in bs.readings)
            system_factors[st.name] = factor
    if system_factors:
        response['system_factors'] = system_factors

    db.session.commit()

    return jsonify(response)