mirror of
https://github.com/XFox111/GUTSchedule.git
synced 2026-04-22 06:58:01 +03:00
Cabinet functionality updated (#25)
Cabinet authorization has been turned on Occupation check in functionality
This commit is contained in:
@@ -26,10 +26,21 @@ namespace GUTSchedule.Droid.Activities
|
|||||||
public static int SelectedCalendarIndex { get; set; }
|
public static int SelectedCalendarIndex { get; set; }
|
||||||
public static int Reminder { get; set; }
|
public static int Reminder { get; set; }
|
||||||
|
|
||||||
|
private List<(string, string)> _availableOccupations;
|
||||||
|
private List<(string, string)> AvailableOccupations
|
||||||
|
{
|
||||||
|
get => _availableOccupations;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_availableOccupations = value;
|
||||||
|
applyForOccupation.Visibility = value.Count > 0 ? ViewStates.Visible : ViewStates.Gone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DateTime startDate = DateTime.Today;
|
DateTime startDate = DateTime.Today;
|
||||||
DateTime endDate = DateTime.Today.AddDays(7);
|
DateTime endDate = DateTime.Today.AddDays(7);
|
||||||
|
|
||||||
Button start, end, export;
|
Button start, end, export, applyForOccupation, validateCredential;
|
||||||
Button forDay, forWeek, forMonth, forSemester;
|
Button forDay, forWeek, forMonth, forSemester;
|
||||||
Spinner faculty, course, group, reminder, calendar;
|
Spinner faculty, course, group, reminder, calendar;
|
||||||
CheckBox groupTitle, authorize;
|
CheckBox groupTitle, authorize;
|
||||||
@@ -81,10 +92,19 @@ 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", "");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AvailableOccupations = await Parser.CheckAvailableOccupations(email.Text, password.Text);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
AvailableOccupations = new List<(string, string)>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Export_Click(object sender, EventArgs e)
|
private void Export_Click(object sender, EventArgs e)
|
||||||
@@ -119,7 +139,7 @@ namespace GUTSchedule.Droid.Activities
|
|||||||
// According to this SO thread: https://stackoverflow.com/questions/1925486/android-storing-username-and-password
|
// According to this SO thread: https://stackoverflow.com/questions/1925486/android-storing-username-and-password
|
||||||
// I consider Preferences as safe enough method for storing credentials
|
// I consider Preferences as safe enough method for storing credentials
|
||||||
// А во-вторых, даже такой казалось бы небезопасный метод хранения учетных данных в сто раз надежнее того дерьма,
|
// А во-вторых, даже такой казалось бы небезопасный метод хранения учетных данных в сто раз надежнее того дерьма,
|
||||||
// что творится на серверах Бонча (я не шучу, там все ОЧЕНЬ плохо)
|
// что творится на серверах Бонча (я не шучу, там пиздец)
|
||||||
// Ну и в-третьих: Андроид - это пиздец и настоящий ад разработчика. И если бы была моя воля, я бы под него никогда не писал #FuckAndroid
|
// Ну и в-третьих: Андроид - это пиздец и настоящий ад разработчика. И если бы была моя воля, я бы под него никогда не писал #FuckAndroid
|
||||||
// З.Ы. Помнишь про второй пункт? Так вот, если ты используешь такой же пароль как в ЛК где-то еще, настоятельно рекомендую его поменять
|
// З.Ы. Помнишь про второй пункт? Так вот, если ты используешь такой же пароль как в ЛК где-то еще, настоятельно рекомендую его поменять
|
||||||
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("email", email.Text).Apply();
|
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("email", email.Text).Apply();
|
||||||
@@ -192,6 +212,8 @@ namespace GUTSchedule.Droid.Activities
|
|||||||
forWeek = FindViewById<Button>(Resource.Id.forWeek);
|
forWeek = FindViewById<Button>(Resource.Id.forWeek);
|
||||||
forMonth = FindViewById<Button>(Resource.Id.forMonth);
|
forMonth = FindViewById<Button>(Resource.Id.forMonth);
|
||||||
forSemester = FindViewById<Button>(Resource.Id.forSemester);
|
forSemester = FindViewById<Button>(Resource.Id.forSemester);
|
||||||
|
applyForOccupation = FindViewById<Button>(Resource.Id.applyForOccupation);
|
||||||
|
validateCredential = FindViewById<Button>(Resource.Id.validateCredential);
|
||||||
|
|
||||||
faculty = FindViewById<Spinner>(Resource.Id.faculty);
|
faculty = FindViewById<Spinner>(Resource.Id.faculty);
|
||||||
course = FindViewById<Spinner>(Resource.Id.course);
|
course = FindViewById<Spinner>(Resource.Id.course);
|
||||||
@@ -261,6 +283,40 @@ namespace GUTSchedule.Droid.Activities
|
|||||||
endDate = new DateTime(DateTime.Today.Year, 8, 31);
|
endDate = new DateTime(DateTime.Today.Year, 8, 31);
|
||||||
end.Text = endDate.ToShortDateString();
|
end.Text = endDate.ToShortDateString();
|
||||||
};
|
};
|
||||||
|
applyForOccupation.Click += async (s, e) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
applyForOccupation.Visibility = ViewStates.Gone;
|
||||||
|
var occupations = await Parser.CheckAvailableOccupations(email.Text, password.Text);
|
||||||
|
await Parser.ApplyForOccupations(email.Text, password.Text, occupations);
|
||||||
|
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.attendSuccess), ToastLength.Short).Show();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Toast.MakeText(ApplicationContext, $"{Resources.GetText(Resource.String.attendFailed)}\n{ex.Message}", ToastLength.Short).Show();
|
||||||
|
}
|
||||||
|
AvailableOccupations = await Parser.CheckAvailableOccupations(email.Text, password.Text);
|
||||||
|
};
|
||||||
|
validateCredential.Click += async (s, e) =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
validateCredential.Enabled = false;
|
||||||
|
await Parser.VaildateAuthorization(email.Text, password.Text);
|
||||||
|
|
||||||
|
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("email", email.Text).Apply();
|
||||||
|
PreferenceManager.GetDefaultSharedPreferences(this).Edit().PutString("password", password.Text).Apply();
|
||||||
|
|
||||||
|
AvailableOccupations = await Parser.CheckAvailableOccupations(email.Text, password.Text);
|
||||||
|
Toast.MakeText(ApplicationContext, Resources.GetText(Resource.String.validationSuccess), ToastLength.Short).Show();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Toast.MakeText(ApplicationContext, $"{Resources.GetText(Resource.String.validationFailed)}\n{ex.Message}", ToastLength.Short).Show();
|
||||||
|
}
|
||||||
|
validateCredential.Enabled = true;
|
||||||
|
};
|
||||||
|
|
||||||
start.Click += Start_Click;
|
start.Click += Start_Click;
|
||||||
end.Click += End_Click;
|
end.Click += End_Click;
|
||||||
|
|||||||
@@ -138,6 +138,9 @@
|
|||||||
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.Design" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.Core.Utils" Version="28.0.0.3" />
|
||||||
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" />
|
<PackageReference Include="Xamarin.Android.Support.CustomTabs" Version="28.0.0.3" />
|
||||||
|
<PackageReference Include="Xamarin.Android.Support.v7.AppCompat">
|
||||||
|
<Version>28.0.0.3</Version>
|
||||||
|
</PackageReference>
|
||||||
<PackageReference Include="Xamarin.Essentials" Version="1.3.1" />
|
<PackageReference Include="Xamarin.Essentials" Version="1.3.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
+343
-320
File diff suppressed because it is too large
Load Diff
@@ -11,6 +11,15 @@
|
|||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:padding="10dp">
|
android:padding="10dp">
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/applyForOccupation"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:visibility="gone"
|
||||||
|
android:text="@string/applyForOccupation"
|
||||||
|
android:background="@color/colorPrimary"
|
||||||
|
android:textColor="@android:color/white"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
@@ -22,15 +31,15 @@
|
|||||||
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:enabled="false"
|
android:checked="true"
|
||||||
android:checked="false"
|
|
||||||
android:text="@string/authorizeCheckbox"/>
|
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"
|
||||||
|
android:visibility="gone">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -67,8 +76,7 @@
|
|||||||
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">
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@@ -91,6 +99,13 @@
|
|||||||
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"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/validateCredential"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/validateCredential"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
|||||||
@@ -28,6 +28,14 @@
|
|||||||
<string name="groupSpinner">Группа</string>
|
<string name="groupSpinner">Группа</string>
|
||||||
|
|
||||||
<string name="passwordField">Пароль</string>
|
<string name="passwordField">Пароль</string>
|
||||||
|
<string name="applyForOccupation">Начать занятие</string>
|
||||||
|
<string name="validateCredential">Проверить данные</string>
|
||||||
|
|
||||||
|
<string name="attendFailed">Что-то пошло не так. Попроуйте снова или выполните действие через личный кабинет</string>
|
||||||
|
<string name="attendSuccess">Регистрация на занятие выполнена</string>
|
||||||
|
|
||||||
|
<string name="validationSuccess">Авторизация выполнена успешно</string>
|
||||||
|
<string name="validationFailed">Ошибка авторизации. Проверьте данные.</string>
|
||||||
|
|
||||||
<string name="exportParametersTitle">Параметры экспорта</string>
|
<string name="exportParametersTitle">Параметры экспорта</string>
|
||||||
<string name="dateRange">Диапазон экспорта</string>
|
<string name="dateRange">Диапазон экспорта</string>
|
||||||
|
|||||||
@@ -27,6 +27,14 @@
|
|||||||
<string name="groupSpinner">Group</string>
|
<string name="groupSpinner">Group</string>
|
||||||
|
|
||||||
<string name="passwordField">Password</string>
|
<string name="passwordField">Password</string>
|
||||||
|
<string name="applyForOccupation">Apply for occupation</string>
|
||||||
|
<string name="validateCredential">Validate credential</string>
|
||||||
|
|
||||||
|
<string name="attendFailed">Something went wrong. Please try again or do it via personal cabinet</string>
|
||||||
|
<string name="attendSuccess">Successfully registered for occupation</string>
|
||||||
|
|
||||||
|
<string name="validationSuccess">Authorized successfully</string>
|
||||||
|
<string name="validationFailed">Authorization failed. Check your credential.</string>
|
||||||
|
|
||||||
<string name="exportParametersTitle">Export parameters</string>
|
<string name="exportParametersTitle">Export parameters</string>
|
||||||
<string name="dateRange">Export range</string>
|
<string name="dateRange">Export range</string>
|
||||||
@@ -37,7 +45,7 @@
|
|||||||
<string name="forSemesterButton">For semester</string>
|
<string name="forSemesterButton">For semester</string>
|
||||||
|
|
||||||
<string name="reminderSpinner">Set reminders for</string>
|
<string name="reminderSpinner">Set reminders for</string>
|
||||||
<string name="reminderNote">(i) Attention, if you choose \"None\" for cloud-based Google calendars Google sets default reminder for events automatically sets reminders for 30 minutes if there\'s no reminder set by user</string>
|
<string name="reminderNote">(i) Attention, if you choose \"None\" for cloud-based Google calendars Google sets default reminder for events automatically (usually, 30 minutes)</string>
|
||||||
<string name="noReminderOption">None</string>
|
<string name="noReminderOption">None</string>
|
||||||
<string name="inTimeReminderOption">At the start of event</string>
|
<string name="inTimeReminderOption">At the start of event</string>
|
||||||
<string name="fiveMinuteReminderOption">5 minutes</string>
|
<string name="fiveMinuteReminderOption">5 minutes</string>
|
||||||
|
|||||||
@@ -13,9 +13,7 @@ namespace GUTSchedule.Test
|
|||||||
[Test]
|
[Test]
|
||||||
public async Task ScheduleListTest()
|
public async Task ScheduleListTest()
|
||||||
{
|
{
|
||||||
Assert.Warn("Feature is temporarly disabled. Skipping test");
|
JObject secrets = JsonConvert.DeserializeObject(File.ReadAllText(Directory.GetCurrentDirectory() + "\\TestCredential.json")) as JObject;
|
||||||
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"].ToObject<string>(),
|
Email = secrets["testEmail"].ToObject<string>(),
|
||||||
@@ -36,7 +34,43 @@ 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);
|
||||||
}*/
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task OccupationsCheckTest()
|
||||||
|
{
|
||||||
|
JObject secrets = JsonConvert.DeserializeObject(File.ReadAllText(Directory.GetCurrentDirectory() + "\\TestCredential.json")) as JObject;
|
||||||
|
var list = await Parser.CheckAvailableOccupations(secrets["testEmail"].ToObject<string>(), secrets["testPassword"].ToObject<string>());
|
||||||
|
|
||||||
|
Assert.IsNotNull(list);
|
||||||
|
if (list.Count < 1)
|
||||||
|
{
|
||||||
|
Assert.Warn("No available occupations");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Available occupations:");
|
||||||
|
list.ForEach(i => Console.WriteLine($"{i.Item1} / {i.Item2}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task ApplyForOccupationsTest()
|
||||||
|
{
|
||||||
|
JObject secrets = JsonConvert.DeserializeObject(File.ReadAllText(Directory.GetCurrentDirectory() + "\\TestCredential.json")) as JObject;
|
||||||
|
var list = await Parser.CheckAvailableOccupations(secrets["testEmail"].ToObject<string>(), secrets["testPassword"].ToObject<string>());
|
||||||
|
|
||||||
|
Assert.IsNotNull(list);
|
||||||
|
if (list.Count < 1)
|
||||||
|
{
|
||||||
|
Assert.Warn("No available occupations to test");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console.WriteLine("Available occupations:");
|
||||||
|
list.ForEach(i => Console.WriteLine($"{i.Item1} / {i.Item2}"));
|
||||||
|
|
||||||
|
await Parser.ApplyForOccupations(secrets["testEmail"].ToObject<string>(), secrets["testPassword"].ToObject<string>(), list);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -61,15 +61,18 @@
|
|||||||
<ColumnDefinition Width="0"/>
|
<ColumnDefinition Width="0"/>
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<StackPanel Padding="10" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
<StackPanel Padding="10" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||||
|
<Button x:Uid="applyForOccupation" x:Name="applyForOccupation" Content="Register for lesson" Click="ApplyForLesson" Style="{StaticResource AccentButtonStyle}" Visibility="Collapsed"/>
|
||||||
|
|
||||||
<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="False" IsEnabled="False" x:Name="authorize"/>
|
<CheckBox x:Uid="authorizeCheckbox" Content="Authorize via personal cabinet" Checked="ChangeAuthorizationMethod" Unchecked="ChangeAuthorizationMethod" IsChecked="True" x:Name="authorize"/>
|
||||||
<StackPanel x:Name="credentialMethod" Visibility="Collapsed">
|
<StackPanel x:Name="credentialMethod" Visibility="Visible">
|
||||||
<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"/>
|
||||||
|
<Button x:Uid="validateCredential" x:Name="validateCredential" Content="Validate credential" Click="ValidateCredential"/>
|
||||||
<CheckBox x:Uid="remember" Content="Remember" x:Name="rememberCredential" Checked="RememberCredential_Checked" Unchecked="RememberCredential_Checked"/>
|
<CheckBox x:Uid="remember" Content="Remember" x:Name="rememberCredential" Checked="RememberCredential_Checked" Unchecked="RememberCredential_Checked"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel x:Name="defaultMethod" Visibility="Visible">
|
<StackPanel x:Name="defaultMethod" Visibility="Collapsed">
|
||||||
<ComboBox x:Uid="facultySpinner" x:Name="faculty" PlaceholderText="No schedule is available" Header="Course" SelectionChanged="Faculty_SelectionChanged"/>
|
<ComboBox x:Uid="facultySpinner" x:Name="faculty" PlaceholderText="No schedule is available" Header="Course" SelectionChanged="Faculty_SelectionChanged"/>
|
||||||
<ComboBox x:Uid="courseSpinner" x:Name="course" Header="Course" SelectionChanged="Course_SelectionChanged">
|
<ComboBox x:Uid="courseSpinner" x:Name="course" Header="Course" SelectionChanged="Course_SelectionChanged">
|
||||||
<ComboBoxItem Content="1"/>
|
<ComboBoxItem Content="1"/>
|
||||||
|
|||||||
@@ -24,6 +24,17 @@ namespace GUTSchedule.UWP.Pages
|
|||||||
private readonly ResourceLoader resources = ResourceLoader.GetForCurrentView();
|
private readonly ResourceLoader resources = ResourceLoader.GetForCurrentView();
|
||||||
static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
|
static readonly ApplicationDataContainer settings = ApplicationData.Current.LocalSettings;
|
||||||
|
|
||||||
|
private List<(string, string)> _availableOccupations;
|
||||||
|
private List<(string, string)> AvailableOccupations
|
||||||
|
{
|
||||||
|
get => _availableOccupations;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_availableOccupations = value;
|
||||||
|
applyForOccupation.Visibility = value.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public MainPage() =>
|
public MainPage() =>
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
@@ -34,7 +45,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;
|
||||||
@@ -59,6 +70,15 @@ namespace GUTSchedule.UWP.Pages
|
|||||||
|
|
||||||
reminder.SelectedIndex = (int?)settings.Values["Reminder"] ?? 2;
|
reminder.SelectedIndex = (int?)settings.Values["Reminder"] ?? 2;
|
||||||
addGroupToTitle.IsChecked = (bool?)settings.Values["AddGroupToTitle"] ?? false;
|
addGroupToTitle.IsChecked = (bool?)settings.Values["AddGroupToTitle"] ?? false;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
AvailableOccupations = await Parser.CheckAvailableOccupations(email.Text, password.Password);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
AvailableOccupations = new List<(string, string)>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (HttpRequestException e)
|
catch (HttpRequestException e)
|
||||||
{
|
{
|
||||||
@@ -281,5 +301,49 @@ namespace GUTSchedule.UWP.Pages
|
|||||||
|
|
||||||
await dialog.ShowAsync();
|
await dialog.ShowAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void ValidateCredential(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
validateCredential.IsEnabled = false;
|
||||||
|
await Parser.VaildateAuthorization(email.Text, password.Password);
|
||||||
|
|
||||||
|
if (rememberCredential.IsChecked.Value)
|
||||||
|
vault.Add(new PasswordCredential
|
||||||
|
{
|
||||||
|
UserName = email.Text,
|
||||||
|
Password = password.Password,
|
||||||
|
Resource = "xfox111.gutschedule"
|
||||||
|
});
|
||||||
|
else
|
||||||
|
foreach (PasswordCredential credential in vault.RetrieveAll())
|
||||||
|
vault.Remove(credential);
|
||||||
|
|
||||||
|
AvailableOccupations = await Parser.CheckAvailableOccupations(email.Text, password.Password);
|
||||||
|
await new MessageDialog(resources.GetString("validationSuccess")).ShowAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await new MessageDialog($"{resources.GetString("validationFailed")}\n{ex.Message}").ShowAsync();
|
||||||
|
}
|
||||||
|
validateCredential.IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ApplyForLesson(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
applyForOccupation.Visibility = Visibility.Collapsed;
|
||||||
|
AvailableOccupations = await Parser.CheckAvailableOccupations(email.Text, password.Password);
|
||||||
|
await Parser.ApplyForOccupations(email.Text, password.Password, AvailableOccupations);
|
||||||
|
await new MessageDialog(resources.GetString("attendSuccess")).ShowAsync();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await new MessageDialog($"{resources.GetString("attendFailed")}\n{ex.Message}").ShowAsync();
|
||||||
|
applyForOccupation.Visibility = Visibility.Visible;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,7 +160,10 @@
|
|||||||
<value>Schedule is cleared</value>
|
<value>Schedule is cleared</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="clearScheduleMessage" xml:space="preserve">
|
<data name="clearScheduleMessage" xml:space="preserve">
|
||||||
<value>This action will purge exported schedule from all available calendars.
|
<value>This action will purge exported schedule from all available calendars.
|
||||||
|
It will affect only events created by the app.
|
||||||
|
'All' - will purge all timetable events including the past ones
|
||||||
|
'Upcoming' - will affect only upcoming timetable events</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="clearScheduleTitle.PrimaryButtonText" xml:space="preserve">
|
<data name="clearScheduleTitle.PrimaryButtonText" xml:space="preserve">
|
||||||
<value>Clear schedule</value>
|
<value>Clear schedule</value>
|
||||||
@@ -327,4 +330,22 @@
|
|||||||
<data name="websiteContact.Text" xml:space="preserve">
|
<data name="websiteContact.Text" xml:space="preserve">
|
||||||
<value>Website</value>
|
<value>Website</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="applyForOccupation.Content" xml:space="preserve">
|
||||||
|
<value>Apply for occupation</value>
|
||||||
|
</data>
|
||||||
|
<data name="validateCredential.Content" xml:space="preserve">
|
||||||
|
<value>Validate credential</value>
|
||||||
|
</data>
|
||||||
|
<data name="attendFailed" xml:space="preserve">
|
||||||
|
<value>Something went wrong. Please try again or do it via personal cabinet</value>
|
||||||
|
</data>
|
||||||
|
<data name="attendSuccess" xml:space="preserve">
|
||||||
|
<value>Successfully registered for occupation</value>
|
||||||
|
</data>
|
||||||
|
<data name="validationSuccess" xml:space="preserve">
|
||||||
|
<value>Authorized successfully</value>
|
||||||
|
</data>
|
||||||
|
<data name="validationFailed" xml:space="preserve">
|
||||||
|
<value>Authorization failed. Check your credential.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -160,7 +160,10 @@
|
|||||||
<value>Расписание очищено</value>
|
<value>Расписание очищено</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="clearScheduleMessage" xml:space="preserve">
|
<data name="clearScheduleMessage" xml:space="preserve">
|
||||||
<value>Это действие удалит экспортированное расписание из всех доступных календарей.
|
<value>Это действие удалит экспортированное расписание из всех доступных календарей.
|
||||||
|
Данное действие затронет только расписание, экспортированное этим приложением
|
||||||
|
'Все' - удалит все события расписания, включая прошедшие
|
||||||
|
'Только новые' - удалит будущие события расписания</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="clearScheduleTitle.PrimaryButtonText" xml:space="preserve">
|
<data name="clearScheduleTitle.PrimaryButtonText" xml:space="preserve">
|
||||||
<value>Очистить расписание</value>
|
<value>Очистить расписание</value>
|
||||||
@@ -327,4 +330,22 @@
|
|||||||
<data name="websiteContact.Text" xml:space="preserve">
|
<data name="websiteContact.Text" xml:space="preserve">
|
||||||
<value>Веб-сайт</value>
|
<value>Веб-сайт</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="applyForOccupation.Content" xml:space="preserve">
|
||||||
|
<value>Начать занятие</value>
|
||||||
|
</data>
|
||||||
|
<data name="validateCredential.Content" xml:space="preserve">
|
||||||
|
<value>Проверить данные</value>
|
||||||
|
</data>
|
||||||
|
<data name="attendFailed" xml:space="preserve">
|
||||||
|
<value>Что-то пошло не так. Попроуйте снова или выполните действие через личный кабинет</value>
|
||||||
|
</data>
|
||||||
|
<data name="attendSuccess" xml:space="preserve">
|
||||||
|
<value>Регистрация на занятие выполнена</value>
|
||||||
|
</data>
|
||||||
|
<data name="validationSuccess" xml:space="preserve">
|
||||||
|
<value>Авторизация выполнена успешно</value>
|
||||||
|
</data>
|
||||||
|
<data name="validationFailed" xml:space="preserve">
|
||||||
|
<value>Ошибка авторизации. Проверьте данные.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -8,13 +8,14 @@ using System.Globalization;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace GUTSchedule
|
namespace GUTSchedule
|
||||||
{
|
{
|
||||||
public static class Parser
|
public static class Parser
|
||||||
{
|
{
|
||||||
private static async Task<HttpClient> VaildateAuthorization(string email, string password)
|
public static async Task<HttpClient> VaildateAuthorization(string email, string password)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrWhiteSpace(email))
|
if (string.IsNullOrWhiteSpace(email))
|
||||||
throw new ArgumentNullException(nameof(email));
|
throw new ArgumentNullException(nameof(email));
|
||||||
@@ -46,6 +47,8 @@ namespace GUTSchedule
|
|||||||
throw new System.Security.VerificationException(responseQuery["error"].Replace("|", "; "));
|
throw new System.Security.VerificationException(responseQuery["error"].Replace("|", "; "));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await client.GetAsync("https://lk.sut.ru/cabinet/?login=yes");
|
||||||
|
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,5 +443,30 @@ namespace GUTSchedule
|
|||||||
|
|
||||||
return schedule;
|
return schedule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async Task<List<(string, string)>> CheckAvailableOccupations(string email, string password)
|
||||||
|
{
|
||||||
|
HttpClient client = await VaildateAuthorization(email, password);
|
||||||
|
HttpResponseMessage response = await client.GetAsync("https://lk.sut.ru/cabinet//project/cabinet/forms/raspisanie_bak.php");
|
||||||
|
string responseContent = await response.GetString();
|
||||||
|
|
||||||
|
if (!response.IsSuccessStatusCode)
|
||||||
|
throw new HttpRequestException(responseContent);
|
||||||
|
|
||||||
|
IHtmlDocument doc = new HtmlParser().ParseDocument(responseContent);
|
||||||
|
List<(string, string)> occupations = doc.QuerySelectorAll(".simple-little-table td[align=left] > span[id] > a").Select(i =>
|
||||||
|
{
|
||||||
|
string[] parameters = new Regex(@"(?<=\()[0-9,]*(?=\))").Match(i.Attributes["onclick"].Value).Value.Split(',');
|
||||||
|
return (parameters[0], parameters[1]);
|
||||||
|
}).ToList();
|
||||||
|
return occupations;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async Task ApplyForOccupations(string email, string password, List<(string, string)> occupations)
|
||||||
|
{
|
||||||
|
HttpClient client = await VaildateAuthorization(email, password);
|
||||||
|
foreach (var i in occupations)
|
||||||
|
await client.GetAsync($"https://lk.sut.ru/cabinet/project/cabinet/forms/raspisanie_bak.php?open=1&rasp={i.Item1}&week={i.Item2}");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
- Updated schedule parser Обновлен парсер расписания
|
- Personal cabinet authorization is available again
|
||||||
|
- Added ability to validate your personal cabinet credential
|
||||||
Personal cabinet authorization still disabled due to some server-side connection issues
|
- Added ability to apply for lesson in one click
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
- Обновлен парсер расписания
|
- Авторизация через личный кабинет снова доступна
|
||||||
|
- Добавлена возможность проверить введеные данные личного кабинета
|
||||||
Авторизация через личный кабинет все еще отключена из-за проблем подкключения на серверной стороне
|
- Добавлена возможность регистрироваться на занятия с помощью одного клика
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
- Updated schedule parser Обновлен парсер расписания
|
- Personal cabinet authorization is available again
|
||||||
|
- Added ability to validate your personal cabinet credential
|
||||||
Personal cabinet authorization still disabled due to some server-side connection issues
|
- Added ability to apply for lesson in one click
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
- Обновлен парсер расписания
|
- Авторизация через личный кабинет снова доступна
|
||||||
|
- Добавлена возможность проверить введеные данные личного кабинета
|
||||||
Авторизация через личный кабинет все еще отключена из-за проблем подкключения на серверной стороне
|
- Добавлена возможность регистрироваться на занятия с помощью одного клика
|
||||||
Reference in New Issue
Block a user