示例#1
0
def verify():
    json = request.get_json()
    if json is None:
        return jsonify(error='invalid-request'), 400

    try:
        data = FlightSchema(partial=True).load(json, many=True).data
    except ValidationError, e:
        return jsonify(error='validation-failed', fields=e.messages), 422
示例#2
0
def _distance_flights(user):
    schema = FlightSchema(only=("id", "scoreDate", "distance"))

    return {
        "50km": _distance_flight(user, 50000, schema),
        "100km": _distance_flight(user, 100000, schema),
        "300km": _distance_flight(user, 300000, schema),
        "500km": _distance_flight(user, 500000, schema),
        "700km": _distance_flight(user, 700000, schema),
        "1000km": _distance_flight(user, 1000000, schema),
        "largest": _largest_flight(user, schema),
    }
示例#3
0
文件: user.py 项目: kerel-fs/skylines
def _distance_flights(user):
    schema = FlightSchema(only=('id', 'scoreDate', 'distance'))

    return {
        '50km': _distance_flight(user, 50000, schema),
        '100km': _distance_flight(user, 100000, schema),
        '300km': _distance_flight(user, 300000, schema),
        '500km': _distance_flight(user, 500000, schema),
        '700km': _distance_flight(user, 700000, schema),
        '1000km': _distance_flight(user, 1000000, schema),
        'largest': _largest_flight(user, schema),
    }
示例#4
0
def index_post():
    current_user = User.get(request.user_id)

    form = request.form

    if form.get('pilotId') == u'':
        form = form.copy()
        form.pop('pilotId')

    try:
        data = FlightSchema(only=('pilotId', 'pilotName')).load(form).data
    except ValidationError, e:
        return jsonify(error='validation-failed', fields=e.messages), 422
示例#5
0
def update(flight_id):
    flight = get_requested_record(Flight, flight_id)

    current_user = User.get(request.user_id)
    if not flight.is_writable(current_user):
        return jsonify(), 403

    json = request.get_json()
    if json is None:
        return jsonify(error='invalid-request'), 400

    try:
        data = FlightSchema(partial=True).load(json).data
    except ValidationError, e:
        return jsonify(error='validation-failed', fields=e.messages), 422
示例#6
0
文件: flights.py 项目: vdrok/skylines
def update(flight_id):
    flight = get_requested_record(Flight, flight_id)

    current_user = User.get(request.user_id)
    if not flight.is_writable(current_user):
        return jsonify(), 403

    json = request.get_json()
    if json is None:
        return jsonify(error='invalid-request'), 400

    try:
        data = FlightSchema(partial=True).load(json).data
    except ValidationError as e:
        return jsonify(error='validation-failed', fields=e.messages), 422

    if 'pilot_id' in data:
        pilot_id = data['pilot_id']

        if pilot_id is not None:

            if not User.exists(id=pilot_id):
                return jsonify(error='unknown-pilot'), 422

            pilot_club_id = User.get(pilot_id).club_id

            if pilot_club_id != current_user.club_id or (
                    pilot_club_id is None and pilot_id != current_user.id):
                return jsonify(error='pilot-disallowed'), 422

            if flight.pilot_id != pilot_id:
                flight.pilot_id = pilot_id
                # pilot_name is irrelevant, if pilot_id is given
                flight.pilot_name = None
                # update club if pilot changed
                flight.club_id = pilot_club_id

        else:
            flight.pilot_id = None

    if 'pilot_name' in data:
        flight.pilot_name = data['pilot_name']

    if 'co_pilot_id' in data:
        co_pilot_id = data['co_pilot_id']

        if co_pilot_id is not None:

            if not User.exists(id=co_pilot_id):
                return jsonify(error='unknown-copilot'), 422

            co_pilot_club_id = User.get(co_pilot_id).club_id

            if co_pilot_club_id != current_user.club_id \
                    or (co_pilot_club_id is None and co_pilot_id != current_user.id):
                return jsonify(error='co-pilot-disallowed'), 422

            flight.co_pilot_id = co_pilot_id
            # co_pilot_name is irrelevant, if co_pilot_id is given
            flight.co_pilot_name = None

        else:
            flight.co_pilot_id = None

    if 'co_pilot_name' in data:
        flight.co_pilot_name = data['co_pilot_name']

    if flight.co_pilot_id is not None and flight.co_pilot_id == flight.pilot_id:
        return jsonify(error='copilot-equals-pilot'), 422

    if 'model_id' in data:
        model_id = data['model_id']

        if model_id is not None and not AircraftModel.exists(id=model_id):
            return jsonify(error='unknown-aircraft-model'), 422

        flight.model_id = model_id

    if 'registration' in data:
        flight.registration = data['registration']

    if 'competition_id' in data:
        flight.competition_id = data['competition_id']

    if 'privacy_level' in data:
        flight.privacy_level = data['privacy_level']

        try:
            tasks.analyse_flight.delay(flight.id)
            tasks.find_meetings.delay(flight.id)
        except ConnectionError:
            current_app.logger.info('Cannot connect to Redis server')

    flight.time_modified = datetime.utcnow()
    db.session.commit()

    return jsonify()
示例#7
0
文件: flights.py 项目: vdrok/skylines
def _create_list(date=None,
                 pilot=None,
                 club=None,
                 airport=None,
                 pinned=None,
                 filter=None,
                 default_sorting_column='score',
                 default_sorting_order='desc'):

    pilot_alias = aliased(User, name='pilot')
    owner_alias = aliased(User, name='owner')

    subq = db.session \
        .query(FlightComment.flight_id, func.count('*').label('count')) \
        .group_by(FlightComment.flight_id).subquery()

    current_user = User.get(request.user_id) if request.user_id else None

    flights = db.session.query(Flight, subq.c.count) \
        .filter(Flight.is_listable(current_user)) \
        .join(Flight.igc_file) \
        .options(contains_eager(Flight.igc_file)) \
        .join(owner_alias, IGCFile.owner) \
        .options(contains_eager(Flight.igc_file, IGCFile.owner, alias=owner_alias)) \
        .outerjoin(pilot_alias, Flight.pilot) \
        .options(contains_eager(Flight.pilot, alias=pilot_alias)) \
        .options(joinedload(Flight.co_pilot)) \
        .outerjoin(Flight.club) \
        .options(contains_eager(Flight.club)) \
        .outerjoin(Flight.takeoff_airport) \
        .options(contains_eager(Flight.takeoff_airport)) \
        .outerjoin(Flight.model) \
        .options(contains_eager(Flight.model)) \
        .outerjoin((subq, Flight.comments))

    if date:
        flights = flights.filter(Flight.date_local == date)

    if pilot:
        flights = flights.filter(
            or_(Flight.pilot == pilot, Flight.co_pilot == pilot))
    if club:
        flights = flights.filter(Flight.club == club)

    if airport:
        flights = flights.filter(Flight.takeoff_airport == airport)

    if pinned:
        flights = flights.filter(Flight.id.in_(pinned))

    if filter is not None:
        flights = flights.filter(filter)

    valid_columns = {
        'date': getattr(Flight, 'date_local'),
        'score': getattr(Flight, 'index_score'),
        'pilot': getattr(pilot_alias, 'name'),
        'distance': getattr(Flight, 'olc_classic_distance'),
        'airport': getattr(Airport, 'name'),
        'club': getattr(Club, 'name'),
        'aircraft': getattr(AircraftModel, 'name'),
        'time': getattr(Flight, 'takeoff_time'),
    }

    flights_count = flights.count()

    flights = Sorter.sort(flights,
                          'flights',
                          default_sorting_column,
                          valid_columns=valid_columns,
                          default_order=default_sorting_order)

    flights = flights.order_by(Flight.index_score.desc())

    flights = Pager.paginate(flights,
                             'flights',
                             items_per_page=int(
                                 current_app.config.get(
                                     'SKYLINES_LISTS_DISPLAY_LENGTH', 50)))

    flight_schema = FlightSchema()
    flights_json = []
    for f, num_comments in flights:
        flight = flight_schema.dump(f).data
        flight['private'] = not f.is_rankable()
        flight['numComments'] = num_comments
        flights_json.append(flight)

    json = dict(flights=flights_json, count=flights_count)

    if date:
        json['date'] = date.isoformat()

    if pilot:
        user_schema = UserSchema(only=('id', 'name'))
        json['pilot'] = user_schema.dump(pilot).data

    if club:
        club_schema = ClubSchema(only=('id', 'name'))
        json['club'] = club_schema.dump(club).data

    if airport:
        airport_schema = AirportSchema(only=('id', 'name', 'countryCode'))
        json['airport'] = airport_schema.dump(airport).data

    return jsonify(json)
示例#8
0
文件: flights.py 项目: vdrok/skylines
def read(flight_id):
    flight = get_requested_record(Flight,
                                  flight_id,
                                  joinedload=[Flight.igc_file])

    current_user = User.get(request.user_id) if request.user_id else None
    if not flight.is_viewable(current_user):
        return jsonify(), 404

    _reanalyse_if_needed(flight)
    mark_flight_notifications_read(flight)

    flight_json = FlightSchema().dump(flight).data

    if 'extended' not in request.args:
        return jsonify(flight=flight_json)

    near_flights = FlightMeetings.get_meetings(flight).values()
    near_flights = NearFlightSchema().dump(near_flights, many=True).data

    comments = FlightCommentSchema().dump(flight.comments, many=True).data

    phases_schema = FlightPhaseSchema(only=(
        'circlingDirection',
        'type',
        'secondsOfDay',
        'startTime',
        'duration',
        'altDiff',
        'distance',
        'vario',
        'speed',
        'glideRate',
    ))

    phases = phases_schema.dump(flight.phases, many=True).data

    cruise_performance_schema = FlightPhaseSchema(only=(
        'duration',
        'fraction',
        'altDiff',
        'distance',
        'vario',
        'speed',
        'glideRate',
        'count',
    ))

    cruise_performance = cruise_performance_schema.dump(
        flight.cruise_performance).data

    circling_performance_schema = FlightPhaseSchema(only=(
        'circlingDirection',
        'count',
        'vario',
        'fraction',
        'duration',
        'altDiff',
    ))

    circling_performance = circling_performance_schema.dump(
        flight.circling_performance, many=True).data
    performance = dict(circling=circling_performance,
                       cruise=cruise_performance)

    contest_leg_schema = ContestLegSchema()
    contest_legs = {}
    for type in ['classic', 'triangle']:
        legs = flight.get_contest_legs('olc_plus', type)
        contest_legs[type] = contest_leg_schema.dump(legs, many=True).data

    return jsonify(flight=flight_json,
                   near_flights=near_flights,
                   comments=comments,
                   contest_legs=contest_legs,
                   phases=phases,
                   performance=performance)
示例#9
0
def verify():
    current_user = User.get(request.user_id)

    json = request.get_json()
    if json is None:
        return jsonify(error="invalid-request"), 400

    try:
        data = FlightSchema(partial=True).load(json, many=True).data
    except ValidationError as e:
        return jsonify(error="validation-failed", fields=e.messages), 422

    ids = [it.get("id") for it in data]
    if not all(ids):
        return jsonify(error="id-missing"), 422

    user_ids = [it["pilot_id"] for it in data if "pilot_id" in it]
    user_ids.extend([it["co_pilot_id"] for it in data if "co_pilot_id" in it])

    model_ids = [it["model_id"] for it in data if "model_id" in it]

    flights = {
        flight.id: flight for flight in Flight.query().filter(Flight.id.in_(ids)).all()
    }
    users = {user.id: user for user in User.query().filter(User.id.in_(user_ids)).all()}
    models = {
        model.id: model
        for model in AircraftModel.query().filter(AircraftModel.id.in_(model_ids)).all()
    }

    for d in data:
        flight = flights.get(d.pop("id"))
        if not flight or not flight.is_writable(current_user):
            return jsonify(error="unknown-flight"), 422

        if "pilot_id" in d and d["pilot_id"] is not None and d["pilot_id"] not in users:
            return jsonify(error="unknown-pilot"), 422

        if (
            "co_pilot_id" in d
            and d["co_pilot_id"] is not None
            and d["co_pilot_id"] not in users
        ):
            return jsonify(error="unknown-copilot"), 422

        if (
            "model_id" in d
            and d["model_id"] is not None
            and d["model_id"] not in models
        ):
            return jsonify(error="unknown-aircraft-model"), 422

        for key in (
            "takeoff_time",
            "scoring_start_time",
            "scoring_end_time",
            "landing_time",
        ):
            if key in d:
                d[key] = d[key].replace(tzinfo=None)

        old_pilot = flight.pilot_id

        for key, value in d.items():
            setattr(flight, key, value)

        if not (
            flight.takeoff_time
            <= flight.scoring_start_time
            <= flight.scoring_end_time
            <= flight.landing_time
        ):
            return jsonify(error="invalid-times"), 422

        if flight.pilot_id != old_pilot and flight.pilot_id:
            flight.club_id = users[flight.pilot_id].club_id

        flight.privacy_level = Flight.PrivacyLevel.PUBLIC
        flight.time_modified = datetime.utcnow()

    db.session.commit()

    for flight_id in flights.keys():
        try:
            tasks.analyse_flight.delay(flight_id)
            tasks.find_meetings.delay(flight_id)
        except ConnectionError:
            current_app.logger.info("Cannot connect to Redis server")

    return jsonify()
示例#10
0
def _create_list(
    date=None,
    pilot=None,
    club=None,
    airport=None,
    pinned=None,
    filter=None,
    default_sorting_column="score",
    default_sorting_order="desc",
):

    pilot_alias = aliased(User, name="pilot")
    owner_alias = aliased(User, name="owner")

    subq = (db.session.query(FlightComment.flight_id,
                             func.count("*").label("count")).group_by(
                                 FlightComment.flight_id).subquery())

    current_user = User.get(request.user_id) if request.user_id else None

    flights = (db.session.query(Flight, subq.c.count).filter(
        Flight.is_listable(current_user)).join(Flight.igc_file).options(
            contains_eager(Flight.igc_file)).join(
                owner_alias, IGCFile.owner).options(
                    contains_eager(Flight.igc_file,
                                   IGCFile.owner,
                                   alias=owner_alias)).outerjoin(
                                       pilot_alias, Flight.pilot).options(
                                           contains_eager(Flight.pilot,
                                                          alias=pilot_alias)).
               options(joinedload(Flight.co_pilot)).outerjoin(
                   Flight.club).options(contains_eager(Flight.club)).outerjoin(
                       Flight.takeoff_airport).options(
                           contains_eager(Flight.takeoff_airport)).outerjoin(
                               Flight.model).options(
                                   contains_eager(Flight.model)).outerjoin(
                                       (subq, Flight.comments)))

    if date:
        flights = flights.filter(Flight.date_local == date)

    if pilot:
        flights = flights.filter(
            or_(Flight.pilot == pilot, Flight.co_pilot == pilot))
    if club:
        flights = flights.filter(Flight.club == club)

    if airport:
        flights = flights.filter(Flight.takeoff_airport == airport)

    if pinned:
        flights = flights.filter(Flight.id.in_(pinned))

    if filter is not None:
        flights = flights.filter(filter)

    valid_columns = {
        "date": getattr(Flight, "date_local"),
        "score": getattr(Flight, "index_score"),
        "pilot": getattr(pilot_alias, "name"),
        "distance": getattr(Flight, "olc_classic_distance"),
        "airport": getattr(Airport, "name"),
        "club": getattr(Club, "name"),
        "aircraft": getattr(AircraftModel, "name"),
        "time": getattr(Flight, "takeoff_time"),
    }

    flights_count = flights.count()

    flights = Sorter.sort(
        flights,
        "flights",
        default_sorting_column,
        valid_columns=valid_columns,
        default_order=default_sorting_order,
    )

    flights = flights.order_by(Flight.index_score.desc())

    flights = Pager.paginate(
        flights,
        "flights",
        items_per_page=int(
            current_app.config.get("SKYLINES_LISTS_DISPLAY_LENGTH", 50)),
    )

    flight_schema = FlightSchema()
    flights_json = []
    for f, num_comments in flights:
        flight = flight_schema.dump(f).data
        flight["private"] = not f.is_rankable()
        flight["numComments"] = num_comments
        flights_json.append(flight)

    json = dict(flights=flights_json, count=flights_count)

    if date:
        json["date"] = date.isoformat()

    if pilot:
        user_schema = UserSchema(only=("id", "name"))
        json["pilot"] = user_schema.dump(pilot).data

    if club:
        club_schema = ClubSchema(only=("id", "name"))
        json["club"] = club_schema.dump(club).data

    if airport:
        airport_schema = AirportSchema(only=("id", "name", "countryCode"))
        json["airport"] = airport_schema.dump(airport).data

    return jsonify(json)
示例#11
0
def index_post():
    current_user = User.get(request.user_id)

    form = request.form

    if form.get("pilotId") == u"":
        form = form.copy()
        form.pop("pilotId")

    try:
        data = FlightSchema(only=("pilotId", "pilotName")).load(form).data
    except ValidationError as e:
        return jsonify(error="validation-failed", fields=e.messages), 422

    pilot_id = data.get("pilot_id")
    pilot = pilot_id and User.get(pilot_id)
    pilot_id = pilot and pilot.id

    club_id = (pilot and pilot.club_id) or current_user.club_id

    results = []

    _files = request.files.getlist("files")

    prefix = 0
    for name, f in iterate_upload_files(_files):
        prefix += 1
        filename = files.sanitise_filename(name)
        filename = files.add_file(filename, f)

        # check if the file already exists
        with files.open_file(filename) as f:
            md5 = file_md5(f)
            other = Flight.by_md5(md5)
            if other:
                files.delete_file(filename)
                results.append(UploadResult.for_duplicate(name, other, str(prefix)))
                continue

        igc_file = IGCFile()
        igc_file.owner = current_user
        igc_file.filename = filename
        igc_file.md5 = md5
        igc_file.update_igc_headers()

        if igc_file.date_utc is None:
            files.delete_file(filename)
            results.append(UploadResult.for_missing_date(name, str(prefix)))
            continue

        flight = Flight()
        flight.pilot_id = pilot_id
        flight.pilot_name = data.get("pilot_name")
        flight.club_id = club_id
        flight.igc_file = igc_file

        flight.model_id = igc_file.guess_model()

        if igc_file.registration:
            flight.registration = igc_file.registration
        else:
            flight.registration = igc_file.guess_registration()

        flight.competition_id = igc_file.competition_id

        fp = flight_path(flight.igc_file, add_elevation=True, max_points=None)

        analyzed = False
        try:
            analyzed = analyse_flight(flight, fp=fp)
        except:
            current_app.logger.exception("analyse_flight() raised an exception")

        if not analyzed:
            files.delete_file(filename)
            results.append(UploadResult.for_parser_error(name, str(prefix)))
            continue

        if not flight.takeoff_time or not flight.landing_time:
            files.delete_file(filename)
            results.append(UploadResult.for_no_flight(name, str(prefix)))
            continue

        if flight.landing_time > datetime.now():
            files.delete_file(filename)
            results.append(UploadResult.for_future_flight(name, str(prefix)))
            continue

        if not flight.update_flight_path():
            files.delete_file(filename)
            results.append(UploadResult.for_no_flight(name, str(prefix)))
            continue

        flight.privacy_level = Flight.PrivacyLevel.PRIVATE

        trace = _encode_flight_path(fp, qnh=flight.qnh)
        infringements = get_airspace_infringements(fp, qnh=flight.qnh)

        db.session.add(igc_file)
        db.session.add(flight)

        # flush data to make sure we don't get duplicate files from ZIP files
        db.session.flush()

        # Store data in cache for image creation
        cache_key = hashlib.sha1(
            (to_unicode(flight.id) + u"_" + to_unicode(current_user.id)).encode("utf-8")
        ).hexdigest()

        cache.set(
            "upload_airspace_infringements_" + cache_key, infringements, timeout=15 * 60
        )
        cache.set("upload_airspace_flight_path_" + cache_key, fp, timeout=15 * 60)

        airspace = (
            db.session.query(Airspace)
            .filter(Airspace.id.in_(infringements.keys()))
            .all()
        )

        results.append(
            UploadResult(
                name,
                flight,
                UploadStatus.SUCCESS,
                str(prefix),
                trace,
                airspace,
                cache_key,
            )
        )

        create_flight_notifications(flight)

    db.session.commit()

    results = UploadResultSchema().dump(results, many=True).data

    club_members = []
    if current_user.club_id:
        member_schema = UserSchema(only=("id", "name"))

        club_members = (
            User.query(club_id=current_user.club_id)
            .order_by(func.lower(User.name))
            .filter(User.id != current_user.id)
        )

        club_members = member_schema.dump(club_members.all(), many=True).data

    aircraft_models = (
        AircraftModel.query()
        .order_by(AircraftModel.kind)
        .order_by(AircraftModel.name)
        .all()
    )

    aircraft_models = AircraftModelSchema().dump(aircraft_models, many=True).data

    return jsonify(
        results=results, club_members=club_members, aircraft_models=aircraft_models
    )
示例#12
0
def test_deserialization_passes_for_missing_model_id():
    data = FlightSchema(partial=True).load(dict()).data
    assert 'model_id' not in data
示例#13
0
def test_deserialization_passes_for_valid_model_id():
    data = FlightSchema(partial=True).load(dict(modelId=4)).data
    assert data['model_id'] == 4
示例#14
0
def _create_list(
    date=None,
    pilot=None,
    club=None,
    airport=None,
    pinned=None,
    filter=None,
    default_sorting_column="score",
    default_sorting_order="desc",
):

    pilot_alias = aliased(User, name="pilot")
    owner_alias = aliased(User, name="owner")

    subq = (
        db.session.query(FlightComment.flight_id, func.count("*").label("count"))
        .group_by(FlightComment.flight_id)
        .subquery()
    )

    current_user = User.get(request.user_id) if request.user_id else None

    flights = (
        db.session.query(Flight, subq.c.count)
        .filter(Flight.is_listable(current_user))
        .join(Flight.igc_file)
        .options(contains_eager(Flight.igc_file))
        .join(owner_alias, IGCFile.owner)
        .options(contains_eager(Flight.igc_file, IGCFile.owner, alias=owner_alias))
        .outerjoin(pilot_alias, Flight.pilot)
        .options(contains_eager(Flight.pilot, alias=pilot_alias))
        .options(joinedload(Flight.co_pilot))
        .outerjoin(Flight.club)
        .options(contains_eager(Flight.club))
        .outerjoin(Flight.takeoff_airport)
        .options(contains_eager(Flight.takeoff_airport))
        .outerjoin(Flight.model)
        .options(contains_eager(Flight.model))
        .outerjoin((subq, Flight.comments))
    )

    if date:
        flights = flights.filter(Flight.date_local == date)

    if pilot:
        flights = flights.filter(or_(Flight.pilot == pilot, Flight.co_pilot == pilot))
    if club:
        flights = flights.filter(Flight.club == club)

    if airport:
        flights = flights.filter(Flight.takeoff_airport == airport)

    if pinned:
        flights = flights.filter(Flight.id.in_(pinned))

    if filter is not None:
        flights = flights.filter(filter)

    valid_columns = {
        "date": getattr(Flight, "date_local"),
        "score": getattr(Flight, "index_score"),
        "pilot": getattr(pilot_alias, "name"),
        "distance": getattr(Flight, "olc_classic_distance"),
        "airport": getattr(Airport, "name"),
        "club": getattr(Club, "name"),
        "aircraft": getattr(AircraftModel, "name"),
        "time": getattr(Flight, "takeoff_time"),
    }

    flights_count = flights.count()

    flights = Sorter.sort(
        flights, "flights", default_sorting_column, valid_columns=valid_columns, default_order=default_sorting_order
    )

    flights = flights.order_by(Flight.index_score.desc())

    flights = Pager.paginate(
        flights, "flights", items_per_page=int(current_app.config.get("SKYLINES_LISTS_DISPLAY_LENGTH", 50))
    )

    flight_schema = FlightSchema()
    flights_json = []
    for f, num_comments in flights:
        flight = flight_schema.dump(f).data
        flight["private"] = not f.is_rankable()
        flight["numComments"] = num_comments
        flights_json.append(flight)

    json = dict(flights=flights_json, count=flights_count)

    if date:
        json["date"] = date.isoformat()

    if pilot:
        user_schema = UserSchema(only=("id", "name"))
        json["pilot"] = user_schema.dump(pilot).data

    if club:
        club_schema = ClubSchema(only=("id", "name"))
        json["club"] = club_schema.dump(club).data

    if airport:
        airport_schema = AirportSchema(only=("id", "name", "countryCode"))
        json["airport"] = airport_schema.dump(airport).data

    return jsonify(json)
示例#15
0
def test_deserialization_passes_for_null_model_id():
    data = FlightSchema(partial=True).load(dict(modelId=None)).data
    assert data["model_id"] == None
示例#16
0
def _create_list(date=None, pilot=None, club=None, airport=None,
                 pinned=None, filter=None,
                 default_sorting_column='score', default_sorting_order='desc'):

    pilot_alias = aliased(User, name='pilot')
    owner_alias = aliased(User, name='owner')

    subq = db.session \
        .query(FlightComment.flight_id, func.count('*').label('count')) \
        .group_by(FlightComment.flight_id).subquery()

    current_user = User.get(request.user_id) if request.user_id else None

    flights = db.session.query(Flight, subq.c.count) \
        .filter(Flight.is_listable(current_user)) \
        .join(Flight.igc_file) \
        .options(contains_eager(Flight.igc_file)) \
        .join(owner_alias, IGCFile.owner) \
        .options(contains_eager(Flight.igc_file, IGCFile.owner, alias=owner_alias)) \
        .outerjoin(pilot_alias, Flight.pilot) \
        .options(contains_eager(Flight.pilot, alias=pilot_alias)) \
        .options(joinedload(Flight.co_pilot)) \
        .outerjoin(Flight.club) \
        .options(contains_eager(Flight.club)) \
        .outerjoin(Flight.takeoff_airport) \
        .options(contains_eager(Flight.takeoff_airport)) \
        .outerjoin(Flight.model) \
        .options(contains_eager(Flight.model)) \
        .outerjoin((subq, Flight.comments))

    if date:
        flights = flights.filter(Flight.date_local == date)

    if pilot:
        flights = flights.filter(or_(Flight.pilot == pilot,
                                     Flight.co_pilot == pilot))
    if club:
        flights = flights.filter(Flight.club == club)

    if airport:
        flights = flights.filter(Flight.takeoff_airport == airport)

    if pinned:
        flights = flights.filter(Flight.id.in_(pinned))

    if filter is not None:
        flights = flights.filter(filter)

    valid_columns = {
        'date': getattr(Flight, 'date_local'),
        'score': getattr(Flight, 'index_score'),
        'pilot': getattr(pilot_alias, 'name'),
        'distance': getattr(Flight, 'olc_classic_distance'),
        'airport': getattr(Airport, 'name'),
        'club': getattr(Club, 'name'),
        'aircraft': getattr(AircraftModel, 'name'),
        'time': getattr(Flight, 'takeoff_time'),
    }

    flights_count = flights.count()

    flights = Sorter.sort(flights, 'flights', default_sorting_column,
                          valid_columns=valid_columns,
                          default_order=default_sorting_order)

    flights = flights.order_by(Flight.index_score.desc())

    flights = Pager.paginate(flights, 'flights',
                             items_per_page=int(current_app.config.get('SKYLINES_LISTS_DISPLAY_LENGTH', 50)))

    flight_schema = FlightSchema()
    flights_json = []
    for f, num_comments in flights:
        flight = flight_schema.dump(f).data
        flight['private'] = not f.is_rankable()
        flight['numComments'] = num_comments
        flights_json.append(flight)

    json = dict(flights=flights_json, count=flights_count)

    if date:
        json['date'] = date.isoformat()

    if pilot:
        user_schema = UserSchema(only=('id', 'name'))
        json['pilot'] = user_schema.dump(pilot).data

    if club:
        club_schema = ClubSchema(only=('id', 'name'))
        json['club'] = club_schema.dump(club).data

    if airport:
        airport_schema = AirportSchema(only=('id', 'name', 'countryCode'))
        json['airport'] = airport_schema.dump(airport).data

    return jsonify(json)