Skip to content

Commit

Permalink
Merge pull request #427 from sinfo/feature/schedule
Browse files Browse the repository at this point in the history
adds calendar functionality to schedule
  • Loading branch information
PMax5 authored Apr 9, 2024
2 parents f8b6bf4 + f377df3 commit b95fab6
Show file tree
Hide file tree
Showing 10 changed files with 255 additions and 21 deletions.
2 changes: 1 addition & 1 deletion backend/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.12

require (
cloud.google.com/go v0.46.3 // indirect
github.com/arran4/golang-ical v0.2.7
github.com/dgrijalva/jwt-go v3.2.0+incompatible
github.com/digitalocean/godo v1.19.0
github.com/google/uuid v1.3.0
Expand All @@ -23,7 +24,6 @@ require (
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45
golang.org/x/sys v0.1.0 // indirect
google.golang.org/appengine v1.6.2 // indirect
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
gopkg.in/ini.v1 v1.46.0 // indirect
gotest.tools v0.0.0-20181223230014-1083505acf35
)
8 changes: 8 additions & 0 deletions backend/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAE
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/arran4/golang-ical v0.2.7 h1:VO7YlVaGupZE15aj6NhUhte/MIfZuoIzkoI71VsG6Gg=
github.com/arran4/golang-ical v0.2.7/go.mod h1:RqMuPGmwRRwjkb07hmm+JBqcWa1vF1LvVmPtSZN2OhQ=
github.com/aws/aws-sdk-go v1.34.28 h1:sscPpn/Ns3i0F4HPEWAVcwdIRaZZCuL7llJ2/60yPIk=
github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
Expand All @@ -27,6 +29,7 @@ github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand Down Expand Up @@ -140,6 +143,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
Expand All @@ -154,6 +158,7 @@ github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQz
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
Expand Down Expand Up @@ -209,6 +214,7 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
Expand Down Expand Up @@ -362,6 +368,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/ini.v1 v1.41.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.46.0 h1:VeDZbLYGaupuvIrsYCEOe/L/2Pcs5n7hdO1ZTjporag=
Expand All @@ -374,6 +381,7 @@ gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools v0.0.0-20181223230014-1083505acf35 h1:zpdCK+REwbk+rqjJmHhiCN6iBIigrZ39glqSF0P3KF0=
gotest.tools v0.0.0-20181223230014-1083505acf35/go.mod h1:R//lfYlUuTOTfblYI3lGoAAAebUdzjvbmQsuB7Ykd90=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
Expand Down
3 changes: 3 additions & 0 deletions backend/src/models/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ type Event struct {

// Teams is an array of Team_id (see models.Team).
Teams []primitive.ObjectID `json:"teams" bson:"teams"`

// Calendar is a link to the event's calendar.
CalendarUrl string `json:"calendarUrl" bson:"calendarUrl"`
}

// DurationInDays returns the duration of the event in days.
Expand Down
42 changes: 34 additions & 8 deletions backend/src/mongodb/event.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,14 +120,15 @@ func (e *EventsType) CreateEvent(data CreateEventData) (*models.Event, error) {
}

var c = bson.M{
"_id": latestEvent.ID + 1,
"name": data.Name,
"themes": make([]string, 0),
"packages": make([]models.EventPackages, 0),
"items": make([]primitive.ObjectID, 0),
"meetings": make([]primitive.ObjectID, 0),
"sessions": make([]primitive.ObjectID, 0),
"teams": make([]primitive.ObjectID, 0),
"_id": latestEvent.ID + 1,
"name": data.Name,
"themes": make([]string, 0),
"packages": make([]models.EventPackages, 0),
"items": make([]primitive.ObjectID, 0),
"meetings": make([]primitive.ObjectID, 0),
"sessions": make([]primitive.ObjectID, 0),
"teams": make([]primitive.ObjectID, 0),
"calendarUrl": "",
}

insertResult, err := e.Collection.InsertOne(ctx, c)
Expand Down Expand Up @@ -779,3 +780,28 @@ func (e *EventsType) RemoveTeam(eventID int, teamID primitive.ObjectID) (*models

return &updatedEvent, nil
}

// Func that updates event calendar
func (e *EventsType) UpdateCalendar(eventID int, calendarUrl string) (*models.Event, error) {
ctx := context.Background()

var updateQuery = bson.M{
"$set": bson.M{
"calendarUrl": calendarUrl,
},
}

var filterQuery = bson.M{"_id": eventID}

var optionsQuery = options.FindOneAndUpdate()
optionsQuery.SetReturnDocument(options.After)

var updatedEvent models.Event

if err := e.Collection.FindOneAndUpdate(ctx, filterQuery, updateQuery, optionsQuery).Decode(&updatedEvent); err != nil {
log.Println("error updating event's calendar:", err)
return nil, err
}

return &updatedEvent, nil
}
111 changes: 108 additions & 3 deletions backend/src/router/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,14 @@ import (
"log"
"net/http"
"strconv"
"strings"
"time"

ics "github.com/arran4/golang-ical"
"github.com/gorilla/mux"
"github.com/sinfo/deck2/src/models"
"github.com/sinfo/deck2/src/mongodb"
"github.com/sinfo/deck2/src/spaces"
"go.mongodb.org/mongo-driver/bson/primitive"
)

Expand Down Expand Up @@ -498,21 +501,123 @@ func removeTeamFromEvent(w http.ResponseWriter, r *http.Request) {
currentEvent, err := mongodb.Events.GetCurrentEvent()

if err != nil {
http.Error(w, "Could not find current event: " + err.Error(), http.StatusNotFound)
http.Error(w, "Could not find current event: "+err.Error(), http.StatusNotFound)
return
}

if _, err = mongodb.Teams.GetTeam(teamID); err != nil {
http.Error(w, "Could not find team: " + err.Error(), http.StatusNotFound)
http.Error(w, "Could not find team: "+err.Error(), http.StatusNotFound)
return
}

updatedEvent, err := mongodb.Events.RemoveTeam(currentEvent.ID, teamID)

if err != nil {
http.Error(w, "Could not remove team from event: " + err.Error(), http.StatusExpectationFailed)
http.Error(w, "Could not remove team from event: "+err.Error(), http.StatusExpectationFailed)
return
}

json.NewEncoder(w).Encode(updatedEvent)
}

func updateCalendar(w http.ResponseWriter, r *http.Request) {

defer r.Body.Close()

currentEvent, err := mongodb.Events.GetCurrentEvent()
if err != nil {
http.Error(w, "Could not find current event: "+err.Error(), http.StatusNotFound)
return
}

sessions, err := mongodb.Sessions.GetPublicSessions(mongodb.GetSessionsPublicOptions{})
if err != nil {
http.Error(w, "Could not get sessions: "+err.Error(), http.StatusExpectationFailed)
return
}

calendar := ics.NewCalendar()
calendar.SetMethod(ics.MethodRequest)
calendar.SetProductId("-//deck.sinfo.org//deck//EN")
calendar.SetXWRCalName(fmt.Sprintf("SINFO %d Sessions", currentEvent.ID))
calendar.SetVersion("3.0")

for _, session := range sessions {
event := calendar.AddEvent(fmt.Sprintf("sinfo-%d-%s", currentEvent.ID, session.ID.Hex()))
event.SetCreatedTime(time.Now())
event.SetDtStampTime(time.Now())

// makes session names more readable
kind := session.Kind
sessionKind := "Session"

if kind == "TALK" {
sessionKind = "Keynote"
} else if kind == "WORKSHOP" {
sessionKind = "Workshop"
} else if kind == "PRESENTATION" {
sessionKind = "Presentation"
}

// sets summary of event differently depending on the kind of session
if kind == "WORKSHOP" || kind == "PRESENTATION" {
event.SetSummary(fmt.Sprintf("%s - %s", session.CompanyPublic.Name, sessionKind))
} else {
speakerNames := ""

// in case of a panel with more than one speaker
for _, speaker := range *session.SpeakersPublic {
speakerNames += speaker.Name + ", "
}

// remove last comma
speakerNames = speakerNames[:len(speakerNames)-2]

event.SetSummary(fmt.Sprintf("%s - %s", speakerNames, sessionKind))
}

event.SetDescription(fmt.Sprintf("%s Title:\n%s\n\nDescription:\n%s", sessionKind, session.Title, session.Description))
event.SetLocation(session.Place)
event.SetStartAt(session.Begin)
event.SetEndAt(session.End)
}

// get size of calendar file
calendarString := calendar.Serialize()
calendarReader := strings.NewReader(calendarString)
size := int64(calendarReader.Len())

url, err := spaces.UploadCalendarFile(currentEvent.ID, calendarReader, size, "text/calendar")
if err != nil {
http.Error(w, fmt.Sprintf("Couldn't upload file: %v", err), http.StatusExpectationFailed)
return
}

updatedEvent, err := mongodb.Events.UpdateCalendar(currentEvent.ID, *url)
if err != nil {
http.Error(w, "Could not update event's calendar: "+err.Error(), http.StatusExpectationFailed)
return
}

json.NewEncoder(w).Encode(updatedEvent)
}

func getEventCalendar(w http.ResponseWriter, r *http.Request) {

defer r.Body.Close()

currentEvent, err := mongodb.Events.GetCurrentEvent()

if err != nil {
http.Error(w, "Could not find event: "+err.Error(), http.StatusNotFound)
return
}

// check if calendar file exists
if currentEvent.CalendarUrl == "" {
http.Error(w, "Calendar file not found", http.StatusNotFound)
return
}

http.Redirect(w, r, currentEvent.CalendarUrl, http.StatusPermanentRedirect)
}
2 changes: 2 additions & 0 deletions backend/src/router/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ func InitializeRouter() {
publicRouter.HandleFunc("/sessions/{id}", getSessionPublic).Methods("GET")
publicRouter.HandleFunc("/speakers/{id}", getSpeakerPublic).Methods("GET")
publicRouter.HandleFunc("/events/latest", getLatestEvent).Methods("GET")
publicRouter.HandleFunc("/calendar.ics", getEventCalendar).Methods("GET")

// auth handlers
authRouter := r.PathPrefix("/auth").Subrouter()
Expand Down Expand Up @@ -221,6 +222,7 @@ func InitializeRouter() {
eventRouter.HandleFunc("/meetings/{id}", authTeamLeader(removeMeetingFromEvent)).Methods("DELETE")
eventRouter.HandleFunc("/sessions", authCoordinator(addSessionToEvent)).Methods("POST")
eventRouter.HandleFunc("/teams/{id}", authAdmin(removeTeamFromEvent)).Methods("DELETE")
eventRouter.HandleFunc("/updateCalendar", authCoordinator(updateCalendar)).Methods("GET")

// team handlers
teamRouter := r.PathPrefix("/teams").Subrouter()
Expand Down
15 changes: 15 additions & 0 deletions backend/src/spaces/calendar.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package spaces

import (
"fmt"
"io"
)

const (
calendarPath = "calendar"
)

func UploadCalendarFile(event int, reader io.Reader, objectSize int64, MIME string) (*string, error) {
path := fmt.Sprintf("sinfo-%d/%s", event, calendarPath)
return uploadImage(path, reader, objectSize, MIME)
}
8 changes: 8 additions & 0 deletions frontend/lib/models/event.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ class Event {

ItemService _itemService = ItemService();

String? calendarUrl;

Event({
required this.id,
required this.name,
required this.start,
required this.end,
this.itemIds,
required this.eventPackagesId,
this.calendarUrl,
});

Future<List<Item>?> get items async {
Expand Down Expand Up @@ -55,6 +58,7 @@ class Event {
end: DateTime.parse(json['end']),
itemIds: List.from(json['items']),
eventPackagesId: evPackages.map((e) => EventPackage.fromJson(e)).toList(),
calendarUrl: json['calendar_url'],
);
}

Expand All @@ -65,6 +69,7 @@ class Event {
'end': end,
'items': itemIds,
'packages': eventPackagesId.map((e) => e.toJson()).toList(),
'calendar_url': calendarUrl,
};

@override
Expand All @@ -90,13 +95,15 @@ class EventPublic {
final DateTime start;
final DateTime end;
final List<String> themes;
final String? calendarUrl;

EventPublic({
required this.id,
required this.name,
required this.start,
required this.end,
required this.themes,
this.calendarUrl,
});

factory EventPublic.fromJson(Map<String, dynamic> json) {
Expand All @@ -106,6 +113,7 @@ class EventPublic {
start: DateTime.parse(json['begin']),
end: DateTime.parse(json['end']),
themes: json['themes'] as List<String>,
calendarUrl: json['calendar_url'],
);
}
}
Expand Down
Loading

0 comments on commit b95fab6

Please sign in to comment.