diff --git a/backend/model/eventModel.go b/backend/model/eventModel.go index 355e594..098c88a 100644 --- a/backend/model/eventModel.go +++ b/backend/model/eventModel.go @@ -2,6 +2,7 @@ package model import ( "slices" + "strings" "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tools/types" @@ -13,21 +14,30 @@ func (m Events) Contains(event Event) bool { return slices.Contains(m, event) } +type AnonymizedEventDTO struct { + Day string `db:"Day" json:"day"` + Week string `db:"Week" json:"week"` + Start types.DateTime `db:"start" json:"start"` + End types.DateTime `db:"end" json:"end"` + Rooms string `db:"Rooms" json:"rooms"` + Free bool `json:"free"` +} + type Event struct { - UUID string `db:"uuid" json:"uuid"` - Day string `db:"Day" json:"day"` - Week string `db:"Week" json:"week"` - Start types.DateTime `db:"start" json:"start"` - End types.DateTime `db:"end" json:"end"` - Name string `db:"Name" json:"name"` - EventType string `db:"EventType" json:"eventType"` - Compulsory string `db:"Compulsory" json:"compulsory"` - Prof string `db:"Prof" json:"prof"` - Rooms string `db:"Rooms" json:"rooms"` - Notes string `db:"Notes" json:"notes"` - BookedAt string `db:"BookedAt" json:"bookedAt"` - Course string `db:"course" json:"course"` - Semester string `db:"semester" json:"semester"` + UUID string `db:"uuid" json:"uuid"` + Day string `db:"Day" json:"day"` + Week string `db:"Week" json:"week"` + Start types.DateTime `db:"start" json:"start"` + End types.DateTime `db:"end" json:"end"` + Name string `db:"Name" json:"name"` + EventType string `db:"EventType" json:"eventType"` + Compulsory string `db:"Compulsory" json:"compulsory"` + Prof string `db:"Prof" json:"prof"` + Rooms string `db:"Rooms" json:"rooms"` + Notes string `db:"Notes" json:"notes"` + BookedAt string `db:"BookedAt" json:"bookedAt"` + Course string `db:"course" json:"course"` + Semester string `db:"semester" json:"semester"` models.BaseModel } @@ -52,3 +62,15 @@ func (m *Event) SetCourse(course string) Event { m.Course = course return *m } + +// Creates an AnonymizedEventDTO from an Event hiding all sensitive data +func (m *Event) AnonymizeEvent() AnonymizedEventDTO { + return AnonymizedEventDTO{ + Day: m.Day, + Week: m.Week, + Start: m.Start, + End: m.End, + Rooms: m.Rooms, + Free: strings.Contains(strings.ToLower(m.Name), "zur freien verfügung"), + } +} diff --git a/backend/model/eventModel_test.go b/backend/model/eventModel_test.go index 4462f4e..9608ba5 100644 --- a/backend/model/eventModel_test.go +++ b/backend/model/eventModel_test.go @@ -1,6 +1,7 @@ package model import ( + "reflect" "testing" "github.com/pocketbase/pocketbase/models" @@ -126,3 +127,73 @@ func TestEvent_Equals(t *testing.T) { }) } } + +func TestEvent_AnonymizeEvent(t *testing.T) { + type fields struct { + UUID string + Day string + Week string + Start types.DateTime + End types.DateTime + Name string + EventType string + Compulsory string + Prof string + Rooms string + Notes string + BookedAt string + Course string + Semester string + BaseModel models.BaseModel + } + tests := []struct { + name string + fields fields + want AnonymizedEventDTO + }{ + { + name: "empty event", + fields: fields{}, + want: AnonymizedEventDTO{Day: "", Week: "", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "", Free: false}, + }, + { + name: "one event", + fields: fields{Name: "Event", Day: "test", Week: "test", Rooms: "test"}, + want: AnonymizedEventDTO{Day: "test", Week: "test", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "test", Free: false}, + }, + { + name: "one event with free", + fields: fields{Name: "Räume zur freien Verfügung", Day: "test", Week: "test", Rooms: "test", Course: "test"}, + want: AnonymizedEventDTO{Day: "test", Week: "test", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "test", Free: true}, + }, + { + name: "another free event", + fields: fields{Name: "Zur freien Verfügung", Day: "Montag", Week: "5", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "TR_A1.28-S", Course: "42INM-3"}, + want: AnonymizedEventDTO{Day: "Montag", Week: "5", Start: types.DateTime{}, End: types.DateTime{}, Rooms: "TR_A1.28-S", Free: true}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + m := &Event{ + UUID: tt.fields.UUID, + Day: tt.fields.Day, + Week: tt.fields.Week, + Start: tt.fields.Start, + End: tt.fields.End, + Name: tt.fields.Name, + EventType: tt.fields.EventType, + Compulsory: tt.fields.Compulsory, + Prof: tt.fields.Prof, + Rooms: tt.fields.Rooms, + Notes: tt.fields.Notes, + BookedAt: tt.fields.BookedAt, + Course: tt.fields.Course, + Semester: tt.fields.Semester, + BaseModel: tt.fields.BaseModel, + } + if got := m.AnonymizeEvent(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Event.AnonymizeEvent() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/backend/service/room/roomService.go b/backend/service/room/roomService.go index 198b2dd..320bfea 100644 --- a/backend/service/room/roomService.go +++ b/backend/service/room/roomService.go @@ -1,10 +1,12 @@ package room import ( - "github.com/labstack/echo/v5" - "github.com/pocketbase/pocketbase" + "htwkalender/model" "htwkalender/service/db" "net/http" + + "github.com/labstack/echo/v5" + "github.com/pocketbase/pocketbase" ) func GetRooms(c echo.Context, app *pocketbase.PocketBase) error { @@ -14,10 +16,19 @@ func GetRooms(c echo.Context, app *pocketbase.PocketBase) error { func GetRoomScheduleForDay(c echo.Context, app *pocketbase.PocketBase, room string, date string) error { events := db.GetRoomScheduleForDay(app, room, date) - return c.JSON(http.StatusOK, events) + return c.JSON(http.StatusOK, anonymizeRooms(events)) } func GetRoomSchedule(c echo.Context, app *pocketbase.PocketBase, room string, from string, to string) error { events := db.GetRoomSchedule(app, room, from, to) - return c.JSON(http.StatusOK, events) + return c.JSON(http.StatusOK, anonymizeRooms(events)) +} + +// Transform the events to anonymized events throwing away all unnecessary information +func anonymizeRooms(events []model.Event) []model.AnonymizedEventDTO { + var anonymizedEvents = []model.AnonymizedEventDTO{} + for _, event := range events { + anonymizedEvents = append(anonymizedEvents, event.AnonymizeEvent()) + } + return anonymizedEvents } diff --git a/backend/service/room/roomService_test.go b/backend/service/room/roomService_test.go new file mode 100644 index 0000000..34345b8 --- /dev/null +++ b/backend/service/room/roomService_test.go @@ -0,0 +1,125 @@ +package room + +import ( + "htwkalender/model" + "reflect" + "testing" + + "github.com/pocketbase/pocketbase/tools/types" +) + +func Test_anonymizeRooms(t *testing.T) { + type args struct { + events []model.Event + } + tests := []struct { + name string + args args + want []model.AnonymizedEventDTO + }{ + { + name: "anonymize single event", + args: args{ + events: []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", + BookedAt: "Secret", + Course: "42INM-3", + Semester: "ws", + Compulsory: "p", + }, + }, + }, + want: []model.AnonymizedEventDTO{ + { + Day: "Montag", + Week: "52", + Start: types.DateTime{}, + End: types.DateTime{}, + Rooms: "Room", + Free: false, + }, + }, + }, + { + name: "anonymize empty list", + args: args{ + events: []model.Event{}, + }, + want: []model.AnonymizedEventDTO{}, + }, + { + name: "anonymize multiple events", + args: args{ + events: []model.Event{ + { + UUID: "testUUID1", + Day: "Montag", + Week: "51", + Start: types.DateTime{}, + End: types.DateTime{}, + Name: "Incognito", + EventType: "V", + Prof: "Prof. Dr. Incognito", + Rooms: "Room", + Notes: "Incognito", + BookedAt: "Incognito", + Course: "69INM-2", + Semester: "sose", + Compulsory: "p", + }, + { + UUID: "testUUID2", + Day: "Dienstag", + Week: "52", + Start: types.DateTime{}, + End: types.DateTime{}, + Name: "Private", + EventType: "S", + Prof: "Prof.In. Dr.-Ing. Private", + Rooms: "Room", + Notes: "Private", + BookedAt: "Private", + Course: "42MIM-3", + Semester: "ws", + Compulsory: "w", + }, + }, + }, + want: []model.AnonymizedEventDTO{ + { + Day: "Montag", + Week: "51", + Start: types.DateTime{}, + End: types.DateTime{}, + Rooms: "Room", + Free: false, + }, + { + Day: "Dienstag", + Week: "52", + Start: types.DateTime{}, + End: types.DateTime{}, + Rooms: "Room", + Free: false, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := anonymizeRooms(tt.args.events); !reflect.DeepEqual(got, tt.want) { + t.Errorf("anonymizeRooms() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/frontend/src/api/fetchRoom.ts b/frontend/src/api/fetchRoom.ts index 1ca7caa..9163d6a 100644 --- a/frontend/src/api/fetchRoom.ts +++ b/frontend/src/api/fetchRoom.ts @@ -1,4 +1,4 @@ -import { Event } from "../model/event.ts"; +import { AnonymizedEventDTO } from "../model/event.ts"; export async function fetchRoom(): Promise { const rooms: string[] = []; @@ -16,8 +16,8 @@ export async function fetchEventsByRoomAndDuration( room: string, from_date: string, to_date: string, -): Promise { - const events: Event[] = []; +): Promise { + const events: AnonymizedEventDTO[] = []; await fetch( "/api/schedule?room=" + room + "&from=" + from_date + "&to=" + to_date, ) @@ -27,7 +27,7 @@ export async function fetchEventsByRoomAndDuration( }) .then((eventsResponse) => { console.log("Response:", eventsResponse); - eventsResponse.forEach((event: Event) => events.push(event)); + eventsResponse.forEach((event: AnonymizedEventDTO) => events.push(event)); }) .catch((error) => { console.log("Error fetching events: ", error); diff --git a/frontend/src/components/RoomOccupation.vue b/frontend/src/components/RoomOccupation.vue index 96fb947..ed294a9 100644 --- a/frontend/src/components/RoomOccupation.vue +++ b/frontend/src/components/RoomOccupation.vue @@ -52,7 +52,7 @@ async function getOccupation() { id: index, start: event.start.replace(/\s\+\d{4}\s\w+$/, "").replace(" ", "T"), end: event.end.replace(/\s\+\d{4}\s\w+$/, "").replace(" ", "T"), - showFree: event.name.toLowerCase().includes("zur freien verfügung"), + showFree: event.free }; }); diff --git a/frontend/src/model/event.ts b/frontend/src/model/event.ts index b9164d3..e4df3e9 100644 --- a/frontend/src/model/event.ts +++ b/frontend/src/model/event.ts @@ -14,3 +14,14 @@ export class Event { public week: string, ) {} } + +export class AnonymizedEventDTO { + constructor( + public day: string, + public week: string, + public start: string, + public end: string, + public rooms: string, + public free: boolean + ) {} +}