/// <summary> /// Displays a "Sign and review next" button if: /// a) the instructor is specified /// b) the specified instructor is the signed-in user. /// c) the flight to sign is specified /// d) there are multiple flights pending signature for that user /// </summary> public void PrepSignAndNext() { btnSignAndNext.Visible = CFIProfile != null && CFIProfile.UserName.CompareCurrentCultureIgnoreCase(Page.User.Identity.Name) == 0 && m_le != null && LogbookEntryBase.PendingSignaturesForStudent(CFIProfile, Profile.GetUser(m_le.User)).Count() > 1; }
private void CheckTimeIssues(LogbookEntryBase le) { if (currentAircraft.InstanceType != AircraftInstanceTypes.RealAircraft) { return; } int totalMinutes = le.TotalFlightTime.ToMinutes(); AddConditionalIssue(le.CrossCountry.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesXCGreaterThanTotal); AddConditionalIssue(le.Nighttime.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesNightGreaterThanTotal); AddConditionalIssue(le.SimulatedIFR.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesSimIFRGreaterThanTotal); AddConditionalIssue(le.IMC.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesIMCGreaterThanTotal); AddConditionalIssue(le.IMC.ToMinutes() + le.SimulatedIFR.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesSimPlusIMCGreaterThanTotal); AddConditionalIssue(le.Dual.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesDualGreaterThanTotal); AddConditionalIssue(le.CFI.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesCFIGreaterThanTotal); AddConditionalIssue(le.SIC.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesSICGreaterThanTotal); AddConditionalIssue(le.PIC.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesPICGreaterThanTotal); foreach (CustomFlightProperty cfp in le.CustomProperties) { AddConditionalIssue(cfp.PropertyType.Type == CFPPropertyType.cfpDecimal && !cfp.PropertyType.IsBasicDecimal && !cfp.PropertyType.IsNoSum && !hsExcludedTimeProps.Contains(cfp.PropTypeID) && cfp.DecValue.ToMinutes() > totalMinutes, LintOptions.TimeIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningPropertyGreaterThanTotal, cfp.PropertyType.Title)); } }
/// <summary> /// Updates the starting flight with the specified value in the specified column /// </summary> /// <param name="sfc">The column to read</param> /// <param name="sf">The target starting flight</param> /// <param name="value">The value</param> protected void SetValueForColumn(StartingFlightColumn sfc, LogbookEntryBase sf, Decimal value) { if (sf == null) { throw new ArgumentNullException("sf"); } switch (sfc) { case StartingFlightColumn.CFI: sf.CFI = value; break; case StartingFlightColumn.SIC: sf.SIC = value; break; case StartingFlightColumn.PIC: sf.PIC = value; break; case StartingFlightColumn.Total: sf.TotalFlightTime = value; break; } }
/// <summary> /// Performs the computation on the milestones to see what progress has been made for each. We MUST use LogbookEntryDisplays, so we override the base class (which uses ExaminerFlightRow) /// </summary> /// <returns>The resulting milestones.</returns> /// <exception cref="MyFlightbookException"></exception> public override Collection <MilestoneItem> Refresh() { if (String.IsNullOrEmpty(Username)) { throw new MyFlightbookException("Cannot compute milestones on an empty user!"); } StringBuilder sbRoutes = new StringBuilder(); Profile pf = Profile.GetUser(Username); IList <LogbookEntryDisplay> lst = LogbookEntryDisplay.GetFlightsForQuery(LogbookEntryBase.QueryCommand(new FlightQuery(Username)), Username, string.Empty, System.Web.UI.WebControls.SortDirection.Descending, pf.UsesHHMM, pf.UsesUTCDateOfFlight); // Set up the airport list once for DB efficiency foreach (LogbookEntryDisplay led in lst) { sbRoutes.AppendFormat(CultureInfo.InvariantCulture, "{0} ", led.Route); } AirportListOfRoutes = new AirportList(sbRoutes.ToString()); IDictionary <string, CannedQuery> d = UserQueries; foreach (LogbookEntryDisplay led in lst) { foreach (CustomRatingProgressItem cpi in ProgressItems) { cpi.ExamineFlight(led, d); } } ; return(Milestones); }
protected void btnCheckAll_Click(object sender, EventArgs e) { UInt32 selectedOptions = SelectedOptions; if (selectedOptions == 0) { lblErr.Text = Resources.FlightLint.errNoOptionsSelected; return; } FlightQuery fq = new FlightQuery(Page.User.Identity.Name); if (mfbDateLastCheck.Date.HasValue()) { fq.DateRange = FlightQuery.DateRanges.Custom; fq.DateMin = mfbDateLastCheck.Date; } DBHelperCommandArgs dbhq = LogbookEntryBase.QueryCommand(fq, fAsc: true); IEnumerable <LogbookEntryBase> rgle = LogbookEntryDisplay.GetFlightsForQuery(dbhq, Page.User.Identity.Name, "Date", SortDirection.Ascending, false, false); BindFlights(new FlightLint().CheckFlights(rgle, Page.User.Identity.Name, selectedOptions, mfbDateLastCheck.Date), rgle.Count()); Response.Cookies[szCookieLastCheck].Value = DateTime.Now.YMDString(); Response.Cookies[szCookieLastCheck].Expires = DateTime.Now.AddYears(5); }
private void CheckDutyIssues(LogbookEntryBase le, CustomFlightProperty cfpBlockIn, CustomFlightProperty cfpBlockOut) { // Look for a new duty start when a prior period is still open or a duty end when a prior period is NOT open CustomFlightProperty cfpDutyStart = le.CustomProperties[CustomPropertyType.KnownProperties.IDPropDutyStart]; CustomFlightProperty cfpFlightDutyStart = le.CustomProperties[CustomPropertyType.KnownProperties.IDPropFlightDutyTimeStart]; CustomFlightProperty cfpDutyEnd = le.CustomProperties[CustomPropertyType.KnownProperties.IDPropDutyEnd]; CustomFlightProperty cfpFlightDutyEnd = le.CustomProperties[CustomPropertyType.KnownProperties.IDPropFlightDutyTimeEnd]; // Starting a new duty period or flight duty period while a prior duty period is open AddConditionalIssue(dutyStart != null && dutyStart.HasValue && cfpDutyStart != null, LintOptions.DateTimeIssues, Resources.FlightLint.warningNewDutyStart); AddConditionalIssue(flightDutyStart != null && flightDutyStart.HasValue && cfpFlightDutyStart != null, LintOptions.DateTimeIssues, Resources.FlightLint.warningNewFlightDutyStart); // Starting a new duty period or flight duty period prior to the close of the prior one. AddConditionalIssue(dutyEnd != null && dutyEnd.HasValue && cfpDutyStart != null && cfpDutyStart.DateValue.CompareTo(dutyEnd.Value) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDutyStartPriorToPreviousDutyEnd); AddConditionalIssue(flightDutyEnd != null && flightDutyEnd.HasValue && cfpFlightDutyStart != null && cfpFlightDutyStart.DateValue.CompareTo(flightDutyEnd.Value) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightDutyStartPriorToPreviousFlightDutyEnd); // Ending a duty period or flight duty period that has no corresponding start. AddConditionalIssue(dutyStart == null && cfpDutyStart == null && cfpDutyEnd != null, LintOptions.DateTimeIssues, Resources.FlightLint.warningNewDutyEndNoStart); AddConditionalIssue(flightDutyStart == null && cfpFlightDutyStart == null && cfpFlightDutyEnd != null, LintOptions.DateTimeIssues, Resources.FlightLint.warningNewFlightDutyEndNoStart); DateTime bogusDate = le.FlightStart.LaterDate(le.FlightEnd) .LaterDate(le.EngineStart).LaterDate(le.EngineEnd) .LaterDate(cfpBlockIn == null ? DateTime.MinValue : cfpBlockIn.DateValue).LaterDate(cfpBlockOut == null ? DateTime.MinValue : cfpBlockOut.DateValue) .LaterDate(cfpDutyStart == null ? DateTime.MinValue : cfpDutyStart.DateValue).LaterDate(cfpDutyEnd == null ? DateTime.MinValue : cfpDutyEnd.DateValue) .LaterDate(cfpFlightDutyStart == null ? DateTime.MinValue : cfpFlightDutyStart.DateValue).LaterDate(cfpFlightDutyEnd == null ? DateTime.MinValue : cfpFlightDutyEnd.DateValue); AddConditionalIssue(bogusDate.CompareTo(DateTime.UtcNow.AddDays(5)) > 0, LintOptions.DateTimeIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningTimesSuspectTime, bogusDate.UTCDateFormatString())); UpdateDutyPeriods(cfpDutyStart, cfpFlightDutyStart, cfpDutyEnd, cfpFlightDutyEnd); }
private void CheckDateTimeIssues(LogbookEntryBase le) { CustomFlightProperty cfpBlockOut = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockOut); CustomFlightProperty cfpBlockIn = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockIn); // Block out after block in AddConditionalIssue(cfpBlockIn != null && cfpBlockOut != null && cfpBlockOut.DateValue.CompareTo(cfpBlockIn.DateValue) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDateTimeInvalidBlock); bool fHasEngineStart = le.EngineStart.HasValue(); bool fHasEngineEnd = le.EngineEnd.HasValue(); bool fHasFlightStart = le.FlightStart.HasValue(); bool fHasFlightEnd = le.FlightEnd.HasValue(); // Engine start must be before flight. Can be after block out, but not before block in AddConditionalIssue(fHasEngineStart && fHasFlightStart && le.FlightStart.CompareTo(le.EngineStart) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDateEngineAfterFlight); AddConditionalIssue(fHasEngineStart && fHasFlightEnd && le.FlightEnd.CompareTo(le.EngineStart) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndBeforeEngineStart); AddConditionalIssue(fHasEngineStart && cfpBlockIn != null && cfpBlockIn.DateValue.CompareTo(le.EngineStart) <= 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningEngineStartAfterBlockIn); // Flight start must be after engine start (checked above) and after block out AddConditionalIssue(fHasFlightStart && cfpBlockOut != null && le.FlightStart.CompareTo(cfpBlockOut.DateValue) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDateBlockAfterFlight); // Flight end must be after engine/flight start (checked in regular validation), after block out, and before block in AddConditionalIssue(fHasFlightEnd && cfpBlockOut != null && le.FlightEnd.CompareTo(cfpBlockOut.DateValue) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndBeforeBlockOut); AddConditionalIssue(fHasFlightEnd && cfpBlockIn != null && le.FlightEnd.CompareTo(cfpBlockIn.DateValue) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndAfterBlockIn); AddConditionalIssue(fHasFlightEnd && fHasEngineEnd && le.FlightEnd.CompareTo(le.EngineEnd) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndAfterEngineEnd); AddConditionalIssue(fHasEngineEnd && cfpBlockIn != null && le.EngineEnd.CompareTo(cfpBlockIn.DateValue) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningEngineEndBeforeBlockIn); CheckFlightLengthIssues(le); // Look for issues with sequential flights CheckSequentialFlightIssues(le); }
private void CheckMiscIssues(LogbookEntryBase le) { foreach (CustomFlightProperty cfp in le.CustomProperties) { if (cfp.PropertyType.IsExcludedFromMRU) { AddConditionalIssue(seenCheckrides.Contains(cfp.PropTypeID), LintOptions.MiscIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningMiscMultipleRedundantCheckrides, cfp.PropertyType.Title)); seenCheckrides.Add(cfp.PropTypeID); } } int maxDescribedLandings = 0; le.CustomProperties.ForEachEvent((cfp) => { if (cfp.PropertyType.IsLanding) { maxDescribedLandings = Math.Max(maxDescribedLandings, cfp.IntValue); } }); AddConditionalIssue(maxDescribedLandings > le.Landings, LintOptions.MiscIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningMoreDescribedLandingsThanTotal, le.Landings)); AddConditionalIssue(le.Dual > 0 && !le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropInstructorName) && le.CFISignatureState == LogbookEntryBase.SignatureState.None, LintOptions.MiscIssues, Resources.FlightLint.warningDualLoggedButNoCFIName); LogbookEntryBase leDefault = new LogbookEntry() { Date = le.Date, AircraftID = le.AircraftID, User = le.User }; AddConditionalIssue(le.IsEqualTo(leDefault), LintOptions.MiscIssues, Resources.FlightLint.warningFlightHasNoData); AddConditionalIssue(previousFlight != null && le.IsEqualTo(previousFlight), LintOptions.MiscIssues, Resources.FlightLint.warningMiscDuplicateFlight); }
protected void CropInRange(LogbookEntryBase le, string clipMin, string clipMax) { if (le == null) { throw new ArgumentNullException(nameof(le)); } int dataStart = (int)Math.Truncate((Convert.ToDouble(clipMin, CultureInfo.InvariantCulture) / DataCropRange) * Math.Max(DataPointCount - 1, 0)); int dataEnd = (int)Math.Truncate((Convert.ToDouble(clipMax, CultureInfo.InvariantCulture) / DataCropRange) * Math.Max(DataPointCount - 1, 0)); if (dataEnd <= dataStart) { dataEnd = dataStart + 1; } if ((dataStart == 0 && dataEnd == 0) || dataEnd >= DataPointCount) { ResetCrop(le); return; } TelemetryReference tr = le.Telemetry; tr.MetaData.DataStart = dataStart; tr.MetaData.DataEnd = dataEnd; using (FlightData fd = new FlightData()) { fd.ParseFlightData(le); tr.RecalcGoogleData(fd); } tr.Commit(); Response.Redirect(Request.RawUrl); }
/// <summary> /// Returns the Uri to view a flight (useful for FB/Twitter/Etc.) /// </summary> /// <param name="le">The flight to be shared</param> /// <param name="szHost">Hostname (if not provided, uses current brand)</param> /// <returns></returns> public static Uri ShareFlightUri(LogbookEntryBase le, string szHost = null) { if (le == null) { throw new ArgumentNullException("le"); } return(String.Format(CultureInfo.InvariantCulture, "~/Public/ViewPublicFlight.aspx/{0}?v={1}", le.FlightID, (new Random()).Next(10000)).ToAbsoluteURL("https", szHost ?? Branding.CurrentBrand.HostName)); }
private void CheckTimeIssues(LogbookEntryBase le) { if (currentAircraft.InstanceType != AircraftInstanceTypes.RealAircraft) { return; } int totalMinutes = le.TotalFlightTime.ToMinutes(); AddConditionalIssue(le.CrossCountry.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesXCGreaterThanTotal); AddConditionalIssue(le.Nighttime.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesNightGreaterThanTotal); AddConditionalIssue(le.SimulatedIFR.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesSimIFRGreaterThanTotal); AddConditionalIssue(le.IMC.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesIMCGreaterThanTotal); AddConditionalIssue(le.IMC.ToMinutes() + le.SimulatedIFR.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesSimPlusIMCGreaterThanTotal); AddConditionalIssue(le.Dual.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesDualGreaterThanTotal); AddConditionalIssue(le.CFI.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesCFIGreaterThanTotal); AddConditionalIssue(le.SIC.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesSICGreaterThanTotal); AddConditionalIssue(le.PIC.ToMinutes() > totalMinutes, LintOptions.TimeIssues, Resources.FlightLint.warningTimesPICGreaterThanTotal); AddConditionalIssue(le.PIC.ToMinutes() + le.SIC.ToMinutes() + le.CFI.ToMinutes() + le.Dual.ToMinutes() == 0 && totalMinutes > 0, LintOptions.TimeIssues, Resources.FlightLint.warningTotalTimeButNoOtherTime); CustomFlightProperty cfpSolo = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDPropSolo); if (cfpSolo != null) { int soloMinutes = cfpSolo.DecValue.ToMinutes(); AddConditionalIssue(soloMinutes > le.PIC.ToMinutes(), LintOptions.TimeIssues, Resources.FlightLint.warningSoloTimeExceedsPICTime); AddConditionalIssue(soloMinutes > totalMinutes - le.SIC.ToMinutes() - le.CFI.ToMinutes() - le.Dual.ToMinutes(), LintOptions.TimeIssues, Resources.FlightLint.warningSoloTimeWithNonSoloTime); } foreach (CustomFlightProperty cfp in le.CustomProperties) { AddConditionalIssue(cfp.PropertyType.Type == CFPPropertyType.cfpDecimal && !cfp.PropertyType.IsBasicDecimal && !cfp.PropertyType.IsNoSum && !hsExcludedTimeProps.Contains(cfp.PropTypeID) && cfp.DecValue.ToMinutes() > totalMinutes, LintOptions.TimeIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningPropertyGreaterThanTotal, cfp.PropertyType.Title)); } CustomFlightProperty cfpTachStart = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDPropTachStart); CustomFlightProperty cfpTachEnd = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDPropTachEnd); AddConditionalIssue(cfpTachStart != null && cfpTachEnd != null && cfpTachEnd.DecValue < cfpTachStart.DecValue, LintOptions.TimeIssues, Resources.FlightLint.warningTachEndBeforeTachStart); if (le.TotalFlightTime > 0) { // Look for block time or engine time that varies significantly from total time UNLESS hobbs is present; if so, compare hobbs to that. Ditto tach, if tach is of by more than 30%. const decimal maxHobbsVariation = 0.2M; const decimal maxBlockVariation = 0.1M; CustomFlightProperty cfpBlockOut = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockOut); CustomFlightProperty cfpBlockIn = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockIn); bool fHasHobbs = le.HobbsEnd > 0 && le.HobbsStart > 0 && le.HobbsEnd > le.HobbsStart; decimal hobbsVariation = Math.Abs(le.HobbsEnd - le.HobbsStart - le.TotalFlightTime); decimal blockTimeVariation = (cfpBlockIn != null && cfpBlockOut != null) ? Math.Abs((decimal)cfpBlockIn.DateValue.Subtract(cfpBlockOut.DateValue).TotalHours - le.TotalFlightTime) : 0; AddConditionalIssue(fHasHobbs && hobbsVariation > maxHobbsVariation, LintOptions.TimeIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningHobbsAndTotalsDiffer, hobbsVariation.ToHHMM())); AddConditionalIssue(!fHasHobbs && blockTimeVariation > maxBlockVariation, LintOptions.TimeIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningBlockAndTotalsDiffer, blockTimeVariation.ToHHMM())); } }
/// <summary> /// Updates recent flights for the specified flight, removing it if it is no longer public /// </summary> /// <param name="le"></param> public static void RefreshForFlight(LogbookEntryBase le) { FlightStats fs = CachedStats(); if (fs != null && fs.RecentPublicFlights != null && !le.fIsPublic) { fs.m_lstFlights.RemoveAll(l => l.FlightID == le.FlightID); } }
private void CheckIFRIssues(LogbookEntryBase le) { AddConditionalIssue(le.Approaches > 0 && !le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropApproachName) && !ApproachDescription.ExtractApproaches(le.Comment).Any(), LintOptions.IFRIssues, Resources.FlightLint.warningIFRNoApproachDescription); AddConditionalIssue(le.SimulatedIFR > 0 && le.Dual == 0 && currentAircraft.InstanceType == AircraftInstanceTypes.RealAircraft && !le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropSafetyPilotName) && !le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropNameOfExaminer), LintOptions.IFRIssues, Resources.FlightLint.warningIFRNoSafetyPilot); AddConditionalIssue((le.Approaches > 0 || le.fHoldingProcedures) && le.SimulatedIFR + le.IMC == 0, LintOptions.IFRIssues, Resources.FlightLint.warningIFRApproachesButNoIFR); }
protected void btnSignAndNext_Click(object sender, EventArgs e) { if (SignFlight()) { List <LogbookEntryBase> lst = new List <LogbookEntryBase>(LogbookEntryBase.PendingSignaturesForStudent(CFIProfile, Profile.GetUser(m_le.User))); lst.RemoveAll(leb => leb.FlightID == m_le.FlightID); SigningFinished?.Invoke(this, new LogbookEventArgs(m_le.FlightID, lst.Any() ? lst[0].FlightID : LogbookEntryCore.idFlightNone)); } }
private void CheckAirportIssues(LogbookEntryBase le) { IEnumerable <string> rgCodes = airport.SplitCodes(le.Route); foreach (string szCode in rgCodes) { if (szCode.StartsWith(airport.ForceNavaidPrefix, StringComparison.CurrentCultureIgnoreCase)) { continue; } if (szCode.CompareCurrentCultureIgnoreCase("LOCAL") == 0 || szCode.CompareCurrentCultureIgnoreCase("LCL") == 0) { AddIssue(LintOptions.AirportIssues, Resources.FlightLint.warningAirportLocal); continue; } airport ap = alSubset.GetAirportByCode(szCode); if (ap == null) { AddIssue(LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportNotFound, szCode)); } else { AddConditionalIssue((currentCatClassID == CategoryClass.CatClassID.AMEL || currentCatClassID == CategoryClass.CatClassID.ASEL) && ap.IsSeaport, LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportLandPlaneAtSeaport, szCode)); AddConditionalIssue(CategoryClass.IsAirplane(currentCatClassID) && ap.FacilityTypeCode == "H", LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportAirplaneAtHeliport, szCode)); } } // Sanity check for speed if (le.TotalFlightTime > 0) { double dist = alSubset.DistanceForRoute(); double speed = dist / (double)le.TotalFlightTime; AddConditionalIssue(speed > (currentModel.EngineType == MakeModel.TurbineLevel.Piston ? 500 : 1000), LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportUnlikelyImpliedSpeed, speed)); } // Look for missing night takeoffs or landings if (rgCodes.Any()) { airport apDep = alSubset.GetAirportByCode(rgCodes.ElementAt(0)); airport apArr = alSubset.GetAirportByCode(rgCodes.ElementAt(rgCodes.Count() - 1)); if (apDep != null) { AddConditionalIssue(le.FlightStart.HasValue() && !le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropNightTakeoff) && new SolarTools.SunriseSunsetTimes(le.FlightStart, apDep.LatLong.Latitude, apDep.LatLong.Longitude).IsFAANight, LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportMissingNightTakeoff, apDep.Code, le.FlightStart.UTCFormattedStringOrEmpty(false))); } if (apArr != null) { AddConditionalIssue(le.FlightEnd.HasValue() && le.NightLandings == 0 && new SolarTools.SunriseSunsetTimes(le.FlightEnd, apArr.LatLong.Latitude, apArr.LatLong.Longitude).IsFAANight, LintOptions.AirportIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningAirportMissingNightLanding, apArr.Code, le.FlightEnd.UTCFormattedStringOrEmpty(false))); } } }
public CloudAhoyPostFileMetaData(LogbookEntryBase le) : this() { if (le == null) { throw new ArgumentNullException("le"); } tail = le.TailNumDisplay; remarks = le.Comment; }
protected void mfbFlightContextMenu_DeleteFlight(object sender, LogbookEventArgs e) { if (e == null) { throw new ArgumentNullException(nameof(e)); } LogbookEntryBase.FDeleteEntry(e.FlightID, Page.User.Identity.Name); Response.Redirect(TargetPage); }
/// <summary> /// Initializes the specified starting flight with the values of the decimal edits in the row /// </summary> /// <param name="sf">The starting flight</param> /// <param name="iRow">The row</param> protected void FromRow(LogbookEntryBase sf, int iRow) { int iCol = 0; foreach (StartingFlightColumn sfc in Enum.GetValues(typeof(StartingFlightColumn))) { Controls_mfbDecimalEdit de = (Controls_mfbDecimalEdit)tblStartingFlights.Rows[iRow].FindControl(IDForCell(iRow, iCol)); SetValueForColumn(sfc, sf, de.Value); iCol++; } }
private void CheckDateTimeIssues(LogbookEntryBase le) { CustomFlightProperty cfpBlockOut = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockOut); CustomFlightProperty cfpBlockIn = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockIn); // Block out after block in AddConditionalIssue(cfpBlockIn != null && cfpBlockOut != null && cfpBlockOut.DateValue.CompareTo(cfpBlockIn.DateValue) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDateTimeInvalidBlock); if (le.EngineStart.HasValue()) { // Engine start must be before flight. Can be after block out, but not before block in AddConditionalIssue(le.FlightStart.HasValue() && le.FlightStart.CompareTo(le.EngineStart) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDateEngineAfterFlight); AddConditionalIssue(le.FlightEnd.HasValue() && le.FlightEnd.CompareTo(le.EngineStart) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndBeforeEngineStart); AddConditionalIssue(cfpBlockIn != null && cfpBlockIn.DateValue.CompareTo(le.EngineStart) <= 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningEngineStartAfterBlockIn); } // Flight start must be after engine start (checked above) and after block out AddConditionalIssue(le.FlightStart.HasValue() && cfpBlockOut != null && le.FlightStart.CompareTo(cfpBlockOut.DateValue) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningDateBlockAfterFlight); // Flight end must be after engine/flight start (checked in regular validation), after block out, and before block in if (le.FlightEnd.HasValue()) { AddConditionalIssue(cfpBlockOut != null && le.FlightEnd.CompareTo(cfpBlockOut.DateValue) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndBeforeBlockOut); AddConditionalIssue(cfpBlockIn != null && le.FlightEnd.CompareTo(cfpBlockIn.DateValue) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndAfterBlockIn); AddConditionalIssue(le.EngineEnd.HasValue() && le.FlightEnd.CompareTo(le.EngineEnd) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightEndAfterEngineEnd); } if (le.EngineEnd.HasValue()) { AddConditionalIssue(cfpBlockIn != null && le.EngineEnd.CompareTo(cfpBlockIn.DateValue) < 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningEngineEndBeforeBlockIn); } const int MaxHoursDifference = 48; // Check that engine, flight, and block times are all roughly equal to date-of-flight AddConditionalIssue((le.EngineStart.HasValue() && Math.Abs(le.EngineStart.Subtract(le.Date).TotalHours) > MaxHoursDifference) || (le.EngineEnd.HasValue() && Math.Abs(le.EngineEnd.Subtract(le.Date).TotalHours) > MaxHoursDifference), LintOptions.DateTimeIssues, Resources.FlightLint.warningEngineTimeDiffersDate); AddConditionalIssue((le.FlightStart.HasValue() && Math.Abs(le.FlightStart.Subtract(le.Date).TotalHours) > MaxHoursDifference) || (le.FlightEnd.HasValue() && Math.Abs(le.FlightEnd.Subtract(le.Date).TotalHours) > MaxHoursDifference), LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightTimeDiffersDate); AddConditionalIssue((cfpBlockOut != null && Math.Abs(cfpBlockOut.DateValue.Subtract(le.Date).TotalHours) > MaxHoursDifference) || (cfpBlockIn != null && Math.Abs(cfpBlockIn.DateValue.Subtract(le.Date).TotalHours) > MaxHoursDifference), LintOptions.DateTimeIssues, Resources.FlightLint.warningBlockTimeDiffersDate); // Look for issues with sequential flights CheckSequentialFlightIssues(le); }
protected void Page_Load(object sender, EventArgs e) { this.Master.SelectedTab = tabID.tabHome; PageSize = 15; // figure out who to show if (!IsPostBack) { IEnumerable <LogbookEntry> rgle = Array.Empty <LogbookEntry>(); string szUserEnc = util.GetStringParam(Request, "uid"); UserName = string.Empty; if (!String.IsNullOrEmpty(szUserEnc)) { SharedDataEncryptor enc = new SharedDataEncryptor(MFBConstants.keyEncryptMyFlights); UserName = enc.Decrypt(szUserEnc); } if (String.IsNullOrEmpty(UserName)) { FlightStats fs = FlightStats.GetFlightStats(); List <LogbookEntry> lst = new List <LogbookEntry>(fs.RecentPublicFlights); if (lst.Count > PageSize) { lst.RemoveRange(PageSize, lst.Count - PageSize); } rgle = lst; } else { try { // below can throw argument null exception if it's an invalid username Profile pf = Profile.GetUser(UserName); if (pf.UserFullName.Length > 0) { lblHeader.Text = String.Format(CultureInfo.CurrentCulture, Resources.LogbookEntry.PublicFlightPageHeader, HttpUtility.HtmlEncode(pf.UserFullName)); } rgle = LogbookEntryBase.GetPublicFlightsForUser(UserName, 0, PageSize); } catch (Exception ex) when(ex is NullReferenceException) { } } gvMyFlights.DataSource = rgle; gvMyFlights.DataBind(); } }
protected void lnkCheckFlight_Click(object sender, EventArgs e) { Page.Validate(szValGroupEdit); // catch any actual errors too. LogbookEntryBase le = InitLogbookEntryFromForm(); // See if there are any actual errors, stick those at the top of the list. le.IsValid(); // will populate ErrorString. if (!le.IsNewFlight) { le.CFISignatureState = new LogbookEntry(le.FlightID, le.User).CFISignatureState; } CheckFlight(pnlFlightLint, gvFlightLint, le); }
protected void AddErrorRow(LogbookEntryBase le, string szContext, int iRow) { if (le == null) { throw new ArgumentNullException("le"); } if (IsPendingOnly && le.LastError != LogbookEntryBase.ErrorCode.None) // ignore errors if the importer is only pending flights and the error is a logbook validation error (no tail, future date, night, etc.) { return; } // if we're here, we are *either* not pending only *or* we didn't have a logbookentry validation error (e.g., could be malformed row) ErrorContext[iRow] = szContext; // save the context for data bind AddTextRow(plcErrorList, String.Format(CultureInfo.CurrentCulture, Resources.LogbookEntry.errImportRowHasError, iRow, le.ErrorString), "error"); }
protected void SetUpDownload(LogbookEntryBase led) { if (led == null) { throw new ArgumentNullException(nameof(led)); } if (Viewer.CloudAhoyToken == null || Viewer.CloudAhoyToken.AccessToken == null) { lnkSendCloudAhoy.Visible = false; } lblOriginalFormat.Text = FormatNameForTelemetry(led); // allow selection of units if units are not implicitly known. cmbAltUnits.Enabled = cmbSpeedUnits.Enabled = CanSpecifyUnitsForTelemetry(led); }
protected void ResetCrop(LogbookEntryBase le) { if (le == null) { throw new ArgumentNullException(nameof(le)); } TelemetryReference tr = le.Telemetry; tr.MetaData.DataEnd = tr.MetaData.DataStart = null; using (FlightData fd = new FlightData()) { fd.ParseFlightData(le); tr.RecalcGoogleData(fd); } tr.Commit(); Response.Redirect(Request.RawUrl); }
protected static void CheckFlight(Control container, GridView gv, LogbookEntryBase le) { if (container == null) { throw new ArgumentNullException(nameof(container)); } if (gv == null) { throw new ArgumentNullException(nameof(gv)); } if (le == null) { throw new ArgumentNullException(nameof(le)); } gv.DataSource = new MyFlightbook.Lint.FlightLint().CheckFlights(new LogbookEntryBase[] { le }, le.User, MyFlightbook.Lint.FlightLint.DefaultOptionsForLocale); gv.DataBind(); container.Visible = true; }
private void CheckSimIssues(LogbookEntryBase le) { bool hasSimRegistration = le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropSimRegistration); if (currentAircraft.InstanceType == AircraftInstanceTypes.RealAircraft) { AddConditionalIssue(le.GroundSim > 0, LintOptions.SimIssues, Resources.FlightLint.warningSIMGroundSimInRealAircraft); AddConditionalIssue(hasSimRegistration, LintOptions.SimIssues, Resources.FlightLint.warningSIMDeviceIdentifierOnRealAircraft); } else { AddConditionalIssue(le.PIC > 0, LintOptions.SimIssues, Resources.FlightLint.warningSIMPICInSim); AddConditionalIssue(le.SIC > 0, LintOptions.SimIssues, Resources.FlightLint.warningSIMSICInSim); AddConditionalIssue(le.TotalFlightTime > 0, LintOptions.SimIssues, Resources.FlightLint.warningSIMTotalInSim); AddConditionalIssue(le.IMC > 0, LintOptions.SimIssues, Resources.FlightLint.warningSIMActualIMC); AddConditionalIssue(le.CrossCountry > 0, LintOptions.SimIssues, Resources.FlightLint.warningSIMCrossCountryInSim); AddConditionalIssue(!hasSimRegistration, LintOptions.SimIssues, Resources.FlightLint.warningSIMNoDeviceIdentifier); } }
private void CheckSequentialFlightIssues(LogbookEntryBase le) { if (previousFlight == null) { return; } AddConditionalIssue(previousFlight.EngineEnd.HasValue() && le.EngineStart.HasValue() && previousFlight.EngineEnd.CompareTo(le.EngineStart) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningPreviousEngineEndsAfterStart); AddConditionalIssue(previousFlight.FlightEnd.HasValue() && le.FlightStart.HasValue() && previousFlight.FlightEnd.CompareTo(le.FlightStart) > 0, LintOptions.DateTimeIssues, Resources.FlightLint.warningPreviousFlightEndsAfterStart); CustomFlightProperty cfpBlockIn = le.CustomProperties[CustomPropertyType.KnownProperties.IDBlockIn]; CustomFlightProperty cfpBlockOut = le.CustomProperties[CustomPropertyType.KnownProperties.IDBlockOut]; CheckBlockIssues(cfpBlockOut); CheckDutyIssues(le, cfpBlockIn, cfpBlockOut); }
private void CheckFlightLengthIssues(LogbookEntryBase le) { CustomFlightProperty cfpBlockOut = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockOut); CustomFlightProperty cfpBlockIn = le.CustomProperties.GetEventWithTypeID(CustomPropertyType.KnownProperties.IDBlockIn); const int MaxHoursDifference = 48; // Check that engine, flight, and block times are all roughly equal to date-of-flight AddConditionalIssue((le.EngineStart.HasValue() && Math.Abs(le.EngineStart.Subtract(le.Date).TotalHours) > MaxHoursDifference) || (le.EngineEnd.HasValue() && Math.Abs(le.EngineEnd.Subtract(le.Date).TotalHours) > MaxHoursDifference), LintOptions.DateTimeIssues, Resources.FlightLint.warningEngineTimeDiffersDate); AddConditionalIssue((le.FlightStart.HasValue() && Math.Abs(le.FlightStart.Subtract(le.Date).TotalHours) > MaxHoursDifference) || (le.FlightEnd.HasValue() && Math.Abs(le.FlightEnd.Subtract(le.Date).TotalHours) > MaxHoursDifference), LintOptions.DateTimeIssues, Resources.FlightLint.warningFlightTimeDiffersDate); AddConditionalIssue((cfpBlockOut != null && Math.Abs(cfpBlockOut.DateValue.Subtract(le.Date).TotalHours) > MaxHoursDifference) || (cfpBlockIn != null && Math.Abs(cfpBlockIn.DateValue.Subtract(le.Date).TotalHours) > MaxHoursDifference), LintOptions.DateTimeIssues, Resources.FlightLint.warningBlockTimeDiffersDate); }
/// <summary> /// If we're setting up a new flight and last flight had an ending hobbs, initialize with that /// clear the cookie, if present, regardless. /// </summary> protected void InitializeHobbs(LogbookEntryBase le) { if (le == null) { throw new ArgumentNullException(nameof(le)); } HttpCookie c = Request.Cookies[keyCookieLastEndingHobbs]; if (c != null) { if (le.IsNewFlight) { if (decimal.TryParse(c.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out decimal hobbsEnd)) { le.HobbsStart = hobbsEnd; } } Response.Cookies[keyCookieLastEndingHobbs].Expires = DateTime.Now.AddDays(-1); // clear it. } }
private void CheckXCIssues(LogbookEntryBase le) { if (currentAircraft.InstanceType != AircraftInstanceTypes.RealAircraft) { return; } AddConditionalIssue(le.CrossCountry > 0 && le.CrossCountry.ToMinutes() < le.TotalFlightTime.ToMinutes(), LintOptions.XCIssues, Resources.FlightLint.warningXCNotWholeFlightXC); AddConditionalIssue(le.CrossCountry > 0 && (le.CFI + le.Dual + le.SIC + le.PIC).ToMinutes() == 0, LintOptions.XCIssues, Resources.FlightLint.warningXCTimeFoundButNoRole); double distance = alSubset.MaxDistanceFromStartingAirport(); if (le.CrossCountry == 0) { int minDistanceXC = (currentCatClassID == CategoryClass.CatClassID.Helicopter ? 25 : 50); AddConditionalIssue(distance > minDistanceXC, LintOptions.XCIssues, String.Format(CultureInfo.CurrentCulture, Resources.FlightLint.warningXCMissingXC, minDistanceXC)); } bool fxcLessThan25 = le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropXCLessThan25nm); bool fxcLessThan50 = le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropXCLessThan50nm); bool fxcMoreThan50 = le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropXCMoreThan50nm); bool fxcMoreThan100 = le.CustomProperties.PropertyExistsWithID(CustomPropertyType.KnownProperties.IDPropXCMoreThan100nm); AddConditionalIssue(fxcLessThan25 && distance > 25, LintOptions.XCIssues, Resources.FlightLint.warningXCDistanceLessThan25ButFlewMore); AddConditionalIssue(fxcLessThan50 && distance > 50, LintOptions.XCIssues, Resources.FlightLint.warningXCDistanceLessThan50ButFlewMore); AddConditionalIssue(fxcMoreThan50 && distance < 50, LintOptions.XCIssues, Resources.FlightLint.warningXCDistanceMoreThan50ButFlewLess); AddConditionalIssue(fxcMoreThan100 && distance < 100, LintOptions.XCIssues, Resources.FlightLint.warningXCDistanceMoreThan100ButFlewLess); AddConditionalIssue((fxcLessThan25 ? 1 : 0) + (fxcLessThan50 ? 1 : 0) + (fxcMoreThan50 ? 1 : 0) + (fxcMoreThan100 ? 1 : 0) > 1, LintOptions.XCIssues, Resources.FlightLint.warningXCInconsistentDistances); decimal xcLessThan25 = le.CustomProperties.DecimalValueForProperty(CustomPropertyType.KnownProperties.IDPropXCLessThan25nm); decimal xcLessThan50 = le.CustomProperties.DecimalValueForProperty(CustomPropertyType.KnownProperties.IDPropXCLessThan50nm); decimal xcMoreThan50 = le.CustomProperties.DecimalValueForProperty(CustomPropertyType.KnownProperties.IDPropXCMoreThan50nm); decimal xcMoreThan100 = le.CustomProperties.DecimalValueForProperty(CustomPropertyType.KnownProperties.IDPropXCMoreThan100nm); AddConditionalIssue(xcLessThan25 > 0 && xcLessThan25.ToMinutes() != le.CrossCountry.ToMinutes(), LintOptions.XCIssues, Resources.FlightLint.warningXCTimeDistanceNotEqualXC); AddConditionalIssue(xcLessThan50 > 0 && xcLessThan50.ToMinutes() != le.CrossCountry.ToMinutes(), LintOptions.XCIssues, Resources.FlightLint.warningXCTimeDistanceNotEqualXC); AddConditionalIssue(xcMoreThan50 > 0 && xcMoreThan50.ToMinutes() != le.CrossCountry.ToMinutes(), LintOptions.XCIssues, Resources.FlightLint.warningXCTimeDistanceNotEqualXC); AddConditionalIssue(xcMoreThan100 > 0 && xcMoreThan100.ToMinutes() != le.CrossCountry.ToMinutes(), LintOptions.XCIssues, Resources.FlightLint.warningXCTimeDistanceNotEqualXC); }