Files
perler-beads-server/internal/domain/domain.go
T

127 lines
3.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package domain
import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"regexp"
"strings"
)
type Color struct {
Code string `json:"code"`
Name string `json:"name"`
Hex string `json:"hex"`
Location string `json:"location"`
Available bool `json:"available"`
}
type Pattern struct {
ID string `json:"id"`
Title string `json:"title"`
Category string `json:"category"`
Width int `json:"width"`
Height int `json:"height"`
Cells []*string `json:"cells"`
Colors []Color `json:"colors"`
BeadCount int `json:"beadCount"`
OwnerID string `json:"ownerId,omitempty"`
Visibility string `json:"visibility"`
CreatedAt string `json:"createdAt"`
StoreID string `json:"storeId"`
Demo bool `json:"demo"`
}
type User struct {
ID string `json:"id"`
Name string `json:"name"`
Role string `json:"role"`
StoreID string `json:"storeId"`
}
type Store struct {
ID string `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
Hours string `json:"hours"`
Notice string `json:"notice"`
LocalBaseURL string `json:"localBaseUrl"`
PublicBaseURL string `json:"publicBaseUrl"`
}
type Table struct {
Code string `json:"code"`
Label string `json:"label"`
Enabled bool `json:"enabled"`
}
type Visit struct {
ID string `json:"id"`
StoreID string `json:"storeId"`
TableCode string `json:"tableCode"`
Status string `json:"status"`
}
type Request struct {
ID string `json:"id"`
StoreID string `json:"storeId"`
UserID string `json:"userId"`
TableCode string `json:"tableCode"`
Kind string `json:"kind"`
Note string `json:"note"`
Status string `json:"status"`
PatternID string `json:"patternId,omitempty"`
CreatedAt string `json:"createdAt"`
UpdatedAt string `json:"updatedAt"`
}
var hexColor = regexp.MustCompile(`^#[0-9a-fA-F]{6}$`)
func ValidateColors(cs []Color) error {
seen := map[string]bool{}
if len(cs) == 0 || len(cs) > 512 {
return fmt.Errorf("色板需包含 1–512 色")
}
for _, c := range cs {
if strings.TrimSpace(c.Code) == "" || len(c.Code) > 32 || seen[c.Code] || !hexColor.MatchString(c.Hex) {
return fmt.Errorf("色号重复或颜色格式错误")
}
seen[c.Code] = true
}
return nil
}
func (p *Pattern) Validate() error {
if strings.TrimSpace(p.Title) == "" || len(p.Title) > 200 || p.Width < 1 || p.Height < 1 || p.Width > 200 || p.Height > 200 || len(p.Cells) != p.Width*p.Height {
return fmt.Errorf("图纸名称或尺寸无效(最大 200×200)")
}
if p.Visibility != "public" && p.Visibility != "private" {
return fmt.Errorf("可见性无效")
}
if err := ValidateColors(p.Colors); err != nil {
return err
}
cs := map[string]bool{}
for _, c := range p.Colors {
cs[c.Code] = true
}
p.BeadCount = 0
for _, c := range p.Cells {
if c != nil {
if !cs[*c] {
return fmt.Errorf("网格含未知色号")
}
p.BeadCount++
}
}
return nil
}
func Transition(role, old, next string, own bool) bool {
if role == "admin" || role == "staff" {
return old == "pending" && next == "accepted" || old == "accepted" && next == "completed"
}
return own && old == "pending" && next == "cancelled"
}
func Fingerprint(kind, note, pattern string) string {
b, _ := json.Marshal([]string{kind, note, pattern})
h := sha256.Sum256(b)
return hex.EncodeToString(h[:])
}
func CanRead(p Pattern, u User) bool {
return p.Visibility == "public" || p.OwnerID == u.ID && u.ID != "" || (u.Role == "admin" || u.Role == "staff") && p.StoreID == u.StoreID
}