Improvments

This commit is contained in:
zervo 2024-11-21 20:24:24 +01:00
parent fcb7687c05
commit b637aeefe9
8 changed files with 416 additions and 44 deletions

195
README.md
View file

@ -1,3 +1,196 @@
# GoSkola24API
Go module for easy interaction with the Skola24 API.
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.

View file

@ -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)
}

View file

@ -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)

View file

@ -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,
}

View file

@ -0,0 +1,59 @@
/*
GoSkola24API
Copyright (C) 2024, Marco Vitchi Thulin
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 <http://www.gnu.org/licenses/>.
*/
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
}

View file

@ -0,0 +1,86 @@
/*
GoSkola24API
Copyright (C) 2024, Marco Vitchi Thulin
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 <http://www.gnu.org/licenses/>.
*/
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
}

View file

@ -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)
}

View file

@ -0,0 +1,37 @@
/*
GoSkola24API
Copyright (C) 2024, Marco Vitchi Thulin
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 <http://www.gnu.org/licenses/>.
*/
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"`
}