-
Notifications
You must be signed in to change notification settings - Fork 39
/
page.go
317 lines (282 loc) · 9.56 KB
/
page.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
package notion
import (
"encoding/json"
"errors"
"fmt"
"time"
)
// Page is a resource on the Notion platform. Its parent is either a workspace,
// another page, or a database.
// See: https://developers.notion.com/reference/page
type Page struct {
ID string `json:"id"`
CreatedTime time.Time `json:"created_time"`
CreatedBy *BaseUser `json:"created_by,omitempty"`
LastEditedTime time.Time `json:"last_edited_time"`
LastEditedBy *BaseUser `json:"last_edited_by,omitempty"`
Parent Parent `json:"parent"`
Archived bool `json:"archived"`
URL string `json:"url"`
Icon *Icon `json:"icon,omitempty"`
Cover *Cover `json:"cover,omitempty"`
// Properties differ between parent type.
// See the `UnmarshalJSON` method.
Properties interface{} `json:"properties"`
}
// PageProperties are properties of a page whose parent is a page or a workspace.
type PageProperties struct {
Title PageTitle `json:"title"`
}
type PageTitle struct {
Title []RichText `json:"title"`
}
// DatabasePageProperties are properties of a page whose parent is a database.
type DatabasePageProperties map[string]DatabasePageProperty
type DatabasePageProperty struct {
ID string `json:"id,omitempty"`
Type DatabasePropertyType `json:"type,omitempty"`
Name string `json:"name,omitempty"`
Title []RichText `json:"title,omitempty"`
RichText []RichText `json:"rich_text,omitempty"`
Number *float64 `json:"number,omitempty"`
Select *SelectOptions `json:"select,omitempty"`
MultiSelect []SelectOptions `json:"multi_select,omitempty"`
Date *Date `json:"date,omitempty"`
Formula *FormulaResult `json:"formula,omitempty"`
Relation []Relation `json:"relation,omitempty"`
Rollup *RollupResult `json:"rollup,omitempty"`
People []User `json:"people,omitempty"`
Files []File `json:"files,omitempty"`
Checkbox *bool `json:"checkbox,omitempty"`
URL *string `json:"url,omitempty"`
Email *string `json:"email,omitempty"`
PhoneNumber *string `json:"phone_number,omitempty"`
Status *SelectOptions `json:"status,omitempty"`
CreatedTime *time.Time `json:"created_time,omitempty"`
CreatedBy *User `json:"created_by,omitempty"`
LastEditedTime *time.Time `json:"last_edited_time,omitempty"`
LastEditedBy *User `json:"last_edited_by,omitempty"`
}
// CreatePageParams are the params used for creating a page.
type CreatePageParams struct {
ParentType ParentType
ParentID string
// Either DatabasePageProperties or Title must be not nil.
DatabasePageProperties *DatabasePageProperties
Title []RichText
// Optionally, children blocks are added to the page.
Children []Block
Icon *Icon
Cover *Cover
}
// UpdatePageParams is used for updating a page. At least one field should have
// a non-empty value.
type UpdatePageParams struct {
DatabasePageProperties DatabasePageProperties `json:"properties,omitempty"`
Archived *bool `json:"archived,omitempty"`
Icon *Icon `json:"icon,omitempty"`
Cover *Cover `json:"cover,omitempty"`
}
// PagePropItem is used for a *single* property object value, e.g. for a `rich_text`
// property, a single value of an array of rich text elements.
// This type is used when fetching single properties.
type PagePropItem struct {
Type DatabasePropertyType `json:"type"`
Title RichText `json:"title"`
RichText RichText `json:"rich_text"`
Number float64 `json:"number"`
Select SelectOptions `json:"select"`
MultiSelect SelectOptions `json:"multi_select"`
Date Date `json:"date"`
Formula FormulaResult `json:"formula"`
Relation Relation `json:"relation"`
Rollup RollupResult `json:"rollup"`
People User `json:"people"`
Files File `json:"files"`
Checkbox bool `json:"checkbox"`
URL string `json:"url"`
Email string `json:"email"`
PhoneNumber string `json:"phone_number"`
CreatedTime time.Time `json:"created_time"`
CreatedBy User `json:"created_by"`
LastEditedTime time.Time `json:"last_edited_time"`
LastEditedBy User `json:"last_edited_by"`
}
// PagePropResponse contains a single database page property item or a list
// of items. For rollup props with an aggregation, both a `results` array and a
// `rollup` field (inside `page_property`) is included.
// See: https://developers.notion.com/reference/retrieve-a-page-property#rollup-properties
type PagePropResponse struct {
PagePropItem
Results []PagePropItem `json:"results"`
HasMore bool `json:"has_more"`
NextCursor string `json:"next_cursor"`
PropertyItem PagePropListItem `json:"property_item"`
}
// PagePropListItem describes the property returned in a paginated list
// response (e.g. `type` is `title`, `rich_text`, `relation` or `people`).
// See: https://developers.notion.com/reference/property-item-object#paginated-property-values
type PagePropListItem struct {
ID string `json:"id"`
Type DatabasePropertyType `json:"type"`
NextURL string `json:"next_url"`
Rollup RollupResult `json:"rollup"`
}
// Value returns the underlying database page property value, based on its `type` field.
// When type is unknown/unmapped or doesn't have a value, `nil` is returned.
func (prop DatabasePageProperty) Value() interface{} {
switch prop.Type {
case DBPropTypeTitle:
return prop.Title
case DBPropTypeRichText:
return prop.RichText
case DBPropTypeNumber:
return prop.Number
case DBPropTypeSelect:
return prop.Select
case DBPropTypeMultiSelect:
return prop.MultiSelect
case DBPropTypeDate:
return prop.Date
case DBPropTypePeople:
return prop.People
case DBPropTypeFiles:
return prop.Files
case DBPropTypeCheckbox:
return prop.Checkbox
case DBPropTypeURL:
return prop.URL
case DBPropTypeEmail:
return prop.Email
case DBPropTypePhoneNumber:
return prop.PhoneNumber
case DBPropTypeStatus:
return prop.Status
case DBPropTypeFormula:
return prop.Formula
case DBPropTypeRelation:
return prop.Relation
case DBPropTypeRollup:
return prop.Rollup
case DBPropTypeCreatedTime:
return prop.CreatedTime
case DBPropTypeCreatedBy:
return prop.CreatedBy
case DBPropTypeLastEditedTime:
return prop.LastEditedTime
case DBPropTypeLastEditedBy:
return prop.LastEditedBy
default:
return nil
}
}
func (p CreatePageParams) Validate() error {
if p.ParentType == "" {
return errors.New("parent type is required")
}
if p.ParentID == "" {
return errors.New("parent ID is required")
}
if p.ParentType == ParentTypeDatabase && p.DatabasePageProperties == nil {
return errors.New("database page properties is required when parent type is database")
}
if p.ParentType == ParentTypePage && p.Title == nil {
return errors.New("title is required when parent type is page")
}
if p.Icon != nil {
if err := p.Icon.Validate(); err != nil {
return err
}
}
if p.Cover != nil {
if err := p.Cover.Validate(); err != nil {
return err
}
}
return nil
}
func (p CreatePageParams) MarshalJSON() ([]byte, error) {
type CreatePageParamsDTO struct {
Parent Parent `json:"parent"`
Properties interface{} `json:"properties"`
Children []Block `json:"children,omitempty"`
Icon *Icon `json:"icon,omitempty"`
Cover *Cover `json:"cover,omitempty"`
}
var parent Parent
if p.DatabasePageProperties != nil {
parent.DatabaseID = p.ParentID
} else if p.Title != nil {
parent.PageID = p.ParentID
}
dto := CreatePageParamsDTO{
Parent: parent,
Children: p.Children,
Icon: p.Icon,
Cover: p.Cover,
}
if p.DatabasePageProperties != nil {
dto.Properties = p.DatabasePageProperties
} else if p.Title != nil {
dto.Properties = PageTitle{
Title: p.Title,
}
}
return json.Marshal(dto)
}
// UnmarshalJSON implements json.Unmarshaler.
//
// Pages get a different Properties type based on the parent of the page.
// If parent type is `workspace` or `page_id`, PageProperties is used. Else if
// parent type is `database_id`, DatabasePageProperties is used.
func (p *Page) UnmarshalJSON(b []byte) error {
type (
PageAlias Page
PageDTO struct {
PageAlias
Properties json.RawMessage `json:"properties"`
}
)
var dto PageDTO
err := json.Unmarshal(b, &dto)
if err != nil {
return err
}
page := dto.PageAlias
switch dto.Parent.Type {
case ParentTypeWorkspace:
fallthrough
case ParentTypeBlock:
fallthrough
case ParentTypePage:
var props PageProperties
err := json.Unmarshal(dto.Properties, &props)
if err != nil {
return err
}
page.Properties = props
case ParentTypeDatabase:
var props DatabasePageProperties
err := json.Unmarshal(dto.Properties, &props)
if err != nil {
return err
}
page.Properties = props
default:
return fmt.Errorf("unknown page parent type %q", dto.Parent.Type)
}
*p = Page(page)
return nil
}
func (p UpdatePageParams) Validate() error {
// At least one of the params must be set.
if p.DatabasePageProperties == nil && p.Archived == nil && p.Icon == nil && p.Cover == nil {
return errors.New("at least one of database page properties, archived, icon or cover is required")
}
if p.Icon != nil {
if err := p.Icon.Validate(); err != nil {
return err
}
}
return nil
}