diff --git a/api/controllers/events.go b/api/controllers/events.go new file mode 100644 index 00000000..3eb6c84f --- /dev/null +++ b/api/controllers/events.go @@ -0,0 +1,92 @@ +package controllers + +import ( + "context" + "net/http" + "time" + + "github.com/UTDNebula/nebula-api/api/common/log" + "github.com/UTDNebula/nebula-api/api/configs" + "github.com/UTDNebula/nebula-api/api/responses" + "github.com/UTDNebula/nebula-api/api/schema" + + "github.com/gin-gonic/gin" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +var eventsCollection *mongo.Collection = configs.GetCollection("events") + +// @Id events +// @Router /events/{date} [get] +// @Description "Returns all sections with meetings on the specified date" +// @Produce json +// @Param date path string true "ISO date of the set of events to get" +// @Success 200 {array} schema.MultiBuildingEvents[schema.SectionWithTime] "All sections with meetings on the specified date" +func Events(c *gin.Context) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + date := c.Param("date") + + var events schema.MultiBuildingEvents[schema.SectionWithTime] + + defer cancel() + + // find and parse matching date + err := eventsCollection.FindOne(ctx, bson.M{"date": date}).Decode(&events) + if err != nil { + log.WriteError(err) + c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()}) + return + } + + c.JSON(http.StatusOK, responses.MultiBuildingEventsResponse[schema.SectionWithTime]{Status: http.StatusOK, Message: "success", Data: events}) +} + +// @Id eventsByBuilding +// @Router /events/{date}/{building} [get] +// @Description "Returns all sections with meetings on the specified date in the specified building" +// @Produce json +// @Param date path string true "ISO date of the set of events to get" +// @Param building path string true "building abbreviation of event locations" +// @Success 200 {array} schema.SingleBuildingEvents[schema.SectionWithTime] "All sections with meetings on the specified date in the specified building" +func EventsByBuilding(c *gin.Context) { + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + + date := c.Param("date") + building := c.Param("building") + + var events schema.MultiBuildingEvents[schema.SectionWithTime] + var eventsByBuilding schema.SingleBuildingEvents[schema.SectionWithTime] + + defer cancel() + + // find and parse matching date + err := eventsCollection.FindOne(ctx, bson.M{"date": date}).Decode(&events) + if err != nil { + log.WriteError(err) + c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()}) + return + } + + // filter for the specified building + for _, b := range events.Buildings { + if b.Building == building { + eventsByBuilding = b + break + } + } + + // If no building is found, return an error + if eventsByBuilding.Building == "" { + c.JSON(http.StatusNotFound, responses.ErrorResponse{ + Status: http.StatusNotFound, + Message: "error", + Data: "No events found for the specified building", + }) + return + } + + c.JSON(http.StatusOK, responses.SingleBuildingEventsResponse[schema.SectionWithTime]{Status: http.StatusOK, Message: "success", Data: eventsByBuilding}) +} diff --git a/api/controllers/rooms.go b/api/controllers/rooms.go new file mode 100644 index 00000000..8a2d286b --- /dev/null +++ b/api/controllers/rooms.go @@ -0,0 +1,54 @@ +package controllers + +import ( + "context" + "net/http" + "time" + + "github.com/gin-gonic/gin" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + + "github.com/UTDNebula/nebula-api/api/configs" + "github.com/UTDNebula/nebula-api/api/responses" + "github.com/UTDNebula/nebula-api/api/schema" +) + +var buildingCollection *mongo.Collection = configs.GetCollection("rooms") + +// @Id rooms +// @Router /rooms [get] +// @Description "Returns all classrooms being used in the current and futures semesters" +// @Produce json +// @Success 200 {array} schema.BuildingRooms "All classrooms being used in the current and futures semesters" +func Rooms(c *gin.Context) { + //gin context has info about request and allows converting to json format + + ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) + defer cancel() //make resources available if Rooms returns before timeout + + var buildingRooms []schema.BuildingRooms //buildings and rooms to be returned + + //cursor is the pointer for the returned documents + cursor, err := buildingCollection.Find(ctx, bson.M{}) + + //if there is an error + if err != nil { + //serialize ErrorResponse struct data into JSON format + c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()}) + return + } + + //use cursor to fill rooms slice to return + err = cursor.All(ctx, &buildingRooms) + + //if there is an error filling rooms slice + if err != nil { + c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()}) + return + } + + //serialize RoomsResponse struct data into JSON format + c.JSON(http.StatusOK, responses.RoomsResponse{Status: http.StatusOK, Message: "success", Data: buildingRooms}) +} diff --git a/api/responses/events_response.go b/api/responses/events_response.go new file mode 100644 index 00000000..a9a80c12 --- /dev/null +++ b/api/responses/events_response.go @@ -0,0 +1,15 @@ +package responses + +import "github.com/UTDNebula/nebula-api/api/schema" + +type MultiBuildingEventsResponse[T any] struct { + Status int `json:"status"` + Message string `json:"message"` + Data schema.MultiBuildingEvents[T] `json:"data"` +} + +type SingleBuildingEventsResponse[T any] struct { + Status int `json:"status"` + Message string `json:"message"` + Data schema.SingleBuildingEvents[T] `json:"data"` +} diff --git a/api/responses/rooms_response.go b/api/responses/rooms_response.go new file mode 100644 index 00000000..6453353d --- /dev/null +++ b/api/responses/rooms_response.go @@ -0,0 +1,9 @@ +package responses + +import "github.com/UTDNebula/nebula-api/api/schema" + +type RoomsResponse struct { + Status int `json:"status"` + Message string `json:"message"` + Data []schema.BuildingRooms `json:"data"` +} diff --git a/api/routes/events.go b/api/routes/events.go new file mode 100644 index 00000000..7efb100b --- /dev/null +++ b/api/routes/events.go @@ -0,0 +1,16 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + + "github.com/UTDNebula/nebula-api/api/controllers" +) + +func EventsRoute(router *gin.Engine) { + // All routes related to sections come here + eventsGroup := router.Group("/events") + + eventsGroup.OPTIONS("", controllers.Preflight) + eventsGroup.GET(":date", controllers.Events) + eventsGroup.GET(":date/:building", controllers.EventsByBuilding) +} diff --git a/api/routes/rooms.go b/api/routes/rooms.go new file mode 100644 index 00000000..1a95f1bf --- /dev/null +++ b/api/routes/rooms.go @@ -0,0 +1,15 @@ +package routes + +import ( + "github.com/gin-gonic/gin" + + "github.com/UTDNebula/nebula-api/api/controllers" +) + +func RoomsRoute(router *gin.Engine) { + // All routes related to sections come here + roomsGroup := router.Group("/rooms") + + roomsGroup.OPTIONS("", controllers.Preflight) + roomsGroup.GET("", controllers.Rooms) +} diff --git a/api/schema/objects.go b/api/schema/objects.go index b61de413..f0a598cf 100644 --- a/api/schema/objects.go +++ b/api/schema/objects.go @@ -133,6 +133,11 @@ type RoomEvents[T any] struct { } // Event types +type SectionWithTime struct { + Section primitive.ObjectID `bson:"section" json:"section"` + StartTime string `bson:"start_time" json:"start_time"` + EndTime string `bson:"end_time" json:"end_time"` +} type AstraEvent struct { ActivityName *string `bson:"activity_name" json:"activity_name"` MeetingType *string `bson:"meeting_type" json:"meeting_type"` @@ -144,6 +149,12 @@ type AstraEvent struct { Capacity *float64 `bson:"capacity" json:"capacity"` } +// Rooms type +type BuildingRooms struct { + Building string `bson:"building" json:"building"` + Rooms []string `bson:"rooms" json:"rooms"` +} + // 5 Level Likert Item scale for evaluation responses type EvaluationResponse int diff --git a/api/server.go b/api/server.go index cde5fd14..95fc2e59 100644 --- a/api/server.go +++ b/api/server.go @@ -60,6 +60,8 @@ func main() { routes.GradesRoute(router) routes.AutocompleteRoute(router) routes.StorageRoute(router) + routes.RoomsRoute(router) + routes.EventsRoute(router) // Retrieve the port string to serve traffic on portString := configs.GetPortString()