timeline.go

 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}