changeset 51:a9b720445bcf

now roughly syncs cals and events to mongodb, one time
author drewp@bigasterisk.com
date Mon, 19 Aug 2024 14:42:27 -0700
parents dade5bbd02e3
children 5f7c393577e9
files calsync/cal_sync.go calsync/convert/convert.go calsync/event_sync.go calsync/gcalclient/gcalclient.go calsync/mongoclient/cals_collection.go calsync/mongoclient/events_collection.go calsync/mongoclient/mongoclient.go
diffstat 7 files changed, 80 insertions(+), 103 deletions(-) [+]
line wrap: on
line diff
--- a/calsync/cal_sync.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/cal_sync.go	Mon Aug 19 14:42:27 2024 -0700
@@ -13,7 +13,7 @@
 
 	seen := make(map[string]bool)
 
-	cals, err := gc.AllCalendars()
+	cals, err := gc.AllCalendars(100)
 	if err != nil {
 		return err
 	}
--- a/calsync/convert/convert.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/convert/convert.go	Mon Aug 19 14:42:27 2024 -0700
@@ -1,7 +1,7 @@
 package convert
 
 import (
-	"net/url"
+	"log"
 	"time"
 
 	"bigasterisk.com/go/gcalendarwatch/gcalclient"
@@ -18,51 +18,45 @@
 	}
 }
 
-func MakeEventUrl(calUrl string, evId string) string {
-	return calUrl + "/" + url.QueryEscape(evId)
-}
-
-func MakeEventUrl2(cal mongoclient.MongoCal, evId string) string {
-	return MakeEventUrl3(cal.GoogleId, evId)
-}
-
-func MakeEventUrl3(googleCalId string, evId string) string {
-	return MakeEventUrl("http://bigasterisk.com/calendar/"+
-		url.QueryEscape(googleCalId), evId)
-}
-
 func MongoEventFromGoogleEvent2(
 	calUrl string,
 	ev *gcalclient.CalendarEvent,
 	now time.Time,
 ) mongoclient.MongoEvent {
-	return mongoEventFromGoogleEvent(calUrl, ev, now)
+	return mongoEventFromGoogleEvent(ev, now)
 
 }
-func MongoEventFromGoogleEvent(
-	cal *calendar.CalendarListEntry,
-	ev *gcalclient.CalendarEvent,
-	now time.Time,
-) mongoclient.MongoEvent {
-	return mongoEventFromGoogleEvent(MakeEventUrl3(cal.Id, ev.Id), ev, now)
-}
 
-func mongoEventFromGoogleEvent(calUrl string, ev *gcalclient.CalendarEvent, now time.Time) mongoclient.MongoEvent {
+func mongoEventFromGoogleEvent(ev *gcalclient.CalendarEvent, now time.Time) mongoclient.MongoEvent {
 	return mongoclient.MongoEvent{
-		Url:      calUrl,
-		GoogleId: ev.Event.Id,
-		HtmlLink: ev.HtmlLink,
-		Title:    ev.Summary, //?
-		// FeedId             : ev.Event.FeedId, // or calid?
-		// FeedTitle          : ev.Event.FeedTitle, // /or what
-		EndTimeUnspecified: ev.Event.EndTimeUnspecified,
-		// Start              : ev.Start.DateTime,
-		// StartDate          : ev.Event.StartDate,
-		// StartTime          : ev.Event.StartTime,
-		// End                : ev.Event.End,
-		// EndDate            : ev.Event.EndDate,
-		// EndTime            : ev.Event.EndTime,
-		LastUpdated: now,
+		LastUpdated:        now,
+		Url:                ev.EventUrl,
+		GoogleId:           ev.Id,
+		CalendarUrl:        ev.CalendarUrl,
+		HtmlLink:           ev.HtmlLink,
+		Title:              ev.Summary,
+		EndTimeUnspecified: ev.EndTimeUnspecified,
+		Start:              ev.Start.DateTime,
+		StartDate:          ev.Start.Date, // if all-day
+		StartTime:          goTimeFromEventField(ev.Start),
+		End:                ev.End.DateTime,
+		EndDate:            ev.End.Date, // if all-day
+		EndTime:            goTimeFromEventField(ev.End),
 	}
 
 }
+
+func goTimeFromEventField(x *calendar.EventDateTime) time.Time {
+	if x.Date != "" {
+		t, err := time.Parse("2006-01-02", x.Date)
+		if err != nil {
+			log.Panicf("Error parsing x.Date %s: %v", x.Date, err)
+		}
+		return t
+	}
+	t, err := time.Parse(time.RFC3339, x.DateTime)
+	if err != nil {
+		log.Panicf("Error parsing x.DateTime %s: %v", x.DateTime, err)
+	}
+	return t
+}
--- a/calsync/event_sync.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/event_sync.go	Mon Aug 19 14:42:27 2024 -0700
@@ -9,17 +9,19 @@
 	"bigasterisk.com/go/gcalendarwatch/mongoclient"
 )
 
-func updateMongoEventsToMatchGoogle(mc *mongoclient.MongoClient, gc *gcalclient.GCalClient) error {
+func updateMongoEventsToMatchGoogle(
+	mc *mongoclient.MongoClient, gc *gcalclient.GCalClient) error {
 	t := time.Now()
-	events, err := gc.FindEvents(t)
+	events, err := gc.FindEvents(mc, t, 3)
 	if err != nil {
 		return err
 	}
-	log.Println("Found", len(events), "events")
-	// todo: wipe mongo time period
-	log.Println("Upcoming events:")
+	log.Println("upserting", len(events), "events")
 	for _, ev := range events {
-		mc.UpsertOneEvent(convert.MongoEventFromGoogleEvent2(ev.CalendarUrl, ev, t))
+		mc.UpsertOneEvent(
+			convert.MongoEventFromGoogleEvent2(ev.CalendarUrl, ev, t),
+		)
 	}
+	mc.DeleteEventsUpdatedBefore(t)
 	return nil
 }
--- a/calsync/gcalclient/gcalclient.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/gcalclient/gcalclient.go	Mon Aug 19 14:42:27 2024 -0700
@@ -4,8 +4,10 @@
 	"context"
 	"log"
 	"net/url"
+	"strings"
 	"time"
 
+	"bigasterisk.com/go/gcalendarwatch/mongoclient"
 	"google.golang.org/api/calendar/v3"
 )
 
@@ -14,16 +16,25 @@
 	srv *calendar.Service
 }
 
-// Same as calendar.Event, but includes the source calendar url
+// Same as calendar.Event, but includes our urls
 type CalendarEvent struct {
 	*calendar.Event
 	CalendarUrl string
+	EventUrl    string
 }
 
 func MakeCalUrl(calId string) string {
 	return "http://bigasterisk.com/calendar/" + url.QueryEscape(calId)
 }
 
+func MakeEventUrl(calUrl string, evId string) string {
+	return calUrl + "/" + url.QueryEscape(evId)
+}
+
+func MakeEventUrl3(googleCalId string, evId string) string {
+	return MakeEventUrl("http://bigasterisk.com/calendar/"+
+		url.QueryEscape(googleCalId), evId)
+}
 func New(ctx context.Context) (*GCalClient, error) {
 	// If modifying these scopes, delete your previously saved token.json.
 	err, srv := newService(ctx)
@@ -37,9 +48,9 @@
 	// todo: disconnect watches if possible
 }
 
-func (gc *GCalClient) AllCalendars() ([]*calendar.CalendarListEntry, error) {
+func (gc *GCalClient) AllCalendars(maxResults int64) ([]*calendar.CalendarListEntry, error) {
 	// todo: pagination
-	list, err := gc.srv.CalendarList.List().MaxResults(100).Do()
+	list, err := gc.srv.CalendarList.List().MaxResults(maxResults).Do()
 	if err != nil {
 		return nil, err
 	}
@@ -48,31 +59,32 @@
 }
 
 // FindEvents considers all calendars
-func (gc *GCalClient) FindEvents(s time.Time) ([]*CalendarEvent, error) {
-	cals, err := gc.AllCalendars()
+func (gc *GCalClient) FindEvents(mc *mongoclient.MongoClient, s time.Time, maxEventsPerCalendar int64) ([]*CalendarEvent, error) {
+	cals, err := mc.GetAllCals()
 	if err != nil {
 		return nil, err
 	}
-
+	log.Println("reading", len(cals), "calendars")
 	ret := make([]*CalendarEvent, 0)
 	for _, cal := range cals {
-		calUrl := MakeCalUrl(cal.Id)
-		log.Println("  getting events from ", calUrl)
-		list, err := gc.srv.
-			Events.List(cal.Id).
-			ShowDeleted(false).
+		calUrl := cal.Url
+		events, err := gc.srv.
+		Events.List(cal.GoogleId).
+		ShowDeleted(false).
 			SingleEvents(true).
 			TimeMin(s.Format(time.RFC3339)).
-			MaxResults(2).
+			MaxResults(maxEventsPerCalendar).
 			OrderBy("startTime").
 			Do()
-		if err != nil {
-			return nil, err
-		}
-		for _, event := range list.Items {
+			if err != nil {
+				return nil, err
+			}
+		log.Println(len(events.Items), "events from", calUrl)
+		for _, event := range events.Items {
 			ev := &CalendarEvent{
 				Event:       event,
 				CalendarUrl: calUrl,
+				EventUrl:    MakeEventUrl(calUrl, event.Id),
 			}
 			ret = append(ret, ev)
 		}
--- a/calsync/mongoclient/cals_collection.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/mongoclient/cals_collection.go	Mon Aug 19 14:42:27 2024 -0700
@@ -69,7 +69,7 @@
 			continue
 		}
 		if !urlsToKeep[calUrl] {
-			log.Println("  cleaning up", calUrl)
+			log.Println("cleaning up", calUrl)
 			_, err = c.calsCollection.DeleteOne(c.ctx, bson.M{"_id": doc["_id"]})
 			if err != nil {
 				return err
--- a/calsync/mongoclient/events_collection.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/mongoclient/events_collection.go	Mon Aug 19 14:42:27 2024 -0700
@@ -2,6 +2,7 @@
 
 import (
 	"log"
+	"time"
 
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/mongo/options"
@@ -9,49 +10,20 @@
 
 func (c *MongoClient) UpsertOneEvent(ev MongoEvent) error {
 	filter := bson.M{"_id": ev.Url}
-	setFields := bson.M{
-		"googleId":    ev.GoogleId,
-		"lastUpdated": ev.LastUpdated,
-		"htmlLink":    ev.HtmlLink,
-		"title":       ev.Title,
-	}
+	setFields := ev
 	update := bson.M{"$set": setFields}
 	_, err := c.eventsCollection.UpdateOne(c.ctx, filter, update, options.Update().SetUpsert(true))
 	if err != nil {
 		return err
 	}
-	log.Println("  mongo upserted", ev.Url)
 	return nil
 }
 
-// func (c *MongoClient) FindEventsIntersecting(t1, t2 time.Time) ([]MongoEvent, error) {
-// 	cur, err := c.eventsCollection.Find(c.ctx, bson.M{
-// 		"end":   bson.M{"$gte": t1},
-// 		"start": bson.M{"$lte": t2},
-// 	}) // todo: allday evs
-// 	if err != nil {
-// 		return nil, err
-// 	}
-// 	defer cur.Close(c.ctx)
-
-// 	var events []MongoEvent
-// 	for cur.Next(c.ctx) {
-// 		var ev MongoEvent
-// 		if err := cur.Decode(&ev); err != nil {
-// 			return nil, err
-// 		}
-// 		events = append(events, ev)
-// 	}
-// 	return events, nil
-// }
-
-// func (c *MongoClient) CurrentEvents(now time.Time) ([]MongoEvent, error) {
-// 	return c.FindEventsIntersecting(now, now)
-// }
-// func (c *MongoClient) UpdateOrInsertEvent(ev MongoEvent) error {
-// 	return errors.New("todo")
-// }
-
-// func (c *MongoClient) DeleteEvent(ev MongoEvent) error {
-// 	return errors.New("todo")
-// }
+func (c *MongoClient) DeleteEventsUpdatedBefore(t time.Time) error {
+	res, err := c.eventsCollection.DeleteMany(c.ctx, bson.M{"lastUpdated": bson.M{"$lt": t}})
+	log.Println("deleted", res.DeletedCount, "events")
+	if err != nil {
+		return err
+	}
+	return nil
+}
--- a/calsync/mongoclient/mongoclient.go	Mon Aug 19 13:37:05 2024 -0700
+++ b/calsync/mongoclient/mongoclient.go	Mon Aug 19 14:42:27 2024 -0700
@@ -5,7 +5,6 @@
 	"log"
 	"time"
 
-	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/mongo"
 	"go.mongodb.org/mongo-driver/mongo/options"
 )
@@ -18,7 +17,6 @@
 	eventsCollection *mongo.Collection
 }
 
-
 // docs in eventsCollection
 type MongoEvent struct {
 	// e.g.
@@ -39,10 +37,9 @@
 
 	Url                string    `bson:"_id"`
 	GoogleId           string    `bson:"googleId"`
+	CalendarUrl        string    `bson:"calendarUrl"`
 	HtmlLink           string    `bson:"htmlLink"`
 	Title              string    `bson:"title"`
-	FeedId             string    `bson:"feedId"`
-	FeedTitle          string    `bson:"feedTitle"`
 	EndTimeUnspecified bool      `bson:"endTimeUnspecified"`
 	Start              string    `bson:"start"`
 	StartDate          string    `bson:"startDate"`