def ship_add():
    payload = request.get_json(force=True)
    token = Token.verify(payload['token'])
    token.record_script_version(payload.get('script_version'))
    station = get_station(payload['system'], payload['station'])
    count = 0
    for ship_sighting in payload['ships']:
        ship_class = autovivify(ShipClass, {'name': ship_sighting['class']})
        ship = autovivify(
            Ship, {
                'registration': ship_sighting['registration'],
                'ship_class': ship_class,
                'name': ship_sighting['name'],
                'captain': ship_sighting['captain'],
            })
        if not ship.captain and ship_sighting['captain']:
            ship.captain = ship_sighting['captain']
            db.session.add(ship)
        db.session.add(ShipSighting(
            ship=ship,
            station=station,
            token=token,
        ))
        count += 1
    db.session.commit()
    print('Recorded {} ship positions on {} by {}'.format(
        count, station.name, token.character.name))
    return jsonify({'success': True, 'num_recorded': count})
Example #2
0
def item_add():
    payload = request.get_json(force=True)
    token = Token.verify(payload['token'])
    token.record_script_version(payload.get('script_version'))
    print('Item {} submitted by {}'.format(payload['name'],
                                           token.character.name))
    item = autovivify(
        Item, {
            'token': token,
            'name': payload['name'],
            'slug': payload.get('slug'),
            'mass_kg': float(payload['mass_kg']),
            'tier': payload['tier'],
            'rarity': autovivify(ItemRarity, dict(name=payload['rarity'])),
            'item_type': autovivify(ItemType, dict(name=payload['type'])),
            'description': payload.get('description'),
        },
        update=True)
    item_aspect_armor(item, payload)
    item_aspect_medical(item, payload)
    item_aspect_food(item, payload)
    item_aspect_weapon(item, payload)
    db.session.commit()

    response = {
        'id':
        item.id,
        'recorded':
        True,
        'message':
        '<a href="https://tracker.tauguide.de/item/detail/{}">this item on the tracker</a>'
        .format(item.id),
    }

    return jsonify(response)
Example #3
0
def add_item_comment():
    payload = request.get_json(force=True)
    try:
        token = Token.verify(payload['token'])
    except InvalidTokenException:
        return jsonify({"success": False, "message": "invalid token."})
    item = Item.query.filter_by(id=payload['item']).one()
    db.session.add(
        ItemComment(token=token, comment=payload['comment'], item=item))
    db.session.commit()
    return jsonify({'success': True})
Example #4
0
def fuel_add():
    payload = request.get_json(force=True)
    mandatory = set(('token', 'station', 'system', 'fuel_g', 'price'))
    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
        })

    token_str = payload['token']
    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'})

    station = get_station(payload['system'], station_name)
    price_per_g = payload['price'] / payload['fuel_g']

    reading = FuelPriceReading(
        token=token,
        station=station,
        fuel_g=payload['fuel_g'],
        price=payload['price'],
        price_per_g=price_per_g,
        when=now(),
    )
    db.session.add(reading)

    response = {
        'recorded': True,
        'systems': {
            station.system.name: {
                station.name: price_per_g
            }
        },
        'message': render_fuel_add_response(station, token_str),
    }
    print('Recorded fuel price {} for station {} by  {}, {}'.format(
        price_per_g, station.name, token.character.name, datetime.now()))

    db.session.commit()

    return jsonify(response)
Example #5
0
def fuel_estimation_add():
    payload = request.get_json(force=True)
    token = Token.verify(payload['token'])
    stations = payload['stations']
    date = today()
    print('Recording fuel price estimations for {} from {}, token {}'.format(
        date, token.character.name, token.id))
    FuelPriceEstimation.query.filter_by(day=date).delete()
    for station_name, price in stations.items():
        try:
            station = Station.query.filter_by(name=station_name).one()
            est = FuelPriceEstimation(
                station=station,
                day=date,
                price_per_g=price,
            )
            db.session.add(est)
        except NoResultFound:
            print('  Found no station {}'.format(station_name))

    db.session.commit()
    return jsonify({'recorded': True})
Example #6
0
def export_fuel_estimation():
    token = Token.verify(request.args.get('token'))
    date_string = request.args.get('date')
    if date_string is None:
        from datetime import date
        day = date.today()
    else:
        day = datetime.strptime(date_string, '%Y-%m-%d').date()

    rs = FuelPriceEstimation.query.filter_by(day=day).order_by(
        FuelPriceEstimation.station_id)
    result = {
        'date': str(day),
        'stations': {
            e.station.short: {
                'name': e.station.name,
                'estimated_fuel_price_per_g': e.price_per_g,
            }
            for e in rs
        }
    }
    return jsonify(result)
def add_vendory_inventory():
    payload = request.get_json(force=True)
    token = Token.verify(payload['token'])
    token.record_script_version(payload.get('script_version'))

    messages = []

    station = get_station(payload['system'], payload['station'])
    vendor_name = payload['vendor']

    print('Vendor {} at {} submitted by {}'.format(vendor_name, station.short
                                                   or station.id,
                                                   token.character.name))

    vendor = Vendor.query.filter_by(station_id=station.id,
                                    name=vendor_name).first()
    if not vendor:
        messages.append('Vendor created.')
        vendor = Vendor(
            station=station,
            name=vendor_name,
        )
        db.session.add(vendor)

    slugs = {iv['slug'] for iv in payload['inventory']} - vendor_blacklist

    items = {
        item.slug: item
        for item in Item.query.filter(Item.slug.in_(sorted(slugs)))
    }
    missing = [slug for slug in slugs if not slug in items]
    if missing:
        return jsonify({
            'recorded':
            False,
            'message':
            'The Tracker does not know about the following item(s): ' +
            ', '.join([linkify(slug) for slug in missing])
        })

    new_timestamp = datetime.utcnow()
    day = today()

    # make sure the inventory is up-to-date
    latest_inventory = VendorInventory.query.filter_by(vendor_id=vendor.id, is_current=True) \
        .order_by(VendorInventory.last_seen.desc()).first()

    has_current_inventory = False
    if latest_inventory:
        if latest_inventory.item_slugs == slugs:
            has_current_inventory = True
            # inventory still up to date
            latest_inventory.last_seen = new_timestamp
            messages.append('Updated inventory timestamp.')
        else:
            latest_inventory.is_current = False
    if not has_current_inventory:
        latest_inventory = VendorInventory(
            token=token,
            vendor=vendor,
            first_seen=new_timestamp,
            last_seen=new_timestamp,
        )
        db.session.add(latest_inventory)
        for item in items.values():
            db.session.add(
                VendorInventoryItem(
                    vendor_inventory=latest_inventory,
                    item=item,
                ))

    # check/update item prices
    def price_tuple(d):
        v = d['price']
        return (float(v), None) if d['currency'] == 'credits' else (None,
                                                                    int(v))

    existing_prices = {
        vipr.item.slug: vipr
        for vipr in VendorItemPriceReading.query.filter_by(
            vendor_inventory_id=latest_inventory.id, day=day)
    }

    prices_updated = False
    for d in payload['inventory']:
        slug = d['slug']
        if slug in vendor_blacklist:
            continue
        credits, bonds = price_tuple(d)
        if slug in existing_prices:
            record = existing_prices[slug]
            if record.price_credits != credits or record.price_bonds != bonds:
                prices_updated = True
                record.price_credits = credits
                record.price_bonds = bonds
                record.token = token
        else:
            vipr = VendorItemPriceReading(
                token=token,
                vendor=vendor,
                vendor_inventory=latest_inventory,
                item=Item.query.filter_by(slug=slug).one(),
                day=day,
                price_credits=credits,
                price_bonds=bonds,
            )
            db.session.add(vipr)
            prices_updated = True

    if prices_updated:
        messages.append('Price information recorded/updated.')

    db.session.commit()

    return jsonify({'recorded': True, 'message': ' '.join(messages)})
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)
def add_distance():
    payload = request.get_json(force=True)
    mandatory = set(('token', 'source', 'system', 'schedules'))
    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
        })

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

    station = get_station(payload['system'], payload['source'])
    count = 0
    new = 0
    price_count = 0
    for schedule in payload['schedules']:
        distances = [t for t in schedule['distances'] if t[0] and t[1]]
        if not distances:
            continue
        destination = get_station(payload['system'], schedule['destination'])
        pair = get_station_pair(station, destination)
        first_price_ratio = None
        for d_tuple in distances:

            price = None
            travel_time = None
            departure, distance, *rest = d_tuple
            if len(rest):
                travel_time = rest[0]
            if len(rest) >= 2:
                price = rest[1]
            if not isinstance(distance, (int, float)):
                continue
            distance = int(distance)

            departure = parse_gct(departure) or departure
            if price is not None and first_price_ratio is None:
                if isinstance(price, str):
                    price = price.replace(',', '')
                    price = float(price)
                first_price_ratio = price / distance

            count += 1
            existing = StationDistanceReading.query.filter_by(
                station_pair_id=pair.id,
                distance_km=distance,
                when=departure,
            ).first()
            if not existing:
                new += 1
                if travel_time and re.search('[0-9]', travel_time):
                    travel_time = int(re.sub(r'[^0-9]', '', travel_time))
                else:
                    travel_time = None
                sdr = StationDistanceReading(
                    station_pair=pair,
                    distance_km=distance,
                    when=departure,
                    travel_time_u=travel_time,
                    token=token,
                )
                db.session.add(sdr)
        if first_price_ratio is not None:
            price_count += 1
            db.session.add(
                ShuttlePriceReading(
                    source_station=station,
                    destination_station=destination,
                    price_per_distance=first_price_ratio,
                    token=token,
                ))
    db.session.commit()
    print('Recorded {} distance pairs ({} new, {} prices) for {} by {}'.format(
        count, new, price_count, payload['source'], token.character.name))
    return jsonify({
        'recorded':
        True,
        'message':
        'Recorded {} distance pairs, of which {} were new. +1 brownie point'.
        format(count, new)
    })