feat(backend): implement task creation and admin web
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
package usecase
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type ErrorKind string
|
||||
|
||||
const (
|
||||
ErrorKindInvalid ErrorKind = "INVALID"
|
||||
ErrorKindNotFound ErrorKind = "NOT_FOUND"
|
||||
ErrorKindConflict ErrorKind = "CONFLICT"
|
||||
ErrorKindUnavailable ErrorKind = "UNAVAILABLE"
|
||||
ErrorKindInternal ErrorKind = "INTERNAL"
|
||||
)
|
||||
|
||||
type Error struct {
|
||||
Kind ErrorKind
|
||||
Code string
|
||||
Message string
|
||||
Retryable bool
|
||||
Fields map[string]string
|
||||
Cause error
|
||||
}
|
||||
|
||||
func (e *Error) Error() string {
|
||||
if e.Message != "" {
|
||||
return e.Message
|
||||
}
|
||||
return "use case failed"
|
||||
}
|
||||
|
||||
func (e *Error) Unwrap() error {
|
||||
return e.Cause
|
||||
}
|
||||
|
||||
func newError(
|
||||
kind ErrorKind,
|
||||
code string,
|
||||
message string,
|
||||
cause error,
|
||||
) *Error {
|
||||
return &Error{
|
||||
Kind: kind,
|
||||
Code: code,
|
||||
Message: message,
|
||||
Cause: cause,
|
||||
Fields: map[string]string{},
|
||||
}
|
||||
}
|
||||
|
||||
func invalidError(code, message string, fields map[string]string) *Error {
|
||||
return &Error{
|
||||
Kind: ErrorKindInvalid,
|
||||
Code: code,
|
||||
Message: message,
|
||||
Fields: fields,
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
ErrRepositoryNotFound = errors.New("repository resource not found")
|
||||
ErrIdempotencyConflict = errors.New("idempotency key payload conflict")
|
||||
ErrSourceReferenceConflict = errors.New("source reference conflict")
|
||||
ErrAssetUnavailable = errors.New("asset is unavailable")
|
||||
ErrTaskStateConflict = errors.New("task state conflict")
|
||||
ErrRepositoryUnavailable = errors.New("repository unavailable")
|
||||
ErrRepositoryInvariant = errors.New("repository invariant failed")
|
||||
)
|
||||
|
||||
func wrapRepositoryError(err error) error {
|
||||
switch {
|
||||
case errors.Is(err, ErrRepositoryNotFound):
|
||||
return newError(
|
||||
ErrorKindNotFound,
|
||||
"RESOURCE_NOT_FOUND",
|
||||
"resource not found",
|
||||
err,
|
||||
)
|
||||
case errors.Is(err, ErrIdempotencyConflict):
|
||||
return newError(
|
||||
ErrorKindConflict,
|
||||
"IDEMPOTENCY_KEY_CONFLICT",
|
||||
"idempotency key was already used for a different request",
|
||||
err,
|
||||
)
|
||||
case errors.Is(err, ErrSourceReferenceConflict):
|
||||
return newError(
|
||||
ErrorKindConflict,
|
||||
"TASK_SOURCE_REF_CONFLICT",
|
||||
"source reference already exists",
|
||||
err,
|
||||
)
|
||||
case errors.Is(err, ErrAssetUnavailable):
|
||||
return newError(
|
||||
ErrorKindConflict,
|
||||
"TASK_ASSET_UNAVAILABLE",
|
||||
"reference image is not available for this task",
|
||||
err,
|
||||
)
|
||||
case errors.Is(err, ErrTaskStateConflict):
|
||||
return newError(
|
||||
ErrorKindConflict,
|
||||
"TASK_STATE_CONFLICT",
|
||||
"task state does not allow this operation",
|
||||
err,
|
||||
)
|
||||
case errors.Is(err, ErrRepositoryUnavailable):
|
||||
result := newError(
|
||||
ErrorKindUnavailable,
|
||||
"STORAGE_UNAVAILABLE",
|
||||
"storage is temporarily unavailable",
|
||||
err,
|
||||
)
|
||||
result.Retryable = true
|
||||
return result
|
||||
default:
|
||||
return newError(
|
||||
ErrorKindInternal,
|
||||
"INTERNAL_ERROR",
|
||||
"internal server error",
|
||||
fmt.Errorf("%w: %v", ErrRepositoryInvariant, err),
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user