1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package lunatask
6
7import (
8 "context"
9 "fmt"
10 "net/http"
11 "time"
12)
13
14// PersonTimelineNote is a note on a person's memory timeline.
15// Content is encrypted client-side and will be null when read.
16type PersonTimelineNote struct {
17 ID string `json:"id"`
18 DateOn *Date `json:"date_on"`
19 CreatedAt time.Time `json:"created_at"`
20 UpdatedAt time.Time `json:"updated_at"`
21}
22
23// createPersonTimelineNoteRequest defines a timeline note for JSON serialization.
24type createPersonTimelineNoteRequest struct {
25 // PersonID is the ID of the person to add the note to (required).
26 PersonID string `json:"person_id"`
27 // DateOn is the date for the note (optional, defaults to today).
28 DateOn *Date `json:"date_on,omitempty"`
29 // Content is the Markdown content of the note (optional but impractical if empty).
30 Content *string `json:"content,omitempty"`
31}
32
33// personTimelineNoteResponse wraps a single timeline note from the API.
34type personTimelineNoteResponse struct {
35 PersonTimelineNote PersonTimelineNote `json:"person_timeline_note"`
36}
37
38// TimelineNoteBuilder constructs and creates a timeline note via method chaining.
39// Content is encrypted client-side; the API accepts it on create but returns null on read.
40//
41// note, err := client.NewTimelineNote(personID).
42// OnDate(lunatask.Today()).
43// WithContent("Had coffee, discussed the project.").
44// Create(ctx)
45type TimelineNoteBuilder struct {
46 client *Client
47 req createPersonTimelineNoteRequest
48}
49
50// NewTimelineNote starts building a timeline note for the given person.
51// Get person IDs from [Client.ListPeople].
52func (c *Client) NewTimelineNote(personID string) *TimelineNoteBuilder {
53 return &TimelineNoteBuilder{client: c, req: createPersonTimelineNoteRequest{PersonID: personID}}
54}
55
56// OnDate sets when this interaction occurred.
57func (b *TimelineNoteBuilder) OnDate(date Date) *TimelineNoteBuilder {
58 b.req.DateOn = &date
59
60 return b
61}
62
63// WithContent sets the Markdown body describing the interaction.
64func (b *TimelineNoteBuilder) WithContent(content string) *TimelineNoteBuilder {
65 b.req.Content = &content
66
67 return b
68}
69
70// Create sends the timeline note to Lunatask.
71// Get person IDs from [Client.ListPeople].
72func (b *TimelineNoteBuilder) Create(ctx context.Context) (*PersonTimelineNote, error) {
73 if b.req.PersonID == "" {
74 return nil, fmt.Errorf("%w: person_id is required", ErrBadRequest)
75 }
76
77 resp, _, err := doJSON[personTimelineNoteResponse](ctx, b.client, http.MethodPost, "/person_timeline_notes", b.req)
78 if err != nil {
79 return nil, err
80 }
81
82 return &resp.PersonTimelineNote, nil
83}