108 lines
2.7 KiB
Go
108 lines
2.7 KiB
Go
package subject
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
"unicode"
|
|
"unicode/utf8"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
const (
|
|
maximumSubjectFieldRunes = 128
|
|
maximumPageSize = 100
|
|
)
|
|
|
|
type Service struct {
|
|
repository *Repository
|
|
}
|
|
|
|
func NewService(repository *Repository) (*Service, error) {
|
|
if repository == nil || repository.db == nil {
|
|
return nil, ErrInvalidInput
|
|
}
|
|
return &Service{repository: repository}, nil
|
|
}
|
|
|
|
func (s *Service) Create(ctx context.Context, input UpsertInput) (Subject, error) {
|
|
if !s.usable(ctx) {
|
|
return Subject{}, ErrInvalidInput
|
|
}
|
|
normalized, err := normalizeInput(input)
|
|
if err != nil {
|
|
return Subject{}, err
|
|
}
|
|
id, err := uuid.NewRandom()
|
|
if err != nil {
|
|
return Subject{}, fmt.Errorf("生成授权对象 UUID v4: %w", err)
|
|
}
|
|
now := time.Now().UTC()
|
|
return s.repository.Create(ctx, Subject{
|
|
ID: id,
|
|
PlatformName: normalized.PlatformName,
|
|
Workspace: normalized.Workspace,
|
|
CreatedAt: now,
|
|
UpdatedAt: now,
|
|
})
|
|
}
|
|
|
|
func (s *Service) Get(ctx context.Context, id uuid.UUID) (Subject, error) {
|
|
if !s.usable(ctx) || id == uuid.Nil {
|
|
return Subject{}, ErrInvalidInput
|
|
}
|
|
return s.repository.Get(ctx, id)
|
|
}
|
|
|
|
func (s *Service) List(ctx context.Context, query string, page, pageSize int) ([]Subject, int64, error) {
|
|
if !s.usable(ctx) || page < 1 || pageSize < 1 || pageSize > maximumPageSize {
|
|
return nil, 0, ErrInvalidInput
|
|
}
|
|
return s.repository.List(ctx, strings.TrimSpace(query), page, pageSize)
|
|
}
|
|
|
|
func (s *Service) Update(ctx context.Context, id uuid.UUID, input UpsertInput) (Subject, error) {
|
|
if !s.usable(ctx) || id == uuid.Nil {
|
|
return Subject{}, ErrInvalidInput
|
|
}
|
|
normalized, err := normalizeInput(input)
|
|
if err != nil {
|
|
return Subject{}, err
|
|
}
|
|
return s.repository.UpdateIfUnsigned(ctx, id, normalized)
|
|
}
|
|
|
|
func (s *Service) Delete(ctx context.Context, id uuid.UUID) error {
|
|
if !s.usable(ctx) || id == uuid.Nil {
|
|
return ErrInvalidInput
|
|
}
|
|
return s.repository.DeleteIfUnsigned(ctx, id)
|
|
}
|
|
|
|
func (s *Service) usable(ctx context.Context) bool {
|
|
return s != nil && s.repository != nil && s.repository.db != nil && ctx != nil
|
|
}
|
|
|
|
func normalizeInput(input UpsertInput) (UpsertInput, error) {
|
|
input.PlatformName = strings.TrimSpace(input.PlatformName)
|
|
input.Workspace = strings.TrimSpace(input.Workspace)
|
|
if !validSubjectField(input.PlatformName) || !validSubjectField(input.Workspace) {
|
|
return UpsertInput{}, ErrInvalidInput
|
|
}
|
|
return input, nil
|
|
}
|
|
|
|
func validSubjectField(value string) bool {
|
|
if value == "" || !utf8.ValidString(value) || utf8.RuneCountInString(value) > maximumSubjectFieldRunes {
|
|
return false
|
|
}
|
|
for _, character := range value {
|
|
if unicode.IsControl(character) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|