Merge branch '11-missing-modules-with-multiple-courses-in-get-api-modules' into 'main'

Resolve "Missing modules with multiple courses in GET /api/modules"

Closes #11

See merge request ekresse/htwkalender!6
This commit is contained in:
ekresse
2024-01-16 00:24:25 +00:00
6 changed files with 129 additions and 69 deletions

View File

@@ -1,4 +1,4 @@
FROM golang:1.21-alpine FROM golang:1.21.6
# Set the Current Working Directory inside the container # Set the Current Working Directory inside the container
WORKDIR /app WORKDIR /app
@@ -12,7 +12,7 @@ COPY *.go ./
COPY . . COPY . .
# Build the Go app # Build the Go app
RUN CGO_ENABLED=0 GOOS=linux go build -o /htwkalender RUN CGO_ENABLED=1 GOOS=linux go build -o /htwkalender
# Expose port 8080 to the outside world # Expose port 8080 to the outside world
EXPOSE 8080 EXPOSE 8080

View File

@@ -41,36 +41,44 @@ type Event struct {
models.BaseModel models.BaseModel
} }
func (m *Event) Equals(event Event) bool { func (e *Event) Equals(event Event) bool {
return m.Day == event.Day && return e.Day == event.Day &&
m.Week == event.Week && e.Week == event.Week &&
m.Start == event.Start && e.Start == event.Start &&
m.End == event.End && e.End == event.End &&
m.Name == event.Name && e.Name == event.Name &&
m.Course == event.Course && e.Course == event.Course &&
m.Prof == event.Prof && e.Prof == event.Prof &&
m.Rooms == event.Rooms && e.Rooms == event.Rooms &&
m.EventType == event.EventType e.EventType == event.EventType
} }
func (m *Event) TableName() string { func (e *Event) TableName() string {
return "events" return "events"
} }
// SetCourse func to set the course and returns the event // SetCourse func to set the course and returns the event
func (m *Event) SetCourse(course string) Event { func (e *Event) SetCourse(course string) Event {
m.Course = course e.Course = course
return *m return *e
} }
// Creates an AnonymizedEventDTO from an Event hiding all sensitive data // Creates an AnonymizedEventDTO from an Event hiding all sensitive data
func (m *Event) AnonymizeEvent() AnonymizedEventDTO { func (e *Event) AnonymizeEvent() AnonymizedEventDTO {
return AnonymizedEventDTO{ return AnonymizedEventDTO{
Day: m.Day, Day: e.Day,
Week: m.Week, Week: e.Week,
Start: m.Start, Start: e.Start,
End: m.End, End: e.End,
Rooms: m.Rooms, Rooms: e.Rooms,
Free: strings.Contains(strings.ToLower(m.Name), "zur freien verfügung"), Free: strings.Contains(strings.ToLower(e.Name), "zur freien verfügung"),
} }
} }
func (e *Event) GetName() string {
return e.Name
}
func (e *Event) SetName(name string) {
e.Name = name
}

View File

@@ -8,3 +8,24 @@ type Module struct {
Semester string `json:"semester" db:"semester"` Semester string `json:"semester" db:"semester"`
Events Events `json:"events"` Events Events `json:"events"`
} }
func (m *Module) SetName(name string) {
m.Name = name
}
type ModuleDTO struct {
UUID string `json:"uuid" db:"uuid"`
Name string `json:"name" db:"Name"`
Prof string `json:"prof" db:"Prof"`
Course string `json:"course" db:"course"`
Semester string `json:"semester" db:"semester"`
EventType string `db:"EventType" json:"eventType"`
}
func (m *ModuleDTO) GetName() string {
return m.Name
}
func (m *ModuleDTO) SetName(name string) {
m.Name = name
}

View File

@@ -189,16 +189,16 @@ func GetAllModulesForCourse(app *pocketbase.PocketBase, course string, semester
return events, nil return events, nil
} }
func GetAllModulesDistinctByNameAndCourse(app *pocketbase.PocketBase) (model.Events, error) { func GetAllModulesDistinctByNameAndCourse(app *pocketbase.PocketBase) ([]model.ModuleDTO, error) {
var events model.Events var modules []model.ModuleDTO
err := app.Dao().DB().Select("*").From("events").GroupBy("Name").Distinct(true).All(&events) err := app.Dao().DB().Select("Name", "EventType", "Prof", "course", "semester", "uuid").From("events").GroupBy("Name", "Course").Distinct(true).All(&modules)
if err != nil { if err != nil {
print("Error while getting events from database: ", err) print("Error while getting events from database: ", err)
return nil, err return nil, err
} }
return events, nil return modules, nil
} }
func DeleteAllEventsForCourse(app *pocketbase.PocketBase, course string, semester string) error { func DeleteAllEventsForCourse(app *pocketbase.PocketBase, course string, semester string) error {

View File

@@ -13,17 +13,28 @@ import (
func GetModulesForCourseDistinct(app *pocketbase.PocketBase, course string, semester string) (model.Events, error) { func GetModulesForCourseDistinct(app *pocketbase.PocketBase, course string, semester string) (model.Events, error) {
modules, err := db.GetAllModulesForCourse(app, course, semester) modules, err := db.GetAllModulesForCourse(app, course, semester)
replaceEmptyEntry(modules, "Sonderveranstaltungen")
// Convert the []model.Module to []Named
var namedEvents []Named
for _, module := range modules {
namedEvents = append(namedEvents, &module)
}
replaceEmptyEntry(namedEvents, "Sonderveranstaltungen")
return modules, err return modules, err
} }
type Named interface {
GetName() string
SetName(name string)
}
// replaceEmptyEntry replaces an empty entry in a module with a replacement string // replaceEmptyEntry replaces an empty entry in a module with a replacement string
// If the module is not empty, nothing happens // If the module is not empty, nothing happens
func replaceEmptyEntry(modules model.Events, replacement string) { func replaceEmptyEntry(namedList []Named, replacement string) {
for i, namedItem := range namedList {
for i, module := range modules { if functions.OnlyWhitespace(namedItem.GetName()) {
if functions.OnlyWhitespace(module.Name) { namedList[i].SetName(replacement)
modules[i].Name = replacement
} }
} }
} }
@@ -33,7 +44,12 @@ func replaceEmptyEntry(modules model.Events, replacement string) {
func GetAllModulesDistinct(app *pocketbase.PocketBase, c echo.Context) error { func GetAllModulesDistinct(app *pocketbase.PocketBase, c echo.Context) error {
modules, err := db.GetAllModulesDistinctByNameAndCourse(app) modules, err := db.GetAllModulesDistinctByNameAndCourse(app)
replaceEmptyEntry(modules, "Sonderveranstaltungen") var namedModules []Named
for _, module := range modules {
namedModules = append(namedModules, &module)
}
replaceEmptyEntry(namedModules, "Sonderveranstaltungen")
if err != nil { if err != nil {
return c.JSON(400, err) return c.JSON(400, err)

View File

@@ -1,57 +1,72 @@
#user nobody;
worker_processes 1; worker_processes 1;
#error_log logs/error.log; error_log /var/log/nginx/error.log;
#error_log logs/error.log notice; pid /var/run/nginx.pid;
#error_log logs/error.log info;
#pid logs/nginx.pid;
events { events {
worker_connections 1024; worker_connections 1024;
} }
http { http {
include mime.types; include mime.types;
default_type application/octet-stream; default_type application/octet-stream;
#log_format main '$remote_addr - $remote_user [$time_local] "$request" '
# '$status $body_bytes_sent "$http_referer" '
# '"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/proxy_access.log; access_log /var/log/nginx/proxy_access.log;
error_log /var/log/nginx/proxy_error.log; error_log /var/log/nginx/proxy_error.log;
sendfile on; sendfile on;
#tcp_nopush on;
#keepalive_timeout 0;
keepalive_timeout 180s; keepalive_timeout 180s;
send_timeout 180s; send_timeout 180s;
#gzip on; map $request_method $cache_bypass {
default 0;
POST 1;
}
server { proxy_cache_path /dev/shm levels=1:2 keys_zone=mcache:16m inactive=600s max_size=512m;
listen 80; proxy_cache_methods GET HEAD;
server_name frontend; proxy_cache_min_uses 1;
proxy_cache_key "$request_method$host$request_uri";
proxy_cache_use_stale timeout updating;
proxy_ignore_headers Cache-Control Expires Set-Cookie;
location /api { server {
proxy_pass http://htwkalender-backend:8090; listen 80;
client_max_body_size 20m; server_name frontend;
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
}
location /_ { location /api {
proxy_pass http://htwkalender-backend:8090; proxy_pass http://htwkalender-backend:8090;
} client_max_body_size 20m;
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
}
location / { # Cache only specific URI
proxy_pass http://htwkalender-frontend:8000; location /api/modules {
} proxy_pass http://htwkalender-backend:8090;
} client_max_body_size 20m;
proxy_connect_timeout 600s;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;
proxy_cache_bypass 0;
proxy_no_cache 0;
proxy_cache mcache; # mcache=RAM
proxy_cache_valid 200 301 302 30m;
proxy_cache_valid 403 404 5m;
proxy_cache_lock on;
proxy_cache_use_stale timeout updating;
add_header X-Proxy-Cache $upstream_cache_status;
}
location /_ {
proxy_pass http://htwkalender-backend:8090;
}
location / {
proxy_pass http://htwkalender-frontend:8000;
}
}
} }