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"` LastEditedTime time.Time `json:"last_edited_time"` Parent PageParent `json:"parent"` Archived bool `json:"archived"` // Properties differ between parent type. // See the `UnmarshalJSON` method. Properties interface{} `json:"properties"` } type PageParent struct { Type string `json:"type"` PageID *string `json:"page_id,omitempty"` DatabaseID *string `json:"database_id,omitempty"` } // 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"` RichText []RichText `json:"rich_text,omitempty"` Number *NumberMetadata `json:"number,omitempty"` Select *SelectOptions `json:"select,omitempty"` MultiSelect []SelectOptions `json:"multi_select,omitempty"` Formula *FormulaMetadata `json:"formula,omitempty"` Relation *RelationMetadata `json:"relation,omitempty"` Rollup *RollupMetadata `json:"rollup,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 } type UpdatePageParams struct { // Either DatabasePageProperties or Title must be not nil. DatabasePageProperties *DatabasePageProperties Title []RichText } type ParentType string const ( ParentTypeDatabase ParentType = "database_id" ParentTypePage ParentType = "page_id" ) 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") } return nil } func (p CreatePageParams) MarshalJSON() ([]byte, error) { type CreatePageParamsDTO struct { Parent PageParent `json:"parent"` Properties interface{} `json:"properties"` Children []Block `json:"children,omitempty"` } var parent PageParent if p.DatabasePageProperties != nil { parent.Type = "database_id" parent.DatabaseID = StringPtr(p.ParentID) } else if p.Title != nil { parent.Type = "page_id" parent.PageID = StringPtr(p.ParentID) } dto := CreatePageParamsDTO{ Parent: parent, Children: p.Children, } 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 "workspace": fallthrough case "page_id": var props PageProperties err := json.Unmarshal(dto.Properties, &props) if err != nil { return err } page.Properties = props case "database_id": 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 { if p.DatabasePageProperties == nil && p.Title == nil { return errors.New("either database page properties or title is required") } return nil } func (p UpdatePageParams) MarshalJSON() ([]byte, error) { type UpdatePageParamsDTO struct { Properties interface{} `json:"properties"` } var dto UpdatePageParamsDTO if p.DatabasePageProperties != nil { dto.Properties = p.DatabasePageProperties } else if p.Title != nil { dto.Properties = PageTitle{ Title: p.Title, } } return json.Marshal(dto) }