feat:#34 refactored function to intended service, fixed docker files

This commit is contained in:
Elmar Kresse
2024-06-10 16:57:40 +02:00
parent cb76b5c188
commit 2d7701b0c9
96 changed files with 212 additions and 79 deletions

View File

@@ -0,0 +1,54 @@
//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU Affero General Public License for more details.
//You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>.
package events
import (
"github.com/pocketbase/pocketbase"
"htwkalender/service/db"
"htwkalender/service/functions"
)
func GetAllCourses(app *pocketbase.PocketBase) []string {
return db.GetAllCourses(app)
}
func GetAllCoursesForSemester(app *pocketbase.PocketBase, semester string) []string {
return db.GetAllCoursesForSemester(app, semester)
}
func GetAllCoursesForSemesterWithEvents(app *pocketbase.PocketBase, semester string) ([]string, error) {
courses, err := db.GetAllCoursesForSemesterWithEvents(app, semester)
if err != nil {
return nil, err
} else {
// remove empty courses like " " or ""
courses = removeEmptyCourses(courses)
return courses, nil
}
}
// removeEmptyCourses removes empty courses from the list of courses
func removeEmptyCourses(courses []string) []string {
var filteredCourses []string
for index, course := range courses {
if !functions.OnlyWhitespace(course) || len(course) != 0 {
filteredCourses = append(filteredCourses, courses[index])
}
}
return filteredCourses
}

View File

@@ -0,0 +1,55 @@
//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU Affero General Public License for more details.
//You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>.
package events
import (
"reflect"
"testing"
)
func Test_removeEmptyCourses(t *testing.T) {
type args struct {
courses []string
}
tests := []struct {
name string
args args
want []string
}{
{
name: "Test remove empty courses",
args: args{
courses: []string{"", "test", "test2", ""},
},
want: []string{"test", "test2"},
},
{
name: "Test remove empty courses",
args: args{
courses: []string{"", "test", "test2", "", "test3"},
},
want: []string{"test", "test2", "test3"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := removeEmptyCourses(tt.args.courses); !reflect.DeepEqual(got, tt.want) {
t.Errorf("removeEmptyCourses() = %v, want %v", got, tt.want)
}
})
}
}

View File

@@ -0,0 +1,215 @@
//Calendar implementation for the HTWK Leipzig timetable. Evaluation and display of the individual dates in iCal format.
//Copyright (C) 2024 HTWKalender support@htwkalender.de
//This program is free software: you can redistribute it and/or modify
//it under the terms of the GNU Affero General Public License as published by
//the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.
//This program is distributed in the hope that it will be useful,
//but WITHOUT ANY WARRANTY; without even the implied warranty of
//MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
//GNU Affero General Public License for more details.
//You should have received a copy of the GNU Affero General Public License
//along with this program. If not, see <https://www.gnu.org/licenses/>.
package events
import (
"github.com/pocketbase/pocketbase"
"htwkalender/model"
"htwkalender/service/db"
"htwkalender/service/fetch/v1"
"htwkalender/service/functions"
"log/slog"
"strconv"
)
func GetModulesForCourseDistinct(app *pocketbase.PocketBase, course string, semester string) (model.Events, error) {
modules, err := db.GetAllModulesForCourse(app, course, semester)
// Convert the []model.Module to []Named
var namedEvents []Named
for _, module := range modules {
namedEvents = append(namedEvents, &module)
}
replaceEmptyEntry(namedEvents, "Sonderveranstaltungen")
return modules, err
}
type Named interface {
GetName() string
SetName(name string)
}
// replaceEmptyEntry replaces an empty entry in a module with a replacement string
// If the module is not empty, nothing happens
func replaceEmptyEntry(namedList []Named, replacement string) {
for i, namedItem := range namedList {
if functions.OnlyWhitespace(namedItem.GetName()) {
namedList[i].SetName(replacement)
}
}
}
// GetAllModulesDistinct returns all modules distinct by name and course from the database
// That means you get all modules with duplicates if they have different courses
func GetAllModulesDistinct(app *pocketbase.PocketBase) ([]model.ModuleDTO, error) {
modules, err := db.GetAllModulesDistinctByNameAndCourse(app)
if err != nil {
return nil, err
}
var namedModules []Named
for _, module := range modules {
namedModules = append(namedModules, &module)
}
replaceEmptyEntry(namedModules, "Sonderveranstaltungen")
return modules, nil
}
func GetModuleByUUID(app *pocketbase.PocketBase, uuid string) (model.Module, error) {
module, findModuleErr := db.FindModuleByUUID(app, uuid)
if findModuleErr != nil {
return model.Module{}, findModuleErr
}
events, findEventsError := db.FindAllEventsByModule(app, module)
if findEventsError != nil || len(events) == 0 {
return model.Module{}, findEventsError
} else {
return model.Module{
UUID: events[0].UUID,
Name: events[0].Name,
Events: events,
Prof: events[0].Prof,
Course: events[0].Course,
Semester: events[0].Semester,
}, nil
}
}
// DeleteAllEventsByCourseAndSemester deletes all events for a course and a semester
// If the deletion was successful, nil is returned
// If the deletion was not successful, an error is returned
func DeleteAllEventsByCourseAndSemester(app *pocketbase.PocketBase, course string, semester string) error {
err := db.DeleteAllEventsByCourse(app, course, semester)
if err != nil {
return err
} else {
return nil
}
}
func DeleteAllEvents(app *pocketbase.PocketBase) error {
err := db.DeleteAllEvents(app)
if err != nil {
return err
} else {
return nil
}
}
// UpdateModulesForCourse updates all modules for a course
// Does Updates for ws and ss semester sequentially
// Update runs through the following steps:
// 1. Delete all events for the course and the semester
// 2. Fetch all events for the course and the semester
// 3. Save all events for the course and the semester
// If the update was successful, nil is returned
// If the update was not successful, an error is returned
func UpdateModulesForCourse(app *pocketbase.PocketBase, course string) (model.Events, error) {
seminarGroup := v1.GetSeminarGroupEventsFromHTML(course)
seminarGroup = v1.ClearEmptySeminarGroups(seminarGroup)
seminarGroup = v1.ReplaceEmptyEventNames(seminarGroup)
//check if events in the seminarGroups Events are already in the database
//if yes, keep the database as it is
//if no, delete all events for the course and the semester and save the new events
//if there are no events in the database, save the new events
//get all events for the course and the semester
dbEvents, err := db.GetAllEventsForCourse(app, course)
if err != nil {
return nil, err
}
//if there are no events in the database, save the new events
if len(dbEvents) == 0 {
events, dbError := db.SaveSeminarGroupEvents(seminarGroup, app)
if dbError != nil {
return nil, dbError
}
return events, nil
}
// Create partial update list and delete list for the events
var insertList model.Events
var deleteList model.Events
// check which events are not already in the database and need to be inserted/saved
for _, event := range seminarGroup.Events {
if !ContainsEvent(dbEvents, event) {
insertList = append(insertList, event)
}
}
// check which events are in the database but not in the seminarGroup and need to be deleted
for _, dbEvent := range dbEvents {
if !ContainsEvent(seminarGroup.Events, dbEvent) {
deleteList = append(deleteList, dbEvent)
}
}
// delete all events that are in the deleteList
err = db.DeleteEvents(deleteList, app)
if err != nil {
slog.Error("Failed to delete events:", "error", err)
return nil, err
}
// save all events that are in the insertList
savedEvents, err := db.SaveEvents(insertList, app)
if err != nil {
slog.Error("Failed to save events: ", "error", err)
return nil, err
}
slog.Info("Course: " + course + " - Event changes: " + strconv.FormatInt(int64(len(insertList)), 10) + " new events, " + strconv.FormatInt(int64(len(deleteList)), 10) + " deleted events")
return savedEvents, nil
}
func ContainsEvent(events model.Events, event model.Event) bool {
for _, e := range events {
if e.Name == event.Name &&
e.Prof == event.Prof &&
e.Rooms == event.Rooms &&
e.Semester == event.Semester &&
e.Start == event.Start &&
e.End == event.End &&
e.Course == event.Course {
return true
}
}
return false
}
func GetEventTypes(app *pocketbase.PocketBase) ([]string, error) {
dbEventTypes, err := db.GetAllEventTypes(app)
if err != nil {
return nil, err
}
// Convert the []model.EventType to []string
var eventTypes []string
for _, eventType := range dbEventTypes {
eventTypes = append(eventTypes, eventType.EventType)
}
return eventTypes, nil
}

View File

@@ -0,0 +1,58 @@
package events
import (
"htwkalender/model"
"testing"
)
func TestContainsEvent(t *testing.T) {
type args struct {
events model.Events
event model.Event
}
tests := []struct {
name string
args args
want bool
}{
{
name: "contains event",
args: args{
events: model.Events{
{
UUID: "934807509832475",
Name: "name",
},
},
event: model.Event{
UUID: "934807509832475",
Name: "name",
},
},
want: true,
},
{
name: "contains no event",
args: args{
events: model.Events{
{
UUID: "9991929292921912343534",
Name: "Name1",
},
},
event: model.Event{
UUID: "1111112312312312",
Name: "Name2",
},
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := ContainsEvent(tt.args.events, tt.args.event); got != tt.want {
t.Errorf("ContainsEvent() = %v, want %v", got, tt.want)
}
})
}
}