Skip to content

Commit

Permalink
change output format to json
Browse files Browse the repository at this point in the history
  • Loading branch information
nukokusa committed Mar 28, 2023
1 parent 48f5b4b commit fb20b66
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 120 deletions.
12 changes: 6 additions & 6 deletions README.md
Expand Up @@ -26,10 +26,10 @@ Commands:
create --calendar-id=STRING --start-time=STRING --end-time=STRING
Creates an event
update --calendar-id=STRING --event-id=STRING
update --calendar-id=STRING --id=STRING
Updates an event
delete --calendar-id=STRING --event-id=STRING
delete --calendar-id=STRING --id=STRING
Deletes an event
```

Expand Down Expand Up @@ -64,13 +64,13 @@ Flags:
### Updates an Event

```
Usage: koyomi update --calendar-id=STRING --event-id=STRING
Usage: koyomi update --calendar-id=STRING --id=STRING
Updates an event
Flags:
--calendar-id=STRING Calendar identifier
--event-id=STRING Identifier of the event
--id=STRING Identifier of the event
--summary=STRING Title of the event
--description=STRING Description of the event
-s, --start-time=STRING The start time of the event
Expand All @@ -80,11 +80,11 @@ Flags:
### Deletes an Event

```
Usage: koyomi delete --calendar-id=STRING --event-id=STRING
Usage: koyomi delete --calendar-id=STRING --id=STRING
Deletes an event
Flags:
--calendar-id=STRING Calendar identifier
--event-id=STRING Identifier of the event
--id=STRING Identifier of the event
```
105 changes: 89 additions & 16 deletions calendar.go
Expand Up @@ -10,10 +10,42 @@ import (
"google.golang.org/api/option"
)

type Event struct {
ID string `json:"id"`
Summary string `json:"summary"`
Description string `json:"description"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
}

func NewEvent(ev *calendar.Event) (*Event, error) {
var startTime, endTime time.Time
var err error
if ev.Start != nil {
startTime, err = time.Parse(time.RFC3339, ev.Start.DateTime)
if err != nil {
return nil, errors.Wrap(err, "error Parse")
}
}
if ev.End != nil {
endTime, err = time.Parse(time.RFC3339, ev.End.DateTime)
if err != nil {
return nil, errors.Wrap(err, "error Parse")
}
}
return &Event{
ID: ev.Id,
Summary: ev.Summary,
Description: ev.Description,
StartTime: startTime,
EndTime: endTime,
}, nil
}

type CalendarService interface {
List(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*calendar.Event, error)
Insert(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error)
Patch(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error)
List(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*Event, error)
Insert(ctx context.Context, calendarID string, event *Event) (*Event, error)
Patch(ctx context.Context, calendarID string, event *Event) (*Event, error)
Delete(ctx context.Context, calendarID, eventID string) error
}

Expand All @@ -31,11 +63,11 @@ func newCalendarService(ctx context.Context, credentialPath string) (CalendarSer
}, nil
}

func (s *calendarService) List(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*calendar.Event, error) {
result := []*calendar.Event{}
func (s *calendarService) List(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*Event, error) {
pageToken := ""
evs := []*calendar.Event{}
for {
evs, err := s.cs.Events.List(calendarID).
es, err := s.cs.Events.List(calendarID).
TimeMin(startTime.Format(time.RFC3339)).
TimeMax(endTime.Format(time.RFC3339)).
SingleEvents(true).
Expand All @@ -44,32 +76,73 @@ func (s *calendarService) List(ctx context.Context, calendarID string, startTime
if err != nil {
return nil, errors.Wrap(err, "error Events.List")
}
result = append(result, evs.Items...)
if evs.NextPageToken == "" {
evs = append(evs, es.Items...)
if es.NextPageToken == "" {
break
}
pageToken = evs.NextPageToken
pageToken = es.NextPageToken
}

result := make([]*Event, 0, len(evs))
for _, ev := range evs {
event, err := NewEvent(ev)
if err != nil {
return nil, errors.Wrap(err, "error NewEvent")
}
result = append(result, event)
}
sort.Slice(result, func(i, j int) bool {
return result[i].Start.DateTime < result[j].Start.DateTime
return result[i].StartTime.Before(result[j].StartTime)
})
return result, nil
}

func (s *calendarService) Insert(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
ev, err := s.cs.Events.Insert(calendarID, event).Context(ctx).Do()
func (s *calendarService) Insert(ctx context.Context, calendarID string, event *Event) (*Event, error) {
ev := &calendar.Event{
Id: event.ID,
Summary: event.Summary,
Description: event.Description,
Start: &calendar.EventDateTime{
DateTime: event.StartTime.Format(time.RFC3339),
},
End: &calendar.EventDateTime{
DateTime: event.EndTime.Format(time.RFC3339),
},
}
ev, err := s.cs.Events.Insert(calendarID, ev).Context(ctx).Do()
if err != nil {
return nil, errors.Wrap(err, "error Events.Insert")
}
return ev, nil

result, err := NewEvent(ev)
if err != nil {
return nil, errors.Wrap(err, "error NewEvent")
}
return result, nil
}

func (s *calendarService) Patch(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
ev, err := s.cs.Events.Patch(calendarID, event.Id, event).Context(ctx).Do()
func (s *calendarService) Patch(ctx context.Context, calendarID string, event *Event) (*Event, error) {
ev := &calendar.Event{
Id: event.ID,
Summary: event.Summary,
Description: event.Description,
}
if !event.StartTime.IsZero() {
ev.Start.DateTime = event.StartTime.Format(time.RFC3339)
}
if !event.EndTime.IsZero() {
ev.End.DateTime = event.EndTime.Format(time.RFC3339)
}
ev, err := s.cs.Events.Patch(calendarID, ev.Id, ev).Context(ctx).Do()
if err != nil {
return nil, errors.Wrap(err, "error Events.Patch")
}
return ev, nil

result, err := NewEvent(ev)
if err != nil {
return nil, errors.Wrap(err, "error NewEvent")
}
return result, nil
}

func (s *calendarService) Delete(ctx context.Context, calendarID, eventID string) error {
Expand Down
20 changes: 9 additions & 11 deletions calendar_mock.go
Expand Up @@ -4,26 +4,24 @@ import (
"context"
"errors"
"time"

"google.golang.org/api/calendar/v3"
)

type calendarServiceMock struct {
ListMock func(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*calendar.Event, error)
InsertMock func(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error)
PatchMock func(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error)
ListMock func(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*Event, error)
InsertMock func(ctx context.Context, calendarID string, event *Event) (*Event, error)
PatchMock func(ctx context.Context, calendarID string, event *Event) (*Event, error)
DeleteMock func(ctx context.Context, calendarID, eventID string) error
}

func newCalendarServiceMock() *calendarServiceMock {
return &calendarServiceMock{
ListMock: func(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*calendar.Event, error) {
ListMock: func(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*Event, error) {
return nil, errors.New("not implememted")
},
InsertMock: func(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
InsertMock: func(ctx context.Context, calendarID string, event *Event) (*Event, error) {
return nil, errors.New("not implememted")
},
PatchMock: func(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
PatchMock: func(ctx context.Context, calendarID string, event *Event) (*Event, error) {
return nil, errors.New("not implememted")
},
DeleteMock: func(ctx context.Context, calendarID, eventID string) error {
Expand All @@ -32,13 +30,13 @@ func newCalendarServiceMock() *calendarServiceMock {
}
}

func (s *calendarServiceMock) List(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*calendar.Event, error) {
func (s *calendarServiceMock) List(ctx context.Context, calendarID string, startTime, endTime time.Time) ([]*Event, error) {
return s.ListMock(ctx, calendarID, startTime, endTime)
}
func (s *calendarServiceMock) Insert(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
func (s *calendarServiceMock) Insert(ctx context.Context, calendarID string, event *Event) (*Event, error) {
return s.InsertMock(ctx, calendarID, event)
}
func (s *calendarServiceMock) Patch(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
func (s *calendarServiceMock) Patch(ctx context.Context, calendarID string, event *Event) (*Event, error) {
return s.PatchMock(ctx, calendarID, event)
}
func (s *calendarServiceMock) Delete(ctx context.Context, calendarID, eventID string) error {
Expand Down
23 changes: 11 additions & 12 deletions create.go
Expand Up @@ -2,13 +2,11 @@ package koyomi

import (
"context"
"fmt"
"encoding/json"
"log"
"time"

"github.com/pkg/errors"
"github.com/tkuchiki/parsetime"
"google.golang.org/api/calendar/v3"
)

type CreateOption struct {
Expand All @@ -20,11 +18,6 @@ type CreateOption struct {
}

func (k *Koyomi) Create(ctx context.Context, opt *CreateOption) error {
event := &calendar.Event{
Summary: opt.Summary,
Description: opt.Description,
}

p, err := parsetime.NewParseTime()
if err != nil {
return errors.Wrap(err, "error parsetime.NewParseTime")
Expand All @@ -33,20 +26,26 @@ func (k *Koyomi) Create(ctx context.Context, opt *CreateOption) error {
if err != nil {
return errors.Wrap(err, "error Parse")
}
event.Start = &calendar.EventDateTime{DateTime: startTime.Format(time.RFC3339)}
endTime, err := p.Parse(opt.EndTime)
if err != nil {
return errors.Wrap(err, "error Parse")
}
event.End = &calendar.EventDateTime{DateTime: endTime.Format(time.RFC3339)}

event := &Event{
Summary: opt.Summary,
Description: opt.Description,
StartTime: startTime,
EndTime: endTime,
}
event, err = k.cs.Insert(ctx, opt.CalendarID, event)
if err != nil {
return errors.Wrap(err, "error Insert")
}

log.Printf("[DEBUG] inserted event: CalendarID=%s, EventID=%s", opt.CalendarID, event.Id)
fmt.Println(event.Id)
log.Printf("[DEBUG] inserted event: CalendarID=%s, ID=%s", opt.CalendarID, event.ID)

if err := json.NewEncoder(k.stdout).Encode(event); err != nil {
return errors.Wrap(err, "error Encode")
}
return nil
}
30 changes: 8 additions & 22 deletions create_test.go
@@ -1,30 +1,29 @@
package koyomi_test

import (
"bytes"
"context"
"testing"

"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
"github.com/nukokusa/koyomi"
"google.golang.org/api/calendar/v3"
)

func TestKoyomi_Create(t *testing.T) {
t.Parallel()

ctx := context.Background()

var result *calendar.Event
cs := koyomi.NewCalendarServiceMock()
cs.InsertMock = func(ctx context.Context, calendarID string, event *calendar.Event) (*calendar.Event, error) {
event.Id = "dummy-id"
result = event
cs.InsertMock = func(ctx context.Context, calendarID string, event *koyomi.Event) (*koyomi.Event, error) {
event.ID = "dummy-id"
return event, nil
}

k := &koyomi.Koyomi{}
k.SetCalendarService(cs)
var b bytes.Buffer
k.SetStdout(&b)

opt := &koyomi.CreateOption{
CalendarID: "dummy-calendar-id",
Expand All @@ -38,22 +37,9 @@ func TestKoyomi_Create(t *testing.T) {
t.Fatal("error Create", err)
}

expected := &calendar.Event{
Id: "dummy-id",
Summary: "dummy-summary",
Description: "dummy-description",
Start: &calendar.EventDateTime{
DateTime: "2023-03-01T12:00:00+09:00",
},
End: &calendar.EventDateTime{
DateTime: "2023-03-02T13:00:00+09:00",
},
}

opts := []cmp.Option{
cmpopts.IgnoreUnexported(calendar.Event{}, calendar.EventDateTime{}),
}
if diff := cmp.Diff(expected, result, opts...); diff != "" {
expected := `{"id":"dummy-id","summary":"dummy-summary","description":"dummy-description","start_time":"2023-03-01T12:00:00+09:00","end_time":"2023-03-02T13:00:00+09:00"}
`
if diff := cmp.Diff(expected, b.String()); diff != "" {
t.Errorf("error mismatch (-want +got):\n%s", diff)
}
}
6 changes: 3 additions & 3 deletions delete.go
Expand Up @@ -9,15 +9,15 @@ import (

type DeleteOption struct {
CalendarID string `required:"" help:"Calendar identifier"`
EventID string `required:"" help:"Identifier of the event"`
ID string `required:"" help:"Identifier of the event"`
}

func (k *Koyomi) Delete(ctx context.Context, opt *DeleteOption) error {
if err := k.cs.Delete(ctx, opt.CalendarID, opt.EventID); err != nil {
if err := k.cs.Delete(ctx, opt.CalendarID, opt.ID); err != nil {
return errors.Wrap(err, "error Delete")
}

log.Printf("[DEBUG] deleted event: CalendarID=%s, EventID=%s", opt.CalendarID, opt.EventID)
log.Printf("[DEBUG] deleted event: CalendarID=%s, ID=%s", opt.CalendarID, opt.ID)

return nil
}
6 changes: 6 additions & 0 deletions export_test.go
@@ -1,5 +1,7 @@
package koyomi

import "io"

var (
NewCalendarServiceMock = newCalendarServiceMock
)
Expand All @@ -9,3 +11,7 @@ type ExportKoyomi = Koyomi
func (k *ExportKoyomi) SetCalendarService(cs CalendarService) {
k.cs = cs
}

func (k *ExportKoyomi) SetStdout(w io.Writer) {
k.stdout = w
}

0 comments on commit fb20b66

Please sign in to comment.