1080 lines
36 KiB
Go
1080 lines
36 KiB
Go
package handlers
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
|
|
afterflightinspection "wucher/internal/domain/after_flight_inspection"
|
|
authdomain "wucher/internal/domain/auth"
|
|
"wucher/internal/domain/flight"
|
|
flightdata "wucher/internal/domain/flight_data"
|
|
fmreport "wucher/internal/domain/fm_report"
|
|
helicopterdomain "wucher/internal/domain/helicopter"
|
|
"wucher/internal/domain/mission"
|
|
reserveac "wucher/internal/domain/reserve_ac"
|
|
"wucher/internal/service"
|
|
sharedconst "wucher/internal/shared/const"
|
|
"wucher/internal/shared/pkg/appctx"
|
|
"wucher/internal/shared/pkg/apperrorsx"
|
|
"wucher/internal/shared/pkg/reserveacutil"
|
|
"wucher/internal/shared/pkg/userctx"
|
|
"wucher/internal/shared/pkg/uuidv7"
|
|
requestdto "wucher/internal/transport/http/dto/request"
|
|
responsedto "wucher/internal/transport/http/dto/response"
|
|
"wucher/internal/transport/http/jsonapi"
|
|
"wucher/internal/transport/http/response"
|
|
"wucher/internal/transport/http/validators"
|
|
)
|
|
|
|
type FlightHandler struct {
|
|
svc flight.FlightService
|
|
afterFlightInspection afterflightinspection.Service
|
|
fmReport fmreport.Service
|
|
takeover takeoverLookupService
|
|
reserveAc reserveac.ReserveAcService
|
|
helicopter helicopterdomain.Service
|
|
mission mission.Service
|
|
flightData flightdata.Service
|
|
auth *service.AuthService
|
|
validate *validators.Validator
|
|
}
|
|
|
|
func NewFlightHandler(svc flight.FlightService) *FlightHandler {
|
|
return &FlightHandler{
|
|
svc: svc,
|
|
validate: validators.New(),
|
|
}
|
|
}
|
|
|
|
func (h *FlightHandler) WithReserveAcService(reserveAcSvc reserveac.ReserveAcService) *FlightHandler {
|
|
h.reserveAc = reserveAcSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithAfterFlightInspectionService(afterSvc afterflightinspection.Service) *FlightHandler {
|
|
h.afterFlightInspection = afterSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithFMReportService(reportSvc fmreport.Service) *FlightHandler {
|
|
h.fmReport = reportSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithTakeoverService(takeoverSvc takeoverLookupService) *FlightHandler {
|
|
h.takeover = takeoverSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithHelicopterService(heliSvc helicopterdomain.Service) *FlightHandler {
|
|
h.helicopter = heliSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithMissionService(missionSvc mission.Service) *FlightHandler {
|
|
h.mission = missionSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithFlightDataService(flightDataSvc flightdata.Service) *FlightHandler {
|
|
h.flightData = flightDataSvc
|
|
return h
|
|
}
|
|
|
|
func (h *FlightHandler) WithAuthService(authSvc *service.AuthService) *FlightHandler {
|
|
h.auth = authSvc
|
|
return h
|
|
}
|
|
|
|
// Create keeps internal compatibility but is no longer exposed as public HTTP route.
|
|
func (h *FlightHandler) Create(c *fiber.Ctx) error {
|
|
var req requestdto.FlightCreateRequest
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return writeFlightErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{
|
|
Status: "400",
|
|
Title: "Invalid JSON",
|
|
Detail: safeInternalDetail(),
|
|
}})
|
|
}
|
|
if errs := h.validate.ValidateStruct(req); errs != nil {
|
|
return writeFlightErrors(c, fiber.StatusUnprocessableEntity, errs)
|
|
}
|
|
|
|
date, err := time.Parse("2006-01-02", strings.TrimSpace(req.Data.Attributes.Date))
|
|
if err != nil {
|
|
return writeFlightErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{
|
|
Status: "422",
|
|
Title: "Validation error",
|
|
Detail: "date must be YYYY-MM-DD",
|
|
Source: &jsonapi.ErrorSource{Pointer: "/data/attributes/date"},
|
|
}})
|
|
}
|
|
if _, errObj := parseOptionalUUIDFlight(req.Data.Attributes.DutyRosterID, "/data/attributes/duty_roster_id"); errObj != nil {
|
|
return writeFlightErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{*errObj})
|
|
}
|
|
if _, errObj := parseOptionalUUIDFlight(req.Data.Attributes.ReserveAcID, "/data/attributes/reserve_ac_id"); errObj != nil {
|
|
return writeFlightErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{*errObj})
|
|
}
|
|
|
|
row := &flight.Flight{
|
|
Date: date.UTC(),
|
|
CreatedBy: actorUserID(c),
|
|
UpdatedBy: actorUserID(c),
|
|
}
|
|
|
|
if err := h.svc.Create(c.UserContext(), row); err != nil {
|
|
return writeFlightErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{
|
|
Status: "400",
|
|
Title: "Create failed",
|
|
Detail: safeInternalDetail(),
|
|
}})
|
|
}
|
|
|
|
created, err := h.svc.GetByID(c.UserContext(), row.ID)
|
|
if err == nil && created != nil {
|
|
return response.Write(c, fiber.StatusCreated, h.flightMutationResource(c.UserContext(), created))
|
|
}
|
|
return response.Write(c, fiber.StatusCreated, h.flightMutationResource(c.UserContext(), row))
|
|
}
|
|
|
|
// GetFlightsByAuthUser godoc
|
|
// @Summary Get flights for current auth user (from duty roster assignment)
|
|
// @Tags Flight
|
|
// @Produce json
|
|
// @Description Returns flights assigned to current auth user, including workflow steps (`duty_roster`, `reserve_ac`, `mission`, `after_flight_inspection`, `fm_report`).
|
|
// @Description Each step includes `status`, `completed_at`, and `completed_by` for consistent FE rendering.
|
|
// @Param page[number] query int false "Page number"
|
|
// @Param page[size] query int false "Page size"
|
|
// @Param page query int false "Page number (fallback)"
|
|
// @Param size query int false "Page size (fallback)"
|
|
// @Param limit query int false "Page size override"
|
|
// @Success 200 {object} responsedto.FlightListResponse
|
|
// @Failure 401 {object} jsonapi.ErrorDocument
|
|
// @Router /api/v1/flights/get [get]
|
|
func (h *FlightHandler) GetByAuthUser(c *fiber.Ctx) error {
|
|
userID := actorUserID(c)
|
|
if len(userID) == 0 {
|
|
return writeFlightErrors(c, fiber.StatusUnauthorized, []jsonapi.ErrorObject{{
|
|
Status: "401",
|
|
Title: "Unauthorized",
|
|
Detail: "missing auth context",
|
|
}})
|
|
}
|
|
|
|
pageNumber := parseIntDefault(c.Query("page[number]"), 0)
|
|
if pageNumber <= 0 {
|
|
pageNumber = parseIntDefault(c.Query("page"), 1)
|
|
}
|
|
pageSize := parseIntDefault(c.Query("page[size]"), 0)
|
|
if pageSize <= 0 {
|
|
pageSize = parseIntDefault(c.Query("limit"), 0)
|
|
}
|
|
if pageSize <= 0 {
|
|
pageSize = parseIntDefault(c.Query("size"), 20)
|
|
}
|
|
if pageSize > 100 {
|
|
pageSize = 100
|
|
}
|
|
if pageSize < 1 {
|
|
pageSize = 20
|
|
}
|
|
if pageNumber < 1 {
|
|
pageNumber = 1
|
|
}
|
|
|
|
offset := (pageNumber - 1) * pageSize
|
|
_ = offset
|
|
rows, total, err := h.svc.ListByUserID(c.UserContext(), userID, pageSize, offset)
|
|
if err != nil {
|
|
return writeFlightErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{
|
|
Status: "400",
|
|
Title: "Get failed",
|
|
Detail: safeInternalDetail(),
|
|
}})
|
|
}
|
|
missionsByFlightID, err := h.prefetchMissionsByFlightID(c.UserContext(), rows)
|
|
if err != nil {
|
|
return writeFlightErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{
|
|
Status: "400",
|
|
Title: "List failed",
|
|
Detail: safeInternalDetail(),
|
|
}})
|
|
}
|
|
|
|
dailyInspectionCache := make(map[string]*responsedto.FlightDailyInspectionSummary)
|
|
afterFlightCache := make(map[string]responsedto.FlightStepItem)
|
|
fmReportCache := make(map[string]responsedto.FlightStepItem)
|
|
|
|
data := make([]responsedto.FlightResource, 0, len(rows))
|
|
for i := range rows {
|
|
data = append(data, h.flightResourceForList(c.UserContext(), c, &rows[i], missionsByFlightID[string(rows[i].ID)], dailyInspectionCache, afterFlightCache, fmReportCache))
|
|
}
|
|
return response.WriteWithMeta(c, fiber.StatusOK, data, map[string]any{
|
|
"total": total,
|
|
})
|
|
}
|
|
|
|
// ListFlights godoc
|
|
// @Summary List flights
|
|
// @Description Supports `search`, `filter[search]`, `sort`, `page[number]`, `page[size]`, `page`, `size`, and `limit`.
|
|
// @Description Supports `date` and `filter[date]` for exact flight date filtering (`YYYY-MM-DD`).
|
|
// @Description Returns paginated flights with workflow steps (`takeover`, `mission`, `after_flight_inspection`, `fm_report`).
|
|
// @Description Each step includes `status`, `completed_at`, and `completed_by` for consistent FE rendering.
|
|
// @Tags Flight
|
|
// @Produce json
|
|
// @Param search query string false "Search text"
|
|
// @Param filter[search] query string false "Search text (JSON:API style)"
|
|
// @Param date query string false "Filter by flight date (YYYY-MM-DD)"
|
|
// @Param filter[date] query string false "Filter by flight date (YYYY-MM-DD) (JSON:API style)"
|
|
// @Param sort query string false "Sort field"
|
|
// @Param page[number] query int false "Page number"
|
|
// @Param page[size] query int false "Page size"
|
|
// @Param page query int false "Page number (fallback)"
|
|
// @Param size query int false "Page size (fallback)"
|
|
// @Param limit query int false "Page size override"
|
|
// @Success 200 {object} responsedto.FlightListResponse
|
|
// @Failure 400 {object} jsonapi.ErrorDocument
|
|
// @Router /api/v1/flights/get-all [get]
|
|
func (h *FlightHandler) List(c *fiber.Ctx) error {
|
|
filter := c.Query("filter[search]")
|
|
if filter == "" {
|
|
filter = c.Query("search")
|
|
}
|
|
dateFilter := strings.TrimSpace(c.Query("filter[date]"))
|
|
if dateFilter == "" {
|
|
dateFilter = strings.TrimSpace(c.Query("date"))
|
|
}
|
|
if dateFilter != "" {
|
|
if _, err := time.Parse("2006-01-02", dateFilter); err != nil {
|
|
return writeFlightErrors(c, fiber.StatusUnprocessableEntity, []jsonapi.ErrorObject{{
|
|
Status: "422",
|
|
Title: "Validation error",
|
|
Detail: "date must be YYYY-MM-DD",
|
|
Source: &jsonapi.ErrorSource{Pointer: "/date"},
|
|
}})
|
|
}
|
|
}
|
|
|
|
pageNumber := parseIntDefault(c.Query("page[number]"), 0)
|
|
if pageNumber <= 0 {
|
|
pageNumber = parseIntDefault(c.Query("page"), 1)
|
|
}
|
|
pageSize := parseIntDefault(c.Query("page[size]"), 0)
|
|
if pageSize <= 0 {
|
|
pageSize = parseIntDefault(c.Query("limit"), 0)
|
|
}
|
|
if pageSize <= 0 {
|
|
pageSize = parseIntDefault(c.Query("size"), 20)
|
|
}
|
|
if pageSize > 100 {
|
|
pageSize = 100
|
|
}
|
|
if pageSize < 1 {
|
|
pageSize = 20
|
|
}
|
|
if pageNumber < 1 {
|
|
pageNumber = 1
|
|
}
|
|
|
|
offset := (pageNumber - 1) * pageSize
|
|
_ = offset
|
|
sort := c.Query("sort")
|
|
rows, total, err := h.listFlightsForCurrentUser(c, filter, dateFilter, sort, 0, 0)
|
|
if err != nil {
|
|
return writeFlightErrors(c, fiber.StatusBadRequest, []jsonapi.ErrorObject{{
|
|
Status: "400",
|
|
Title: "List failed",
|
|
Detail: safeInternalDetail(),
|
|
}})
|
|
}
|
|
|
|
data := make([]responsedto.FlightResource, 0, len(rows))
|
|
for i := range rows {
|
|
data = append(data, h.flightResource(c.UserContext(), c, &rows[i]))
|
|
}
|
|
return response.WriteWithMeta(c, fiber.StatusOK, data, map[string]any{
|
|
"total": total,
|
|
})
|
|
}
|
|
|
|
func (h *FlightHandler) listFlightsForCurrentUser(c *fiber.Ctx, filter, date, sort string, limit, offset int) ([]flight.Flight, int64, error) {
|
|
if h == nil || h.svc == nil {
|
|
return nil, 0, errors.New("flight service not configured")
|
|
}
|
|
if h.auth == nil {
|
|
return h.svc.List(c.UserContext(), filter, date, sort, limit, offset)
|
|
}
|
|
userID := appctx.GetUserID(c.UserContext())
|
|
if len(userID) == 0 {
|
|
return nil, 0, errors.New("missing auth context")
|
|
}
|
|
user, err := h.auth.GetUserByID(c.UserContext(), userID)
|
|
if err != nil {
|
|
return nil, 0, err
|
|
}
|
|
if user == nil {
|
|
return nil, 0, errors.New("user not found")
|
|
}
|
|
if flightUserHasRole(user, "admin") {
|
|
return h.svc.List(c.UserContext(), filter, date, sort, limit, offset)
|
|
}
|
|
return h.svc.ListByCreatedBy(c.UserContext(), userID, filter, date, sort, limit, offset)
|
|
}
|
|
|
|
func flightUserHasRole(user *authdomain.User, roleName string) bool {
|
|
if user == nil {
|
|
return false
|
|
}
|
|
for i := range user.Roles {
|
|
if strings.EqualFold(strings.TrimSpace(user.Roles[i].Name), roleName) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func (h *FlightHandler) flightResource(ctx context.Context, c *fiber.Ctx, row *flight.Flight) responsedto.FlightResource {
|
|
missionStep := flightMissionStep(row)
|
|
takeoverStep := flightTakeoverStep(c.Context(), row, h.takeover)
|
|
afterFlightInspectionStep := h.flightAfterFlightInspectionStep(ctx, row)
|
|
fmReportStep := h.flightFMReportStep(ctx, row)
|
|
var takeover *responsedto.FlightTakeoverSummary
|
|
var draft []responsedto.FlightDraftGroup
|
|
totalDraft := 0
|
|
if row != nil && len(row.TakeoverAcID) == 16 {
|
|
takeover = flightTakeoverSummary(ctx, h.reserveAc, row)
|
|
if takeover == nil {
|
|
takeover = &responsedto.FlightTakeoverSummary{}
|
|
}
|
|
takeover.ID = idString(row.TakeoverAcID)
|
|
takeover.Helicopter = h.helicopterSummaryFromTakeover(ctx, row)
|
|
takeover.RosterDetail = h.takeoverRosterDetailSummary(ctx, row)
|
|
}
|
|
missionID := ""
|
|
if h != nil && h.mission != nil && row != nil && len(row.ID) == 16 {
|
|
rows, err := h.mission.ListByFlightID(ctx, row.ID)
|
|
if err == nil && len(rows) > 0 {
|
|
missionID = idString(rows[0].ID)
|
|
grouped := make(map[string][]responsedto.FlightDraftItem)
|
|
summaries := make(map[string]responsedto.FlightMissionTypeSummary)
|
|
missionComplete := true
|
|
var completedAt time.Time
|
|
var completedBy []byte
|
|
for i := range rows {
|
|
rowComplete := h.missionFlightDataComplete(ctx, rows[i].ID)
|
|
if !rowComplete {
|
|
missionComplete = false
|
|
}
|
|
if rowComplete && rows[i].UpdatedAt.After(completedAt) {
|
|
completedAt = rows[i].UpdatedAt
|
|
completedBy = rows[i].UpdatedBy
|
|
}
|
|
missionType := strings.ToUpper(strings.TrimSpace(rows[i].Type))
|
|
status := mission.StatusDraft
|
|
if rowComplete {
|
|
status = mission.StatusCompleted
|
|
}
|
|
grouped[missionType] = append(grouped[missionType], responsedto.FlightDraftItem{
|
|
ID: idString(rows[i].ID),
|
|
Type: missionType,
|
|
Status: status,
|
|
FlightDataID: idString(rows[i].FlightDataID),
|
|
})
|
|
sum := summaries[missionType]
|
|
sum.Type = missionType
|
|
sum.Draft++
|
|
if status == mission.StatusCompleted {
|
|
sum.Completed++
|
|
}
|
|
summaries[missionType] = sum
|
|
}
|
|
for _, missionType := range []string{sharedconst.MissionTypeHEMS, sharedconst.MissionTypeCAT, sharedconst.MissionTypeSPO, sharedconst.MissionTypeNCO} {
|
|
items := grouped[missionType]
|
|
if len(items) == 0 {
|
|
continue
|
|
}
|
|
draft = append(draft, responsedto.FlightDraftGroup{
|
|
Type: missionType,
|
|
Items: items,
|
|
})
|
|
totalDraft += len(items)
|
|
}
|
|
missionStep.ID = missionID
|
|
missionStep.Status = "in_progress"
|
|
if missionComplete {
|
|
missionStep.Status = "completed"
|
|
}
|
|
missionStep.Complete = missionComplete
|
|
if missionComplete && !completedAt.IsZero() {
|
|
missionStep.CompletedAt = completedAt.UTC().Format(time.RFC3339)
|
|
missionStep.CompletedBy = userctx.GetDisplayName(ctx, completedBy)
|
|
}
|
|
missionStep.MissionType = make([]responsedto.FlightMissionTypeSummary, 0, len(draft))
|
|
for _, missionType := range []string{sharedconst.MissionTypeHEMS, sharedconst.MissionTypeCAT, sharedconst.MissionTypeSPO, sharedconst.MissionTypeNCO} {
|
|
if sum, ok := summaries[missionType]; ok {
|
|
missionStep.MissionType = append(missionStep.MissionType, sum)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
steps := []responsedto.FlightStepItem{missionStep}
|
|
if row != nil && len(row.TakeoverAcID) == 16 {
|
|
steps = []responsedto.FlightStepItem{takeoverStep, missionStep}
|
|
if afterFlightInspectionStep.Phase != "" {
|
|
steps = append(steps, afterFlightInspectionStep)
|
|
}
|
|
if fmReportStep.Phase != "" {
|
|
steps = append(steps, fmReportStep)
|
|
}
|
|
}
|
|
|
|
updatedAt, updatedBy := updatedAuditOrCreated(row.UpdatedAt, row.CreatedAt, row.UpdatedBy, row.UpdatedByName, row.CreatedBy, row.CreatedByName)
|
|
return responsedto.FlightResource{
|
|
Type: "flight",
|
|
ID: idString(row.ID),
|
|
Attributes: responsedto.FlightAttributes{
|
|
MissionID: missionID,
|
|
Code: stringPtrOrEmpty(row.MissionCode),
|
|
Date: row.Date.UTC().Format("2006-01-02"),
|
|
TotalDraft: totalDraft,
|
|
Takeover: takeover,
|
|
Steps: steps,
|
|
Draft: draft,
|
|
CreatedAt: row.CreatedAt.UTC().Format(time.RFC3339),
|
|
CreatedBy: userRef(row.CreatedBy, row.CreatedByName),
|
|
UpdatedAt: updatedAt,
|
|
UpdatedBy: updatedBy,
|
|
DeletedAt: timeStringOrEmpty(row.DeletedAt),
|
|
DeletedBy: userRef(row.DeletedBy, ""),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (h *FlightHandler) flightResourceForList(ctx context.Context, c *fiber.Ctx, row *flight.Flight, missions []mission.Mission, dailyInspectionCache map[string]*responsedto.FlightDailyInspectionSummary, afterFlightCache map[string]responsedto.FlightStepItem, fmReportCache map[string]responsedto.FlightStepItem) responsedto.FlightResource {
|
|
missionStep := flightMissionStep(row)
|
|
takeoverStep := flightTakeoverStep(c.Context(), row, nil)
|
|
afterFlightInspectionStep := h.flightAfterFlightInspectionStepCached(ctx, row, afterFlightCache)
|
|
fmReportStep := h.flightFMReportStepCached(ctx, row, fmReportCache)
|
|
var takeover *responsedto.FlightTakeoverSummary
|
|
var draft []responsedto.FlightDraftGroup
|
|
totalDraft := 0
|
|
if row != nil && len(row.TakeoverAcID) == 16 {
|
|
takeover = flightTakeoverSummaryForList(ctx, h.reserveAc, row, dailyInspectionCache)
|
|
if takeover == nil {
|
|
takeover = &responsedto.FlightTakeoverSummary{}
|
|
}
|
|
takeover.ID = idString(row.TakeoverAcID)
|
|
takeover.Helicopter = h.helicopterSummaryFromTakeoverForList(ctx, row)
|
|
takeover.RosterDetail = h.takeoverRosterDetailSummary(ctx, row)
|
|
}
|
|
missionID := ""
|
|
if len(missions) > 0 {
|
|
missionID = idString(missions[0].ID)
|
|
grouped := make(map[string][]responsedto.FlightDraftItem)
|
|
summaries := make(map[string]responsedto.FlightMissionTypeSummary)
|
|
missionComplete := true
|
|
var completedAt time.Time
|
|
var completedBy []byte
|
|
for i := range missions {
|
|
rowComplete := strings.EqualFold(strings.TrimSpace(missions[i].FlightDataStatus), flightdata.StatusCompleted)
|
|
if !rowComplete {
|
|
missionComplete = false
|
|
}
|
|
if rowComplete && missions[i].UpdatedAt.After(completedAt) {
|
|
completedAt = missions[i].UpdatedAt
|
|
completedBy = missions[i].UpdatedBy
|
|
}
|
|
missionType := strings.ToUpper(strings.TrimSpace(missions[i].Type))
|
|
status := mission.StatusDraft
|
|
if rowComplete {
|
|
status = mission.StatusCompleted
|
|
}
|
|
grouped[missionType] = append(grouped[missionType], responsedto.FlightDraftItem{
|
|
ID: idString(missions[i].ID),
|
|
Type: missionType,
|
|
Status: status,
|
|
FlightDataID: idString(missions[i].FlightDataID),
|
|
})
|
|
sum := summaries[missionType]
|
|
sum.Type = missionType
|
|
sum.Draft++
|
|
if status == mission.StatusCompleted {
|
|
sum.Completed++
|
|
}
|
|
summaries[missionType] = sum
|
|
}
|
|
for _, missionType := range []string{sharedconst.MissionTypeHEMS, sharedconst.MissionTypeCAT, sharedconst.MissionTypeSPO, sharedconst.MissionTypeNCO} {
|
|
items := grouped[missionType]
|
|
if len(items) == 0 {
|
|
continue
|
|
}
|
|
draft = append(draft, responsedto.FlightDraftGroup{
|
|
Type: missionType,
|
|
Items: items,
|
|
})
|
|
totalDraft += len(items)
|
|
}
|
|
missionStep.ID = missionID
|
|
missionStep.Status = "in_progress"
|
|
if missionComplete {
|
|
missionStep.Status = "completed"
|
|
}
|
|
missionStep.Complete = missionComplete
|
|
if missionComplete && !completedAt.IsZero() {
|
|
missionStep.CompletedAt = completedAt.UTC().Format(time.RFC3339)
|
|
missionStep.CompletedBy = userctx.GetDisplayName(ctx, completedBy)
|
|
}
|
|
missionStep.MissionType = make([]responsedto.FlightMissionTypeSummary, 0, len(draft))
|
|
for _, missionType := range []string{sharedconst.MissionTypeHEMS, sharedconst.MissionTypeCAT, sharedconst.MissionTypeSPO, sharedconst.MissionTypeNCO} {
|
|
if sum, ok := summaries[missionType]; ok {
|
|
missionStep.MissionType = append(missionStep.MissionType, sum)
|
|
}
|
|
}
|
|
}
|
|
steps := []responsedto.FlightStepItem{missionStep}
|
|
if row != nil && len(row.TakeoverAcID) == 16 {
|
|
steps = []responsedto.FlightStepItem{takeoverStep, missionStep}
|
|
if afterFlightInspectionStep.Phase != "" {
|
|
steps = append(steps, afterFlightInspectionStep)
|
|
}
|
|
if fmReportStep.Phase != "" {
|
|
steps = append(steps, fmReportStep)
|
|
}
|
|
}
|
|
|
|
updatedAt, updatedBy := updatedAuditOrCreated(row.UpdatedAt, row.CreatedAt, row.UpdatedBy, row.UpdatedByName, row.CreatedBy, row.CreatedByName)
|
|
return responsedto.FlightResource{
|
|
Type: "flight",
|
|
ID: idString(row.ID),
|
|
Attributes: responsedto.FlightAttributes{
|
|
MissionID: missionID,
|
|
Code: stringPtrOrEmpty(row.MissionCode),
|
|
Date: row.Date.UTC().Format("2006-01-02"),
|
|
TotalDraft: totalDraft,
|
|
Takeover: takeover,
|
|
Steps: steps,
|
|
Draft: draft,
|
|
CreatedAt: row.CreatedAt.UTC().Format(time.RFC3339),
|
|
CreatedBy: userRef(row.CreatedBy, row.CreatedByName),
|
|
UpdatedAt: updatedAt,
|
|
UpdatedBy: updatedBy,
|
|
DeletedAt: timeStringOrEmpty(row.DeletedAt),
|
|
DeletedBy: userRef(row.DeletedBy, ""),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (h *FlightHandler) prefetchMissionsByFlightID(ctx context.Context, rows []flight.Flight) (map[string][]mission.Mission, error) {
|
|
if h == nil || h.mission == nil || len(rows) == 0 {
|
|
return map[string][]mission.Mission{}, nil
|
|
}
|
|
flightIDs := make([][]byte, 0, len(rows))
|
|
for i := range rows {
|
|
if len(rows[i].ID) == 16 {
|
|
flightIDs = append(flightIDs, rows[i].ID)
|
|
}
|
|
}
|
|
if len(flightIDs) == 0 {
|
|
return map[string][]mission.Mission{}, nil
|
|
}
|
|
missions, err := h.mission.ListByFlightIDs(ctx, flightIDs)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
grouped := make(map[string][]mission.Mission, len(flightIDs))
|
|
for i := range missions {
|
|
key := string(missions[i].FlightID)
|
|
grouped[key] = append(grouped[key], missions[i])
|
|
}
|
|
return grouped, nil
|
|
}
|
|
|
|
func (h *FlightHandler) flightAfterFlightInspectionStepCached(ctx context.Context, row *flight.Flight, cache map[string]responsedto.FlightStepItem) responsedto.FlightStepItem {
|
|
if row == nil || row.Takeover == nil || row.Takeover.ReserveAc == nil || row.Takeover.ReserveAc.Inspection == nil || len(row.Takeover.ReserveAc.Inspection.ID) != 16 {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
inspectionID := string(row.Takeover.ReserveAc.Inspection.ID)
|
|
if cache != nil {
|
|
if step, ok := cache[inspectionID]; ok {
|
|
return step
|
|
}
|
|
}
|
|
step := h.flightAfterFlightInspectionStep(ctx, row)
|
|
if cache != nil {
|
|
cache[inspectionID] = step
|
|
}
|
|
return step
|
|
}
|
|
|
|
func (h *FlightHandler) flightFMReportStepCached(ctx context.Context, row *flight.Flight, cache map[string]responsedto.FlightStepItem) responsedto.FlightStepItem {
|
|
if row == nil || row.Takeover == nil || len(row.ID) != 16 {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
flightID := string(row.ID)
|
|
if cache != nil {
|
|
if step, ok := cache[flightID]; ok {
|
|
return step
|
|
}
|
|
}
|
|
step := h.flightFMReportStep(ctx, row)
|
|
if cache != nil {
|
|
cache[flightID] = step
|
|
}
|
|
return step
|
|
}
|
|
|
|
func flightTakeoverSummaryForList(ctx context.Context, reserveAcSvc reserveac.ReserveAcService, row *flight.Flight, cache map[string]*responsedto.FlightDailyInspectionSummary) *responsedto.FlightTakeoverSummary {
|
|
if row == nil || row.Takeover == nil {
|
|
return nil
|
|
}
|
|
reserveRow := row.Takeover.ReserveAc
|
|
if reserveRow == nil || len(reserveRow.AircraftID) == 0 {
|
|
if reserveAcSvc == nil || len(row.Takeover.ReserveAcID) != 16 {
|
|
return nil
|
|
}
|
|
var err error
|
|
reserveRow, err = reserveAcSvc.GetByID(ctx, row.Takeover.ReserveAcID)
|
|
if err != nil || reserveRow == nil || len(reserveRow.AircraftID) == 0 {
|
|
return nil
|
|
}
|
|
}
|
|
out := &responsedto.FlightTakeoverSummary{}
|
|
heliID := string(reserveRow.AircraftID)
|
|
if cache != nil {
|
|
if daily, ok := cache[heliID]; ok {
|
|
out.DailyInspection = daily
|
|
}
|
|
}
|
|
if out.DailyInspection == nil && reserveAcSvc != nil {
|
|
lastDaily, _ := reserveAcSvc.GetLastDailyInspectionByHelicopterID(ctx, reserveRow.AircraftID)
|
|
if lastDaily != nil {
|
|
out.DailyInspection = &responsedto.FlightDailyInspectionSummary{
|
|
ID: idString(lastDaily.ID),
|
|
Name: strings.TrimSpace(lastDaily.Name),
|
|
ShortName: strings.TrimSpace(lastDaily.ShortName),
|
|
Date: lastDaily.At.UTC().Format("02.01.2006"),
|
|
UTCTime: lastDaily.At.UTC().Format("15:04"),
|
|
}
|
|
if cache != nil {
|
|
cache[heliID] = out.DailyInspection
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (h *FlightHandler) helicopterSummaryFromTakeoverForList(ctx context.Context, row *flight.Flight) *responsedto.FlightHelicopterSummary {
|
|
if row == nil || row.Takeover == nil || row.Takeover.ReserveAc == nil {
|
|
return h.helicopterSummaryFromTakeover(ctx, row)
|
|
}
|
|
reserveRow := row.Takeover.ReserveAc
|
|
if reserveRow.Aircraft == nil {
|
|
return h.helicopterSummaryFromTakeover(ctx, row)
|
|
}
|
|
heliRow := reserveRow.Aircraft
|
|
return &responsedto.FlightHelicopterSummary{
|
|
AOG: heliRow.AirOnGround,
|
|
Designation: strings.TrimSpace(heliRow.Designation),
|
|
ID: idString(heliRow.ID),
|
|
Identifier: strings.TrimSpace(heliRow.Identifier),
|
|
IsActive: heliRow.IsActive,
|
|
Type: strings.TrimSpace(heliRow.Type),
|
|
}
|
|
}
|
|
|
|
func (h *FlightHandler) missionFlightDataComplete(ctx context.Context, missionID []byte) bool {
|
|
if h == nil || h.flightData == nil || len(missionID) != 16 {
|
|
return false
|
|
}
|
|
fd, err := h.flightData.GetByMissionID(ctx, missionID)
|
|
if err != nil || fd == nil {
|
|
return false
|
|
}
|
|
return flightdata.IsComplete(fd)
|
|
}
|
|
|
|
func (h *FlightHandler) flightMutationResource(ctx context.Context, row *flight.Flight) responsedto.FlightResource {
|
|
if row == nil {
|
|
return responsedto.FlightResource{}
|
|
}
|
|
takeover := &responsedto.FlightTakeoverSummary{
|
|
ID: idString(row.TakeoverAcID),
|
|
}
|
|
missionID := h.flightMissionID(ctx, row)
|
|
updatedAt, updatedBy := updatedAuditOrCreated(row.UpdatedAt, row.CreatedAt, row.UpdatedBy, row.UpdatedByName, row.CreatedBy, row.CreatedByName)
|
|
return responsedto.FlightResource{
|
|
Type: "flight",
|
|
ID: idString(row.ID),
|
|
Attributes: responsedto.FlightAttributes{
|
|
MissionID: missionID,
|
|
Code: stringPtrOrEmpty(row.MissionCode),
|
|
Date: row.Date.UTC().Format("2006-01-02"),
|
|
TotalDraft: 0,
|
|
Takeover: takeover,
|
|
Steps: nil,
|
|
Draft: nil,
|
|
CreatedAt: row.CreatedAt.UTC().Format(time.RFC3339),
|
|
CreatedBy: userRef(row.CreatedBy, row.CreatedByName),
|
|
UpdatedAt: updatedAt,
|
|
UpdatedBy: updatedBy,
|
|
DeletedAt: timeStringOrEmpty(row.DeletedAt),
|
|
DeletedBy: userRef(row.DeletedBy, ""),
|
|
},
|
|
}
|
|
}
|
|
|
|
func (h *FlightHandler) flightMissionID(ctx context.Context, row *flight.Flight) string {
|
|
if h == nil || h.mission == nil || row == nil || len(row.ID) != 16 {
|
|
return ""
|
|
}
|
|
rows, err := h.mission.ListByFlightID(ctx, row.ID)
|
|
if err != nil || len(rows) == 0 {
|
|
return ""
|
|
}
|
|
return idString(rows[0].ID)
|
|
}
|
|
|
|
func flightMissionStep(row *flight.Flight) responsedto.FlightStepItem {
|
|
if row == nil {
|
|
return responsedto.FlightStepItem{Phase: "mission", Step: 2, Status: "unassigned"}
|
|
}
|
|
return responsedto.FlightStepItem{Phase: "mission", Step: 2, Status: "unassigned"}
|
|
}
|
|
|
|
func (h *FlightHandler) flightAfterFlightInspectionStep(ctx context.Context, row *flight.Flight) responsedto.FlightStepItem {
|
|
if row == nil || row.Takeover == nil || row.Takeover.ReserveAc == nil || row.Takeover.ReserveAc.Inspection == nil || len(row.Takeover.ReserveAc.Inspection.ID) != 16 {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
|
|
inspectionID := row.Takeover.ReserveAc.Inspection.ID
|
|
if h == nil || h.afterFlightInspection == nil {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
|
|
afterRow, err := h.afterFlightInspection.GetByFlightInspectionID(ctx, inspectionID)
|
|
if err != nil || afterRow == nil {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
|
|
return responsedto.FlightStepItem{
|
|
Phase: "after_flight_inspection",
|
|
Step: 3,
|
|
ID: idString(afterRow.ID),
|
|
Status: "completed",
|
|
Complete: true,
|
|
CompletedAt: timeStringOrEmptyRefTime(&afterRow.UpdatedAt),
|
|
CompletedBy: uuidStringOrEmpty(afterRow.UpdatedBy),
|
|
}
|
|
}
|
|
|
|
func (h *FlightHandler) flightFMReportStep(ctx context.Context, row *flight.Flight) responsedto.FlightStepItem {
|
|
if row == nil || row.Takeover == nil || h == nil || h.fmReport == nil || len(row.ID) != 16 {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
|
|
reportRow, err := h.fmReport.GetByFlightID(ctx, row.ID)
|
|
if err != nil || reportRow == nil {
|
|
return responsedto.FlightStepItem{}
|
|
}
|
|
|
|
step := responsedto.FlightStepItem{
|
|
Phase: "fm_report",
|
|
Step: 4,
|
|
ID: idString(reportRow.ID),
|
|
Status: "in_progress",
|
|
}
|
|
if reportRow.CompletedAt != nil {
|
|
step.Status = "completed"
|
|
step.Complete = true
|
|
step.CompletedAt = timeStringOrEmpty(reportRow.CompletedAt)
|
|
step.CompletedBy = uuidStringOrEmpty(reportRow.CompletedBy)
|
|
}
|
|
return step
|
|
}
|
|
|
|
// ResolveHelicopterIDByTakeover resolves the flown aircraft's helicopter id from
|
|
// a takeover id via takeover -> reserve_ac -> aircraft. Returns nil when it
|
|
// cannot be resolved.
|
|
func (h *FlightHandler) ResolveHelicopterIDByTakeover(ctx context.Context, takeoverID []byte) []byte {
|
|
if h == nil || h.takeover == nil || h.reserveAc == nil || len(takeoverID) != 16 {
|
|
return nil
|
|
}
|
|
takeoverRow, err := h.takeover.GetByID(ctx, takeoverID)
|
|
if err != nil || takeoverRow == nil || len(takeoverRow.ReserveAcID) != 16 {
|
|
return nil
|
|
}
|
|
reserveRow, err := h.reserveAc.GetByID(ctx, takeoverRow.ReserveAcID)
|
|
if err != nil || reserveRow == nil || len(reserveRow.AircraftID) != 16 {
|
|
return nil
|
|
}
|
|
return reserveRow.AircraftID
|
|
}
|
|
|
|
func (h *FlightHandler) ResolveHelicopterForReportCode(ctx context.Context, takeoverID []byte) ([]byte, string) {
|
|
helicopterID := h.ResolveHelicopterIDByTakeover(ctx, takeoverID)
|
|
if len(helicopterID) != 16 || h.helicopter == nil {
|
|
return nil, ""
|
|
}
|
|
heliRow, err := h.helicopter.GetByID(ctx, helicopterID)
|
|
if err != nil || heliRow == nil {
|
|
return helicopterID, ""
|
|
}
|
|
return helicopterID, strings.TrimSpace(heliRow.Identifier)
|
|
}
|
|
|
|
func (h *FlightHandler) helicopterSummaryFromTakeover(ctx context.Context, row *flight.Flight) *responsedto.FlightHelicopterSummary {
|
|
if row == nil || row.Takeover == nil || h == nil || h.helicopter == nil || h.reserveAc == nil {
|
|
return nil
|
|
}
|
|
reserveID := row.Takeover.ReserveAcID
|
|
if len(reserveID) != 16 {
|
|
return nil
|
|
}
|
|
reserveRow, err := h.reserveAc.GetByID(ctx, reserveID)
|
|
if err != nil || reserveRow == nil || len(reserveRow.AircraftID) != 16 {
|
|
return nil
|
|
}
|
|
heliRow, err := h.helicopter.GetByID(ctx, reserveRow.AircraftID)
|
|
if err != nil || heliRow == nil {
|
|
return nil
|
|
}
|
|
return &responsedto.FlightHelicopterSummary{
|
|
AOG: heliRow.AirOnGround,
|
|
Designation: strings.TrimSpace(heliRow.Designation),
|
|
ID: idString(heliRow.ID),
|
|
Identifier: strings.TrimSpace(heliRow.Identifier),
|
|
IsActive: heliRow.IsActive,
|
|
Type: strings.TrimSpace(heliRow.Type),
|
|
}
|
|
}
|
|
|
|
func stringOrFallback(name string, id []byte) string {
|
|
if trimmed := strings.TrimSpace(name); trimmed != "" {
|
|
return trimmed
|
|
}
|
|
return uuidStringOrEmpty(id)
|
|
}
|
|
|
|
func flightTakeoverSummary(ctx context.Context, reserveAcSvc reserveac.ReserveAcService, row *flight.Flight) *responsedto.FlightTakeoverSummary {
|
|
if row == nil || reserveAcSvc == nil {
|
|
return nil
|
|
}
|
|
var reserveID []byte
|
|
if row.Takeover != nil && len(row.Takeover.ReserveAcID) == 16 {
|
|
reserveID = row.Takeover.ReserveAcID
|
|
}
|
|
if len(reserveID) != 16 {
|
|
return nil
|
|
}
|
|
reserveRow, err := reserveAcSvc.GetByID(ctx, reserveID)
|
|
if err != nil || reserveRow == nil || len(reserveRow.AircraftID) == 0 {
|
|
return nil
|
|
}
|
|
out := &responsedto.FlightTakeoverSummary{}
|
|
lastDaily, _ := reserveAcSvc.GetLastDailyInspectionByHelicopterID(ctx, reserveRow.AircraftID)
|
|
if lastDaily != nil {
|
|
out.DailyInspection = &responsedto.FlightDailyInspectionSummary{
|
|
ID: idString(lastDaily.ID),
|
|
Name: strings.TrimSpace(lastDaily.Name),
|
|
ShortName: strings.TrimSpace(lastDaily.ShortName),
|
|
Date: lastDaily.At.UTC().Format("02.01.2006"),
|
|
UTCTime: lastDaily.At.UTC().Format("15:04"),
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func (h *FlightHandler) takeoverRosterDetailSummary(ctx context.Context, row *flight.Flight) *responsedto.TakeoverDutyRosterDetailsResponse {
|
|
if h == nil || h.takeover == nil || row == nil || len(row.TakeoverAcID) != 16 {
|
|
return nil
|
|
}
|
|
|
|
takeoverRow := row.Takeover
|
|
if takeoverRow == nil || len(takeoverRow.RosterCrews) == 0 && len(takeoverRow.OtherPeople) == 0 {
|
|
loaded, err := h.takeover.GetByID(ctx, row.TakeoverAcID)
|
|
if err != nil || loaded == nil {
|
|
return nil
|
|
}
|
|
takeoverRow = loaded
|
|
}
|
|
if takeoverRow == nil {
|
|
return nil
|
|
}
|
|
|
|
resource := responsedto.DutyRosterResource{
|
|
Attributes: responsedto.DutyRosterAttributes{
|
|
Detail: responsedto.DutyRosterDetailsResponse{
|
|
Pilot: []responsedto.DutyRosterPilotCrew{},
|
|
Doctor: []responsedto.DutyRosterCrew{},
|
|
Rescuer: []responsedto.DutyRosterCrew{},
|
|
Helper: []responsedto.DutyRosterCrew{},
|
|
OtherPerson: []responsedto.DutyRosterCrew{},
|
|
},
|
|
},
|
|
}
|
|
resource = buildDutyRosterResourceFromTakeoverRows(resource, takeoverRow.RosterCrews, row)
|
|
resource = buildDutyRosterResourceFromOtherPeople(resource, takeoverRow.OtherPeople)
|
|
|
|
detail := takeoverDutyRosterDetailsFromRosterDetails(resource.Attributes.Detail)
|
|
return &detail
|
|
}
|
|
|
|
func flightDutyRosterStep(row *flight.Flight) responsedto.FlightStepItem {
|
|
if row == nil || len(row.TakeoverAcID) != 16 {
|
|
return responsedto.FlightStepItem{
|
|
Phase: "duty_roster",
|
|
ID: "",
|
|
Status: "unassigned",
|
|
}
|
|
}
|
|
return responsedto.FlightStepItem{
|
|
Phase: "duty_roster",
|
|
Status: "completed",
|
|
CompletedAt: row.CreatedAt.UTC().Format(time.RFC3339),
|
|
CompletedBy: uuidStringOrEmpty(row.CreatedBy),
|
|
}
|
|
}
|
|
|
|
func flightReserveAcStep(row *flight.Flight) responsedto.FlightStepItem {
|
|
if row == nil {
|
|
return responsedto.FlightStepItem{
|
|
Phase: "reserve_ac",
|
|
ID: "",
|
|
Status: "unassigned",
|
|
}
|
|
}
|
|
var reserveRow *reserveac.ReserveAc
|
|
var reserveID []byte
|
|
if row.Takeover != nil {
|
|
reserveRow = row.Takeover.ReserveAc
|
|
reserveID = row.Takeover.ReserveAcID
|
|
}
|
|
if len(reserveID) != 16 {
|
|
return responsedto.FlightStepItem{
|
|
Phase: "reserve_ac",
|
|
ID: "",
|
|
Status: "unassigned",
|
|
}
|
|
}
|
|
step := responsedto.FlightStepItem{
|
|
Phase: "reserve_ac",
|
|
ID: idString(reserveID),
|
|
Status: "in_progress",
|
|
}
|
|
status := ""
|
|
if reserveRow != nil {
|
|
status = reserveRow.Status
|
|
}
|
|
switch reserveacutil.NormalizeStatus(status) {
|
|
case reserveacutil.StatusApproved:
|
|
step.Status = "completed"
|
|
if reserveRow != nil && !reserveRow.UpdatedAt.IsZero() {
|
|
step.CompletedAt = reserveRow.UpdatedAt.UTC().Format(time.RFC3339)
|
|
}
|
|
if reserveRow != nil {
|
|
step.CompletedBy = uuidStringOrEmpty(reserveRow.UpdatedBy)
|
|
}
|
|
case reserveacutil.StatusOnProgress:
|
|
step.Status = "in_progress"
|
|
case reserveacutil.StatusPending:
|
|
step.Status = "pending"
|
|
default:
|
|
step.Status = "in_progress"
|
|
}
|
|
return step
|
|
}
|
|
|
|
func timeStringOrEmptyRefTime(v *time.Time) string {
|
|
if v == nil || v.IsZero() {
|
|
return ""
|
|
}
|
|
return v.UTC().Format(time.RFC3339)
|
|
}
|
|
|
|
func stringPtrOrEmpty(v *string) string {
|
|
if v == nil {
|
|
return ""
|
|
}
|
|
return strings.TrimSpace(*v)
|
|
}
|
|
|
|
func parseOptionalUUIDFlight(v *string, pointer string) ([]byte, *jsonapi.ErrorObject) {
|
|
if v == nil {
|
|
return nil, nil
|
|
}
|
|
raw := strings.TrimSpace(*v)
|
|
if raw == "" {
|
|
return nil, nil
|
|
}
|
|
id, err := uuidv7.ParseString(raw)
|
|
if err != nil {
|
|
return nil, &jsonapi.ErrorObject{
|
|
Status: "422",
|
|
Title: "Validation error",
|
|
Detail: strings.TrimPrefix(pointer, "/data/attributes/") + " is invalid UUID",
|
|
Source: &jsonapi.ErrorSource{Pointer: pointer},
|
|
}
|
|
}
|
|
return id, nil
|
|
}
|
|
|
|
func writeFlightErrors(c *fiber.Ctx, status int, errs []jsonapi.ErrorObject) error {
|
|
enriched := make([]jsonapi.ErrorObject, 0, len(errs))
|
|
statusStr := strconv.Itoa(status)
|
|
for i := range errs {
|
|
e := errs[i]
|
|
e.Status = statusStr
|
|
if strings.TrimSpace(e.Code) == "" || strings.TrimSpace(e.ErrorCode) == "" {
|
|
code, errorCode := inferFlightErrorCode(status, e.Title, e.Detail)
|
|
if strings.TrimSpace(e.Code) == "" {
|
|
e.Code = code
|
|
}
|
|
if strings.TrimSpace(e.ErrorCode) == "" {
|
|
e.ErrorCode = errorCode
|
|
}
|
|
}
|
|
enriched = append(enriched, e)
|
|
}
|
|
return response.WriteErrors(c, status, enriched)
|
|
}
|
|
|
|
func inferFlightErrorCode(status int, title, detail string) (string, string) {
|
|
lowerTitle := strings.ToLower(strings.TrimSpace(title))
|
|
lowerDetail := strings.ToLower(strings.TrimSpace(detail))
|
|
switch status {
|
|
case fiber.StatusUnauthorized:
|
|
return apperrorsx.CodeFlightUnauthorized, apperrorsx.ErrFlightUnauthorized.ErrorCode
|
|
case fiber.StatusNotFound:
|
|
return apperrorsx.CodeFlightNotFound, apperrorsx.ErrFlightNotFound.ErrorCode
|
|
case fiber.StatusUnprocessableEntity:
|
|
switch {
|
|
case strings.Contains(lowerDetail, "date must be yyyy-mm-dd"):
|
|
return apperrorsx.CodeFlightDateInvalid, apperrorsx.ErrFlightDateInvalid.ErrorCode
|
|
case strings.Contains(lowerDetail, "invalid uuid"):
|
|
return apperrorsx.CodeFlightInvalidUUID, apperrorsx.ErrFlightInvalidUUID.ErrorCode
|
|
default:
|
|
return apperrorsx.CodeFlightValidationFailed, apperrorsx.ErrFlightValidationFailed.ErrorCode
|
|
}
|
|
case fiber.StatusBadRequest:
|
|
switch {
|
|
case strings.Contains(lowerTitle, "invalid json"):
|
|
return apperrorsx.CodeFlightInvalidJSON, apperrorsx.ErrFlightInvalidJSON.ErrorCode
|
|
case strings.Contains(lowerTitle, "create failed"):
|
|
return apperrorsx.CodeFlightCreateFailed, apperrorsx.ErrFlightCreateFailed.ErrorCode
|
|
case strings.Contains(lowerTitle, "get failed"):
|
|
return apperrorsx.CodeFlightGetFailed, apperrorsx.ErrFlightGetFailed.ErrorCode
|
|
case strings.Contains(lowerTitle, "list failed"):
|
|
return apperrorsx.CodeFlightListFailed, apperrorsx.ErrFlightListFailed.ErrorCode
|
|
default:
|
|
return apperrorsx.CodeFlightInvalidPayload, apperrorsx.ErrFlightInvalidPayload.ErrorCode
|
|
}
|
|
default:
|
|
return apperrorsx.CodeInternalServerError, apperrorsx.ErrInternal.ErrorCode
|
|
}
|
|
}
|