diff --git a/block.go b/block.go index 50e65d0..984e62b 100644 --- a/block.go +++ b/block.go @@ -219,6 +219,7 @@ type Block interface { GetArchived() bool GetParent() *Parent GetRichTextString() string + GetMeetingNotes() *MeetingNotes } type Blocks []Block @@ -296,6 +297,11 @@ func (b BasicBlock) GetArchived() bool { func (b BasicBlock) GetParent() *Parent { return b.Parent } + +func (b BasicBlock) GetMeetingNotes() *MeetingNotes { + return nil +} + func concatenateRichText(richtext []RichText) string { var result string for _, rt := range richtext { @@ -380,6 +386,10 @@ func (b LinkPreviewBlock) GetRichTextString() string { return b.LinkPreview.URL } +func (b MeetingNotesBlock) GetRichTextString() string { + return concatenateRichText(b.MeetingNotes.Title) +} + func (b EquationBlock) GetRichTextString() string { return b.Equation.Expression } @@ -738,6 +748,40 @@ type SyncedFrom struct { BlockID BlockID `json:"block_id"` } +type MeetingNotesBlock struct { + BasicBlock + MeetingNotes MeetingNotes `json:"meeting_notes"` +} + +func (b *MeetingNotesBlock) GetMeetingNotes() *MeetingNotes { + return &b.MeetingNotes +} + +type MeetingNotes struct { + Title []RichText `json:"title"` + Status string `json:"status"` + Children *MeetingNotesChildren `json:"children,omitempty"` + CalendarEvent *CalendarEvent `json:"calendar_event,omitempty"` + Recording *Recording `json:"recording,omitempty"` +} + +type MeetingNotesChildren struct { + SummaryBlockID BlockID `json:"summary_block_id,omitempty"` + NotesBlockID BlockID `json:"notes_block_id,omitempty"` + TranscriptBlockID BlockID `json:"transcript_block_id,omitempty"` +} + +type CalendarEvent struct { + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` + Attendees []string `json:"attendees,omitempty"` +} + +type Recording struct { + StartTime string `json:"start_time"` + EndTime string `json:"end_time"` +} + type UnsupportedBlock struct { BasicBlock } @@ -838,6 +882,13 @@ func decodeBlock(raw map[string]interface{}) (Block, error) { b = &TableBlock{} case BlockTypeTableRowBlock: b = &TableRowBlock{} + case BlockTypeMeetingNotes: + b = &MeetingNotesBlock{} + case BlockTypeTranscription: + raw["type"] = "meeting_notes" + raw["meeting_notes"] = raw["transcription"] + delete(raw, "transcription") + b = &MeetingNotesBlock{} case BlockTypeUnsupported: b = &UnsupportedBlock{} diff --git a/block_test.go b/block_test.go index 1706060..8ea8950 100644 --- a/block_test.go +++ b/block_test.go @@ -203,6 +203,110 @@ func TestBlockClient(t *testing.T) { wantErr: false, err: nil, }, + { + name: "returns meeting_notes block", + filePath: "testdata/block_get_meeting_notes.json", + statusCode: http.StatusOK, + id: "d7b3c8f4-9e6e-4c1a-b5b8-2c0f4a0c5b8e", + want: ¬ionapi.MeetingNotesBlock{ + BasicBlock: notionapi.BasicBlock{ + Object: notionapi.ObjectTypeBlock, + ID: "d7b3c8f4-9e6e-4c1a-b5b8-2c0f4a0c5b8e", + Type: notionapi.BlockTypeMeetingNotes, + CreatedTime: ×tamp, + LastEditedTime: ×tamp, + CreatedBy: ¬ionapi.User{ + Object: "user", + ID: "ee5f0f84-409a-440f-983a-a5315961c6e4", + }, + LastEditedBy: ¬ionapi.User{ + Object: "user", + ID: "ee5f0f84-409a-440f-983a-a5315961c6e4", + }, + HasChildren: true, + }, + MeetingNotes: notionapi.MeetingNotes{ + Title: []notionapi.RichText{ + { + Type: notionapi.RichTextTypeText, + Text: ¬ionapi.Text{ + Content: "Team Sync", + }, + PlainText: "Team Sync", + }, + }, + Status: "notes_ready", + Children: ¬ionapi.MeetingNotesChildren{ + SummaryBlockID: "a1b2c3d4-5678-9abc-def0-1234567890ab", + NotesBlockID: "b2c3d4e5-6789-abcd-ef01-234567890abc", + TranscriptBlockID: "c3d4e5f6-789a-bcde-f012-34567890abcd", + }, + CalendarEvent: ¬ionapi.CalendarEvent{ + Attendees: []string{"ee5f0f84-409a-440f-983a-a5315961c6e4"}, + StartTime: "2026-02-24T10:00:00.000Z", + EndTime: "2026-02-24T10:45:00.000Z", + }, + Recording: ¬ionapi.Recording{ + StartTime: "2026-02-24T10:00:00.000Z", + EndTime: "2026-02-24T10:45:00.000Z", + }, + }, + }, + wantErr: false, + err: nil, + }, + { + name: "returns transcription block (legacy) as meeting_notes", + filePath: "testdata/block_get_transcription.json", + statusCode: http.StatusOK, + id: "d7b3c8f4-9e6e-4c1a-b5b8-2c0f4a0c5b8e", + want: ¬ionapi.MeetingNotesBlock{ + BasicBlock: notionapi.BasicBlock{ + Object: notionapi.ObjectTypeBlock, + ID: "d7b3c8f4-9e6e-4c1a-b5b8-2c0f4a0c5b8e", + Type: notionapi.BlockTypeMeetingNotes, + CreatedTime: ×tamp, + LastEditedTime: ×tamp, + CreatedBy: ¬ionapi.User{ + Object: "user", + ID: "ee5f0f84-409a-440f-983a-a5315961c6e4", + }, + LastEditedBy: ¬ionapi.User{ + Object: "user", + ID: "ee5f0f84-409a-440f-983a-a5315961c6e4", + }, + HasChildren: true, + }, + MeetingNotes: notionapi.MeetingNotes{ + Title: []notionapi.RichText{ + { + Type: notionapi.RichTextTypeText, + Text: ¬ionapi.Text{ + Content: "Sprint Retro", + }, + PlainText: "Sprint Retro", + }, + }, + Status: "notes_ready", + Children: ¬ionapi.MeetingNotesChildren{ + SummaryBlockID: "d1e2f3a4-5678-9abc-def0-1234567890ab", + NotesBlockID: "e2f3a4b5-6789-abcd-ef01-234567890abc", + TranscriptBlockID: "f3a4b5c6-789a-bcde-f012-34567890abcd", + }, + CalendarEvent: ¬ionapi.CalendarEvent{ + Attendees: []string{"ee5f0f84-409a-440f-983a-a5315961c6e4"}, + StartTime: "2026-02-21T09:00:00.000Z", + EndTime: "2026-02-21T09:30:00.000Z", + }, + Recording: ¬ionapi.Recording{ + StartTime: "2026-02-21T09:00:00.000Z", + EndTime: "2026-02-21T09:30:00.000Z", + }, + }, + }, + wantErr: false, + err: nil, + }, } for _, tt := range tests { diff --git a/const.go b/const.go index eaa0933..b92d93a 100644 --- a/const.go +++ b/const.go @@ -239,6 +239,8 @@ const ( BlockTypeSyncedBlock BlockType = "synced_block" BlockTypeTableBlock BlockType = "table" BlockTypeTableRowBlock BlockType = "table_row" + BlockTypeMeetingNotes BlockType = "meeting_notes" + BlockTypeTranscription BlockType = "transcription" BlockTypeUnsupported BlockType = "unsupported" ) diff --git a/testdata/block_get_meeting_notes.json b/testdata/block_get_meeting_notes.json new file mode 100644 index 0000000..998380a --- /dev/null +++ b/testdata/block_get_meeting_notes.json @@ -0,0 +1,45 @@ +{ + "object": "block", + "id": "d7b3c8f4-9e6e-4c1a-b5b8-2c0f4a0c5b8e", + "created_time": "2021-05-24T05:06:34.827Z", + "last_edited_time": "2021-05-24T05:06:34.827Z", + "created_by": { + "object": "user", + "id": "ee5f0f84-409a-440f-983a-a5315961c6e4" + }, + "last_edited_by": { + "object": "user", + "id": "ee5f0f84-409a-440f-983a-a5315961c6e4" + }, + "has_children": true, + "archived": false, + "type": "meeting_notes", + "meeting_notes": { + "title": [ + { + "type": "text", + "text": { + "content": "Team Sync", + "link": null + }, + "plain_text": "Team Sync", + "href": null + } + ], + "status": "notes_ready", + "children": { + "summary_block_id": "a1b2c3d4-5678-9abc-def0-1234567890ab", + "notes_block_id": "b2c3d4e5-6789-abcd-ef01-234567890abc", + "transcript_block_id": "c3d4e5f6-789a-bcde-f012-34567890abcd" + }, + "calendar_event": { + "attendees": ["ee5f0f84-409a-440f-983a-a5315961c6e4"], + "start_time": "2026-02-24T10:00:00.000Z", + "end_time": "2026-02-24T10:45:00.000Z" + }, + "recording": { + "start_time": "2026-02-24T10:00:00.000Z", + "end_time": "2026-02-24T10:45:00.000Z" + } + } +} diff --git a/testdata/block_get_transcription.json b/testdata/block_get_transcription.json new file mode 100644 index 0000000..a5f0bf4 --- /dev/null +++ b/testdata/block_get_transcription.json @@ -0,0 +1,45 @@ +{ + "object": "block", + "id": "d7b3c8f4-9e6e-4c1a-b5b8-2c0f4a0c5b8e", + "created_time": "2021-05-24T05:06:34.827Z", + "last_edited_time": "2021-05-24T05:06:34.827Z", + "created_by": { + "object": "user", + "id": "ee5f0f84-409a-440f-983a-a5315961c6e4" + }, + "last_edited_by": { + "object": "user", + "id": "ee5f0f84-409a-440f-983a-a5315961c6e4" + }, + "has_children": true, + "archived": false, + "type": "transcription", + "transcription": { + "title": [ + { + "type": "text", + "text": { + "content": "Sprint Retro", + "link": null + }, + "plain_text": "Sprint Retro", + "href": null + } + ], + "status": "notes_ready", + "children": { + "summary_block_id": "d1e2f3a4-5678-9abc-def0-1234567890ab", + "notes_block_id": "e2f3a4b5-6789-abcd-ef01-234567890abc", + "transcript_block_id": "f3a4b5c6-789a-bcde-f012-34567890abcd" + }, + "calendar_event": { + "attendees": ["ee5f0f84-409a-440f-983a-a5315961c6e4"], + "start_time": "2026-02-21T09:00:00.000Z", + "end_time": "2026-02-21T09:30:00.000Z" + }, + "recording": { + "start_time": "2026-02-21T09:00:00.000Z", + "end_time": "2026-02-21T09:30:00.000Z" + } + } +}