From 240d681f741d04bf3448bbff771b19114f5b2b3a Mon Sep 17 00:00:00 2001 From: Manjurul Hoque Rumi Date: Tue, 5 Mar 2024 11:41:20 +0600 Subject: [PATCH 1/3] Added support for button property --- .gitignore | 1 + const.go | 1 + object.go | 3 +++ property.go | 16 ++++++++++++++++ 4 files changed, 21 insertions(+) diff --git a/.gitignore b/.gitignore index 44c53ad..01c121c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ *.dll *.so *.dylib +.idea # Test binary, built with `go test -c` *.test diff --git a/const.go b/const.go index 83ba6e1..15137a6 100644 --- a/const.go +++ b/const.go @@ -60,6 +60,7 @@ const ( PropertyTypeStatus PropertyType = "status" PropertyTypeUniqueID PropertyType = "unique_id" PropertyTypeVerification PropertyType = "verification" + PropertyTypeButton PropertyType = "button" ) const ( diff --git a/object.go b/object.go index eb6f84b..4bf9578 100644 --- a/object.go +++ b/object.go @@ -212,3 +212,6 @@ type Verification struct { VerifiedBy *User `json:"verified_by,omitempty"` Date *DateObject `json:"date,omitempty"` } + +type Button struct { +} diff --git a/property.go b/property.go index 40ba426..88ded83 100644 --- a/property.go +++ b/property.go @@ -393,6 +393,20 @@ func (p VerificationProperty) GetType() PropertyType { return p.Type } +type ButtonProperty struct { + ID ObjectID `json:"id,omitempty"` + Type PropertyType `json:"type,omitempty"` + Button Button `json:"button"` +} + +func (p ButtonProperty) GetID() string { + return p.ID.String() +} + +func (p ButtonProperty) GetType() PropertyType { + return p.Type +} + type Properties map[string]Property func (p *Properties) UnmarshalJSON(data []byte) error { @@ -485,6 +499,8 @@ func decodeProperty(raw map[string]interface{}) (Property, error) { p = &UniqueIDProperty{} case PropertyTypeVerification: p = &VerificationProperty{} + case PropertyTypeButton: + p = &ButtonProperty{} default: return nil, fmt.Errorf("unsupported property type: %s", raw["type"].(string)) } From 5f938427c16c6a1b55211afb864c1c080f7751a5 Mon Sep 17 00:00:00 2001 From: Manjurul Hoque Rumi Date: Wed, 22 Jul 2026 13:53:30 +0600 Subject: [PATCH 2/3] feat: add MeetingNotesBlock and support for transcription as meeting_notes --- block.go | 41 ++++++++++ block_test.go | 104 ++++++++++++++++++++++++++ const.go | 2 + testdata/block_get_meeting_notes.json | 45 +++++++++++ testdata/block_get_transcription.json | 45 +++++++++++ 5 files changed, 237 insertions(+) create mode 100644 testdata/block_get_meeting_notes.json create mode 100644 testdata/block_get_transcription.json diff --git a/block.go b/block.go index 50e65d0..83f501f 100644 --- a/block.go +++ b/block.go @@ -380,6 +380,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 +742,36 @@ type SyncedFrom struct { BlockID BlockID `json:"block_id"` } +type MeetingNotesBlock struct { + BasicBlock + MeetingNotes MeetingNotes `json:"meeting_notes"` +} + +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 +872,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" + } + } +} From efec6a3ec0f0e950805d96d75fed563663e7b315 Mon Sep 17 00:00:00 2001 From: Manjurul Hoque Rumi Date: Sat, 25 Jul 2026 01:58:00 +0600 Subject: [PATCH 3/3] feat(block): get meeting notes for the block if available --- block.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/block.go b/block.go index 83f501f..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 { @@ -747,6 +753,10 @@ type MeetingNotesBlock struct { MeetingNotes MeetingNotes `json:"meeting_notes"` } +func (b *MeetingNotesBlock) GetMeetingNotes() *MeetingNotes { + return &b.MeetingNotes +} + type MeetingNotes struct { Title []RichText `json:"title"` Status string `json:"status"`