mirror of
https://gitlab.dit.htwk-leipzig.de/htwk-software/htwkalender.git
synced 2025-07-16 09:38:49 +02:00
update fetch and fixed bug
This commit is contained in:
25
addRoute.go
25
addRoute.go
@ -7,10 +7,16 @@ import (
|
||||
"github.com/pocketbase/pocketbase/core"
|
||||
"htwk-planner/service"
|
||||
"net/http"
|
||||
"os"
|
||||
)
|
||||
|
||||
func addRoutes(app *pocketbase.PocketBase) {
|
||||
|
||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||
e.Router.GET("/*", apis.StaticDirectoryHandler(os.DirFS("./pb_public"), false))
|
||||
return nil
|
||||
})
|
||||
|
||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||
_, err := e.Router.AddRoute(echo.Route{
|
||||
Method: http.MethodGet,
|
||||
@ -25,7 +31,6 @@ func addRoutes(app *pocketbase.PocketBase) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
@ -34,7 +39,7 @@ func addRoutes(app *pocketbase.PocketBase) {
|
||||
Method: http.MethodGet,
|
||||
Path: "/api/fetchGroups",
|
||||
Handler: func(c echo.Context) error {
|
||||
return service.FetchSeminarGroups(c)
|
||||
return service.FetchSeminarGroups(c, app)
|
||||
},
|
||||
Middlewares: []echo.MiddlewareFunc{
|
||||
apis.ActivityLogger(app),
|
||||
@ -43,7 +48,23 @@ func addRoutes(app *pocketbase.PocketBase) {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
|
||||
_, err := e.Router.AddRoute(echo.Route{
|
||||
Method: http.MethodGet,
|
||||
Path: "/api/rooms",
|
||||
Handler: func(c echo.Context) error {
|
||||
return service.GetRooms(c, app)
|
||||
},
|
||||
Middlewares: []echo.MiddlewareFunc{
|
||||
apis.ActivityLogger(app),
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
|
10
pb_public/index.html
Normal file
10
pb_public/index.html
Normal file
@ -0,0 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>HTWKalender</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
105
pb_schema.json
105
pb_schema.json
@ -55,6 +55,95 @@
|
||||
"requireEmail": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "cfq9mqlmd97v8z5",
|
||||
"name": "groups",
|
||||
"type": "base",
|
||||
"system": false,
|
||||
"schema": [
|
||||
{
|
||||
"id": "85msl21p",
|
||||
"name": "university",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "2sii4dtp",
|
||||
"name": "shortcut",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "uiwgo28f",
|
||||
"name": "groupId",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "y0l1lrzs",
|
||||
"name": "course",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "kr62mhbz",
|
||||
"name": "faculty",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ya6znpez",
|
||||
"name": "facultyId",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [
|
||||
"CREATE UNIQUE INDEX `idx_rcaN2Oq` ON `groups` (`course`)"
|
||||
],
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
"updateRule": null,
|
||||
"deleteRule": null,
|
||||
"options": {}
|
||||
},
|
||||
{
|
||||
"id": "7her4515qsmrxe8",
|
||||
"name": "events",
|
||||
@ -180,9 +269,23 @@
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "vyyefxp7",
|
||||
"name": "course",
|
||||
"type": "text",
|
||||
"system": false,
|
||||
"required": false,
|
||||
"options": {
|
||||
"min": null,
|
||||
"max": null,
|
||||
"pattern": ""
|
||||
}
|
||||
}
|
||||
],
|
||||
"indexes": [],
|
||||
"indexes": [
|
||||
"CREATE UNIQUE INDEX `idx_orp1NWL` ON `events` (\n `Day`,\n `Week`,\n `Start`,\n `End`,\n `Name`,\n `course`\n)"
|
||||
],
|
||||
"listRule": null,
|
||||
"viewRule": null,
|
||||
"createRule": null,
|
||||
|
72
service/db/dbEvents.go
Normal file
72
service/db/dbEvents.go
Normal file
@ -0,0 +1,72 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"htwk-planner/model"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func SaveEvents(seminarGroup []model.SeminarGroup, collection *models.Collection, app *pocketbase.PocketBase) error {
|
||||
|
||||
for _, seminarGroup := range seminarGroup {
|
||||
for _, event := range seminarGroup.Events {
|
||||
var err error = nil
|
||||
record := models.NewRecord(collection)
|
||||
record.Set("Day", event.Day)
|
||||
record.Set("Week", event.Week)
|
||||
record.Set("Start", event.Start)
|
||||
record.Set("End", event.End)
|
||||
record.Set("Name", event.Name)
|
||||
record.Set("EventType", event.EventType)
|
||||
record.Set("Prof", event.Prof)
|
||||
record.Set("Rooms", event.Rooms)
|
||||
record.Set("Notes", event.Notes)
|
||||
record.Set("BookedAt", event.BookedAt)
|
||||
record.Set("course", seminarGroup.Course)
|
||||
err = app.Dao().SaveRecord(record)
|
||||
if err != nil {
|
||||
println("Error while saving record: ", err.Error())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contains(s []string, e string) bool {
|
||||
for _, a := range s {
|
||||
if a == e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetRooms function to get all rooms from database that are stored as a string in the Events struct
|
||||
func GetRooms(app *pocketbase.PocketBase) []string {
|
||||
|
||||
var events []struct {
|
||||
Rooms string `db:"Rooms" json:"Rooms"`
|
||||
}
|
||||
|
||||
// get all rooms from event records in the events collection
|
||||
err := app.Dao().DB().Select("Rooms").From("events").All(&events)
|
||||
if err != nil {
|
||||
print("Error while getting rooms from database: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var roomArray []string
|
||||
|
||||
for _, event := range events {
|
||||
var room = strings.Split(event.Rooms, " ")
|
||||
//split string room by space and add each room to array if it is not already in there
|
||||
for _, r := range room {
|
||||
var text = strings.TrimSpace(r)
|
||||
if !contains(roomArray, text) && !strings.Contains(text, " ") && len(text) >= 1 {
|
||||
roomArray = append(roomArray, text)
|
||||
}
|
||||
}
|
||||
}
|
||||
return roomArray
|
||||
}
|
45
service/db/dbGroups.go
Normal file
45
service/db/dbGroups.go
Normal file
@ -0,0 +1,45 @@
|
||||
package db
|
||||
|
||||
import (
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"htwk-planner/model"
|
||||
)
|
||||
|
||||
func SaveGroups(seminarGroup []model.SeminarGroup, collection *models.Collection, app *pocketbase.PocketBase) error {
|
||||
for _, group := range seminarGroup {
|
||||
record := models.NewRecord(collection)
|
||||
record.Set("university", group.University)
|
||||
record.Set("shortcut", group.GroupShortcut)
|
||||
record.Set("groupId", group.GroupId)
|
||||
record.Set("course", group.Course)
|
||||
record.Set("faculty", group.Faculty)
|
||||
record.Set("facultyId", group.FacultyId)
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetAllCourses(app *pocketbase.PocketBase) []string {
|
||||
|
||||
var courses []struct {
|
||||
Rooms string `db:"course" json:"course"`
|
||||
}
|
||||
|
||||
// get all rooms from event records in the events collection
|
||||
err := app.Dao().DB().Select("course").From("groups").All(&courses)
|
||||
if err != nil {
|
||||
print("Error while getting groups from database: ", err)
|
||||
return nil
|
||||
}
|
||||
|
||||
var courseArray []string
|
||||
|
||||
for _, room := range courses {
|
||||
courseArray = append(courseArray, room.Rooms)
|
||||
}
|
||||
|
||||
return courseArray
|
||||
}
|
@ -3,11 +3,13 @@ package service
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"github.com/pocketbase/pocketbase/apis"
|
||||
"htwk-planner/model"
|
||||
"htwk-planner/service/db"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/labstack/echo/v5"
|
||||
)
|
||||
|
||||
func getSeminarHTML() (string, error) {
|
||||
@ -38,15 +40,25 @@ func getSeminarHTML() (string, error) {
|
||||
|
||||
}
|
||||
|
||||
func FetchSeminarGroups(c echo.Context) error {
|
||||
func FetchSeminarGroups(c echo.Context, app *pocketbase.PocketBase) error {
|
||||
|
||||
result, _ := getSeminarHTML()
|
||||
|
||||
var studium []model.SeminarGroup
|
||||
var groups []model.SeminarGroup
|
||||
|
||||
studium = parseSeminarGroups(result)
|
||||
groups = parseSeminarGroups(result)
|
||||
|
||||
return c.JSON(http.StatusOK, studium)
|
||||
collection, dbError := findCollection(app, "groups")
|
||||
if dbError != nil {
|
||||
return apis.NewNotFoundError("Collection not found", dbError)
|
||||
}
|
||||
|
||||
dbError = db.SaveGroups(groups, collection, app)
|
||||
if dbError != nil {
|
||||
return apis.NewApiError(400, "Could not save Events into database", dbError)
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, groups)
|
||||
}
|
||||
|
||||
func parseSeminarGroups(result string) []model.SeminarGroup {
|
||||
|
@ -8,8 +8,10 @@ import (
|
||||
"github.com/pocketbase/pocketbase/models"
|
||||
"golang.org/x/net/html"
|
||||
"htwk-planner/model"
|
||||
"htwk-planner/service/db"
|
||||
"io"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
@ -17,73 +19,64 @@ func FetchHTWK(c echo.Context, app *pocketbase.PocketBase) error {
|
||||
|
||||
var seminarGroups []model.SeminarGroup
|
||||
|
||||
seminarGroupsLabel := []string{
|
||||
"22INB-3",
|
||||
"22INB-2",
|
||||
"22INB-1",
|
||||
"21INB-2",
|
||||
"21INB-1",
|
||||
"22INM",
|
||||
//"21INM (Masterarbeit)",
|
||||
"22MIB-BIN",
|
||||
"22MIB-2",
|
||||
"22MIB-1",
|
||||
"21MIB-BIN",
|
||||
"21MIB-1",
|
||||
"21MIB-2",
|
||||
//"20MIB (Praxis/Bachelorarbeit)",
|
||||
"22MIM",
|
||||
//"21MIM (Masterarbeit)"
|
||||
}
|
||||
//seminarGroupsLabel := []string{
|
||||
// "22EIM-MET",
|
||||
//}
|
||||
|
||||
seminarGroupsLabel := db.GetAllCourses(app)
|
||||
for _, seminarGroupLabel := range seminarGroupsLabel {
|
||||
|
||||
result, err := getPlanHTML("ss", seminarGroupLabel)
|
||||
result, getError := getPlanHTML("ws", seminarGroupLabel)
|
||||
|
||||
seminarGroup := parseSeminarGroup(result)
|
||||
|
||||
if err != nil {
|
||||
return apis.NewNotFoundError("The Data could not be fetched", err)
|
||||
if getError == nil {
|
||||
seminarGroup := parseSeminarGroup(result)
|
||||
seminarGroups = append(seminarGroups, seminarGroup)
|
||||
}
|
||||
}
|
||||
|
||||
collection, err := app.Dao().FindCollectionByNameOrId("events")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
//Save SeminarGroups to DB
|
||||
print("Saving SeminarGroups to DB...\n")
|
||||
|
||||
for _, event := range seminarGroup.Events {
|
||||
record := models.NewRecord(collection)
|
||||
record.Set("Day", event.Day)
|
||||
record.Set("Week", event.Week)
|
||||
record.Set("Start", event.Start)
|
||||
record.Set("End", event.End)
|
||||
record.Set("Name", event.Name)
|
||||
record.Set("EventType", event.EventType)
|
||||
record.Set("Prof", event.Prof)
|
||||
record.Set("Rooms", event.Rooms)
|
||||
record.Set("Notes", event.Notes)
|
||||
record.Set("BookedAt", event.BookedAt)
|
||||
if err := app.Dao().SaveRecord(record); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
seminarGroups = append(seminarGroups, seminarGroup)
|
||||
collection, dbError := findCollection(app, "events")
|
||||
if dbError != nil {
|
||||
return apis.NewNotFoundError("Collection not found", dbError)
|
||||
}
|
||||
|
||||
dbError = db.SaveEvents(seminarGroups, collection, app)
|
||||
if dbError != nil {
|
||||
return apis.NewApiError(400, "Could not save Events into database", dbError)
|
||||
}
|
||||
|
||||
return c.JSON(http.StatusOK, seminarGroups)
|
||||
}
|
||||
|
||||
func parseSeminarGroup(result string) model.SeminarGroup {
|
||||
doc, _ := html.Parse(strings.NewReader(result))
|
||||
table := findFirstTable(doc)
|
||||
events := toEvents(getEventTables(doc), getAllDayLabels(doc))
|
||||
func findCollection(app *pocketbase.PocketBase, collectionName string) (*models.Collection, error) {
|
||||
collection, dbError := app.Dao().FindCollectionByNameOrId(collectionName)
|
||||
return collection, dbError
|
||||
}
|
||||
|
||||
func parseSeminarGroup(result string) model.SeminarGroup {
|
||||
doc, err := html.Parse(strings.NewReader(result))
|
||||
if err != nil {
|
||||
fmt.Printf("Error occurred while parsing the HTML document: %s\n", err.Error())
|
||||
return model.SeminarGroup{}
|
||||
}
|
||||
|
||||
table := findFirstTable(doc)
|
||||
eventTables := getEventTables(doc)
|
||||
allDayLabels := getAllDayLabels(doc)
|
||||
|
||||
if eventTables == nil || allDayLabels == nil {
|
||||
return model.SeminarGroup{}
|
||||
}
|
||||
|
||||
eventsWithCombinedWeeks := toEvents(eventTables, allDayLabels)
|
||||
splitEventsByWeekVal := splitEventsByWeek(eventsWithCombinedWeeks)
|
||||
events := splitEventsBySingleWeek(splitEventsByWeekVal)
|
||||
var seminarGroup = model.SeminarGroup{
|
||||
University: findFirstSpanWithClass(table, "header-1-0-0").FirstChild.Data,
|
||||
GroupShortcut: findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data,
|
||||
Events: events,
|
||||
University: findFirstSpanWithClass(table, "header-1-0-0").FirstChild.Data,
|
||||
Course: findFirstSpanWithClass(table, "header-2-0-1").FirstChild.Data,
|
||||
Events: events,
|
||||
}
|
||||
|
||||
return seminarGroup
|
||||
@ -117,6 +110,59 @@ func toEvents(tables [][]*html.Node, days []string) []model.Events {
|
||||
return events
|
||||
}
|
||||
|
||||
func splitEventsByWeek(events []model.Events) []model.Events {
|
||||
var newEvents []model.Events
|
||||
|
||||
for _, event := range events {
|
||||
weeks := strings.Split(event.Week, ",")
|
||||
for _, week := range weeks {
|
||||
newEvent := event
|
||||
newEvent.Week = strings.TrimSpace(week)
|
||||
newEvents = append(newEvents, newEvent)
|
||||
}
|
||||
}
|
||||
return newEvents
|
||||
}
|
||||
|
||||
func splitEventsBySingleWeek(events []model.Events) []model.Events {
|
||||
var newEvents []model.Events
|
||||
|
||||
for _, event := range events {
|
||||
if strings.Contains(event.Week, "-") {
|
||||
weeks := splitWeekRange(event.Week)
|
||||
for _, week := range weeks {
|
||||
newEvent := event
|
||||
newEvent.Week = week
|
||||
newEvents = append(newEvents, newEvent)
|
||||
}
|
||||
} else {
|
||||
newEvents = append(newEvents, event)
|
||||
}
|
||||
}
|
||||
return newEvents
|
||||
}
|
||||
|
||||
func splitWeekRange(weekRange string) []string {
|
||||
parts := strings.Split(weekRange, "-")
|
||||
if len(parts) != 2 {
|
||||
return nil // Invalid format
|
||||
}
|
||||
|
||||
start, errStart := strconv.Atoi(strings.TrimSpace(parts[0]))
|
||||
end, errEnd := strconv.Atoi(strings.TrimSpace(parts[1]))
|
||||
|
||||
if errStart != nil || errEnd != nil {
|
||||
return nil // Error converting to integers
|
||||
}
|
||||
|
||||
var weeks []string
|
||||
for i := start; i <= end; i++ {
|
||||
weeks = append(weeks, strconv.Itoa(i))
|
||||
}
|
||||
|
||||
return weeks
|
||||
}
|
||||
|
||||
func toUtf8(iso88591Buf []byte) string {
|
||||
buf := make([]rune, len(iso88591Buf))
|
||||
for i, b := range iso88591Buf {
|
||||
@ -202,11 +248,14 @@ func getEventTables(node *html.Node) [][]*html.Node {
|
||||
var eventTables [][]*html.Node
|
||||
|
||||
tables := findTables(node)
|
||||
|
||||
// get all tables with events
|
||||
for events := range tables {
|
||||
rows := findTableRows(tables[events])
|
||||
rows = rows[1:]
|
||||
eventTables = append(eventTables, rows)
|
||||
// check that a first row exists
|
||||
if len(rows) > 0 {
|
||||
rows = rows[1:]
|
||||
eventTables = append(eventTables, rows)
|
||||
}
|
||||
}
|
||||
|
||||
return eventTables
|
||||
@ -256,11 +305,19 @@ func findTableRows(node *html.Node) []*html.Node {
|
||||
}
|
||||
}
|
||||
|
||||
// Traverse child nodes recursively
|
||||
for child := node.FirstChild; child != nil; child = child.NextSibling {
|
||||
tableRows = append(tableRows, findTableRows(child)...)
|
||||
var tableRowElement = findTableRows(child)
|
||||
if tableRowElement != nil {
|
||||
tableRows = append(tableRows, tableRowElement...)
|
||||
}
|
||||
}
|
||||
|
||||
return tableRows
|
||||
if tableRows == nil {
|
||||
return []*html.Node{}
|
||||
} else {
|
||||
return tableRows
|
||||
}
|
||||
}
|
||||
|
||||
// Find all <p> elements in the HTML document
|
||||
|
13
service/roomService.go
Normal file
13
service/roomService.go
Normal file
@ -0,0 +1,13 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"github.com/labstack/echo/v5"
|
||||
"github.com/pocketbase/pocketbase"
|
||||
"htwk-planner/service/db"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func GetRooms(c echo.Context, app *pocketbase.PocketBase) error {
|
||||
rooms := db.GetRooms(app)
|
||||
return c.JSON(http.StatusOK, rooms)
|
||||
}
|
Reference in New Issue
Block a user