diff --git a/README.md b/README.md index 6a02751..222d5b2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,196 @@ # GoSkola24API -Go module for easy interaction with the Skola24 API. \ No newline at end of file +Go module for easy interaction with the Skola24 API. + +The only data you need to use this module is the hostname of your target institution. +Available hostnames can be found in a list [here](https://www.skola24.se/Applications/Authentication/login.aspx). + +If you know of a way to get these via API, without scraping, please let me know. + +Please remember that you can only retrieve data within the currently active hostname/domain. + + + +# Getting started + +SomeExampleHere + + + +# Methods + +Here is a list of all available methods, complete with detailed descriptions. + +## GetTerms() (_result, _error) + +Retrieves all currently available terms (aka semesters). + +### Parameters + +None. + +### Returns + +**_result**: < [Terms](#terms) > Holds the retrieved terms data. + +**_error**: < error > Holds standard error data if errors were encountered. + +## GetSchools() (_result, _error) + +Retrieves all available schools. + +### Parameters + +None. + +### Returns + +**_result**: < [] [School](#school) > Array of available schools. + +**_error**: < error > Holds standard error data if errors were encountered. + +## GetRooms(school, checkAvailability) (_result, _error) + +Retrieves all rooms in a school. + +### Parameters + +**school**: < [School](#school) > School to get rooms from. + +**checkAvailability**: < bool > If stored availability data should be used to skip requests for unavailable data. + +### Returns + +**_result**: < [] [Room](#room) > Array of available rooms. + +**_error**: < error > Holds standard error data if errors were encountered. + +## GetTeachers(school, checkAvailability) (_result, _error) + +Retrieves all teachers in a school. + +### Parameters + +**school**: < [School](#school) > School to get teachers from. + +**checkAvailability**: < bool > If stored availability data should be used to skip requests for unavailable data. + +### Returns + +**_result**: < [] [Teacher](#teacher) > Array of available teachers. + +**_error**: < error > Holds standard error data if errors were encountered. + +## GetStudents(school, checkAvailability) (_result, _error) + +Retrieves all students in a school. + +WARNING: Use with caution. I am yet to find a host/school that provides this data, and therefor this method is not typed. + +### Parameters + +**school**: < [School](#school) > School to get students from. + +**checkAvailability**: < bool > If stored availability data should be used to skip requests for unavailable data. + +### Returns + +**_result**: < any > Returned student data. WARNING: Types currently unknown. + +**_error**: < error > Holds standard error data if errors were encountered. + + + +# Types + +## Terms + +Holds terms (aka semesters) data. + +### Fields + +**ActiveTerms**: < [] [SchoolTerm](#schoolterm) > Array of currently active terms. + +**UseSchoolYearsFeatures**: < bool > Purpose unknown. + +## SchoolTerm + +Represents a school term. + +### Fields + +**Start**: < string > Term startdate. + +**TermId**: < string > ID of the term (GUID). + +**Name**: < string > Friendlyname of the term. + +**End**: < string > Term enddate. + +## School + +Represents a school. + +### Fields + +**Name**: < string > Friendlyname of the school. + +**SchoolId**: < string > ID of the school (GUID). + +**HostName**: < string > The hostname / domain the school belongs to. + +**AllowCalendarExport**: < string > Whether or not school allows traditional calendar export (does not affect exports via this module). + +**AvailableData**: < [DataAvailability](#dataavailability) > Types of data available for retrieval on the school. + +## DataAvailability + +Defines types of data available on a specific entity. + +### Fields + +**HasClasses**: < bool > If entity provides classes data. + +**HasCourses**: < bool > If entity provides courses data. + +**HasGroups**: < bool > If entity provides groups data. + +**HasResources**: < bool > If entity provides resources data. + +**HasRooms**: < bool > If entity provides rooms data. + +**HasStudents**: < bool > If entity provides students data. + +**HasSubjects**: < bool > If entity provides teachers data. + +## Room + +Represents a room. + +**Name**: < string > Friendlyname of the room. + +**RoomId**: < string > ID of the room (GUID). + +**External**: < bool > Purpose unknown, but assumed to indicate a room physically isolated from the rest of the school. + +## Teacher + +Represents a teacher. + +**FirstName**: < string > Teacher's first name. + +**LastName**: < string > Teacher's last name. + +**FullName**: < string > Full name (usually firstname+lastname+friendlyid). + +**FriendlyId**: < string > Friendly/readable ID, usually teacher's initials. + +**TeacherId**: < string > ID of the teacher (GUID). + +**IsActive**: < bool > Purpose unknown. + +**Integrity**: < bool > Purpose unknown. + +**Reported**: < bool > Purpose unknown. + +**ReadOnly**: < bool > Purpose unknown. \ No newline at end of file diff --git a/cmd/goskola24api/main.go b/cmd/goskola24api/main.go index b72dd7c..321c82e 100644 --- a/cmd/goskola24api/main.go +++ b/cmd/goskola24api/main.go @@ -30,11 +30,25 @@ func main() { fmt.Println(err.Error()) } - fmt.Println(rooms) - for _, room := range rooms { fmt.Println(room.Name) } + teachers, err := api.GetTeachers(schools[4], true) + if err != nil { + fmt.Println(err.Error()) + } + + for _, teacher := range teachers { + fmt.Println(teacher.FullName) + } + + students, err := api.GetStudents(schools[4], true) + if err != nil { + fmt.Println(err.Error()) + } + + fmt.Println(students) + fmt.Println(key) } diff --git a/internal/requests/get_rooms.go b/internal/requests/get_rooms.go index 3e1ce24..89dcdf6 100644 --- a/internal/requests/get_rooms.go +++ b/internal/requests/get_rooms.go @@ -26,7 +26,6 @@ package requests import ( "errors" - "fmt" "git.zervo.org/zervo/GoSkola24API/internal/types" pubtypes "git.zervo.org/zervo/GoSkola24API/pkg/goskola24api/types" @@ -53,17 +52,12 @@ func GetRooms(school pubtypes.School, checkAvailability bool) (_result []pubtype return nil, errors.New("failed to get rooms: " + err.Error()) } - fmt.Println(school) - fmt.Println(responseMap) - // Extract rooms as []interface{} roomsRaw, ok := responseMap["rooms"].([]interface{}) if !ok { return nil, errors.New("missing or invalid \"rooms\" field in response") } - fmt.Println(roomsRaw) - // Convert raw rooms into usable room type var rooms []pubtypes.Room for _, roomRaw := range roomsRaw { @@ -72,16 +66,11 @@ func GetRooms(school pubtypes.School, checkAvailability bool) (_result []pubtype return nil, errors.New("unexpected room format") } - // Extract fields from each room - roomName, _ := roomMap["name"].(string) - roomId, _ := roomMap["eid"].(string) - external, _ := roomMap["external"].(bool) - - // Map to struct + // Create room struct room := pubtypes.Room{ - Name: roomName, - RoomId: roomId, - External: external, + Name: func() string { val, _ := roomMap["name"].(string); return val }(), + RoomId: func() string { val, _ := roomMap["eid"].(string); return val }(), + External: func() bool { val, _ := roomMap["external"].(bool); return val }(), } rooms = append(rooms, room) diff --git a/internal/requests/get_schools.go b/internal/requests/get_schools.go index 414d0a6..e8bcb44 100644 --- a/internal/requests/get_schools.go +++ b/internal/requests/get_schools.go @@ -78,39 +78,25 @@ func GetSchools(api_host string) (_result []pubtypes.School, _error error) { return nil, errors.New("unexpected unit format") } - // Extract fields from each unit - unitGuid, _ := unitMap["unitGuid"].(string) - unitId, _ := unitMap["unitId"].(string) - allowCalendarExport, _ := unitMap["allowCalendarExport"].(bool) + // Extract data from the anonymous field anonMap, _ := unitMap["anonymous"].(map[string]interface{}) - - // Same for anonymous units - hasClasses, _ := anonMap["classes"].(bool) - hasCourses, _ := anonMap["courses"].(bool) - hasGroups, _ := anonMap["groups"].(bool) - hasResources, _ := anonMap["resources"].(bool) - hasRooms, _ := anonMap["rooms"].(bool) - hasStudents, _ := anonMap["students"].(bool) - hasSubjects, _ := anonMap["subjects"].(bool) - hasTeachers, _ := anonMap["teachers"].(bool) - availableData := pubtypes.DataAvailability{ - HasClasses: hasClasses, - HasCourses: hasCourses, - HasGroups: hasGroups, - HasResources: hasResources, - HasRooms: hasRooms, - HasStudents: hasStudents, - HasSubjects: hasSubjects, - HasTeachers: hasTeachers, + HasClasses: func() bool { val, _ := anonMap["classes"].(bool); return val }(), + HasCourses: func() bool { val, _ := anonMap["courses"].(bool); return val }(), + HasGroups: func() bool { val, _ := anonMap["groups"].(bool); return val }(), + HasResources: func() bool { val, _ := anonMap["resources"].(bool); return val }(), + HasRooms: func() bool { val, _ := anonMap["rooms"].(bool); return val }(), + HasStudents: func() bool { val, _ := anonMap["students"].(bool); return val }(), + HasSubjects: func() bool { val, _ := anonMap["subjects"].(bool); return val }(), + HasTeachers: func() bool { val, _ := anonMap["teachers"].(bool); return val }(), } // Map to the struct unit := pubtypes.School{ - Name: unitId, - SchoolId: unitGuid, + Name: func() string { val, _ := unitMap["unitId"].(string); return val }(), + SchoolId: func() string { val, _ := unitMap["unitGuid"].(string); return val }(), HostName: hostname, - AllowCalendarExport: allowCalendarExport, + AllowCalendarExport: func() bool { val, _ := unitMap["allowCalendarExport"].(bool); return val }(), AvailableData: availableData, } diff --git a/internal/requests/get_students.go b/internal/requests/get_students.go new file mode 100644 index 0000000..d172816 --- /dev/null +++ b/internal/requests/get_students.go @@ -0,0 +1,59 @@ +/* +GoSkola24API +Copyright (C) 2024, Zervó Zadachin + +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License version 3 +as published by the Free Software Foundation. + +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 version 3 for more details. + +This program incorporates external libraries for certain functionalities. +These libraries are covered by their respective licenses, and their usage +agreements are as outlined in their respective documentation or source +code. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ + +package requests + +import ( + "errors" + + "git.zervo.org/zervo/GoSkola24API/internal/types" + pubtypes "git.zervo.org/zervo/GoSkola24API/pkg/goskola24api/types" +) + +// TODO: Create and implement proper students type once we have data + +func GetStudents(school pubtypes.School, checkAvailability bool) (_result any, _error error) { + if checkAvailability && !school.AvailableData.HasStudents { + return nil, errors.New("availability check failed: school does not provide student data") + } + + filters := types.RequestFilters{ + Class: false, + Course: false, + Group: false, + Period: false, + Room: false, + Student: true, + Subject: false, + Teacher: false, + } + + responseMap, err := GetGenericSelection(school, filters) + if err != nil { + return nil, errors.New("failed to get students: " + err.Error()) + } + + // Just return students as-is since we do not have any data do go from + return responseMap, nil +} diff --git a/internal/requests/get_teachers.go b/internal/requests/get_teachers.go new file mode 100644 index 0000000..df950d9 --- /dev/null +++ b/internal/requests/get_teachers.go @@ -0,0 +1,86 @@ +/* +GoSkola24API +Copyright (C) 2024, Zervó Zadachin + +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License version 3 +as published by the Free Software Foundation. + +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 version 3 for more details. + +This program incorporates external libraries for certain functionalities. +These libraries are covered by their respective licenses, and their usage +agreements are as outlined in their respective documentation or source +code. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ + +package requests + +import ( + "errors" + + "git.zervo.org/zervo/GoSkola24API/internal/types" + pubtypes "git.zervo.org/zervo/GoSkola24API/pkg/goskola24api/types" +) + +func GetTeachers(school pubtypes.School, checkAvailability bool) (_result []pubtypes.Teacher, _error error) { + if checkAvailability && !school.AvailableData.HasTeachers { + return nil, errors.New("availability check failed: school does not provide teacher data") + } + + filters := types.RequestFilters{ + Class: false, + Course: false, + Group: false, + Period: false, + Room: false, + Student: false, + Subject: false, + Teacher: true, + } + + responseMap, err := GetGenericSelection(school, filters) + if err != nil { + return nil, errors.New("failed to get teachers: " + err.Error()) + } + + // Extract teachers as []interface{} + teachersRaw, ok := responseMap["teachers"].([]interface{}) + if !ok { + return nil, errors.New("missing or invalid \"teachers\" field in response") + } + + // Convert raw teachers into usable teacher type + var teachers []pubtypes.Teacher + for _, teacherRaw := range teachersRaw { + teacherMap, ok := teacherRaw.(map[string]interface{}) + if !ok { + return nil, errors.New("unexpected room format") + } + + // Map to struct + teacher := pubtypes.Teacher{ + FirstName: func() string { val, _ := teacherMap["firstName"].(string); return val }(), + LastName: func() string { val, _ := teacherMap["lastName"].(string); return val }(), + FullName: func() string { val, _ := teacherMap["fullName"].(string); return val }(), + FriendlyId: func() string { val, _ := teacherMap["id"].(string); return val }(), + TeacherId: func() string { val, _ := teacherMap["personGuid"].(string); return val }(), + IsActive: func() bool { val, _ := teacherMap["isActiveUser"].(bool); return val }(), + Integrity: func() bool { val, _ := teacherMap["integrity"].(bool); return val }(), + Reported: func() bool { val, _ := teacherMap["reported"].(bool); return val }(), + ReadOnly: func() bool { val, _ := teacherMap["readOnly"].(bool); return val }(), + } + + teachers = append(teachers, teacher) + } + + return teachers, nil +} diff --git a/pkg/goskola24api/skola24api.go b/pkg/goskola24api/skola24api.go index 92ea490..4cca318 100644 --- a/pkg/goskola24api/skola24api.go +++ b/pkg/goskola24api/skola24api.go @@ -44,3 +44,11 @@ func (api Skola24API) GetSchools() (_result []pubtypes.School, _error error) { func (api Skola24API) GetRooms(school pubtypes.School, checkAvailability bool) (_result []pubtypes.Room, _error error) { return requests.GetRooms(school, checkAvailability) } + +func (api Skola24API) GetTeachers(school pubtypes.School, checkAvailability bool) (_result []pubtypes.Teacher, _error error) { + return requests.GetTeachers(school, checkAvailability) +} + +func (api Skola24API) GetStudents(school pubtypes.School, checkAvailability bool) (_result any, _error error) { + return requests.GetStudents(school, checkAvailability) +} diff --git a/pkg/goskola24api/types/teachers.go b/pkg/goskola24api/types/teachers.go new file mode 100644 index 0000000..58e4880 --- /dev/null +++ b/pkg/goskola24api/types/teachers.go @@ -0,0 +1,37 @@ +/* +GoSkola24API +Copyright (C) 2024, Zervó Zadachin + +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License version 3 +as published by the Free Software Foundation. + +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 version 3 for more details. + +This program incorporates external libraries for certain functionalities. +These libraries are covered by their respective licenses, and their usage +agreements are as outlined in their respective documentation or source +code. + +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see . +*/ + +package types + +type Teacher struct { + FirstName string `json:"firstName"` + LastName string `json:"lastName"` + FullName string `json:"fullName"` + FriendlyId string `json:"friendlyId"` + TeacherId string `json:"teacherId"` + IsActive bool `json:"isActive"` + Integrity bool `json:"integrity"` + Reported bool `json:"reported"` + ReadOnly bool `json:"readOnly"` +}