Skip to content

Commit 4223f32

Browse files
TyHiljpahmrecursiveTurtle
authored
Rooms and events route (#247)
* Events route * Include start and end time in response * Generic events hierarchy * Forgot a rename * rooms controller * change collection name --------- Co-authored-by: Josh <20374744+jpahm@users.noreply.github.com> Co-authored-by: recursiveTurtle <recursiveturtle25@gmail.com>
1 parent a1ba446 commit 4223f32

File tree

8 files changed

+214
-0
lines changed

8 files changed

+214
-0
lines changed

api/controllers/events.go

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"time"
7+
8+
"github.com/UTDNebula/nebula-api/api/common/log"
9+
"github.com/UTDNebula/nebula-api/api/configs"
10+
"github.com/UTDNebula/nebula-api/api/responses"
11+
"github.com/UTDNebula/nebula-api/api/schema"
12+
13+
"github.com/gin-gonic/gin"
14+
15+
"go.mongodb.org/mongo-driver/bson"
16+
"go.mongodb.org/mongo-driver/mongo"
17+
)
18+
19+
var eventsCollection *mongo.Collection = configs.GetCollection("events")
20+
21+
// @Id events
22+
// @Router /events/{date} [get]
23+
// @Description "Returns all sections with meetings on the specified date"
24+
// @Produce json
25+
// @Param date path string true "ISO date of the set of events to get"
26+
// @Success 200 {array} schema.MultiBuildingEvents[schema.SectionWithTime] "All sections with meetings on the specified date"
27+
func Events(c *gin.Context) {
28+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
29+
30+
date := c.Param("date")
31+
32+
var events schema.MultiBuildingEvents[schema.SectionWithTime]
33+
34+
defer cancel()
35+
36+
// find and parse matching date
37+
err := eventsCollection.FindOne(ctx, bson.M{"date": date}).Decode(&events)
38+
if err != nil {
39+
log.WriteError(err)
40+
c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()})
41+
return
42+
}
43+
44+
c.JSON(http.StatusOK, responses.MultiBuildingEventsResponse[schema.SectionWithTime]{Status: http.StatusOK, Message: "success", Data: events})
45+
}
46+
47+
// @Id eventsByBuilding
48+
// @Router /events/{date}/{building} [get]
49+
// @Description "Returns all sections with meetings on the specified date in the specified building"
50+
// @Produce json
51+
// @Param date path string true "ISO date of the set of events to get"
52+
// @Param building path string true "building abbreviation of event locations"
53+
// @Success 200 {array} schema.SingleBuildingEvents[schema.SectionWithTime] "All sections with meetings on the specified date in the specified building"
54+
func EventsByBuilding(c *gin.Context) {
55+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
56+
57+
date := c.Param("date")
58+
building := c.Param("building")
59+
60+
var events schema.MultiBuildingEvents[schema.SectionWithTime]
61+
var eventsByBuilding schema.SingleBuildingEvents[schema.SectionWithTime]
62+
63+
defer cancel()
64+
65+
// find and parse matching date
66+
err := eventsCollection.FindOne(ctx, bson.M{"date": date}).Decode(&events)
67+
if err != nil {
68+
log.WriteError(err)
69+
c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()})
70+
return
71+
}
72+
73+
// filter for the specified building
74+
for _, b := range events.Buildings {
75+
if b.Building == building {
76+
eventsByBuilding = b
77+
break
78+
}
79+
}
80+
81+
// If no building is found, return an error
82+
if eventsByBuilding.Building == "" {
83+
c.JSON(http.StatusNotFound, responses.ErrorResponse{
84+
Status: http.StatusNotFound,
85+
Message: "error",
86+
Data: "No events found for the specified building",
87+
})
88+
return
89+
}
90+
91+
c.JSON(http.StatusOK, responses.SingleBuildingEventsResponse[schema.SectionWithTime]{Status: http.StatusOK, Message: "success", Data: eventsByBuilding})
92+
}

api/controllers/rooms.go

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package controllers
2+
3+
import (
4+
"context"
5+
"net/http"
6+
"time"
7+
8+
"github.com/gin-gonic/gin"
9+
10+
"go.mongodb.org/mongo-driver/bson"
11+
"go.mongodb.org/mongo-driver/mongo"
12+
13+
"github.com/UTDNebula/nebula-api/api/configs"
14+
"github.com/UTDNebula/nebula-api/api/responses"
15+
"github.com/UTDNebula/nebula-api/api/schema"
16+
)
17+
18+
var buildingCollection *mongo.Collection = configs.GetCollection("rooms")
19+
20+
// @Id rooms
21+
// @Router /rooms [get]
22+
// @Description "Returns all classrooms being used in the current and futures semesters"
23+
// @Produce json
24+
// @Success 200 {array} schema.BuildingRooms "All classrooms being used in the current and futures semesters"
25+
func Rooms(c *gin.Context) {
26+
//gin context has info about request and allows converting to json format
27+
28+
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
29+
defer cancel() //make resources available if Rooms returns before timeout
30+
31+
var buildingRooms []schema.BuildingRooms //buildings and rooms to be returned
32+
33+
//cursor is the pointer for the returned documents
34+
cursor, err := buildingCollection.Find(ctx, bson.M{})
35+
36+
//if there is an error
37+
if err != nil {
38+
//serialize ErrorResponse struct data into JSON format
39+
c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()})
40+
return
41+
}
42+
43+
//use cursor to fill rooms slice to return
44+
err = cursor.All(ctx, &buildingRooms)
45+
46+
//if there is an error filling rooms slice
47+
if err != nil {
48+
c.JSON(http.StatusInternalServerError, responses.ErrorResponse{Status: http.StatusInternalServerError, Message: "error", Data: err.Error()})
49+
return
50+
}
51+
52+
//serialize RoomsResponse struct data into JSON format
53+
c.JSON(http.StatusOK, responses.RoomsResponse{Status: http.StatusOK, Message: "success", Data: buildingRooms})
54+
}

api/responses/events_response.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package responses
2+
3+
import "github.com/UTDNebula/nebula-api/api/schema"
4+
5+
type MultiBuildingEventsResponse[T any] struct {
6+
Status int `json:"status"`
7+
Message string `json:"message"`
8+
Data schema.MultiBuildingEvents[T] `json:"data"`
9+
}
10+
11+
type SingleBuildingEventsResponse[T any] struct {
12+
Status int `json:"status"`
13+
Message string `json:"message"`
14+
Data schema.SingleBuildingEvents[T] `json:"data"`
15+
}

api/responses/rooms_response.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package responses
2+
3+
import "github.com/UTDNebula/nebula-api/api/schema"
4+
5+
type RoomsResponse struct {
6+
Status int `json:"status"`
7+
Message string `json:"message"`
8+
Data []schema.BuildingRooms `json:"data"`
9+
}

api/routes/events.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package routes
2+
3+
import (
4+
"github.com/gin-gonic/gin"
5+
6+
"github.com/UTDNebula/nebula-api/api/controllers"
7+
)
8+
9+
func EventsRoute(router *gin.Engine) {
10+
// All routes related to sections come here
11+
eventsGroup := router.Group("/events")
12+
13+
eventsGroup.OPTIONS("", controllers.Preflight)
14+
eventsGroup.GET(":date", controllers.Events)
15+
eventsGroup.GET(":date/:building", controllers.EventsByBuilding)
16+
}

api/routes/rooms.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package routes
2+
3+
import (
4+
"github.com/gin-gonic/gin"
5+
6+
"github.com/UTDNebula/nebula-api/api/controllers"
7+
)
8+
9+
func RoomsRoute(router *gin.Engine) {
10+
// All routes related to sections come here
11+
roomsGroup := router.Group("/rooms")
12+
13+
roomsGroup.OPTIONS("", controllers.Preflight)
14+
roomsGroup.GET("", controllers.Rooms)
15+
}

api/schema/objects.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ type RoomEvents[T any] struct {
133133
}
134134

135135
// Event types
136+
type SectionWithTime struct {
137+
Section primitive.ObjectID `bson:"section" json:"section"`
138+
StartTime string `bson:"start_time" json:"start_time"`
139+
EndTime string `bson:"end_time" json:"end_time"`
140+
}
136141
type AstraEvent struct {
137142
ActivityName *string `bson:"activity_name" json:"activity_name"`
138143
MeetingType *string `bson:"meeting_type" json:"meeting_type"`
@@ -144,6 +149,12 @@ type AstraEvent struct {
144149
Capacity *float64 `bson:"capacity" json:"capacity"`
145150
}
146151

152+
// Rooms type
153+
type BuildingRooms struct {
154+
Building string `bson:"building" json:"building"`
155+
Rooms []string `bson:"rooms" json:"rooms"`
156+
}
157+
147158
// 5 Level Likert Item scale for evaluation responses
148159
type EvaluationResponse int
149160

api/server.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ func main() {
6060
routes.GradesRoute(router)
6161
routes.AutocompleteRoute(router)
6262
routes.StorageRoute(router)
63+
routes.RoomsRoute(router)
64+
routes.EventsRoute(router)
6365

6466
// Retrieve the port string to serve traffic on
6567
portString := configs.GetPortString()

0 commit comments

Comments
 (0)