1
0
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:
Michael Gordeev
2020-11-12 15:21:55 +03:00
committed by GitHub
parent 018981002b
commit 6c475dd621
16 changed files with 1457 additions and 1173 deletions
@@ -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;
@@ -24,7 +24,7 @@
<MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix> <MonoAndroidAssetsPrefix>Assets</MonoAndroidAssetsPrefix>
<AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent> <AndroidEnableSGenConcurrent>true</AndroidEnableSGenConcurrent>
<AndroidUseAapt2>true</AndroidUseAapt2> <AndroidUseAapt2>true</AndroidUseAapt2>
<LangVersion>8.0</LangVersion> <LangVersion>8.0</LangVersion>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>True</DebugSymbols> <DebugSymbols>True</DebugSymbols>
@@ -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>
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
@@ -1,102 +1,110 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<resources> <resources>
<string name="appName">ГУТ.Расписание</string> <string name="appName">ГУТ.Расписание</string>
<!-- StartActivity --> <!-- StartActivity -->
<string name="initializationStatus">Инициализация</string> <string name="initializationStatus">Инициализация</string>
<string name="permissionsCheckStatus">Проверка наличия разрешений</string> <string name="permissionsCheckStatus">Проверка наличия разрешений</string>
<string name="calendarLoadingStatus">Загрузка списка календарей</string> <string name="calendarLoadingStatus">Загрузка списка календарей</string>
<string name="facultiesLoadingStatus">Загрузка списка факультативов</string> <string name="facultiesLoadingStatus">Загрузка списка факультативов</string>
<string name="offsetDatesLoadingStatus">Загрузка дат смещения</string> <string name="offsetDatesLoadingStatus">Загрузка дат смещения</string>
<string name="calendarAccessTitle">Доступ к календарю</string>
<string name="calendarAccessRationale">Разрешите приложению получать доступ к календарю. Без этого разрешения приложение не сможет добавлять расписание в ваш календарь</string>
<string name="createCalendarTitle">Создайте новый календарь</string>
<string name="createCalendarMessage">На вашем устройстве нет календарей пригодных для записи расписания</string>
<string name="connectionFailMessage">Невозможно загрузить расписание. Проверьте интернет-соединение или попробуйте позже</string> <string name="calendarAccessTitle">Доступ к календарю</string>
<string name="repeat">Повторить</string> <string name="calendarAccessRationale">Разрешите приложению получать доступ к календарю. Без этого разрешения приложение не сможет добавлять расписание в ваш календарь</string>
<string name="quit">Выйти</string>
<string name="close">Закрыть</string>
<!-- MainActivity --> <string name="createCalendarTitle">Создайте новый календарь</string>
<string name="scheduleParametersTitle">Параметры расписания</string> <string name="createCalendarMessage">На вашем устройстве нет календарей пригодных для записи расписания</string>
<string name="authorizeCheckbox">Авторизоваться через Личный кабинет</string>
<string name="facultySpinner">Факультет</string>
<string name="courseSpinner">Курс</string>
<string name="groupSpinner">Группа</string>
<string name="passwordField">Пароль</string> <string name="connectionFailMessage">Невозможно загрузить расписание. Проверьте интернет-соединение или попробуйте позже</string>
<string name="repeat">Повторить</string>
<string name="quit">Выйти</string>
<string name="close">Закрыть</string>
<string name="exportParametersTitle">Параметры экспорта</string> <!-- MainActivity -->
<string name="dateRange">Диапазон экспорта</string> <string name="scheduleParametersTitle">Параметры расписания</string>
<string name="authorizeCheckbox">Авторизоваться через Личный кабинет</string>
<string name="facultySpinner">Факультет</string>
<string name="courseSpinner">Курс</string>
<string name="groupSpinner">Группа</string>
<string name="forDayButton">На день</string> <string name="passwordField">Пароль</string>
<string name="forWeekButton">На неделю</string> <string name="applyForOccupation">Начать занятие</string>
<string name="forMonthButton">На месяц</string> <string name="validateCredential">Проверить данные</string>
<string name="forSemesterButton">На семестр</string>
<string name="reminderSpinner">Напоминать за</string> <string name="attendFailed">Что-то пошло не так. Попроуйте снова или выполните действие через личный кабинет</string>
<string name="reminderNote">(i) Внимание, при экспорте в облачный Google-календарь, Google автоматически ставит уведомление за пол часа, если его не поставил пользователь</string> <string name="attendSuccess">Регистрация на занятие выполнена</string>
<string name="noReminderOption">Нет</string>
<string name="inTimeReminderOption">Во время начала</string>
<string name="fiveMinuteReminderOption">За 5 минут</string>
<string name="tenMinuteReminderOption">За 10 минут</string>
<string name="addGroupToTitleCheckbox">Добавить номер группы в заголовок</string> <string name="validationSuccess">Авторизация выполнена успешно</string>
<string name="titleNote">(i) Не касается преподавательского расписания</string> <string name="validationFailed">Ошибка авторизации. Проверьте данные.</string>
<string name="destinationCalendarSpinner">Конечный календарь</string> <string name="exportParametersTitle">Параметры экспорта</string>
<string name="dateRange">Диапазон экспорта</string>
<string name="addScheduleButton">Добавить расписание</string> <string name="forDayButton">На день</string>
<string name="forWeekButton">На неделю</string>
<string name="forMonthButton">На месяц</string>
<string name="forSemesterButton">На семестр</string>
<string name="copyrights">©2020 Михаил Гордеев, ИСиТ, ИСТ-942</string> <string name="reminderSpinner">Напоминать за</string>
<string name="reminderNote">(i) Внимание, при экспорте в облачный Google-календарь, Google автоматически ставит уведомление за пол часа, если его не поставил пользователь</string>
<string name="noReminderOption">Нет</string>
<string name="inTimeReminderOption">Во время начала</string>
<string name="fiveMinuteReminderOption">За 5 минут</string>
<string name="tenMinuteReminderOption">За 10 минут</string>
<string name="clearCalendarOption">Очистить расписание</string> <string name="addGroupToTitleCheckbox">Добавить номер группы в заголовок</string>
<string name="reportErrorOption">Сообщить об ошибке</string> <string name="titleNote">(i) Не касается преподавательского расписания</string>
<string name="invalidDateRangeError">Ошибка: Неправильный диапазон дат</string> <string name="destinationCalendarSpinner">Конечный календарь</string>
<string name="authorizationState">Авторизация...</string>
<string name="invalidAuthorizationError">Ошибка: Введите корректные учетные данные</string>
<string name="authorizationError">Ошибка авторизации</string>
<string name="invalidCredentialError">Ошибка авторизации: Неверный e-mail и/или пароль</string>
<string name="groupSelectionError">Ошибка: Не выбрана группа</string>
<string name="clearScheduleTitle">Очистка расписания</string> <string name="addScheduleButton">Добавить расписание</string>
<string name="clearScheduleMessage">Это действие удалит экспортированное расписание из всех доступных календарей. \nДанное действие затронет только расписание, экспортированное этим приложением \n\'Все\' - удалит все события расписания, включая прошедшие \n\'Только новые\' - удалит будущие события расписания
</string>
<string name="clearAllOption">Все</string>
<string name="clearUpcomingOption">Только новые</string>
<string name="cancelOption">Отмена</string>
<string name="clearingStatus">Очистка...</string>
<!-- ExportActivity --> <string name="copyrights">©2020 Михаил Гордеев, ИСиТ, ИСТ-942</string>
<string name="loadingStatus">Загрузка</string>
<string name="potatoLoadingStatus">Загрузка расписания с картофельных серверов Бонча</string> <string name="clearCalendarOption">Очистить расписание</string>
<string name="scheduleLoadingStatus">Загрузка расписания</string> <string name="reportErrorOption">Сообщить об ошибке</string>
<string name="calendarExportStatus">Экспортирование в календарь</string>
<string name="doneStatus">Готово</string> <string name="invalidDateRangeError">Ошибка: Неправильный диапазон дат</string>
<string name="authorizationState">Авторизация...</string>
<!-- AboutActivity --> <string name="invalidAuthorizationError">Ошибка: Введите корректные учетные данные</string>
<string name="aboutTitle">О приложении</string> <string name="authorizationError">Ошибка авторизации</string>
<string name="appDescription">Приложение для экспорта перподавательского и учебного расписаний Санкт-Петербургского Государственного Университета Телекоммуникаций им. проф. М.А. Бонч-Бруевича</string> <string name="invalidCredentialError">Ошибка авторизации: Неверный e-mail и/или пароль</string>
<string name="developedBy">Разработано Михаилом Гордеевым, ИСТ-942, ИСиТ в Научно-образовательном центре \"Технологии информационных образовательных систем\"</string> <string name="groupSelectionError">Ошибка: Не выбрана группа</string>
<string name="contributorsTitle">Свой вклад в разработку внесли</string>
<string name="clearScheduleTitle">Очистка расписания</string>
<string name="specialThanksTitle">Особые благодарности</string> <string name="clearScheduleMessage">Это действие удалит экспортированное расписание из всех доступных календарей. \nДанное действие затронет только расписание, экспортированное этим приложением \n\'Все\' - удалит все события расписания, включая прошедшие \n\'Только новые\' - удалит будущие события расписания
<string name="specialThanksPeople">Виталий Мошков, Анастасия Годунова</string> </string>
<string name="clearAllOption">Все</string>
<string name="contactsTitle">Контакты</string> <string name="clearUpcomingOption">Только новые</string>
<string name="websiteContact">Веб-сайт</string> <string name="cancelOption">Отмена</string>
<string name="twitterContact">Твиттер</string> <string name="clearingStatus">Очистка...</string>
<string name="vkontakteContact">ВКонтакте</string>
<!-- ExportActivity -->
<string name="linksTitle">Полезные ссылки</string> <string name="loadingStatus">Загрузка</string>
<string name="privacyPolicyLink">Политика конфиденциальности</string> <string name="potatoLoadingStatus">Загрузка расписания с картофельных серверов Бонча</string>
<string name="repositoryLink">Репозиторий GitHub</string> <string name="scheduleLoadingStatus">Загрузка расписания</string>
<string name="notsLink">НОЦ \"ТИОС\"</string> <string name="calendarExportStatus">Экспортирование в календарь</string>
<string name="sutLink">СПбГУТ</string> <string name="doneStatus">Готово</string>
<string name="feedbackButton">Оставить отзыв</string> <!-- AboutActivity -->
<string name="aboutTitle">О приложении</string>
<string name="appDescription">Приложение для экспорта перподавательского и учебного расписаний Санкт-Петербургского Государственного Университета Телекоммуникаций им. проф. М.А. Бонч-Бруевича</string>
<string name="developedBy">Разработано Михаилом Гордеевым, ИСТ-942, ИСиТ в Научно-образовательном центре \"Технологии информационных образовательных систем\"</string>
<string name="contributorsTitle">Свой вклад в разработку внесли</string>
<string name="specialThanksTitle">Особые благодарности</string>
<string name="specialThanksPeople">Виталий Мошков, Анастасия Годунова</string>
<string name="contactsTitle">Контакты</string>
<string name="websiteContact">Веб-сайт</string>
<string name="twitterContact">Твиттер</string>
<string name="vkontakteContact">ВКонтакте</string>
<string name="linksTitle">Полезные ссылки</string>
<string name="privacyPolicyLink">Политика конфиденциальности</string>
<string name="repositoryLink">Репозиторий GitHub</string>
<string name="notsLink">НОЦ \"ТИОС\"</string>
<string name="sutLink">СПбГУТ</string>
<string name="feedbackButton">Оставить отзыв</string>
</resources> </resources>
@@ -1,100 +1,108 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<resources> <resources>
<string name="appName">GUT.Schedule</string> <string name="appName">GUT.Schedule</string>
<string name="initializationStatus">Initialization</string>
<string name="permissionsCheckStatus">Checking permissions</string>
<string name="calendarLoadingStatus">Loading calendars list</string>
<string name="facultiesLoadingStatus">Loading faculties list</string>
<string name="offsetDatesLoadingStatus">Loading offset dates</string>
<string name="calendarAccessTitle">Calendar access</string>
<string name="calendarAccessRationale">Grant permission to the app to access calendar. Without it the app will not be able to add schedule to your calendar</string>
<string name="createCalendarTitle">Create new calendar</string>
<string name="createCalendarMessage">There\'s no calendars on your device we can write schedule to</string>
<string name="connectionFailMessage">Unable to load schedule. Check your internet connection or try again later</string> <string name="initializationStatus">Initialization</string>
<string name="repeat">Try again</string> <string name="permissionsCheckStatus">Checking permissions</string>
<string name="quit">Quit</string> <string name="calendarLoadingStatus">Loading calendars list</string>
<string name="close">Close</string> <string name="facultiesLoadingStatus">Loading faculties list</string>
<string name="offsetDatesLoadingStatus">Loading offset dates</string>
<!-- MainActivity --> <string name="calendarAccessTitle">Calendar access</string>
<string name="scheduleParametersTitle">Schedule parameters</string> <string name="calendarAccessRationale">Grant permission to the app to access calendar. Without it the app will not be able to add schedule to your calendar</string>
<string name="authorizeCheckbox">Authorize via Personal cabinet</string>
<string name="facultySpinner">Faculty</string>
<string name="courseSpinner">Course</string>
<string name="groupSpinner">Group</string>
<string name="passwordField">Password</string> <string name="createCalendarTitle">Create new calendar</string>
<string name="createCalendarMessage">There\'s no calendars on your device we can write schedule to</string>
<string name="exportParametersTitle">Export parameters</string> <string name="connectionFailMessage">Unable to load schedule. Check your internet connection or try again later</string>
<string name="dateRange">Export range</string> <string name="repeat">Try again</string>
<string name="quit">Quit</string>
<string name="close">Close</string>
<string name="forDayButton">For day</string> <!-- MainActivity -->
<string name="forWeekButton">For week</string> <string name="scheduleParametersTitle">Schedule parameters</string>
<string name="forMonthButton">For month</string> <string name="authorizeCheckbox">Authorize via Personal cabinet</string>
<string name="forSemesterButton">For semester</string> <string name="facultySpinner">Faculty</string>
<string name="courseSpinner">Course</string>
<string name="groupSpinner">Group</string>
<string name="reminderSpinner">Set reminders for</string> <string name="passwordField">Password</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="applyForOccupation">Apply for occupation</string>
<string name="noReminderOption">None</string> <string name="validateCredential">Validate credential</string>
<string name="inTimeReminderOption">At the start of event</string>
<string name="fiveMinuteReminderOption">5 minutes</string>
<string name="tenMinuteReminderOption">10 minutes</string>
<string name="addGroupToTitleCheckbox">Add group number to event title</string> <string name="attendFailed">Something went wrong. Please try again or do it via personal cabinet</string>
<string name="titleNote">(i) This doesn\'t affect professors\' schedule</string> <string name="attendSuccess">Successfully registered for occupation</string>
<string name="destinationCalendarSpinner">Destination calendar</string> <string name="validationSuccess">Authorized successfully</string>
<string name="validationFailed">Authorization failed. Check your credential.</string>
<string name="addScheduleButton">Add schedule</string>
<string name="copyrights">©2020 Michael Gordeev, IST, IST-942</string> <string name="exportParametersTitle">Export parameters</string>
<string name="dateRange">Export range</string>
<string name="clearCalendarOption">Clear schedule</string> <string name="forDayButton">For day</string>
<string name="reportErrorOption">Report error</string> <string name="forWeekButton">For week</string>
<string name="forMonthButton">For month</string>
<string name="forSemesterButton">For semester</string>
<string name="invalidDateRangeError">Error: Invalid date range</string> <string name="reminderSpinner">Set reminders for</string>
<string name="authorizationState">Authorization...</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="invalidAuthorizationError">Error: Invalid credential</string> <string name="noReminderOption">None</string>
<string name="authorizationError">Authorization error</string> <string name="inTimeReminderOption">At the start of event</string>
<string name="invalidCredentialError">Authorization error: Invalid e-mail and/or password</string> <string name="fiveMinuteReminderOption">5 minutes</string>
<string name="groupSelectionError">Error: no group was selected</string> <string name="tenMinuteReminderOption">10 minutes</string>
<string name="clearScheduleTitle">Clear schedule</string> <string name="addGroupToTitleCheckbox">Add group number to event title</string>
<string name="clearScheduleMessage">This action will purge exported schedule from all available calendars. \nIt will affect only events created by the app. \n\'All\' - will purge all timetable events including the past ones \n\'Upcoming\' - will affect only upcoming timetable events</string> <string name="titleNote">(i) This doesn\'t affect professors\' schedule</string>
<string name="clearAllOption">All</string>
<string name="clearUpcomingOption">Upcoming</string>
<string name="cancelOption">Cancel</string>
<string name="clearingStatus">Clearing...</string>
<!-- ExportActivity -->
<string name="loadingStatus">Loading</string>
<string name="potatoLoadingStatus">Loading schedule from SPbSUT potato servers</string>
<string name="scheduleLoadingStatus">Loading schedule</string>
<string name="calendarExportStatus">Exporting to calendar</string>
<string name="doneStatus">Done</string>
<!-- AboutActivity --> <string name="destinationCalendarSpinner">Destination calendar</string>
<string name="aboutTitle">About application</string>
<string name="appDescription">Application for SPbSUT professors\' and students\' schedule export</string>
<string name="developedBy">Developed by Michael Gordeev (IST-942, IST) in the \"Technologies of Informational and Educational Systems\" Research and Educational Center</string>
<string name="contributorsTitle">Contributors</string>
<string name="specialThanksTitle">Special thanks</string> <string name="addScheduleButton">Add schedule</string>
<string name="specialThanksPeople">Vitaliy Moshkov, Anastasiya Godunova</string>
<string name="contactsTitle">Contacts</string> <string name="copyrights">©2020 Michael Gordeev, IST, IST-942</string>
<string name="websiteContact">Website</string>
<string name="twitterContact">Twitter</string>
<string name="vkontakteContact">Vkontakte</string>
<string name="linksTitle">Useful links</string> <string name="clearCalendarOption">Clear schedule</string>
<string name="privacyPolicyLink">Privacy policy</string> <string name="reportErrorOption">Report error</string>
<string name="repositoryLink">GitHub Repository</string>
<string name="notsLink">\"TIES\" REC</string>
<string name="sutLink">SPbSUT</string>
<string name="feedbackButton">Leave feedback</string> <string name="invalidDateRangeError">Error: Invalid date range</string>
<string name="authorizationState">Authorization...</string>
<string name="invalidAuthorizationError">Error: Invalid credential</string>
<string name="authorizationError">Authorization error</string>
<string name="invalidCredentialError">Authorization error: Invalid e-mail and/or password</string>
<string name="groupSelectionError">Error: no group was selected</string>
<string name="clearScheduleTitle">Clear schedule</string>
<string name="clearScheduleMessage">This action will purge exported schedule from all available calendars. \nIt will affect only events created by the app. \n\'All\' - will purge all timetable events including the past ones \n\'Upcoming\' - will affect only upcoming timetable events</string>
<string name="clearAllOption">All</string>
<string name="clearUpcomingOption">Upcoming</string>
<string name="cancelOption">Cancel</string>
<string name="clearingStatus">Clearing...</string>
<!-- ExportActivity -->
<string name="loadingStatus">Loading</string>
<string name="potatoLoadingStatus">Loading schedule from SPbSUT potato servers</string>
<string name="scheduleLoadingStatus">Loading schedule</string>
<string name="calendarExportStatus">Exporting to calendar</string>
<string name="doneStatus">Done</string>
<!-- AboutActivity -->
<string name="aboutTitle">About application</string>
<string name="appDescription">Application for SPbSUT professors\' and students\' schedule export</string>
<string name="developedBy">Developed by Michael Gordeev (IST-942, IST) in the \"Technologies of Informational and Educational Systems\" Research and Educational Center</string>
<string name="contributorsTitle">Contributors</string>
<string name="specialThanksTitle">Special thanks</string>
<string name="specialThanksPeople">Vitaliy Moshkov, Anastasiya Godunova</string>
<string name="contactsTitle">Contacts</string>
<string name="websiteContact">Website</string>
<string name="twitterContact">Twitter</string>
<string name="vkontakteContact">Vkontakte</string>
<string name="linksTitle">Useful links</string>
<string name="privacyPolicyLink">Privacy policy</string>
<string name="repositoryLink">GitHub Repository</string>
<string name="notsLink">\"TIES\" REC</string>
<string name="sutLink">SPbSUT</string>
<string name="feedbackButton">Leave feedback</string>
</resources> </resources>
@@ -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;
}
}
} }
} }
@@ -1,330 +1,351 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
Version 2.0 Version 2.0
The primary goals of this format is to allow a simple XML format The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes various data types are done through the TypeConverter classes
associated with the data types. associated with the data types.
Example: Example:
... ado.net/XML headers & schema ... ... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader> <resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader> <resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value> <value>[base64 mime encoded serialized .NET Framework object]</value>
</data> </data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment> <comment>This is a comment</comment>
</data> </data>
There are any number of "resheader" rows that contain simple There are any number of "resheader" rows that contain simple
name/value pairs. name/value pairs.
Each data row contains a name, and value. The row also contains a Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture. text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the Classes that don't support this are serialized and stored with the
mimetype set. mimetype set.
The mimetype is used for serialized objects, and tells the The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly: extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below. read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64 mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64 mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64 mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
--> -->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" /> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" /> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" /> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" /> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" /> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" /> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" /> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" /> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" /> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:schema> </xsd:schema>
<resheader name="resmimetype"> <resheader name="resmimetype">
<value>text/microsoft-resx</value> <value>text/microsoft-resx</value>
</resheader> </resheader>
<resheader name="version"> <resheader name="version">
<value>2.0</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="aboutOption.Label" xml:space="preserve"> <data name="aboutOption.Label" xml:space="preserve">
<value>About application</value> <value>About application</value>
</data> </data>
<data name="aboutTitle.Text" xml:space="preserve"> <data name="aboutTitle.Text" xml:space="preserve">
<value>About application</value> <value>About application</value>
</data> </data>
<data name="addGroupToTitle.Content" xml:space="preserve"> <data name="addGroupToTitle.Content" xml:space="preserve">
<value>Add group number to event title</value> <value>Add group number to event title</value>
</data> </data>
<data name="addScheduleButton.Content" xml:space="preserve"> <data name="addScheduleButton.Content" xml:space="preserve">
<value>Add schedule</value> <value>Add schedule</value>
</data> </data>
<data name="appDescription.Text" xml:space="preserve"> <data name="appDescription.Text" xml:space="preserve">
<value>Application for SPbSUT professors' and students' schedule export</value> <value>Application for SPbSUT professors' and students' schedule export</value>
</data> </data>
<data name="appDisplayDescription" xml:space="preserve"> <data name="appDisplayDescription" xml:space="preserve">
<value>Application which exports SPbSUT timetable to calendar</value> <value>Application which exports SPbSUT timetable to calendar</value>
</data> </data>
<data name="appDisplayName" xml:space="preserve"> <data name="appDisplayName" xml:space="preserve">
<value>GUT.Schedule</value> <value>GUT.Schedule</value>
</data> </data>
<data name="appName.Text" xml:space="preserve"> <data name="appName.Text" xml:space="preserve">
<value>GUT.Schedule</value> <value>GUT.Schedule</value>
</data> </data>
<data name="authorizeCheckbox.Content" xml:space="preserve"> <data name="authorizeCheckbox.Content" xml:space="preserve">
<value>Authorize via Personal cabinet</value> <value>Authorize via Personal cabinet</value>
</data> </data>
<data name="calendarExportStatus" xml:space="preserve"> <data name="calendarExportStatus" xml:space="preserve">
<value>Exporting to calendar</value> <value>Exporting to calendar</value>
</data> </data>
<data name="cancelOption" xml:space="preserve"> <data name="cancelOption" xml:space="preserve">
<value>Cancel</value> <value>Cancel</value>
</data> </data>
<data name="clearAllOption" xml:space="preserve"> <data name="clearAllOption" xml:space="preserve">
<value>All</value> <value>All</value>
</data> </data>
<data name="clearCalendarOption.Label" xml:space="preserve"> <data name="clearCalendarOption.Label" xml:space="preserve">
<value>Clear schedule</value> <value>Clear schedule</value>
</data> </data>
<data name="clearScheduleDone" xml:space="preserve"> <data name="clearScheduleDone" xml:space="preserve">
<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. It will affect only events created by the app.
'All' - will purge all timetable events including the past ones 'All' - will purge all timetable events including the past ones
'Upcoming' - will affect only upcoming timetable events</value> '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>
</data> </data>
<data name="clearScheduleTitle.SecondaryButtonText" xml:space="preserve"> <data name="clearScheduleTitle.SecondaryButtonText" xml:space="preserve">
<value>Cancel</value> <value>Cancel</value>
</data> </data>
<data name="clearScheduleTitle.Title" xml:space="preserve"> <data name="clearScheduleTitle.Title" xml:space="preserve">
<value>Clear schedule</value> <value>Clear schedule</value>
</data> </data>
<data name="clearUpcoming.Content" xml:space="preserve"> <data name="clearUpcoming.Content" xml:space="preserve">
<value>Remove only upcoming events</value> <value>Remove only upcoming events</value>
</data> </data>
<data name="clearUpcomingOption" xml:space="preserve"> <data name="clearUpcomingOption" xml:space="preserve">
<value>Upcoming</value> <value>Upcoming</value>
</data> </data>
<data name="connectionFailMessage" xml:space="preserve"> <data name="connectionFailMessage" xml:space="preserve">
<value>Unable to load schedule. Check your internet connection or try again later</value> <value>Unable to load schedule. Check your internet connection or try again later</value>
</data> </data>
<data name="contactsTitle.Text" xml:space="preserve"> <data name="contactsTitle.Text" xml:space="preserve">
<value>Contacts</value> <value>Contacts</value>
</data> </data>
<data name="contributorsTitle.Text" xml:space="preserve"> <data name="contributorsTitle.Text" xml:space="preserve">
<value>Contributors</value> <value>Contributors</value>
</data> </data>
<data name="copyrights.Text" xml:space="preserve"> <data name="copyrights.Text" xml:space="preserve">
<value>©2020 Michael Gordeev, IST, IST-942</value> <value>©2020 Michael Gordeev, IST, IST-942</value>
</data> </data>
<data name="courseSpinner.Header" xml:space="preserve"> <data name="courseSpinner.Header" xml:space="preserve">
<value>Course</value> <value>Course</value>
</data> </data>
<data name="createCalendarMessage" xml:space="preserve"> <data name="createCalendarMessage" xml:space="preserve">
<value>There's no calendars on your device we can write schedule to</value> <value>There's no calendars on your device we can write schedule to</value>
</data> </data>
<data name="createCalendarTitle" xml:space="preserve"> <data name="createCalendarTitle" xml:space="preserve">
<value>Create new calendar</value> <value>Create new calendar</value>
</data> </data>
<data name="dateRangeFrom.Header" xml:space="preserve"> <data name="dateRangeFrom.Header" xml:space="preserve">
<value>Export from</value> <value>Export from</value>
</data> </data>
<data name="dateRangeTo.Header" xml:space="preserve"> <data name="dateRangeTo.Header" xml:space="preserve">
<value>Export to</value> <value>Export to</value>
</data> </data>
<data name="destinationCalendar.Header" xml:space="preserve"> <data name="destinationCalendar.Header" xml:space="preserve">
<value>Destination calendar</value> <value>Destination calendar</value>
</data> </data>
<data name="developedBy.Text" xml:space="preserve"> <data name="developedBy.Text" xml:space="preserve">
<value>Developed by Michael Gordeev (IST-942, IST) in the "Technologies of Informational and Educational Systems" Research and Educational Center</value> <value>Developed by Michael Gordeev (IST-942, IST) in the "Technologies of Informational and Educational Systems" Research and Educational Center</value>
</data> </data>
<data name="doneStatus" xml:space="preserve"> <data name="doneStatus" xml:space="preserve">
<value>Done</value> <value>Done</value>
</data> </data>
<data name="email.PlaceholderText" xml:space="preserve"> <data name="email.PlaceholderText" xml:space="preserve">
<value>E-mail</value> <value>E-mail</value>
</data> </data>
<data name="exportParametersTitle.Text" xml:space="preserve"> <data name="exportParametersTitle.Text" xml:space="preserve">
<value>Export parameters</value> <value>Export parameters</value>
</data> </data>
<data name="facultySpinner.Header" xml:space="preserve"> <data name="facultySpinner.Header" xml:space="preserve">
<value>Faculty</value> <value>Faculty</value>
</data> </data>
<data name="facultySpinner.PlaceholderText" xml:space="preserve"> <data name="facultySpinner.PlaceholderText" xml:space="preserve">
<value>No schedule is available</value> <value>No schedule is available</value>
</data> </data>
<data name="fiveMinuteReminder.Content" xml:space="preserve"> <data name="fiveMinuteReminder.Content" xml:space="preserve">
<value>5 minutes</value> <value>5 minutes</value>
</data> </data>
<data name="forDay.Content" xml:space="preserve"> <data name="forDay.Content" xml:space="preserve">
<value>For day</value> <value>For day</value>
</data> </data>
<data name="forMonth.Content" xml:space="preserve"> <data name="forMonth.Content" xml:space="preserve">
<value>For month</value> <value>For month</value>
</data> </data>
<data name="forSemester.Content" xml:space="preserve"> <data name="forSemester.Content" xml:space="preserve">
<value>For semester</value> <value>For semester</value>
</data> </data>
<data name="forWeek.Content" xml:space="preserve"> <data name="forWeek.Content" xml:space="preserve">
<value>For week</value> <value>For week</value>
</data> </data>
<data name="groupSelectionError" xml:space="preserve"> <data name="groupSelectionError" xml:space="preserve">
<value>Error: no group was selected</value> <value>Error: no group was selected</value>
</data> </data>
<data name="groupSpinner.Header" xml:space="preserve"> <data name="groupSpinner.Header" xml:space="preserve">
<value>Group</value> <value>Group</value>
</data> </data>
<data name="groupSpinner.PlaceholderText" xml:space="preserve"> <data name="groupSpinner.PlaceholderText" xml:space="preserve">
<value>No schedule is available</value> <value>No schedule is available</value>
</data> </data>
<data name="inTimeReminder.Content" xml:space="preserve"> <data name="inTimeReminder.Content" xml:space="preserve">
<value>At the start of event</value> <value>At the start of event</value>
</data> </data>
<data name="invalidAuthorizationError" xml:space="preserve"> <data name="invalidAuthorizationError" xml:space="preserve">
<value>Error: Invalid credential</value> <value>Error: Invalid credential</value>
</data> </data>
<data name="invalidDateRangeError" xml:space="preserve"> <data name="invalidDateRangeError" xml:space="preserve">
<value>Error: Invalid date range</value> <value>Error: Invalid date range</value>
</data> </data>
<data name="leaveFeedback.Content" xml:space="preserve"> <data name="leaveFeedback.Content" xml:space="preserve">
<value>Leave feedback</value> <value>Leave feedback</value>
</data> </data>
<data name="linksTitle.Text" xml:space="preserve"> <data name="linksTitle.Text" xml:space="preserve">
<value>Useful links</value> <value>Useful links</value>
</data> </data>
<data name="loadingStatus" xml:space="preserve"> <data name="loadingStatus" xml:space="preserve">
<value>Loading</value> <value>Loading</value>
</data> </data>
<data name="mySchedule" xml:space="preserve"> <data name="mySchedule" xml:space="preserve">
<value>My schedule</value> <value>My schedule</value>
</data> </data>
<data name="noReminder.Content" xml:space="preserve"> <data name="noReminder.Content" xml:space="preserve">
<value>None</value> <value>None</value>
</data> </data>
<data name="notsLink.Text" xml:space="preserve"> <data name="notsLink.Text" xml:space="preserve">
<value>"TIES" REC</value> <value>"TIES" REC</value>
</data> </data>
<data name="password.PlaceholderText" xml:space="preserve"> <data name="password.PlaceholderText" xml:space="preserve">
<value>Password</value> <value>Password</value>
</data> </data>
<data name="privacyPolicyLink.Text" xml:space="preserve"> <data name="privacyPolicyLink.Text" xml:space="preserve">
<value>Privacy policy</value> <value>Privacy policy</value>
</data> </data>
<data name="remember.Content" xml:space="preserve"> <data name="remember.Content" xml:space="preserve">
<value>Remember</value> <value>Remember</value>
</data> </data>
<data name="reminderSpinner.Header" xml:space="preserve"> <data name="reminderSpinner.Header" xml:space="preserve">
<value>Set reminder for:</value> <value>Set reminder for:</value>
</data> </data>
<data name="repeat" xml:space="preserve"> <data name="repeat" xml:space="preserve">
<value>Try again</value> <value>Try again</value>
</data> </data>
<data name="reportErrorOption.Label" xml:space="preserve"> <data name="reportErrorOption.Label" xml:space="preserve">
<value>Report error</value> <value>Report error</value>
</data> </data>
<data name="repositoryLink.Text" xml:space="preserve"> <data name="repositoryLink.Text" xml:space="preserve">
<value>GitHub Repository</value> <value>GitHub Repository</value>
</data> </data>
<data name="scheduleParametersTitle.Text" xml:space="preserve"> <data name="scheduleParametersTitle.Text" xml:space="preserve">
<value>Schedule parameters</value> <value>Schedule parameters</value>
</data> </data>
<data name="specialThanksPeople.Text" xml:space="preserve"> <data name="specialThanksPeople.Text" xml:space="preserve">
<value>Vitaliy Moshkov, Anastasiya Godunova</value> <value>Vitaliy Moshkov, Anastasiya Godunova</value>
</data> </data>
<data name="specialThanksTitle.Text" xml:space="preserve"> <data name="specialThanksTitle.Text" xml:space="preserve">
<value>Special thanks</value> <value>Special thanks</value>
</data> </data>
<data name="sutLink.Text" xml:space="preserve"> <data name="sutLink.Text" xml:space="preserve">
<value>SPbSUT</value> <value>SPbSUT</value>
</data> </data>
<data name="tenMinuteReminder.Content" xml:space="preserve"> <data name="tenMinuteReminder.Content" xml:space="preserve">
<value>10 minutes</value> <value>10 minutes</value>
</data> </data>
<data name="titleNote.Text" xml:space="preserve"> <data name="titleNote.Text" xml:space="preserve">
<value>(i) This doesn't affect professors' schedule</value> <value>(i) This doesn't affect professors' schedule</value>
</data> </data>
<data name="today.Content" xml:space="preserve"> <data name="today.Content" xml:space="preserve">
<value>Today</value> <value>Today</value>
</data> </data>
<data name="twitterContact.Text" xml:space="preserve"> <data name="twitterContact.Text" xml:space="preserve">
<value>Twitter</value> <value>Twitter</value>
</data> </data>
<data name="vkontakteContact.Text" xml:space="preserve"> <data name="vkontakteContact.Text" xml:space="preserve">
<value>VKontakte</value> <value>VKontakte</value>
</data> </data>
<data name="websiteContact.Text" xml:space="preserve">
<value>Website</value>
</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>
@@ -1,330 +1,351 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<root> <root>
<!-- <!--
Microsoft ResX Schema Microsoft ResX Schema
Version 2.0 Version 2.0
The primary goals of this format is to allow a simple XML format The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes various data types are done through the TypeConverter classes
associated with the data types. associated with the data types.
Example: Example:
... ado.net/XML headers & schema ... ... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader> <resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader> <resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value> <value>[base64 mime encoded serialized .NET Framework object]</value>
</data> </data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment> <comment>This is a comment</comment>
</data> </data>
There are any number of "resheader" rows that contain simple There are any number of "resheader" rows that contain simple
name/value pairs. name/value pairs.
Each data row contains a name, and value. The row also contains a Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture. text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the Classes that don't support this are serialized and stored with the
mimetype set. mimetype set.
The mimetype is used for serialized objects, and tells the The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly: extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below. read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64 mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64 mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64 mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter : using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding. : and then encoded with base64 encoding.
--> -->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true"> <xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType> <xsd:complexType>
<xsd:choice maxOccurs="unbounded"> <xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata"> <xsd:element name="metadata">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" /> <xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" /> <xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" /> <xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" /> <xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" /> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="assembly"> <xsd:element name="assembly">
<xsd:complexType> <xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" /> <xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" /> <xsd:attribute name="name" type="xsd:string" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="data"> <xsd:element name="data">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" /> <xsd:attribute ref="xml:space" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
<xsd:element name="resheader"> <xsd:element name="resheader">
<xsd:complexType> <xsd:complexType>
<xsd:sequence> <xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence> </xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" /> <xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:choice> </xsd:choice>
</xsd:complexType> </xsd:complexType>
</xsd:element> </xsd:element>
</xsd:schema> </xsd:schema>
<resheader name="resmimetype"> <resheader name="resmimetype">
<value>text/microsoft-resx</value> <value>text/microsoft-resx</value>
</resheader> </resheader>
<resheader name="version"> <resheader name="version">
<value>2.0</value> <value>2.0</value>
</resheader> </resheader>
<resheader name="reader"> <resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<resheader name="writer"> <resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader> </resheader>
<data name="aboutOption.Label" xml:space="preserve"> <data name="aboutOption.Label" xml:space="preserve">
<value>О приложении</value> <value>О приложении</value>
</data> </data>
<data name="aboutTitle.Text" xml:space="preserve"> <data name="aboutTitle.Text" xml:space="preserve">
<value>О приложении</value> <value>О приложении</value>
</data> </data>
<data name="addGroupToTitle.Content" xml:space="preserve"> <data name="addGroupToTitle.Content" xml:space="preserve">
<value>Добавить номер группы в заголовок</value> <value>Добавить номер группы в заголовок</value>
</data> </data>
<data name="addScheduleButton.Content" xml:space="preserve"> <data name="addScheduleButton.Content" xml:space="preserve">
<value>Добавить расписание</value> <value>Добавить расписание</value>
</data> </data>
<data name="appDescription.Text" xml:space="preserve"> <data name="appDescription.Text" xml:space="preserve">
<value>Приложение для экспорта перподавательского и учебного расписаний Санкт-Петербургского Государственного Университета Телекоммуникаций им. проф. М.А. Бонч-Бруевича</value> <value>Приложение для экспорта перподавательского и учебного расписаний Санкт-Петербургского Государственного Университета Телекоммуникаций им. проф. М.А. Бонч-Бруевича</value>
</data> </data>
<data name="appDisplayDescription" xml:space="preserve"> <data name="appDisplayDescription" xml:space="preserve">
<value>Приложение для экспорта расписания СПбГУТ в календарь</value> <value>Приложение для экспорта расписания СПбГУТ в календарь</value>
</data> </data>
<data name="appDisplayName" xml:space="preserve"> <data name="appDisplayName" xml:space="preserve">
<value>ГУТ.Расписание</value> <value>ГУТ.Расписание</value>
</data> </data>
<data name="appName.Text" xml:space="preserve"> <data name="appName.Text" xml:space="preserve">
<value>ГУТ.Расписание</value> <value>ГУТ.Расписание</value>
</data> </data>
<data name="authorizeCheckbox.Content" xml:space="preserve"> <data name="authorizeCheckbox.Content" xml:space="preserve">
<value>Авторизоваться через Личный кабинет</value> <value>Авторизоваться через Личный кабинет</value>
</data> </data>
<data name="calendarExportStatus" xml:space="preserve"> <data name="calendarExportStatus" xml:space="preserve">
<value>Экспортирование в календарь</value> <value>Экспортирование в календарь</value>
</data> </data>
<data name="cancelOption" xml:space="preserve"> <data name="cancelOption" xml:space="preserve">
<value>Отмена</value> <value>Отмена</value>
</data> </data>
<data name="clearAllOption" xml:space="preserve"> <data name="clearAllOption" xml:space="preserve">
<value>Все</value> <value>Все</value>
</data> </data>
<data name="clearCalendarOption.Label" xml:space="preserve"> <data name="clearCalendarOption.Label" xml:space="preserve">
<value>Очистить расписание</value> <value>Очистить расписание</value>
</data> </data>
<data name="clearScheduleDone" xml:space="preserve"> <data name="clearScheduleDone" xml:space="preserve">
<value>Расписание очищено</value> <value>Расписание очищено</value>
</data> </data>
<data name="clearScheduleMessage" xml:space="preserve"> <data name="clearScheduleMessage" xml:space="preserve">
<value>Это действие удалит экспортированное расписание из всех доступных календарей. <value>Это действие удалит экспортированное расписание из всех доступных календарей.
Данное действие затронет только расписание, экспортированное этим приложением Данное действие затронет только расписание, экспортированное этим приложением
'Все' - удалит все события расписания, включая прошедшие 'Все' - удалит все события расписания, включая прошедшие
'Только новые' - удалит будущие события расписания</value> 'Только новые' - удалит будущие события расписания</value>
</data> </data>
<data name="clearScheduleTitle.PrimaryButtonText" xml:space="preserve"> <data name="clearScheduleTitle.PrimaryButtonText" xml:space="preserve">
<value>Очистить расписание</value> <value>Очистить расписание</value>
</data> </data>
<data name="clearScheduleTitle.SecondaryButtonText" xml:space="preserve"> <data name="clearScheduleTitle.SecondaryButtonText" xml:space="preserve">
<value>Отмена</value> <value>Отмена</value>
</data> </data>
<data name="clearScheduleTitle.Title" xml:space="preserve"> <data name="clearScheduleTitle.Title" xml:space="preserve">
<value>Очистка расписания</value> <value>Очистка расписания</value>
</data> </data>
<data name="clearUpcoming.Content" xml:space="preserve"> <data name="clearUpcoming.Content" xml:space="preserve">
<value>Удалить только будущие события</value> <value>Удалить только будущие события</value>
</data> </data>
<data name="clearUpcomingOption" xml:space="preserve"> <data name="clearUpcomingOption" xml:space="preserve">
<value>Только новые</value> <value>Только новые</value>
</data> </data>
<data name="connectionFailMessage" xml:space="preserve"> <data name="connectionFailMessage" xml:space="preserve">
<value>Невозможно загрузить расписание. Проверьте интернет-соединение или попробуйте позже</value> <value>Невозможно загрузить расписание. Проверьте интернет-соединение или попробуйте позже</value>
</data> </data>
<data name="contactsTitle.Text" xml:space="preserve"> <data name="contactsTitle.Text" xml:space="preserve">
<value>Контакты</value> <value>Контакты</value>
</data> </data>
<data name="contributorsTitle.Text" xml:space="preserve"> <data name="contributorsTitle.Text" xml:space="preserve">
<value>Свой вклад в разработку внесли</value> <value>Свой вклад в разработку внесли</value>
</data> </data>
<data name="copyrights.Text" xml:space="preserve"> <data name="copyrights.Text" xml:space="preserve">
<value>©2020 Михаил Гордеев, ИСиТ, ИСТ-942</value> <value>©2020 Михаил Гордеев, ИСиТ, ИСТ-942</value>
</data> </data>
<data name="courseSpinner.Header" xml:space="preserve"> <data name="courseSpinner.Header" xml:space="preserve">
<value>Курс</value> <value>Курс</value>
</data> </data>
<data name="createCalendarMessage" xml:space="preserve"> <data name="createCalendarMessage" xml:space="preserve">
<value>На вашем устройстве нет календарей пригодных для записи расписания</value> <value>На вашем устройстве нет календарей пригодных для записи расписания</value>
</data> </data>
<data name="createCalendarTitle" xml:space="preserve"> <data name="createCalendarTitle" xml:space="preserve">
<value>Создайте новый календарь</value> <value>Создайте новый календарь</value>
</data> </data>
<data name="dateRangeFrom.Header" xml:space="preserve"> <data name="dateRangeFrom.Header" xml:space="preserve">
<value>Брать расписание с</value> <value>Брать расписание с</value>
</data> </data>
<data name="dateRangeTo.Header" xml:space="preserve"> <data name="dateRangeTo.Header" xml:space="preserve">
<value>По</value> <value>По</value>
</data> </data>
<data name="destinationCalendar.Header" xml:space="preserve"> <data name="destinationCalendar.Header" xml:space="preserve">
<value>Конечный календарь</value> <value>Конечный календарь</value>
</data> </data>
<data name="developedBy.Text" xml:space="preserve"> <data name="developedBy.Text" xml:space="preserve">
<value>Разработано Михаилом Гордеевым, ИСТ-942, ИСиТ в Научно-образовательном центре "Технологии информационных образовательных систем"</value> <value>Разработано Михаилом Гордеевым, ИСТ-942, ИСиТ в Научно-образовательном центре "Технологии информационных образовательных систем"</value>
</data> </data>
<data name="doneStatus" xml:space="preserve"> <data name="doneStatus" xml:space="preserve">
<value>Готово</value> <value>Готово</value>
</data> </data>
<data name="email.PlaceholderText" xml:space="preserve"> <data name="email.PlaceholderText" xml:space="preserve">
<value>E-mail</value> <value>E-mail</value>
</data> </data>
<data name="exportParametersTitle.Text" xml:space="preserve"> <data name="exportParametersTitle.Text" xml:space="preserve">
<value>Параметры экспорта</value> <value>Параметры экспорта</value>
</data> </data>
<data name="facultySpinner.Header" xml:space="preserve"> <data name="facultySpinner.Header" xml:space="preserve">
<value>Факультет</value> <value>Факультет</value>
</data> </data>
<data name="facultySpinner.PlaceholderText" xml:space="preserve"> <data name="facultySpinner.PlaceholderText" xml:space="preserve">
<value>Нет доступного расписания</value> <value>Нет доступного расписания</value>
</data> </data>
<data name="fiveMinuteReminder.Content" xml:space="preserve"> <data name="fiveMinuteReminder.Content" xml:space="preserve">
<value>5 минут</value> <value>5 минут</value>
</data> </data>
<data name="forDay.Content" xml:space="preserve"> <data name="forDay.Content" xml:space="preserve">
<value>На день</value> <value>На день</value>
</data> </data>
<data name="forMonth.Content" xml:space="preserve"> <data name="forMonth.Content" xml:space="preserve">
<value>На месяц</value> <value>На месяц</value>
</data> </data>
<data name="forSemester.Content" xml:space="preserve"> <data name="forSemester.Content" xml:space="preserve">
<value>На семестр</value> <value>На семестр</value>
</data> </data>
<data name="forWeek.Content" xml:space="preserve"> <data name="forWeek.Content" xml:space="preserve">
<value>На неделю</value> <value>На неделю</value>
</data> </data>
<data name="groupSelectionError" xml:space="preserve"> <data name="groupSelectionError" xml:space="preserve">
<value>Ошибка: Не выбрана группа</value> <value>Ошибка: Не выбрана группа</value>
</data> </data>
<data name="groupSpinner.Header" xml:space="preserve"> <data name="groupSpinner.Header" xml:space="preserve">
<value>Группа</value> <value>Группа</value>
</data> </data>
<data name="groupSpinner.PlaceholderText" xml:space="preserve"> <data name="groupSpinner.PlaceholderText" xml:space="preserve">
<value>Нет доступного расписания</value> <value>Нет доступного расписания</value>
</data> </data>
<data name="inTimeReminder.Content" xml:space="preserve"> <data name="inTimeReminder.Content" xml:space="preserve">
<value>Во время начала</value> <value>Во время начала</value>
</data> </data>
<data name="invalidAuthorizationError" xml:space="preserve"> <data name="invalidAuthorizationError" xml:space="preserve">
<value>Ошибка авторизации</value> <value>Ошибка авторизации</value>
</data> </data>
<data name="invalidDateRangeError" xml:space="preserve"> <data name="invalidDateRangeError" xml:space="preserve">
<value>Ошибка: Неправильный диапазон дат</value> <value>Ошибка: Неправильный диапазон дат</value>
</data> </data>
<data name="leaveFeedback.Content" xml:space="preserve"> <data name="leaveFeedback.Content" xml:space="preserve">
<value>Оставить отзыв</value> <value>Оставить отзыв</value>
</data> </data>
<data name="linksTitle.Text" xml:space="preserve"> <data name="linksTitle.Text" xml:space="preserve">
<value>Полезные ссылки</value> <value>Полезные ссылки</value>
</data> </data>
<data name="loadingStatus" xml:space="preserve"> <data name="loadingStatus" xml:space="preserve">
<value>Загрузка</value> <value>Загрузка</value>
</data> </data>
<data name="mySchedule" xml:space="preserve"> <data name="mySchedule" xml:space="preserve">
<value>Мое расписание</value> <value>Мое расписание</value>
</data> </data>
<data name="noReminder.Content" xml:space="preserve"> <data name="noReminder.Content" xml:space="preserve">
<value>Нет</value> <value>Нет</value>
</data> </data>
<data name="notsLink.Text" xml:space="preserve"> <data name="notsLink.Text" xml:space="preserve">
<value>НОЦ "ТИОС"</value> <value>НОЦ "ТИОС"</value>
</data> </data>
<data name="password.PlaceholderText" xml:space="preserve"> <data name="password.PlaceholderText" xml:space="preserve">
<value>Пароль</value> <value>Пароль</value>
</data> </data>
<data name="privacyPolicyLink.Text" xml:space="preserve"> <data name="privacyPolicyLink.Text" xml:space="preserve">
<value>Политика конфиденциальности</value> <value>Политика конфиденциальности</value>
</data> </data>
<data name="remember.Content" xml:space="preserve"> <data name="remember.Content" xml:space="preserve">
<value>Запомнить</value> <value>Запомнить</value>
</data> </data>
<data name="reminderSpinner.Header" xml:space="preserve"> <data name="reminderSpinner.Header" xml:space="preserve">
<value>Напоминать за</value> <value>Напоминать за</value>
</data> </data>
<data name="repeat" xml:space="preserve"> <data name="repeat" xml:space="preserve">
<value>Повторить</value> <value>Повторить</value>
</data> </data>
<data name="reportErrorOption.Label" xml:space="preserve"> <data name="reportErrorOption.Label" xml:space="preserve">
<value>Сообщить об ошибке</value> <value>Сообщить об ошибке</value>
</data> </data>
<data name="repositoryLink.Text" xml:space="preserve"> <data name="repositoryLink.Text" xml:space="preserve">
<value>Репозиторий GitHub</value> <value>Репозиторий GitHub</value>
</data> </data>
<data name="scheduleParametersTitle.Text" xml:space="preserve"> <data name="scheduleParametersTitle.Text" xml:space="preserve">
<value>Параметры расписания</value> <value>Параметры расписания</value>
</data> </data>
<data name="specialThanksPeople.Text" xml:space="preserve"> <data name="specialThanksPeople.Text" xml:space="preserve">
<value>Виталий Мошков, Анастасия Годунова</value> <value>Виталий Мошков, Анастасия Годунова</value>
</data> </data>
<data name="specialThanksTitle.Text" xml:space="preserve"> <data name="specialThanksTitle.Text" xml:space="preserve">
<value>Особые благодарности</value> <value>Особые благодарности</value>
</data> </data>
<data name="sutLink.Text" xml:space="preserve"> <data name="sutLink.Text" xml:space="preserve">
<value>СПбГУТ</value> <value>СПбГУТ</value>
</data> </data>
<data name="tenMinuteReminder.Content" xml:space="preserve"> <data name="tenMinuteReminder.Content" xml:space="preserve">
<value>10 минут</value> <value>10 минут</value>
</data> </data>
<data name="titleNote.Text" xml:space="preserve"> <data name="titleNote.Text" xml:space="preserve">
<value>(i) Не касается преподавательского расписания</value> <value>(i) Не касается преподавательского расписания</value>
</data> </data>
<data name="today.Content" xml:space="preserve"> <data name="today.Content" xml:space="preserve">
<value>Сегодня</value> <value>Сегодня</value>
</data> </data>
<data name="twitterContact.Text" xml:space="preserve"> <data name="twitterContact.Text" xml:space="preserve">
<value>Твиттер</value> <value>Твиттер</value>
</data> </data>
<data name="vkontakteContact.Text" xml:space="preserve"> <data name="vkontakteContact.Text" xml:space="preserve">
<value>ВКонтакте</value> <value>ВКонтакте</value>
</data> </data>
<data name="websiteContact.Text" xml:space="preserve">
<value>Веб-сайт</value>
</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>
+29 -1
View File
@@ -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 @@
- Обновлен парсер расписания - Авторизация через личный кабинет снова доступна
- Добавлена возможность проверить введеные данные личного кабинета
Авторизация через личный кабинет все еще отключена из-за проблем подкключения на серверной стороне - Добавлена возможность регистрироваться на занятия с помощью одного клика