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
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), }
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), }
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
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
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()
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)
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)
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()
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)
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 )
def test_deserialization_passes_for_missing_model_id(): data = FlightSchema(partial=True).load(dict()).data assert 'model_id' not in data
def test_deserialization_passes_for_valid_model_id(): data = FlightSchema(partial=True).load(dict(modelId=4)).data assert data['model_id'] == 4
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)
def test_deserialization_passes_for_null_model_id(): data = FlightSchema(partial=True).load(dict(modelId=None)).data assert data["model_id"] == None
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)