Skip to content

Commit 4a840b5

Browse files
committed
refactor(cmd): split calendar and gmail entry files
1 parent 49729c1 commit 4a840b5

File tree

9 files changed

+919
-840
lines changed

9 files changed

+919
-840
lines changed

internal/cmd/calendar.go

Lines changed: 0 additions & 350 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,5 @@
11
package cmd
22

3-
import (
4-
"context"
5-
"fmt"
6-
"os"
7-
"strings"
8-
9-
"google.golang.org/api/calendar/v3"
10-
11-
"github.com/steipete/gogcli/internal/outfmt"
12-
"github.com/steipete/gogcli/internal/ui"
13-
)
14-
153
type CalendarCmd struct {
164
Calendars CalendarCalendarsCmd `cmd:"" name:"calendars" help:"List calendars"`
175
Subscribe CalendarSubscribeCmd `cmd:"" name:"subscribe" aliases:"sub,add-calendar" help:"Add a calendar to your calendar list"`
@@ -34,341 +22,3 @@ type CalendarCmd struct {
3422
OOO CalendarOOOCmd `cmd:"" name:"out-of-office" aliases:"ooo" help:"Create an Out of Office event"`
3523
WorkingLocation CalendarWorkingLocationCmd `cmd:"" name:"working-location" aliases:"wl" help:"Set working location (home/office/custom)"`
3624
}
37-
38-
type CalendarCalendarsCmd struct {
39-
Max int64 `name:"max" aliases:"limit" help:"Max results" default:"100"`
40-
Page string `name:"page" aliases:"cursor" help:"Page token"`
41-
All bool `name:"all" aliases:"all-pages,allpages" help:"Fetch all pages"`
42-
FailEmpty bool `name:"fail-empty" aliases:"non-empty,require-results" help:"Exit with code 3 if no results"`
43-
}
44-
45-
func (c *CalendarCalendarsCmd) Run(ctx context.Context, flags *RootFlags) error {
46-
u := ui.FromContext(ctx)
47-
account, err := requireAccount(flags)
48-
if err != nil {
49-
return err
50-
}
51-
52-
svc, err := newCalendarService(ctx, account)
53-
if err != nil {
54-
return err
55-
}
56-
57-
fetch := func(pageToken string) ([]*calendar.CalendarListEntry, string, error) {
58-
call := svc.CalendarList.List().MaxResults(c.Max)
59-
if strings.TrimSpace(pageToken) != "" {
60-
call = call.PageToken(pageToken)
61-
}
62-
r, err := call.Do()
63-
if err != nil {
64-
return nil, "", err
65-
}
66-
return r.Items, r.NextPageToken, nil
67-
}
68-
69-
var items []*calendar.CalendarListEntry
70-
nextPageToken := ""
71-
if c.All {
72-
all, err := collectAllPages(c.Page, fetch)
73-
if err != nil {
74-
return err
75-
}
76-
items = all
77-
} else {
78-
var err error
79-
items, nextPageToken, err = fetch(c.Page)
80-
if err != nil {
81-
return err
82-
}
83-
}
84-
if outfmt.IsJSON(ctx) {
85-
if err := outfmt.WriteJSON(ctx, os.Stdout, map[string]any{
86-
"calendars": items,
87-
"nextPageToken": nextPageToken,
88-
}); err != nil {
89-
return err
90-
}
91-
if len(items) == 0 {
92-
return failEmptyExit(c.FailEmpty)
93-
}
94-
return nil
95-
}
96-
if len(items) == 0 {
97-
u.Err().Println("No calendars")
98-
return failEmptyExit(c.FailEmpty)
99-
}
100-
101-
w, flush := tableWriter(ctx)
102-
defer flush()
103-
fmt.Fprintln(w, "ID\tNAME\tROLE")
104-
for _, cal := range items {
105-
fmt.Fprintf(w, "%s\t%s\t%s\n", cal.Id, cal.Summary, cal.AccessRole)
106-
}
107-
printNextPageHint(u, nextPageToken)
108-
return nil
109-
}
110-
111-
type CalendarSubscribeCmd struct {
112-
CalendarID string `arg:"" name:"calendarId" help:"Calendar ID to subscribe to (e.g., user@example.com or calendar ID)"`
113-
ColorID string `name:"color-id" help:"Color ID (1-24, see 'calendar colors')"`
114-
Hidden bool `name:"hidden" help:"Hide from the calendar list UI"`
115-
Selected bool `name:"selected" help:"Show events in the calendar UI" default:"true" negatable:""`
116-
}
117-
118-
func (c *CalendarSubscribeCmd) Run(ctx context.Context, flags *RootFlags) error {
119-
u := ui.FromContext(ctx)
120-
account, err := requireAccount(flags)
121-
if err != nil {
122-
return err
123-
}
124-
calendarID := strings.TrimSpace(c.CalendarID)
125-
if calendarID == "" {
126-
return usage("calendarId required")
127-
}
128-
colorID, err := validateCalendarColorId(c.ColorID)
129-
if err != nil {
130-
return err
131-
}
132-
133-
svc, err := newCalendarService(ctx, account)
134-
if err != nil {
135-
return err
136-
}
137-
138-
entry := &calendar.CalendarListEntry{
139-
Id: calendarID,
140-
Hidden: c.Hidden,
141-
Selected: c.Selected,
142-
}
143-
if colorID != "" {
144-
entry.ColorId = colorID
145-
}
146-
147-
added, err := svc.CalendarList.Insert(entry).Do()
148-
if err != nil {
149-
return err
150-
}
151-
if outfmt.IsJSON(ctx) {
152-
return outfmt.WriteJSON(ctx, os.Stdout, map[string]any{"calendar": added})
153-
}
154-
u.Out().Printf("subscribed\t%s", added.Id)
155-
u.Out().Printf("name\t%s", added.Summary)
156-
u.Out().Printf("role\t%s", added.AccessRole)
157-
return nil
158-
}
159-
160-
type CalendarAclCmd struct {
161-
CalendarID string `arg:"" name:"calendarId" help:"Calendar ID"`
162-
Max int64 `name:"max" aliases:"limit" help:"Max results" default:"100"`
163-
Page string `name:"page" aliases:"cursor" help:"Page token"`
164-
All bool `name:"all" aliases:"all-pages,allpages" help:"Fetch all pages"`
165-
FailEmpty bool `name:"fail-empty" aliases:"non-empty,require-results" help:"Exit with code 3 if no results"`
166-
}
167-
168-
func (c *CalendarAclCmd) Run(ctx context.Context, flags *RootFlags) error {
169-
u := ui.FromContext(ctx)
170-
account, err := requireAccount(flags)
171-
if err != nil {
172-
return err
173-
}
174-
calendarID := strings.TrimSpace(c.CalendarID)
175-
if calendarID == "" {
176-
return usage("calendarId required")
177-
}
178-
179-
svc, err := newCalendarService(ctx, account)
180-
if err != nil {
181-
return err
182-
}
183-
calendarID, err = resolveCalendarID(ctx, svc, calendarID)
184-
if err != nil {
185-
return err
186-
}
187-
188-
fetch := func(pageToken string) ([]*calendar.AclRule, string, error) {
189-
call := svc.Acl.List(calendarID).MaxResults(c.Max)
190-
if strings.TrimSpace(pageToken) != "" {
191-
call = call.PageToken(pageToken)
192-
}
193-
r, err := call.Do()
194-
if err != nil {
195-
return nil, "", err
196-
}
197-
return r.Items, r.NextPageToken, nil
198-
}
199-
200-
var items []*calendar.AclRule
201-
nextPageToken := ""
202-
if c.All {
203-
all, err := collectAllPages(c.Page, fetch)
204-
if err != nil {
205-
return err
206-
}
207-
items = all
208-
} else {
209-
var err error
210-
items, nextPageToken, err = fetch(c.Page)
211-
if err != nil {
212-
return err
213-
}
214-
}
215-
if outfmt.IsJSON(ctx) {
216-
if err := outfmt.WriteJSON(ctx, os.Stdout, map[string]any{
217-
"rules": items,
218-
"nextPageToken": nextPageToken,
219-
}); err != nil {
220-
return err
221-
}
222-
if len(items) == 0 {
223-
return failEmptyExit(c.FailEmpty)
224-
}
225-
return nil
226-
}
227-
if len(items) == 0 {
228-
u.Err().Println("No ACL rules")
229-
return failEmptyExit(c.FailEmpty)
230-
}
231-
232-
w, flush := tableWriter(ctx)
233-
defer flush()
234-
fmt.Fprintln(w, "SCOPE_TYPE\tSCOPE_VALUE\tROLE")
235-
for _, rule := range items {
236-
scopeType := ""
237-
scopeValue := ""
238-
if rule.Scope != nil {
239-
scopeType = rule.Scope.Type
240-
scopeValue = rule.Scope.Value
241-
}
242-
fmt.Fprintf(w, "%s\t%s\t%s\n", scopeType, scopeValue, rule.Role)
243-
}
244-
printNextPageHint(u, nextPageToken)
245-
return nil
246-
}
247-
248-
type CalendarEventsCmd struct {
249-
CalendarID string `arg:"" name:"calendarId" optional:"" help:"Calendar ID (default: primary)"`
250-
Cal []string `name:"cal" help:"Calendar ID or name (can be repeated)"`
251-
Calendars string `name:"calendars" help:"Comma-separated calendar IDs, names, or indices from 'calendar calendars'"`
252-
From string `name:"from" help:"Start time (RFC3339 with timezone, date, or relative: today, tomorrow, monday)"`
253-
To string `name:"to" help:"End time (RFC3339 with timezone, date, or relative)"`
254-
Today bool `name:"today" help:"Today only (timezone-aware)"`
255-
Tomorrow bool `name:"tomorrow" help:"Tomorrow only (timezone-aware)"`
256-
Week bool `name:"week" help:"This week (uses --week-start, default Mon)"`
257-
Days int `name:"days" help:"Next N days (timezone-aware)" default:"0"`
258-
WeekStart string `name:"week-start" help:"Week start day for --week (sun, mon, ...)" default:""`
259-
Max int64 `name:"max" aliases:"limit" help:"Max results" default:"10"`
260-
Page string `name:"page" aliases:"cursor" help:"Page token"`
261-
AllPages bool `name:"all-pages" aliases:"allpages" help:"Fetch all pages"`
262-
FailEmpty bool `name:"fail-empty" aliases:"non-empty,require-results" help:"Exit with code 3 if no results"`
263-
Query string `name:"query" help:"Free text search"`
264-
All bool `name:"all" help:"Fetch events from all calendars"`
265-
PrivatePropFilter string `name:"private-prop-filter" help:"Filter by private extended property (key=value)"`
266-
SharedPropFilter string `name:"shared-prop-filter" help:"Filter by shared extended property (key=value)"`
267-
Fields string `name:"fields" help:"Comma-separated fields to return"`
268-
Weekday bool `name:"weekday" help:"Include start/end day-of-week columns" default:"${calendar_weekday}"`
269-
}
270-
271-
func (c *CalendarEventsCmd) Run(ctx context.Context, flags *RootFlags) error {
272-
account, err := requireAccount(flags)
273-
if err != nil {
274-
return err
275-
}
276-
277-
calendarID := strings.TrimSpace(c.CalendarID)
278-
calInputs := append([]string{}, c.Cal...)
279-
if strings.TrimSpace(c.Calendars) != "" {
280-
calInputs = append(calInputs, splitCSV(c.Calendars)...)
281-
}
282-
if c.All && (calendarID != "" || len(calInputs) > 0) {
283-
return usage("calendarId or --cal/--calendars not allowed with --all flag")
284-
}
285-
if calendarID != "" && len(calInputs) > 0 {
286-
return usage("calendarId not allowed with --cal/--calendars")
287-
}
288-
if !c.All && calendarID == "" && len(calInputs) == 0 {
289-
calendarID = primaryCalendarID
290-
}
291-
292-
svc, err := newCalendarService(ctx, account)
293-
if err != nil {
294-
return err
295-
}
296-
if !c.All {
297-
calendarID, err = resolveCalendarID(ctx, svc, calendarID)
298-
if err != nil {
299-
return err
300-
}
301-
}
302-
303-
// Use timezone-aware time resolution
304-
timeRange, err := ResolveTimeRange(ctx, svc, TimeRangeFlags{
305-
From: c.From,
306-
To: c.To,
307-
Today: c.Today,
308-
Tomorrow: c.Tomorrow,
309-
Week: c.Week,
310-
Days: c.Days,
311-
WeekStart: c.WeekStart,
312-
})
313-
if err != nil {
314-
return err
315-
}
316-
317-
from, to := timeRange.FormatRFC3339()
318-
319-
if c.All {
320-
return listAllCalendarsEvents(ctx, svc, from, to, c.Max, c.Page, c.AllPages, c.FailEmpty, c.Query, c.PrivatePropFilter, c.SharedPropFilter, c.Fields, c.Weekday)
321-
}
322-
if len(calInputs) > 0 {
323-
ids, err := resolveCalendarIDs(ctx, svc, calInputs)
324-
if err != nil {
325-
return err
326-
}
327-
if len(ids) == 0 {
328-
return usage("no calendars specified")
329-
}
330-
return listSelectedCalendarsEvents(ctx, svc, ids, from, to, c.Max, c.Page, c.AllPages, c.FailEmpty, c.Query, c.PrivatePropFilter, c.SharedPropFilter, c.Fields, c.Weekday)
331-
}
332-
return listCalendarEvents(ctx, svc, calendarID, from, to, c.Max, c.Page, c.AllPages, c.FailEmpty, c.Query, c.PrivatePropFilter, c.SharedPropFilter, c.Fields, c.Weekday)
333-
}
334-
335-
type CalendarEventCmd struct {
336-
CalendarID string `arg:"" name:"calendarId" help:"Calendar ID"`
337-
EventID string `arg:"" name:"eventId" help:"Event ID"`
338-
}
339-
340-
func (c *CalendarEventCmd) Run(ctx context.Context, flags *RootFlags) error {
341-
u := ui.FromContext(ctx)
342-
account, err := requireAccount(flags)
343-
if err != nil {
344-
return err
345-
}
346-
calendarID := strings.TrimSpace(c.CalendarID)
347-
eventID := normalizeCalendarEventID(c.EventID)
348-
if calendarID == "" {
349-
return usage("empty calendarId")
350-
}
351-
if eventID == "" {
352-
return usage("empty eventId")
353-
}
354-
355-
svc, err := newCalendarService(ctx, account)
356-
if err != nil {
357-
return err
358-
}
359-
calendarID, err = resolveCalendarID(ctx, svc, calendarID)
360-
if err != nil {
361-
return err
362-
}
363-
364-
event, err := svc.Events.Get(calendarID, eventID).Do()
365-
if err != nil {
366-
return err
367-
}
368-
tz, loc, _ := getCalendarLocation(ctx, svc, calendarID)
369-
if outfmt.IsJSON(ctx) {
370-
return outfmt.WriteJSON(ctx, os.Stdout, map[string]any{"event": wrapEventWithDaysWithTimezone(event, tz, loc)})
371-
}
372-
printCalendarEventWithTimezone(u, event, tz, loc)
373-
return nil
374-
}

0 commit comments

Comments
 (0)