1
0
mirror of https://github.com/XFox111/GUTSchedule.git synced 2026-04-22 06:58:01 +03:00

- Updated schedule parser

- Authorization via personal cabinet is temporarly disabled
- Updated target Android version
This commit is contained in:
Michael Gordeev
2020-08-30 09:06:41 +03:00
parent ebdafc273f
commit 634804cbdc
12 changed files with 231 additions and 221 deletions
@@ -81,7 +81,7 @@ namespace GUTSchedule.Droid.Activities
start.Text = startDate.ToShortDateString(); start.Text = startDate.ToShortDateString();
groupTitle.Checked = prefs.GetBoolean("AddGroupToHeader", false); groupTitle.Checked = prefs.GetBoolean("AddGroupToHeader", false);
authorize.Checked = prefs.GetBoolean("Authorize", true); //authorize.Checked = prefs.GetBoolean("Authorize", true);
email.Text = prefs.GetString("email", ""); email.Text = prefs.GetString("email", "");
password.Text = prefs.GetString("password", ""); password.Text = prefs.GetString("password", "");
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="0-development-test" package="com.xfox111.gut.schedule" android:installLocation="auto"> <manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="0-development-test" package="com.xfox111.gut.schedule" android:installLocation="auto">
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="28" /> <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="29" />
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/appName" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme.Light"></application> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/appName" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme.Light"></application>
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
<uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" />
@@ -1,231 +1,234 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" <ScrollView
android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent" android:layout_width="match_parent"
android:theme="@style/AppTheme.Light"> android:layout_height="match_parent"
android:theme="@style/AppTheme.Light">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:padding="10dp"> android:padding="10dp">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/scheduleParametersTitle" android:text="@string/scheduleParametersTitle"
android:textStyle="bold" android:textStyle="bold"
android:textSize="16dp"/> android:textSize="16dp"/>
<CheckBox <CheckBox
android:id="@+id/authorization" android:id="@+id/authorization"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/authorizeCheckbox"/> android:enabled="false"
android:checked="false"
android:text="@string/authorizeCheckbox"/>
<LinearLayout <LinearLayout
android:id="@+id/studentParams" android:id="@+id/studentParams"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/facultySpinner"/> android:text="@string/facultySpinner"/>
<Spinner <Spinner
android:id="@+id/faculty" android:id="@+id/faculty"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/courseSpinner"/> android:text="@string/courseSpinner"/>
<Spinner <Spinner
android:id="@+id/course" android:id="@+id/course"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/groupSpinner"/> android:text="@string/groupSpinner"/>
<Spinner <Spinner
android:id="@+id/group" android:id="@+id/group"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/professorParams" android:id="@+id/professorParams"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical" android:orientation="vertical"
android:visibility="gone"> android:visibility="gone">
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="E-mail"/> android:text="E-mail"/>
<EditText <EditText
android:id="@+id/email" android:id="@+id/email"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textWebEmailAddress"/> android:inputType="textWebEmailAddress"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/passwordField"/> android:text="@string/passwordField"/>
<EditText <EditText
android:id="@+id/password" android:id="@+id/password"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:inputType="textWebPassword"/> android:inputType="textWebPassword"/>
</LinearLayout> </LinearLayout>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/exportParametersTitle" android:text="@string/exportParametersTitle"
android:textStyle="bold" android:textStyle="bold"
android:textSize="16dp"/> android:textSize="16dp"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/dateRange"/> android:text="@string/dateRange"/>
<TableLayout <TableLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:stretchColumns="*" android:stretchColumns="*"
android:shrinkColumns="*"> android:shrinkColumns="*">
<TableRow <TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content">
<Button <Button
android:id="@+id/start" android:id="@+id/start"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="20-Dec-2019"/> android:text="20-Dec-2019"/>
<Button <Button
android:id="@+id/end" android:id="@+id/end"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="31-Dec-2019"/> android:text="31-Dec-2019"/>
</TableRow> </TableRow>
<TableRow <TableRow
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="10dp"> android:layout_marginTop="10dp">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<Button <Button
android:id="@+id/forDay" android:id="@+id/forDay"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/forDayButton"/> android:text="@string/forDayButton"/>
<Button <Button
android:id="@+id/forWeek" android:id="@+id/forWeek"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/forWeekButton"/> android:text="@string/forWeekButton"/>
</LinearLayout> </LinearLayout>
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:orientation="vertical"> android:orientation="vertical">
<Button <Button
android:id="@+id/forMonth" android:id="@+id/forMonth"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/forMonthButton"/> android:text="@string/forMonthButton"/>
<Button <Button
android:id="@+id/forSemester" android:id="@+id/forSemester"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/forSemesterButton"/> android:text="@string/forSemesterButton"/>
</LinearLayout> </LinearLayout>
</TableRow> </TableRow>
</TableLayout> </TableLayout>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/reminderSpinner"/> android:text="@string/reminderSpinner"/>
<Spinner <Spinner
android:id="@+id/reminder" android:id="@+id/reminder"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/reminderNote"/> android:text="@string/reminderNote"/>
<CheckBox <CheckBox
android:id="@+id/groupTitle" android:id="@+id/groupTitle"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/addGroupToTitleCheckbox"/> android:text="@string/addGroupToTitleCheckbox"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/titleNote"/> android:text="@string/titleNote"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/destinationCalendarSpinner"/> android:text="@string/destinationCalendarSpinner"/>
<Spinner <Spinner
android:id="@+id/calendar" android:id="@+id/calendar"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"/> android:layout_height="wrap_content"/>
<TextView <TextView
android:id="@+id/error" android:id="@+id/error"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:textColor="#FF0000" android:textColor="#FF0000"
android:text="Error" android:text="Error"
android:layout_marginVertical="5dp" android:layout_marginVertical="5dp"
android:visibility="gone"/> android:visibility="gone"/>
<Button <Button
android:id="@+id/export" android:id="@+id/export"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/addScheduleButton"/> android:text="@string/addScheduleButton"/>
<TextView <TextView
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/copyrights"/> android:text="@string/copyrights"/>
<TextView <TextView
android:id="@+id/version" android:id="@+id/version"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="v$(Build.BuildNumber) (ci-id #$(Build.BuildId))"/> android:text="v$(Build.BuildNumber) (ci-id #$(Build.BuildId))"/>
</LinearLayout> </LinearLayout>
</ScrollView> </ScrollView>
@@ -4,6 +4,7 @@ using GUTSchedule.Models;
using System; using System;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.IO; using System.IO;
using Newtonsoft.Json.Linq;
namespace GUTSchedule.Test namespace GUTSchedule.Test
{ {
@@ -12,11 +13,13 @@ namespace GUTSchedule.Test
[Test] [Test]
public async Task ScheduleListTest() public async Task ScheduleListTest()
{ {
dynamic secrets = JsonConvert.DeserializeObject(File.ReadAllText(Directory.GetCurrentDirectory() + "\\TestCredential.json")); Assert.Warn("Feature is temporarly disabled. Skipping test");
Assert.Pass();
/*JObject secrets = JsonConvert.DeserializeObject(File.ReadAllText(Directory.GetCurrentDirectory() + "\\TestCredential.json")) as JObject;
var list = await Parser.GetSchedule(new CabinetExportParameters var list = await Parser.GetSchedule(new CabinetExportParameters
{ {
Email = secrets.testEmail, Email = secrets["testEmail"].ToObject<string>(),
Password = secrets.testPassword, Password = secrets["testPassword"].ToObject<string>(),
EndDate = DateTime.Today.AddDays(7), EndDate = DateTime.Today.AddDays(7),
StartDate = DateTime.Today StartDate = DateTime.Today
}); });
@@ -24,7 +27,6 @@ namespace GUTSchedule.Test
Assert.IsNotNull(list); Assert.IsNotNull(list);
Assert.IsTrue(list.Count > 0); Assert.IsTrue(list.Count > 0);
Console.WriteLine("Events list:"); Console.WriteLine("Events list:");
foreach (var i in list) foreach (var i in list)
{ {
@@ -34,7 +36,7 @@ namespace GUTSchedule.Test
Console.WriteLine(i.StartTime.ToShortDateString()); Console.WriteLine(i.StartTime.ToShortDateString());
Console.WriteLine($"{i.StartTime.ToShortTimeString()}-{i.EndTime.ToShortTimeString()}"); Console.WriteLine($"{i.StartTime.ToShortTimeString()}-{i.EndTime.ToShortTimeString()}");
Console.WriteLine(i.Opponent); Console.WriteLine(i.Opponent);
} }*/
} }
} }
} }
@@ -63,7 +63,7 @@
<StackPanel Padding="10" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <StackPanel Padding="10" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<TextBlock x:Uid="scheduleParametersTitle" Style="{StaticResource SubtitleTextBlockStyle}" Text="Schedule parameters"/> <TextBlock x:Uid="scheduleParametersTitle" Style="{StaticResource SubtitleTextBlockStyle}" Text="Schedule parameters"/>
<CheckBox x:Uid="authorizeCheckbox" Content="Authorize via personal cabinet" Checked="ChangeAuthorizationMethod" Unchecked="ChangeAuthorizationMethod" IsChecked="True" x:Name="authorize"/> <CheckBox x:Uid="authorizeCheckbox" Content="Authorize via personal cabinet" Checked="ChangeAuthorizationMethod" Unchecked="ChangeAuthorizationMethod" IsChecked="False" IsEnabled="False" x:Name="authorize"/>
<StackPanel x:Name="credentialMethod"> <StackPanel x:Name="credentialMethod">
<TextBox x:Uid="email" PlaceholderText="E-mail" x:Name="email" IsSpellCheckEnabled="False"/> <TextBox x:Uid="email" PlaceholderText="E-mail" x:Name="email" IsSpellCheckEnabled="False"/>
<PasswordBox x:Uid="password" PlaceholderText="Password" x:Name="password"/> <PasswordBox x:Uid="password" PlaceholderText="Password" x:Name="password"/>
@@ -34,7 +34,7 @@ namespace GUTSchedule.UWP.Pages
PackageVersion ver = Package.Current.Id.Version; PackageVersion ver = Package.Current.Id.Version;
version.Text = $"v{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}"; version.Text = $"v{ver.Major}.{ver.Minor}.{ver.Build}.{ver.Revision}";
authorize.IsChecked = (bool?)settings.Values["Authorize"] ?? true; //authorize.IsChecked = (bool?)settings.Values["Authorize"] ?? true;
if (vault.RetrieveAll() is IReadOnlyList<PasswordCredential> credentials && credentials.Count > 0) if (vault.RetrieveAll() is IReadOnlyList<PasswordCredential> credentials && credentials.Count > 0)
{ {
email.Text = credentials.First().UserName; email.Text = credentials.First().UserName;
+6 -7
View File
@@ -64,10 +64,10 @@ namespace GUTSchedule
} }
else if (exportParameters is DefaultExportParameters args) else if (exportParameters is DefaultExportParameters args)
{ {
int offsetDay = int.Parse(await new HttpClient().GetStringAsync("https://xfox111.net/API/GUTSchedule/SemesterOffsetDay")); DateTime startDate = new DateTime(long.Parse(await new HttpClient().GetStringAsync("https://xfox111.net/API/GUTSchedule/SemesterOffsetDay")));
IHtmlDocument[] rawSchedule = await GetRawSchedule(args.FacultyId, args.Course, args.GroupId); IHtmlDocument[] rawSchedule = await GetRawSchedule(args.FacultyId, args.Course, args.GroupId);
if(rawSchedule[0] != null) if(rawSchedule[0] != null)
schedule.AddRange(ParseRegularSchedule(offsetDay, rawSchedule[0])); schedule.AddRange(ParseRegularSchedule(startDate, rawSchedule[0]));
if(rawSchedule[1] != null) if(rawSchedule[1] != null)
schedule.AddRange(ParseSessionSchedule(rawSchedule[1])); schedule.AddRange(ParseSessionSchedule(rawSchedule[1]));
} }
@@ -156,13 +156,12 @@ namespace GUTSchedule
return $"205.{now.Year - 2000}{now.Year - 1999}/1"; return $"205.{now.Year - 2000}{now.Year - 1999}/1";
} }
private static DateTime[] GetDatesFromWeeks(int offsetDay, int weekday, string[] weeks) private static DateTime[] GetDatesFromWeeks(DateTime date, int weekday, string[] weeks)
{ {
List<DateTime> dates = new List<DateTime>(); List<DateTime> dates = new List<DateTime>();
foreach(string rawWeek in weeks) foreach(string rawWeek in weeks)
{ {
int week = int.Parse(rawWeek.Replace("*", "")); int week = int.Parse(rawWeek.Replace("*", ""));
DateTime date = new DateTime(DateTime.Today.Year, DateTime.Today.Month >= 8 ? 9 : 2, offsetDay);
date = date.AddDays(--week * 7); date = date.AddDays(--week * 7);
date = date.AddDays(weekday - 1); date = date.AddDays(weekday - 1);
@@ -209,7 +208,7 @@ namespace GUTSchedule
return docs; return docs;
} }
private static List<Occupation> ParseRegularSchedule(int offsetDay, IHtmlDocument raw) private static List<Occupation> ParseRegularSchedule(DateTime startDate, IHtmlDocument raw)
{ {
if (raw == null) if (raw == null)
throw new ArgumentNullException(nameof(raw)); throw new ArgumentNullException(nameof(raw));
@@ -221,7 +220,7 @@ namespace GUTSchedule
foreach (IElement item in pairs) foreach (IElement item in pairs)
{ {
DateTime[] dates = GetDatesFromWeeks( DateTime[] dates = GetDatesFromWeeks(
offsetDay, startDate,
int.Parse(item.GetAttribute("weekday")), int.Parse(item.GetAttribute("weekday")),
item.QuerySelector(".weeks").TextContent.Replace("(", "").Replace("н)", "").Replace(" ", "").Split(',')); item.QuerySelector(".weeks").TextContent.Replace("(", "").Replace("н)", "").Replace(" ", "").Split(','));
@@ -233,7 +232,7 @@ namespace GUTSchedule
Name = item.QuerySelector(".subect").TextContent.Replace(" (1)", "").Replace(" (2)", ""), Name = item.QuerySelector(".subect").TextContent.Replace(" (1)", "").Replace(" (2)", ""),
Type = item.QuerySelector(".type").TextContent.Replace("(", "").Replace(")", ""), Type = item.QuerySelector(".type").TextContent.Replace("(", "").Replace(")", ""),
Group = groupName, Group = groupName,
Opponent = item.QuerySelector(".teacher")?.GetAttribute("title").Replace("; ", "") ?? "", Opponent = item.QuerySelector(".teacher")?.GetAttribute("title").Replace("; ", "\n") ?? "",
Cabinet = item.QuerySelector(".aud")?.TextContent.Replace("ауд.: ", "").Replace("; Б22", "").Replace(" ", "") ?? "СПбГУТ", Cabinet = item.QuerySelector(".aud")?.TextContent.Replace("ауд.: ", "").Replace("; Б22", "").Replace(" ", "") ?? "СПбГУТ",
Order = order > 50 ? $"Ф{order - 81}" : order.ToString() Order = order > 50 ? $"Ф{order - 81}" : order.ToString()
}; };
+1 -1
View File
@@ -13,7 +13,7 @@ Cross-platform application which exports SPbSUT timetable to calendar
- Platforms: Xamarin.Android, Universal Windows Platform - Platforms: Xamarin.Android, Universal Windows Platform
- Android: - Android:
- Minimal version: 4.1 (API level 16 - Jelly Bean) - Minimal version: 4.1 (API level 16 - Jelly Bean)
- Target version: 9.0 (API level 28 - Pie) - Target version: 10.0 (API level 29 - Oreo)
- UWP: - UWP:
- Minimal version: 1507 (10.0.10240) - Minimal version: 1507 (10.0.10240)
- Target version: 1709 (10.0.16299, Fall Creators Update) - Target version: 1709 (10.0.16299, Fall Creators Update)
@@ -1 +1,3 @@
- Fixed and improved parser - Updated schedule parser Обновлен парсер расписания
- Authorization via personal cabinet is temporarly disabled
- Updated target Android version
@@ -1 +1,3 @@
- Исправлен и улучшен парсер расписания - Обновлен парсер расписания
- Функция авторизации через ЛК временно отключена
- Обнавлена целевая версия Android
@@ -1 +1,2 @@
- Fixed and improved parser - Updated schedule parser Обновлен парсер расписания
- Authorization via personal cabinet is temporarly disabled
@@ -1 +1,2 @@
- Исправлен и улучшен парсер расписания - Обновлен парсер расписания
- Функция авторизации через ЛК временно отключена