package useCases import ( "RenewCMS/internal/domain/article" "RenewCMS/internal/domain/audit" "RenewCMS/internal/domain/author" "RenewCMS/internal/domain/image" "RenewCMS/internal/domain/invite" "RenewCMS/internal/domain/purge" "RenewCMS/internal/domain/site" "RenewCMS/internal/domain/update" "RenewCMS/internal/domain/user" "context" "errors" "slices" ) const GenericFailureReason = "Something went wrong on our side. Please try again." type failureReason struct { cause error reason string } var failureReasons = []failureReason{ {article.ErrInvalidTitle, "The title must be between 3 and 200 characters."}, {image.ErrImageTypeNotAllowed, "The file must be a PNG, JPEG, WEBP or SVG image."}, {image.ErrImageTooLarge, "The file is too large to upload."}, {image.ErrImageUnreadable, "The image could not be read."}, {image.ErrInvalidFilename, "That file name is not valid."}, {image.ErrInvalidMergeRequest, "The merge request is not valid."}, {image.ErrMergeCopyMissing, "One of the copies no longer exists."}, {image.ErrMergeHashMismatch, "The images are not identical copies."}, {image.ErrSourceTooLarge, "The source image is too large to generate this variant."}, {image.ErrVariantSourceUnsupported, "Variants aren't generated for this format."}, {image.ErrVariantSourceUnreadable, "The source image can't be read, so this variant can't be generated."}, {image.ErrVariantExists, "A variant with that name already exists."}, {purge.ErrPurgeConflict, "The library changed since the preview. Review it again."}, {purge.ErrPurgeBusy, "A purge is already running."}, {user.ErrRegistrationClosed, "Registration is closed on this site."}, {user.ErrVerificationEmailNotSent, "The verification email could not be sent."}, {user.ErrInvalidVerificationCode, "The verification code is not valid."}, {user.ErrVerificationCodeExpired, "The verification code has expired."}, {user.ErrInvalidDisplayName, "That display name is too long."}, {user.ErrUsernameTaken, "That username is already taken."}, {invite.ErrEmailHasAccount, "That email already has an account."}, {invite.ErrPendingInvite, "An invitation is already pending for that email."}, {invite.ErrInviteEmailNotSent, "The invitation email could not be sent."}, {invite.ErrInviteAlreadyAccepted, "That invitation was already accepted."}, {invite.ErrInviteInvalid, "That invitation is not valid."}, {invite.ErrInviteExpired, "That invitation has expired."}, {update.ErrFeedUnavailable, "The release feed could not be reached."}, {update.ErrNoRelease, "No release was found."}, {update.ErrNotPrepared, "This server cannot apply updates."}, {update.ErrJobInProgress, "An update is already being downloaded."}, {update.ErrRestartPending, "A restart is already pending."}, {update.ErrNothingToUpdate, "There is nothing to update."}, {update.ErrPreflightRefused, "The update cannot be downloaded."}, {update.ErrRestartKindMismatch, "The requested restart does not match the server state."}, {site.ErrSiteKeyTaken, "A site with that key already exists."}, {site.ErrKeyImmutable, "The key of a site cannot be changed."}, {site.ErrDefaultSite, "The default site cannot be deleted."}, {site.ErrSiteHasArticles, "The site still has articles."}, {site.ErrInvalidSiteURL, "The site address is not valid."}, {site.ErrInvalidLocale, "The locale is not valid."}, {site.ErrUseSetDefault, "Use the default site action to change the default."}, {site.ErrInvalidReassign, "The destination site is not valid."}, {author.ErrSlugTaken, "That slug is already used by another author."}, {author.ErrUserAlreadyLinked, "That user already has an author."}, {author.ErrAuthorAlreadyLinked, "That author is already linked to a user."}, {author.ErrAuthorRights, "Only an owner or admin can change this author."}, {author.ErrAuthorHasArticles, "The author is still credited on articles."}, {author.ErrInvalidReassign, "The destination author is not valid."}, } var restartFailureReasons = []failureReason{ {update.ErrJobInProgress, "An update is still being downloaded."}, } var downloadFailureReasons = map[string]string{ update.ErrorKindDownload: "The update could not be downloaded.", update.ErrorKindVerification: "The downloaded update failed its integrity check.", } var notFoundCauses = []error{ article.ErrArticleNotFound, image.ErrImageNotFound, image.ErrVariantNotFound, invite.ErrInviteNotFound, user.ErrUserNotFound, site.ErrSiteNotFound, author.ErrAuthorNotFound, author.ErrBioTooLong, author.ErrInvalidURL, author.ErrTooManyLinks, author.ErrInvalidSlug, } func reasonFor(err error, overrides ...failureReason) string { for _, candidate := range slices.Concat(overrides, failureReasons) { if errors.Is(err, candidate.cause) { return candidate.reason } } return GenericFailureReason } func isNotFound(err error) bool { for _, cause := range notFoundCauses { if errors.Is(err, cause) { return true } } return false } func recordFailure(ctx context.Context, recorder audit.Recorder, event audit.Event, err error, overrides ...failureReason) { if isNotFound(err) { return } failFrom(ctx, recorder, event, reasonFor(err, overrides...)) } func failFrom(ctx context.Context, recorder audit.Recorder, event audit.Event, reason string) { event.Outcome = audit.OutcomeFailed event.FailureReason = &reason recorder.Record(ctx, event) }