/
models.go
159 lines (136 loc) · 3.89 KB
/
models.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
package sakescript
import (
"encoding/json"
"errors"
"fmt"
"time"
)
const defaultStoryType = "story"
// Sentence struct
type Sentence struct {
Ja string `json:"ja"`
En string `json:"en"`
}
// MediaEntry struct
type MediaEntry struct {
Type string `json:"type"`
URI string `json:"uri"`
}
// Chapter struct
type Chapter struct {
Title *Sentence `json:"title,omitempty"`
Sentences []Sentence `json:"sentences"`
MediaEntries map[int]MediaEntry `json:"mediaEntries,omitempty"`
}
// Story struct
type Story struct {
Title Sentence `json:"title"`
Type string `json:"type,omitempty"`
Cover *MediaEntry `json:"cover,omitempty"`
Chapters []Chapter `json:"chapters"`
}
// validateStory checks the required fields and structures of the Story.
func (s *Story) Validate() error {
if s.Title.En == "" || s.Title.Ja == "" {
return fmt.Errorf("story title is incomplete, have en: %s, ja: %s", s.Title.En, s.Title.Ja)
}
storyType := defaultStoryType
if s.Type != "" {
storyType = s.Type
}
if len(s.Chapters) == 0 {
return errors.New("story has no chapters")
}
for _, c := range s.Chapters {
if storyType == "story" && (c.Title == nil || (c.Title.En == "" || c.Title.Ja == "")) {
return errors.New("chapter title is incomplete for story")
}
if len(c.Sentences) == 0 {
return errors.New("chapter has no sentences")
}
for _, s := range c.Sentences {
if s.En == "" || s.Ja == "" {
return fmt.Errorf("sentence is incomplete, have en: %s, ja: %s", s.En, s.Ja)
}
}
}
return nil
}
// ParseStoryJSON takes a JSON string and attempts to parse it into a Story struct.
func (s *Story) FromString(jsonString string) error {
if err := json.Unmarshal([]byte(jsonString), s); err != nil {
return err
}
// Validate the parsed story
if err := s.Validate(); err != nil {
return err
}
return nil
}
// Manifest struct
type Manifest struct {
ID string `json:"id"`
Version string `json:"version"`
Type string `json:"type,omitempty"`
Title Sentence `json:"title"`
TeaserImage string `json:"teaserImage,omitempty"`
Author string `json:"author"`
AuthorTwitter string `json:"authorTwitter,omitempty"`
AuthorNote string `json:"authorNote,omitempty"`
Created string `json:"created"`
Modified string `json:"modified"`
Summary Sentence `json:"summary"`
Tags []string `json:"tags"`
License string `json:"license,omitempty"`
Origin string `json:"origin,omitempty"`
}
// ValidateManifest checks the required fields and structures of the Manifest.
func (m *Manifest) Validate() error {
if m.ID == "" {
return errors.New("manifest ID is missing")
}
if m.Version == "" {
return errors.New("manifest version is missing")
}
if m.Title.En == "" || m.Title.Ja == "" {
return fmt.Errorf("manifest title is incomplete, have en: %s, ja: %s", m.Title.En, m.Title.Ja)
}
if m.Author == "" {
return errors.New("manifest author is missing")
}
storyType := defaultStoryType
if m.Type != "" {
storyType = m.Type
}
m.Created = time.Now().Format(time.RFC3339)
m.Modified = time.Now().Format(time.RFC3339)
if m.Summary.En == "" || m.Summary.Ja == "" {
return errors.New("manifest summary is incomplete")
}
if len(m.Tags) == 0 {
return errors.New("manifest has no tags")
}
if storyType == "article" {
if m.Origin == "" {
return errors.New("article has no origin")
}
}
return nil
}
// FromString unmarshals a JSON string into a Manifest struct and validates it.
func (m *Manifest) FromString(jsonString string) error {
if err := json.Unmarshal([]byte(jsonString), m); err != nil {
return err
}
// Validate the parsed manifest
if err := m.Validate(); err != nil {
return err
}
return nil
}
// IndexEntry struct
type IndexEntry struct {
Path string `json:"path"`
Sha256 string `json:"sha256"`
Manifest Manifest `json:"manifest"`
}