feat: more data

This commit is contained in:
William Ryder 2023-09-22 15:17:39 +02:00
parent 3f469de3d5
commit 6130fdb796
5 changed files with 199 additions and 108 deletions

View File

@ -27,6 +27,10 @@ const cookieJar = new CookieJar()
let bankIdUsed = true
const recordFolder = `${__dirname}/record`
const now = DateTime.local()
const [year, week] = now.toISOWeekDate().split('-')
const isoWeek = week.replace('W','')
async function run() {
const fetch = fetchCookie(nodeFetch, cookieJar)
@ -45,7 +49,26 @@ async function run() {
console.log('children')
const children = await api.getChildren()
console.log(children)
try {
console.log('timetable')
const timetable = await api.getTimetable(
children[0],
isoWeek,
year,
'sv'
)
console.log(inspect(timetable, false, 1000, true))
} catch (error) {
console.error(error)
}
console.log('menu')
const menu = await api.getMenu(children[0])
console.log(menu)
/*
console.log('calendar')
const calendar = await api.getCalendar(children[0])
console.log(calendar)
@ -74,18 +97,6 @@ async function run() {
console.error(error)
}
try {
console.log('timetable')
const timetable = await api.getTimetable(
skola24children[0],
15,
2021,
'sv'
)
console.log(inspect(timetable, false, 1000, true))
} catch (error) {
console.error(error)
}
/*
console.log('news')
@ -100,9 +111,7 @@ async function run() {
)
console.log(newsItems) */
/* console.log('menu')
const menu = await api.getMenu(children[0])
console.log(menu) */
// console.log('notifications')
// const notifications = await api.getNotifications(children[0])

View File

@ -54,6 +54,7 @@ export class ApiAdmentum extends EventEmitter implements Api {
private realFetcher: Fetcher
private personalNumber?: string
private userId: string
private cookieManager: CookieManager
@ -83,6 +84,7 @@ export class ApiAdmentum extends EventEmitter implements Api {
this.fetch = wrap(fetch, options)
this.realFetcher = this.fetch
this.cookieManager = cookieManager
this.userId = ''
}
public replaceFetcher(fetcher: Fetcher) {
@ -143,12 +145,15 @@ export class ApiAdmentum extends EventEmitter implements Api {
}
async getUser(): Promise<User> {
const user = await this.fetch('fetch-me', apiUrls.me);
const userJson = await user.json();
this.userId = userJson.user?.id;
console.log('userId: ', this.userId);
console.log('fetching user')
const userId = '437236'
const currentUserResponse = await this.fetch(
'current-user',
apiUrls.user(userId)
) // + /id?
apiUrls.user(this.userId)
)
console.log('current-user', currentUserResponse)
if (currentUserResponse.status !== 200) {
return { isAuthenticated: false }
@ -163,9 +168,7 @@ export class ApiAdmentum extends EventEmitter implements Api {
throw new Error('Not logged in...')
}
console.log("get children")
const testUserId = '437236'
const fetchUrl = apiUrls.user(testUserId)
console.log('v3.4 fetching children for user id', testUserId, 'from', fetchUrl)
const fetchUrl = apiUrls.user(this.userId)
const currentUserResponse = await this.fetch('current-user', fetchUrl, {
method: 'GET',
headers: {
@ -193,11 +196,19 @@ export class ApiAdmentum extends EventEmitter implements Api {
throw new Error('Not logged in...')
}
const [year, week] = new DateTime().toISOWeekDate().split('-')
const isoWeek = week.replace('W','')
const fetchUrl = apiUrls.schedule(year, isoWeek)
const calendarResponse = await this.fetch('get-calendar', fetchUrl)
return calendarResponse.map(parseCalendarItem)
return []
// const fetchUrl = apiUrls.schedule_events
// const events = await this.fetch('scheduled-events', fetchUrl, {
// method: 'GET',
// headers: {
// 'Accept': 'application/json, text/plain, */*',
// },
// }).then(res => res.json()).then(json => json.results)
// return events.map(parseScheduleEvent)*/
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
@ -236,14 +247,45 @@ export class ApiAdmentum extends EventEmitter implements Api {
async getNewsDetails(_child: EtjanstChild, item: NewsItem): Promise<any> {
return { ...item }
}
/*
"data": {
"food_week": {
"id": 12846,
"week": 38,
"year": 2023,
"food_days": [
{
"id": 60620,
"date": "2023-09-18",
"menu": "Förrätt: Morotssoppa med knäckebröd\r\nHuvudrätt: Kycklinggryta med ris och grönsaker\r\nEfterrätt: Fruktkompott",
"weekday": "Måndag",
"weekday_nbr": 0
},
{
"id": 60621,
"date": "2023-09-19",
"menu": "Förrätt: Gurksallad\
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars
getMenu(_child: EtjanstChild): Promise<MenuItem[]> {
async getMenu(_child: EtjanstChild): Promise<MenuItem[]> {
if (!this.isLoggedIn) {
throw new Error('Not logged in...')
}
// Have not found this available on hjärntorget. Perhaps do a mapping to https://www.skolmaten.se/ ?
return Promise.resolve([])
const now = DateTime.local()
const [year, week] = now.toISOWeekDate().split('-')
const isoWeek = week.replace('W','')
const fetchUrl = apiUrls.menu(year.toString(), isoWeek.toString())
const menuResponse = (await this.fetch('get-menu', fetchUrl))
const menuResponseJson = await menuResponse.json()
console.log('menu response', menuResponseJson)
const days = (await menuResponseJson)?.data?.food_week?.food_days
return Promise.resolve(days.map(({ menu, date } : any) => ({
title: date,
description: menu
})))
}
async getChildEventsWithAssociatedMembers(child: EtjanstChild) {
@ -272,31 +314,13 @@ export class ApiAdmentum extends EventEmitter implements Api {
year: number,
_lang: string
): Promise<TimetableEntry[]> {
const startDate = DateTime.fromJSDate(getDateOfISOWeek(week, year))
const endDate = startDate.plus({ days: 7 })
const lessonsResponseJson: any[] = []
return lessonsResponseJson.map((l) => {
const start = DateTime.fromMillis(l.startDate.ts, {
zone: FixedOffsetZone.instance(l.startDate.timezoneOffsetMinutes),
})
const end = DateTime.fromMillis(l.endDate.ts, {
zone: FixedOffsetZone.instance(l.endDate.timezoneOffsetMinutes),
})
return {
...parse(l.title, _lang),
id: l.id,
teacher: l.bookedTeacherNames && l.bookedTeacherNames[0],
location: l.location,
timeStart: start.toISOTime().substring(0, 5),
timeEnd: end.toISOTime().substring(0, 5),
dayOfWeek: start.toJSDate().getDay(),
blockName: l.title,
dateStart: start.toISODate(),
dateEnd: end.toISODate(),
} as TimetableEntry
})
const fetchUrl = apiUrls.schedule(year.toString(), week.toString())
console.log('fetching timetable', fetchUrl)
const calendarResponse = await this.fetch('get-calendar', fetchUrl)
const calendarResponseJson = await calendarResponse.json()
const timetableEntries = parseCalendarItem(calendarResponseJson)
return timetableEntries;
}
async logout(): Promise<void> {
@ -314,6 +338,16 @@ export class ApiAdmentum extends EventEmitter implements Api {
console.log('login adentum', personalNumber)
this.isFake = false
const authenticatedUser = await this.getUser();
if (authenticatedUser && authenticatedUser.isAuthenticated) {
console.log('already logged in to admentum')
this.isLoggedIn = true
this.personalNumber = personalNumber
this.emit('login')
return new DummyStatusChecker()
}
const url = await this.fetch('get-session', bankIdSessionUrl('')).then(
(res) => {
console.log('got res', res, (res as any).url, res.headers)
@ -357,15 +391,8 @@ export class ApiAdmentum extends EventEmitter implements Api {
const locomotiveUrl = redirectLocomotive(sessionId)
console.log('calling locomotive url: ', locomotiveUrl);
/*const response = await this.fetch('follow-locomotive', locomotiveUrl, {
method: 'GET',
redirect: 'follow',
});*/
//console.log('locomotive response', response)
const callbackResponse = await this.followRedirects(locomotiveUrl);
console.log('final response:', callbackResponse);
//const testChildren = await this.getChildren()
//console.log('test children', testChildren)
this.emit('login')
})
statusChecker.on('ERROR', () => {

View File

@ -3,6 +3,6 @@ import { Features } from '@skolplattformen/api'
export const features: Features = {
LOGIN_BANK_ID_SAME_DEVICE_WITHOUT_ID: false,
LOGIN_FREJA_EID: false,
FOOD_MENU: false,
FOOD_MENU: true,
CLASS_LIST: false,
}

View File

@ -1,5 +1,7 @@
import * as html from 'node-html-parser'
import { decode } from 'he'
import { CalendarItem, TimetableEntry } from 'libs/api/lib/types'
import { DateTime, FixedOffsetZone } from 'luxon'
// TODO: Move this into the parse folder and convert it to follow the pattern of other parsers (include tests).
@ -46,10 +48,60 @@ export function extractAuthGbgLoginRequestBody(signatureResponseText: string) {
return authGbgLoginBody
}
export const parseCalendarItem = (jsonRow: any): any => {
return {}
/*
return myChildrenResponseJson.students.map((student: { id: any; first_name: any; last_name: any }) => ({
id: student.id,
sdsId: student.id,
personGuid: student.id,
firstName: student.first_name,
lastName: student.last_name,
name: `${student.first_name} ${student.last_name}`,
}) as Skola24Child & EtjanstChild);
*/
/*
export const parseScheduleEvent = (({
url, id, eid, school_id, schedule_id, name, start_time, end_time, rooms: [room], teachers, schedule_groups, primary_groups, weekly_interval
})): CalendarItem => ({
id
title: name
location?: room?.name
startDate?: start_time
endDate?: end_time
allDay?: start_time === '00:00:00' && end_time === '23:59:00'
})
*/
enum DayOfWeek {
'Måndag'= 1,
'Tisdag'= 2,
'Onsdag'= 3,
'Torsdag'= 4,
'Fredag'= 5,
'Lördag'= 6,
'Söndag'= 7,
}
export const parseCalendarItem = (jsonData: any): any => {
const timetableEntries: TimetableEntry[] = []
if (jsonData && jsonData.days && Array.isArray(jsonData.days) && jsonData.days.length > 0) {
jsonData.days.forEach((day: { name: string, lessons: any[] }) => {
day.lessons.forEach(lesson => {
const dayOfWeek = DayOfWeek[day.name as keyof typeof DayOfWeek]
timetableEntries.push({
id: lesson.id,
teacher: lesson.bookedTeacherNames && lesson.bookedTeacherNames[0],
location: lesson.location,
timeStart: lesson.time.substring(0, 5),
timeEnd: lesson.time.substring(9),
dayOfWeek,
blockName: lesson.title || lesson.subject_name
} as TimetableEntry)
});
})
} else {
console.error("Failed to parse calendar item, no days found in json data.")
}
return timetableEntries;
}
/*

View File

@ -1,48 +1,51 @@
const baseUrl = 'https://skola.admentum.se/api/v1/'
const baseUrl = 'https://skola.admentum.se/'
const api = baseUrl + 'api/v1/'
export const apiUrls = {
assignments: baseUrl + 'assignments',
attendance_summary_users: baseUrl + 'attendance/summary/users',
course_sections: baseUrl + 'course_sections',
courses: baseUrl + 'courses',
forecast_collections: baseUrl + 'forecast_collections',
forecasts: baseUrl + 'forecasts',
grade_permissions: baseUrl + 'grade_permissions',
grades: baseUrl + 'grades',
gymnasium_courses: baseUrl + 'gymnasium_courses',
leisure_group_enrollments: baseUrl + 'leisure_group_enrollments',
leisure_groups: baseUrl + 'leisure_groups',
lesson_infos: baseUrl + 'lesson_infos',
lessons: baseUrl + 'lessons',
organisations: baseUrl + 'organisations',
orientations: baseUrl + 'orientations',
permission_groups: baseUrl + 'permission_groups',
primary_group_enrollments: baseUrl + 'primary_group_enrollments',
assignments: api + 'assignments',
attendance_summary_users: api + 'attendance/summary/users',
course_sections: api + 'course_sections',
courses: api + 'courses',
forecast_collections: api + 'forecast_collections',
forecasts: api + 'forecasts',
grade_permissions: api + 'grade_permissions',
grades: api + 'grades',
gymnasium_courses: api + 'gymnasium_courses',
leisure_group_enrollments: api + 'leisure_group_enrollments',
leisure_groups: api + 'leisure_groups',
lesson_infos: api + 'lesson_infos',
lessons: api + 'lessons',
organisations: api + 'organisations',
orientations: api + 'orientations',
permission_groups: api + 'permission_groups',
primary_group_enrollments: api + 'primary_group_enrollments',
primary_group_municipality_statistics:
baseUrl + 'primary_groups/municipality_statistic',
primary_groups: baseUrl + 'primary_groups',
program_courses: baseUrl + 'program_courses',
programs: baseUrl + 'programs',
reviews: baseUrl + 'reviews',
rooms: baseUrl + 'rooms',
schedule_breaks: baseUrl + 'schedule_breaks',
schedule_event_instances: baseUrl + 'schedule_event_instances',
schedule_events: baseUrl + 'schedule_events',
schedule_group_enrollments: baseUrl + 'schedule_group_enrollments',
api + 'primary_groups/municipality_statistic',
primary_groups: api + 'primary_groups',
program_courses: api + 'program_courses',
programs: api + 'programs',
reviews: api + 'reviews',
rooms: api + 'rooms',
schedule_breaks: api + 'schedule_breaks',
schedule_event_instances: api + 'schedule_event_instances',
schedule_events: api + 'schedule_events',
schedule_group_enrollments: api + 'schedule_group_enrollments',
schedule_group_teacher_enrollments:
baseUrl + 'schedule_group_teacher_enrollments',
schedule_groups: baseUrl + 'schedule_groups',
schedules: baseUrl + 'schedules',
schedule: (year: string, week: string) => baseUrl + `schedule?week=${week}&year=${year}`,
school_enrollments: `${baseUrl}school_enrollments`,
school_years: baseUrl + 'school_years',
schools: baseUrl + 'schools',
sickness: baseUrl + 'sickness',
subjects: baseUrl + 'subjects',
teachers: baseUrl + 'teachers',
upper_secondary_subjects: baseUrl + 'upper_secondary_subjects',
users: baseUrl + 'users?format=json',
user: (userId: string) => baseUrl + `users/${userId}/?format=json`,
api + 'schedule_group_teacher_enrollments',
schedule_groups: api + 'schedule_groups',
schedules: api + 'schedules',
schedule: (year: string, week: string) => baseUrl + `schedule/schedule?week=${week}&year=${year}`,
school_enrollments: `${api}school_enrollments`,
school_years: api + 'school_years',
schools: api + 'schools',
sickness: api + 'sickness',
subjects: api + 'subjects',
teachers: api + 'teachers',
menu: (year: string, week: string) => baseUrl + `api/food/week/${week}/${year}`,
upper_secondary_subjects: api + 'upper_secondary_subjects',
users: api + 'users?format=json',
user: (userId: string) => api + `users/${userId}/?format=json`,
me: baseUrl + 'api/me?format=json',
}
export const bankIdCheckUrl = (sessionId: string) =>