mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-14 22:50:17 +02:00
Compare commits
38 Commits
v4.11.6
...
v4.13-beta
Author | SHA1 | Date | |
---|---|---|---|
6f12227c2e | |||
3a91f87ccd | |||
52a53334ca | |||
3ab9602865 | |||
dc19043f73 | |||
cf25507850 | |||
044cedff99 | |||
4de066bf5f | |||
8d174bda01 | |||
e2fd714070 | |||
8097e8d06d | |||
93ccdbdeb7 | |||
7ded400a30 | |||
2ff784066e | |||
6c96875c83 | |||
9f3aaf6e86 | |||
55369eaa8b | |||
c983c16907 | |||
c7362bce12 | |||
7935d0f097 | |||
4b64277948 | |||
132729bbd9 | |||
6d36ab27d1 | |||
11fabb231f | |||
6fd999f88c | |||
7711413b30 | |||
cdc0c9d458 | |||
8e5f750a80 | |||
f4e7e8978c | |||
96c542d6d2 | |||
77d22b87aa | |||
37c68443bd | |||
9dbb5d70e9 | |||
99afa77a63 | |||
a5d0f4212d | |||
a85f935eb4 | |||
bb44fa066c | |||
54a61c6254 |
1
.idea/dictionaries/Kuba.xml
generated
1
.idea/dictionaries/Kuba.xml
generated
@ -13,6 +13,7 @@
|
|||||||
<w>synergia</w>
|
<w>synergia</w>
|
||||||
<w>szczodrzyński</w>
|
<w>szczodrzyński</w>
|
||||||
<w>szkolny</w>
|
<w>szkolny</w>
|
||||||
|
<w>usos</w>
|
||||||
</words>
|
</words>
|
||||||
</dictionary>
|
</dictionary>
|
||||||
</component>
|
</component>
|
@ -70,9 +70,11 @@ android {
|
|||||||
sourceSets {
|
sourceSets {
|
||||||
unofficial {
|
unofficial {
|
||||||
java.srcDirs = ["src/main/java", "src/play-not/java"]
|
java.srcDirs = ["src/main/java", "src/play-not/java"]
|
||||||
|
manifest.srcFile("src/play-not/AndroidManifest.xml")
|
||||||
}
|
}
|
||||||
official {
|
official {
|
||||||
java.srcDirs = ["src/main/java", "src/play-not/java"]
|
java.srcDirs = ["src/main/java", "src/play-not/java"]
|
||||||
|
manifest.srcFile("src/play-not/AndroidManifest.xml")
|
||||||
}
|
}
|
||||||
play {
|
play {
|
||||||
java.srcDirs = ["src/main/java", "src/play/java"]
|
java.srcDirs = ["src/main/java", "src/play/java"]
|
||||||
@ -82,9 +84,6 @@ android {
|
|||||||
defaultConfig {
|
defaultConfig {
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
}
|
}
|
||||||
lintOptions {
|
|
||||||
checkReleaseBuilds = false
|
|
||||||
}
|
|
||||||
buildFeatures {
|
buildFeatures {
|
||||||
dataBinding = true
|
dataBinding = true
|
||||||
viewBinding = true
|
viewBinding = true
|
||||||
@ -98,7 +97,9 @@ android {
|
|||||||
jvmTarget = "1.8"
|
jvmTarget = "1.8"
|
||||||
}
|
}
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/library-core_release.kotlin_module'
|
resources {
|
||||||
|
excludes += ['META-INF/library-core_release.kotlin_module']
|
||||||
|
}
|
||||||
}
|
}
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
cmake {
|
cmake {
|
||||||
@ -106,6 +107,9 @@ android {
|
|||||||
version "3.10.2"
|
version "3.10.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lint {
|
||||||
|
checkReleaseBuilds false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.whenTaskAdded { task ->
|
tasks.whenTaskAdded { task ->
|
||||||
@ -140,28 +144,29 @@ dependencies {
|
|||||||
|
|
||||||
// Language cores
|
// Language cores
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
|
implementation "androidx.multidex:multidex:2.0.1"
|
||||||
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
|
coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5"
|
||||||
|
|
||||||
// Android Jetpack
|
// Android Jetpack
|
||||||
implementation "androidx.appcompat:appcompat:1.3.1"
|
implementation "androidx.appcompat:appcompat:1.5.1"
|
||||||
implementation "androidx.cardview:cardview:1.0.0"
|
implementation "androidx.cardview:cardview:1.0.0"
|
||||||
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
|
implementation "androidx.constraintlayout:constraintlayout:2.1.4"
|
||||||
implementation "androidx.core:core-ktx:1.6.0"
|
implementation "androidx.core:core-ktx:1.9.0"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.3.1"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:2.5.1"
|
||||||
implementation "androidx.navigation:navigation-fragment-ktx:2.3.5"
|
implementation "androidx.navigation:navigation-fragment-ktx:2.5.2"
|
||||||
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
implementation "androidx.recyclerview:recyclerview:1.2.1"
|
||||||
implementation "androidx.room:room-runtime:2.3.0"
|
implementation "androidx.room:room-runtime:2.4.3"
|
||||||
implementation "androidx.work:work-runtime-ktx:2.6.0"
|
implementation "androidx.work:work-runtime-ktx:2.7.1"
|
||||||
kapt "androidx.room:room-compiler:2.3.0"
|
kapt "androidx.room:room-compiler:2.4.3"
|
||||||
|
|
||||||
// Google design libs
|
// Google design libs
|
||||||
implementation "com.google.android.material:material:1.4.0"
|
implementation "com.google.android.material:material:1.6.1"
|
||||||
implementation "com.google.android.flexbox:flexbox:3.0.0"
|
implementation "com.google.android.flexbox:flexbox:3.0.0"
|
||||||
|
|
||||||
// Play Services/Firebase
|
// Play Services/Firebase
|
||||||
implementation "com.google.android.gms:play-services-wearable:17.1.0"
|
implementation "com.google.android.gms:play-services-wearable:17.1.0"
|
||||||
implementation "com.google.firebase:firebase-core:19.0.2"
|
implementation("com.google.firebase:firebase-core") { version { strictly "19.0.2" } }
|
||||||
implementation "com.google.firebase:firebase-crashlytics:18.2.3"
|
implementation "com.google.firebase:firebase-crashlytics:18.2.13"
|
||||||
implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
|
implementation("com.google.firebase:firebase-messaging") { version { strictly "20.1.3" } }
|
||||||
|
|
||||||
// OkHttp, Retrofit, Gson, Jsoup
|
// OkHttp, Retrofit, Gson, Jsoup
|
||||||
|
2314
app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json
Normal file
2314
app/schemas/pl.szczodrzynski.edziennik.data.db.AppDb/98.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,6 @@
|
|||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
package="pl.szczodrzynski.edziennik">
|
package="pl.szczodrzynski.edziennik">
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
@ -13,7 +12,7 @@
|
|||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
<uses-permission android:name="android.permission.CAMERA" />
|
<uses-permission android:name="android.permission.CAMERA" />
|
||||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS"/>
|
||||||
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
|
<!-- PowerPermission uses minSdk 21, it's safe to override as it is used only in >= 23 -->
|
||||||
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
|
<uses-sdk tools:overrideLibrary="com.qifan.powerpermission.coroutines, com.qifan.powerpermission.core" />
|
||||||
|
|
||||||
@ -43,6 +42,7 @@
|
|||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
android:exported="true"
|
||||||
android:theme="@style/SplashTheme">
|
android:theme="@style/SplashTheme">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
@ -66,6 +66,7 @@
|
|||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
|
android:exported="true"
|
||||||
android:theme="@style/AppTheme.Dark.NoDisplay">
|
android:theme="@style/AppTheme.Dark.NoDisplay">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
|
||||||
@ -73,7 +74,8 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<!-- TIMETABLE -->
|
<!-- TIMETABLE -->
|
||||||
<receiver android:name=".ui.widgets.timetable.WidgetTimetableProvider"
|
<receiver android:name=".ui.widgets.timetable.WidgetTimetableProvider"
|
||||||
android:label="@string/widget_timetable_title">
|
android:label="@string/widget_timetable_title"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -88,10 +90,12 @@
|
|||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:excludeFromRecents="true"
|
android:excludeFromRecents="true"
|
||||||
android:noHistory="true"
|
android:noHistory="true"
|
||||||
|
android:exported="true"
|
||||||
android:theme="@style/AppTheme.Dark.NoDisplay" />
|
android:theme="@style/AppTheme.Dark.NoDisplay" />
|
||||||
<!-- NOTIFICATIONS -->
|
<!-- NOTIFICATIONS -->
|
||||||
<receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
|
<receiver android:name=".ui.widgets.notifications.WidgetNotificationsProvider"
|
||||||
android:label="@string/widget_notifications_title">
|
android:label="@string/widget_notifications_title"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -104,7 +108,8 @@
|
|||||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||||
<!-- LUCKY NUMBER -->
|
<!-- LUCKY NUMBER -->
|
||||||
<receiver android:name=".ui.widgets.luckynumber.WidgetLuckyNumberProvider"
|
<receiver android:name=".ui.widgets.luckynumber.WidgetLuckyNumberProvider"
|
||||||
android:label="@string/widget_lucky_number_title">
|
android:label="@string/widget_lucky_number_title"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
@ -124,29 +129,40 @@
|
|||||||
<activity android:name=".ui.base.CrashActivity"
|
<activity android:name=".ui.base.CrashActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||||
android:process=":error_activity"
|
android:process=":error_activity"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/DeadTheme" />
|
android:theme="@style/DeadTheme" />
|
||||||
<activity android:name=".ui.intro.ChangelogIntroActivity"
|
<activity android:name=".ui.intro.ChangelogIntroActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/Theme.Intro" />
|
android:theme="@style/Theme.Intro" />
|
||||||
<activity android:name=".ui.login.LoginActivity"
|
<activity android:name=".ui.login.LoginActivity"
|
||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/AppTheme.Light" />
|
android:theme="@style/AppTheme.Light" />
|
||||||
<activity android:name=".ui.home.CounterActivity"
|
<activity android:name=".ui.home.CounterActivity"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/AppTheme.Black" />
|
android:theme="@style/AppTheme.Black" />
|
||||||
<activity android:name=".ui.feedback.FeedbackActivity"
|
<activity android:name=".ui.feedback.FeedbackActivity"
|
||||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
<activity android:name=".ui.settings.SettingsLicenseActivity"
|
<activity android:name=".ui.settings.SettingsLicenseActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/AppTheme" />
|
android:theme="@style/AppTheme" />
|
||||||
<activity android:name="com.canhub.cropper.CropImageActivity"
|
<activity android:name="com.canhub.cropper.CropImageActivity"
|
||||||
android:configChanges="orientation|keyboardHidden"
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
android:theme="@style/Base.Theme.AppCompat" />
|
android:theme="@style/Base.Theme.AppCompat" />
|
||||||
<activity android:name=".ui.base.BuildInvalidActivity" />
|
<activity android:name=".ui.login.oauth.OAuthLoginActivity"
|
||||||
<activity android:name=".ui.settings.contributors.ContributorsActivity" />
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:exported="false"
|
||||||
|
android:theme="@style/AppTheme.Light" />
|
||||||
|
<activity android:name=".ui.base.BuildInvalidActivity" android:exported="false" />
|
||||||
|
<activity android:name=".ui.settings.contributors.ContributorsActivity" android:exported="false" />
|
||||||
|
|
||||||
<!-- _____ _
|
<!-- _____ _
|
||||||
| __ \ (_)
|
| __ \ (_)
|
||||||
@ -156,12 +172,14 @@
|
|||||||
|_| \_\___|\___\___|_| \_/ \___|_| |___/
|
|_| \_\___|\___\___|_| \_/ \___|_| |___/
|
||||||
-->
|
-->
|
||||||
<receiver android:name=".receivers.UserPresentReceiver"
|
<receiver android:name=".receivers.UserPresentReceiver"
|
||||||
android:enabled="true">
|
android:enabled="true"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.USER_PRESENT" />
|
<action android:name="android.intent.action.USER_PRESENT" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".sync.UpdateDownloaderService$DownloadProgressReceiver">
|
<receiver android:name=".sync.UpdateDownloaderService$DownloadProgressReceiver"
|
||||||
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
<h3>Wersja 4.11.6, 2022-05-27</h3>
|
<h3>Wersja 4.13-beta.1, 2022-10-17</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Poprawiono błędy formatowania wiadomości. @BxOxSxS</li>
|
<li>Poprawione powiadomienia na Androidzie 13. @santoni0</li>
|
||||||
|
<li>Możliwość dostosowania wyświetlania planu lekcji</li>
|
||||||
|
<li>Opcja kolorowania bloków w planie lekcji</li>
|
||||||
|
<li><b>USOS</b> - pierwsza wersja obsługi systemu</li>
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
/*secret password - removed for source code publication*/
|
/*secret password - removed for source code publication*/
|
||||||
static toys AES_IV[16] = {
|
static toys AES_IV[16] = {
|
||||||
0xeb, 0x3c, 0x93, 0xf5, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
0x12, 0xdd, 0xb2, 0x93, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||||
|
|
||||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@ import org.greenrobot.eventbus.EventBus
|
|||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
import pl.droidsonroids.gif.GifDrawable
|
import pl.droidsonroids.gif.GifDrawable
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
|
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.*
|
import pl.szczodrzynski.edziennik.data.api.events.*
|
||||||
@ -69,6 +70,7 @@ import pl.szczodrzynski.edziennik.ui.grades.editor.GradesEditorFragment
|
|||||||
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
|
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment
|
import pl.szczodrzynski.edziennik.ui.homework.HomeworkFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
|
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
|
||||||
|
import pl.szczodrzynski.edziennik.ui.login.LoginProgressFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment
|
import pl.szczodrzynski.edziennik.ui.messages.compose.MessagesComposeFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
|
import pl.szczodrzynski.edziennik.ui.messages.list.MessagesFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment
|
import pl.szczodrzynski.edziennik.ui.messages.single.MessageFragment
|
||||||
@ -83,6 +85,7 @@ import pl.szczodrzynski.edziennik.utils.*
|
|||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
import pl.szczodrzynski.edziennik.utils.managers.AvailabilityManager.Error.Type
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
||||||
import pl.szczodrzynski.navlib.*
|
import pl.szczodrzynski.navlib.*
|
||||||
@ -853,7 +856,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
|
fun onUserActionRequiredEvent(event: UserActionRequiredEvent) {
|
||||||
app.userActionManager.execute(this, event.profileId, event.type)
|
app.userActionManager.execute(this, event, UserActionManager.UserActionCallback())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fragmentToSyncName(currentFragment: Int): Int {
|
private fun fragmentToSyncName(currentFragment: Int): Int {
|
||||||
@ -911,11 +914,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
false
|
false
|
||||||
}
|
}
|
||||||
"userActionRequired" -> {
|
"userActionRequired" -> {
|
||||||
app.userActionManager.execute(
|
val event = UserActionRequiredEvent(
|
||||||
this,
|
profileId = extras.getInt("profileId"),
|
||||||
extras.getInt("profileId"),
|
type = extras.getEnum<UserActionRequiredEvent.Type>("type") ?: return,
|
||||||
extras.getInt("type")
|
params = extras.getBundle("params") ?: return,
|
||||||
|
errorText = 0,
|
||||||
)
|
)
|
||||||
|
app.userActionManager.execute(this, event, UserActionManager.UserActionCallback())
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
"createManualEvent" -> {
|
"createManualEvent" -> {
|
||||||
|
@ -69,4 +69,24 @@ class ProfileConfigUI(private val config: ProfileConfig) {
|
|||||||
var messagesGreetingText: String?
|
var messagesGreetingText: String?
|
||||||
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
get() { mMessagesGreetingText = mMessagesGreetingText ?: config.values["messagesGreetingText"]; return mMessagesGreetingText }
|
||||||
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
set(value) { config.set("messagesGreetingText", value); mMessagesGreetingText = value }
|
||||||
|
|
||||||
|
private var mTimetableShowAttendance: Boolean? = null
|
||||||
|
var timetableShowAttendance: Boolean
|
||||||
|
get() { mTimetableShowAttendance = mTimetableShowAttendance ?: config.values.get("timetableShowAttendance", true); return mTimetableShowAttendance ?: true }
|
||||||
|
set(value) { config.set("timetableShowAttendance", value); mTimetableShowAttendance = value }
|
||||||
|
|
||||||
|
private var mTimetableShowEvents: Boolean? = null
|
||||||
|
var timetableShowEvents: Boolean
|
||||||
|
get() { mTimetableShowEvents = mTimetableShowEvents ?: config.values.get("timetableShowEvents", true); return mTimetableShowEvents ?: true }
|
||||||
|
set(value) { config.set("timetableShowEvents", value); mTimetableShowEvents = value }
|
||||||
|
|
||||||
|
private var mTimetableTrimHourRange: Boolean? = null
|
||||||
|
var timetableTrimHourRange: Boolean
|
||||||
|
get() { mTimetableTrimHourRange = mTimetableTrimHourRange ?: config.values.get("timetableTrimHourRange", false); return mTimetableTrimHourRange ?: false }
|
||||||
|
set(value) { config.set("timetableTrimHourRange", value); mTimetableTrimHourRange = value }
|
||||||
|
|
||||||
|
private var mTimetableColorSubjectName: Boolean? = null
|
||||||
|
var timetableColorSubjectName: Boolean
|
||||||
|
get() { mTimetableColorSubjectName = mTimetableColorSubjectName ?: config.values.get("timetableColorSubjectName", false); return mTimetableColorSubjectName ?: false }
|
||||||
|
set(value) { config.set("timetableColorSubjectName", value); mTimetableColorSubjectName = value }
|
||||||
}
|
}
|
||||||
|
@ -84,19 +84,21 @@ class ApiService : Service() {
|
|||||||
runTask()
|
runTask()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
|
||||||
|
app.userActionManager.sendToUser(event)
|
||||||
|
taskRunning?.cancel()
|
||||||
|
clearTask()
|
||||||
|
runTask()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
lastEventTime = System.currentTimeMillis()
|
lastEventTime = System.currentTimeMillis()
|
||||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||||
apiError.profileId = taskProfileId
|
apiError.profileId = taskProfileId
|
||||||
|
|
||||||
if (app.userActionManager.requiresUserAction(apiError)) {
|
EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
|
||||||
app.userActionManager.sendToUser(apiError)
|
errorList.add(apiError)
|
||||||
}
|
apiError.throwable?.printStackTrace()
|
||||||
else {
|
|
||||||
EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
|
|
||||||
errorList.add(apiError)
|
|
||||||
apiError.throwable?.printStackTrace()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (apiError.isCritical) {
|
if (apiError.isCritical) {
|
||||||
taskRunning?.cancel()
|
taskRunning?.cancel()
|
||||||
|
@ -59,40 +59,15 @@ const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action="
|
|||||||
const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile"
|
const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile"
|
||||||
const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik"
|
const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik"
|
||||||
|
|
||||||
const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT
|
const val LIBRUS_PORTAL_RECAPTCHA_KEY = "6Lf48moUAAAAAB9ClhdvHr46gRWR"
|
||||||
const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik"
|
const val LIBRUS_PORTAL_RECAPTCHA_REFERER = "https://portal.librus.pl/rodzina/login"
|
||||||
const val IDZIENNIK_WEB_LOGIN = "login.aspx"
|
|
||||||
const val IDZIENNIK_WEB_SETTINGS = "mod_panelRodzica/Ustawienia.aspx"
|
|
||||||
const val IDZIENNIK_WEB_HOME = "mod_panelRodzica/StronaGlowna.aspx"
|
|
||||||
const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzPlanZajec"
|
|
||||||
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
|
||||||
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
|
||||||
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
|
||||||
const val IDZIENNIK_WEB_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzPraceDomowe"
|
|
||||||
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
|
||||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
|
||||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
|
||||||
const val IDZIENNIK_WEB_MESSAGES_LIST = "mod_komunikator/WS_wiadomosci.asmx/PobierzListeWiadomosci"
|
|
||||||
const val IDZIENNIK_WEB_GET_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/PobierzWiadomosc"
|
|
||||||
const val IDZIENNIK_WEB_GET_RECIPIENT_LIST = "mod_komunikator/WS_wiadomosci.asmx/pobierzListeOdbiorcowPanelRodzic"
|
|
||||||
const val IDZIENNIK_WEB_SEND_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/WyslijWiadomosc"
|
|
||||||
const val IDZIENNIK_WEB_GET_ATTACHMENT = "mod_komunikator/Download.ashx"
|
|
||||||
const val IDZIENNIK_WEB_GET_HOMEWORK = "mod_panelRodzica/pracaDomowa/WS_pracaDomowa.asmx/pobierzJednaPraceDomowa"
|
|
||||||
const val IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT = "mod_panelRodzica/pracaDomowa.aspx"
|
|
||||||
|
|
||||||
val IDZIENNIK_API_USER_AGENT = SYSTEM_USER_AGENT
|
|
||||||
const val IDZIENNIK_API_URL = "https://iuczniowie.progman.pl/idziennik/api"
|
|
||||||
const val IDZIENNIK_API_CURRENT_REGISTER = "Uczniowie/\$STUDENT_ID/AktualnyDziennik"
|
|
||||||
const val IDZIENNIK_API_GRADES = "Uczniowie/\$STUDENT_ID/Oceny/" /* + semester */
|
|
||||||
const val IDZIENNIK_API_MESSAGES_INBOX = "Wiadomosci/Odebrane"
|
|
||||||
const val IDZIENNIK_API_MESSAGES_SENT = "Wiadomosci/Wyslane"
|
|
||||||
|
|
||||||
|
|
||||||
val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT
|
val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT
|
||||||
|
|
||||||
const val VULCAN_HEBE_USER_AGENT = "Dart/2.10 (dart:io)"
|
const val VULCAN_HEBE_USER_AGENT = "Dart/2.10 (dart:io)"
|
||||||
const val VULCAN_HEBE_APP_NAME = "DzienniczekPlus 2.0"
|
const val VULCAN_HEBE_APP_NAME = "DzienniczekPlus 2.0"
|
||||||
const val VULCAN_HEBE_APP_VERSION = "21.02.09 (G)"
|
const val VULCAN_HEBE_APP_VERSION = "22.09.02 (G)"
|
||||||
private const val VULCAN_API_DEVICE_NAME_PREFIX = "Szkolny.eu "
|
private const val VULCAN_API_DEVICE_NAME_PREFIX = "Szkolny.eu "
|
||||||
private const val VULCAN_API_DEVICE_NAME_SUFFIX = " - nie usuwać"
|
private const val VULCAN_API_DEVICE_NAME_SUFFIX = " - nie usuwać"
|
||||||
val VULCAN_API_DEVICE_NAME by lazy {
|
val VULCAN_API_DEVICE_NAME by lazy {
|
||||||
@ -116,14 +91,23 @@ const val VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY = "api/mobile/grade/summary"
|
|||||||
const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework"
|
const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework"
|
||||||
const val VULCAN_HEBE_ENDPOINT_NOTICES = "api/mobile/note"
|
const val VULCAN_HEBE_ENDPOINT_NOTICES = "api/mobile/note"
|
||||||
const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson"
|
const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson"
|
||||||
const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message"
|
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX = "api/mobile/messagebox"
|
||||||
const val VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS = "api/mobile/message/status"
|
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_ADDRESSBOOK = "api/mobile/messagebox/addressbook"
|
||||||
const val VULCAN_HEBE_ENDPOINT_MESSAGES_SEND = "api/mobile/message"
|
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_MESSAGES = "api/mobile/messagebox/message"
|
||||||
|
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_STATUS = "api/mobile/messagebox/message/status"
|
||||||
|
const val VULCAN_HEBE_ENDPOINT_MESSAGEBOX_SEND = "api/mobile/messagebox/message"
|
||||||
const val VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER = "api/mobile/school/lucky"
|
const val VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER = "api/mobile/school/lucky"
|
||||||
|
|
||||||
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
|
|
||||||
|
|
||||||
const val PODLASIE_API_VERSION = "1.0.62"
|
const val PODLASIE_API_VERSION = "1.0.62"
|
||||||
const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api"
|
const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api"
|
||||||
const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia"
|
const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia"
|
||||||
const val PODLASIE_API_LOGOUT_DEVICES_ENDPOINT = "/wyczyscUrzadzenia"
|
const val PODLASIE_API_LOGOUT_DEVICES_ENDPOINT = "/wyczyscUrzadzenia"
|
||||||
|
|
||||||
|
const val USOS_API_OAUTH_REDIRECT_URL = "szkolny://redirect/usos"
|
||||||
|
|
||||||
|
val USOS_API_SCOPES by lazy { listOf(
|
||||||
|
"offline_access",
|
||||||
|
"studies",
|
||||||
|
"grades",
|
||||||
|
"events",
|
||||||
|
) }
|
||||||
|
@ -13,6 +13,7 @@ import androidx.core.app.NotificationCompat.PRIORITY_MIN
|
|||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.ext.Bundle
|
import pl.szczodrzynski.edziennik.ext.Bundle
|
||||||
|
import pl.szczodrzynski.edziennik.ext.pendingIntentFlag
|
||||||
import pl.szczodrzynski.edziennik.receivers.SzkolnyReceiver
|
import pl.szczodrzynski.edziennik.receivers.SzkolnyReceiver
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
@ -40,14 +41,14 @@ class EdziennikNotification(val app: App) {
|
|||||||
"task" to "TaskCancelRequest",
|
"task" to "TaskCancelRequest",
|
||||||
"taskId" to taskId
|
"taskId" to taskId
|
||||||
))
|
))
|
||||||
return PendingIntent.getBroadcast(app, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT) as PendingIntent
|
return PendingIntent.getBroadcast(app, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or pendingIntentFlag()) as PendingIntent
|
||||||
}
|
}
|
||||||
private val closePendingIntent: PendingIntent
|
private val closePendingIntent: PendingIntent
|
||||||
get() {
|
get() {
|
||||||
val intent = SzkolnyReceiver.getIntent(app, Bundle(
|
val intent = SzkolnyReceiver.getIntent(app, Bundle(
|
||||||
"task" to "ServiceCloseRequest"
|
"task" to "ServiceCloseRequest"
|
||||||
))
|
))
|
||||||
return PendingIntent.getBroadcast(app, 0, intent, 0) as PendingIntent
|
return PendingIntent.getBroadcast(app, 0, intent, pendingIntentFlag()) as PendingIntent
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun errorCountText(): String? {
|
private fun errorCountText(): String? {
|
||||||
|
@ -58,11 +58,7 @@ const val ERROR_INVALID_LOGIN_MODE = 110
|
|||||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||||
const val ERROR_NOT_IMPLEMENTED = 112
|
const val ERROR_NOT_IMPLEMENTED = 112
|
||||||
const val ERROR_FILE_DOWNLOAD = 113
|
const val ERROR_FILE_DOWNLOAD = 113
|
||||||
|
const val ERROR_REQUIRES_USER_ACTION = 114
|
||||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
|
||||||
|
|
||||||
const val ERROR_CAPTCHA_NEEDED = 3000
|
|
||||||
const val ERROR_CAPTCHA_LIBRUS_PORTAL = 3001
|
|
||||||
|
|
||||||
const val ERROR_API_PDO_ERROR = 5000
|
const val ERROR_API_PDO_ERROR = 5000
|
||||||
const val ERROR_API_INVALID_CLIENT = 5001
|
const val ERROR_API_INVALID_CLIENT = 5001
|
||||||
@ -198,19 +194,18 @@ const val ERROR_VULCAN_HEBE_ENTITY_NOT_FOUND = 365
|
|||||||
const val ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY = 366
|
const val ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY = 366
|
||||||
const val ERROR_VULCAN_API_DEPRECATED = 390
|
const val ERROR_VULCAN_API_DEPRECATED = 390
|
||||||
|
|
||||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN = 501
|
|
||||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER = 510
|
|
||||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID = 511
|
|
||||||
const val ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS = 521
|
|
||||||
const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522
|
|
||||||
const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530
|
|
||||||
|
|
||||||
const val ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN = 601
|
const val ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN = 601
|
||||||
const val ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT = 602
|
const val ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT = 602
|
||||||
const val ERROR_PODLASIE_API_NO_TOKEN = 630
|
const val ERROR_PODLASIE_API_NO_TOKEN = 630
|
||||||
const val ERROR_PODLASIE_API_OTHER = 631
|
const val ERROR_PODLASIE_API_OTHER = 631
|
||||||
const val ERROR_PODLASIE_API_DATA_MISSING = 632
|
const val ERROR_PODLASIE_API_DATA_MISSING = 632
|
||||||
|
|
||||||
|
const val ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN = 702
|
||||||
|
const val ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE = 703
|
||||||
|
const val ERROR_USOS_NO_STUDENT_PROGRAMMES = 704
|
||||||
|
const val ERROR_USOS_API_INCOMPLETE_RESPONSE = 705
|
||||||
|
const val ERROR_USOS_API_MISSING_RESPONSE = 706
|
||||||
|
|
||||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||||
|
|
||||||
const val EXCEPTION_API_TASK = 900
|
const val EXCEPTION_API_TASK = 900
|
||||||
@ -224,8 +219,6 @@ const val EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST = 908
|
|||||||
const val EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST = 909
|
const val EXCEPTION_LIBRUS_MESSAGES_FILE_REQUEST = 909
|
||||||
const val EXCEPTION_NOTIFY = 910
|
const val EXCEPTION_NOTIFY = 910
|
||||||
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
||||||
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
|
|
||||||
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
|
|
||||||
const val ERROR_ONEDRIVE_DOWNLOAD = 930
|
const val ERROR_ONEDRIVE_DOWNLOAD = 930
|
||||||
const val EXCEPTION_VULCAN_WEB_LOGIN = 931
|
const val EXCEPTION_VULCAN_WEB_LOGIN = 931
|
||||||
const val EXCEPTION_VULCAN_WEB_REQUEST = 932
|
const val EXCEPTION_VULCAN_WEB_REQUEST = 932
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api
|
package pl.szczodrzynski.edziennik.data.api
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginApi
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginMessages
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginMessages
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPortal
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPortal
|
||||||
@ -14,6 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.Mobidzie
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginHebe
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
||||||
@ -26,8 +26,9 @@ import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
|||||||
|
|
||||||
const val SYNERGIA_API_ENABLED = false
|
const val SYNERGIA_API_ENABLED = false
|
||||||
|
|
||||||
|
// the graveyard
|
||||||
const val LOGIN_TYPE_IDZIENNIK = 3
|
const val LOGIN_TYPE_IDZIENNIK = 3
|
||||||
|
const val LOGIN_TYPE_EDUDZIENNIK = 5
|
||||||
|
|
||||||
const val LOGIN_TYPE_TEMPLATE = 21
|
const val LOGIN_TYPE_TEMPLATE = 21
|
||||||
|
|
||||||
@ -118,15 +119,6 @@ val vulcanLoginMethods = listOf(
|
|||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||||
)
|
)
|
||||||
|
|
||||||
const val LOGIN_TYPE_EDUDZIENNIK = 5
|
|
||||||
const val LOGIN_MODE_EDUDZIENNIK_WEB = 0
|
|
||||||
const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100
|
|
||||||
val edudziennikLoginMethods = listOf(
|
|
||||||
LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java)
|
|
||||||
.withIsPossible { _, _ -> true }
|
|
||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
|
||||||
)
|
|
||||||
|
|
||||||
const val LOGIN_TYPE_PODLASIE = 6
|
const val LOGIN_TYPE_PODLASIE = 6
|
||||||
const val LOGIN_MODE_PODLASIE_API = 0
|
const val LOGIN_MODE_PODLASIE_API = 0
|
||||||
const val LOGIN_METHOD_PODLASIE_API = 100
|
const val LOGIN_METHOD_PODLASIE_API = 100
|
||||||
@ -136,6 +128,15 @@ val podlasieLoginMethods = listOf(
|
|||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const val LOGIN_TYPE_USOS = 7
|
||||||
|
const val LOGIN_MODE_USOS_OAUTH = 0
|
||||||
|
const val LOGIN_METHOD_USOS_API = 100
|
||||||
|
val usosLoginMethods = listOf(
|
||||||
|
LoginMethod(LOGIN_TYPE_USOS, LOGIN_METHOD_USOS_API, UsosLoginApi::class.java)
|
||||||
|
.withIsPossible { _, _ -> true }
|
||||||
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||||
|
)
|
||||||
|
|
||||||
val templateLoginMethods = listOf(
|
val templateLoginMethods = listOf(
|
||||||
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
|
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
|
||||||
.withIsPossible { _, _ -> true }
|
.withIsPossible { _, _ -> true }
|
||||||
|
@ -20,6 +20,10 @@ object Regexes {
|
|||||||
"""<br\s?/?>""".toRegex()
|
"""<br\s?/?>""".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val MESSAGE_META by lazy {
|
||||||
|
"""^\[META:([A-z0-9-&=]+)]""".toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
||||||
@ -142,44 +146,6 @@ object Regexes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
|
||||||
"""<input type="hidden".+?name="([A-z0-9_]+)?".+?value="([A-z0-9_+-/=]+)?".+?>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val IDZIENNIK_LOGIN_ERROR by lazy {
|
|
||||||
"""id="spanErrorMessage">(.*?)</""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME by lazy {
|
|
||||||
"""Imię i nazwisko:.+?">(.+?)</div>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val IDZIENNIK_LOGIN_FIRST_IS_PARENT by lazy {
|
|
||||||
"""id="ctl00_CzyRodzic" value="([01])" />""".toRegex()
|
|
||||||
}
|
|
||||||
val IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR by lazy {
|
|
||||||
"""name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9]+)/([0-9]+)<""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val IDZIENNIK_LOGIN_FIRST_STUDENT_SELECT by lazy {
|
|
||||||
"""<select.*?name="ctl00\${"$"}dxComboUczniowie".*?</select>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
|
||||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val IDZIENNIK_MESSAGES_RECIPIENT_PARENT by lazy {
|
|
||||||
"""(.+?)\s\((.+)\)""".toRegex()
|
|
||||||
}
|
|
||||||
/*<span id="ctl00_spanSzczesliwyLos">Szczęśliwy los na dzisiaj to <b>19</b>. Los na jutro to <b>22</b></span>*/
|
|
||||||
val IDZIENNIK_WEB_LUCKY_NUMBER by lazy {
|
|
||||||
"""dzisiaj to <b>([0-9]+)</b>""".toRegex()
|
|
||||||
}
|
|
||||||
val IDZIENNIK_WEB_SELECTED_REGISTER by lazy {
|
|
||||||
"""selected="selected" value="([0-9]+)" data-id-ucznia""".toRegex()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val VULCAN_SHIFT_ANNOTATION by lazy {
|
|
||||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
|
||||||
}
|
|
||||||
val VULCAN_WEB_PERMISSIONS by lazy {
|
val VULCAN_WEB_PERMISSIONS by lazy {
|
||||||
"""permissions: '([A-z0-9/=+\-_|]+?)'""".toRegex()
|
"""permissions: '([A-z0-9/=+\-_|]+?)'""".toRegex()
|
||||||
}
|
}
|
||||||
@ -197,82 +163,6 @@ object Regexes {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val EDUDZIENNIK_STUDENTS_START by lazy {
|
|
||||||
"""<li><a href="/Students/([\w-_]+?)/start/">(.*?)</a>""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_ACCOUNT_NAME_START by lazy {
|
|
||||||
"""<span id='user_dn'>(.*?)</span>""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_SUBJECTS_START by lazy {
|
|
||||||
"""<a class="menu-course" href="/Students/[\w-_]+?/Courses/([\w-_]+)/">(.+?)</a>""".toRegex()
|
|
||||||
}
|
|
||||||
|
|
||||||
val EDUDZIENNIK_ATTENDANCE_ENTRIES by lazy {
|
|
||||||
"""<td id="([\d-]+?):(\d+?)".*?>(.+?)</td>""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_ATTENDANCE_TYPES by lazy {
|
|
||||||
"""<div class="info">.*?<p>(.*?)</p>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_ATTENDANCE_TYPE by lazy {
|
|
||||||
"""\((.+?)\) (.+)""".toRegex()
|
|
||||||
}
|
|
||||||
|
|
||||||
val EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION by lazy {
|
|
||||||
"""<div class="desc">.*?<p>(.*?)</p>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_HOMEWORK_DESCRIPTION by lazy {
|
|
||||||
"""<div class="desc">(.*?)</div>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
|
|
||||||
val EDUDZIENNIK_SUBJECT_ID by lazy {
|
|
||||||
"""/Courses/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_GRADE_ID by lazy {
|
|
||||||
"""/Grades/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_EXAM_ID by lazy {
|
|
||||||
"""/Evaluations/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_EVENT_TYPE_ID by lazy {
|
|
||||||
"""/GradeLabels/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_ANNOUNCEMENT_ID by lazy {
|
|
||||||
"""/Announcement/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_HOMEWORK_ID by lazy {
|
|
||||||
"""/Homework/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_TEACHER_ID by lazy {
|
|
||||||
"""/Teachers/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_EVENT_ID by lazy {
|
|
||||||
"""/KlassEvent/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_NOTE_ID by lazy {
|
|
||||||
"""/RegistryNotes/([\w-_]+?)/""".toRegex()
|
|
||||||
}
|
|
||||||
|
|
||||||
val EDUDZIENNIK_SCHOOL_DETAIL_ID by lazy {
|
|
||||||
"""<a id="School_detail".*?/School/([\w-_]+?)/""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_SCHOOL_DETAIL_NAME by lazy {
|
|
||||||
"""</li>.*?<p>(.*?)</p>.*?<li>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_CLASS_DETAIL_ID by lazy {
|
|
||||||
"""<a id="Klass_detail".*?/Klass/([\w-_]+?)/""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
val EDUDZIENNIK_CLASS_DETAIL_NAME by lazy {
|
|
||||||
"""<a id="Klass_detail".*?>(.*?)</a>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
|
|
||||||
val EDUDZIENNIK_TEACHERS by lazy {
|
|
||||||
"""<div class="teacher">.*?<p>(.+?) (.+?)</p>""".toRegex(DOT_MATCHES_ALL)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val LINKIFY_DATE_YMD by lazy {
|
val LINKIFY_DATE_YMD by lazy {
|
||||||
"""(1\d{3}|20\d{2})[\-./](1[0-2]|0?\d)[\-./]([1-2]\d|3[0-1]|0?\d)""".toRegex()
|
"""(1\d{3}|20\d{2})[\-./](1[0-2]|0?\d)[\-./]([1-2]\d|3[0-1]|0?\d)""".toRegex()
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@ import com.google.gson.JsonObject
|
|||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.Edudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.Usos
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
|
import pl.szczodrzynski.edziennik.data.api.events.RegisterAvailabilityEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
@ -112,9 +112,9 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||||
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
||||||
LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
|
||||||
LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(app, profile, loginStore, taskCallback)
|
|
||||||
LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
|
||||||
LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback)
|
||||||
|
LOGIN_TYPE_USOS -> Usos(app, profile, loginStore, taskCallback)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
if (edziennikInterface == null) {
|
if (edziennikInterface == null) {
|
||||||
|
@ -1,125 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.EventType
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
|
|
||||||
*
|
|
||||||
* Use https://codepen.io/kubasz/pen/RwwwbGN to easily generate the student data getters/setters
|
|
||||||
*/
|
|
||||||
class DataEdudziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
|
||||||
|
|
||||||
fun isWebLoginValid() = webSessionIdExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty()
|
|
||||||
|
|
||||||
override fun satisfyLoginMethods() {
|
|
||||||
loginMethods.clear()
|
|
||||||
if (isWebLoginValid()) {
|
|
||||||
loginMethods += LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun generateUserCode() = "$schoolName:$loginEmail:${studentId?.crc32()}"
|
|
||||||
|
|
||||||
private var mLoginEmail: String? = null
|
|
||||||
var loginEmail: String?
|
|
||||||
get() { mLoginEmail = mLoginEmail ?: loginStore.getLoginData("email", null); return mLoginEmail }
|
|
||||||
set(value) { loginStore.putLoginData("email", value); mLoginEmail = value }
|
|
||||||
|
|
||||||
private var mLoginPassword: String? = null
|
|
||||||
var loginPassword: String?
|
|
||||||
get() { mLoginPassword = mLoginPassword ?: loginStore.getLoginData("password", null); return mLoginPassword }
|
|
||||||
set(value) { loginStore.putLoginData("password", value); mLoginPassword = value }
|
|
||||||
|
|
||||||
private var mStudentId: String? = null
|
|
||||||
var studentId: String?
|
|
||||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
|
||||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
|
||||||
|
|
||||||
private var mSchoolId: String? = null
|
|
||||||
var schoolId: String?
|
|
||||||
get() { mSchoolId = mSchoolId ?: profile?.getStudentData("schoolId", null); return mSchoolId }
|
|
||||||
set(value) { profile?.putStudentData("schoolId", value) ?: return; mSchoolId = value }
|
|
||||||
|
|
||||||
private var mClassId: String? = null
|
|
||||||
var classId: String?
|
|
||||||
get() { mClassId = mClassId ?: profile?.getStudentData("classId", null); return mClassId }
|
|
||||||
set(value) { profile?.putStudentData("classId", value) ?: return; mClassId = value }
|
|
||||||
|
|
||||||
/* __ __ _
|
|
||||||
\ \ / / | |
|
|
||||||
\ \ /\ / /__| |__
|
|
||||||
\ \/ \/ / _ \ '_ \
|
|
||||||
\ /\ / __/ |_) |
|
|
||||||
\/ \/ \___|_._*/
|
|
||||||
private var mWebSessionId: String? = null
|
|
||||||
var webSessionId: String?
|
|
||||||
get() { mWebSessionId = mWebSessionId ?: loginStore.getLoginData("webSessionId", null); return mWebSessionId }
|
|
||||||
set(value) { loginStore.putLoginData("webSessionId", value); mWebSessionId = value }
|
|
||||||
|
|
||||||
private var mWebSessionIdExpiryTime: Long? = null
|
|
||||||
var webSessionIdExpiryTime: Long
|
|
||||||
get() { mWebSessionIdExpiryTime = mWebSessionIdExpiryTime ?: loginStore.getLoginData("webSessionIdExpiryTime", 0L); return mWebSessionIdExpiryTime ?: 0L }
|
|
||||||
set(value) { loginStore.putLoginData("webSessionIdExpiryTime", value); mWebSessionIdExpiryTime = value }
|
|
||||||
|
|
||||||
/* ____ _ _
|
|
||||||
/ __ \| | | |
|
|
||||||
| | | | |_| |__ ___ _ __
|
|
||||||
| | | | __| '_ \ / _ \ '__|
|
|
||||||
| |__| | |_| | | | __/ |
|
|
||||||
\____/ \__|_| |_|\___|*/
|
|
||||||
private var mCurrentSemester: Int? = null
|
|
||||||
var currentSemester: Int
|
|
||||||
get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 1); return mCurrentSemester ?: 1 }
|
|
||||||
set(value) { profile?.putStudentData("currentSemester", value) ?: return; mCurrentSemester = value }
|
|
||||||
|
|
||||||
private var mSchoolName: String? = null
|
|
||||||
var schoolName: String?
|
|
||||||
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
|
|
||||||
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
|
|
||||||
|
|
||||||
val studentEndpoint: String
|
|
||||||
get() = "Students/$studentId/"
|
|
||||||
|
|
||||||
val schoolEndpoint: String
|
|
||||||
get() = "Schools/$schoolId/"
|
|
||||||
|
|
||||||
val classStudentEndpoint: String
|
|
||||||
get() = "Class/$studentId/"
|
|
||||||
|
|
||||||
val schoolClassEndpoint: String
|
|
||||||
get() = "Schools/$classId/"
|
|
||||||
|
|
||||||
val studentAndClassEndpoint: String
|
|
||||||
get() = "Students/$studentId/Klass/$classId/"
|
|
||||||
|
|
||||||
val studentAndClassesEndpoint: String
|
|
||||||
get() = "Students/$studentId/Classes/$classId/"
|
|
||||||
|
|
||||||
val timetableEndpoint: String
|
|
||||||
get() = "Plan/$studentId/"
|
|
||||||
|
|
||||||
val studentAndTeacherClassEndpoint: String
|
|
||||||
get() = "Students/$studentId/Teachers/$classId/"
|
|
||||||
|
|
||||||
val courseStudentEndpoint: String
|
|
||||||
get() = "Course/$studentId/"
|
|
||||||
|
|
||||||
fun getEventType(longId: String, name: String): EventType {
|
|
||||||
val id = longId.crc16().toLong()
|
|
||||||
return eventTypes.singleOrNull { it.id == id } ?: run {
|
|
||||||
val eventType = EventType(profileId, id, name, colorFromName(name))
|
|
||||||
eventTypes.put(id, eventType)
|
|
||||||
eventType
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikData
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetAnnouncement
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetHomework
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin.EdudziennikFirstLogin
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLogin
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
|
|
||||||
class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "Edudziennik"
|
|
||||||
}
|
|
||||||
|
|
||||||
val internalErrorList = mutableListOf<Int>()
|
|
||||||
val data: DataEdudziennik
|
|
||||||
private var afterLogin: (() -> Unit)? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
data = DataEdudziennik(app, profile, loginStore).apply {
|
|
||||||
callback = wrapCallback(this@Edudziennik.callback)
|
|
||||||
satisfyLoginMethods()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun completed() {
|
|
||||||
data.saveData()
|
|
||||||
callback.onCompleted()
|
|
||||||
}
|
|
||||||
|
|
||||||
/* _______ _ _ _ _ _
|
|
||||||
|__ __| | /\ | | (_) | | |
|
|
||||||
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
|
|
||||||
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
|
|
||||||
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|
|
||||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
|
||||||
__/ |
|
|
||||||
|__*/
|
|
||||||
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
|
|
||||||
data.arguments = arguments
|
|
||||||
data.prepare(edudziennikLoginMethods, EdudziennikFeatures, featureIds, viewId, onlyEndpoints)
|
|
||||||
login()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
|
|
||||||
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
|
||||||
if (internalErrorList.isNotEmpty()) {
|
|
||||||
d(TAG, " - Internal errors:")
|
|
||||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
|
||||||
}
|
|
||||||
loginMethodId?.let { data.prepareFor(edudziennikLoginMethods, it) }
|
|
||||||
afterLogin?.let { this.afterLogin = it }
|
|
||||||
EdudziennikLogin(data) {
|
|
||||||
data()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun data() {
|
|
||||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
|
||||||
if (internalErrorList.isNotEmpty()) {
|
|
||||||
d(TAG, " - Internal errors:")
|
|
||||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
|
||||||
}
|
|
||||||
afterLogin?.invoke() ?: EdudziennikData(data) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMessage(message: MessageFull) {}
|
|
||||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {}
|
|
||||||
override fun markAllAnnouncementsAsRead() {}
|
|
||||||
|
|
||||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
|
||||||
EdudziennikLoginWeb(data) {
|
|
||||||
EdudziennikWebGetAnnouncement(data, announcement) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
|
|
||||||
override fun getRecipientList() {}
|
|
||||||
|
|
||||||
override fun getEvent(eventFull: EventFull) {
|
|
||||||
EdudziennikLoginWeb(data) {
|
|
||||||
EdudziennikWebGetHomework(data, eventFull) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun firstLogin() { EdudziennikFirstLogin(data) { completed() } }
|
|
||||||
override fun cancel() {
|
|
||||||
d(TAG, "Cancelled")
|
|
||||||
data.cancel()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
|
||||||
return object : EdziennikCallback {
|
|
||||||
override fun onCompleted() { callback.onCompleted() }
|
|
||||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
|
||||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
|
||||||
override fun onError(apiError: ApiError) {
|
|
||||||
if (apiError.errorCode in internalErrorList) {
|
|
||||||
// finish immediately if the same error occurs twice during the same sync
|
|
||||||
callback.onError(apiError)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
internalErrorList.add(apiError.errorCode)
|
|
||||||
when (apiError.errorCode) {
|
|
||||||
ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED -> {
|
|
||||||
login()
|
|
||||||
}
|
|
||||||
ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID -> {
|
|
||||||
login()
|
|
||||||
}
|
|
||||||
ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS -> {
|
|
||||||
data()
|
|
||||||
}
|
|
||||||
else -> callback.onError(apiError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
|
||||||
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_START = 1000
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_TEACHERS = 1001
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_GRADES = 1011
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE = 1012
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_EXAMS = 1013
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE = 1014
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS = 1015
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK = 1016
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_EVENTS = 1017
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_NOTES = 1018
|
|
||||||
const val ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER = 1030
|
|
||||||
|
|
||||||
val EdudziennikFeatures = listOf(
|
|
||||||
/* School and team info and subjects */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_STUDENT_INFO, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_START to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Teachers */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TEACHERS, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Timetable */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TIMETABLE, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Grades */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_GRADES, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Agenda */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_AGENDA, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS to LOGIN_METHOD_EDUDZIENNIK_WEB,
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB,
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Homework */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_HOMEWORK, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Behaviour */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Attendance */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ATTENDANCE, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Announcements */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/* Lucky number */
|
|
||||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_LUCKY_NUMBER, listOf(
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER to LOGIN_METHOD_EDUDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB))
|
|
||||||
)
|
|
@ -1,88 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.R
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.*
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
|
|
||||||
class EdudziennikData(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikData"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
nextEndpoint(onSuccess)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
|
||||||
if (data.targetEndpointIds.isEmpty()) {
|
|
||||||
onSuccess()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (data.cancelled) {
|
|
||||||
onSuccess()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val id = data.targetEndpointIds.firstKey()
|
|
||||||
val lastSync = data.targetEndpointIds.remove(id)
|
|
||||||
useEndpoint(id, lastSync) { endpointId ->
|
|
||||||
data.progress(data.progressStep)
|
|
||||||
nextEndpoint(onSuccess)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
|
||||||
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
|
||||||
when (endpointId) {
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_START -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_data)
|
|
||||||
EdudziennikWebStart(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
|
||||||
EdudziennikWebTeachers(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
|
||||||
EdudziennikWebGrades(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
|
||||||
EdudziennikWebTimetable(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
|
||||||
EdudziennikWebExams(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
|
||||||
EdudziennikWebAttendance(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
|
||||||
EdudziennikWebAnnouncements(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
|
||||||
EdudziennikWebHomework(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
|
||||||
EdudziennikWebEvents(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
|
||||||
EdudziennikWebNotes(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
|
||||||
EdudziennikWebLuckyNumber(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
else -> onSuccess(endpointId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
|
|
||||||
|
|
||||||
import im.wangchao.mhttp.Request
|
|
||||||
import im.wangchao.mhttp.Response
|
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
open class EdudziennikWeb(open val data: DataEdudziennik, open val lastSync: Long?) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWeb"
|
|
||||||
}
|
|
||||||
|
|
||||||
val profileId
|
|
||||||
get() = data.profile?.id ?: -1
|
|
||||||
|
|
||||||
val profile
|
|
||||||
get() = data.profile
|
|
||||||
|
|
||||||
fun webGet(tag: String, endpoint: String, xhr: Boolean = false, semester: Int? = null, onSuccess: (text: String) -> Unit) {
|
|
||||||
val url = "https://dziennikel.appspot.com/" + when (endpoint.endsWith('/') || endpoint.contains('?') || endpoint.isEmpty()) {
|
|
||||||
true -> endpoint
|
|
||||||
else -> "$endpoint/"
|
|
||||||
} + (semester?.let { "?semester=" + if(it == -1) "all" else it } ?: "")
|
|
||||||
|
|
||||||
d(tag, "Request: Edudziennik/Web - $url")
|
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
if (text == null || response == null) {
|
|
||||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (semester == null && url.contains("start")) {
|
|
||||||
profile?.also { profile ->
|
|
||||||
val cookies = data.app.cookieJar.getAll("dziennikel.appspot.com")
|
|
||||||
val semesterCookie = cookies["semester"]?.toIntOrNull()
|
|
||||||
|
|
||||||
semesterCookie?.let { data.currentSemester = it }
|
|
||||||
|
|
||||||
if (semesterCookie == 2 && profile.dateSemester2Start > Date.getToday())
|
|
||||||
profile.dateSemester2Start = Date.getToday().stepForward(0, 0, -1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onSuccess(text)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_WEB_REQUEST)
|
|
||||||
.withThrowable(e)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
val error = when (response?.code()) {
|
|
||||||
402 -> ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS
|
|
||||||
403 -> ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED
|
|
||||||
else -> ERROR_REQUEST_FAILURE
|
|
||||||
}
|
|
||||||
data.error(ApiError(tag, error)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.app.cookieJar.set("dziennikel.appspot.com", "sessionid", data.webSessionId)
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url(url)
|
|
||||||
.userAgent(EDUDZIENNIK_USER_AGENT)
|
|
||||||
.apply {
|
|
||||||
if (xhr) header("X-Requested-With", "XMLHttpRequest")
|
|
||||||
}
|
|
||||||
.get()
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,75 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-26
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ANNOUNCEMENT_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Announcement
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebAnnouncements"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.schoolClassEndpoint + "Announcements") { text ->
|
|
||||||
val doc = Jsoup.parse(text)
|
|
||||||
|
|
||||||
if (doc.getElementsByClass("message").text().trim() != "Brak ogłoszeń.") {
|
|
||||||
doc.select("table.list tbody tr").forEach { announcementElement ->
|
|
||||||
val titleElement = announcementElement.child(0).child(0)
|
|
||||||
|
|
||||||
val longId = EDUDZIENNIK_ANNOUNCEMENT_ID.find(titleElement.attr("href"))?.get(1)
|
|
||||||
?: return@forEach
|
|
||||||
val id = longId.crc32()
|
|
||||||
val subject = titleElement.text()
|
|
||||||
|
|
||||||
val teacherName = announcementElement.child(1).text()
|
|
||||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
|
||||||
|
|
||||||
val dateString = announcementElement.getElementsByClass("datetime").first()?.text()
|
|
||||||
val startDate = Date.fromY_m_d(dateString)
|
|
||||||
val addedDate = Date.fromIsoHm(dateString)
|
|
||||||
|
|
||||||
val announcementObject = Announcement(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
subject = subject,
|
|
||||||
text = null,
|
|
||||||
startDate = startDate,
|
|
||||||
endDate = null,
|
|
||||||
teacherId = teacher.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
).also {
|
|
||||||
it.idString = longId
|
|
||||||
}
|
|
||||||
|
|
||||||
data.announcementList.add(announcementObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_ANNOUNCEMENT,
|
|
||||||
id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS) }
|
|
||||||
}
|
|
@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-24
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_ENTRIES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.ext.singleOrNull
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class EdudziennikWebAttendance(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWebAttendance"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var requestSemester: Int? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (profile?.empty == true && data.currentSemester == 2) requestSemester = 1
|
|
||||||
getAttendances()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAttendances() { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.studentEndpoint + "Presence", semester = requestSemester) { text ->
|
|
||||||
|
|
||||||
val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map {
|
|
||||||
val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim())
|
|
||||||
val symbol = type?.get(1)?.trim() ?: "?"
|
|
||||||
val name = type?.get(2)?.trim() ?: "nieznany rodzaj"
|
|
||||||
return@map Triple(
|
|
||||||
symbol,
|
|
||||||
name,
|
|
||||||
when (name.lowercase()) {
|
|
||||||
"obecność" -> Attendance.TYPE_PRESENT
|
|
||||||
"nieobecność" -> Attendance.TYPE_ABSENT
|
|
||||||
"spóźnienie" -> Attendance.TYPE_BELATED
|
|
||||||
"nieobecność usprawiedliwiona" -> Attendance.TYPE_ABSENT_EXCUSED
|
|
||||||
"dzień wolny" -> Attendance.TYPE_DAY_FREE
|
|
||||||
"brak zajęć" -> Attendance.TYPE_DAY_FREE
|
|
||||||
"oddelegowany" -> Attendance.TYPE_RELEASED
|
|
||||||
else -> Attendance.TYPE_UNKNOWN
|
|
||||||
}
|
|
||||||
)
|
|
||||||
} ?: emptyList()
|
|
||||||
|
|
||||||
EDUDZIENNIK_ATTENDANCE_ENTRIES.findAll(text).forEach { attendanceElement ->
|
|
||||||
val date = Date.fromY_m_d(attendanceElement[1])
|
|
||||||
val lessonNumber = attendanceElement[2].toInt()
|
|
||||||
val attendanceSymbol = attendanceElement[3]
|
|
||||||
|
|
||||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
|
||||||
val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber }
|
|
||||||
|
|
||||||
val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32()
|
|
||||||
|
|
||||||
val (typeSymbol, typeName, baseType) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol }
|
|
||||||
?: return@forEach
|
|
||||||
|
|
||||||
val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime
|
|
||||||
?: return@forEach
|
|
||||||
|
|
||||||
val attendanceObject = Attendance(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
baseType = baseType,
|
|
||||||
typeName = typeName,
|
|
||||||
typeShort = data.app.attendanceManager.getTypeShort(baseType),
|
|
||||||
typeSymbol = typeSymbol,
|
|
||||||
typeColor = null,
|
|
||||||
date = date,
|
|
||||||
startTime = lesson?.displayStartTime ?: startTime,
|
|
||||||
semester = profile.currentSemester,
|
|
||||||
teacherId = lesson?.displayTeacherId ?: -1,
|
|
||||||
subjectId = lesson?.displaySubjectId ?: -1
|
|
||||||
).also {
|
|
||||||
it.lessonNumber = lessonNumber
|
|
||||||
}
|
|
||||||
|
|
||||||
data.attendanceList.add(attendanceObject)
|
|
||||||
if (baseType != Attendance.TYPE_PRESENT) {
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_ATTENDANCE,
|
|
||||||
id,
|
|
||||||
profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
|
|
||||||
profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profile.empty && requestSemester == 1 && data.currentSemester == 2) {
|
|
||||||
requestSemester = null
|
|
||||||
getAttendances()
|
|
||||||
} else {
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE) }
|
|
||||||
}
|
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-1
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EVENTS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebEvents(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebEvents"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.studentAndClassesEndpoint + "KlassEvent", xhr = true) { text ->
|
|
||||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
|
||||||
|
|
||||||
doc.getElementsByTag("tr").forEach { eventElement ->
|
|
||||||
val date = Date.fromY_m_d(eventElement.child(1).text())
|
|
||||||
|
|
||||||
val titleElement = eventElement.child(2).child(0)
|
|
||||||
val title = titleElement.text().trim()
|
|
||||||
|
|
||||||
val id = EDUDZIENNIK_EVENT_ID.find(titleElement.attr("href"))?.get(1)?.crc32()
|
|
||||||
?: return@forEach
|
|
||||||
|
|
||||||
val eventObject = Event(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
date = date,
|
|
||||||
time = null,
|
|
||||||
topic = title,
|
|
||||||
color = null,
|
|
||||||
type = Event.TYPE_CLASS_EVENT,
|
|
||||||
teacherId = -1,
|
|
||||||
subjectId = -1,
|
|
||||||
teamId = data.teamClass?.id ?: -1
|
|
||||||
)
|
|
||||||
|
|
||||||
data.eventList.add(eventObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_EVENT,
|
|
||||||
id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_CLASS_EVENT))
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EVENTS, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS) }
|
|
||||||
}
|
|
@ -1,90 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-24
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_TYPE_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EXAM_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EXAMS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebExams(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebExams"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { profile?.also { profile ->
|
|
||||||
webGet(TAG, data.studentAndClassEndpoint + "Evaluations", xhr = true) { text ->
|
|
||||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
|
||||||
|
|
||||||
doc.select("tr").forEach { examElement ->
|
|
||||||
val id = EDUDZIENNIK_EXAM_ID.find(examElement.child(0).child(0).attr("href"))
|
|
||||||
?.get(1)?.crc32() ?: return@forEach
|
|
||||||
val topic = examElement.child(0).text().trim()
|
|
||||||
|
|
||||||
val subjectElement = examElement.child(1).child(0)
|
|
||||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
|
||||||
?: return@forEach
|
|
||||||
val subjectName = subjectElement.text().trim()
|
|
||||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
|
||||||
|
|
||||||
val dateString = examElement.child(2).text().trim()
|
|
||||||
if (dateString.isBlank()) return@forEach
|
|
||||||
val date = Date.fromY_m_d(dateString)
|
|
||||||
|
|
||||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
|
||||||
val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime
|
|
||||||
|
|
||||||
val eventTypeElement = examElement.child(3).child(0)
|
|
||||||
val eventTypeId = EDUDZIENNIK_EVENT_TYPE_ID.find(eventTypeElement.attr("href"))?.get(1)
|
|
||||||
?: return@forEach
|
|
||||||
val eventTypeName = eventTypeElement.text()
|
|
||||||
val eventType = data.getEventType(eventTypeId, eventTypeName)
|
|
||||||
|
|
||||||
val eventObject = Event(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
date = date,
|
|
||||||
time = startTime,
|
|
||||||
topic = topic,
|
|
||||||
color = null,
|
|
||||||
type = eventType.id,
|
|
||||||
teacherId = -1,
|
|
||||||
subjectId = subject.id,
|
|
||||||
teamId = data.teamClass?.id ?: -1
|
|
||||||
)
|
|
||||||
|
|
||||||
data.eventList.add(eventObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_EVENT,
|
|
||||||
id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.toRemove.add(DataRemoveModel.Events.futureExceptTypes(listOf(
|
|
||||||
Event.TYPE_HOMEWORK,
|
|
||||||
Event.TYPE_CLASS_EVENT
|
|
||||||
)))
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EXAMS)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-26
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
|
|
||||||
class EdudziennikWebGetAnnouncement(override val data: DataEdudziennik,
|
|
||||||
private val announcement: AnnouncementFull,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : EdudziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebGetAnnouncement"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
webGet(TAG, "Announcement/${announcement.idString}") { text ->
|
|
||||||
val description = Regexes.EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION.find(text)?.get(1)?.trim() ?: ""
|
|
||||||
|
|
||||||
announcement.text = description
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(AnnouncementGetEvent(announcement))
|
|
||||||
|
|
||||||
data.announcementList.add(announcement)
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
|
||||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
|
||||||
|
|
||||||
class EdudziennikWebGetHomework(
|
|
||||||
override val data: DataEdudziennik,
|
|
||||||
val event: EventFull,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : EdudziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebGetHomework"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (event.attachmentNames.isNotNullNorEmpty()) {
|
|
||||||
val id = event.attachmentNames!![0]
|
|
||||||
|
|
||||||
webGet(TAG, "Homework/$id") { text ->
|
|
||||||
val description = Regexes.EDUDZIENNIK_HOMEWORK_DESCRIPTION.find(text)?.get(1)?.trim()
|
|
||||||
|
|
||||||
if (description != null)
|
|
||||||
event.topic = BetterHtml.fromHtml(context = null, description).toString()
|
|
||||||
|
|
||||||
event.homeworkBody = ""
|
|
||||||
event.isDownloaded = true
|
|
||||||
event.attachmentNames = null
|
|
||||||
|
|
||||||
data.eventList += event
|
|
||||||
data.eventListReplace = true
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(EventGetEvent(event))
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
EventBus.getDefault().postSticky(EventGetEvent(event))
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,230 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-25
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import android.graphics.Color
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_GRADES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.colorFromCssName
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebGrades(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWebGrades"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var requestSemester: Int? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
if (profile?.empty == true && data.currentSemester == 2) requestSemester = 1
|
|
||||||
getGrades()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getGrades() { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.studentEndpoint + "start", semester = requestSemester) { text ->
|
|
||||||
val semester = requestSemester ?: data.currentSemester
|
|
||||||
|
|
||||||
val doc = Jsoup.parse(text)
|
|
||||||
val subjects = doc.select("#student_grades tbody").firstOrNull()?.children()
|
|
||||||
|
|
||||||
subjects?.forEach { subjectElement ->
|
|
||||||
if (subjectElement.id().isBlank()) return@forEach
|
|
||||||
|
|
||||||
val subjectId = subjectElement.id().trim()
|
|
||||||
val subjectName = subjectElement.child(0).text().trim()
|
|
||||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
|
||||||
|
|
||||||
val gradeType = when {
|
|
||||||
subjectElement.select("#sum").text().isNotBlank() -> TYPE_POINT_SUM
|
|
||||||
else -> TYPE_NORMAL
|
|
||||||
}
|
|
||||||
|
|
||||||
val gradeCountToAverage = subjectElement.select("#avg").text().isNotBlank()
|
|
||||||
|
|
||||||
val grades = subjectElement.select(".grade[data-edited]")
|
|
||||||
val gradesInfo = subjectElement.select(".grade-tip")
|
|
||||||
|
|
||||||
val gradeValues = if (grades.isNotEmpty()) {
|
|
||||||
subjects.select(".avg-$subjectId .grade-tip > p").first()
|
|
||||||
?.text()?.split('+')?.map {
|
|
||||||
val split = it.split('*')
|
|
||||||
val value = split[1].trim().toFloatOrNull()
|
|
||||||
val weight = value?.let { split[0].trim().toFloatOrNull() } ?: 0f
|
|
||||||
|
|
||||||
Pair(value ?: 0f, weight)
|
|
||||||
} ?: emptyList()
|
|
||||||
} else emptyList()
|
|
||||||
|
|
||||||
grades.forEachIndexed { index, gradeElement ->
|
|
||||||
val id = Regexes.EDUDZIENNIK_GRADE_ID.find(gradeElement.attr("href"))?.get(1)?.crc32()
|
|
||||||
?: return@forEachIndexed
|
|
||||||
val (value, weight) = gradeValues[index]
|
|
||||||
val name = gradeElement.text().trim().let {
|
|
||||||
if (it.contains(',') || it.contains('.')) {
|
|
||||||
val replaced = it.replace(',', '.')
|
|
||||||
val float = replaced.toFloatOrNull()
|
|
||||||
|
|
||||||
if (float != null && float % 1 == 0f) float.toInt().toString()
|
|
||||||
else it
|
|
||||||
} else it
|
|
||||||
}
|
|
||||||
|
|
||||||
val info = gradesInfo[index]
|
|
||||||
val fullName = info.child(0).text().trim()
|
|
||||||
val columnName = info.child(4).text().trim()
|
|
||||||
val comment = info.ownText()
|
|
||||||
|
|
||||||
val description = columnName + if (comment.isNotBlank()) " - $comment" else null
|
|
||||||
|
|
||||||
val teacherName = info.child(1).text()
|
|
||||||
val teacher = data.getTeacherByLastFirst(teacherName)
|
|
||||||
|
|
||||||
val addedDate = info.child(2).text().split(' ').let {
|
|
||||||
val day = it[0].toInt()
|
|
||||||
val month = Utils.monthFromName(it[1])
|
|
||||||
val year = it[2].toInt()
|
|
||||||
|
|
||||||
Date(year, month, day).inMillis
|
|
||||||
}
|
|
||||||
|
|
||||||
val color = Regexes.STYLE_CSS_COLOR.find(gradeElement.attr("style"))?.get(1)?.let {
|
|
||||||
if (it.startsWith('#')) Color.parseColor(it)
|
|
||||||
else colorFromCssName(it)
|
|
||||||
} ?: -1
|
|
||||||
|
|
||||||
val gradeObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
name = name,
|
|
||||||
type = gradeType,
|
|
||||||
value = value,
|
|
||||||
weight = if (gradeCountToAverage) weight else 0f,
|
|
||||||
color = color,
|
|
||||||
category = fullName,
|
|
||||||
description = description,
|
|
||||||
comment = null,
|
|
||||||
semester = semester,
|
|
||||||
teacherId = teacher.id,
|
|
||||||
subjectId = subject.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
|
|
||||||
data.gradeList.add(gradeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
val proposed = subjectElement.select(".proposal").firstOrNull()?.text()?.trim()
|
|
||||||
|
|
||||||
if (proposed != null && proposed.isNotBlank()) {
|
|
||||||
val proposedGradeObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = (-1 * subject.id) - 1,
|
|
||||||
name = proposed,
|
|
||||||
type = when (semester) {
|
|
||||||
1 -> TYPE_SEMESTER1_PROPOSED
|
|
||||||
else -> TYPE_SEMESTER2_PROPOSED
|
|
||||||
},
|
|
||||||
value = proposed.toFloatOrNull() ?: 0f,
|
|
||||||
weight = 0f,
|
|
||||||
color = -1,
|
|
||||||
category = null,
|
|
||||||
description = null,
|
|
||||||
comment = null,
|
|
||||||
semester = semester,
|
|
||||||
teacherId = -1,
|
|
||||||
subjectId = subject.id
|
|
||||||
)
|
|
||||||
|
|
||||||
data.gradeList.add(proposedGradeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
proposedGradeObject.id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
val final = subjectElement.select(".final").firstOrNull()?.text()?.trim()
|
|
||||||
|
|
||||||
if (final != null && final.isNotBlank()) {
|
|
||||||
val finalGradeObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = (-1 * subject.id) - 2,
|
|
||||||
name = final,
|
|
||||||
type = when (semester) {
|
|
||||||
1 -> TYPE_SEMESTER1_FINAL
|
|
||||||
else -> TYPE_SEMESTER2_FINAL
|
|
||||||
},
|
|
||||||
value = final.toFloatOrNull() ?: 0f,
|
|
||||||
weight = 0f,
|
|
||||||
color = -1,
|
|
||||||
category = null,
|
|
||||||
description = null,
|
|
||||||
comment = null,
|
|
||||||
semester = semester,
|
|
||||||
teacherId = -1,
|
|
||||||
subjectId = subject.id
|
|
||||||
)
|
|
||||||
|
|
||||||
data.gradeList.add(finalGradeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
data.profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
finalGradeObject.id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subjects.isNullOrEmpty()) {
|
|
||||||
data.toRemove.addAll(listOf(
|
|
||||||
TYPE_NORMAL,
|
|
||||||
TYPE_POINT_SUM,
|
|
||||||
TYPE_SEMESTER1_PROPOSED,
|
|
||||||
TYPE_SEMESTER2_PROPOSED,
|
|
||||||
TYPE_SEMESTER1_FINAL,
|
|
||||||
TYPE_SEMESTER2_FINAL
|
|
||||||
).map {
|
|
||||||
DataRemoveModel.Grades.semesterWithType(semester, it)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profile.empty && requestSemester == 1 && data.currentSemester == 2) {
|
|
||||||
requestSemester = null
|
|
||||||
getGrades()
|
|
||||||
} else {
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_GRADES)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_GRADES) }
|
|
||||||
}
|
|
@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_HOMEWORK_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebHomework(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebHomework"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.courseStudentEndpoint + "Homework", xhr = true) { text ->
|
|
||||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
|
||||||
|
|
||||||
if (doc.getElementsByClass("message").text().trim() != "Brak prac domowych") {
|
|
||||||
doc.getElementsByTag("tr").forEach { homeworkElement ->
|
|
||||||
val dateElement = homeworkElement.getElementsByClass("date").first()?.child(0) ?: return@forEach
|
|
||||||
val idStr = EDUDZIENNIK_HOMEWORK_ID.find(dateElement.attr("href"))?.get(1) ?: return@forEach
|
|
||||||
val id = idStr.crc32()
|
|
||||||
val date = Date.fromY_m_d(dateElement.text())
|
|
||||||
|
|
||||||
val subjectElement = homeworkElement.child(1).child(0)
|
|
||||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
|
||||||
?: return@forEach
|
|
||||||
val subjectName = subjectElement.text()
|
|
||||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
|
||||||
|
|
||||||
val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
|
|
||||||
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
|
|
||||||
|
|
||||||
val teacherName = homeworkElement.child(2).text()
|
|
||||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
|
||||||
|
|
||||||
val topic = homeworkElement.child(4).text().trim()
|
|
||||||
|
|
||||||
val eventObject = Event(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
date = date,
|
|
||||||
time = startTime,
|
|
||||||
topic = topic ?: "",
|
|
||||||
color = null,
|
|
||||||
type = Event.TYPE_HOMEWORK,
|
|
||||||
teacherId = teacher.id,
|
|
||||||
subjectId = subject.id,
|
|
||||||
teamId = data.teamClass?.id ?: -1
|
|
||||||
)
|
|
||||||
|
|
||||||
eventObject.attachmentNames = mutableListOf(idStr)
|
|
||||||
|
|
||||||
data.eventList.add(eventObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_HOMEWORK,
|
|
||||||
id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK) }
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWebLuckyNumber"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text ->
|
|
||||||
text.toIntOrNull()?.also { luckyNumber ->
|
|
||||||
val luckyNumberObject = LuckyNumber(
|
|
||||||
profileId = profileId,
|
|
||||||
date = Date.getToday(),
|
|
||||||
number = luckyNumber
|
|
||||||
)
|
|
||||||
|
|
||||||
data.luckyNumberList.add(luckyNumberObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_LUCKY_NUMBER,
|
|
||||||
luckyNumberObject.date.value.toLong(),
|
|
||||||
true,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER) }
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-1
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_NOTE_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_NOTES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class EdudziennikWebNotes(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "EdudziennikWebNotes"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webGet(TAG, data.classStudentEndpoint + "RegistryNotesStudent", xhr = true) { text ->
|
|
||||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
|
||||||
|
|
||||||
doc.getElementsByTag("tr").forEach { noteElement ->
|
|
||||||
val dateElement = noteElement.getElementsByClass("date").first()?.child(0) ?: return@forEach
|
|
||||||
val addedDate = Date.fromY_m_d(dateElement.text()).inMillis
|
|
||||||
|
|
||||||
val id = EDUDZIENNIK_NOTE_ID.find(dateElement.attr("href"))?.get(0)?.crc32()
|
|
||||||
?: return@forEach
|
|
||||||
|
|
||||||
val teacherName = noteElement.child(1).text()
|
|
||||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
|
||||||
|
|
||||||
val description = noteElement.child(3).text()
|
|
||||||
|
|
||||||
val noticeObject = Notice(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
type = Notice.TYPE_NEUTRAL,
|
|
||||||
semester = profile.currentSemester,
|
|
||||||
text = description,
|
|
||||||
category = null,
|
|
||||||
points = null,
|
|
||||||
teacherId = teacher.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
|
|
||||||
data.noticeList.add(noticeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_NOTICE,
|
|
||||||
id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_NOTES, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES) }
|
|
||||||
}
|
|
@ -1,79 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_EDUDZIENNIK_WEB_TEAM_MISSING
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECTS_START
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_START
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
|
||||||
import pl.szczodrzynski.edziennik.ext.MONTH
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.firstLettersName
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
|
|
||||||
class EdudziennikWebStart(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWebStart"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
webGet(TAG, data.studentEndpoint + "start") { text ->
|
|
||||||
getSchoolAndTeam(text)
|
|
||||||
getSubjects(text)
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_START, MONTH)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_START)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSchoolAndTeam(text: String) {
|
|
||||||
val schoolId = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_ID.find(text)?.get(1)?.trim()
|
|
||||||
val schoolLongName = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_NAME.find(text)?.get(1)?.trim()
|
|
||||||
data.schoolId = schoolId
|
|
||||||
|
|
||||||
val classId = Regexes.EDUDZIENNIK_CLASS_DETAIL_ID.find(text)?.get(1)?.trim()
|
|
||||||
val className = Regexes.EDUDZIENNIK_CLASS_DETAIL_NAME.find(text)?.get(1)?.trim()
|
|
||||||
data.classId = classId
|
|
||||||
|
|
||||||
if (classId == null || className == null || schoolId == null || schoolLongName == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_EDUDZIENNIK_WEB_TEAM_MISSING)
|
|
||||||
.withApiResponse(text))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val schoolName = schoolId.crc32().toString() + schoolLongName.firstLettersName + "_edu"
|
|
||||||
data.schoolName = schoolName
|
|
||||||
|
|
||||||
val teamId = classId.crc32()
|
|
||||||
val teamCode = "$schoolName:$className"
|
|
||||||
|
|
||||||
val teamObject = Team(
|
|
||||||
data.profileId,
|
|
||||||
teamId,
|
|
||||||
className,
|
|
||||||
Team.TYPE_CLASS,
|
|
||||||
teamCode,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
|
|
||||||
data.teamClass = teamObject
|
|
||||||
data.teamList.put(teamObject.id, teamObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getSubjects(text: String) {
|
|
||||||
EDUDZIENNIK_SUBJECTS_START.findAll(text).forEach {
|
|
||||||
val id = it[1].trim()
|
|
||||||
val name = it[2].trim()
|
|
||||||
data.getSubject(id.crc32(), name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,34 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-25
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHERS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TEACHERS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.ext.MONTH
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
|
|
||||||
class EdudziennikWebTeachers(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWebTeachers"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
webGet(TAG, data.studentAndTeacherClassEndpoint + "grid") { text ->
|
|
||||||
EDUDZIENNIK_TEACHERS.findAll(text).forEach {
|
|
||||||
val lastName = it[1].trim()
|
|
||||||
val firstName = it[2].trim()
|
|
||||||
data.getTeacher(firstName, lastName)
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS, MONTH)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
|
||||||
|
|
||||||
import org.jsoup.Jsoup
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHER_ID
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.ext.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.ext.getString
|
|
||||||
import pl.szczodrzynski.edziennik.ext.singleOrNull
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
|
||||||
|
|
||||||
class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : EdudziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikWebTimetable"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
|
|
||||||
val currentWeekStart = Week.getWeekStart()
|
|
||||||
|
|
||||||
if (Date.getToday().weekDay > 4) {
|
|
||||||
currentWeekStart.stepForward(0, 0, 7)
|
|
||||||
}
|
|
||||||
|
|
||||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
|
||||||
|
|
||||||
val weekStart = Date.fromY_m_d(getDate)
|
|
||||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
|
||||||
|
|
||||||
webGet(TAG, data.timetableEndpoint + "print?date=$getDate") { text ->
|
|
||||||
val doc = Jsoup.parse(text)
|
|
||||||
|
|
||||||
val dataDays = mutableListOf<Int>()
|
|
||||||
val dataStart = weekStart.clone()
|
|
||||||
while (dataStart <= weekEnd) {
|
|
||||||
dataDays += dataStart.value
|
|
||||||
dataStart.stepForward(0, 0, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
val table = doc.select("#Schedule tbody").first()
|
|
||||||
|
|
||||||
if (table?.text()?.contains("Brak planu lekcji.") == false) {
|
|
||||||
table.children().forEach { row ->
|
|
||||||
val rowElements = row.children()
|
|
||||||
|
|
||||||
val lessonNumber = rowElements[0].text().toInt()
|
|
||||||
|
|
||||||
val times = rowElements[1].text().split('-')
|
|
||||||
val startTime = Time.fromH_m(times[0].trim())
|
|
||||||
val endTime = Time.fromH_m(times[1].trim())
|
|
||||||
|
|
||||||
data.lessonRanges.singleOrNull {
|
|
||||||
it.lessonNumber == lessonNumber && it.startTime == startTime && it.endTime == endTime
|
|
||||||
} ?: run {
|
|
||||||
data.lessonRanges.put(lessonNumber, LessonRange(profileId, lessonNumber, startTime, endTime))
|
|
||||||
}
|
|
||||||
|
|
||||||
rowElements.subList(2, rowElements.size).forEachIndexed { index, lesson ->
|
|
||||||
val course = lesson.select(".course").firstOrNull() ?: return@forEachIndexed
|
|
||||||
val info = course.select("span > span")
|
|
||||||
|
|
||||||
if (info.isEmpty()) return@forEachIndexed
|
|
||||||
|
|
||||||
val type = when (course.hasClass("substitute")) {
|
|
||||||
true -> Lesson.TYPE_CHANGE
|
|
||||||
else -> Lesson.TYPE_NORMAL
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Getting subject */
|
|
||||||
|
|
||||||
val subjectElement = info[0].child(0)
|
|
||||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
|
||||||
?: return@forEachIndexed
|
|
||||||
val subjectName = subjectElement.text().trim()
|
|
||||||
val subject = data.getSubject(subjectId.crc32(), subjectName)
|
|
||||||
|
|
||||||
/* Getting teacher */
|
|
||||||
|
|
||||||
val teacherId = if (info.size >= 2) {
|
|
||||||
val teacherElement = info[1].child(0)
|
|
||||||
val teacherLongId = EDUDZIENNIK_TEACHER_ID.find(teacherElement.attr("href"))?.get(1)
|
|
||||||
val teacherName = teacherElement.text().trim()
|
|
||||||
data.getTeacherByLastFirst(teacherName, teacherLongId).id
|
|
||||||
} else null
|
|
||||||
|
|
||||||
val lessonObject = Lesson(profileId, -1).also {
|
|
||||||
it.type = type
|
|
||||||
it.date = weekStart.clone().stepForward(0, 0, index)
|
|
||||||
it.lessonNumber = lessonNumber
|
|
||||||
it.startTime = startTime
|
|
||||||
it.endTime = endTime
|
|
||||||
it.subjectId = subject.id
|
|
||||||
it.teacherId = teacherId
|
|
||||||
it.teamId = data.teamClass?.id
|
|
||||||
|
|
||||||
it.id = it.buildId()
|
|
||||||
}
|
|
||||||
|
|
||||||
data.lessonList.add(lessonObject)
|
|
||||||
dataDays.remove(lessonObject.date!!.value)
|
|
||||||
|
|
||||||
if (type != Lesson.TYPE_NORMAL) {
|
|
||||||
val seen = profile.empty || lessonObject.date!! < Date.getToday()
|
|
||||||
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_LESSON_CHANGE,
|
|
||||||
lessonObject.id,
|
|
||||||
seen,
|
|
||||||
seen
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (day in dataDays) {
|
|
||||||
val lessonDate = Date.fromValue(day)
|
|
||||||
data.lessonList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
|
||||||
type = Lesson.TYPE_NO_LESSONS
|
|
||||||
date = lessonDate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
|
||||||
|
|
||||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
|
||||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE) }
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_EDUDZIENNIK
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ACCOUNT_NAME_START
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_STUDENTS_START
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
|
||||||
import pl.szczodrzynski.edziennik.ext.fixName
|
|
||||||
import pl.szczodrzynski.edziennik.ext.get
|
|
||||||
import pl.szczodrzynski.edziennik.ext.getShortName
|
|
||||||
import pl.szczodrzynski.edziennik.ext.set
|
|
||||||
|
|
||||||
class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikFirstLogin"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val web = EdudziennikWeb(data, null)
|
|
||||||
private val profileList = mutableListOf<Profile>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
val loginStoreId = data.loginStore.id
|
|
||||||
val loginStoreType = LOGIN_TYPE_EDUDZIENNIK
|
|
||||||
var firstProfileId = loginStoreId
|
|
||||||
|
|
||||||
EdudziennikLoginWeb(data) {
|
|
||||||
web.webGet(TAG, "") { text ->
|
|
||||||
val accountNameLong = EDUDZIENNIK_ACCOUNT_NAME_START.find(text)?.get(1)?.fixName()
|
|
||||||
|
|
||||||
EDUDZIENNIK_STUDENTS_START.findAll(text).forEach {
|
|
||||||
val studentId = it[1]
|
|
||||||
val studentNameLong = it[2].fixName()
|
|
||||||
|
|
||||||
if (studentId.isBlank() || studentNameLong.isBlank()) return@forEach
|
|
||||||
|
|
||||||
val studentNameShort = studentNameLong.getShortName()
|
|
||||||
val accountName = if (accountNameLong == studentNameLong) null else accountNameLong
|
|
||||||
|
|
||||||
val profile = Profile(
|
|
||||||
firstProfileId++,
|
|
||||||
loginStoreId,
|
|
||||||
loginStoreType,
|
|
||||||
studentNameLong,
|
|
||||||
data.loginEmail,
|
|
||||||
studentNameLong,
|
|
||||||
studentNameShort,
|
|
||||||
accountName
|
|
||||||
).apply {
|
|
||||||
studentData["studentId"] = studentId
|
|
||||||
}
|
|
||||||
profileList.add(profile)
|
|
||||||
}
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
|
|
||||||
|
|
||||||
import im.wangchao.mhttp.Request
|
|
||||||
import im.wangchao.mhttp.Response
|
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.ext.getUnixDate
|
|
||||||
import pl.szczodrzynski.edziennik.ext.isNotNullNorEmpty
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
|
|
||||||
class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "EdudziennikLoginWeb"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { run {
|
|
||||||
if (data.isWebLoginValid()) {
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data.app.cookieJar.clear("dziennikel.appspot.com")
|
|
||||||
if (data.loginEmail.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) {
|
|
||||||
loginWithCredentials()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
private fun loginWithCredentials() {
|
|
||||||
d(TAG, "Request: Edudziennik/Login/Web - https://dziennikel.appspot.com/login/?next=/")
|
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
if (text == null || response == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val url = response.raw().request().url().toString()
|
|
||||||
|
|
||||||
if (!url.contains("Student")) {
|
|
||||||
when {
|
|
||||||
text.contains("Wprowadzono nieprawidłową nazwę użytkownika lub hasło.") -> ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN
|
|
||||||
else -> ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER
|
|
||||||
}.let { errorCode ->
|
|
||||||
data.error(ApiError(TAG, errorCode)
|
|
||||||
.withApiResponse(text)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val cookies = data.app.cookieJar.getAll("dziennikel.appspot.com")
|
|
||||||
val sessionId = cookies["sessionid"]
|
|
||||||
|
|
||||||
if (sessionId == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(text))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
data.webSessionId = sessionId
|
|
||||||
data.webSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url("https://dziennikel.appspot.com/login/?next=/")
|
|
||||||
.userAgent(EDUDZIENNIK_USER_AGENT)
|
|
||||||
.contentType("application/x-www-form-urlencoded")
|
|
||||||
.addParameter("email", data.loginEmail)
|
|
||||||
.addParameter("password", data.loginPassword)
|
|
||||||
.addParameter("auth_method", "password")
|
|
||||||
.addParameter("next", "/")
|
|
||||||
.post()
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
@ -162,6 +163,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
return object : EdziennikCallback {
|
return object : EdziennikCallback {
|
||||||
override fun onCompleted() { callback.onCompleted() }
|
override fun onCompleted() { callback.onCompleted() }
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
|
||||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
override fun onProgress(step: Float) { callback.onProgress(step) }
|
||||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
|
@ -10,6 +10,7 @@ import im.wangchao.mhttp.callback.TextCallbackHandler
|
|||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
@ -148,12 +149,23 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
val error = if (response.code() == 200) null else
|
val error = if (response.code() == 200) null else
|
||||||
json.getJsonArray("errors")?.getString(0)
|
json.getJsonArray("errors")?.getString(0)
|
||||||
?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString
|
?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString
|
||||||
|
|
||||||
|
if (error?.contains("robotem") == true || json.getBoolean("captchaRequired") == true) {
|
||||||
|
data.requireUserAction(
|
||||||
|
type = UserActionRequiredEvent.Type.RECAPTCHA,
|
||||||
|
params = Bundle(
|
||||||
|
"siteKey" to LIBRUS_PORTAL_RECAPTCHA_KEY,
|
||||||
|
"referer" to LIBRUS_PORTAL_RECAPTCHA_REFERER,
|
||||||
|
),
|
||||||
|
errorText = R.string.notification_user_action_required_captcha_librus,
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
error?.let { code ->
|
error?.let { code ->
|
||||||
when {
|
when {
|
||||||
code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED
|
code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED
|
||||||
code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
|
code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
|
||||||
// this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set
|
|
||||||
code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL
|
|
||||||
code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
|
code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
|
||||||
else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR
|
else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR
|
||||||
}.let { errorCode ->
|
}.let { errorCode ->
|
||||||
@ -163,12 +175,6 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (json.getBoolean("captchaRequired") == true) {
|
|
||||||
data.error(ApiError(TAG, ERROR_CAPTCHA_LIBRUS_PORTAL)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(json))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL))
|
authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.Mobidzien
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.*
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin.MobidziennikFirstLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin.MobidziennikFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
@ -142,6 +143,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
|||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
return object : EdziennikCallback {
|
return object : EdziennikCallback {
|
||||||
override fun onCompleted() { callback.onCompleted() }
|
override fun onCompleted() { callback.onCompleted() }
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
|
||||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
override fun onProgress(step: Float) { callback.onProgress(step) }
|
||||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieData
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin.PodlasieFirstLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin.PodlasieFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogin
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
@ -142,6 +143,10 @@ class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
callback.onCompleted()
|
callback.onCompleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
|
||||||
|
callback.onRequiresUserAction(event)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onProgress(step: Float) {
|
override fun onProgress(step: Float) {
|
||||||
callback.onProgress(step)
|
callback.onProgress(step)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateData
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.TemplateData
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.firstlogin.TemplateFirstLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.firstlogin.TemplateFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
@ -108,6 +109,10 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
callback.onCompleted()
|
callback.onCompleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
|
||||||
|
callback.onRequiresUserAction(event)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onProgress(step: Float) {
|
override fun onProgress(step: Float) {
|
||||||
callback.onProgress(step)
|
callback.onProgress(step)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
|
||||||
|
class DataUsos(
|
||||||
|
app: App,
|
||||||
|
profile: Profile?,
|
||||||
|
loginStore: LoginStore,
|
||||||
|
) : Data(app, profile, loginStore) {
|
||||||
|
|
||||||
|
fun isApiLoginValid() = oauthTokenKey != null && oauthTokenSecret != null && oauthTokenIsUser
|
||||||
|
|
||||||
|
override fun satisfyLoginMethods() {
|
||||||
|
loginMethods.clear()
|
||||||
|
if (isApiLoginValid()) {
|
||||||
|
loginMethods += LOGIN_METHOD_USOS_API
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateUserCode() = "$schoolId:${profile?.studentNumber ?: studentId}"
|
||||||
|
|
||||||
|
var schoolId: String?
|
||||||
|
get() { mSchoolId = mSchoolId ?: loginStore.getLoginData("schoolId", null); return mSchoolId }
|
||||||
|
set(value) { loginStore.putLoginData("schoolId", value); mSchoolId = value }
|
||||||
|
private var mSchoolId: String? = null
|
||||||
|
|
||||||
|
var instanceUrl: String?
|
||||||
|
get() { mInstanceUrl = mInstanceUrl ?: loginStore.getLoginData("instanceUrl", null); return mInstanceUrl }
|
||||||
|
set(value) { loginStore.putLoginData("instanceUrl", value); mInstanceUrl = value }
|
||||||
|
private var mInstanceUrl: String? = null
|
||||||
|
|
||||||
|
var oauthLoginResponse: String?
|
||||||
|
get() { mOauthLoginResponse = mOauthLoginResponse ?: loginStore.getLoginData("oauthLoginResponse", null); return mOauthLoginResponse }
|
||||||
|
set(value) { loginStore.putLoginData("oauthLoginResponse", value); mOauthLoginResponse = value }
|
||||||
|
private var mOauthLoginResponse: String? = null
|
||||||
|
|
||||||
|
var oauthConsumerKey: String?
|
||||||
|
get() { mOauthConsumerKey = mOauthConsumerKey ?: loginStore.getLoginData("oauthConsumerKey", null); return mOauthConsumerKey }
|
||||||
|
set(value) { loginStore.putLoginData("oauthConsumerKey", value); mOauthConsumerKey = value }
|
||||||
|
private var mOauthConsumerKey: String? = null
|
||||||
|
|
||||||
|
var oauthConsumerSecret: String?
|
||||||
|
get() { mOauthConsumerSecret = mOauthConsumerSecret ?: loginStore.getLoginData("oauthConsumerSecret", null); return mOauthConsumerSecret }
|
||||||
|
set(value) { loginStore.putLoginData("oauthConsumerSecret", value); mOauthConsumerSecret = value }
|
||||||
|
private var mOauthConsumerSecret: String? = null
|
||||||
|
|
||||||
|
var oauthTokenKey: String?
|
||||||
|
get() { mOauthTokenKey = mOauthTokenKey ?: loginStore.getLoginData("oauthTokenKey", null); return mOauthTokenKey }
|
||||||
|
set(value) { loginStore.putLoginData("oauthTokenKey", value); mOauthTokenKey = value }
|
||||||
|
private var mOauthTokenKey: String? = null
|
||||||
|
|
||||||
|
var oauthTokenSecret: String?
|
||||||
|
get() { mOauthTokenSecret = mOauthTokenSecret ?: loginStore.getLoginData("oauthTokenSecret", null); return mOauthTokenSecret }
|
||||||
|
set(value) { loginStore.putLoginData("oauthTokenSecret", value); mOauthTokenSecret = value }
|
||||||
|
private var mOauthTokenSecret: String? = null
|
||||||
|
|
||||||
|
var oauthTokenIsUser: Boolean
|
||||||
|
get() { mOauthTokenIsUser = mOauthTokenIsUser ?: loginStore.getLoginData("oauthTokenIsUser", false); return mOauthTokenIsUser ?: false }
|
||||||
|
set(value) { loginStore.putLoginData("oauthTokenIsUser", value); mOauthTokenIsUser = value }
|
||||||
|
private var mOauthTokenIsUser: Boolean? = null
|
||||||
|
|
||||||
|
var studentId: Int
|
||||||
|
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 }
|
||||||
|
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
||||||
|
private var mStudentId: Int? = null
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosData
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin.UsosFirstLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.usosLoginMethods
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
|
class Usos(
|
||||||
|
val app: App,
|
||||||
|
val profile: Profile?,
|
||||||
|
val loginStore: LoginStore,
|
||||||
|
val callback: EdziennikCallback,
|
||||||
|
) : EdziennikInterface {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "Usos"
|
||||||
|
}
|
||||||
|
|
||||||
|
val internalErrorList = mutableListOf<Int>()
|
||||||
|
val data: DataUsos
|
||||||
|
|
||||||
|
init {
|
||||||
|
data = DataUsos(app, profile, loginStore).apply {
|
||||||
|
callback = wrapCallback(this@Usos.callback)
|
||||||
|
satisfyLoginMethods()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun completed() {
|
||||||
|
data.saveData()
|
||||||
|
callback.onCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun sync(
|
||||||
|
featureIds: List<Int>,
|
||||||
|
viewId: Int?,
|
||||||
|
onlyEndpoints: List<Int>?,
|
||||||
|
arguments: JsonObject?,
|
||||||
|
) {
|
||||||
|
data.arguments = arguments
|
||||||
|
data.prepare(usosLoginMethods, UsosFeatures, featureIds, viewId, onlyEndpoints)
|
||||||
|
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||||
|
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
|
UsosLogin(data) {
|
||||||
|
UsosData(data) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMessage(message: MessageFull) {}
|
||||||
|
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {}
|
||||||
|
override fun markAllAnnouncementsAsRead() {}
|
||||||
|
override fun getAnnouncement(announcement: AnnouncementFull) {}
|
||||||
|
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
|
||||||
|
override fun getRecipientList() {}
|
||||||
|
override fun getEvent(eventFull: EventFull) {}
|
||||||
|
|
||||||
|
override fun firstLogin() {
|
||||||
|
UsosFirstLogin(data) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cancel() {
|
||||||
|
d(TAG, "Cancelled")
|
||||||
|
data.cancel()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
|
return object : EdziennikCallback {
|
||||||
|
override fun onCompleted() {
|
||||||
|
callback.onCompleted()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) {
|
||||||
|
callback.onRequiresUserAction(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProgress(step: Float) {
|
||||||
|
callback.onProgress(step)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onStartProgress(stringRes: Int) {
|
||||||
|
callback.onStartProgress(stringRes)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(apiError: ApiError) {
|
||||||
|
when (apiError.errorCode) {
|
||||||
|
in internalErrorList -> {
|
||||||
|
// finish immediately if the same error occurs twice during the same sync
|
||||||
|
callback.onError(apiError)
|
||||||
|
}
|
||||||
|
else -> callback.onError(apiError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||||
|
|
||||||
|
const val ENDPOINT_USOS_API_USER = 7000
|
||||||
|
const val ENDPOINT_USOS_API_TERMS = 7010
|
||||||
|
const val ENDPOINT_USOS_API_COURSES = 7020
|
||||||
|
const val ENDPOINT_USOS_API_TIMETABLE = 7030
|
||||||
|
|
||||||
|
val UsosFeatures = listOf(
|
||||||
|
/*
|
||||||
|
* Student information
|
||||||
|
*/
|
||||||
|
Feature(LOGIN_TYPE_USOS, FEATURE_STUDENT_INFO, listOf(
|
||||||
|
ENDPOINT_USOS_API_USER to LOGIN_METHOD_USOS_API,
|
||||||
|
), listOf(LOGIN_METHOD_USOS_API)),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Terms & courses
|
||||||
|
*/
|
||||||
|
Feature(LOGIN_TYPE_USOS, FEATURE_SCHOOL_INFO, listOf(
|
||||||
|
ENDPOINT_USOS_API_TERMS to LOGIN_METHOD_USOS_API,
|
||||||
|
), listOf(LOGIN_METHOD_USOS_API)),
|
||||||
|
Feature(LOGIN_TYPE_USOS, FEATURE_TEAM_INFO, listOf(
|
||||||
|
ENDPOINT_USOS_API_COURSES to LOGIN_METHOD_USOS_API,
|
||||||
|
), listOf(LOGIN_METHOD_USOS_API)),
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Timetable
|
||||||
|
*/
|
||||||
|
Feature(LOGIN_TYPE_USOS, FEATURE_TIMETABLE, listOf(
|
||||||
|
ENDPOINT_USOS_API_TIMETABLE to LOGIN_METHOD_USOS_API,
|
||||||
|
), listOf(LOGIN_METHOD_USOS_API)),
|
||||||
|
)
|
@ -0,0 +1,209 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import im.wangchao.mhttp.Request
|
||||||
|
import im.wangchao.mhttp.Response
|
||||||
|
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||||
|
import im.wangchao.mhttp.callback.JsonArrayCallbackHandler
|
||||||
|
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||||
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_MISSING_RESPONSE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.SERVER_USER_AGENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import java.net.HttpURLConnection.*
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
|
open class UsosApi(open val data: DataUsos, open val lastSync: Long?) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UsosApi"
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ResponseType {
|
||||||
|
OBJECT,
|
||||||
|
ARRAY,
|
||||||
|
PLAIN,
|
||||||
|
}
|
||||||
|
|
||||||
|
val profileId
|
||||||
|
get() = data.profile?.id ?: -1
|
||||||
|
|
||||||
|
val profile
|
||||||
|
get() = data.profile
|
||||||
|
|
||||||
|
protected fun JsonObject.getLangString(key: String) =
|
||||||
|
this.getJsonObject(key)?.getString("pl")
|
||||||
|
|
||||||
|
protected fun JsonObject.getLecturerIds(key: String) =
|
||||||
|
this.getJsonArray(key)?.asJsonObjectList()?.mapNotNull {
|
||||||
|
val id = it.getLong("id") ?: return@mapNotNull null
|
||||||
|
val firstName = it.getString("first_name") ?: return@mapNotNull null
|
||||||
|
val lastName = it.getString("last_name") ?: return@mapNotNull null
|
||||||
|
data.getTeacher(firstName, lastName, id = id).id
|
||||||
|
} ?: listOf()
|
||||||
|
|
||||||
|
private fun valueToString(value: Any) = when (value) {
|
||||||
|
is String -> value
|
||||||
|
is Number -> value.toString()
|
||||||
|
is List<*> -> listToString(value)
|
||||||
|
else -> value.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun listToString(list: List<*>): String {
|
||||||
|
return list.map {
|
||||||
|
if (it is Pair<*, *> && it.first is String && it.second is List<*>)
|
||||||
|
return@map "${it.first}[${listToString(it.second as List<*>)}]"
|
||||||
|
return@map valueToString(it ?: "")
|
||||||
|
}.joinToString("|")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildSignature(method: String, url: String, params: Map<String, String>): String {
|
||||||
|
val query = params.toQueryString()
|
||||||
|
val signatureString = listOf(
|
||||||
|
method.uppercase(),
|
||||||
|
url.urlEncode(),
|
||||||
|
query.urlEncode(),
|
||||||
|
).joinToString("&")
|
||||||
|
val signingKey = listOf(
|
||||||
|
data.oauthConsumerSecret ?: "",
|
||||||
|
data.oauthTokenSecret ?: "",
|
||||||
|
).joinToString("&") { it.urlEncode() }
|
||||||
|
return signatureString.hmacSHA1(signingKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T> apiRequest(
|
||||||
|
tag: String,
|
||||||
|
service: String,
|
||||||
|
params: Map<String, Any>? = null,
|
||||||
|
fields: List<Any>? = null,
|
||||||
|
responseType: ResponseType,
|
||||||
|
onSuccess: (data: T, response: Response?) -> Unit,
|
||||||
|
) {
|
||||||
|
val url = "${data.instanceUrl}services/$service"
|
||||||
|
d(tag, "Request: Usos/Api - $url")
|
||||||
|
|
||||||
|
val formData = mutableMapOf<String, String>()
|
||||||
|
if (params != null)
|
||||||
|
formData.putAll(params.mapValues {
|
||||||
|
valueToString(it.value)
|
||||||
|
})
|
||||||
|
if (fields != null)
|
||||||
|
formData["fields"] = valueToString(fields)
|
||||||
|
|
||||||
|
val auth = mutableMapOf(
|
||||||
|
"realm" to url,
|
||||||
|
"oauth_consumer_key" to (data.oauthConsumerKey ?: ""),
|
||||||
|
"oauth_nonce" to UUID.randomUUID().toString(),
|
||||||
|
"oauth_signature_method" to "HMAC-SHA1",
|
||||||
|
"oauth_timestamp" to currentTimeUnix().toString(),
|
||||||
|
"oauth_token" to (data.oauthTokenKey ?: ""),
|
||||||
|
"oauth_version" to "1.0",
|
||||||
|
)
|
||||||
|
val signature = buildSignature(
|
||||||
|
method = "POST",
|
||||||
|
url = url,
|
||||||
|
params = formData + auth.filterKeys { it.startsWith("oauth_") },
|
||||||
|
)
|
||||||
|
auth["oauth_signature"] = signature
|
||||||
|
|
||||||
|
val authString = auth.map {
|
||||||
|
"""${it.key}="${it.value.urlEncode()}""""
|
||||||
|
}.joinToString(", ")
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url(url)
|
||||||
|
.userAgent(SERVER_USER_AGENT)
|
||||||
|
.addHeader("Authorization", "OAuth $authString")
|
||||||
|
.post()
|
||||||
|
.setTextBody(formData.toQueryString(), MediaTypeUtils.APPLICATION_FORM)
|
||||||
|
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||||
|
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HTTP_FORBIDDEN)
|
||||||
|
.allowErrorCode(HTTP_NOT_FOUND)
|
||||||
|
.allowErrorCode(HTTP_UNAVAILABLE)
|
||||||
|
.callback(getCallback(tag, responseType, onSuccess))
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
private fun <T> getCallback(
|
||||||
|
tag: String,
|
||||||
|
responseType: ResponseType,
|
||||||
|
onSuccess: (data: T, response: Response?) -> Unit,
|
||||||
|
) = when (responseType) {
|
||||||
|
ResponseType.OBJECT -> object : JsonCallbackHandler() {
|
||||||
|
override fun onSuccess(data: JsonObject?, response: Response) {
|
||||||
|
processResponse(tag, response, data as T?, onSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
processError(tag, response, throwable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResponseType.ARRAY -> object : JsonArrayCallbackHandler() {
|
||||||
|
override fun onSuccess(data: JsonArray?, response: Response) {
|
||||||
|
processResponse(tag, response, data as T?, onSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
processError(tag, response, throwable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ResponseType.PLAIN -> object : TextCallbackHandler() {
|
||||||
|
override fun onSuccess(data: String?, response: Response) {
|
||||||
|
processResponse(tag, response, data as T?, onSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
processError(tag, response, throwable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T> processResponse(
|
||||||
|
tag: String,
|
||||||
|
response: Response,
|
||||||
|
value: T?,
|
||||||
|
onSuccess: (data: T, response: Response?) -> Unit,
|
||||||
|
) {
|
||||||
|
val errorCode = when {
|
||||||
|
response.code() == HTTP_UNAUTHORIZED -> {
|
||||||
|
data.oauthTokenKey = null
|
||||||
|
data.oauthTokenSecret = null
|
||||||
|
data.oauthTokenIsUser = false
|
||||||
|
data.oauthLoginResponse = null
|
||||||
|
UsosLoginApi(data) { }
|
||||||
|
return
|
||||||
|
}
|
||||||
|
value == null -> ERROR_USOS_API_MISSING_RESPONSE
|
||||||
|
response.code() == HTTP_OK -> {
|
||||||
|
onSuccess(value, response)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
else -> response.toErrorCode()
|
||||||
|
}
|
||||||
|
if (errorCode != null) {
|
||||||
|
data.error(tag, errorCode, response, value.toString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processError(
|
||||||
|
tag: String,
|
||||||
|
response: Response?,
|
||||||
|
throwable: Throwable?,
|
||||||
|
) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-13.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.data.web.TemplateWebSample
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiCourses
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTerms
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiTimetable
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api.UsosApiUser
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
|
class UsosData(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UsosData"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
nextEndpoint(onSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||||
|
if (data.targetEndpointIds.isEmpty()) {
|
||||||
|
onSuccess()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (data.cancelled) {
|
||||||
|
onSuccess()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val id = data.targetEndpointIds.firstKey()
|
||||||
|
val lastSync = data.targetEndpointIds.remove(id)
|
||||||
|
useEndpoint(id, lastSync) { endpointId ->
|
||||||
|
data.progress(data.progressStep)
|
||||||
|
nextEndpoint(onSuccess)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
||||||
|
d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
||||||
|
when (endpointId) {
|
||||||
|
ENDPOINT_USOS_API_USER -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||||
|
UsosApiUser(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_USOS_API_TERMS -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_school_info)
|
||||||
|
UsosApiTerms(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_USOS_API_COURSES -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_teams)
|
||||||
|
UsosApiCourses(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_USOS_API_TIMETABLE -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||||
|
UsosApiTimetable(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
else -> onSuccess(endpointId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_COURSES
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
|
||||||
|
class UsosApiCourses(
|
||||||
|
override val data: DataUsos,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit,
|
||||||
|
) : UsosApi(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "UsosApiCourses"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiRequest<JsonObject>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "courses/user",
|
||||||
|
fields = listOf(
|
||||||
|
// "terms" to listOf("id", "name", "start_date", "end_date"),
|
||||||
|
"course_editions" to listOf(
|
||||||
|
"course_id",
|
||||||
|
"course_name",
|
||||||
|
// "term_id",
|
||||||
|
"user_groups" to listOf(
|
||||||
|
"course_unit_id",
|
||||||
|
"group_number",
|
||||||
|
// "class_type",
|
||||||
|
"class_type_id",
|
||||||
|
"lecturers",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
responseType = ResponseType.OBJECT,
|
||||||
|
) { json, response ->
|
||||||
|
if (!processResponse(json)) {
|
||||||
|
data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response)
|
||||||
|
return@apiRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_USOS_API_COURSES, 2 * DAY)
|
||||||
|
onSuccess(ENDPOINT_USOS_API_COURSES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processResponse(json: JsonObject): Boolean {
|
||||||
|
// val term = json.getJsonArray("terms")?.firstOrNull() ?: return false
|
||||||
|
val courseEditions = json.getJsonObject("course_editions")
|
||||||
|
?.entrySet()
|
||||||
|
?.flatMap { it.value.asJsonArray }
|
||||||
|
?.map { it.asJsonObject } ?: return false
|
||||||
|
|
||||||
|
var hasValidTeam = false
|
||||||
|
for (courseEdition in courseEditions) {
|
||||||
|
val courseId = courseEdition.getString("course_id") ?: continue
|
||||||
|
val courseName = courseEdition.getLangString("course_name") ?: continue
|
||||||
|
val userGroups = courseEdition.getJsonArray("user_groups")?.asJsonObjectList() ?: continue
|
||||||
|
for (userGroup in userGroups) {
|
||||||
|
val courseUnitId = userGroup.getLong("course_unit_id") ?: continue
|
||||||
|
val groupNumber = userGroup.getInt("group_number") ?: continue
|
||||||
|
// val classType = userGroup.getLangString("class_type") ?: continue
|
||||||
|
val classTypeId = userGroup.getString("class_type_id") ?: continue
|
||||||
|
val lecturers = userGroup.getLecturerIds("lecturers")
|
||||||
|
|
||||||
|
data.teamList.put(courseUnitId, Team(
|
||||||
|
profileId,
|
||||||
|
courseUnitId,
|
||||||
|
"${profile?.studentClassName} $classTypeId$groupNumber - $courseName",
|
||||||
|
2,
|
||||||
|
"${data.schoolId}:${courseId} $classTypeId$groupNumber",
|
||||||
|
lecturers.firstOrNull() ?: -1L,
|
||||||
|
))
|
||||||
|
hasValidTeam = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hasValidTeam
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TERMS
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class UsosApiTerms(
|
||||||
|
override val data: DataUsos,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit,
|
||||||
|
) : UsosApi(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "UsosApiTerms"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiRequest<JsonArray>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "terms/search",
|
||||||
|
params = mapOf(
|
||||||
|
"query" to Date.getToday().year.toString(),
|
||||||
|
),
|
||||||
|
responseType = ResponseType.ARRAY,
|
||||||
|
) { json, response ->
|
||||||
|
if (!processResponse(json)) {
|
||||||
|
data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response)
|
||||||
|
return@apiRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_USOS_API_TERMS, 7 * DAY)
|
||||||
|
onSuccess(ENDPOINT_USOS_API_TERMS)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processResponse(json: JsonArray): Boolean {
|
||||||
|
val dates = mutableSetOf<Date>()
|
||||||
|
for (term in json.asJsonObjectList()) {
|
||||||
|
if (!term.getBoolean("is_active", false))
|
||||||
|
continue
|
||||||
|
val startDate = term.getString("start_date")?.let { Date.fromY_m_d(it) }
|
||||||
|
val finishDate = term.getString("finish_date")?.let { Date.fromY_m_d(it) }
|
||||||
|
if (startDate != null)
|
||||||
|
dates += startDate
|
||||||
|
if (finishDate != null)
|
||||||
|
dates += finishDate
|
||||||
|
}
|
||||||
|
val datesSorted = dates.sorted()
|
||||||
|
if (datesSorted.size != 3)
|
||||||
|
return false
|
||||||
|
profile?.studentSchoolYearStart = datesSorted[0].year
|
||||||
|
profile?.dateSemester1Start = datesSorted[0]
|
||||||
|
profile?.dateSemester2Start = datesSorted[1]
|
||||||
|
profile?.dateYearEnd = datesSorted[2]
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_API_INCOMPLETE_RESPONSE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_TIMETABLE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
|
class UsosApiTimetable(
|
||||||
|
override val data: DataUsos,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit,
|
||||||
|
) : UsosApi(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "UsosApiTimetable"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val currentWeekStart = Week.getWeekStart()
|
||||||
|
if (Date.getToday().weekDay > 4)
|
||||||
|
currentWeekStart.stepForward(0, 0, 7)
|
||||||
|
|
||||||
|
val weekStart = data.arguments
|
||||||
|
?.getString("weekStart")
|
||||||
|
?.let { Date.fromY_m_d(it) }
|
||||||
|
?: currentWeekStart
|
||||||
|
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||||
|
|
||||||
|
apiRequest<JsonArray>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "tt/user",
|
||||||
|
params = mapOf(
|
||||||
|
"start" to weekStart.stringY_m_d,
|
||||||
|
"days" to 7,
|
||||||
|
),
|
||||||
|
fields = listOf(
|
||||||
|
"type",
|
||||||
|
"start_time",
|
||||||
|
"end_time",
|
||||||
|
"unit_id",
|
||||||
|
"course_id",
|
||||||
|
"course_name",
|
||||||
|
"lecturer_ids",
|
||||||
|
"building_id",
|
||||||
|
"room_number",
|
||||||
|
"classtype_id",
|
||||||
|
"group_number",
|
||||||
|
),
|
||||||
|
responseType = ResponseType.ARRAY,
|
||||||
|
) { json, response ->
|
||||||
|
if (!processResponse(json, weekStart..weekEnd)) {
|
||||||
|
data.error(TAG, ERROR_USOS_API_INCOMPLETE_RESPONSE, response)
|
||||||
|
return@apiRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
data.setSyncNext(ENDPOINT_USOS_API_TIMETABLE, SYNC_ALWAYS)
|
||||||
|
onSuccess(ENDPOINT_USOS_API_TIMETABLE)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun processResponse(json: JsonArray, syncRange: ClosedRange<Date>): Boolean {
|
||||||
|
val foundDates = mutableSetOf<Date>()
|
||||||
|
|
||||||
|
for (activity in json.asJsonObjectList()) {
|
||||||
|
val type = activity.getString("type")
|
||||||
|
if (type !in listOf("classgroup", "classgroup2"))
|
||||||
|
continue
|
||||||
|
|
||||||
|
val startTime = activity.getString("start_time") ?: continue
|
||||||
|
val endTime = activity.getString("end_time") ?: continue
|
||||||
|
val unitId = activity.getLong("unit_id", -1)
|
||||||
|
val courseName = activity.getLangString("course_name") ?: continue
|
||||||
|
val courseId = activity.getString("course_id") ?: continue
|
||||||
|
val lecturerIds = activity.getJsonArray("lecturer_ids")?.map { it.asLong }
|
||||||
|
val buildingId = activity.getString("building_id")
|
||||||
|
val roomNumber = activity.getString("room_number")
|
||||||
|
val classTypeId = activity.getString("classtype_id")
|
||||||
|
val groupNumber = activity.getString("group_number")
|
||||||
|
|
||||||
|
val lesson = Lesson(profileId, -1).also {
|
||||||
|
it.type = Lesson.TYPE_NORMAL
|
||||||
|
it.date = Date.fromY_m_d(startTime)
|
||||||
|
it.startTime = Time.fromY_m_d_H_m_s(startTime)
|
||||||
|
it.endTime = Time.fromY_m_d_H_m_s(endTime)
|
||||||
|
it.subjectId = data.getSubject(
|
||||||
|
id = null,
|
||||||
|
name = courseName,
|
||||||
|
shortName = courseId,
|
||||||
|
).id
|
||||||
|
it.teacherId = lecturerIds?.firstOrNull() ?: -1L
|
||||||
|
it.teamId = unitId
|
||||||
|
val groupName = classTypeId?.plus(groupNumber)?.let { s -> "($s)" }
|
||||||
|
it.classroom = "$buildingId / $roomNumber ${groupName ?: ""}"
|
||||||
|
it.id = it.buildId()
|
||||||
|
|
||||||
|
it.color = when (classTypeId) {
|
||||||
|
"WYK" -> 0xff0d6091
|
||||||
|
"CW" -> 0xff54306e
|
||||||
|
"LAB" -> 0xff772747
|
||||||
|
"KON" -> 0xff1e5128
|
||||||
|
"^P?SEM" -> 0xff1e5128 // TODO make it regex
|
||||||
|
else -> 0xff08534c
|
||||||
|
}.toInt()
|
||||||
|
}
|
||||||
|
lesson.date?.let { foundDates += it }
|
||||||
|
|
||||||
|
val seen = profile?.empty != false || lesson.date!! < Date.getToday()
|
||||||
|
data.lessonList.add(lesson)
|
||||||
|
if (lesson.type != Lesson.TYPE_NORMAL)
|
||||||
|
data.metadataList += Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_LESSON_CHANGE,
|
||||||
|
lesson.id,
|
||||||
|
seen,
|
||||||
|
seen,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
val notFoundDates = syncRange.asSequence() - foundDates
|
||||||
|
for (date in notFoundDates) {
|
||||||
|
data.lessonList += Lesson(profileId, date.value.toLong()).also {
|
||||||
|
it.type = Lesson.TYPE_NO_LESSONS
|
||||||
|
it.date = date
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.ENDPOINT_USOS_API_USER
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
|
||||||
|
class UsosApiUser(
|
||||||
|
override val data: DataUsos,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit,
|
||||||
|
) : UsosApi(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "UsosApiUser"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiRequest<JsonObject>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "users/user",
|
||||||
|
params = mapOf(
|
||||||
|
"fields" to listOf(
|
||||||
|
"id",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"student_number",
|
||||||
|
"student_programmes" to listOf(
|
||||||
|
"programme" to listOf("id"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
responseType = ResponseType.OBJECT,
|
||||||
|
) { json, response ->
|
||||||
|
val programmes = json.getJsonArray("student_programmes")
|
||||||
|
if (programmes.isNullOrEmpty()) {
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_NO_STUDENT_PROGRAMMES)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return@apiRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
val firstName = json.getString("first_name")
|
||||||
|
val lastName = json.getString("last_name")
|
||||||
|
val studentName = buildFullName(firstName, lastName)
|
||||||
|
|
||||||
|
data.studentId = json.getInt("id") ?: data.studentId
|
||||||
|
profile?.studentNameLong = studentName
|
||||||
|
profile?.studentNameShort = studentName.getShortName()
|
||||||
|
profile?.studentNumber = json.getInt("student_number", -1)
|
||||||
|
profile?.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id")
|
||||||
|
|
||||||
|
profile?.studentClassName?.let {
|
||||||
|
data.getTeam(
|
||||||
|
id = null,
|
||||||
|
name = it,
|
||||||
|
schoolCode = data.schoolId ?: "",
|
||||||
|
isTeamClass = true,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_USOS_API_USER, 4 * DAY)
|
||||||
|
onSuccess(ENDPOINT_USOS_API_USER)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-14.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.firstlogin
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_USOS_NO_STUDENT_PROGRAMMES
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_USOS
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.login.UsosLoginApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
|
||||||
|
class UsosFirstLogin(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UsosFirstLogin"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val api = UsosApi(data, null)
|
||||||
|
|
||||||
|
init {
|
||||||
|
val loginStoreId = data.loginStore.id
|
||||||
|
val loginStoreType = LOGIN_TYPE_USOS
|
||||||
|
var firstProfileId = loginStoreId
|
||||||
|
|
||||||
|
UsosLoginApi(data) {
|
||||||
|
api.apiRequest<JsonObject>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "users/user",
|
||||||
|
params = mapOf(
|
||||||
|
"fields" to listOf(
|
||||||
|
"id",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"student_number",
|
||||||
|
"student_programmes" to listOf(
|
||||||
|
"programme" to listOf("id"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
responseType = UsosApi.ResponseType.OBJECT,
|
||||||
|
) { json, response ->
|
||||||
|
val programmes = json.getJsonArray("student_programmes")
|
||||||
|
if (programmes.isNullOrEmpty()) {
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_NO_STUDENT_PROGRAMMES)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return@apiRequest
|
||||||
|
}
|
||||||
|
|
||||||
|
val firstName = json.getString("first_name")
|
||||||
|
val lastName = json.getString("last_name")
|
||||||
|
val studentName = buildFullName(firstName, lastName)
|
||||||
|
|
||||||
|
val profile = Profile(
|
||||||
|
id = firstProfileId++,
|
||||||
|
loginStoreId = loginStoreId, loginStoreType = loginStoreType,
|
||||||
|
name = studentName,
|
||||||
|
subname = data.schoolId,
|
||||||
|
studentNameLong = studentName,
|
||||||
|
studentNameShort = studentName.getShortName(),
|
||||||
|
accountName = null, // student account
|
||||||
|
studentData = JsonObject(
|
||||||
|
"studentId" to json.getInt("id"),
|
||||||
|
),
|
||||||
|
).also {
|
||||||
|
it.studentNumber = json.getInt("student_number", -1)
|
||||||
|
it.studentClassName = programmes.getJsonObject(0).getJsonObject("programme").getString("id")
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(
|
||||||
|
FirstLoginFinishedEvent(listOf(profile), data.loginStore),
|
||||||
|
)
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
* Copyright (c) Kuba Szczodrzyński 2022-10-11.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_USOS_API
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
class EdudziennikLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
class UsosLogin(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "EdudziennikLogin"
|
private const val TAG = "UsosLogin"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cancelled = false
|
private var cancelled = false
|
||||||
@ -43,11 +43,11 @@ class EdudziennikLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
|||||||
onSuccess(-1)
|
onSuccess(-1)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Utils.d(TAG, "Using login method $loginMethodId")
|
d(TAG, "Using login method $loginMethodId")
|
||||||
when (loginMethodId) {
|
when (loginMethodId) {
|
||||||
LOGIN_METHOD_EDUDZIENNIK_WEB -> {
|
LOGIN_METHOD_USOS_API -> {
|
||||||
data.startProgress(R.string.edziennik_progress_login_edudziennik_web)
|
data.startProgress(R.string.edziennik_progress_login_usos_api)
|
||||||
EdudziennikLoginWeb(data) { onSuccess(loginMethodId) }
|
UsosLoginApi(data) { onSuccess(loginMethodId) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-11.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.usos.login
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.DataUsos
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.usos.data.UsosApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
|
class UsosLoginApi(val data: DataUsos, val onSuccess: () -> Unit) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "UsosLoginApi"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val api = UsosApi(data, null)
|
||||||
|
|
||||||
|
init {
|
||||||
|
run {
|
||||||
|
data.arguments?.getString("oauthLoginResponse")?.let {
|
||||||
|
data.oauthLoginResponse = it
|
||||||
|
}
|
||||||
|
if (data.isApiLoginValid()) {
|
||||||
|
onSuccess()
|
||||||
|
} else if (data.oauthLoginResponse != null) {
|
||||||
|
login()
|
||||||
|
} else {
|
||||||
|
authorize()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun authorize() {
|
||||||
|
data.oauthTokenKey = null
|
||||||
|
data.oauthTokenSecret = null
|
||||||
|
api.apiRequest<String>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "oauth/request_token",
|
||||||
|
params = mapOf(
|
||||||
|
"oauth_callback" to USOS_API_OAUTH_REDIRECT_URL,
|
||||||
|
"scopes" to USOS_API_SCOPES,
|
||||||
|
),
|
||||||
|
responseType = UsosApi.ResponseType.PLAIN,
|
||||||
|
) { text, _ ->
|
||||||
|
val authorizeData = text.fromQueryString()
|
||||||
|
data.oauthTokenKey = authorizeData["oauth_token"]
|
||||||
|
data.oauthTokenSecret = authorizeData["oauth_token_secret"]
|
||||||
|
data.oauthTokenIsUser = false
|
||||||
|
|
||||||
|
val authUrl = "${data.instanceUrl}services/oauth/authorize"
|
||||||
|
val authParams = mapOf(
|
||||||
|
"interactivity" to "confirm_user",
|
||||||
|
"oauth_token" to (data.oauthTokenKey ?: ""),
|
||||||
|
)
|
||||||
|
data.requireUserAction(
|
||||||
|
type = UserActionRequiredEvent.Type.OAUTH,
|
||||||
|
params = Bundle(
|
||||||
|
"authorizeUrl" to "$authUrl?${authParams.toQueryString()}",
|
||||||
|
"redirectUrl" to USOS_API_OAUTH_REDIRECT_URL,
|
||||||
|
"responseStoreKey" to "oauthLoginResponse",
|
||||||
|
"extras" to data.loginStore.data.toBundle(),
|
||||||
|
),
|
||||||
|
errorText = R.string.notification_user_action_required_oauth_usos,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun login() {
|
||||||
|
d(TAG, "Login to ${data.schoolId} with ${data.oauthLoginResponse}")
|
||||||
|
|
||||||
|
val authorizeResponse = data.oauthLoginResponse?.fromQueryString()
|
||||||
|
?: return // checked in init {}
|
||||||
|
if (authorizeResponse["oauth_token"] != data.oauthTokenKey) {
|
||||||
|
// got different token
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_OAUTH_GOT_DIFFERENT_TOKEN)
|
||||||
|
.withApiResponse(data.oauthLoginResponse))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
val verifier = authorizeResponse["oauth_verifier"]
|
||||||
|
if (verifier.isNullOrBlank()) {
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE)
|
||||||
|
.withApiResponse(data.oauthLoginResponse))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.apiRequest<String>(
|
||||||
|
tag = TAG,
|
||||||
|
service = "oauth/access_token",
|
||||||
|
params = mapOf(
|
||||||
|
"oauth_verifier" to verifier,
|
||||||
|
),
|
||||||
|
responseType = UsosApi.ResponseType.PLAIN,
|
||||||
|
) { text, response ->
|
||||||
|
val accessData = text.fromQueryString()
|
||||||
|
data.oauthTokenKey = accessData["oauth_token"]
|
||||||
|
data.oauthTokenSecret = accessData["oauth_token_secret"]
|
||||||
|
data.oauthTokenIsUser = data.oauthTokenKey != null && data.oauthTokenSecret != null
|
||||||
|
data.loginStore.removeLoginData("oauthLoginResponse")
|
||||||
|
|
||||||
|
if (!data.oauthTokenIsUser)
|
||||||
|
data.error(ApiError(TAG, ERROR_USOS_OAUTH_INCOMPLETE_RESPONSE)
|
||||||
|
.withApiResponse(text)
|
||||||
|
.withResponse(response))
|
||||||
|
else
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -222,15 +222,15 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext }
|
get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext }
|
||||||
set(value) { profile?.putStudentData("hebeContext", value) ?: return; mHebeContext = value }
|
set(value) { profile?.putStudentData("hebeContext", value) ?: return; mHebeContext = value }
|
||||||
|
|
||||||
private var mSenderAddressHash: String? = null
|
private var mMessageBoxKey: String? = null
|
||||||
var senderAddressHash: String?
|
var messageBoxKey: String?
|
||||||
get() { mSenderAddressHash = mSenderAddressHash ?: profile?.getStudentData("senderAddressHash", null); return mSenderAddressHash }
|
get() { mMessageBoxKey = mMessageBoxKey ?: profile?.getStudentData("messageBoxKey", null); return mMessageBoxKey }
|
||||||
set(value) { profile?.putStudentData("senderAddressHash", value) ?: return; mSenderAddressHash = value }
|
set(value) { profile?.putStudentData("messageBoxKey", value) ?: return; mMessageBoxKey = value }
|
||||||
|
|
||||||
private var mSenderAddressName: String? = null
|
private var mMessageBoxName: String? = null
|
||||||
var senderAddressName: String?
|
var messageBoxName: String?
|
||||||
get() { mSenderAddressName = mSenderAddressName ?: profile?.getStudentData("senderAddressName", null); return mSenderAddressName }
|
get() { mMessageBoxName = mMessageBoxName ?: profile?.getStudentData("messageBoxName", null); return mMessageBoxName }
|
||||||
set(value) { profile?.putStudentData("senderAddressName", value) ?: return; mSenderAddressName = value }
|
set(value) { profile?.putStudentData("messageBoxName", value) ?: return; mMessageBoxName = value }
|
||||||
|
|
||||||
val apiUrl: String?
|
val apiUrl: String?
|
||||||
get() {
|
get() {
|
||||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin
|
|||||||
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
@ -179,6 +180,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
return object : EdziennikCallback {
|
return object : EdziennikCallback {
|
||||||
override fun onCompleted() { callback.onCompleted() }
|
override fun onCompleted() { callback.onCompleted() }
|
||||||
|
override fun onRequiresUserAction(event: UserActionRequiredEvent) { callback.onRequiresUserAction(event) }
|
||||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
override fun onProgress(step: Float) { callback.onProgress(step) }
|
||||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
||||||
override fun onError(apiError: ApiError) {
|
override fun onError(apiError: ApiError) {
|
||||||
|
@ -12,6 +12,7 @@ const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010
|
|||||||
const val ENDPOINT_VULCAN_HEBE_MAIN = 3000
|
const val ENDPOINT_VULCAN_HEBE_MAIN = 3000
|
||||||
const val ENDPOINT_VULCAN_HEBE_PUSH_CONFIG = 3005
|
const val ENDPOINT_VULCAN_HEBE_PUSH_CONFIG = 3005
|
||||||
const val ENDPOINT_VULCAN_HEBE_ADDRESSBOOK = 3010
|
const val ENDPOINT_VULCAN_HEBE_ADDRESSBOOK = 3010
|
||||||
|
const val ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2 = 3501 // after message boxes (3500)
|
||||||
const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020
|
const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020
|
||||||
const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030
|
const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030
|
||||||
const val ENDPOINT_VULCAN_HEBE_GRADES = 3040
|
const val ENDPOINT_VULCAN_HEBE_GRADES = 3040
|
||||||
@ -19,10 +20,11 @@ const val ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY = 3050
|
|||||||
const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060
|
const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060
|
||||||
const val ENDPOINT_VULCAN_HEBE_NOTICES = 3070
|
const val ENDPOINT_VULCAN_HEBE_NOTICES = 3070
|
||||||
const val ENDPOINT_VULCAN_HEBE_ATTENDANCE = 3080
|
const val ENDPOINT_VULCAN_HEBE_ATTENDANCE = 3080
|
||||||
const val ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX = 3090
|
|
||||||
const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3100
|
|
||||||
const val ENDPOINT_VULCAN_HEBE_TEACHERS = 3110
|
const val ENDPOINT_VULCAN_HEBE_TEACHERS = 3110
|
||||||
const val ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER = 3200
|
const val ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER = 3200
|
||||||
|
const val ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES = 3500
|
||||||
|
const val ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX = 3510
|
||||||
|
const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3520
|
||||||
|
|
||||||
val VulcanFeatures = listOf(
|
val VulcanFeatures = listOf(
|
||||||
// timetable
|
// timetable
|
||||||
@ -85,6 +87,8 @@ val VulcanFeatures = listOf(
|
|||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
|
||||||
ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE,
|
ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE,
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
ENDPOINT_VULCAN_HEBE_TEACHERS to LOGIN_METHOD_VULCAN_HEBE
|
ENDPOINT_VULCAN_HEBE_TEACHERS to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
|
ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2 to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
), listOf(LOGIN_METHOD_VULCAN_HEBE))
|
), listOf(LOGIN_METHOD_VULCAN_HEBE))
|
||||||
)
|
)
|
||||||
|
@ -21,10 +21,12 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
ENDPOINT_VULCAN_HEBE_MAIN,
|
ENDPOINT_VULCAN_HEBE_MAIN,
|
||||||
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG,
|
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG,
|
||||||
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK,
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK,
|
||||||
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2,
|
||||||
ENDPOINT_VULCAN_HEBE_TIMETABLE,
|
ENDPOINT_VULCAN_HEBE_TIMETABLE,
|
||||||
ENDPOINT_VULCAN_HEBE_EXAMS,
|
ENDPOINT_VULCAN_HEBE_EXAMS,
|
||||||
ENDPOINT_VULCAN_HEBE_HOMEWORK,
|
ENDPOINT_VULCAN_HEBE_HOMEWORK,
|
||||||
ENDPOINT_VULCAN_HEBE_NOTICES,
|
ENDPOINT_VULCAN_HEBE_NOTICES,
|
||||||
|
ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES,
|
||||||
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX,
|
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX,
|
||||||
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT,
|
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT,
|
||||||
ENDPOINT_VULCAN_HEBE_TEACHERS,
|
ENDPOINT_VULCAN_HEBE_TEACHERS,
|
||||||
@ -107,6 +109,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_addressbook)
|
data.startProgress(R.string.edziennik_progress_endpoint_addressbook)
|
||||||
VulcanHebeAddressbook(data, lastSync, onSuccess)
|
VulcanHebeAddressbook(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2 -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_addressbook)
|
||||||
|
VulcanHebeAddressbook2(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
ENDPOINT_VULCAN_HEBE_TEACHERS -> {
|
ENDPOINT_VULCAN_HEBE_TEACHERS -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||||
VulcanHebeTeachers(data, lastSync, onSuccess)
|
VulcanHebeTeachers(data, lastSync, onSuccess)
|
||||||
@ -139,6 +145,10 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||||
VulcanHebeAttendance(data, lastSync, onSuccess)
|
VulcanHebeAttendance(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_messages)
|
||||||
|
VulcanHebeMessageBoxes(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX -> {
|
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_RECEIVED)
|
VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_RECEIVED)
|
||||||
|
@ -14,7 +14,6 @@ import im.wangchao.mhttp.Response
|
|||||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||||
import io.github.wulkanowy.signer.hebe.getSignatureHeaders
|
import io.github.wulkanowy.signer.hebe.getSignatureHeaders
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilterType
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.HebeFilterType
|
||||||
@ -55,6 +54,15 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
return date.getLong("Timestamp") ?: return default
|
return date.getLong("Timestamp") ?: return default
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun buildDateTime(): JsonObject {
|
||||||
|
return JsonObject(
|
||||||
|
"Timestamp" to System.currentTimeMillis(),
|
||||||
|
"Date" to Date.getToday().stringY_m_d,
|
||||||
|
"DateDisplay" to Date.getToday().stringDmy,
|
||||||
|
"Time" to Time.getNow().stringHMS,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun getDate(json: JsonObject?, key: String): Date? {
|
fun getDate(json: JsonObject?, key: String): Date? {
|
||||||
val date = json.getJsonObject(key)
|
val date = json.getJsonObject(key)
|
||||||
return date.getString("Date")?.let { Date.fromY_m_d(it) }
|
return date.getString("Date")?.let { Date.fromY_m_d(it) }
|
||||||
@ -74,6 +82,22 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
return teacherId
|
return teacherId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getTeacherRecipient(json: JsonObject): Teacher? {
|
||||||
|
val globalKey = json.getString("GlobalKey") ?: return null
|
||||||
|
if (globalKey == data.messageBoxKey)
|
||||||
|
return null
|
||||||
|
var name = json.getString("Name") ?: return null
|
||||||
|
val group = json.getString("Group", "P")
|
||||||
|
val loginId = "${globalKey};${group};${name}"
|
||||||
|
val pattern = " - $group - (${data.schoolShort})"
|
||||||
|
if (name.endsWith(pattern))
|
||||||
|
name = name.substringBefore(pattern)
|
||||||
|
val teacher = data.getTeacherByFirstLast(name, loginId)
|
||||||
|
if (teacher.type == 0)
|
||||||
|
teacher.type = Teacher.TYPE_OTHER
|
||||||
|
return teacher
|
||||||
|
}
|
||||||
|
|
||||||
fun getSubjectId(json: JsonObject?, key: String): Long? {
|
fun getSubjectId(json: JsonObject?, key: String): Long? {
|
||||||
val subject = json.getJsonObject(key)
|
val subject = json.getJsonObject(key)
|
||||||
val subjectId = subject.getLong("Id") ?: return null
|
val subjectId = subject.getLong("Id") ?: return null
|
||||||
@ -89,7 +113,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getTeamId(json: JsonObject?, key: String): Long? {
|
fun getTeamId(json: JsonObject?, key: String): Long? {
|
||||||
val team = json.getJsonObject(key)
|
val team = json.getJsonObject(key) ?: return null
|
||||||
val teamId = team.getLong("Id")
|
val teamId = team.getLong("Id")
|
||||||
var teamName = team.getString("Shortcut")
|
var teamName = team.getString("Shortcut")
|
||||||
?: team.getString("Name")
|
?: team.getString("Name")
|
||||||
@ -104,7 +128,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getClassId(json: JsonObject?, key: String): Long? {
|
fun getClassId(json: JsonObject?, key: String): Long? {
|
||||||
val team = json.getJsonObject(key)
|
val team = json.getJsonObject(key) ?: return null
|
||||||
val teamId = team.getLong("Id")
|
val teamId = team.getLong("Id")
|
||||||
val teamName = data.profile?.studentClassName
|
val teamName = data.profile?.studentClassName
|
||||||
?: team.getString("Name")
|
?: team.getString("Name")
|
||||||
@ -148,7 +172,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
|
|
||||||
fun isCurrentYear(dateTime: Long): Boolean {
|
fun isCurrentYear(dateTime: Long): Boolean {
|
||||||
return profile?.let { profile ->
|
return profile?.let { profile ->
|
||||||
return@let dateTime >= profile.dateSemester1Start.inMillis
|
return@let dateTime >= profile.dateSemester1Start.inMillis - WEEK * MS
|
||||||
} ?: false
|
} ?: false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -355,6 +379,7 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
dateTo: Date? = null,
|
dateTo: Date? = null,
|
||||||
lastSync: Long? = null,
|
lastSync: Long? = null,
|
||||||
folder: Int? = null,
|
folder: Int? = null,
|
||||||
|
messageBox: String? = null,
|
||||||
params: Map<String, String> = mapOf(),
|
params: Map<String, String> = mapOf(),
|
||||||
includeFilterType: Boolean = true,
|
includeFilterType: Boolean = true,
|
||||||
onSuccess: (data: List<JsonObject>, response: Response?) -> Unit
|
onSuccess: (data: List<JsonObject>, response: Response?) -> Unit
|
||||||
@ -378,6 +403,9 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
|||||||
query["periodId"] = data.studentSemesterId.toString()
|
query["periodId"] = data.studentSemesterId.toString()
|
||||||
query["pupilId"] = data.studentId.toString()
|
query["pupilId"] = data.studentId.toString()
|
||||||
}
|
}
|
||||||
|
HebeFilterType.BY_MESSAGEBOX -> {
|
||||||
|
query["box"] = messageBox ?: data.messageBoxKey ?: ""
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dateFrom != null)
|
if (dateFrom != null)
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
enum class HebeFilterType(val endpoint: String) {
|
enum class HebeFilterType(val endpoint: String) {
|
||||||
|
BY_MESSAGEBOX("byBox"),
|
||||||
BY_PUPIL("byPupil"),
|
BY_PUPIL("byPupil"),
|
||||||
BY_PERSON("byPerson"),
|
BY_PERSON("byPerson"),
|
||||||
BY_PERIOD("byPeriod")
|
BY_PERIOD("byPeriod")
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
import androidx.core.util.set
|
import androidx.core.util.set
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ADDRESSBOOK
|
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ADDRESSBOOK
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
@ -44,7 +45,6 @@ class VulcanHebeAddressbook(
|
|||||||
) { list, _ ->
|
) { list, _ ->
|
||||||
list.forEach { person ->
|
list.forEach { person ->
|
||||||
val id = person.getString("Id") ?: return@forEach
|
val id = person.getString("Id") ?: return@forEach
|
||||||
val loginId = person.getString("LoginId") ?: return@forEach
|
|
||||||
|
|
||||||
val idType = id.split("-")
|
val idType = id.split("-")
|
||||||
.getOrNull(0)
|
.getOrNull(0)
|
||||||
@ -69,7 +69,7 @@ class VulcanHebeAddressbook(
|
|||||||
idLong,
|
idLong,
|
||||||
name,
|
name,
|
||||||
surname,
|
surname,
|
||||||
loginId
|
null
|
||||||
).also {
|
).also {
|
||||||
data.teacherList[idLong] = it
|
data.teacherList[idLong] = it
|
||||||
}
|
}
|
||||||
@ -108,13 +108,14 @@ class VulcanHebeAddressbook(
|
|||||||
}
|
}
|
||||||
|
|
||||||
teacher.setTeacherType(personType)
|
teacher.setTeacherType(personType)
|
||||||
teacher.typeDescription = roleText
|
if (roleText != null)
|
||||||
|
teacher.typeDescription = roleText
|
||||||
}
|
}
|
||||||
|
|
||||||
if (teacher.type == 0)
|
if (teacher.type == 0)
|
||||||
teacher.setTeacherType(typeBase)
|
teacher.setTeacherType(typeBase)
|
||||||
}
|
}
|
||||||
|
data.teacherOnConflictStrategy = OnConflictStrategy.REPLACE
|
||||||
data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK, 2 * DAY)
|
data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK, 2 * DAY)
|
||||||
onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK)
|
onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
|
import androidx.room.OnConflictStrategy
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGEBOX_ADDRESSBOOK
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_OTHER
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_PARENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_STUDENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_TEACHER
|
||||||
|
import pl.szczodrzynski.edziennik.ext.DAY
|
||||||
|
import pl.szczodrzynski.edziennik.ext.MINUTE
|
||||||
|
import pl.szczodrzynski.edziennik.ext.getString
|
||||||
|
|
||||||
|
class VulcanHebeAddressbook2(
|
||||||
|
override val data: DataVulcan,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit
|
||||||
|
) : VulcanHebe(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanHebeAddressbook2"
|
||||||
|
}
|
||||||
|
|
||||||
|
init { let {
|
||||||
|
if (data.messageBoxKey == null) {
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2, 30 * MINUTE)
|
||||||
|
onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2)
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
|
||||||
|
apiGetList(
|
||||||
|
TAG,
|
||||||
|
VULCAN_HEBE_ENDPOINT_MESSAGEBOX_ADDRESSBOOK,
|
||||||
|
HebeFilterType.BY_MESSAGEBOX,
|
||||||
|
messageBox = data.messageBoxKey,
|
||||||
|
lastSync = lastSync,
|
||||||
|
includeFilterType = false
|
||||||
|
) { list, _ ->
|
||||||
|
list.forEach { person ->
|
||||||
|
val teacher = getTeacherRecipient(person) ?: return@forEach
|
||||||
|
val group = person.getString("Group", "P")
|
||||||
|
if (teacher.type == TYPE_OTHER) {
|
||||||
|
teacher.type = when (group) {
|
||||||
|
"P" -> TYPE_TEACHER // Pracownik
|
||||||
|
"O" -> TYPE_PARENT // Opiekun
|
||||||
|
"U" -> TYPE_STUDENT // Uczeń
|
||||||
|
else -> TYPE_OTHER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.teacherOnConflictStrategy = OnConflictStrategy.REPLACE
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2, 2 * DAY)
|
||||||
|
onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK_2)
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-9-16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGEBOX
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
||||||
|
import pl.szczodrzynski.edziennik.ext.DAY
|
||||||
|
import pl.szczodrzynski.edziennik.ext.getString
|
||||||
|
|
||||||
|
class VulcanHebeMessageBoxes(
|
||||||
|
override val data: DataVulcan,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit
|
||||||
|
) : VulcanHebe(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanHebeMessageBoxes"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiGetList(
|
||||||
|
TAG,
|
||||||
|
VULCAN_HEBE_ENDPOINT_MESSAGEBOX,
|
||||||
|
lastSync = lastSync
|
||||||
|
) { list, _ ->
|
||||||
|
var found = false
|
||||||
|
for (messageBox in list) {
|
||||||
|
val name = messageBox.getString("Name") ?: continue
|
||||||
|
val studentName = profile?.studentNameLong ?: continue
|
||||||
|
if (!name.contains(studentName))
|
||||||
|
continue
|
||||||
|
|
||||||
|
data.messageBoxKey = messageBox.getString("GlobalKey")
|
||||||
|
data.messageBoxName = name
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if (!found && list.isNotEmpty()) {
|
||||||
|
list.firstOrNull()?.let { messageBox ->
|
||||||
|
data.messageBoxKey = messageBox.getString("GlobalKey")
|
||||||
|
data.messageBoxName = messageBox.getString("Name")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
data.setSyncNext(ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES, 7 * DAY)
|
||||||
|
onSuccess(ENDPOINT_VULCAN_HEBE_MESSAGE_BOXES)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,22 +4,21 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
import androidx.core.util.set
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES
|
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGEBOX_MESSAGES
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED
|
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
|
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
|
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.navlib.crc16
|
|
||||||
|
|
||||||
class VulcanHebeMessages(
|
class VulcanHebeMessages(
|
||||||
override val data: DataVulcan,
|
override val data: DataVulcan,
|
||||||
@ -27,29 +26,7 @@ class VulcanHebeMessages(
|
|||||||
val onSuccess: (endpointId: Int) -> Unit
|
val onSuccess: (endpointId: Int) -> Unit
|
||||||
) : VulcanHebe(data, lastSync) {
|
) : VulcanHebe(data, lastSync) {
|
||||||
companion object {
|
companion object {
|
||||||
const val TAG = "VulcanHebeMessagesInbox"
|
const val TAG = "VulcanHebeMessages"
|
||||||
}
|
|
||||||
|
|
||||||
private fun getPersonId(json: JsonObject): Long {
|
|
||||||
val senderLoginId = json.getInt("LoginId") ?: return -1
|
|
||||||
/*if (senderLoginId == data.studentLoginId)
|
|
||||||
return -1*/
|
|
||||||
|
|
||||||
val senderName = json.getString("Address") ?: return -1
|
|
||||||
val senderNameSplit = senderName.splitName()
|
|
||||||
val senderLoginIdStr = senderLoginId.toString()
|
|
||||||
val teacher = data.teacherList.singleOrNull { it.loginId == senderLoginIdStr }
|
|
||||||
?: Teacher(
|
|
||||||
profileId,
|
|
||||||
-1 * crc16(senderName).toLong(),
|
|
||||||
senderNameSplit?.second ?: "",
|
|
||||||
senderNameSplit?.first ?: "",
|
|
||||||
senderLoginIdStr
|
|
||||||
).also {
|
|
||||||
it.setTeacherType(Teacher.TYPE_OTHER)
|
|
||||||
data.teacherList[it.id] = it
|
|
||||||
}
|
|
||||||
return teacher.id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getMessages(messageType: Int) {
|
fun getMessages(messageType: Int) {
|
||||||
@ -64,17 +41,28 @@ class VulcanHebeMessages(
|
|||||||
TYPE_SENT -> ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
|
TYPE_SENT -> ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
|
||||||
else -> ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
|
else -> ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val messageBox = data.messageBoxKey
|
||||||
|
if (messageBox == null) {
|
||||||
|
onSuccess(endpointId)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
apiGetList(
|
apiGetList(
|
||||||
TAG,
|
TAG,
|
||||||
VULCAN_HEBE_ENDPOINT_MESSAGES,
|
VULCAN_HEBE_ENDPOINT_MESSAGEBOX_MESSAGES,
|
||||||
HebeFilterType.BY_PERSON,
|
HebeFilterType.BY_MESSAGEBOX,
|
||||||
|
messageBox = data.messageBoxKey,
|
||||||
folder = folder,
|
folder = folder,
|
||||||
lastSync = lastSync
|
lastSync = lastSync
|
||||||
) { list, _ ->
|
) { list, _ ->
|
||||||
list.forEach { message ->
|
list.forEach { message ->
|
||||||
val id = message.getLong("Id") ?: return@forEach
|
val uuid = message.getString("Id") ?: return@forEach
|
||||||
|
val id = Utils.crc32(uuid.toByteArray())
|
||||||
|
val globalKey = message.getString("GlobalKey", "")
|
||||||
|
val threadKey = message.getString("ThreadKey", "")
|
||||||
val subject = message.getString("Subject") ?: return@forEach
|
val subject = message.getString("Subject") ?: return@forEach
|
||||||
val body = message.getString("Content") ?: return@forEach
|
var body = message.getString("Content") ?: return@forEach
|
||||||
|
|
||||||
val sender = message.getJsonObject("Sender") ?: return@forEach
|
val sender = message.getJsonObject("Sender") ?: return@forEach
|
||||||
|
|
||||||
@ -83,27 +71,45 @@ class VulcanHebeMessages(
|
|||||||
|
|
||||||
if (!isCurrentYear(sentDate)) return@forEach
|
if (!isCurrentYear(sentDate)) return@forEach
|
||||||
|
|
||||||
|
val senderId = if (messageType == TYPE_RECEIVED)
|
||||||
|
getTeacherRecipient(sender)?.id
|
||||||
|
else
|
||||||
|
null
|
||||||
|
|
||||||
|
val meta = mutableMapOf(
|
||||||
|
"uuid" to uuid,
|
||||||
|
"globalKey" to globalKey,
|
||||||
|
"threadKey" to threadKey,
|
||||||
|
)
|
||||||
|
val metaString = meta.map { "${it.key}=${it.value}" }.join("&")
|
||||||
|
body = "[META:${metaString}]" + body
|
||||||
|
body = body.replace("\n", "<br>")
|
||||||
|
|
||||||
val messageObject = Message(
|
val messageObject = Message(
|
||||||
profileId = profileId,
|
profileId = profileId,
|
||||||
id = id,
|
id = id,
|
||||||
type = messageType,
|
type = messageType,
|
||||||
subject = subject,
|
subject = subject,
|
||||||
body = body.replace("\n", "<br>"),
|
body = body,
|
||||||
senderId = if (messageType == TYPE_RECEIVED) getPersonId(sender) else null,
|
senderId = senderId,
|
||||||
addedDate = sentDate
|
addedDate = sentDate
|
||||||
)
|
)
|
||||||
|
|
||||||
val receivers = message.getJsonArray("Receiver")
|
val receivers = message.getJsonArray("Receiver")
|
||||||
?.asJsonObjectList()
|
?.asJsonObjectList()
|
||||||
?: return@forEach
|
?: return@forEach
|
||||||
val receiverReadDate =
|
|
||||||
if (receivers.size == 1) readDate
|
|
||||||
else -1
|
|
||||||
|
|
||||||
for (receiver in receivers) {
|
for (receiver in receivers) {
|
||||||
|
val recipientId = if (messageType == TYPE_SENT)
|
||||||
|
getTeacherRecipient(receiver)?.id ?: -1
|
||||||
|
else
|
||||||
|
-1
|
||||||
|
|
||||||
|
val receiverReadDate = receiver.getLong("HasRead", -1)
|
||||||
|
|
||||||
val messageRecipientObject = MessageRecipient(
|
val messageRecipientObject = MessageRecipient(
|
||||||
profileId,
|
profileId,
|
||||||
if (messageType == TYPE_SENT) getPersonId(receiver) else -1,
|
recipientId,
|
||||||
-1,
|
-1,
|
||||||
receiverReadDate,
|
receiverReadDate,
|
||||||
id
|
id
|
||||||
@ -115,6 +121,9 @@ class VulcanHebeMessages(
|
|||||||
?.asJsonObjectList()
|
?.asJsonObjectList()
|
||||||
?: return@forEach
|
?: return@forEach
|
||||||
|
|
||||||
|
messageObject.attachmentIds = mutableListOf()
|
||||||
|
messageObject.attachmentNames = mutableListOf()
|
||||||
|
messageObject.attachmentSizes = mutableListOf()
|
||||||
for (attachment in attachments) {
|
for (attachment in attachments) {
|
||||||
val fileName = attachment.getString("Name") ?: continue
|
val fileName = attachment.getString("Name") ?: continue
|
||||||
val url = attachment.getString("Link") ?: continue
|
val url = attachment.getString("Link") ?: continue
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS
|
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGEBOX_STATUS
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
||||||
@ -23,13 +23,19 @@ class VulcanHebeMessagesChangeStatus(
|
|||||||
const val TAG = "VulcanHebeMessagesChangeStatus"
|
const val TAG = "VulcanHebeMessagesChangeStatus"
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init { let {
|
||||||
|
val messageKey = messageObject.body?.let { data.parseMessageMeta(it) }?.get("uuid") ?: run {
|
||||||
|
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
|
||||||
|
onSuccess()
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
|
||||||
apiPost(
|
apiPost(
|
||||||
TAG,
|
TAG,
|
||||||
VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS,
|
VULCAN_HEBE_ENDPOINT_MESSAGEBOX_STATUS,
|
||||||
payload = JsonObject(
|
payload = JsonObject(
|
||||||
"MessageId" to messageObject.id,
|
"BoxKey" to data.messageBoxKey,
|
||||||
"LoginId" to data.studentLoginId,
|
"MessageKey" to messageKey,
|
||||||
"Status" to 1
|
"Status" to 1
|
||||||
)
|
)
|
||||||
) { _: Boolean, _ ->
|
) { _: Boolean, _ ->
|
||||||
@ -61,5 +67,5 @@ class VulcanHebeMessagesChangeStatus(
|
|||||||
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
|
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
@ -4,17 +4,20 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_MESSAGE_NOT_SENT
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY
|
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY
|
||||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES_SEND
|
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGEBOX_SEND
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
|
import java.util.UUID
|
||||||
|
|
||||||
class VulcanHebeSendMessage(
|
class VulcanHebeSendMessage(
|
||||||
override val data: DataVulcan,
|
override val data: DataVulcan,
|
||||||
@ -28,9 +31,9 @@ class VulcanHebeSendMessage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (data.senderAddressName == null || data.senderAddressHash == null) {
|
if (data.messageBoxKey == null || data.messageBoxName == null) {
|
||||||
VulcanHebeMain(data).getStudents(data.profile, null) {
|
VulcanHebeMessageBoxes(data, 0) {
|
||||||
if (data.senderAddressName == null || data.senderAddressHash == null) {
|
if (data.messageBoxKey == null || data.messageBoxName == null) {
|
||||||
data.error(TAG, ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY)
|
data.error(TAG, ERROR_VULCAN_HEBE_MISSING_SENDER_ENTRY)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@ -44,47 +47,64 @@ class VulcanHebeSendMessage(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun sendMessage() {
|
private fun sendMessage() {
|
||||||
|
val uuid = UUID.randomUUID().toString()
|
||||||
|
val globalKey = UUID.randomUUID().toString()
|
||||||
|
val partition = "${data.symbol}-${data.schoolSymbol}"
|
||||||
|
|
||||||
val recipientsArray = JsonArray()
|
val recipientsArray = JsonArray()
|
||||||
recipients.forEach { teacher ->
|
recipients.forEach { teacher ->
|
||||||
|
val loginId = teacher.loginId?.split(";", limit = 3) ?: return@forEach
|
||||||
|
val key = loginId.getOrNull(0) ?: teacher.loginId
|
||||||
|
val group = loginId.getOrNull(1)
|
||||||
|
val name = loginId.getOrNull(2)
|
||||||
|
if (key?.toIntOrNull() != null) {
|
||||||
|
// raise error for old-format (non-UUID) login IDs
|
||||||
|
data.error(TAG, ERROR_MESSAGE_NOT_SENT)
|
||||||
|
return
|
||||||
|
}
|
||||||
recipientsArray += JsonObject(
|
recipientsArray += JsonObject(
|
||||||
"Address" to teacher.fullNameLastFirst,
|
"Id" to "${data.messageBoxKey}-${key}",
|
||||||
"LoginId" to (teacher.loginId?.toIntOrNull() ?: return@forEach),
|
"Partition" to partition,
|
||||||
"Initials" to teacher.initialsLastFirst,
|
"Owner" to data.messageBoxKey,
|
||||||
"AddressHash" to teacher.fullNameLastFirst.sha1Hex()
|
"GlobalKey" to key,
|
||||||
|
"Name" to name,
|
||||||
|
"Group" to group,
|
||||||
|
"Initials" to "",
|
||||||
|
"HasRead" to 0,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val senderName = (profile?.accountName ?: profile?.studentNameLong)
|
|
||||||
?.swapFirstLastName() ?: ""
|
|
||||||
val sender = JsonObject(
|
val sender = JsonObject(
|
||||||
"Address" to data.senderAddressName,
|
"Id" to "0",
|
||||||
"LoginId" to data.studentLoginId.toString(),
|
"Partition" to partition,
|
||||||
"Initials" to senderName.getNameInitials(),
|
"Owner" to data.messageBoxKey,
|
||||||
"AddressHash" to data.senderAddressHash
|
"GlobalKey" to data.messageBoxKey,
|
||||||
|
"Name" to data.messageBoxName,
|
||||||
|
"Group" to "",
|
||||||
|
"Initials" to "",
|
||||||
|
"HasRead" to 0,
|
||||||
)
|
)
|
||||||
|
|
||||||
apiPost(
|
apiPost(
|
||||||
TAG,
|
TAG,
|
||||||
VULCAN_HEBE_ENDPOINT_MESSAGES_SEND,
|
VULCAN_HEBE_ENDPOINT_MESSAGEBOX_SEND,
|
||||||
payload = JsonObject(
|
payload = JsonObject(
|
||||||
"Status" to 1,
|
"Id" to uuid,
|
||||||
"Sender" to sender,
|
"GlobalKey" to globalKey,
|
||||||
"DateSent" to null,
|
"Partition" to partition,
|
||||||
"DateRead" to null,
|
"ThreadKey" to globalKey, // TODO correct threadKey for reply messages
|
||||||
"Content" to text,
|
|
||||||
"Receiver" to recipientsArray,
|
|
||||||
"Id" to 0,
|
|
||||||
"Subject" to subject,
|
"Subject" to subject,
|
||||||
"Attachments" to null,
|
"Content" to text,
|
||||||
"Self" to null
|
"Status" to 1,
|
||||||
|
"Owner" to data.messageBoxKey,
|
||||||
|
"DateSent" to buildDateTime(),
|
||||||
|
"DateRead" to null,
|
||||||
|
"Sender" to sender,
|
||||||
|
"Receiver" to recipientsArray,
|
||||||
|
"Attachments" to JsonArray(),
|
||||||
)
|
)
|
||||||
) { json: JsonObject, _ ->
|
) { _: JsonObject, _ ->
|
||||||
val messageId = json.getLong("Id")
|
// TODO handle errors
|
||||||
|
|
||||||
if (messageId == null) {
|
|
||||||
// TODO error
|
|
||||||
return@apiPost
|
|
||||||
}
|
|
||||||
|
|
||||||
VulcanHebeMessages(data, null) {
|
VulcanHebeMessages(data, null) {
|
||||||
val message = data.messageList.firstOrNull { it.isSent && it.subject == subject }
|
val message = data.messageList.firstOrNull { it.isSent && it.subject == subject }
|
||||||
|
@ -45,6 +45,7 @@ class VulcanHebeTeachers(
|
|||||||
|
|
||||||
when (subjectName) {
|
when (subjectName) {
|
||||||
"Pedagog" -> teacher.setTeacherType(Teacher.TYPE_PEDAGOGUE)
|
"Pedagog" -> teacher.setTeacherType(Teacher.TYPE_PEDAGOGUE)
|
||||||
|
"Dyrektor" -> teacher.setTeacherType(Teacher.TYPE_PRINCIPAL)
|
||||||
else -> {
|
else -> {
|
||||||
val subjectId = data.getSubject(null, subjectName).id
|
val subjectId = data.getSubject(null, subjectName).id
|
||||||
if (!teacher.subjects.contains(subjectId))
|
if (!teacher.subjects.contains(subjectId))
|
||||||
|
@ -4,13 +4,16 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.events
|
package pl.szczodrzynski.edziennik.data.api.events
|
||||||
|
|
||||||
data class UserActionRequiredEvent(val profileId: Int, val type: Int) {
|
import android.os.Bundle
|
||||||
companion object {
|
|
||||||
const val LOGIN_DATA_MOBIDZIENNIK = 101
|
data class UserActionRequiredEvent(
|
||||||
const val LOGIN_DATA_LIBRUS = 102
|
val profileId: Int?,
|
||||||
const val LOGIN_DATA_IDZIENNIK = 103
|
val type: Type,
|
||||||
const val LOGIN_DATA_VULCAN = 104
|
val params: Bundle,
|
||||||
const val LOGIN_DATA_EDUDZIENNIK = 105
|
val errorText: Int,
|
||||||
const val CAPTCHA_LIBRUS = 202
|
) {
|
||||||
|
enum class Type {
|
||||||
|
RECAPTCHA,
|
||||||
|
OAUTH,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.interfaces
|
package pl.szczodrzynski.edziennik.data.api.interfaces
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
||||||
|
|
||||||
@ -14,4 +15,5 @@ import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
|||||||
*/
|
*/
|
||||||
interface EdziennikCallback : EndpointCallback {
|
interface EdziennikCallback : EndpointCallback {
|
||||||
fun onCompleted()
|
fun onCompleted()
|
||||||
|
fun onRequiresUserAction(event: UserActionRequiredEvent)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.models
|
package pl.szczodrzynski.edziennik.data.api.models
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import android.os.Bundle
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import im.wangchao.mhttp.Request
|
import im.wangchao.mhttp.Request
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
@ -30,6 +31,7 @@ class ApiError(val tag: String, var errorCode: Int) {
|
|||||||
var request: Request? = null
|
var request: Request? = null
|
||||||
var response: Response? = null
|
var response: Response? = null
|
||||||
var isCritical = true
|
var isCritical = true
|
||||||
|
var params: Bundle? = null
|
||||||
|
|
||||||
fun withThrowable(throwable: Throwable?): ApiError {
|
fun withThrowable(throwable: Throwable?): ApiError {
|
||||||
this.throwable = throwable
|
this.throwable = throwable
|
||||||
@ -58,6 +60,11 @@ class ApiError(val tag: String, var errorCode: Int) {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun withParams(bundle: Bundle): ApiError {
|
||||||
|
this.params = bundle
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun getStringText(context: Context): String {
|
fun getStringText(context: Context): String {
|
||||||
return context.resources.getIdentifier("error_${errorCode}", "string", context.packageName).let {
|
return context.resources.getIdentifier("error_${errorCode}", "string", context.packageName).let {
|
||||||
if (it != 0)
|
if (it != 0)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.models
|
package pl.szczodrzynski.edziennik.data.api.models
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
import android.util.LongSparseArray
|
import android.util.LongSparseArray
|
||||||
import android.util.SparseArray
|
import android.util.SparseArray
|
||||||
import androidx.core.util.set
|
import androidx.core.util.set
|
||||||
@ -11,7 +12,9 @@ import pl.szczodrzynski.edziennik.App
|
|||||||
import pl.szczodrzynski.edziennik.BuildConfig
|
import pl.szczodrzynski.edziennik.BuildConfig
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
||||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EndpointCallback
|
import pl.szczodrzynski.edziennik.data.api.Regexes.MESSAGE_META
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.UserActionRequiredEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
import pl.szczodrzynski.edziennik.data.db.AppDb
|
import pl.szczodrzynski.edziennik.data.db.AppDb
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
@ -36,7 +39,7 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
|||||||
/**
|
/**
|
||||||
* A callback passed to all [Feature]s and [LoginMethod]s
|
* A callback passed to all [Feature]s and [LoginMethod]s
|
||||||
*/
|
*/
|
||||||
lateinit var callback: EndpointCallback
|
lateinit var callback: EdziennikCallback
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A list of [LoginMethod]s *already fulfilled* during this sync.
|
* A list of [LoginMethod]s *already fulfilled* during this sync.
|
||||||
@ -373,6 +376,15 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
|||||||
callback.onError(apiError)
|
callback.onError(apiError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun requireUserAction(type: UserActionRequiredEvent.Type, params: Bundle, errorText: Int) {
|
||||||
|
callback.onRequiresUserAction(UserActionRequiredEvent(
|
||||||
|
profileId = profile?.id,
|
||||||
|
type = type,
|
||||||
|
params = params,
|
||||||
|
errorText = errorText,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fun progress(step: Float) {
|
fun progress(step: Float) {
|
||||||
callback.onProgress(step)
|
callback.onProgress(step)
|
||||||
}
|
}
|
||||||
@ -437,14 +449,14 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
|||||||
return team
|
return team
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacher(firstName: String, lastName: String, loginId: String? = null): Teacher {
|
fun getTeacher(firstName: String, lastName: String, loginId: String? = null, id: Long? = null): Teacher {
|
||||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
||||||
return validateTeacher(teacher, firstName, lastName, loginId)
|
return validateTeacher(teacher, firstName, lastName, loginId, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacher(firstNameChar: Char, lastName: String, loginId: String? = null): Teacher {
|
fun getTeacher(firstNameChar: Char, lastName: String, loginId: String? = null): Teacher {
|
||||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
||||||
return validateTeacher(teacher, firstNameChar.toString(), lastName, loginId)
|
return validateTeacher(teacher, firstNameChar.toString(), lastName, loginId, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacherByLastFirst(nameLastFirst: String, loginId: String? = null): Teacher {
|
fun getTeacherByLastFirst(nameLastFirst: String, loginId: String? = null): Teacher {
|
||||||
@ -452,9 +464,9 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
|||||||
val teacher = teacherList.singleOrNull { it.fullNameLastFirst == nameLastFirst }
|
val teacher = teacherList.singleOrNull { it.fullNameLastFirst == nameLastFirst }
|
||||||
val nameParts = nameLastFirst.split(" ", limit = 2)
|
val nameParts = nameLastFirst.split(" ", limit = 2)
|
||||||
return if (nameParts.size == 1)
|
return if (nameParts.size == 1)
|
||||||
validateTeacher(teacher, nameParts[0], "", loginId)
|
validateTeacher(teacher, nameParts[0], "", loginId, null)
|
||||||
else
|
else
|
||||||
validateTeacher(teacher, nameParts[1], nameParts[0], loginId)
|
validateTeacher(teacher, nameParts[1], nameParts[0], loginId, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacherByFirstLast(nameFirstLast: String, loginId: String? = null): Teacher {
|
fun getTeacherByFirstLast(nameFirstLast: String, loginId: String? = null): Teacher {
|
||||||
@ -462,9 +474,9 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
|||||||
val teacher = teacherList.singleOrNull { it.fullName == nameFirstLast }
|
val teacher = teacherList.singleOrNull { it.fullName == nameFirstLast }
|
||||||
val nameParts = nameFirstLast.split(" ", limit = 2)
|
val nameParts = nameFirstLast.split(" ", limit = 2)
|
||||||
return if (nameParts.size == 1)
|
return if (nameParts.size == 1)
|
||||||
validateTeacher(teacher, nameParts[0], "", loginId)
|
validateTeacher(teacher, nameParts[0], "", loginId, null)
|
||||||
else
|
else
|
||||||
validateTeacher(teacher, nameParts[0], nameParts[1], loginId)
|
validateTeacher(teacher, nameParts[0], nameParts[1], loginId, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getTeacherByFDotLast(nameFDotLast: String, loginId: String? = null): Teacher {
|
fun getTeacherByFDotLast(nameFDotLast: String, loginId: String? = null): Teacher {
|
||||||
@ -483,17 +495,31 @@ abstract class Data(val app: App, val profile: Profile?, val loginStore: LoginSt
|
|||||||
getTeacher(nameParts[0][0], nameParts[1], loginId)
|
getTeacher(nameParts[0][0], nameParts[1], loginId)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun validateTeacher(teacher: Teacher?, firstName: String, lastName: String, loginId: String?): Teacher {
|
private fun validateTeacher(
|
||||||
val obj = teacher ?: Teacher(profileId, -1, firstName, lastName, loginId).apply {
|
teacher: Teacher?,
|
||||||
id = fullName.crc32()
|
firstName: String,
|
||||||
teacherList[id] = this
|
lastName: String,
|
||||||
|
loginId: String?,
|
||||||
|
id: Long?
|
||||||
|
): Teacher {
|
||||||
|
val obj = teacher ?: Teacher(profileId, -1, firstName, lastName, loginId).also {
|
||||||
|
it.id = id ?: it.fullName.crc32()
|
||||||
|
teacherList[it.id] = it
|
||||||
}
|
}
|
||||||
return obj.also {
|
return obj.also {
|
||||||
if (loginId != null && it.loginId != null)
|
if (loginId != null)
|
||||||
it.loginId = loginId
|
it.loginId = loginId
|
||||||
if (firstName.length > 1)
|
if (firstName.length > 1)
|
||||||
it.name = firstName
|
it.name = firstName
|
||||||
it.surname = lastName
|
it.surname = lastName
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun parseMessageMeta(body: String): Map<String, String>? {
|
||||||
|
val match = MESSAGE_META.find(body) ?: return null
|
||||||
|
return match[1].split("&").associateBy(
|
||||||
|
{ it.substringBefore("=") },
|
||||||
|
{ it.substringAfter("=") },
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -451,9 +451,9 @@ class SzkolnyApi(val app: App) : CoroutineScope {
|
|||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun getRealms(registerName: String): List<LoginInfo.Platform> {
|
fun getRealms(registerName: String): List<LoginInfo.Platform> {
|
||||||
val response = api.fsLoginRealms(registerName).execute()
|
val response = api.platforms(registerName).execute()
|
||||||
if (response.isSuccessful && response.body() != null) {
|
if (response.isSuccessful && response.body() != null) {
|
||||||
return response.body()!!
|
return parseResponse(response)
|
||||||
}
|
}
|
||||||
throw SzkolnyApiException(null)
|
throw SzkolnyApiException(null)
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,6 @@ interface SzkolnyService {
|
|||||||
@GET("registerAvailability")
|
@GET("registerAvailability")
|
||||||
fun registerAvailability(): Call<ApiResponse<Map<String, RegisterAvailabilityStatus>>>
|
fun registerAvailability(): Call<ApiResponse<Map<String, RegisterAvailabilityStatus>>>
|
||||||
|
|
||||||
@GET("https://szkolny-eu.github.io/FSLogin/realms/{registerName}.json")
|
@GET("platforms/{registerName}")
|
||||||
fun fsLoginRealms(@Path("registerName") registerName: String): Call<List<LoginInfo.Platform>>
|
fun platforms(@Path("registerName") registerName: String): Call<ApiResponse<List<LoginInfo.Platform>>>
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,6 @@ object Signing {
|
|||||||
|
|
||||||
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
|
||||||
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
|
||||||
return "$param1.MTIzNDU2Nzg5MDocQtfDuE===.$param2".sha256()
|
return "$param1.MTIzNDU2Nzg5MD5fPgIjyZ===.$param2".sha256()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Notification.Companion.TYPE_SER
|
|||||||
import pl.szczodrzynski.edziennik.ext.Intent
|
import pl.szczodrzynski.edziennik.ext.Intent
|
||||||
import pl.szczodrzynski.edziennik.ext.asBoldSpannable
|
import pl.szczodrzynski.edziennik.ext.asBoldSpannable
|
||||||
import pl.szczodrzynski.edziennik.ext.concat
|
import pl.szczodrzynski.edziennik.ext.concat
|
||||||
|
import pl.szczodrzynski.edziennik.ext.pendingIntentFlag
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Notification as AppNotification
|
import pl.szczodrzynski.edziennik.data.db.entity.Notification as AppNotification
|
||||||
|
|
||||||
@ -92,7 +93,7 @@ class PostNotifications(val app: App, nList: List<AppNotification>) {
|
|||||||
MainActivity::class.java,
|
MainActivity::class.java,
|
||||||
"fragmentId" to MainActivity.DRAWER_ITEM_NOTIFICATIONS
|
"fragmentId" to MainActivity.DRAWER_ITEM_NOTIFICATIONS
|
||||||
)
|
)
|
||||||
val summaryIntent = PendingIntent.getActivity(app, app.notificationChannelsManager.data.id, intent, PendingIntent.FLAG_ONE_SHOT)
|
val summaryIntent = PendingIntent.getActivity(app, app.notificationChannelsManager.data.id, intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag())
|
||||||
|
|
||||||
// On Nougat or newer - show maximum 8 notifications
|
// On Nougat or newer - show maximum 8 notifications
|
||||||
// On Marshmallow or older - show maximum 4 notifications
|
// On Marshmallow or older - show maximum 4 notifications
|
||||||
|
@ -44,7 +44,7 @@ import pl.szczodrzynski.edziennik.data.db.migration.*
|
|||||||
TimetableManual::class,
|
TimetableManual::class,
|
||||||
Note::class,
|
Note::class,
|
||||||
Metadata::class
|
Metadata::class
|
||||||
], version = 97)
|
], version = 98)
|
||||||
@TypeConverters(
|
@TypeConverters(
|
||||||
ConverterTime::class,
|
ConverterTime::class,
|
||||||
ConverterDate::class,
|
ConverterDate::class,
|
||||||
@ -185,6 +185,7 @@ abstract class AppDb : RoomDatabase() {
|
|||||||
Migration95(),
|
Migration95(),
|
||||||
Migration96(),
|
Migration96(),
|
||||||
Migration97(),
|
Migration97(),
|
||||||
|
Migration98(),
|
||||||
).allowMainThreadQueries().build()
|
).allowMainThreadQueries().build()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ abstract class EventDao : BaseDao<Event, EventFull> {
|
|||||||
abstract fun removeNotManual(profileId: Int)*/
|
abstract fun removeNotManual(profileId: Int)*/
|
||||||
|
|
||||||
@RawQuery
|
@RawQuery
|
||||||
abstract fun dontKeepFuture(query: SupportSQLiteQuery?): Long
|
abstract fun dontKeepFuture(query: SupportSQLiteQuery): Long
|
||||||
|
|
||||||
@Transaction
|
@Transaction
|
||||||
open fun dontKeepFuture(profileId: Int, todayDate: Date, filter: String) {
|
open fun dontKeepFuture(profileId: Int, todayDate: Date, filter: String) {
|
||||||
|
@ -74,6 +74,8 @@ open class Lesson(
|
|||||||
@Ignore
|
@Ignore
|
||||||
var showAsUnseen = false
|
var showAsUnseen = false
|
||||||
|
|
||||||
|
var color: Int? = null
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "Lesson(profileId=$profileId, " +
|
return "Lesson(profileId=$profileId, " +
|
||||||
"id=$id, " +
|
"id=$id, " +
|
||||||
|
@ -13,6 +13,7 @@ import com.google.gson.JsonObject
|
|||||||
import com.mikepenz.iconics.typeface.IIcon
|
import com.mikepenz.iconics.typeface.IIcon
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
import pl.szczodrzynski.edziennik.MainActivity
|
import pl.szczodrzynski.edziennik.MainActivity
|
||||||
|
import pl.szczodrzynski.edziennik.ext.pendingIntentFlag
|
||||||
|
|
||||||
@Entity(tableName = "notifications")
|
@Entity(tableName = "notifications")
|
||||||
data class Notification(
|
data class Notification(
|
||||||
@ -98,7 +99,7 @@ data class Notification(
|
|||||||
fun getPendingIntent(context: Context): PendingIntent {
|
fun getPendingIntent(context: Context): PendingIntent {
|
||||||
val intent = Intent(context, MainActivity::class.java)
|
val intent = Intent(context, MainActivity::class.java)
|
||||||
fillIntent(intent)
|
fillIntent(intent)
|
||||||
return PendingIntent.getActivity(context, id.toInt(), intent, PendingIntent.FLAG_ONE_SHOT)
|
return PendingIntent.getActivity(context, id.toInt(), intent, PendingIntent.FLAG_ONE_SHOT or pendingIntentFlag())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getLargeIcon(): IIcon = when (type) {
|
fun getLargeIcon(): IIcon = when (type) {
|
||||||
|
@ -233,6 +233,10 @@ open class Profile(
|
|||||||
MainActivity.DRAWER_ITEM_GRADES,
|
MainActivity.DRAWER_ITEM_GRADES,
|
||||||
MainActivity.DRAWER_ITEM_HOMEWORK
|
MainActivity.DRAWER_ITEM_HOMEWORK
|
||||||
)
|
)
|
||||||
|
LOGIN_TYPE_USOS -> listOf(
|
||||||
|
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||||
|
MainActivity.DRAWER_ITEM_AGENDA
|
||||||
|
)
|
||||||
else -> listOf(
|
else -> listOf(
|
||||||
MainActivity.DRAWER_ITEM_TIMETABLE,
|
MainActivity.DRAWER_ITEM_TIMETABLE,
|
||||||
MainActivity.DRAWER_ITEM_AGENDA,
|
MainActivity.DRAWER_ITEM_AGENDA,
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-16.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.db.migration
|
||||||
|
|
||||||
|
import androidx.room.migration.Migration
|
||||||
|
import androidx.sqlite.db.SupportSQLiteDatabase
|
||||||
|
|
||||||
|
class Migration98 : Migration(97, 98) {
|
||||||
|
override fun migrate(database: SupportSQLiteDatabase) {
|
||||||
|
// timetable colors - override color in lesson object
|
||||||
|
database.execSQL("ALTER TABLE timetable ADD COLUMN color INT DEFAULT NULL;")
|
||||||
|
}
|
||||||
|
}
|
@ -22,6 +22,15 @@ fun Bundle?.getFloat(key: String, defaultValue: Float): Float {
|
|||||||
fun Bundle?.getString(key: String, defaultValue: String): String {
|
fun Bundle?.getString(key: String, defaultValue: String): String {
|
||||||
return this?.getString(key, defaultValue) ?: defaultValue
|
return this?.getString(key, defaultValue) ?: defaultValue
|
||||||
}
|
}
|
||||||
|
inline fun <reified E : Enum<E>> Bundle?.getEnum(key: String): E? {
|
||||||
|
return this?.getString(key)?.let {
|
||||||
|
try {
|
||||||
|
enumValueOf<E>(it)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun Bundle?.getIntOrNull(key: String): Int? {
|
fun Bundle?.getIntOrNull(key: String): Int? {
|
||||||
return this?.get(key) as? Int
|
return this?.get(key) as? Int
|
||||||
@ -48,6 +57,7 @@ fun Bundle(vararg properties: Pair<String, Any?>): Bundle {
|
|||||||
is Bundle -> putBundle(property.first, property.second as Bundle)
|
is Bundle -> putBundle(property.first, property.second as Bundle)
|
||||||
is Parcelable -> putParcelable(property.first, property.second as Parcelable)
|
is Parcelable -> putParcelable(property.first, property.second as Parcelable)
|
||||||
is Array<*> -> putParcelableArray(property.first, property.second as Array<out Parcelable>)
|
is Array<*> -> putParcelableArray(property.first, property.second as Array<out Parcelable>)
|
||||||
|
is Enum<*> -> putString(property.first, (property.second as Enum<*>).name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,8 @@ import com.google.gson.JsonElement
|
|||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
import com.google.gson.JsonParser
|
||||||
import com.google.gson.JsonPrimitive
|
import com.google.gson.JsonPrimitive
|
||||||
|
import kotlin.contracts.ExperimentalContracts
|
||||||
|
import kotlin.contracts.contract
|
||||||
|
|
||||||
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
||||||
|
|
||||||
@ -93,7 +95,13 @@ fun JsonArray(vararg properties: Any?): JsonArray {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0
|
@OptIn(ExperimentalContracts::class)
|
||||||
|
fun JsonArray?.isNullOrEmpty(): Boolean {
|
||||||
|
contract {
|
||||||
|
returns(false) implies (this@isNullOrEmpty != null)
|
||||||
|
}
|
||||||
|
return this == null || this.isEmpty
|
||||||
|
}
|
||||||
operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o)
|
operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o)
|
||||||
operator fun JsonArray.plusAssign(o: String) = this.add(o)
|
operator fun JsonArray.plusAssign(o: String) = this.add(o)
|
||||||
operator fun JsonArray.plusAssign(o: Char) = this.add(o)
|
operator fun JsonArray.plusAssign(o: Char) = this.add(o)
|
||||||
|
@ -4,7 +4,9 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.ext
|
package pl.szczodrzynski.edziennik.ext
|
||||||
|
|
||||||
|
import android.app.PendingIntent
|
||||||
import android.database.Cursor
|
import android.database.Cursor
|
||||||
|
import android.os.Build
|
||||||
import androidx.core.database.getIntOrNull
|
import androidx.core.database.getIntOrNull
|
||||||
import androidx.core.database.getLongOrNull
|
import androidx.core.database.getLongOrNull
|
||||||
import androidx.core.database.getStringOrNull
|
import androidx.core.database.getStringOrNull
|
||||||
@ -64,3 +66,9 @@ inline fun <A, B, R> ifNotNull(a: A?, b: B?, code: (A, B) -> R): R? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
infix fun Int.hasSet(what: Int) = this and what == what
|
infix fun Int.hasSet(what: Int) = this and what == what
|
||||||
|
|
||||||
|
fun pendingIntentFlag(): Int {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
|
||||||
|
return PendingIntent.FLAG_IMMUTABLE
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
@ -18,6 +18,8 @@ import android.text.style.StyleSpan
|
|||||||
import androidx.annotation.PluralsRes
|
import androidx.annotation.PluralsRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
import com.mikepenz.materialdrawer.holder.StringHolder
|
import com.mikepenz.materialdrawer.holder.StringHolder
|
||||||
|
import java.net.URLDecoder
|
||||||
|
import java.net.URLEncoder
|
||||||
|
|
||||||
fun CharSequence?.isNotNullNorEmpty(): Boolean {
|
fun CharSequence?.isNotNullNorEmpty(): Boolean {
|
||||||
return this != null && this.isNotEmpty()
|
return this != null && this.isNotEmpty()
|
||||||
@ -343,3 +345,17 @@ fun Int.toStringHolder() = StringHolder(this)
|
|||||||
fun CharSequence.toStringHolder() = StringHolder(this)
|
fun CharSequence.toStringHolder() = StringHolder(this)
|
||||||
|
|
||||||
fun @receiver:StringRes Int.resolveString(context: Context) = context.getString(this)
|
fun @receiver:StringRes Int.resolveString(context: Context) = context.getString(this)
|
||||||
|
|
||||||
|
fun String.urlEncode(): String = URLEncoder.encode(this, "UTF-8").replace("+", "%20")
|
||||||
|
fun String.urlDecode(): String = URLDecoder.decode(this, "UTF-8")
|
||||||
|
|
||||||
|
fun Map<String, String>.toQueryString() = this
|
||||||
|
.map { it.key.urlEncode() to it.value.urlEncode() }
|
||||||
|
.sortedBy { it.first }
|
||||||
|
.joinToString("&") { "${it.first}=${it.second}" }
|
||||||
|
|
||||||
|
fun String.fromQueryString() = this
|
||||||
|
.substringAfter('?')
|
||||||
|
.split("&")
|
||||||
|
.map { it.split("=") }
|
||||||
|
.associate { it[0].urlDecode() to it[1].urlDecode() }
|
||||||
|
@ -7,9 +7,10 @@ package pl.szczodrzynski.edziennik.ext
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.Locale
|
||||||
|
|
||||||
const val MINUTE = 60L
|
const val MINUTE = 60L
|
||||||
const val HOUR = 60L*MINUTE
|
const val HOUR = 60L*MINUTE
|
||||||
@ -115,3 +116,11 @@ fun Context.getSyncInterval(interval: Int): String {
|
|||||||
""
|
""
|
||||||
return hoursText?.plus(" $minutesText") ?: minutesText
|
return hoursText?.plus(" $minutesText") ?: minutesText
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ClosedRange<Date>.asSequence(): Sequence<Date> = sequence {
|
||||||
|
val date = this@asSequence.start.clone()
|
||||||
|
while (date in this@asSequence) {
|
||||||
|
yield(date.clone())
|
||||||
|
date.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,6 +21,7 @@ import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
|||||||
import pl.szczodrzynski.edziennik.ext.DAY
|
import pl.szczodrzynski.edziennik.ext.DAY
|
||||||
import pl.szczodrzynski.edziennik.ext.concat
|
import pl.szczodrzynski.edziennik.ext.concat
|
||||||
import pl.szczodrzynski.edziennik.ext.formatDate
|
import pl.szczodrzynski.edziennik.ext.formatDate
|
||||||
|
import pl.szczodrzynski.edziennik.ext.pendingIntentFlag
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
import pl.szczodrzynski.edziennik.utils.html.BetterHtml
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
@ -109,7 +110,7 @@ class UpdateWorker(val context: Context, val params: WorkerParameters) : Worker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val notificationIntent = Intent(app, UpdateDownloaderService::class.java)
|
val notificationIntent = Intent(app, UpdateDownloaderService::class.java)
|
||||||
val pendingIntent = PendingIntent.getService(app, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT)
|
val pendingIntent = PendingIntent.getService(app, 0, notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT or pendingIntentFlag())
|
||||||
val notification = NotificationCompat.Builder(app, app.notificationChannelsManager.updates.key)
|
val notification = NotificationCompat.Builder(app, app.notificationChannelsManager.updates.key)
|
||||||
.setContentTitle(app.getString(R.string.notification_updates_title))
|
.setContentTitle(app.getString(R.string.notification_updates_title))
|
||||||
.setContentText(app.getString(R.string.notification_updates_text, update.versionName))
|
.setContentText(app.getString(R.string.notification_updates_text, update.versionName))
|
||||||
|
@ -13,14 +13,16 @@ import pl.szczodrzynski.edziennik.databinding.RecaptchaViewBinding
|
|||||||
import pl.szczodrzynski.edziennik.ext.onClick
|
import pl.szczodrzynski.edziennik.ext.onClick
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.base.BindingDialog
|
||||||
|
|
||||||
class LibrusCaptchaDialog(
|
class RecaptchaPromptDialog(
|
||||||
activity: AppCompatActivity,
|
activity: AppCompatActivity,
|
||||||
|
private val siteKey: String,
|
||||||
|
private val referer: String,
|
||||||
private val onSuccess: (recaptchaCode: String) -> Unit,
|
private val onSuccess: (recaptchaCode: String) -> Unit,
|
||||||
private val onFailure: (() -> Unit)?,
|
private val onCancel: (() -> Unit)?,
|
||||||
onShowListener: ((tag: String) -> Unit)? = null,
|
onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
onDismissListener: ((tag: String) -> Unit)? = null,
|
onDismissListener: ((tag: String) -> Unit)? = null,
|
||||||
) : BindingDialog<RecaptchaViewBinding>(activity, onShowListener, onDismissListener) {
|
) : BindingDialog<RecaptchaViewBinding>(activity, onShowListener, onDismissListener) {
|
||||||
override val TAG = "LibrusCaptchaDialog"
|
override val TAG = "RecaptchaPromptDialog"
|
||||||
|
|
||||||
override fun getTitleRes(): Int? = null
|
override fun getTitleRes(): Int? = null
|
||||||
override fun inflate(layoutInflater: LayoutInflater) =
|
override fun inflate(layoutInflater: LayoutInflater) =
|
||||||
@ -46,8 +48,8 @@ class LibrusCaptchaDialog(
|
|||||||
b.progress.visibility = View.VISIBLE
|
b.progress.visibility = View.VISIBLE
|
||||||
RecaptchaDialog(
|
RecaptchaDialog(
|
||||||
activity,
|
activity,
|
||||||
siteKey = "6Lf48moUAAAAAB9ClhdvHr46gRWR-CN31CXQPG2U",
|
siteKey = siteKey,
|
||||||
referer = "https://portal.librus.pl/rodzina/login",
|
referer = referer,
|
||||||
onSuccess = { recaptchaCode ->
|
onSuccess = { recaptchaCode ->
|
||||||
b.checkbox.background = checkboxBackground
|
b.checkbox.background = checkboxBackground
|
||||||
b.checkbox.foreground = checkboxForeground
|
b.checkbox.foreground = checkboxForeground
|
||||||
@ -67,6 +69,6 @@ class LibrusCaptchaDialog(
|
|||||||
|
|
||||||
override fun onDismiss() {
|
override fun onDismiss() {
|
||||||
if (!success)
|
if (!success)
|
||||||
onFailure?.invoke()
|
onCancel?.invoke()
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -8,6 +8,7 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -17,6 +18,8 @@ import pl.szczodrzynski.edziennik.MainActivity
|
|||||||
import pl.szczodrzynski.edziennik.databinding.TemplateFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.TemplateFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.addOnPageSelectedListener
|
import pl.szczodrzynski.edziennik.ext.addOnPageSelectedListener
|
||||||
import pl.szczodrzynski.edziennik.ui.base.lazypager.FragmentLazyPagerAdapter
|
import pl.szczodrzynski.edziennik.ui.base.lazypager.FragmentLazyPagerAdapter
|
||||||
|
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
|
||||||
|
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class LabFragment : Fragment(), CoroutineScope {
|
class LabFragment : Fragment(), CoroutineScope {
|
||||||
@ -26,7 +29,7 @@ class LabFragment : Fragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var app: App
|
private lateinit var app: App
|
||||||
private lateinit var activity: MainActivity
|
private lateinit var activity: AppCompatActivity
|
||||||
private lateinit var b: TemplateFragmentBinding
|
private lateinit var b: TemplateFragmentBinding
|
||||||
|
|
||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
@ -36,11 +39,14 @@ class LabFragment : Fragment(), CoroutineScope {
|
|||||||
// local/private variables go here
|
// local/private variables go here
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as AppCompatActivity?) ?: return null
|
||||||
context ?: return null
|
context ?: return null
|
||||||
app = activity.application as App
|
app = activity.application as App
|
||||||
b = TemplateFragmentBinding.inflate(inflater)
|
b = TemplateFragmentBinding.inflate(inflater)
|
||||||
b.refreshLayout.setParent(activity.swipeRefreshLayout)
|
when (activity) {
|
||||||
|
is MainActivity -> b.refreshLayout.setParent((activity as MainActivity).swipeRefreshLayout)
|
||||||
|
is LoginActivity -> b.refreshLayout.setParent((activity as LoginActivity).swipeRefreshLayout)
|
||||||
|
}
|
||||||
b.refreshLayout.isEnabled = false
|
b.refreshLayout.isEnabled = false
|
||||||
return b.root
|
return b.root
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import android.os.Process
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.sqlite.db.SimpleSQLiteQuery
|
import androidx.sqlite.db.SimpleSQLiteQuery
|
||||||
import com.chuckerteam.chucker.api.Chucker
|
import com.chuckerteam.chucker.api.Chucker
|
||||||
@ -35,7 +36,7 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var app: App
|
private lateinit var app: App
|
||||||
private lateinit var activity: MainActivity
|
private lateinit var activity: AppCompatActivity
|
||||||
private lateinit var b: LabFragmentBinding
|
private lateinit var b: LabFragmentBinding
|
||||||
|
|
||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
@ -45,7 +46,7 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
// local/private variables go here
|
// local/private variables go here
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as AppCompatActivity?) ?: return null
|
||||||
context ?: return null
|
context ?: return null
|
||||||
app = activity.application as App
|
app = activity.application as App
|
||||||
b = LabFragmentBinding.inflate(inflater)
|
b = LabFragmentBinding.inflate(inflater)
|
||||||
@ -55,6 +56,16 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
override fun onPageCreated(): Boolean {
|
override fun onPageCreated(): Boolean {
|
||||||
b.app = app
|
b.app = app
|
||||||
|
|
||||||
|
if (app.profile.id == 0) {
|
||||||
|
b.last10unseen.isVisible = false
|
||||||
|
b.fullSync.isVisible = false
|
||||||
|
b.clearProfile.isVisible = false
|
||||||
|
b.rodo.isVisible = false
|
||||||
|
b.removeHomework.isVisible = false
|
||||||
|
b.unarchive.isVisible = false
|
||||||
|
b.profile.isVisible = false
|
||||||
|
}
|
||||||
|
|
||||||
b.last10unseen.onClick {
|
b.last10unseen.onClick {
|
||||||
launch(Dispatchers.Default) {
|
launch(Dispatchers.Default) {
|
||||||
val events = app.db.eventDao().getAllNow(App.profileId)
|
val events = app.db.eventDao().getAllNow(App.profileId)
|
||||||
@ -139,7 +150,8 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
|
|||||||
b.profile += profiles.map { TextInputDropDown.Item(it.id.toLong(), "${it.id} ${it.name} archived ${it.archived}", tag = it) }
|
b.profile += profiles.map { TextInputDropDown.Item(it.id.toLong(), "${it.id} ${it.name} archived ${it.archived}", tag = it) }
|
||||||
b.profile.select(app.profileId.toLong())
|
b.profile.select(app.profileId.toLong())
|
||||||
b.profile.setOnChangeListener {
|
b.profile.setOnChangeListener {
|
||||||
activity.loadProfile(it.id.toInt())
|
if (activity is MainActivity)
|
||||||
|
(activity as MainActivity).loadProfile(it.id.toInt())
|
||||||
return@setOnChangeListener true
|
return@setOnChangeListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ import android.os.Bundle
|
|||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
@ -22,6 +23,7 @@ import pl.szczodrzynski.edziennik.ext.input
|
|||||||
import pl.szczodrzynski.edziennik.ext.set
|
import pl.szczodrzynski.edziennik.ext.set
|
||||||
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
|
import pl.szczodrzynski.edziennik.ext.startCoroutineTimer
|
||||||
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
|
import pl.szczodrzynski.edziennik.ui.base.lazypager.LazyFragment
|
||||||
|
import pl.szczodrzynski.edziennik.ui.login.LoginActivity
|
||||||
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
import pl.szczodrzynski.edziennik.utils.SimpleDividerItemDecoration
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
@ -31,7 +33,7 @@ class LabProfileFragment : LazyFragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var app: App
|
private lateinit var app: App
|
||||||
private lateinit var activity: MainActivity
|
private lateinit var activity: AppCompatActivity
|
||||||
private lateinit var b: TemplateListPageFragmentBinding
|
private lateinit var b: TemplateListPageFragmentBinding
|
||||||
|
|
||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
@ -45,7 +47,7 @@ class LabProfileFragment : LazyFragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as AppCompatActivity?) ?: return null
|
||||||
context ?: return null
|
context ?: return null
|
||||||
app = activity.application as App
|
app = activity.application as App
|
||||||
b = TemplateListPageFragmentBinding.inflate(inflater)
|
b = TemplateListPageFragmentBinding.inflate(inflater)
|
||||||
@ -142,7 +144,10 @@ class LabProfileFragment : LazyFragment(), CoroutineScope {
|
|||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
catch (e: Exception) {
|
catch (e: Exception) {
|
||||||
activity.error(ApiError.fromThrowable(TAG, e))
|
if (activity is MainActivity)
|
||||||
|
(activity as MainActivity).error(ApiError.fromThrowable(TAG, e))
|
||||||
|
if (activity is LoginActivity)
|
||||||
|
(activity as LoginActivity).error(ApiError.fromThrowable(TAG, e))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.dialogs.settings
|
||||||
|
|
||||||
|
import android.view.LayoutInflater
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import pl.szczodrzynski.edziennik.MainActivity
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.databinding.TimetableConfigDialogBinding
|
||||||
|
import pl.szczodrzynski.edziennik.ext.Intent
|
||||||
|
import pl.szczodrzynski.edziennik.ext.onClick
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.base.ConfigDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.timetable.TimetableFragment
|
||||||
|
|
||||||
|
class TimetableConfigDialog(
|
||||||
|
activity: AppCompatActivity,
|
||||||
|
reloadOnDismiss: Boolean = true,
|
||||||
|
onShowListener: ((tag: String) -> Unit)? = null,
|
||||||
|
onDismissListener: ((tag: String) -> Unit)? = null,
|
||||||
|
) : ConfigDialog<TimetableConfigDialogBinding>(
|
||||||
|
activity,
|
||||||
|
reloadOnDismiss,
|
||||||
|
onShowListener,
|
||||||
|
onDismissListener,
|
||||||
|
) {
|
||||||
|
|
||||||
|
override val TAG = "TimetableConfigDialog"
|
||||||
|
|
||||||
|
override fun getTitleRes() = R.string.menu_timetable_config
|
||||||
|
override fun inflate(layoutInflater: LayoutInflater) =
|
||||||
|
TimetableConfigDialogBinding.inflate(layoutInflater)
|
||||||
|
|
||||||
|
private val profileConfig by lazy { app.config.getFor(app.profileId).ui }
|
||||||
|
|
||||||
|
override suspend fun loadConfig() {
|
||||||
|
b.config = profileConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun saveConfig() {
|
||||||
|
activity.sendBroadcast(Intent(TimetableFragment.ACTION_RELOAD_PAGES))
|
||||||
|
}
|
||||||
|
}
|
@ -81,7 +81,8 @@ class HomeFragment : Fragment(), CoroutineScope {
|
|||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
get() = job + Dispatchers.Main
|
get() = job + Dispatchers.Main
|
||||||
|
private val manager
|
||||||
|
get() = app.permissionManager
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
activity = (getActivity() as MainActivity?) ?: return null
|
activity = (getActivity() as MainActivity?) ?: return null
|
||||||
context ?: return null
|
context ?: return null
|
||||||
@ -96,6 +97,10 @@ class HomeFragment : Fragment(), CoroutineScope {
|
|||||||
if (!isAdded)
|
if (!isAdded)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
if (!manager.isNotificationPermissionGranted) {
|
||||||
|
manager.requestNotificationsPermission(activity, 0, false){}
|
||||||
|
}
|
||||||
|
|
||||||
activity.bottomSheet.prependItems(
|
activity.bottomSheet.prependItems(
|
||||||
BottomSheetPrimaryItem(true)
|
BottomSheetPrimaryItem(true)
|
||||||
.withTitle(R.string.menu_add_remove_cards)
|
.withTitle(R.string.menu_add_remove_cards)
|
||||||
@ -198,7 +203,7 @@ class HomeFragment : Fragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun performAccessibilityAction(host: View, action: Int, args: Bundle): Boolean {
|
override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
|
||||||
val fromPosition: Int = b.list.getChildLayoutPosition(host)
|
val fromPosition: Int = b.list.getChildLayoutPosition(host)
|
||||||
if (action == R.id.move_card_down_action) {
|
if (action == R.id.move_card_down_action) {
|
||||||
swapCards(fromPosition, fromPosition + 1, adapter)
|
swapCards(fromPosition, fromPosition + 1, adapter)
|
||||||
|
@ -27,7 +27,7 @@ import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
|||||||
import pl.szczodrzynski.edziennik.databinding.CardHomeDebugBinding
|
import pl.szczodrzynski.edziennik.databinding.CardHomeDebugBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.dp
|
import pl.szczodrzynski.edziennik.ext.dp
|
||||||
import pl.szczodrzynski.edziennik.ext.onClick
|
import pl.szczodrzynski.edziennik.ext.onClick
|
||||||
import pl.szczodrzynski.edziennik.ui.captcha.LibrusCaptchaDialog
|
import pl.szczodrzynski.edziennik.ui.captcha.RecaptchaPromptDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
import pl.szczodrzynski.edziennik.ui.home.HomeCard
|
||||||
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
|
import pl.szczodrzynski.edziennik.ui.home.HomeCardAdapter
|
||||||
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
|
import pl.szczodrzynski.edziennik.ui.home.HomeFragment
|
||||||
@ -85,11 +85,6 @@ class HomeDebugCard(
|
|||||||
app.startActivity(Chucker.getLaunchIntent(activity, 1));
|
app.startActivity(Chucker.getLaunchIntent(activity, 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
b.librusCaptchaButton.onClick {
|
|
||||||
//app.startActivity(Intent(activity, LoginLibrusCaptchaActivity::class.java))
|
|
||||||
LibrusCaptchaDialog(activity, onSuccess = {}, onFailure = {}).show()
|
|
||||||
}
|
|
||||||
|
|
||||||
b.getLogs.onClick {
|
b.getLogs.onClick {
|
||||||
val logs = HyperLog.getDeviceLogsInFile(activity, true)
|
val logs = HyperLog.getDeviceLogsInFile(activity, true)
|
||||||
val intent = Intent(Intent.ACTION_SEND)
|
val intent = Intent(Intent.ACTION_SEND)
|
||||||
|
@ -75,7 +75,7 @@ class HomeTimetableCard(
|
|||||||
private var counterEnd: Time? = null
|
private var counterEnd: Time? = null
|
||||||
private var subjectSpannable: CharSequence? = null
|
private var subjectSpannable: CharSequence? = null
|
||||||
|
|
||||||
private val ignoreCancelled = true
|
private val ignoreCancelled = false
|
||||||
|
|
||||||
private val countInSeconds: Boolean
|
private val countInSeconds: Boolean
|
||||||
get() = app.config.timetable.countInSeconds
|
get() = app.config.timetable.countInSeconds
|
||||||
@ -160,6 +160,9 @@ class HomeTimetableCard(
|
|||||||
&& it.displayEndTime > now
|
&& it.displayEndTime > now
|
||||||
&& !(it.isCancelled && ignoreCancelled)
|
&& !(it.isCancelled && ignoreCancelled)
|
||||||
}
|
}
|
||||||
|
if (!ignoreCancelled && lessons.all { it.isCancelled })
|
||||||
|
// skip current day if all lessons are cancelled
|
||||||
|
lessons = listOf()
|
||||||
while ((lessons.isEmpty() || lessons.none {
|
while ((lessons.isEmpty() || lessons.none {
|
||||||
it.type != Lesson.TYPE_NO_LESSONS
|
it.type != Lesson.TYPE_NO_LESSONS
|
||||||
&& (it.displayDate != today
|
&& (it.displayDate != today
|
||||||
@ -174,6 +177,7 @@ class HomeTimetableCard(
|
|||||||
it.profileId == profile.id
|
it.profileId == profile.id
|
||||||
&& it.displayDate == timetableDate
|
&& it.displayDate == timetableDate
|
||||||
}
|
}
|
||||||
|
lessons = lessons.dropWhile { it.isCancelled }
|
||||||
|
|
||||||
if (lessons.isEmpty())
|
if (lessons.isEmpty())
|
||||||
break
|
break
|
||||||
@ -238,15 +242,18 @@ class HomeTimetableCard(
|
|||||||
b.counter.visibility = View.GONE
|
b.counter.visibility = View.GONE
|
||||||
|
|
||||||
val now = syncedNow
|
val now = syncedNow
|
||||||
val firstLesson = lessons.firstOrNull()
|
val firstLesson = lessons.firstOrNull { !it.isCancelled }
|
||||||
val lastLesson = lessons.lastOrNull()
|
val lastLesson = lessons.lastOrNull { !it.isCancelled }
|
||||||
|
val skipFirst = if (firstLesson == null) 0 else lessons.indexOf(firstLesson)
|
||||||
|
val skipLast = if (lastLesson == null) 0 else lessons.size - 1 - lessons.indexOf(lastLesson)
|
||||||
|
val lessonCount = lessons.size - skipFirst - skipLast
|
||||||
|
|
||||||
if (isToday) {
|
if (isToday) {
|
||||||
// today
|
// today
|
||||||
b.dayInfo.setText(R.string.home_timetable_today)
|
b.dayInfo.setText(R.string.home_timetable_today)
|
||||||
b.lessonInfo.setText(
|
b.lessonInfo.setText(
|
||||||
R.string.home_timetable_lessons_remaining,
|
R.string.home_timetable_lessons_remaining,
|
||||||
lessons.size,
|
lessonCount,
|
||||||
lastLesson?.displayEndTime?.stringHM ?: "?"
|
lastLesson?.displayEndTime?.stringHM ?: "?"
|
||||||
)
|
)
|
||||||
counterStart = firstLesson?.displayStartTime
|
counterStart = firstLesson?.displayStartTime
|
||||||
@ -291,12 +298,14 @@ class HomeTimetableCard(
|
|||||||
b.dayInfo.setText(dayInfoRes, Week.getFullDayName(timetableDate.weekDay), timetableDate.formattedString)
|
b.dayInfo.setText(dayInfoRes, Week.getFullDayName(timetableDate.weekDay), timetableDate.formattedString)
|
||||||
b.lessonInfo.setText(
|
b.lessonInfo.setText(
|
||||||
R.string.home_timetable_lessons_info,
|
R.string.home_timetable_lessons_info,
|
||||||
lessons.size,
|
lessonCount,
|
||||||
firstLesson?.displayStartTime?.stringHM ?: "?",
|
firstLesson?.displayStartTime?.stringHM ?: "?",
|
||||||
lastLesson?.displayEndTime?.stringHM ?: "?"
|
lastLesson?.displayEndTime?.stringHM ?: "?"
|
||||||
)
|
)
|
||||||
|
|
||||||
b.lessonBig.setText(R.string.home_timetable_lesson_first, firstLesson.subjectSpannable)
|
b.lessonBig.setText(R.string.home_timetable_lesson_first, firstLesson.subjectSpannable)
|
||||||
|
b.counter.visibility = View.VISIBLE
|
||||||
|
b.counter.text = firstLesson?.displayStartTime?.stringHM
|
||||||
firstLesson?.displayClassroom?.let {
|
firstLesson?.displayClassroom?.let {
|
||||||
b.classroom.visibility = View.VISIBLE
|
b.classroom.visibility = View.VISIBLE
|
||||||
b.classroom.text = it
|
b.classroom.text = it
|
||||||
@ -308,9 +317,8 @@ class HomeTimetableCard(
|
|||||||
val text = mutableListOf<CharSequence>(
|
val text = mutableListOf<CharSequence>(
|
||||||
activity.getString(R.string.home_timetable_later)
|
activity.getString(R.string.home_timetable_later)
|
||||||
)
|
)
|
||||||
var first = true
|
val nextLessons = lessons.drop(skipFirst + 1)
|
||||||
for (lesson in lessons) {
|
for (lesson in nextLessons) {
|
||||||
if (first) { first = false; continue }
|
|
||||||
text += listOf(
|
text += listOf(
|
||||||
lesson.displayStartTime?.stringHM,
|
lesson.displayStartTime?.stringHM,
|
||||||
lesson.subjectSpannable
|
lesson.subjectSpannable
|
||||||
@ -363,7 +371,10 @@ class HomeTimetableCard(
|
|||||||
b.progress.visibility = View.GONE
|
b.progress.visibility = View.GONE
|
||||||
b.counter.visibility = View.VISIBLE
|
b.counter.visibility = View.VISIBLE
|
||||||
val diff = counterStart - now
|
val diff = counterStart - now
|
||||||
b.counter.text = activity.timeTill(diff.toInt(), "\n", countInSeconds)
|
if (diff >= 60 * MINUTE)
|
||||||
|
b.counter.text = counterStart.stringHM
|
||||||
|
else
|
||||||
|
b.counter.text = activity.timeTill(diff.toInt(), "\n", countInSeconds)
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// the lesson is right now
|
// the lesson is right now
|
||||||
|
@ -20,6 +20,7 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.databinding.LoginActivityBinding
|
import pl.szczodrzynski.edziennik.databinding.LoginActivityBinding
|
||||||
import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar
|
import pl.szczodrzynski.edziennik.ui.error.ErrorSnackbar
|
||||||
|
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class LoginActivity : AppCompatActivity(), CoroutineScope {
|
class LoginActivity : AppCompatActivity(), CoroutineScope {
|
||||||
@ -30,8 +31,10 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
private val app: App by lazy { applicationContext as App }
|
private val app: App by lazy { applicationContext as App }
|
||||||
private lateinit var b: LoginActivityBinding
|
private lateinit var b: LoginActivityBinding
|
||||||
lateinit var navOptions: NavOptions
|
lateinit var navOptions: NavOptions
|
||||||
|
lateinit var navOptionsBuilder: NavOptions.Builder
|
||||||
val nav by lazy { Navigation.findNavController(this, R.id.nav_host_fragment) }
|
val nav by lazy { Navigation.findNavController(this, R.id.nav_host_fragment) }
|
||||||
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
||||||
|
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
||||||
|
|
||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
@ -85,12 +88,12 @@ class LoginActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
setTheme(R.style.AppTheme_Light)
|
setTheme(R.style.AppTheme_Light)
|
||||||
|
|
||||||
navOptions = NavOptions.Builder()
|
navOptionsBuilder = NavOptions.Builder()
|
||||||
.setEnterAnim(R.anim.slide_in_right)
|
.setEnterAnim(R.anim.slide_in_right)
|
||||||
.setExitAnim(R.anim.slide_out_left)
|
.setExitAnim(R.anim.slide_out_left)
|
||||||
.setPopEnterAnim(R.anim.slide_in_left)
|
.setPopEnterAnim(R.anim.slide_in_left)
|
||||||
.setPopExitAnim(R.anim.slide_out_right)
|
.setPopExitAnim(R.anim.slide_out_right)
|
||||||
.build()
|
navOptions = navOptionsBuilder.build()
|
||||||
|
|
||||||
b = LoginActivityBinding.inflate(layoutInflater)
|
b = LoginActivityBinding.inflate(layoutInflater)
|
||||||
setContentView(b.root)
|
setContentView(b.root)
|
||||||
|
@ -23,8 +23,8 @@ import androidx.fragment.app.Fragment
|
|||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import pl.szczodrzynski.edziennik.*
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.LoginChooserFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.*
|
import pl.szczodrzynski.edziennik.ext.*
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.sync.RegisterUnavailableDialog
|
||||||
@ -51,7 +51,8 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
private val job: Job = Job()
|
private val job: Job = Job()
|
||||||
override val coroutineContext: CoroutineContext
|
override val coroutineContext: CoroutineContext
|
||||||
get() = job + Dispatchers.Main
|
get() = job + Dispatchers.Main
|
||||||
|
private val manager
|
||||||
|
get() = app.permissionManager
|
||||||
// local/private variables go here
|
// local/private variables go here
|
||||||
|
|
||||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||||
@ -66,6 +67,11 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
if (!isAdded) return
|
if (!isAdded) return
|
||||||
|
|
||||||
|
val adapter = LoginChooserAdapter(activity, this::onLoginModeClicked)
|
||||||
|
if (!manager.isNotificationPermissionGranted) {
|
||||||
|
manager.requestNotificationsPermission(activity, 0, false){}
|
||||||
|
}
|
||||||
|
|
||||||
b.versionText.setText(
|
b.versionText.setText(
|
||||||
R.string.login_chooser_version_format,
|
R.string.login_chooser_version_format,
|
||||||
app.buildManager.versionName,
|
app.buildManager.versionName,
|
||||||
@ -73,10 +79,33 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
)
|
)
|
||||||
b.versionText.onClick {
|
b.versionText.onClick {
|
||||||
app.buildManager.showVersionDialog(activity)
|
app.buildManager.showVersionDialog(activity)
|
||||||
|
if (!App.devMode)
|
||||||
|
return@onClick
|
||||||
|
if (adapter.items.firstOrNull { it is LoginInfo.Register && it.internalName == "lab" } != null)
|
||||||
|
return@onClick
|
||||||
|
adapter.items.add(
|
||||||
|
index = 0,
|
||||||
|
element = LoginInfo.Register(
|
||||||
|
loginType = 999999,
|
||||||
|
internalName = "lab",
|
||||||
|
registerName = R.string.menu_lab,
|
||||||
|
registerLogo = R.drawable.face_2,
|
||||||
|
loginModes = listOf(
|
||||||
|
LoginInfo.Mode(
|
||||||
|
loginMode = 0,
|
||||||
|
name = 0,
|
||||||
|
icon = 0,
|
||||||
|
guideText = 0,
|
||||||
|
credentials = listOf(),
|
||||||
|
errorCodes = mapOf()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
adapter.notifyItemInserted(0)
|
||||||
|
b.list.smoothScrollToPosition(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
val adapter = LoginChooserAdapter(activity, this::onLoginModeClicked)
|
|
||||||
|
|
||||||
LoginInfo.chooserList = LoginInfo.chooserList
|
LoginInfo.chooserList = LoginInfo.chooserList
|
||||||
?: LoginInfo.list.toMutableList()
|
?: LoginInfo.list.toMutableList()
|
||||||
|
|
||||||
@ -164,7 +193,7 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
anim.fillAfter = true
|
anim.fillAfter = true
|
||||||
activity.getRootView().startAnimation(anim)
|
activity.getRootView().startAnimation(anim)
|
||||||
|
|
||||||
b.list.smoothScrollToPosition(0)
|
adapter.items.removeAll { it !is LoginInfo.Register }
|
||||||
adapter.items.add(
|
adapter.items.add(
|
||||||
LoginInfo.Register(
|
LoginInfo.Register(
|
||||||
loginType = 74,
|
loginType = 74,
|
||||||
@ -183,7 +212,8 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
adapter.notifyItemInserted(adapter.items.size - 1)
|
adapter.notifyDataSetChanged()
|
||||||
|
b.list.smoothScrollToPosition(adapter.items.size - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
when {
|
||||||
@ -216,6 +246,11 @@ class LoginChooserFragment : Fragment(), CoroutineScope {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (loginType.internalName == "lab") {
|
||||||
|
nav.navigate(R.id.labFragment, null, activity.navOptions)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!app.config.privacyPolicyAccepted) {
|
if (!app.config.privacyPolicyAccepted) {
|
||||||
MaterialAlertDialogBuilder(activity)
|
MaterialAlertDialogBuilder(activity)
|
||||||
.setTitle(R.string.privacy_policy)
|
.setTitle(R.string.privacy_policy)
|
||||||
|
@ -14,6 +14,8 @@ import android.widget.Toast
|
|||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.addTextChangedListener
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
|
import androidx.navigation.NavOptions
|
||||||
|
import androidx.navigation.navOptions
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import com.mikepenz.iconics.IconicsDrawable
|
import com.mikepenz.iconics.IconicsDrawable
|
||||||
@ -33,7 +35,6 @@ import pl.szczodrzynski.edziennik.ui.login.LoginInfo.BaseCredential
|
|||||||
import pl.szczodrzynski.edziennik.ui.login.LoginInfo.FormCheckbox
|
import pl.szczodrzynski.edziennik.ui.login.LoginInfo.FormCheckbox
|
||||||
import pl.szczodrzynski.edziennik.ui.login.LoginInfo.FormField
|
import pl.szczodrzynski.edziennik.ui.login.LoginInfo.FormField
|
||||||
import pl.szczodrzynski.navlib.colorAttr
|
import pl.szczodrzynski.navlib.colorAttr
|
||||||
import java.util.*
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
class LoginFormFragment : Fragment(), CoroutineScope {
|
class LoginFormFragment : Fragment(), CoroutineScope {
|
||||||
@ -63,8 +64,10 @@ class LoginFormFragment : Fragment(), CoroutineScope {
|
|||||||
get() = arguments?.getString("platformDescription")
|
get() = arguments?.getString("platformDescription")
|
||||||
private val platformFormFields
|
private val platformFormFields
|
||||||
get() = arguments?.getString("platformFormFields")?.split(";")
|
get() = arguments?.getString("platformFormFields")?.split(";")
|
||||||
private val platformRealmData
|
private val platformData
|
||||||
get() = arguments?.getString("platformRealmData")?.toJsonObject()
|
get() = arguments?.getString("platformData")?.toJsonObject()
|
||||||
|
private val platformStoreKey
|
||||||
|
get() = arguments?.getString("platformStoreKey")
|
||||||
|
|
||||||
override fun onCreateView(
|
override fun onCreateView(
|
||||||
inflater: LayoutInflater,
|
inflater: LayoutInflater,
|
||||||
@ -90,6 +93,11 @@ class LoginFormFragment : Fragment(), CoroutineScope {
|
|||||||
val loginMode = arguments?.getInt("loginMode") ?: return
|
val loginMode = arguments?.getInt("loginMode") ?: return
|
||||||
val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return
|
val mode = register.loginModes.firstOrNull { it.loginMode == loginMode } ?: return
|
||||||
|
|
||||||
|
if (mode.credentials.isEmpty()) {
|
||||||
|
login(loginType, loginMode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
b.title.setText(R.string.login_form_title_format, app.getString(register.registerName))
|
b.title.setText(R.string.login_form_title_format, app.getString(register.registerName))
|
||||||
b.subTitle.text = platformName ?: app.getString(mode.name)
|
b.subTitle.text = platformName ?: app.getString(mode.name)
|
||||||
b.text.text = platformGuideText ?: app.getString(mode.guideText)
|
b.text.text = platformGuideText ?: app.getString(mode.guideText)
|
||||||
@ -156,12 +164,12 @@ class LoginFormFragment : Fragment(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (credential.qrDecoderClass != null) {
|
if (credential.qrDecoderClass != null) {
|
||||||
|
b.textLayout.endIconMode = TextInputLayout.END_ICON_CUSTOM
|
||||||
b.textLayout.endIconDrawable = IconicsDrawable(activity).apply {
|
b.textLayout.endIconDrawable = IconicsDrawable(activity).apply {
|
||||||
icon = CommunityMaterial.Icon3.cmd_qrcode
|
icon = CommunityMaterial.Icon3.cmd_qrcode
|
||||||
sizeDp = 24
|
sizeDp = 24
|
||||||
colorAttr(activity, R.attr.colorOnBackground)
|
colorAttr(activity, R.attr.colorOnBackground)
|
||||||
}
|
}
|
||||||
b.textLayout.endIconMode = TextInputLayout.END_ICON_CUSTOM
|
|
||||||
b.textLayout.setEndIconOnClickListener {
|
b.textLayout.setEndIconOnClickListener {
|
||||||
scanQrCode(credential)
|
scanQrCode(credential)
|
||||||
}
|
}
|
||||||
@ -250,7 +258,10 @@ class LoginFormFragment : Fragment(), CoroutineScope {
|
|||||||
payload.putBoolean("fakeLogin", true)
|
payload.putBoolean("fakeLogin", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
payload.putBundle("webRealmData", platformRealmData?.toBundle())
|
if (platformStoreKey == null)
|
||||||
|
payload.putAll(platformData?.toBundle() ?: Bundle())
|
||||||
|
else
|
||||||
|
payload.putBundle(platformStoreKey, platformData?.toBundle())
|
||||||
|
|
||||||
var hasErrors = false
|
var hasErrors = false
|
||||||
credentials.forEach { (credential, b) ->
|
credentials.forEach { (credential, b) ->
|
||||||
@ -295,6 +306,14 @@ class LoginFormFragment : Fragment(), CoroutineScope {
|
|||||||
if (hasErrors)
|
if (hasErrors)
|
||||||
return
|
return
|
||||||
|
|
||||||
nav.navigate(R.id.loginProgressFragment, payload, activity.navOptions)
|
val navOptions =
|
||||||
|
if (credentials.isEmpty())
|
||||||
|
activity.navOptionsBuilder
|
||||||
|
.setPopUpTo(R.id.loginPlatformListFragment, inclusive = false)
|
||||||
|
.build()
|
||||||
|
else
|
||||||
|
activity.navOptions
|
||||||
|
|
||||||
|
nav.navigate(R.id.loginProgressFragment, payload, navOptions)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.ui.login
|
|||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import com.mikepenz.iconics.typeface.IIcon
|
import com.mikepenz.iconics.typeface.IIcon
|
||||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
@ -64,7 +65,6 @@ object LoginInfo {
|
|||||||
errorCodes = mapOf(
|
errorCodes = mapOf(
|
||||||
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED to R.string.login_error_account_not_activated,
|
ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED to R.string.login_error_account_not_activated,
|
||||||
ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password,
|
ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password,
|
||||||
ERROR_CAPTCHA_LIBRUS_PORTAL to R.string.error_3001_reason
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
/*Mode(
|
/*Mode(
|
||||||
@ -278,28 +278,6 @@ object LoginInfo {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
Register(
|
|
||||||
loginType = LOGIN_TYPE_EDUDZIENNIK,
|
|
||||||
internalName = "edudziennik",
|
|
||||||
registerName = R.string.login_type_edudziennik,
|
|
||||||
registerLogo = R.drawable.login_logo_edudziennik,
|
|
||||||
loginModes = listOf(
|
|
||||||
Mode(
|
|
||||||
loginMode = LOGIN_MODE_EDUDZIENNIK_WEB,
|
|
||||||
name = R.string.login_mode_edudziennik_web,
|
|
||||||
icon = R.drawable.login_mode_edudziennik_web,
|
|
||||||
hintText = R.string.login_mode_edudziennik_web_hint,
|
|
||||||
guideText = R.string.login_mode_edudziennik_web_guide,
|
|
||||||
credentials = listOf(
|
|
||||||
getEmailCredential("email"),
|
|
||||||
getPasswordCredential("password")
|
|
||||||
),
|
|
||||||
errorCodes = mapOf(
|
|
||||||
ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN to R.string.login_error_incorrect_login_or_password
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
),
|
|
||||||
Register(
|
Register(
|
||||||
loginType = LOGIN_TYPE_PODLASIE,
|
loginType = LOGIN_TYPE_PODLASIE,
|
||||||
internalName = "podlasie",
|
internalName = "podlasie",
|
||||||
@ -335,7 +313,24 @@ object LoginInfo {
|
|||||||
errorCodes = mapOf()
|
errorCodes = mapOf()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
),
|
||||||
|
Register(
|
||||||
|
loginType = LOGIN_TYPE_USOS,
|
||||||
|
internalName = "usos",
|
||||||
|
registerName = R.string.login_type_usos,
|
||||||
|
registerLogo = R.drawable.login_logo_usos,
|
||||||
|
loginModes = listOf(
|
||||||
|
Mode(
|
||||||
|
loginMode = LOGIN_MODE_USOS_OAUTH,
|
||||||
|
name = R.string.login_mode_usos_oauth,
|
||||||
|
icon = R.drawable.login_mode_usos_api,
|
||||||
|
guideText = R.string.login_mode_usos_oauth_guide,
|
||||||
|
isPlatformSelection = true,
|
||||||
|
credentials = listOf(),
|
||||||
|
errorCodes = mapOf(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -379,7 +374,8 @@ object LoginInfo {
|
|||||||
val icon: String,
|
val icon: String,
|
||||||
val screenshot: String?,
|
val screenshot: String?,
|
||||||
val formFields: List<String>,
|
val formFields: List<String>,
|
||||||
val realmData: RealmData
|
val data: JsonObject,
|
||||||
|
val storeKey: String?,
|
||||||
)
|
)
|
||||||
|
|
||||||
open class BaseCredential(
|
open class BaseCredential(
|
||||||
|
@ -68,7 +68,8 @@ class LoginPlatformListFragment : Fragment(), CoroutineScope {
|
|||||||
"platformName" to platform.name,
|
"platformName" to platform.name,
|
||||||
"platformDescription" to platform.description,
|
"platformDescription" to platform.description,
|
||||||
"platformFormFields" to platform.formFields.joinToString(";"),
|
"platformFormFields" to platform.formFields.joinToString(";"),
|
||||||
"platformRealmData" to app.gson.toJson(platform.realmData)
|
"platformData" to platform.data.toString(),
|
||||||
|
"platformStoreKey" to platform.storeKey,
|
||||||
), activity.navOptions)
|
), activity.navOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import org.greenrobot.eventbus.Subscribe
|
|||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_CAPTCHA_NEEDED
|
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUIRES_USER_ACTION
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_NO_ARGUMENTS
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_NO_ARGUMENTS
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
|
import pl.szczodrzynski.edziennik.data.api.events.ApiTaskErrorEvent
|
||||||
@ -29,6 +29,7 @@ import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding
|
import pl.szczodrzynski.edziennik.databinding.LoginProgressFragmentBinding
|
||||||
import pl.szczodrzynski.edziennik.ext.joinNotNullStrings
|
import pl.szczodrzynski.edziennik.ext.joinNotNullStrings
|
||||||
|
import pl.szczodrzynski.edziennik.utils.managers.UserActionManager
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
|
|
||||||
@ -137,14 +138,21 @@ class LoginProgressFragment : Fragment(), CoroutineScope {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
app.userActionManager.execute(activity, event.profileId, event.type, onSuccess = { code ->
|
val callback = UserActionManager.UserActionCallback(
|
||||||
args.putString("recaptchaCode", code)
|
onSuccess = { data ->
|
||||||
args.putLong("recaptchaTime", System.currentTimeMillis())
|
args.putAll(data)
|
||||||
doFirstLogin(args)
|
doFirstLogin(args)
|
||||||
}, onFailure = {
|
},
|
||||||
activity.error(ApiError(TAG, ERROR_CAPTCHA_NEEDED))
|
onFailure = {
|
||||||
nav.navigateUp()
|
activity.error(ApiError(TAG, ERROR_REQUIRES_USER_ACTION))
|
||||||
})
|
nav.navigateUp()
|
||||||
|
},
|
||||||
|
onCancel = {
|
||||||
|
nav.navigateUp()
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
app.userActionManager.execute(activity, event, callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStart() {
|
override fun onStart() {
|
||||||
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2022-10-15.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.ui.login.oauth
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.view.ViewGroup.LayoutParams.MATCH_PARENT
|
||||||
|
import android.webkit.WebView
|
||||||
|
import android.webkit.WebViewClient
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
|
class OAuthLoginActivity : AppCompatActivity() {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "OAuthLoginActivity"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var isSuccessful = false
|
||||||
|
|
||||||
|
@SuppressLint("SetJavaScriptEnabled")
|
||||||
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
super.onCreate(savedInstanceState)
|
||||||
|
|
||||||
|
setTitle(R.string.oauth_dialog_title)
|
||||||
|
|
||||||
|
val authorizeUrl = intent.getStringExtra("authorizeUrl") ?: return
|
||||||
|
val redirectUrl = intent.getStringExtra("redirectUrl") ?: return
|
||||||
|
|
||||||
|
val webView = WebView(this)
|
||||||
|
webView.webViewClient = object : WebViewClient() {
|
||||||
|
override fun onPageStarted(view: WebView, url: String, favicon: Bitmap?) {
|
||||||
|
d(TAG, "Navigating to $url")
|
||||||
|
if (url.startsWith(redirectUrl)) {
|
||||||
|
isSuccessful = true
|
||||||
|
EventBus.getDefault().post(OAuthLoginResult(
|
||||||
|
isError = false,
|
||||||
|
responseUrl = url,
|
||||||
|
))
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
webView.settings.javaScriptEnabled = true
|
||||||
|
webView.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||||
|
setContentView(webView)
|
||||||
|
|
||||||
|
webView.loadUrl(authorizeUrl)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onDestroy() {
|
||||||
|
super.onDestroy()
|
||||||
|
if (!isSuccessful)
|
||||||
|
EventBus.getDefault().post(OAuthLoginResult(
|
||||||
|
isError = false,
|
||||||
|
responseUrl = null,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user