2023-12-20 07:03:03 +00:00
|
|
|
package domain
|
|
|
|
|
|
|
|
import (
|
2024-01-27 08:37:12 +00:00
|
|
|
"encoding/base64"
|
2024-02-01 06:39:38 +00:00
|
|
|
"fmt"
|
2023-12-20 07:03:03 +00:00
|
|
|
"net/url"
|
2024-02-06 06:14:19 +00:00
|
|
|
"strings"
|
2023-12-20 07:03:03 +00:00
|
|
|
)
|
|
|
|
|
2023-12-27 08:07:40 +00:00
|
|
|
const (
|
|
|
|
versionCodeMinLength = 2
|
|
|
|
versionCodeMaxLength = 2
|
|
|
|
)
|
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
type Version struct {
|
|
|
|
code string
|
|
|
|
name string
|
|
|
|
host string
|
|
|
|
timezone string
|
|
|
|
}
|
|
|
|
|
2023-12-28 10:56:59 +00:00
|
|
|
var versionModelName = "Version"
|
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
// UnmarshalVersionFromDatabase unmarshals Version from the database.
|
|
|
|
//
|
|
|
|
// It should be used only for unmarshalling from the database!
|
|
|
|
// You can't use UnmarshalVersionFromDatabase as constructor - It may put domain into the invalid state!
|
|
|
|
func UnmarshalVersionFromDatabase(
|
|
|
|
code string,
|
|
|
|
name string,
|
|
|
|
host string,
|
|
|
|
timezone string,
|
|
|
|
) (Version, error) {
|
|
|
|
if code == "" {
|
2023-12-28 10:56:59 +00:00
|
|
|
return Version{}, ValidationError{
|
|
|
|
Model: versionModelName,
|
|
|
|
Field: "code",
|
|
|
|
Err: ErrRequired,
|
|
|
|
}
|
2023-12-20 07:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if name == "" {
|
2023-12-28 10:56:59 +00:00
|
|
|
return Version{}, ValidationError{
|
|
|
|
Model: versionModelName,
|
|
|
|
Field: "name",
|
|
|
|
Err: ErrRequired,
|
|
|
|
}
|
2023-12-20 07:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if host == "" {
|
2023-12-28 10:56:59 +00:00
|
|
|
return Version{}, ValidationError{
|
|
|
|
Model: versionModelName,
|
|
|
|
Field: "host",
|
|
|
|
Err: ErrRequired,
|
|
|
|
}
|
2023-12-20 07:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if timezone == "" {
|
2023-12-28 10:56:59 +00:00
|
|
|
return Version{}, ValidationError{
|
|
|
|
Model: versionModelName,
|
|
|
|
Field: "timezone",
|
|
|
|
Err: ErrRequired,
|
|
|
|
}
|
2023-12-20 07:03:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Version{
|
|
|
|
code: code,
|
|
|
|
name: name,
|
|
|
|
host: host,
|
|
|
|
timezone: timezone,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v Version) Code() string {
|
|
|
|
return v.code
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v Version) Name() string {
|
|
|
|
return v.name
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v Version) Host() string {
|
|
|
|
return v.host
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v Version) Timezone() string {
|
|
|
|
return v.timezone
|
|
|
|
}
|
|
|
|
|
|
|
|
func (v Version) URL() *url.URL {
|
|
|
|
return &url.URL{
|
|
|
|
Scheme: "https",
|
|
|
|
Host: v.host,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-27 08:37:12 +00:00
|
|
|
func (v Version) IsZero() bool {
|
|
|
|
return v == Version{}
|
|
|
|
}
|
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
type Versions []Version
|
|
|
|
|
|
|
|
type VersionSort uint8
|
|
|
|
|
|
|
|
const (
|
|
|
|
VersionSortCodeASC VersionSort = iota + 1
|
|
|
|
VersionSortCodeDESC
|
|
|
|
)
|
|
|
|
|
2024-01-27 08:37:12 +00:00
|
|
|
type VersionCursor struct {
|
2024-02-06 06:49:01 +00:00
|
|
|
code string
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
|
|
|
|
2024-01-31 07:14:18 +00:00
|
|
|
const versionCursorModelName = "VersionCursor"
|
|
|
|
|
2024-02-06 06:49:01 +00:00
|
|
|
func NewVersionCursor(code string) (VersionCursor, error) {
|
|
|
|
if err := validateVersionCode(code); err != nil {
|
2024-01-31 07:14:18 +00:00
|
|
|
return VersionCursor{}, ValidationError{
|
|
|
|
Model: versionCursorModelName,
|
|
|
|
Field: "code",
|
|
|
|
Err: err,
|
|
|
|
}
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return VersionCursor{
|
|
|
|
code: code,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
const (
|
|
|
|
encodedVersionCursorMinLength = 1
|
2024-01-31 07:14:18 +00:00
|
|
|
encodedVersionCursorMaxLength = 1000
|
2024-01-27 08:37:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func decodeVersionCursor(encoded string) (VersionCursor, error) {
|
|
|
|
if err := validateStringLen(encoded, encodedVersionCursorMinLength, encodedVersionCursorMaxLength); err != nil {
|
|
|
|
return VersionCursor{}, err
|
|
|
|
}
|
|
|
|
|
2024-02-06 06:14:19 +00:00
|
|
|
decodedBytes, err := base64.StdEncoding.DecodeString(encoded)
|
2024-01-27 08:37:12 +00:00
|
|
|
if err != nil {
|
2024-01-31 07:14:18 +00:00
|
|
|
return VersionCursor{}, ErrInvalidCursor
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
2024-02-06 06:14:19 +00:00
|
|
|
decoded := string(decodedBytes)
|
|
|
|
|
|
|
|
code, ok := strings.CutPrefix(decoded, "code=")
|
|
|
|
if !ok {
|
|
|
|
return VersionCursor{}, ErrInvalidCursor
|
|
|
|
}
|
2024-01-27 08:37:12 +00:00
|
|
|
|
2024-02-06 06:49:01 +00:00
|
|
|
vc, err := NewVersionCursor(code)
|
2024-01-31 07:14:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return VersionCursor{}, ErrInvalidCursor
|
|
|
|
}
|
|
|
|
|
|
|
|
return vc, nil
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
|
|
|
|
2024-02-06 06:49:01 +00:00
|
|
|
func (vc VersionCursor) Code() string {
|
2024-01-27 08:37:12 +00:00
|
|
|
return vc.code
|
|
|
|
}
|
|
|
|
|
|
|
|
func (vc VersionCursor) IsZero() bool {
|
2024-02-06 06:49:01 +00:00
|
|
|
return vc == VersionCursor{}
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (vc VersionCursor) Encode() string {
|
|
|
|
if vc.IsZero() {
|
|
|
|
return ""
|
|
|
|
}
|
|
|
|
|
2024-02-06 06:49:01 +00:00
|
|
|
return base64.StdEncoding.EncodeToString([]byte("code=" + vc.code))
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
type ListVersionsParams struct {
|
2024-02-01 06:39:38 +00:00
|
|
|
codes []string
|
2024-01-27 08:37:12 +00:00
|
|
|
sort []VersionSort
|
|
|
|
cursor VersionCursor
|
|
|
|
limit int
|
2023-12-20 07:03:03 +00:00
|
|
|
}
|
|
|
|
|
2024-01-27 08:37:12 +00:00
|
|
|
const (
|
|
|
|
VersionListMaxLimit = 200
|
|
|
|
listVersionsParamsModelName = "ListVersionsParams"
|
|
|
|
)
|
2023-12-27 08:07:40 +00:00
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
func NewListVersionsParams() ListVersionsParams {
|
2024-01-27 08:37:12 +00:00
|
|
|
return ListVersionsParams{
|
|
|
|
sort: []VersionSort{VersionSortCodeASC},
|
|
|
|
limit: VersionListMaxLimit,
|
|
|
|
}
|
2023-12-20 07:03:03 +00:00
|
|
|
}
|
|
|
|
|
2024-02-01 06:39:38 +00:00
|
|
|
func (params *ListVersionsParams) Codes() []string {
|
|
|
|
return params.codes
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *ListVersionsParams) SetCodes(codes []string) error {
|
|
|
|
params.codes = codes
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
const (
|
|
|
|
versionSortMinLength = 1
|
|
|
|
versionSortMaxLength = 1
|
|
|
|
)
|
|
|
|
|
2023-12-24 10:44:20 +00:00
|
|
|
func (params *ListVersionsParams) Sort() []VersionSort {
|
|
|
|
return params.sort
|
|
|
|
}
|
|
|
|
|
2023-12-20 07:03:03 +00:00
|
|
|
func (params *ListVersionsParams) SetSort(sort []VersionSort) error {
|
|
|
|
if err := validateSliceLen(sort, versionSortMinLength, versionSortMaxLength); err != nil {
|
|
|
|
return ValidationError{
|
2023-12-27 08:07:40 +00:00
|
|
|
Model: listVersionsParamsModelName,
|
2023-12-20 07:03:03 +00:00
|
|
|
Field: "sort",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params.sort = sort
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2024-01-27 08:37:12 +00:00
|
|
|
|
|
|
|
func (params *ListVersionsParams) Cursor() VersionCursor {
|
|
|
|
return params.cursor
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *ListVersionsParams) SetCursor(vc VersionCursor) error {
|
|
|
|
params.cursor = vc
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *ListVersionsParams) SetEncodedCursor(encoded string) error {
|
|
|
|
decoded, err := decodeVersionCursor(encoded)
|
|
|
|
if err != nil {
|
|
|
|
return ValidationError{
|
|
|
|
Model: listVersionsParamsModelName,
|
|
|
|
Field: "cursor",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params.cursor = decoded
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *ListVersionsParams) Limit() int {
|
|
|
|
return params.limit
|
|
|
|
}
|
|
|
|
|
|
|
|
func (params *ListVersionsParams) SetLimit(limit int) error {
|
|
|
|
if err := validateIntInRange(limit, 1, VersionListMaxLimit); err != nil {
|
|
|
|
return ValidationError{
|
|
|
|
Model: listVersionsParamsModelName,
|
|
|
|
Field: "limit",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
params.limit = limit
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
type ListVersionsResult struct {
|
|
|
|
versions Versions
|
|
|
|
self VersionCursor
|
|
|
|
next VersionCursor
|
|
|
|
}
|
|
|
|
|
|
|
|
const listVersionsResultModelName = "ListVersionsResult"
|
|
|
|
|
|
|
|
func NewListVersionsResult(versions Versions, next Version) (ListVersionsResult, error) {
|
|
|
|
var err error
|
|
|
|
res := ListVersionsResult{
|
|
|
|
versions: versions,
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(versions) > 0 {
|
2024-02-06 06:49:01 +00:00
|
|
|
res.self, err = NewVersionCursor(versions[0].Code())
|
2024-01-27 08:37:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return ListVersionsResult{}, ValidationError{
|
|
|
|
Model: listVersionsResultModelName,
|
|
|
|
Field: "self",
|
|
|
|
Err: err,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-06 06:49:01 +00:00
|
|
|
if !next.IsZero() {
|
|
|
|
res.next, err = NewVersionCursor(next.Code())
|
|
|
|
if err != nil {
|
|
|
|
return ListVersionsResult{}, ValidationError{
|
|
|
|
Model: listVersionsResultModelName,
|
|
|
|
Field: "next",
|
|
|
|
Err: err,
|
|
|
|
}
|
2024-01-27 08:37:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (res ListVersionsResult) Versions() Versions {
|
|
|
|
return res.versions
|
|
|
|
}
|
|
|
|
|
|
|
|
func (res ListVersionsResult) Self() VersionCursor {
|
|
|
|
return res.self
|
|
|
|
}
|
|
|
|
|
|
|
|
func (res ListVersionsResult) Next() VersionCursor {
|
|
|
|
return res.next
|
|
|
|
}
|
2024-02-01 06:39:38 +00:00
|
|
|
|
|
|
|
type VersionNotFoundError struct {
|
|
|
|
VersionCode string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e VersionNotFoundError) Error() string {
|
|
|
|
return fmt.Sprintf("version with code %s not found", e.VersionCode)
|
|
|
|
}
|
|
|
|
|
2024-02-01 06:48:03 +00:00
|
|
|
func (e VersionNotFoundError) Type() ErrorType {
|
|
|
|
return ErrorTypeNotFound
|
2024-02-01 06:39:38 +00:00
|
|
|
}
|
|
|
|
|
2024-02-01 06:48:03 +00:00
|
|
|
func (e VersionNotFoundError) Code() string {
|
2024-02-01 06:39:38 +00:00
|
|
|
return "version-not-found"
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e VersionNotFoundError) Params() map[string]any {
|
|
|
|
return map[string]any{
|
|
|
|
"Code": e.VersionCode,
|
|
|
|
}
|
|
|
|
}
|