def update_flight_path(self): from skylines.lib.xcsoar_ import flight_path from skylines.lib.datetime import from_seconds_of_day # Run the IGC file through the FlightPath utility path = flight_path(self.igc_file, qnh=self.qnh) if len(path) < 2: return False # Save the timestamps of the coordinates date_utc = self.igc_file.date_utc self.timestamps = [ from_seconds_of_day(date_utc, c.seconds_of_day) for c in path ] # Convert the coordinate into a list of tuples coordinates = [(c.location["longitude"], c.location["latitude"]) for c in path] # Create a shapely LineString object from the coordinates linestring = LineString(coordinates) # Save the new path as WKB self.locations = from_shape(linestring, srid=4326) return True
def update_flight_path(self): from skylines.lib.xcsoar_ import flight_path from skylines.lib.datetime import from_seconds_of_day # Run the IGC file through the FlightPath utility path = flight_path(self.igc_file, qnh=self.qnh) if len(path) < 2: return False # Save the timestamps of the coordinates date_utc = self.igc_file.date_utc self.timestamps = \ [from_seconds_of_day(date_utc, c.seconds_of_day) for c in path] # Convert the coordinate into a list of tuples coordinates = [(c.location['longitude'], c.location['latitude']) for c in path] # Create a shapely LineString object from the coordinates linestring = LineString(coordinates) # Save the new path as WKB self.locations = from_shape(linestring, srid=4326) return True
def _get_flight_path(flight, threshold=0.001, max_points=3000): fp = flight_path(flight.igc_file, max_points) if len(fp) == 0: current_app.logger.error('flight_path("' + flight.igc_file.filename + '") returned with an empty list') return None num_levels = 4 zoom_factor = 4 zoom_levels = [0] zoom_levels.extend([round(-math.log(32.0 / 45.0 * (threshold * pow(zoom_factor, num_levels - i - 1)), 2)) for i in range(1, num_levels)]) max_delta_time = max(4, (fp[-1].seconds_of_day - fp[0].seconds_of_day) / 500) encoder = SkyLinesPolyEncoder(num_levels=4, threshold=threshold, zoom_factor=4) fixes = map(lambda x: (x.longitude, x.latitude, (x.seconds_of_day / max_delta_time * threshold)), fp) fixes = encoder.classify(fixes, remove=False, type="ppd") encoded = encoder.encode(fixes['points'], fixes['levels']) barogram_t = encoder.encodeList([fp[i].seconds_of_day for i in range(len(fp)) if fixes['levels'][i] != -1]) barogram_h = encoder.encodeList([fp[i].altitude for i in range(len(fp)) if fixes['levels'][i] != -1]) enl = encoder.encodeList([fp[i].enl for i in range(len(fp)) if fixes['levels'][i] != -1]) elevations_t, elevations_h = _get_elevations(flight, encoder) contest_traces = _get_contest_traces(flight, encoder) return dict(encoded=encoded, zoom_levels=zoom_levels, num_levels=num_levels, barogram_t=barogram_t, barogram_h=barogram_h, enl=enl, contests=contest_traces, elevations_t=elevations_t, elevations_h=elevations_h, sfid=flight.id)
def update_flight_path(flight): from skylines.lib.xcsoar_ import flight_path from skylines.lib.datetime import from_seconds_of_day # Now populate the FlightPathChunks table with the (full) flight path path_detailed = flight_path(flight.igc_file, max_points=3000, qnh=flight.qnh) if len(path_detailed) < 2: return False # Number of points in each chunck. num_points = 100 # Interval of the current chunck: [i, j] (-> path_detailed[i:j + 1]) i = 0 j = min(num_points - 1, len(path_detailed) - 1) # Ensure that the last chunk contains at least two fixes if j == len(path_detailed) - 2: j = len(path_detailed) - 1 FlightPathChunks.query().filter( FlightPathChunks.flight == flight).delete() date_utc = flight.igc_file.date_utc while True: flight_path = FlightPathChunks(flight=flight) # Save the timestamps of the coordinates flight_path.timestamps = \ [from_seconds_of_day(date_utc, c.seconds_of_day) for c in path_detailed[i:j + 1]] flight_path.start_time = path_detailed[i].datetime flight_path.end_time = path_detailed[j].datetime # Convert the coordinate into a list of tuples coordinates = [(c.location['longitude'], c.location['latitude']) for c in path_detailed[i:j + 1]] # Create a shapely LineString object from the coordinates linestring = LineString(coordinates) # Save the new path as WKB flight_path.locations = from_shape(linestring, srid=4326) db.session.add(flight_path) if j == len(path_detailed) - 1: break else: i = j + 1 j = min(j + num_points, len(path_detailed) - 1) if j == len(path_detailed) - 2: j = len(path_detailed) - 1 db.session.commit() return True
def update_flight_path(flight): from skylines.lib.xcsoar_ import flight_path from skylines.lib.datetime import from_seconds_of_day # Now populate the FlightPathChunks table with the (full) flight path path_detailed = flight_path(flight.igc_file, max_points=3000, qnh=flight.qnh) if len(path_detailed) < 2: return False # Number of points in each chunck. num_points = 100 # Interval of the current chunck: [i, j] (-> path_detailed[i:j + 1]) i = 0 j = min(num_points - 1, len(path_detailed) - 1) # Ensure that the last chunk contains at least two fixes if j == len(path_detailed) - 2: j = len(path_detailed) - 1 FlightPathChunks.query().filter(FlightPathChunks.flight == flight).delete() date_utc = flight.igc_file.date_utc while True: flight_path = FlightPathChunks(flight=flight) # Save the timestamps of the coordinates flight_path.timestamps = \ [from_seconds_of_day(date_utc, c.seconds_of_day) for c in path_detailed[i:j + 1]] flight_path.start_time = path_detailed[i].datetime flight_path.end_time = path_detailed[j].datetime # Convert the coordinate into a list of tuples coordinates = [(c.location['longitude'], c.location['latitude']) for c in path_detailed[i:j + 1]] # Create a shapely LineString object from the coordinates linestring = LineString(coordinates) # Save the new path as WKB flight_path.locations = from_shape(linestring, srid=4326) db.session.add(flight_path) if j == len(path_detailed) - 1: break else: i = j + 1 j = min(j + num_points, len(path_detailed) - 1) if j == len(path_detailed) - 2: j = len(path_detailed) - 1 db.session.commit() return True
def _get_flight_path(flight): fp = flight_path(flight.igc_file, add_elevation=True) barogram_h = xcsoar.encode([fix.altitude for fix in fp], method="signed") barogram_t = xcsoar.encode([fix.seconds_of_day for fix in fp], method="signed") enl = xcsoar.encode([fix.enl if fix.enl is not None else 0 for fix in fp], method="signed") elevations_h = xcsoar.encode([fix.elevation if fix.elevation is not None else -1000 for fix in fp], method="signed") return dict(barogram_h=barogram_h, barogram_t=barogram_t, enl=enl, elevations_h=elevations_h, igc_start_time=fp[0].datetime, igc_end_time=fp[-1].datetime)
def check_update_form(prefix, status): form = UploadUpdateForm(prefix=str(prefix)) if not form.id or not form.id.data: return None, None, None flight_id = form.id.data # Get flight from database and check if it is writable flight = Flight.get(flight_id) if not flight: abort(404) if status == UploadStatus.DUPLICATE: return flight, None, None else: if not flight.is_writable(g.current_user): abort(403) fp = flight_path(flight.igc_file, add_elevation=True, max_points=None) form.populate_obj(flight) # replace None in form.pilot_id and form.co_pilot_id with 0 if not form.pilot_id.data: form.pilot_id.data = 0 if not form.co_pilot_id.data: form.co_pilot_id.data = 0 # Force takeoff_time and landing_time to be within the igc file limits if form.takeoff_time.data < fp[0].datetime: form.takeoff_time.data = fp[0].datetime if form.landing_time.data > fp[-1].datetime: form.landing_time.data = fp[-1].datetime return flight, fp, form
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)))
def index_post(form): user = g.current_user pilot_id = form.pilot.data if form.pilot.data != 0 else None pilot = pilot_id and User.get(int(pilot_id)) pilot_id = pilot and pilot.id club_id = (pilot and pilot.club_id) or user.club_id flights = [] success = False prefix = 0 for name, f in IterateUploadFiles(form.file.raw_data): 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) flights.append((name, other, UploadStatus.DUPLICATE, str(prefix), None, None, None, None)) continue igc_file = IGCFile() igc_file.owner = 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) flights.append((name, None, UploadStatus.MISSING_DATE, str(prefix), None, None, None, None)) continue flight = Flight() flight.pilot_id = pilot_id flight.pilot_name = form.pilot_name.data if form.pilot_name.data else None 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: analyse_flight(flight, fp=fp) analyzed = True except: current_app.logger.exception('analyse_flight() raised an exception') if not analyzed: files.delete_file(filename) flights.append((name, None, UploadStatus.PARSER_ERROR, str(prefix), None, None, None, None)) continue if not flight.takeoff_time or not flight.landing_time: files.delete_file(filename) flights.append((name, None, UploadStatus.NO_FLIGHT, str(prefix), None, None, None, None)) continue if flight.landing_time > datetime.now(): files.delete_file(filename) flights.append((name, None, UploadStatus.FLIGHT_IN_FUTURE, str(prefix), None, None, None, None)) continue if not flight.update_flight_path(): files.delete_file(filename) flights.append((name, None, UploadStatus.NO_FLIGHT, str(prefix), None, None, None, None)) 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(str(flight.id) + '_' + str(user.id)).hexdigest() current_app.cache.set('upload_airspace_infringements_' + cache_key, infringements, timeout=15 * 60) current_app.cache.set('upload_airspace_flight_path_' + cache_key, fp, timeout=15 * 60) airspace = db.session.query(Airspace) \ .filter(Airspace.id.in_(infringements.keys())) \ .all() # create form after flushing the session, otherwise we wouldn't have a flight.id form = UploadUpdateForm(formdata=None, prefix=str(prefix), obj=flight) # remove airspace field from form if no airspace infringements found if not infringements: del form.airspace_usage # replace None in form.pilot_id and form.co_pilot_id with 0 if not form.pilot_id.data: form.pilot_id.data = 0 if not form.co_pilot_id.data: form.co_pilot_id.data = 0 form.pilot_id.validate(form) flights.append((name, flight, UploadStatus.SUCCESS, str(prefix), trace, airspace, cache_key, form)) create_flight_notifications(flight) success = True db.session.commit() if success: flash(_('Please click "Publish Flight(s)" at the bottom to confirm our automatic analysis.')) return render_template( 'upload/result.jinja', num_flights=prefix, flights=flights, success=success)
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)
def index_post(): current_user = User.get(request.user_id) try: data = FlightUploadSchema().load(request.form).data except ValidationError as e: return jsonify(error="validation-failed", fields=e.messages), 422 pilot_id = data.get("pilot_id") if pilot_id: pilot = User.get(pilot_id) if not pilot: return jsonify(error="unknown-pilot"), 422 else: pilot = None club_id = (pilot and pilot.club_id) or current_user.club_id results = [] weglide_uploads = [] _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() # Queue WeGlide upload if requested weglide_user_id = data.get("weglideUserId") weglide_birthday = data.get("weglideBirthday") if weglide_user_id and weglide_birthday: # Save `upload_to_weglide` task parameters for later. We can't start # the task directly here, because the DB transaction has not been # committed at this point. weglide_uploads.append( (igc_file.id, weglide_user_id, weglide_birthday.isoformat()) ) # Update `weglide_status` in the database igc_file.weglide_status = 1 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() # Schedule the deferred WeGlide upload tasks from above for weglide_upload in weglide_uploads: tasks.upload_to_weglide.delay(*weglide_upload) 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 index_post(form): user = g.current_user pilot_id = form.pilot.data if form.pilot.data != 0 else None pilot = pilot_id and User.get(int(pilot_id)) pilot_id = pilot and pilot.id club_id = (pilot and pilot.club_id) or user.club_id results = [] success = False prefix = 0 for name, f in iterate_upload_files(form.file.raw_data): 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 = 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 = form.pilot_name.data if form.pilot_name.data else None 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(str(flight.id) + '_' + str(user.id)).hexdigest() current_app.cache.set('upload_airspace_infringements_' + cache_key, infringements, timeout=15 * 60) current_app.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) success = True db.session.commit() if success: flash(_('Please click "Publish Flight(s)" at the bottom to confirm our automatic analysis.')) results_json = UploadResultSchema().dump(results, many=True).data club_members = [] if g.current_user.club_id: member_schema = UserSchema(only=('id', 'name')) club_members = User.query(club_id=g.current_user.club_id) \ .order_by(func.lower(User.name)) \ .filter(User.id != g.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 render_template( 'upload/result.jinja', num_flights=prefix, results=results, success=success, results_json=results_json, club_members=club_members, aircraft_models=aircraft_models)
def index_post(form): user = g.current_user pilot_id = form.pilot.data if form.pilot.data != 0 else None pilot = pilot_id and User.get(int(pilot_id)) pilot_id = pilot and pilot.id club_id = (pilot and pilot.club_id) or user.club_id results = [] success = False prefix = 0 for name, f in iterate_upload_files(form.file.raw_data): 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 = 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 = form.pilot_name.data if form.pilot_name.data else None 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(str(flight.id) + '_' + str(user.id)).hexdigest() current_app.cache.set('upload_airspace_infringements_' + cache_key, infringements, timeout=15 * 60) current_app.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) success = True db.session.commit() if success: flash( _('Please click "Publish Flight(s)" at the bottom to confirm our automatic analysis.' )) results_json = UploadResultSchema().dump(results, many=True).data club_members = [] if g.current_user.club_id: member_schema = UserSchema(only=('id', 'name')) club_members = User.query(club_id=g.current_user.club_id) \ .order_by(func.lower(User.name)) \ .filter(User.id != g.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 render_template('upload/result.jinja', num_flights=prefix, results=results, success=success, results_json=results_json, club_members=club_members, aircraft_models=aircraft_models)
def index_post(form): user = g.current_user pilot_id = form.pilot.data if form.pilot.data != 0 else None pilot = pilot_id and User.get(int(pilot_id)) pilot_id = pilot and pilot.id club_id = (pilot and pilot.club_id) or user.club_id flights = [] success = False prefix = 0 for name, f in IterateUploadFiles(form.file.raw_data): 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) flights.append((name, other, UploadStatus.DUPLICATE, str(prefix), None, None, None, None)) continue igc_file = IGCFile() igc_file.owner = 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) flights.append((name, None, UploadStatus.MISSING_DATE, str(prefix), None, None, None, None)) continue flight = Flight() flight.pilot_id = pilot_id flight.pilot_name = form.pilot_name.data if form.pilot_name.data else None 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) if not analyse_flight(flight, fp=fp): files.delete_file(filename) flights.append((name, None, UploadStatus.PARSER_ERROR, str(prefix), None, None, None, None)) continue if not flight.takeoff_time or not flight.landing_time: files.delete_file(filename) flights.append((name, None, UploadStatus.NO_FLIGHT, str(prefix), None, None, None, None)) continue if flight.landing_time > datetime.now(): files.delete_file(filename) flights.append((name, None, UploadStatus.FLIGHT_IN_FUTURE, str(prefix), None, None, None, None)) continue if not flight.update_flight_path(): files.delete_file(filename) flights.append((name, None, UploadStatus.NO_FLIGHT, str(prefix), None, None, None, None)) 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(str(flight.id) + '_' + str(user.id)).hexdigest() current_app.cache.set('upload_airspace_infringements_' + cache_key, infringements, timeout=15 * 60) current_app.cache.set('upload_airspace_flight_path_' + cache_key, fp, timeout=15 * 60) airspace = db.session.query(Airspace) \ .filter(Airspace.id.in_(infringements.keys())) \ .all() # create form after flushing the session, otherwise we wouldn't have a flight.id form = UploadUpdateForm(formdata=None, prefix=str(prefix), obj=flight) # remove airspace field from form if no airspace infringements found if not infringements: del form.airspace_usage # replace None in form.pilot_id and form.co_pilot_id with 0 if not form.pilot_id.data: form.pilot_id.data = 0 if not form.co_pilot_id.data: form.co_pilot_id.data = 0 form.pilot_id.validate(form) flights.append((name, flight, UploadStatus.SUCCESS, str(prefix), trace, airspace, cache_key, form)) create_flight_notifications(flight) success = True db.session.commit() if success: flash(_('Please click "Publish Flight(s)" at the bottom to confirm our automatic analysis.')) return render_template( 'upload/result.jinja', num_flights=prefix, flights=flights, success=success)
def get_constant_elevation(flight): path = flight_path(flight.igc_file) return ((fix.seconds_of_day, elevation) for fix in path)
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 )