104 lines
3.8 KiB
Go
104 lines
3.8 KiB
Go
package useCases
|
|
|
|
import (
|
|
"RenewCMS/internal/domain/article"
|
|
"RenewCMS/internal/domain/audit"
|
|
"RenewCMS/internal/domain/image"
|
|
"RenewCMS/internal/domain/invite"
|
|
"RenewCMS/internal/domain/purge"
|
|
"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.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."},
|
|
}
|
|
|
|
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,
|
|
}
|
|
|
|
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)
|
|
}
|