Schedule parsing

This commit is contained in:
Timerix22 2023-09-02 19:57:09 +06:00
parent ba2ca206bd
commit 8ad3a57b72
8 changed files with 239 additions and 47 deletions

View File

@ -1,6 +1,6 @@
namespace Platonus.API.DataModels; namespace Platonus.API.DataModels;
class LoginResponse internal class LoginResponse
{ {
/// session_id /// session_id
public string? sid { get; set; } public string? sid { get; set; }

View File

@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Globalization;
namespace Platonus.API.DataModels;
public class Schedule
{
public int SelectedYear { get; }
public int SelectedTermNumber { get; }
public int SelectedWeekNumber { get; }
public int CurrentWeekNumber { get; }
public List<int> TermWeekNumbers { get; }
internal Schedule(ScheduleResponse scheduleData)
{
SelectedYear = scheduleData.selectedStudyYear;
SelectedTermNumber = scheduleData.selectedTerm;
SelectedWeekNumber = scheduleData.selectedWeek;
CurrentWeekNumber = scheduleData.activeWeekNumber;
TermWeekNumbers = scheduleData.weekList;
Days = new Day[scheduleData.timetable.days.Count];
for (int di = 0; di < Days.Length; di++)
{
var dayData = scheduleData.timetable.days[(di + 1).ToString()];
Days[di] = new Day(di, dayData.lessons.Count);
int li = 0;
foreach (var lessonWrapper in dayData.lessons)
{
var lessonHourData = scheduleData.lessonHours.Find(lh => lh.number.ToString() == lessonWrapper.Key);
if (lessonHourData is null)
throw new NullReferenceException($"lesson hour with number {lessonWrapper.Key} not found");
Days[di].LessonHours[li].Time = new TimeRange(lessonHourData.start, lessonHourData.finish);
switch (lessonWrapper.Value.lessons.Count)
{
case 0:
Days[di].LessonHours[li].Lesson = null;
break;
case 1:
var lessonData = lessonWrapper.Value.lessons[0];
Days[di].LessonHours[li].Lesson = new Day.Lesson(lessonData);
break;
default:
throw new Exception($"lessonWrapper has data for more than one lessons ({lessonWrapper.Value.lessons.Count})");
}
li++;
}
}
}
public readonly struct TimeRange
{
public readonly TimeSpan Start;
public readonly TimeSpan Finish;
public TimeRange(TimeSpan from, TimeSpan to)
{
Start = from;
Finish = to;
}
/// format: hh:mm:ss
public TimeRange(string startStr, string finishStr)
{
Start = TimeSpan.ParseExact(startStr, @"hh\:mm\:ss", CultureInfo.InvariantCulture);
Finish = TimeSpan.ParseExact(finishStr, @"hh\:mm\:ss", CultureInfo.InvariantCulture);
}
}
/// days of week (monday=0, sunday=6)
public Day[] Days { get; }
public class Day
{
public (TimeRange Time, Lesson? Lesson)[] LessonHours { get; }
internal DayOfWeek DayOfWeek { get; }
internal Day(int dayIndex, int dayLessonsCount)
{
LessonHours = new (TimeRange, Lesson?)[dayLessonsCount];
DayOfWeek = dayIndex switch
{
0 => DayOfWeek.Monday,
1 => DayOfWeek.Tuesday,
2 => DayOfWeek.Wednesday,
3 => DayOfWeek.Thursday,
4 => DayOfWeek.Friday,
5 => DayOfWeek.Saturday,
6 => DayOfWeek.Sunday,
_ => throw new Exception($"there is no day of week with index {dayIndex}")
};
}
public class Lesson
{
// example: Жанабеков Ж.О
public string TutorName { get; }
/// example: 420 б
public string Auditory { get; }
/// example: Байзак центр
public string Building { get; }
/// example: Lecture
public string LessonTypeName { get; }
/// example: Программирование на языке С#
public string SubjectName { get; }
/// may not work, idk
public bool OnlineClass { get; }
internal Lesson(ScheduleResponse.Timetable.Day.LessonWrapper.Lesson lessonData)
{
TutorName = lessonData.tutorName;
Auditory = lessonData.auditory;
Building = lessonData.building;
LessonTypeName = lessonData.groupTypeFullName;
SubjectName = lessonData.subjectName;
OnlineClass = lessonData.onlineClass;
}
}
}
}

View File

@ -1,6 +1,6 @@
namespace Platonus.API.DataModels; namespace Platonus.API.DataModels;
public class ScheduleRequest internal class ScheduleRequest
{ {
public int statusID { get; set; } = 1; public int statusID { get; set; } = 1;
public int studentTypeID { get; set; } = 1; public int studentTypeID { get; set; } = 1;

View File

@ -0,0 +1,88 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Platonus.API.DataModels;
#nullable disable
internal class ScheduleResponse
{
/// example: 2023
[JsonRequired] public int selectedStudyYear { get; set; }
/// 1 or 2
[JsonRequired] public int selectedTerm { get; set; }
[JsonRequired] public int defaultSelectedTerm { get; set; }
/// selected week number
[JsonRequired] public int selectedWeek { get; set; }
[JsonRequired] public int defaultSelectedWeek { get; set; }
/// current week number
[JsonRequired] public int activeWeekNumber { get; set; }
/// all week numbers
[JsonRequired] public List<int> weekList { get; set; }
/// all lesson hours in the week
[JsonRequired] public List<LessonHour> lessonHours { get; set; }
public class LessonHour
{
/// number of the lesson in Timetable.Day.lessons
[JsonRequired] public int number { get; set; }
/// example: 08:00:00
[JsonRequired] public string start { get; set; }
/// example: 08:50:00
[JsonRequired] public string finish { get; set; }
/// duration in minutes, usually 50
[JsonRequired] public int duration { get; set; }
/// idk what is it
[JsonRequired] public int shiftNumber { get; set; }
/// idk what is it
[JsonRequired] public int displayNumber { get; set; }
}
/// all days with lesson hours with or without lessons
[JsonRequired] public Timetable timetable { get; set; }
public class Timetable
{
/// day number string, Day class
[JsonRequired] public Dictionary<string, Day> days { get; set; }
public class Day
{
/// Lesson.number string, LessonWrapper class
[JsonRequired] public Dictionary<string, LessonWrapper> lessons { get; set; }
public class LessonWrapper
{
/// one or zero lessons at time
[JsonRequired] public List<Lesson> lessons { get; set; }
public class Lesson
{
/// number of the lesson, corresponds a number in a LessonHour
[JsonRequired] public int number { get; set; }
/// example: Жанабеков Ж.О
[JsonRequired] public string tutorName { get; set; }
/// same as tutorName
[JsonRequired] public string tutorShortName { get; set; }
/// example: 420 б
[JsonRequired] public string auditory { get; set; }
/// example: Байзак центр
[JsonRequired] public string building { get; set; }
/// some platonus internal id
[JsonRequired] public int lessonID { get; set; }
/// some platonus internal group id
[JsonRequired] public int studyGroupID { get; set; }
/// example: SFT6541-6-L
[JsonRequired] public string studygroupShortName { get; set; }
/// example: Программирование на языке С#,'Л'
[JsonRequired] public string studyGroupName { get; set; }
/// example: L
[JsonRequired] public string groupTypeShortName { get; set; }
/// example: Lecture
[JsonRequired] public string groupTypeFullName { get; set; }
/// example: Программирование на языке С#
[JsonRequired] public string subjectName { get; set; }
/// may not work, idk
[JsonRequired] public bool onlineClass { get; set; }
}
}
}
}
}

View File

@ -5,9 +5,9 @@ using System.Threading.Tasks;
namespace Platonus.API; namespace Platonus.API;
public class LoggindHttpHandler : DelegatingHandler public class LoggingHttpHandler : DelegatingHandler
{ {
public LoggindHttpHandler(HttpMessageHandler innerHandler) : base(innerHandler) public LoggingHttpHandler(HttpMessageHandler innerHandler) : base(innerHandler)
{ } { }
void LogHttpRequest(HttpRequestMessage req) void LogHttpRequest(HttpRequestMessage req)

View File

@ -30,7 +30,7 @@ public class PlatonusClient
{ {
CookieContainer = _cookies CookieContainer = _cookies
}; };
_http = new HttpClient(new LoggindHttpHandler(httpClientHandler)) _http = new HttpClient(new LoggingHttpHandler(httpClientHandler))
{ {
BaseAddress = new Uri(base_url) BaseAddress = new Uri(base_url)
}; };
@ -50,54 +50,35 @@ public class PlatonusClient
_language = userCredentials.Language; _language = userCredentials.Language;
reqContent.Headers.Add("language", _language.Number.ToString()); reqContent.Headers.Add("language", _language.Number.ToString());
// send POST request
try var res = await _http.PostAsync("rest/api/login", reqContent);
{ // parse json
// send POST request if (res.Content.Headers.ContentLength < 1)
var res = await _http.PostAsync("rest/api/login", reqContent); throw new Exception("responce doesn't have any content");
// parse json _loginResponse = await res.Content.ReadFromJsonAsync<LoginResponse>()
if (res.Content.Headers.ContentLength < 1) ?? throw new Exception("invalid login request rezult");
throw new Exception("responce doesn't have any content"); if(_loginResponse.login_status != "success")
_loginResponse = await res.Content.ReadFromJsonAsync<LoginResponse>() throw new Exception("invalid login request rezult");
?? throw new Exception("invalid login request rezult");
if(_loginResponse.login_status != "success") // set session id and user token headers in HttpClient
throw new Exception("invalid login request rezult"); _http.DefaultRequestHeaders.Add("sid", _loginResponse.sid);
_http.DefaultRequestHeaders.Add("token", _loginResponse.auth_token);
// set session id and user token headers in HttpClient
_http.DefaultRequestHeaders.Add("sid", _loginResponse.sid);
_http.DefaultRequestHeaders.Add("token", _loginResponse.auth_token);
}
catch (HttpRequestException re)
{
HandleRequestException(re);
}
} }
public async Task GetScheduleAsync() public async Task<Schedule> GetScheduleAsync()
{ {
if (_language is null) if (_language is null)
throw new Exception("language is null, you need to login"); throw new Exception("language is null, you need to login");
if (_loginResponse is null) if (_loginResponse is null)
throw new Exception("session id is null, you need to login"); throw new Exception("session id is null, you need to login");
try var req = JsonContent.Create(new ScheduleRequest());
{ var res = await _http.PostAsync(
var req = JsonContent.Create<ScheduleRequest>(new ScheduleRequest()); $"rest/schedule/userSchedule/student/initial/{_language.LiteralCode}",
var res = await _http.PostAsync( req);
$"rest/schedule/userSchedule/student/initial/{_language.LiteralCode}", ScheduleResponse scheduleData = await res.Content.ReadFromJsonAsync<ScheduleResponse>()
req); ?? throw new NullReferenceException("ScheduleResponse is null");
// var rezult = await res.Content.ReadFromJsonAsync<ScheduleResponseData>(); var schedule = new Schedule(scheduleData);
} return schedule;
catch (HttpRequestException re)
{
HandleRequestException(re);
}
}
private void HandleRequestException(HttpRequestException re)
{
// TODO http exception handling
throw re;
} }
} }

View File

@ -7,7 +7,7 @@ var loginCredentials = new LoginCredentials(
ReadString("password"), ReadString("password"),
PlatonusLanguage.English); PlatonusLanguage.English);
await p.LoginAsync(loginCredentials); await p.LoginAsync(loginCredentials);
await p.GetScheduleAsync(); var schedule = await p.GetScheduleAsync();
return; return;
string ReadString(string question) string ReadString(string question)