feat:#5 added free rooms api endpoint

This commit is contained in:
Elmar Kresse
2024-01-24 02:07:30 +01:00
parent 2430913a51
commit 4c16605bd6
8 changed files with 295 additions and 7 deletions

View File

@ -46,6 +46,27 @@ paths:
responses: responses:
'200': '200':
description: Successful response description: Successful response
/api/rooms/free:
get:
summary: Get Free Rooms
parameters:
- name: from
in: query
description: start date
example: "2006-01-02T15:04:05Z"
required: true
schema:
type: string
- name: to
in: query
description: end date
example: "2006-01-02T15:04:05Z"
required: true
schema:
type: string
responses:
'200':
description: Successful response
/api/schedule/day: /api/schedule/day:
get: get:
summary: Get Day Schedule summary: Get Day Schedule

View File

@ -5,6 +5,7 @@ import (
"htwkalender/service/fetch/sport" "htwkalender/service/fetch/sport"
v1 "htwkalender/service/fetch/v1" v1 "htwkalender/service/fetch/v1"
v2 "htwkalender/service/fetch/v2" v2 "htwkalender/service/fetch/v2"
"htwkalender/service/functions/time"
"htwkalender/service/ical" "htwkalender/service/ical"
"htwkalender/service/room" "htwkalender/service/room"
"log/slog" "log/slog"
@ -181,6 +182,39 @@ func AddRoutes(app *pocketbase.PocketBase) {
return nil return nil
}) })
// API Endpoint to get all rooms that have no events in a specific time frame
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
_, err := e.Router.AddRoute(echo.Route{
Method: http.MethodGet,
Path: "/api/rooms/free",
Handler: func(c echo.Context) error {
from, err := time.ParseTime(c.QueryParam("from"))
if err != nil {
slog.Error("Failed to parse time: %v", err)
return c.JSON(http.StatusBadRequest, "Failed to parse time")
}
to, err := time.ParseTime(c.QueryParam("to"))
if err != nil {
slog.Error("Failed to parse time: %v", err)
return c.JSON(http.StatusBadRequest, "Failed to parse time")
}
rooms, err := room.GetFreeRooms(app, from, to)
if err != nil {
slog.Error("Failed to get free rooms: %v", err)
return c.JSON(http.StatusBadRequest, "Failed to get free rooms")
}
return c.JSON(http.StatusOK, rooms)
},
Middlewares: []echo.MiddlewareFunc{
apis.ActivityLogger(app),
},
})
if err != nil {
return err
}
return nil
})
addFeedRoutes(app) addFeedRoutes(app)
app.OnBeforeServe().Add(func(e *core.ServeEvent) error { app.OnBeforeServe().Add(func(e *core.ServeEvent) error {

View File

@ -10,12 +10,12 @@ import (
"github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase"
) )
func SaveSeminarGroupEvents(seminarGroup []model.SeminarGroup, app *pocketbase.PocketBase) ([]model.Event, error) { func SaveSeminarGroupEvents(seminarGroups []model.SeminarGroup, app *pocketbase.PocketBase) ([]model.Event, error) {
var toBeSavedEvents model.Events var toBeSavedEvents model.Events
var savedRecords model.Events var savedRecords model.Events
// check if event is already in database and add to toBeSavedEvents if not // check if event is already in database and add to toBeSavedEvents if not
for _, seminarGroup := range seminarGroup { for _, seminarGroup := range seminarGroups {
for _, event := range seminarGroup.Events { for _, event := range seminarGroup.Events {
event = event.SetCourse(seminarGroup.Course) event = event.SetCourse(seminarGroup.Course)
existsInDatabase, err := findEventByDayWeekStartEndNameCourse(event, seminarGroup.Course, app) existsInDatabase, err := findEventByDayWeekStartEndNameCourse(event, seminarGroup.Course, app)
@ -254,3 +254,14 @@ func GetAllModulesByNameAndDateRange(app *pocketbase.PocketBase, name string, st
return events, nil return events, nil
} }
func GetEventsInTimeRange(app *pocketbase.PocketBase, from time.Time, to time.Time) (model.Events, error) {
var events model.Events
err := app.Dao().DB().Select("*").From("events").Where(dbx.NewExp("Start >= {:startDate} AND End <= {:endDate}", dbx.Params{"startDate": from, "endDate": to})).All(&events)
if err != nil {
return nil, err
}
return events, nil
}

View File

@ -47,9 +47,7 @@ func clearAndSeparateRooms(events []struct {
// sport rooms don't have to be separated // sport rooms don't have to be separated
if event.Course != "Sport" { if event.Course != "Sport" {
//split rooms by comma, tab, newline, carriage return, semicolon, space and non-breaking space //split rooms by comma, tab, newline, carriage return, semicolon, space and non-breaking space
room = strings.FieldsFunc(event.Rooms, functions.IsSeparator( room = functions.SeperateRoomString(event.Rooms)
[]rune{',', '\t', '\n', '\r', ';', ' ', '\u00A0'}),
)
} else { } else {
room = append(room, event.Rooms) room = append(room, event.Rooms)
} }

View File

@ -45,3 +45,9 @@ func HashString(s string) string {
hashInBytes := hash.Sum(nil) hashInBytes := hash.Sum(nil)
return hex.EncodeToString(hashInBytes) return hex.EncodeToString(hashInBytes)
} }
func SeperateRoomString(rooms string) []string {
return strings.FieldsFunc(rooms, IsSeparator(
[]rune{',', '\t', '\n', '\r', ';', ' ', '\u00A0'}),
)
}

View File

@ -0,0 +1,7 @@
package time
import "time"
func ParseTime(timeString string) (time.Time, error) {
return time.Parse("2006-01-02T15:04:05Z", timeString)
}

View File

@ -4,6 +4,8 @@ import (
"github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase"
"htwkalender/model" "htwkalender/model"
"htwkalender/service/db" "htwkalender/service/db"
"htwkalender/service/functions"
"time"
) )
func GetRooms(app *pocketbase.PocketBase) ([]string, error) { func GetRooms(app *pocketbase.PocketBase) ([]string, error) {
@ -41,3 +43,46 @@ func anonymizeRooms(events []model.Event) []model.AnonymizedEventDTO {
} }
return anonymizedEvents return anonymizedEvents
} }
func GetFreeRooms(app *pocketbase.PocketBase, from time.Time, to time.Time) ([]string, error) {
rooms, err := db.GetRooms(app)
if err != nil {
return nil, err
}
var events model.Events
events, err = db.GetEventsInTimeRange(app, from, to)
if err != nil {
return nil, err
}
freeRooms := removeRoomsThatHaveEvents(rooms, events)
return freeRooms, nil
}
func removeRoomsThatHaveEvents(rooms []string, schedule []model.Event) []string {
var freeRooms []string
for _, room := range rooms {
if !isRoomInSchedule(room, schedule) {
freeRooms = append(freeRooms, room)
}
}
return freeRooms
}
func isRoomInSchedule(room string, schedule []model.Event) bool {
for _, event := range schedule {
if event.Course != "Sport" {
rooms := functions.SeperateRoomString(event.Rooms)
// check if room is in rooms
for _, r := range rooms {
if r == room {
return true
}
}
} else {
if event.Rooms == room {
return true
}
}
}
return false
}

View File

@ -1,11 +1,10 @@
package room package room
import ( import (
"github.com/pocketbase/pocketbase/tools/types"
"htwkalender/model" "htwkalender/model"
"reflect" "reflect"
"testing" "testing"
"github.com/pocketbase/pocketbase/tools/types"
) )
func Test_anonymizeRooms(t *testing.T) { func Test_anonymizeRooms(t *testing.T) {
@ -123,3 +122,170 @@ func Test_anonymizeRooms(t *testing.T) {
}) })
} }
} }
func Test_isRoomInSchedule(t *testing.T) {
type args struct {
room string
schedule []model.Event
}
tests := []struct {
name string
args args
want bool
}{
{
name: "room is in schedule",
args: args{
room: "Room",
schedule: []model.Event{
{
UUID: "testUUID",
Day: "Montag",
Week: "52",
Start: types.DateTime{},
End: types.DateTime{},
Name: "Secret",
EventType: "V",
Prof: "Prof. Dr. Secret",
Rooms: "Room",
Notes: "Secret",
},
},
},
want: true,
},
{
name: "room is not in schedule",
args: args{
room: "Z324",
schedule: []model.Event{
{
UUID: "testUUID",
Day: "Montag",
Week: "52",
Start: types.DateTime{},
End: types.DateTime{},
Name: "Secret",
EventType: "V",
Prof: "Prof. Dr. Bond",
Rooms: "LI007",
Notes: "Keine Zeit für die Uni",
},
},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := isRoomInSchedule(tt.args.room, tt.args.schedule); got != tt.want {
t.Errorf("isRoomInSchedule() = %v, want %v", got, tt.want)
}
})
}
}
func Test_getFreeRooms(t *testing.T) {
type args struct {
rooms []string
schedule []model.Event
}
tests := []struct {
name string
args args
want []string
}{
{
name: "remove room1 from list",
args: args{
rooms: []string{
"Room1",
"Room2",
"Room3",
},
schedule: []model.Event{
{
UUID: "testUUID",
Day: "Montag",
Week: "52",
Start: types.DateTime{},
End: types.DateTime{},
Name: "Secret",
EventType: "V",
Prof: "Prof. Dr. Secret",
Rooms: "Room1",
Notes: "Secret",
},
},
},
want: []string{
"Room2",
"Room3",
},
},
{
name: "remove room2 from list",
args: args{
rooms: []string{
"Room1",
"Room2",
"Room3",
},
schedule: []model.Event{
{
UUID: "testUUID",
Day: "Montag",
Week: "52",
Start: types.DateTime{},
End: types.DateTime{},
Name: "Secret",
EventType: "V",
Prof: "Prof. Dr. Secret",
Rooms: "Room3",
Notes: "Secret",
},
},
},
want: []string{
"Room1",
"Room2",
},
},
{
name: "remove no room from list",
args: args{
rooms: []string{
"Room1",
"Room2",
"Room3",
},
schedule: []model.Event{
{
UUID: "testUUID",
Day: "Montag",
Week: "52",
Start: types.DateTime{},
End: types.DateTime{},
Name: "Secret",
EventType: "V",
Prof: "Prof. Dr. Secret",
Rooms: "Room4",
Notes: "Secret",
},
},
},
want: []string{
"Room1",
"Room2",
"Room3",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := removeRoomsThatHaveEvents(tt.args.rooms, tt.args.schedule); !reflect.DeepEqual(got, tt.want) {
t.Errorf("removeRoomsThatHaveEvents() = %v, want %v", got, tt.want)
}
})
}
}