aboutsummaryrefslogtreecommitdiff
path: root/cmd/mi
diff options
context:
space:
mode:
authorXe Iaso <me@xeiaso.net>2024-05-24 15:31:51 -0400
committerXe Iaso <me@xeiaso.net>2024-05-24 15:32:30 -0400
commitc3b8a7a5f9276b62cc3a93b1720f8c1c7d60c6eb (patch)
tree4a7fc94c5df7bd8545758144f1968c0192d78326 /cmd/mi
parent042eb1851d06597ca91a83a9cf93d4135efe1096 (diff)
downloadx-c3b8a7a5f9276b62cc3a93b1720f8c1c7d60c6eb.tar.xz
x-c3b8a7a5f9276b62cc3a93b1720f8c1c7d60c6eb.zip
cmd/mi: add event tracking
Signed-off-by: Xe Iaso <me@xeiaso.net>
Diffstat (limited to 'cmd/mi')
-rw-r--r--cmd/mi/main.go2
-rw-r--r--cmd/mi/models/dao.go7
-rw-r--r--cmd/mi/models/events.go60
-rw-r--r--cmd/mi/services/events/events.go70
4 files changed, 138 insertions, 1 deletions
diff --git a/cmd/mi/main.go b/cmd/mi/main.go
index 1be0734..42d8d70 100644
--- a/cmd/mi/main.go
+++ b/cmd/mi/main.go
@@ -11,6 +11,7 @@ import (
"github.com/prometheus/client_golang/prometheus/promhttp"
"golang.org/x/sync/errgroup"
"within.website/x/cmd/mi/models"
+ "within.website/x/cmd/mi/services/events"
"within.website/x/cmd/mi/services/homefrontshim"
"within.website/x/cmd/mi/services/importer"
"within.website/x/cmd/mi/services/posse"
@@ -74,6 +75,7 @@ func main() {
mux.Handle(announce.AnnouncePathPrefix, announce.NewAnnounceServer(ann))
mux.Handle(pb.SwitchTrackerPathPrefix, pb.NewSwitchTrackerServer(switchtracker.New(dao)))
+ mux.Handle(pb.EventsPathPrefix, pb.NewEventsServer(events.New(dao)))
mux.Handle("/front", homefrontshim.New(dao))
i := importer.New(dao)
diff --git a/cmd/mi/models/dao.go b/cmd/mi/models/dao.go
index e747a0d..3241d5e 100644
--- a/cmd/mi/models/dao.go
+++ b/cmd/mi/models/dao.go
@@ -46,7 +46,12 @@ func New(dbLoc string) (*DAO, error) {
return nil, fmt.Errorf("failed to connect to database: %w", err)
}
- if err := db.AutoMigrate(&Member{}, &Switch{}, &Blogpost{}); err != nil {
+ if err := db.AutoMigrate(
+ &Member{},
+ &Switch{},
+ &Blogpost{},
+ &Event{},
+ ); err != nil {
return nil, fmt.Errorf("failed to migrate schema: %w", err)
}
diff --git a/cmd/mi/models/events.go b/cmd/mi/models/events.go
new file mode 100644
index 0000000..c4239b2
--- /dev/null
+++ b/cmd/mi/models/events.go
@@ -0,0 +1,60 @@
+package models
+
+import (
+ "context"
+ "time"
+
+ "google.golang.org/protobuf/types/known/timestamppb"
+ "gorm.io/gorm"
+ pb "within.website/x/proto/mi"
+)
+
+// Event represents an event that members of DevRel will be attending.
+type Event struct {
+ gorm.Model
+ ID int `gorm:"primaryKey"`
+ Name string
+ URL string
+ StartDate time.Time
+ EndDate time.Time
+ Location string `gorm:"index"`
+ Description string
+}
+
+func (e *Event) AsProto() *pb.Event {
+ return &pb.Event{
+ Id: int32(e.ID),
+ Name: e.Name,
+ Url: e.URL,
+ StartDate: timestamppb.New(e.StartDate),
+ EndDate: timestamppb.New(e.EndDate),
+ Location: e.Location,
+ Description: e.Description,
+ }
+}
+
+func (d *DAO) CreateEvent(ctx context.Context, event *Event) (*Event, error) {
+ return event, d.db.WithContext(ctx).Create(event).Error
+}
+
+func (d *DAO) GetEvent(ctx context.Context, id int) (*Event, error) {
+ var event Event
+ if err := d.db.WithContext(ctx).Where("id = ?", id).First(&event).Error; err != nil {
+ return nil, err
+ }
+
+ return &event, nil
+}
+
+func (d *DAO) UpcomingEvents(ctx context.Context, count int) ([]Event, error) {
+ var events []Event
+ if err := d.db.
+ WithContext(ctx).
+ Where("end_date >= ?", time.Now()).
+ Limit(count).
+ Find(&events).Error; err != nil {
+ return nil, err
+ }
+
+ return events, nil
+}
diff --git a/cmd/mi/services/events/events.go b/cmd/mi/services/events/events.go
new file mode 100644
index 0000000..bbc1015
--- /dev/null
+++ b/cmd/mi/services/events/events.go
@@ -0,0 +1,70 @@
+package events
+
+import (
+ "context"
+ "errors"
+ "log/slog"
+
+ "github.com/twitchtv/twirp"
+ "google.golang.org/protobuf/types/known/emptypb"
+ "gorm.io/gorm"
+ "within.website/x/cmd/mi/models"
+ pb "within.website/x/proto/mi"
+)
+
+type Events struct {
+ dao *models.DAO
+}
+
+var _ pb.Events = &Events{}
+
+// New creates a new Events service.
+func New(dao *models.DAO) *Events {
+ return &Events{dao: dao}
+}
+
+// Get fetches upcoming events.
+func (e *Events) Get(ctx context.Context, _ *emptypb.Empty) (*pb.EventFeed, error) {
+ events, err := e.dao.UpcomingEvents(ctx, 10)
+ if err != nil {
+ slog.Error("can't fetch upcoming events", "err", err)
+ switch {
+ case errors.Is(err, gorm.ErrRecordNotFound):
+ return nil, twirp.NotFoundError("can't find any events")
+ default:
+ return nil, twirp.InternalErrorWith(err)
+ }
+ }
+
+ if len(events) == 0 {
+ return nil, twirp.NotFoundError("can't find any events")
+ }
+
+ var pbEvents []*pb.Event
+ for _, event := range events {
+ pbEvents = append(pbEvents, event.AsProto())
+ }
+
+ return &pb.EventFeed{Events: pbEvents}, nil
+}
+
+// Add adds a new event to the database.
+func (e *Events) Add(ctx context.Context, ev *pb.Event) (*emptypb.Empty, error) {
+ event := &models.Event{
+ Name: ev.Name,
+ URL: ev.Url,
+ StartDate: ev.StartDate.AsTime(),
+ EndDate: ev.EndDate.AsTime(),
+ Location: ev.Location,
+ Description: ev.Description,
+ }
+
+ _, err := e.dao.CreateEvent(ctx, event)
+ if err != nil {
+ return nil, err
+ }
+
+ slog.Info("tracking new event", "event", event)
+
+ return &emptypb.Empty{}, nil
+}