mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-16 07:21:54 +02:00
Compare commits
168 Commits
Author | SHA1 | Date | |
---|---|---|---|
147f4c39e5 | |||
9e95d05182 | |||
9ccb6e0a24 | |||
92d7a46314 | |||
7aaefa977b | |||
530034d7da | |||
44647946e0 | |||
efd63797e4 | |||
74820fe67d | |||
e825af0ff0 | |||
256f6c8732 | |||
22abad35cc | |||
6a33088352 | |||
01c41645ab | |||
54f74d2a3c | |||
e0688fe79b | |||
36c7bb1127 | |||
045205754e | |||
e34e4d6906 | |||
481af64137 | |||
2b3a7f6b41 | |||
e3fe03c5fc | |||
9740e0b7bf | |||
58a26cc0c6 | |||
d201c0c448 | |||
359432d24d | |||
edf8ec20f0 | |||
3ad9e5da1f | |||
459bbf78b2 | |||
d0baf02750 | |||
a5bb7d9c6e | |||
a939d95ea3 | |||
4c081c970e | |||
b75ab76c2a | |||
9da6dbccb3 | |||
66444ae35b | |||
3e8b3de2b7 | |||
85ac5769a1 | |||
93e3d5994a | |||
0cf24c527b | |||
97c5acd6ba | |||
30aeb70647 | |||
b599d679c4 | |||
1eecd24d91 | |||
c698dfdb73 | |||
c7a44f5ced | |||
c8ee6ff1e7 | |||
552acd4043 | |||
ede101ea20 | |||
13c2640ed5 | |||
dd0739fd4b | |||
9023f13932 | |||
f8456fb087 | |||
9b48041cd9 | |||
46cecf3474 | |||
c27254bcad | |||
80333cdea4 | |||
6aee3ea420 | |||
a11a44b768 | |||
e869107101 | |||
5903bbe59d | |||
6c0ddd3e6d | |||
621a7ac642 | |||
e86b47fb1b | |||
98fb7ac8c9 | |||
f49e39e858 | |||
8fc57cd3f5 | |||
a9eda087e0 | |||
3f36a284ee | |||
1814fd67e1 | |||
54e49af943 | |||
d6a67a0da6 | |||
28725c6400 | |||
4fc965d970 | |||
2aaf713d58 | |||
c7d2ac4e3e | |||
ae20c30c88 | |||
aef3f66654 | |||
c7abde8f11 | |||
2fcff33bd6 | |||
b08e4c2d3d | |||
73ff09052c | |||
9649afd43f | |||
ed3a245b51 | |||
477730708f | |||
f39d0c595d | |||
46407f9647 | |||
6ecb97b87e | |||
ecdaaeae65 | |||
a0c302b663 | |||
b31039ecd9 | |||
5c84086f42 | |||
752cdfa8d6 | |||
8e3d404352 | |||
810cfd8092 | |||
bd2a9524c6 | |||
d780d5118d | |||
f1570b8eb9 | |||
de0f29a09e | |||
c0d11c91e3 | |||
22c540a3d4 | |||
b7e35d0322 | |||
7bcd6bf038 | |||
ea4591144b | |||
7627d184a2 | |||
076b485fda | |||
09cb97e367 | |||
4e1f2ed41a | |||
281b6a95ef | |||
e40871c0d0 | |||
b74eeed994 | |||
ccde482364 | |||
a02033d0f3 | |||
6c6bc89f57 | |||
1e3da45340 | |||
0d366adddb | |||
2c24eba46d | |||
7c6dbca986 | |||
33a8fa2a1e | |||
300e2c4bc2 | |||
f883318bd2 | |||
5460c1e2a0 | |||
137c975e81 | |||
001de4a88c | |||
5dcb3fd580 | |||
f13995aa5c | |||
e23deb5ca6 | |||
d688b379a2 | |||
d6a796e25e | |||
e02d3e571d | |||
907b75b22d | |||
c3660b5f80 | |||
7ff10df70c | |||
83e1b21ec3 | |||
deb54e4b24 | |||
48873caecc | |||
cadd1a3dbd | |||
f09f069b2c | |||
1fb5aaed5d | |||
65ba330d5f | |||
795317f13f | |||
031cc05209 | |||
0ac8e1d9c1 | |||
4389dc9d79 | |||
b13257cb78 | |||
fcffa2afeb | |||
3c2f85f263 | |||
0a2323acf3 | |||
45c2948ed1 | |||
f72a6103b5 | |||
9261848369 | |||
7f4e45c57c | |||
180154b684 | |||
a4f58eb19b | |||
fada483d55 | |||
3ae9ba3d61 | |||
15102fe818 | |||
8864bb2a5e | |||
ef1cdd5b20 | |||
35f4f34342 | |||
1a8134459a | |||
a6ce3a5068 | |||
328b20f78b | |||
771712da99 | |||
f685a4dceb | |||
e8dad29e5d | |||
27e49b10fd | |||
97dc8d12f1 |
16
.idea/codeStyles/Project.xml
generated
16
.idea/codeStyles/Project.xml
generated
@ -1,6 +1,10 @@
|
|||||||
<component name="ProjectCodeStyleConfiguration">
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
<code_scheme name="Project" version="173">
|
<code_scheme name="Project" version="173">
|
||||||
|
<JetCodeStyleSettings>
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</JetCodeStyleSettings>
|
||||||
<codeStyleSettings language="XML">
|
<codeStyleSettings language="XML">
|
||||||
|
<option name="FORCE_REARRANGE_MODE" value="1" />
|
||||||
<indentOptions>
|
<indentOptions>
|
||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
</indentOptions>
|
</indentOptions>
|
||||||
@ -11,7 +15,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>xmlns:android</NAME>
|
<NAME>xmlns:android</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -22,7 +25,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>xmlns:.*</NAME>
|
<NAME>xmlns:.*</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -34,7 +36,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>.*:id</NAME>
|
<NAME>.*:id</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -45,7 +46,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>.*:name</NAME>
|
<NAME>.*:name</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -56,7 +56,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>name</NAME>
|
<NAME>name</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -67,7 +66,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>style</NAME>
|
<NAME>style</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -78,7 +76,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>.*</NAME>
|
<NAME>.*</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
<XML_NAMESPACE>^$</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -90,7 +87,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>.*</NAME>
|
<NAME>.*</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
<XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -102,7 +98,6 @@
|
|||||||
<match>
|
<match>
|
||||||
<AND>
|
<AND>
|
||||||
<NAME>.*</NAME>
|
<NAME>.*</NAME>
|
||||||
<XML_ATTRIBUTE />
|
|
||||||
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
<XML_NAMESPACE>.*</XML_NAMESPACE>
|
||||||
</AND>
|
</AND>
|
||||||
</match>
|
</match>
|
||||||
@ -112,5 +107,8 @@
|
|||||||
</rules>
|
</rules>
|
||||||
</arrangement>
|
</arrangement>
|
||||||
</codeStyleSettings>
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="kotlin">
|
||||||
|
<option name="CODE_STYLE_DEFAULTS" value="KOTLIN_OFFICIAL" />
|
||||||
|
</codeStyleSettings>
|
||||||
</code_scheme>
|
</code_scheme>
|
||||||
</component>
|
</component>
|
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
5
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
17
.idea/compiler.xml
generated
Normal file
17
.idea/compiler.xml
generated
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="CompilerConfiguration">
|
||||||
|
<bytecodeTargetLevel target="1.7">
|
||||||
|
<module name="annotation" target="1.7" />
|
||||||
|
<module name="codegen" target="1.7" />
|
||||||
|
<module name="Szkolny.eu.agendacalendarview" target="11" />
|
||||||
|
<module name="Szkolny.eu.app" target="11" />
|
||||||
|
<module name="Szkolny.eu.cafebar" target="11" />
|
||||||
|
<module name="Szkolny.eu.material-about-library" target="11" />
|
||||||
|
<module name="Szkolny.eu.mhttp" target="11" />
|
||||||
|
<module name="Szkolny.eu.nachos" target="11" />
|
||||||
|
<module name="Szkolny.eu.szkolny-font" target="11" />
|
||||||
|
<module name="Szkolny.eu.wear" target="11" />
|
||||||
|
</bytecodeTargetLevel>
|
||||||
|
</component>
|
||||||
|
</project>
|
2
.idea/discord.xml
generated
2
.idea/discord.xml
generated
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="DiscordProjectSettings">
|
<component name="DiscordProjectSettings">
|
||||||
<option name="show" value="true" />
|
<option name="show" value="PROJECT_FILES" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectNotificationSettings">
|
<component name="ProjectNotificationSettings">
|
||||||
<option name="askShowProject" value="false" />
|
<option name="askShowProject" value="false" />
|
||||||
|
3
.idea/misc.xml
generated
3
.idea/misc.xml
generated
@ -11,7 +11,6 @@
|
|||||||
<item index="1" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
|
<item index="1" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
|
||||||
</list>
|
</list>
|
||||||
</component>
|
</component>
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="NullableNotNullManager">
|
<component name="NullableNotNullManager">
|
||||||
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
||||||
<option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" />
|
<option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" />
|
||||||
@ -51,7 +50,7 @@
|
|||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" default="false" project-jdk-name="1.8" project-jdk-type="JavaSDK">
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
<output url="file://$PROJECT_DIR$/build/classes" />
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectType">
|
<component name="ProjectType">
|
||||||
|
1
.idea/runConfigurations.xml
generated
1
.idea/runConfigurations.xml
generated
@ -3,6 +3,7 @@
|
|||||||
<component name="RunConfigurationProducerService">
|
<component name="RunConfigurationProducerService">
|
||||||
<option name="ignoredProducers">
|
<option name="ignoredProducers">
|
||||||
<set>
|
<set>
|
||||||
|
<option value="com.android.tools.idea.compose.preview.runconfiguration.ComposePreviewRunConfigurationProducer" />
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
|
||||||
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
|
||||||
|
@ -3,7 +3,7 @@ apply plugin: 'kotlin-android'
|
|||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'kotlin-android-extensions'
|
apply plugin: 'kotlin-android-extensions'
|
||||||
apply plugin: 'com.google.gms.google-services'
|
apply plugin: 'com.google.gms.google-services'
|
||||||
apply plugin: 'io.fabric'
|
apply plugin: 'com.google.firebase.crashlytics'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
signingConfigs {
|
signingConfigs {
|
||||||
@ -54,10 +54,11 @@ android {
|
|||||||
lintOptions {
|
lintOptions {
|
||||||
checkReleaseBuilds false
|
checkReleaseBuilds false
|
||||||
}
|
}
|
||||||
dataBinding {
|
buildFeatures {
|
||||||
enabled = true
|
dataBinding = true
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
|
coreLibraryDesugaringEnabled true
|
||||||
sourceCompatibility '1.8'
|
sourceCompatibility '1.8'
|
||||||
targetCompatibility '1.8'
|
targetCompatibility '1.8'
|
||||||
}
|
}
|
||||||
@ -75,6 +76,7 @@ android {
|
|||||||
version "3.10.2"
|
version "3.10.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ndkVersion '21.3.6528147'
|
||||||
}
|
}
|
||||||
|
|
||||||
/*task finalizeBundleDebug(type: Copy) {
|
/*task finalizeBundleDebug(type: Copy) {
|
||||||
@ -104,6 +106,8 @@ tasks.whenTaskAdded { task ->
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
|
|
||||||
|
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'
|
||||||
|
|
||||||
kapt "androidx.room:room-compiler:${versions.room}"
|
kapt "androidx.room:room-compiler:${versions.room}"
|
||||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
||||||
|
|
||||||
@ -114,7 +118,7 @@ dependencies {
|
|||||||
implementation "androidx.core:core-ktx:${versions.ktx}"
|
implementation "androidx.core:core-ktx:${versions.ktx}"
|
||||||
implementation "androidx.gridlayout:gridlayout:${versions.gridLayout}"
|
implementation "androidx.gridlayout:gridlayout:${versions.gridLayout}"
|
||||||
implementation "androidx.legacy:legacy-support-v4:${versions.legacy}"
|
implementation "androidx.legacy:legacy-support-v4:${versions.legacy}"
|
||||||
implementation "androidx.lifecycle:lifecycle-livedata:${versions.lifecycle}"
|
implementation "androidx.lifecycle:lifecycle-livedata-ktx:${versions.lifecycle}"
|
||||||
implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}"
|
implementation "androidx.recyclerview:recyclerview:${versions.recyclerView}"
|
||||||
implementation "androidx.room:room-runtime:${versions.room}"
|
implementation "androidx.room:room-runtime:${versions.room}"
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:${versions.kotlin}"
|
||||||
@ -137,7 +141,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation "cat.ereza:customactivityoncrash:2.2.0"
|
implementation "cat.ereza:customactivityoncrash:2.2.0"
|
||||||
implementation "com.applandeo:material-calendar-view:1.5.0"
|
implementation "com.applandeo:material-calendar-view:1.5.0"
|
||||||
implementation "com.crashlytics.sdk.android:crashlytics:2.10.1"
|
implementation 'com.google.firebase:firebase-crashlytics:17.3.1'
|
||||||
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
implementation "com.daimajia.swipelayout:library:1.2.0@aar"
|
||||||
implementation "com.evernote:android-job:1.2.6"
|
implementation "com.evernote:android-job:1.2.6"
|
||||||
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2"
|
implementation "com.github.antonKozyriatskyi:CircularProgressIndicator:1.2.2"
|
||||||
@ -145,7 +149,11 @@ dependencies {
|
|||||||
implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true}
|
implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true}
|
||||||
implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update
|
implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update
|
||||||
implementation "com.jaredrummler:colorpicker:1.0.2"
|
implementation "com.jaredrummler:colorpicker:1.0.2"
|
||||||
implementation "com.squareup.okhttp3:okhttp:3.12.2"
|
implementation("com.squareup.okhttp3:okhttp") {
|
||||||
|
version {
|
||||||
|
strictly "3.12.13"
|
||||||
|
}
|
||||||
|
}
|
||||||
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update
|
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update
|
||||||
implementation "com.wdullaer:materialdatetimepicker:4.1.2"
|
implementation "com.wdullaer:materialdatetimepicker:4.1.2"
|
||||||
implementation "com.yuyh.json:jsonviewer:1.0.6"
|
implementation "com.yuyh.json:jsonviewer:1.0.6"
|
||||||
@ -153,7 +161,7 @@ dependencies {
|
|||||||
implementation "me.grantland:autofittextview:0.2.1"
|
implementation "me.grantland:autofittextview:0.2.1"
|
||||||
implementation "me.leolin:ShortcutBadger:1.1.22@aar"
|
implementation "me.leolin:ShortcutBadger:1.1.22@aar"
|
||||||
implementation "org.greenrobot:eventbus:3.1.1"
|
implementation "org.greenrobot:eventbus:3.1.1"
|
||||||
implementation "org.jsoup:jsoup:1.10.1"
|
implementation "org.jsoup:jsoup:1.12.1"
|
||||||
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15"
|
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15"
|
||||||
//implementation "se.emilsjolander:stickylistheaders:2.7.0"
|
//implementation "se.emilsjolander:stickylistheaders:2.7.0"
|
||||||
implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar'
|
implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar'
|
||||||
@ -175,7 +183,7 @@ dependencies {
|
|||||||
|
|
||||||
//implementation "org.redundent:kotlin-xml-builder:1.5.3"
|
//implementation "org.redundent:kotlin-xml-builder:1.5.3"
|
||||||
|
|
||||||
implementation "io.github.wulkanowy:signer-android:0.1.1"
|
implementation 'com.github.wulkanowy.uonet-request-signer:hebe-jvm:a99ca50a31'
|
||||||
|
|
||||||
implementation "androidx.work:work-runtime-ktx:${versions.work}"
|
implementation "androidx.work:work-runtime-ktx:${versions.work}"
|
||||||
|
|
||||||
@ -199,8 +207,13 @@ dependencies {
|
|||||||
|
|
||||||
implementation 'com.google.android:flexbox:2.0.1'
|
implementation 'com.google.android:flexbox:2.0.1'
|
||||||
|
|
||||||
implementation 'com.qifan.powerpermission:powerpermission:1.0.0'
|
implementation 'com.qifan.powerpermission:powerpermission:1.3.0'
|
||||||
implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.0.0'
|
implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.3.0'
|
||||||
|
|
||||||
|
implementation 'com.github.kuba2k2.FSLogin:lib:2.0.0'
|
||||||
|
implementation 'pl.droidsonroids:jspoon:1.3.2'
|
||||||
|
implementation "com.squareup.retrofit2:converter-scalars:2.8.1"
|
||||||
|
implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
|
||||||
}
|
}
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -64,5 +64,9 @@
|
|||||||
|
|
||||||
-keep class pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing { public final byte[] pleaseStopRightNow(java.lang.String, long); }
|
-keep class pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing { public final byte[] pleaseStopRightNow(java.lang.String, long); }
|
||||||
|
|
||||||
-keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
|
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
|
||||||
-keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
|
-keepclassmembers class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
|
||||||
|
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo$Platform { *; }
|
||||||
|
|
||||||
|
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData { *; }
|
||||||
|
-keepclassmembernames class pl.szczodrzynski.fslogin.realm.RealmData$Type { *; }
|
||||||
|
BIN
app/sampledata/vulcan/edu.lublin.eu.png
Normal file
BIN
app/sampledata/vulcan/edu.lublin.eu.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.6 KiB |
@ -24,7 +24,6 @@
|
|||||||
android:icon="@mipmap/ic_launcher"
|
android:icon="@mipmap/ic_launcher"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:networkSecurityConfig="@xml/network_security_config"
|
android:networkSecurityConfig="@xml/network_security_config"
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme.Dark"
|
android:theme="@style/AppTheme.Dark"
|
||||||
android:usesCleartextTraffic="true"
|
android:usesCleartextTraffic="true"
|
||||||
@ -135,9 +134,6 @@
|
|||||||
android:configChanges="orientation|screenSize"
|
android:configChanges="orientation|screenSize"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/AppTheme.Light" />
|
android:theme="@style/AppTheme.Light" />
|
||||||
<activity android:name=".ui.modules.login.LoginLibrusCaptchaActivity"
|
|
||||||
android:theme="@android:style/Theme.Dialog"
|
|
||||||
android:excludeFromRecents="true"/>
|
|
||||||
<activity android:name=".ui.modules.home.CounterActivity"
|
<activity android:name=".ui.modules.home.CounterActivity"
|
||||||
android:theme="@style/AppTheme.Black" />
|
android:theme="@style/AppTheme.Black" />
|
||||||
<activity android:name=".ui.modules.feedback.FeedbackActivity"
|
<activity android:name=".ui.modules.feedback.FeedbackActivity"
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
<h3>Wersja 4.1, 2020-05-09</h3>
|
<h3>Wersja 4.6.1, 2021-03-04</h3>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Naprawiona synchronizacja Wiadomości w Librusie.</li>
|
<li>Przywrócono obsługę dziennika Librus Synergia.</li>
|
||||||
<li>Widok adresu dołączenia do lekcji online w kalendarzu (jeżeli nauczyciel wpisze adres).</li>
|
|
||||||
<li>Nowy moduł Frekwencji, obsługujący również lekcje zdalne.</li>
|
|
||||||
</ul>
|
</ul>
|
||||||
<br>
|
<br>
|
||||||
<br>
|
<br>
|
||||||
Dzięki za korzystanie ze Szkolnego!<br>
|
Dzięki za korzystanie ze Szkolnego!<br>
|
||||||
<i>© Kuba Szczodrzyński, Kacper Ziubryniewicz 2020</i>
|
<i>© Kuba Szczodrzyński, Kacper Ziubryniewicz 2021</i>
|
||||||
|
@ -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] = {
|
||||||
0xec, 0xc0, 0x3e, 0x4e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
0xdc, 0x61, 0x4d, 0x5b, 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);
|
||||||
|
|
||||||
|
@ -43,6 +43,7 @@ import pl.szczodrzynski.edziennik.sync.SyncWorker
|
|||||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
|
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity
|
||||||
import pl.szczodrzynski.edziennik.utils.*
|
import pl.szczodrzynski.edziennik.utils.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import pl.szczodrzynski.edziennik.utils.managers.*
|
import pl.szczodrzynski.edziennik.utils.managers.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
@ -56,8 +57,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
val profileId
|
val profileId
|
||||||
get() = profile.id
|
get() = profile.id
|
||||||
|
|
||||||
var devMode = false
|
|
||||||
var debugMode = false
|
var debugMode = false
|
||||||
|
var devMode = false
|
||||||
}
|
}
|
||||||
|
|
||||||
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
|
val notificationChannelsManager by lazy { NotificationChannelsManager(this) }
|
||||||
@ -101,12 +102,12 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
.followSslRedirects(true)
|
.followSslRedirects(true)
|
||||||
.retryOnConnectionFailure(true)
|
.retryOnConnectionFailure(true)
|
||||||
.cookieJar(cookieJar)
|
.cookieJar(cookieJar)
|
||||||
.connectTimeout(20, TimeUnit.SECONDS)
|
.connectTimeout(15, TimeUnit.SECONDS)
|
||||||
.writeTimeout(5, TimeUnit.SECONDS)
|
.writeTimeout(10, TimeUnit.SECONDS)
|
||||||
.readTimeout(10, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
builder.installHttpsSupport(this)
|
builder.installHttpsSupport(this)
|
||||||
|
|
||||||
if (debugMode || BuildConfig.DEBUG) {
|
if (devMode || BuildConfig.DEBUG) {
|
||||||
HyperLog.initialize(this)
|
HyperLog.initialize(this)
|
||||||
HyperLog.setLogLevel(Log.VERBOSE)
|
HyperLog.setLogLevel(Log.VERBOSE)
|
||||||
HyperLog.setLogFormat(DebugLogFormat(this))
|
HyperLog.setLogFormat(DebugLogFormat(this))
|
||||||
@ -161,7 +162,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
Iconics.registerFont(SzkolnyFont)
|
Iconics.registerFont(SzkolnyFont)
|
||||||
App.db = AppDb(this)
|
App.db = AppDb(this)
|
||||||
Themes.themeInt = config.ui.theme
|
Themes.themeInt = config.ui.theme
|
||||||
debugMode = config.debugMode
|
devMode = config.debugMode
|
||||||
MHttp.instance().customOkHttpClient(http)
|
MHttp.instance().customOkHttpClient(http)
|
||||||
|
|
||||||
if (!profileLoadById(config.lastProfileId)) {
|
if (!profileLoadById(config.lastProfileId)) {
|
||||||
@ -172,7 +173,9 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
setLanguage(it)
|
setLanguage(it)
|
||||||
}
|
}
|
||||||
|
|
||||||
devMode = BuildConfig.DEBUG
|
debugMode = BuildConfig.DEBUG
|
||||||
|
if (BuildConfig.DEBUG)
|
||||||
|
devMode = true
|
||||||
|
|
||||||
Signing.getCert(this)
|
Signing.getCert(this)
|
||||||
|
|
||||||
@ -182,7 +185,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
|
|
||||||
if (config.devModePassword != null)
|
if (config.devModePassword != null)
|
||||||
checkDevModePassword()
|
checkDevModePassword()
|
||||||
debugMode = devMode || config.debugMode
|
devMode = debugMode || config.debugMode
|
||||||
|
|
||||||
if (config.sync.enabled)
|
if (config.sync.enabled)
|
||||||
SyncWorker.scheduleNext(this@App, false)
|
SyncWorker.scheduleNext(this@App, false)
|
||||||
@ -255,6 +258,10 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
val pushMobidziennikApp = FirebaseApp.initializeApp(
|
val pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||||
this@App,
|
this@App,
|
||||||
FirebaseOptions.Builder()
|
FirebaseOptions.Builder()
|
||||||
|
.setProjectId("mobidziennik")
|
||||||
|
.setStorageBucket("mobidziennik.appspot.com")
|
||||||
|
.setDatabaseUrl("https://mobidziennik.firebaseio.com")
|
||||||
|
.setGcmSenderId("747285019373")
|
||||||
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
||||||
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
||||||
.build(),
|
.build(),
|
||||||
@ -264,6 +271,10 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
val pushLibrusApp = FirebaseApp.initializeApp(
|
val pushLibrusApp = FirebaseApp.initializeApp(
|
||||||
this@App,
|
this@App,
|
||||||
FirebaseOptions.Builder()
|
FirebaseOptions.Builder()
|
||||||
|
.setProjectId("synergiadru")
|
||||||
|
.setStorageBucket("synergiadru.appspot.com")
|
||||||
|
.setDatabaseUrl("https://synergiadru.firebaseio.com")
|
||||||
|
.setGcmSenderId("513056078587")
|
||||||
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
||||||
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
||||||
.build(),
|
.build(),
|
||||||
@ -273,19 +284,38 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
val pushVulcanApp = FirebaseApp.initializeApp(
|
val pushVulcanApp = FirebaseApp.initializeApp(
|
||||||
this@App,
|
this@App,
|
||||||
FirebaseOptions.Builder()
|
FirebaseOptions.Builder()
|
||||||
|
.setProjectId("dzienniczekplus")
|
||||||
|
.setStorageBucket("dzienniczekplus.appspot.com")
|
||||||
|
.setDatabaseUrl("https://dzienniczekplus.firebaseio.com")
|
||||||
|
.setGcmSenderId("987828170337")
|
||||||
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
||||||
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
|
.setApplicationId("1:987828170337:android:ac97431a0a4578c3")
|
||||||
.build(),
|
.build(),
|
||||||
"Vulcan"
|
"Vulcan"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val pushVulcanHebeApp = FirebaseApp.initializeApp(
|
||||||
|
this@App,
|
||||||
|
FirebaseOptions.Builder()
|
||||||
|
.setProjectId("dzienniczekplus")
|
||||||
|
.setStorageBucket("dzienniczekplus.appspot.com")
|
||||||
|
.setDatabaseUrl("https://dzienniczekplus.firebaseio.com")
|
||||||
|
.setGcmSenderId("987828170337")
|
||||||
|
.setApiKey("AIzaSyDW8MUtanHy64_I0oCpY6cOxB3jrvJd_iA")
|
||||||
|
.setApplicationId("1:987828170337:android:7e16404b9e5deaaa")
|
||||||
|
.build(),
|
||||||
|
"VulcanHebe"
|
||||||
|
)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
|
FirebaseInstanceId.getInstance().instanceId.addOnSuccessListener { instanceIdResult ->
|
||||||
val token = instanceIdResult.token
|
val token = instanceIdResult.token
|
||||||
|
d("Firebase", "Got App token: $token")
|
||||||
config.sync.tokenApp = token
|
config.sync.tokenApp = token
|
||||||
}
|
}
|
||||||
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
FirebaseInstanceId.getInstance(pushMobidziennikApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||||
val token = instanceIdResult.token
|
val token = instanceIdResult.token
|
||||||
|
d("Firebase", "Got Mobidziennik2 token: $token")
|
||||||
if (token != config.sync.tokenMobidziennik) {
|
if (token != config.sync.tokenMobidziennik) {
|
||||||
config.sync.tokenMobidziennik = token
|
config.sync.tokenMobidziennik = token
|
||||||
config.sync.tokenMobidziennikList = listOf()
|
config.sync.tokenMobidziennikList = listOf()
|
||||||
@ -293,6 +323,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
}
|
}
|
||||||
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
FirebaseInstanceId.getInstance(pushLibrusApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||||
val token = instanceIdResult.token
|
val token = instanceIdResult.token
|
||||||
|
d("Firebase", "Got Librus token: $token")
|
||||||
if (token != config.sync.tokenLibrus) {
|
if (token != config.sync.tokenLibrus) {
|
||||||
config.sync.tokenLibrus = token
|
config.sync.tokenLibrus = token
|
||||||
config.sync.tokenLibrusList = listOf()
|
config.sync.tokenLibrusList = listOf()
|
||||||
@ -300,11 +331,20 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
}
|
}
|
||||||
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
FirebaseInstanceId.getInstance(pushVulcanApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||||
val token = instanceIdResult.token
|
val token = instanceIdResult.token
|
||||||
|
d("Firebase", "Got Vulcan token: $token")
|
||||||
if (token != config.sync.tokenVulcan) {
|
if (token != config.sync.tokenVulcan) {
|
||||||
config.sync.tokenVulcan = token
|
config.sync.tokenVulcan = token
|
||||||
config.sync.tokenVulcanList = listOf()
|
config.sync.tokenVulcanList = listOf()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
FirebaseInstanceId.getInstance(pushVulcanHebeApp).instanceId.addOnSuccessListener { instanceIdResult ->
|
||||||
|
val token = instanceIdResult.token
|
||||||
|
d("Firebase", "Got VulcanHebe token: $token")
|
||||||
|
if (token != config.sync.tokenVulcanHebe) {
|
||||||
|
config.sync.tokenVulcanHebe = token
|
||||||
|
config.sync.tokenVulcanHebeList = listOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
|
FirebaseMessaging.getInstance().subscribeToTopic(packageName)
|
||||||
} catch (e: IllegalStateException) {
|
} catch (e: IllegalStateException) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
@ -345,6 +385,9 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
|
|||||||
if (!success) {
|
if (!success) {
|
||||||
EventBus.getDefault().post(ProfileListEmptyEvent())
|
EventBus.getDefault().post(ProfileListEmptyEvent())
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
onSuccess(profile)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fun profileSave() = profileSave(profile)
|
fun profileSave() = profileSave(profile)
|
||||||
|
@ -42,10 +42,10 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
|
|||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import com.google.android.gms.security.ProviderInstaller
|
import com.google.android.gms.security.ProviderInstaller
|
||||||
import com.google.android.material.button.MaterialButton
|
import com.google.android.material.button.MaterialButton
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
|
import com.google.gson.*
|
||||||
import com.google.gson.JsonArray
|
import com.google.gson.JsonArray
|
||||||
import com.google.gson.JsonElement
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import com.google.gson.JsonParser
|
|
||||||
import im.wangchao.mhttp.Response
|
import im.wangchao.mhttp.Response
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
@ -95,30 +95,30 @@ fun List<Teacher>.byNameFDotSpaceLast(nameFDotSpaceLast: String) = firstOrNull {
|
|||||||
|
|
||||||
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
||||||
|
|
||||||
fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (it.isJsonNull) null else it.asBoolean }
|
fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean }
|
||||||
fun JsonObject?.getString(key: String): String? = get(key)?.let { if (it.isJsonNull) null else it.asString }
|
fun JsonObject?.getString(key: String): String? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asString }
|
||||||
fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (it.isJsonNull) null else it.asInt }
|
fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt }
|
||||||
fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (it.isJsonNull) null else it.asLong }
|
fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong }
|
||||||
fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(it.isJsonNull) null else it.asFloat }
|
fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat }
|
||||||
fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(it.isJsonNull) null else it.asCharacter }
|
fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter }
|
||||||
fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
|
fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
|
||||||
fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
|
fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
|
||||||
|
|
||||||
fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (it.isJsonNull) defaultValue else it.asBoolean } ?: defaultValue
|
fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asBoolean } ?: defaultValue
|
||||||
fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (it.isJsonNull) defaultValue else it.asString } ?: defaultValue
|
fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asString } ?: defaultValue
|
||||||
fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (it.isJsonNull) defaultValue else it.asInt } ?: defaultValue
|
fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asInt } ?: defaultValue
|
||||||
fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (it.isJsonNull) defaultValue else it.asLong } ?: defaultValue
|
fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asLong } ?: defaultValue
|
||||||
fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(it.isJsonNull) defaultValue else it.asFloat } ?: defaultValue
|
fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asFloat } ?: defaultValue
|
||||||
fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(it.isJsonNull) defaultValue else it.asCharacter } ?: defaultValue
|
fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asCharacter } ?: defaultValue
|
||||||
fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonObject) it.asJsonObject else defaultValue } ?: defaultValue
|
fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonObject) it.asJsonObject else defaultValue } ?: defaultValue
|
||||||
fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonArray) it.asJsonArray else defaultValue } ?: defaultValue
|
fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonArray) it.asJsonArray else defaultValue } ?: defaultValue
|
||||||
|
|
||||||
fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asBoolean }
|
fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean }
|
||||||
fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asString }
|
fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asString }
|
||||||
fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asInt }
|
fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt }
|
||||||
fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asLong }
|
fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong }
|
||||||
fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asFloat }
|
fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat }
|
||||||
fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asCharacter }
|
fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter }
|
||||||
fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
|
fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
|
||||||
fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
|
fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
|
||||||
|
|
||||||
@ -298,7 +298,7 @@ fun colorFromCssName(name: String): Int {
|
|||||||
"orange" -> 0xffffa500
|
"orange" -> 0xffffa500
|
||||||
"black" -> 0xff000000
|
"black" -> 0xff000000
|
||||||
"white" -> 0xffffffff
|
"white" -> 0xffffffff
|
||||||
else -> -1
|
else -> -1L
|
||||||
}.toInt()
|
}.toInt()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -537,6 +537,12 @@ fun String.md5(): String {
|
|||||||
return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
|
return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun String.sha1Hex(): String {
|
||||||
|
val md = MessageDigest.getInstance("SHA-1")
|
||||||
|
md.update(toByteArray())
|
||||||
|
return md.digest().joinToString("") { "%02x".format(it) }
|
||||||
|
}
|
||||||
|
|
||||||
fun String.sha256(): ByteArray {
|
fun String.sha256(): ByteArray {
|
||||||
val md = MessageDigest.getInstance("SHA-256")
|
val md = MessageDigest.getInstance("SHA-256")
|
||||||
md.update(toByteArray())
|
md.update(toByteArray())
|
||||||
@ -672,6 +678,16 @@ fun TextView.setText(@StringRes resid: Int, vararg formatArgs: Any) {
|
|||||||
text = context.getString(resid, *formatArgs)
|
text = context.getString(resid, *formatArgs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MaterialAlertDialogBuilder.setTitle(@StringRes resid: Int, vararg formatArgs: Any): MaterialAlertDialogBuilder {
|
||||||
|
setTitle(context.getString(resid, *formatArgs))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
fun MaterialAlertDialogBuilder.setMessage(@StringRes resid: Int, vararg formatArgs: Any): MaterialAlertDialogBuilder {
|
||||||
|
setMessage(context.getString(resid, *formatArgs))
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
||||||
return JsonObject().apply {
|
return JsonObject().apply {
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
@ -686,6 +702,21 @@ fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun JsonObject.toBundle(): Bundle {
|
||||||
|
return Bundle().also {
|
||||||
|
for ((key, value) in this.entrySet()) {
|
||||||
|
when (value) {
|
||||||
|
is JsonObject -> it.putBundle(key, value.toBundle())
|
||||||
|
is JsonPrimitive -> when {
|
||||||
|
value.isString -> it.putString(key, value.asString)
|
||||||
|
value.isBoolean -> it.putBoolean(key, value.asBoolean)
|
||||||
|
value.isNumber -> it.putInt(key, value.asInt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun JsonArray(vararg properties: Any?): JsonArray {
|
fun JsonArray(vararg properties: Any?): JsonArray {
|
||||||
return JsonArray().apply {
|
return JsonArray().apply {
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
@ -1161,7 +1192,7 @@ fun Iterable<Float>.averageOrNull() = this.average().let { if (it.isNaN()) null
|
|||||||
fun String.copyToClipboard(context: Context) {
|
fun String.copyToClipboard(context: Context) {
|
||||||
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
val clipboard = context.getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
|
||||||
val clipData = ClipData.newPlainText("Tekst", this)
|
val clipData = ClipData.newPlainText("Tekst", this)
|
||||||
clipboard.primaryClip = clipData
|
clipboard.setPrimaryClip(clipData)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun TextView.getTextPosition(range: IntRange): Rect {
|
fun TextView.getTextPosition(range: IntRange): Rect {
|
||||||
@ -1245,3 +1276,5 @@ val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
|
|||||||
operator fun <K, V> Iterable<Pair<K, V>>.get(key: K): V? {
|
operator fun <K, V> Iterable<Pair<K, V>>.get(key: K): V? {
|
||||||
return firstOrNull { it.first == key }?.second
|
return firstOrNull { it.first == key }?.second
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
|
||||||
|
@ -38,16 +38,22 @@ 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_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.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.Update
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||||
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
import pl.szczodrzynski.edziennik.sync.UpdateWorker
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.RegisterUnavailableDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.ServerMessageDialog
|
||||||
|
import pl.szczodrzynski.edziennik.ui.dialogs.UpdateAvailableDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.event.EventManualDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
import pl.szczodrzynski.edziennik.ui.dialogs.settings.ProfileRemoveDialog
|
||||||
@ -59,6 +65,7 @@ import pl.szczodrzynski.edziennik.ui.modules.base.MainSnackbar
|
|||||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.debug.DebugFragment
|
import pl.szczodrzynski.edziennik.ui.modules.debug.DebugFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment
|
import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment
|
||||||
|
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||||
@ -227,7 +234,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
|
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class).withPopTo(DRAWER_ITEM_MESSAGES)
|
||||||
list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
|
list += NavTarget(TARGET_MESSAGES_COMPOSE, R.string.menu_message_compose, MessagesComposeFragment::class)
|
||||||
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
|
list += NavTarget(TARGET_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
|
||||||
if (App.debugMode) {
|
if (App.devMode) {
|
||||||
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
||||||
list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
|
list += NavTarget(TARGET_LAB, R.string.menu_lab, LabFragment::class)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_flask_outline)
|
.withIcon(CommunityMaterial.Icon.cmd_flask_outline)
|
||||||
@ -295,12 +302,21 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||||
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||||
|
|
||||||
if (BuildConfig.VERSION_NAME.contains("nightly")) {
|
when {
|
||||||
b.nightlyText.isVisible = true
|
BuildConfig.VERSION_NAME.contains("nightly") -> {
|
||||||
b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
|
b.nightlyText.isVisible = true
|
||||||
|
b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
|
||||||
|
}
|
||||||
|
BuildConfig.VERSION_NAME.contains("daily") -> {
|
||||||
|
b.nightlyText.isVisible = true
|
||||||
|
b.nightlyText.text = "Daily\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
|
||||||
|
}
|
||||||
|
BuildConfig.DEBUG -> {
|
||||||
|
b.nightlyText.isVisible = true
|
||||||
|
b.nightlyText.text = "Debug\n"+BuildConfig.VERSION_NAME
|
||||||
|
}
|
||||||
|
else -> b.nightlyText.isVisible = false
|
||||||
}
|
}
|
||||||
else
|
|
||||||
b.nightlyText.isVisible = false
|
|
||||||
|
|
||||||
navLoading = true
|
navLoading = true
|
||||||
|
|
||||||
@ -399,7 +415,20 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.db.profileDao().all.observe(this, Observer { profiles ->
|
app.db.profileDao().all.observe(this, Observer { profiles ->
|
||||||
drawer.setProfileList(profiles.filter { it.id >= 0 }.toMutableList())
|
val allArchived = profiles.all { it.archived }
|
||||||
|
drawer.setProfileList(profiles.filter { it.id >= 0 && (!it.archived || allArchived) }.toMutableList())
|
||||||
|
//prepend the archived profile if loaded
|
||||||
|
if (app.profile.archived && !allArchived) {
|
||||||
|
drawer.prependProfile(Profile(
|
||||||
|
id = app.profile.id,
|
||||||
|
loginStoreId = app.profile.loginStoreId,
|
||||||
|
loginStoreType = app.profile.loginStoreType,
|
||||||
|
name = app.profile.name,
|
||||||
|
subname = "Archiwum - ${app.profile.subname}"
|
||||||
|
).also {
|
||||||
|
it.archived = true
|
||||||
|
})
|
||||||
|
}
|
||||||
drawer.currentProfile = App.profileId
|
drawer.currentProfile = App.profileId
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -415,7 +444,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
})
|
})
|
||||||
|
|
||||||
b.swipeRefreshLayout.isEnabled = true
|
b.swipeRefreshLayout.isEnabled = true
|
||||||
b.swipeRefreshLayout.setOnRefreshListener { this.syncCurrentFeature() }
|
b.swipeRefreshLayout.setOnRefreshListener { launch { syncCurrentFeature() } }
|
||||||
b.swipeRefreshLayout.setColorSchemeResources(
|
b.swipeRefreshLayout.setColorSchemeResources(
|
||||||
R.color.md_blue_500,
|
R.color.md_blue_500,
|
||||||
R.color.md_amber_500,
|
R.color.md_amber_500,
|
||||||
@ -425,6 +454,23 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
SyncWorker.scheduleNext(app)
|
SyncWorker.scheduleNext(app)
|
||||||
UpdateWorker.scheduleNext(app)
|
UpdateWorker.scheduleNext(app)
|
||||||
|
|
||||||
|
// if loaded profile is archived, switch to the up-to-date version of it
|
||||||
|
if (app.profile.archived) {
|
||||||
|
launch {
|
||||||
|
if (app.profile.archiveId != null) {
|
||||||
|
val profile = withContext(Dispatchers.IO) {
|
||||||
|
app.db.profileDao().getNotArchivedOf(app.profile.archiveId!!)
|
||||||
|
}
|
||||||
|
if (profile != null)
|
||||||
|
loadProfile(profile)
|
||||||
|
else
|
||||||
|
loadProfile(0)
|
||||||
|
} else {
|
||||||
|
loadProfile(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// APP BACKGROUND
|
// APP BACKGROUND
|
||||||
if (app.config.ui.appBackground != null) {
|
if (app.config.ui.appBackground != null) {
|
||||||
try {
|
try {
|
||||||
@ -522,7 +568,7 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
.withIcon(CommunityMaterial.Icon2.cmd_help_circle_outline)
|
||||||
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
.withOnClickListener(View.OnClickListener { loadTarget(TARGET_FEEDBACK) })
|
||||||
)
|
)
|
||||||
if (App.debugMode) {
|
if (App.devMode) {
|
||||||
bottomSheet += BottomSheetPrimaryItem(false)
|
bottomSheet += BottomSheetPrimaryItem(false)
|
||||||
.withTitle(R.string.menu_debug)
|
.withTitle(R.string.menu_debug)
|
||||||
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
.withIcon(CommunityMaterial.Icon.cmd_android_studio)
|
||||||
@ -564,7 +610,66 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
|_____/ \__, |_| |_|\___|
|
|_____/ \__, |_| |_|\___|
|
||||||
__/ |
|
__/ |
|
||||||
|__*/
|
|__*/
|
||||||
fun syncCurrentFeature() {
|
suspend fun syncCurrentFeature() {
|
||||||
|
if (app.profile.archived) {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.profile_archived_title)
|
||||||
|
.setMessage(
|
||||||
|
R.string.profile_archived_text,
|
||||||
|
app.profile.studentSchoolYearStart,
|
||||||
|
app.profile.studentSchoolYearStart + 1
|
||||||
|
)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show()
|
||||||
|
swipeRefreshLayout.isRefreshing = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (app.profile.shouldArchive()) {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.profile_archiving_title)
|
||||||
|
.setMessage(
|
||||||
|
R.string.profile_archiving_format,
|
||||||
|
app.profile.dateYearEnd.formattedString
|
||||||
|
)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
if (app.profile.isBeforeYear()) {
|
||||||
|
MaterialAlertDialogBuilder(this)
|
||||||
|
.setTitle(R.string.profile_year_not_started_title)
|
||||||
|
.setMessage(
|
||||||
|
R.string.profile_year_not_started_format,
|
||||||
|
app.profile.dateSemester1Start.formattedString
|
||||||
|
)
|
||||||
|
.setPositiveButton(R.string.ok, null)
|
||||||
|
.show()
|
||||||
|
swipeRefreshLayout.isRefreshing = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
app.profile.registerName?.let { registerName ->
|
||||||
|
var status = app.config.sync.registerAvailability[registerName]
|
||||||
|
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
val api = SzkolnyApi(app)
|
||||||
|
api.runCatching(this@MainActivity) {
|
||||||
|
val availability = getRegisterAvailability()
|
||||||
|
app.config.sync.registerAvailability = availability
|
||||||
|
status = availability[registerName]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status?.available != true
|
||||||
|
|| status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
|
||||||
|
swipeRefreshLayout.isRefreshing = false
|
||||||
|
loadTarget(DRAWER_ITEM_HOME)
|
||||||
|
if (status != null)
|
||||||
|
RegisterUnavailableDialog(this, status!!)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
swipeRefreshLayout.isRefreshing = true
|
swipeRefreshLayout.isRefreshing = true
|
||||||
Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
|
Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
|
||||||
val fragmentParam = when (navTargetId) {
|
val fragmentParam = when (navTargetId) {
|
||||||
@ -581,6 +686,20 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
arguments = arguments
|
arguments = arguments
|
||||||
).enqueue(this)
|
).enqueue(this)
|
||||||
}
|
}
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
|
fun onUpdateEvent(event: Update) {
|
||||||
|
EventBus.getDefault().removeStickyEvent(event)
|
||||||
|
UpdateAvailableDialog(this, event)
|
||||||
|
}
|
||||||
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
|
fun onRegisterAvailabilityEvent(event: RegisterAvailabilityEvent) {
|
||||||
|
EventBus.getDefault().removeStickyEvent(event)
|
||||||
|
app.profile.registerName?.let { registerName ->
|
||||||
|
event.data[registerName]?.let {
|
||||||
|
RegisterUnavailableDialog(this, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onApiTaskStartedEvent(event: ApiTaskStartedEvent) {
|
fun onApiTaskStartedEvent(event: ApiTaskStartedEvent) {
|
||||||
swipeRefreshLayout.isRefreshing = true
|
swipeRefreshLayout.isRefreshing = true
|
||||||
@ -632,6 +751,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||||
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
|
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
|
||||||
EventBus.getDefault().removeStickyEvent(event)
|
EventBus.getDefault().removeStickyEvent(event)
|
||||||
|
if (event.error.errorCode == ERROR_VULCAN_API_DEPRECATED) {
|
||||||
|
if (event.error.profileId != App.profileId)
|
||||||
|
return
|
||||||
|
ErrorDetailsDialog(this, listOf(event.error))
|
||||||
|
}
|
||||||
navView.toolbar.apply {
|
navView.toolbar.apply {
|
||||||
subtitleFormat = R.string.toolbar_subtitle
|
subtitleFormat = R.string.toolbar_subtitle
|
||||||
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
||||||
@ -885,23 +1009,51 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
|
|||||||
|
|
||||||
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
||||||
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
||||||
fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
fun loadProfile(profile: Profile) = loadProfile(
|
||||||
|
profile,
|
||||||
|
navTargetId,
|
||||||
|
null,
|
||||||
|
if (app.profile.archived) app.profile.id else null
|
||||||
|
)
|
||||||
|
private fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
||||||
if (App.profileId == id) {
|
if (App.profileId == id) {
|
||||||
drawer.currentProfile = app.profile.id
|
drawer.currentProfile = app.profile.id
|
||||||
loadTarget(drawerSelection, arguments)
|
loadTarget(drawerSelection, arguments)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
val previousArchivedId = if (app.profile.archived) app.profile.id else null
|
||||||
app.profileLoad(id) {
|
app.profileLoad(id) {
|
||||||
MessagesFragment.pageSelection = -1
|
loadProfile(it, drawerSelection, arguments, previousArchivedId)
|
||||||
|
|
||||||
setDrawerItems()
|
|
||||||
// the drawer profile is updated automatically when the drawer item is clicked
|
|
||||||
// update it manually when switching profiles from other source
|
|
||||||
//if (drawer.currentProfile != app.profile.id)
|
|
||||||
drawer.currentProfile = app.profileId
|
|
||||||
loadTarget(drawerSelection, arguments)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private fun loadProfile(profile: Profile, drawerSelection: Int, arguments: Bundle?, previousArchivedId: Int?) {
|
||||||
|
App.profile = profile
|
||||||
|
MessagesFragment.pageSelection = -1
|
||||||
|
|
||||||
|
setDrawerItems()
|
||||||
|
|
||||||
|
if (previousArchivedId != null) {
|
||||||
|
// prevents accidentally removing the first item if the archived profile is not shown
|
||||||
|
drawer.removeProfileById(previousArchivedId)
|
||||||
|
}
|
||||||
|
if (profile.archived) {
|
||||||
|
drawer.prependProfile(Profile(
|
||||||
|
id = profile.id,
|
||||||
|
loginStoreId = profile.loginStoreId,
|
||||||
|
loginStoreType = profile.loginStoreType,
|
||||||
|
name = profile.name,
|
||||||
|
subname = "Archiwum - ${profile.subname}"
|
||||||
|
).also {
|
||||||
|
it.archived = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// the drawer profile is updated automatically when the drawer item is clicked
|
||||||
|
// update it manually when switching profiles from other source
|
||||||
|
//if (drawer.currentProfile != app.profile.id)
|
||||||
|
drawer.currentProfile = app.profileId
|
||||||
|
loadTarget(drawerSelection, arguments)
|
||||||
|
}
|
||||||
fun loadTarget(id: Int, arguments: Bundle? = null) {
|
fun loadTarget(id: Int, arguments: Bundle? = null) {
|
||||||
var loadId = id
|
var loadId = id
|
||||||
if (loadId == -1) {
|
if (loadId == -1) {
|
||||||
|
@ -105,6 +105,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
|||||||
get() { mWidgetConfigs = mWidgetConfigs ?: values.get("widgetConfigs", JsonObject()); return mWidgetConfigs ?: JsonObject() }
|
get() { mWidgetConfigs = mWidgetConfigs ?: values.get("widgetConfigs", JsonObject()); return mWidgetConfigs ?: JsonObject() }
|
||||||
set(value) { set("widgetConfigs", value); mWidgetConfigs = value }
|
set(value) { set("widgetConfigs", value); mWidgetConfigs = value }
|
||||||
|
|
||||||
|
private var mArchiverEnabled: Boolean? = null
|
||||||
|
var archiverEnabled: Boolean
|
||||||
|
get() { mArchiverEnabled = mArchiverEnabled ?: values.get("archiverEnabled", true); return mArchiverEnabled ?: true }
|
||||||
|
set(value) { set("archiverEnabled", value); mArchiverEnabled = value }
|
||||||
|
|
||||||
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
||||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||||
init {
|
init {
|
||||||
|
@ -4,12 +4,18 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.config
|
package pl.szczodrzynski.edziennik.config
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import com.google.gson.reflect.TypeToken
|
||||||
import pl.szczodrzynski.edziennik.config.utils.get
|
import pl.szczodrzynski.edziennik.config.utils.get
|
||||||
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
import pl.szczodrzynski.edziennik.config.utils.getIntList
|
||||||
import pl.szczodrzynski.edziennik.config.utils.set
|
import pl.szczodrzynski.edziennik.config.utils.set
|
||||||
|
import pl.szczodrzynski.edziennik.config.utils.setMap
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.response.RegisterAvailabilityStatus
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
|
||||||
class ConfigSync(private val config: Config) {
|
class ConfigSync(private val config: Config) {
|
||||||
|
private val gson = Gson()
|
||||||
|
|
||||||
private var mDontShowAppManagerDialog: Boolean? = null
|
private var mDontShowAppManagerDialog: Boolean? = null
|
||||||
var dontShowAppManagerDialog: Boolean
|
var dontShowAppManagerDialog: Boolean
|
||||||
get() { mDontShowAppManagerDialog = mDontShowAppManagerDialog ?: config.values.get("dontShowAppManagerDialog", false); return mDontShowAppManagerDialog ?: false }
|
get() { mDontShowAppManagerDialog = mDontShowAppManagerDialog ?: config.values.get("dontShowAppManagerDialog", false); return mDontShowAppManagerDialog ?: false }
|
||||||
@ -93,6 +99,10 @@ class ConfigSync(private val config: Config) {
|
|||||||
var tokenVulcan: String?
|
var tokenVulcan: String?
|
||||||
get() { mTokenVulcan = mTokenVulcan ?: config.values.get("tokenVulcan", null as String?); return mTokenVulcan }
|
get() { mTokenVulcan = mTokenVulcan ?: config.values.get("tokenVulcan", null as String?); return mTokenVulcan }
|
||||||
set(value) { config.set("tokenVulcan", value); mTokenVulcan = value }
|
set(value) { config.set("tokenVulcan", value); mTokenVulcan = value }
|
||||||
|
private var mTokenVulcanHebe: String? = null
|
||||||
|
var tokenVulcanHebe: String?
|
||||||
|
get() { mTokenVulcanHebe = mTokenVulcanHebe ?: config.values.get("tokenVulcanHebe", null as String?); return mTokenVulcanHebe }
|
||||||
|
set(value) { config.set("tokenVulcanHebe", value); mTokenVulcanHebe = value }
|
||||||
|
|
||||||
private var mTokenMobidziennikList: List<Int>? = null
|
private var mTokenMobidziennikList: List<Int>? = null
|
||||||
var tokenMobidziennikList: List<Int>
|
var tokenMobidziennikList: List<Int>
|
||||||
@ -106,4 +116,13 @@ class ConfigSync(private val config: Config) {
|
|||||||
var tokenVulcanList: List<Int>
|
var tokenVulcanList: List<Int>
|
||||||
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
|
get() { mTokenVulcanList = mTokenVulcanList ?: config.values.getIntList("tokenVulcanList", listOf()); return mTokenVulcanList ?: listOf() }
|
||||||
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
|
set(value) { config.set("tokenVulcanList", value); mTokenVulcanList = value }
|
||||||
|
private var mTokenVulcanHebeList: List<Int>? = null
|
||||||
|
var tokenVulcanHebeList: List<Int>
|
||||||
|
get() { mTokenVulcanHebeList = mTokenVulcanHebeList ?: config.values.getIntList("tokenVulcanHebeList", listOf()); return mTokenVulcanHebeList ?: listOf() }
|
||||||
|
set(value) { config.set("tokenVulcanHebeList", value); mTokenVulcanHebeList = value }
|
||||||
|
|
||||||
|
private var mRegisterAvailability: Map<String, RegisterAvailabilityStatus>? = null
|
||||||
|
var registerAvailability: Map<String, RegisterAvailabilityStatus>
|
||||||
|
get() { mRegisterAvailability = mRegisterAvailability ?: config.values.get("registerAvailability", null as String?)?.let { it -> gson.fromJson<Map<String, RegisterAvailabilityStatus>>(it, object: TypeToken<Map<String, RegisterAvailabilityStatus>>(){}.type) }; return mRegisterAvailability ?: mapOf() }
|
||||||
|
set(value) { config.setMap("registerAvailability", value); mRegisterAvailability = value }
|
||||||
}
|
}
|
||||||
|
@ -49,4 +49,9 @@ class ProfileConfigGrades(private val config: ProfileConfig) {
|
|||||||
var dontCountGrades: List<String>
|
var dontCountGrades: List<String>
|
||||||
get() { mDontCountGrades = mDontCountGrades ?: config.values.get("dontCountGrades", listOf()); return mDontCountGrades ?: listOf() }
|
get() { mDontCountGrades = mDontCountGrades ?: config.values.get("dontCountGrades", listOf()); return mDontCountGrades ?: listOf() }
|
||||||
set(value) { config.set("dontCountGrades", value); mDontCountGrades = value }
|
set(value) { config.set("dontCountGrades", value); mDontCountGrades = value }
|
||||||
|
|
||||||
|
private var mHideSticksFromOld: Boolean? = null
|
||||||
|
var hideSticksFromOld: Boolean
|
||||||
|
get() { mHideSticksFromOld = mHideSticksFromOld ?: config.values.get("hideSticksFromOld", false); return mHideSticksFromOld ?: false }
|
||||||
|
set(value) { config.set("hideSticksFromOld", value); mHideSticksFromOld = value }
|
||||||
}
|
}
|
||||||
|
@ -49,6 +49,9 @@ fun AbstractConfig.setIntList(key: String, value: List<Int>?) {
|
|||||||
fun AbstractConfig.setLongList(key: String, value: List<Long>?) {
|
fun AbstractConfig.setLongList(key: String, value: List<Long>?) {
|
||||||
set(key, value?.let { gson.toJson(it) })
|
set(key, value?.let { gson.toJson(it) })
|
||||||
}
|
}
|
||||||
|
fun <K, V> AbstractConfig.setMap(key: String, value: Map<K, V>?) {
|
||||||
|
set(key, value?.let { gson.toJson(it) })
|
||||||
|
}
|
||||||
|
|
||||||
fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
fun HashMap<String, String?>.get(key: String, default: String?): String? {
|
||||||
return this[key] ?: default
|
return this[key] ?: default
|
||||||
|
@ -24,14 +24,14 @@ const val FAKE_LIBRUS_ACCOUNTS = "/synergia_accounts.php"
|
|||||||
|
|
||||||
val LIBRUS_USER_AGENT = "${SYSTEM_USER_AGENT}LibrusMobileApp"
|
val LIBRUS_USER_AGENT = "${SYSTEM_USER_AGENT}LibrusMobileApp"
|
||||||
const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0"
|
const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0"
|
||||||
const val LIBRUS_CLIENT_ID = "6XPsKf10LPz1nxgHQLcvZ1KM48DYzlBAhxipaXY8"
|
const val LIBRUS_CLIENT_ID = "0RbsDOkV9tyKEQYzlLv5hs3DM1ukrynFI4p6C1Yc"
|
||||||
const val LIBRUS_REDIRECT_URL = "http://localhost/bar"
|
const val LIBRUS_REDIRECT_URL = "app://librus"
|
||||||
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/oauth2/authorize?client_id=$LIBRUS_CLIENT_ID&redirect_uri=$LIBRUS_REDIRECT_URL&response_type=code"
|
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/oauth2/authorize?client_id=$LIBRUS_CLIENT_ID&redirect_uri=$LIBRUS_REDIRECT_URL&response_type=code"
|
||||||
const val LIBRUS_LOGIN_URL = "https://portal.librus.pl/rodzina/login/action"
|
const val LIBRUS_LOGIN_URL = "https://portal.librus.pl/rodzina/login/action"
|
||||||
const val LIBRUS_TOKEN_URL = "https://portal.librus.pl/oauth2/access_token"
|
const val LIBRUS_TOKEN_URL = "https://portal.librus.pl/oauth2/access_token"
|
||||||
|
|
||||||
const val LIBRUS_ACCOUNT_URL = "/v2/SynergiaAccounts/fresh/" // + login
|
const val LIBRUS_ACCOUNT_URL = "/v3/SynergiaAccounts/fresh/" // + login
|
||||||
const val LIBRUS_ACCOUNTS_URL = "/v2/SynergiaAccounts"
|
const val LIBRUS_ACCOUNTS_URL = "/v3/SynergiaAccounts"
|
||||||
|
|
||||||
/** https://api.librus.pl/2.0 */
|
/** https://api.librus.pl/2.0 */
|
||||||
const val LIBRUS_API_URL = "https://api.librus.pl/2.0"
|
const val LIBRUS_API_URL = "https://api.librus.pl/2.0"
|
||||||
@ -57,6 +57,7 @@ const val LIBRUS_MESSAGES_URL = "https://wiadomosci.librus.pl/module"
|
|||||||
const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action="
|
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 IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT
|
const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT
|
||||||
const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik"
|
const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik"
|
||||||
@ -89,29 +90,39 @@ 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_API_USER_AGENT = "MobileUserAgent"
|
const val VULCAN_HEBE_USER_AGENT = "Dart/2.10 (dart:io)"
|
||||||
const val VULCAN_API_APP_NAME = "VULCAN-Android-ModulUcznia"
|
const val VULCAN_HEBE_APP_NAME = "DzienniczekPlus 2.0"
|
||||||
const val VULCAN_API_APP_VERSION = "19.4.1.436"
|
const val VULCAN_HEBE_APP_VERSION = "21.02.09 (G)"
|
||||||
const val VULCAN_API_PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06"
|
private const val VULCAN_API_DEVICE_NAME_PREFIX = "Szkolny.eu "
|
||||||
const val VULCAN_API_PASSWORD_FAKELOG = "012345678901234567890123456789AB"
|
private const val VULCAN_API_DEVICE_NAME_SUFFIX = " - nie usuwać"
|
||||||
val VULCAN_API_DEVICE_NAME = "Szkolny.eu ${Build.MODEL}"
|
val VULCAN_API_DEVICE_NAME by lazy {
|
||||||
|
val base = "$VULCAN_API_DEVICE_NAME_PREFIX${Build.MODEL}"
|
||||||
|
val baseMaxLength = 50 - VULCAN_API_DEVICE_NAME_SUFFIX.length
|
||||||
|
base.take(baseMaxLength) + VULCAN_API_DEVICE_NAME_SUFFIX
|
||||||
|
}
|
||||||
|
|
||||||
const val VULCAN_API_ENDPOINT_CERTIFICATE = "mobile-api/Uczen.v3.UczenStart/Certyfikat"
|
const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers"
|
||||||
const val VULCAN_API_ENDPOINT_STUDENT_LIST = "mobile-api/Uczen.v3.UczenStart/ListaUczniow"
|
const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get"
|
||||||
const val VULCAN_API_ENDPOINT_DICTIONARIES = "mobile-api/Uczen.v3.Uczen/Slowniki"
|
const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new"
|
||||||
const val VULCAN_API_ENDPOINT_TIMETABLE = "mobile-api/Uczen.v3.Uczen/PlanLekcjiZeZmianami"
|
const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe"
|
||||||
const val VULCAN_API_ENDPOINT_GRADES = "mobile-api/Uczen.v3.Uczen/Oceny"
|
const val VULCAN_HEBE_ENDPOINT_PUSH_ALL = "api/mobile/push/all"
|
||||||
const val VULCAN_API_ENDPOINT_GRADES_PROPOSITIONS = "mobile-api/Uczen.v3.Uczen/OcenyPodsumowanie"
|
const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule"
|
||||||
const val VULCAN_API_ENDPOINT_EVENTS = "mobile-api/Uczen.v3.Uczen/Sprawdziany"
|
const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes"
|
||||||
const val VULCAN_API_ENDPOINT_HOMEWORK = "mobile-api/Uczen.v3.Uczen/ZadaniaDomowe"
|
const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook"
|
||||||
const val VULCAN_API_ENDPOINT_NOTICES = "mobile-api/Uczen.v3.Uczen/UwagiUcznia"
|
const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam"
|
||||||
const val VULCAN_API_ENDPOINT_ATTENDANCE = "mobile-api/Uczen.v3.Uczen/Frekwencje"
|
const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade"
|
||||||
const val VULCAN_API_ENDPOINT_MESSAGES_RECEIVED = "mobile-api/Uczen.v3.Uczen/WiadomosciOdebrane"
|
const val VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY = "api/mobile/grade/summary"
|
||||||
const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/WiadomosciWyslane"
|
const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework"
|
||||||
const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci"
|
const val VULCAN_HEBE_ENDPOINT_NOTICES = "api/mobile/note"
|
||||||
const val VULCAN_API_ENDPOINT_MESSAGES_ADD = "mobile-api/Uczen.v3.Uczen/DodajWiadomosc"
|
const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson"
|
||||||
const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"
|
const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message"
|
||||||
const val VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/WiadomosciZalacznik"
|
const val VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS = "api/mobile/message/status"
|
||||||
const val VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ZadaniaDomoweZalacznik"
|
const val VULCAN_HEBE_ENDPOINT_MESSAGES_SEND = "api/mobile/message"
|
||||||
|
const val VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER = "api/mobile/school/lucky"
|
||||||
|
|
||||||
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
|
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
|
||||||
|
|
||||||
|
const val PODLASIE_API_VERSION = "1.0.62"
|
||||||
|
const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api"
|
||||||
|
const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia"
|
||||||
|
const val PODLASIE_API_LOGOUT_DEVICES_ENDPOINT = "/wyczyscUrzadzenia"
|
||||||
|
@ -148,40 +148,30 @@ const val ERROR_MOBIDZIENNIK_WEB_SERVER_PROBLEM = 218
|
|||||||
|
|
||||||
const val ERROR_LOGIN_VULCAN_INVALID_SYMBOL = 301
|
const val ERROR_LOGIN_VULCAN_INVALID_SYMBOL = 301
|
||||||
const val ERROR_LOGIN_VULCAN_INVALID_TOKEN = 302
|
const val ERROR_LOGIN_VULCAN_INVALID_TOKEN = 302
|
||||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN = 309
|
|
||||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING = 310
|
const val ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING = 310
|
||||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN_1_REMAINING = 311
|
const val ERROR_LOGIN_VULCAN_INVALID_PIN_1_REMAINING = 311
|
||||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN_2_REMAINING = 312
|
const val ERROR_LOGIN_VULCAN_INVALID_PIN_2_REMAINING = 312
|
||||||
const val ERROR_LOGIN_VULCAN_EXPIRED_TOKEN = 321
|
const val ERROR_LOGIN_VULCAN_EXPIRED_TOKEN = 321
|
||||||
const val ERROR_LOGIN_VULCAN_OTHER = 322
|
|
||||||
const val ERROR_LOGIN_VULCAN_ONLY_KINDERGARTEN = 330
|
|
||||||
const val ERROR_LOGIN_VULCAN_NO_PUPILS = 331
|
const val ERROR_LOGIN_VULCAN_NO_PUPILS = 331
|
||||||
const val ERROR_VULCAN_API_MAINTENANCE = 340
|
|
||||||
const val ERROR_VULCAN_API_BAD_REQUEST = 341
|
|
||||||
const val ERROR_VULCAN_API_OTHER = 342
|
|
||||||
const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343
|
const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343
|
||||||
|
const val ERROR_VULCAN_WEB_DATA_MISSING = 344
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
|
const val ERROR_VULCAN_WEB_429 = 345
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
|
const val ERROR_VULCAN_WEB_OTHER = 346
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 403
|
const val ERROR_VULCAN_WEB_NO_CERTIFICATE = 347
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE = 404
|
const val ERROR_VULCAN_WEB_NO_REGISTER = 348
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR = 405
|
const val ERROR_VULCAN_WEB_CERTIFICATE_EXPIRED = 349
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_OTHER = 410
|
const val ERROR_VULCAN_WEB_LOGGED_OUT = 350
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_API_NO_ACCESS = 411 /* {"d":{"__type":"mds.Web.mod_komunikator.WS_mod_wiadomosci+detailWiadomosci","Wiadomosc":{"_recordId":0,"DataNadania":null,"DataOdczytania":null,"Nadawca":null,"ListaOdbiorcow":[],"Tytul":null,"Text":null,"ListaZal":[]},"Bledy":{"__type":"mds.Module.Globalne+sBledy","CzyJestBlad":true,"ListaBledow":["Nie masz dostępu do tych zasobów!"],"ListaKodowBledow":[]},"czyJestWiecej":false}} */
|
const val ERROR_VULCAN_WEB_CERTIFICATE_POST_FAILED = 351
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION = 420
|
const val ERROR_VULCAN_WEB_GRADUATE_ACCOUNT = 352
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH = 421
|
const val ERROR_VULCAN_WEB_NO_SCHOOLS = 353
|
||||||
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER = 422
|
const val ERROR_VULCAN_HEBE_OTHER = 354
|
||||||
const val ERROR_IDZIENNIK_WEB_ACCESS_DENIED = 430
|
const val ERROR_VULCAN_HEBE_SIGNATURE_ERROR = 360
|
||||||
const val ERROR_IDZIENNIK_WEB_OTHER = 431
|
const val ERROR_VULCAN_HEBE_INVALID_PAYLOAD = 361
|
||||||
const val ERROR_IDZIENNIK_WEB_MAINTENANCE = 432
|
const val ERROR_VULCAN_HEBE_FIREBASE_ERROR = 362
|
||||||
const val ERROR_IDZIENNIK_WEB_SERVER_ERROR = 433
|
const val ERROR_VULCAN_HEBE_CERTIFICATE_GONE = 363
|
||||||
const val ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 434
|
const val ERROR_VULCAN_HEBE_SERVER_ERROR = 364
|
||||||
const val ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR = 440
|
const val ERROR_VULCAN_HEBE_ENTITY_NOT_FOUND = 365
|
||||||
const val ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA = 441
|
const val ERROR_VULCAN_API_DEPRECATED = 390
|
||||||
const val ERROR_IDZIENNIK_API_ACCESS_DENIED = 450
|
|
||||||
const val ERROR_IDZIENNIK_API_OTHER = 451
|
|
||||||
const val ERROR_IDZIENNIK_API_NO_REGISTER = 452
|
|
||||||
const val ERROR_IDZIENNIK_WEB_RECIPIENT_LIST_NO_PERMISSION = 453
|
|
||||||
|
|
||||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN = 501
|
const val ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN = 501
|
||||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER = 510
|
const val ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER = 510
|
||||||
@ -190,6 +180,12 @@ const val ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS = 521
|
|||||||
const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522
|
const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522
|
||||||
const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530
|
const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530
|
||||||
|
|
||||||
|
const val ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN = 601
|
||||||
|
const val ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT = 602
|
||||||
|
const val ERROR_PODLASIE_API_NO_TOKEN = 630
|
||||||
|
const val ERROR_PODLASIE_API_OTHER = 631
|
||||||
|
const val ERROR_PODLASIE_API_DATA_MISSING = 632
|
||||||
|
|
||||||
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
|
||||||
@ -199,16 +195,16 @@ const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903
|
|||||||
const val EXCEPTION_LIBRUS_API_REQUEST = 904
|
const val EXCEPTION_LIBRUS_API_REQUEST = 904
|
||||||
const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905
|
const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905
|
||||||
const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906
|
const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906
|
||||||
const val EXCEPTION_VULCAN_API_REQUEST = 907
|
|
||||||
const val EXCEPTION_MOBIDZIENNIK_WEB_FILE_REQUEST = 908
|
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_IDZIENNIK_WEB_REQUEST = 912
|
|
||||||
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
|
||||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
|
||||||
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
|
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
|
||||||
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
|
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_REQUEST = 932
|
||||||
|
const val EXCEPTION_PODLASIE_API_REQUEST = 940
|
||||||
|
const val EXCEPTION_VULCAN_HEBE_REQUEST = 950
|
||||||
|
|
||||||
const val LOGIN_NO_ARGUMENTS = 1201
|
const val LOGIN_NO_ARGUMENTS = 1201
|
||||||
|
@ -5,42 +5,37 @@
|
|||||||
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.edudziennik.login.EdudziennikLoginWeb
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLoginApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLoginWeb
|
|
||||||
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
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginSynergia
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginSynergia
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginApi2
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginApi2
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb
|
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb
|
||||||
|
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.vulcan.login.VulcanLoginApi
|
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.models.LoginMethod
|
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
|
||||||
|
|
||||||
// librus
|
// librus
|
||||||
// mobidziennik
|
// mobidziennik
|
||||||
// idziennik
|
// idziennik [*]
|
||||||
// vulcan
|
// vulcan
|
||||||
// mobireg
|
// mobireg
|
||||||
|
|
||||||
const val SYNERGIA_API_ENABLED = false
|
const val SYNERGIA_API_ENABLED = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const val LOGIN_TYPE_IDZIENNIK = 3
|
const val LOGIN_TYPE_IDZIENNIK = 3
|
||||||
|
|
||||||
const val LOGIN_TYPE_TEMPLATE = 21
|
const val LOGIN_TYPE_TEMPLATE = 21
|
||||||
|
|
||||||
// LOGIN MODES
|
// LOGIN MODES
|
||||||
const val LOGIN_MODE_IDZIENNIK_WEB = 0
|
|
||||||
|
|
||||||
const val LOGIN_MODE_TEMPLATE_WEB = 0
|
const val LOGIN_MODE_TEMPLATE_WEB = 0
|
||||||
|
|
||||||
// LOGIN METHODS
|
// LOGIN METHODS
|
||||||
const val LOGIN_METHOD_NOT_NEEDED = -1
|
const val LOGIN_METHOD_NOT_NEEDED = -1
|
||||||
const val LOGIN_METHOD_IDZIENNIK_WEB = 100
|
|
||||||
const val LOGIN_METHOD_IDZIENNIK_API = 200
|
|
||||||
const val LOGIN_METHOD_TEMPLATE_WEB = 100
|
const val LOGIN_METHOD_TEMPLATE_WEB = 100
|
||||||
const val LOGIN_METHOD_TEMPLATE_API = 200
|
const val LOGIN_METHOD_TEMPLATE_API = 200
|
||||||
|
|
||||||
@ -97,17 +92,18 @@ val mobidziennikLoginMethods = listOf(
|
|||||||
const val LOGIN_TYPE_VULCAN = 4
|
const val LOGIN_TYPE_VULCAN = 4
|
||||||
const val LOGIN_MODE_VULCAN_API = 0
|
const val LOGIN_MODE_VULCAN_API = 0
|
||||||
const val LOGIN_MODE_VULCAN_WEB = 1
|
const val LOGIN_MODE_VULCAN_WEB = 1
|
||||||
|
const val LOGIN_MODE_VULCAN_HEBE = 2
|
||||||
const val LOGIN_METHOD_VULCAN_WEB_MAIN = 100
|
const val LOGIN_METHOD_VULCAN_WEB_MAIN = 100
|
||||||
const val LOGIN_METHOD_VULCAN_WEB_NEW = 200
|
const val LOGIN_METHOD_VULCAN_WEB_NEW = 200
|
||||||
const val LOGIN_METHOD_VULCAN_WEB_OLD = 300
|
const val LOGIN_METHOD_VULCAN_WEB_OLD = 300
|
||||||
const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400
|
const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400
|
||||||
const val LOGIN_METHOD_VULCAN_API = 500
|
const val LOGIN_METHOD_VULCAN_HEBE = 600
|
||||||
val vulcanLoginMethods = listOf(
|
val vulcanLoginMethods = listOf(
|
||||||
/*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java)
|
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java)
|
||||||
.withIsPossible { _, _ -> false }
|
.withIsPossible { _, loginStore -> loginStore.hasLoginData("webHost") }
|
||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||||
|
|
||||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java)
|
/*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java)
|
||||||
.withIsPossible { _, _ -> false }
|
.withIsPossible { _, _ -> false }
|
||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },
|
||||||
|
|
||||||
@ -115,24 +111,15 @@ val vulcanLoginMethods = listOf(
|
|||||||
.withIsPossible { _, _ -> false }
|
.withIsPossible { _, _ -> false }
|
||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },*/
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },*/
|
||||||
|
|
||||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java)
|
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_HEBE, VulcanLoginHebe::class.java)
|
||||||
.withIsPossible { _, _ -> true }
|
.withIsPossible { _, loginStore ->
|
||||||
.withRequiredLoginMethod { _, loginStore ->
|
loginStore.mode != LOGIN_MODE_VULCAN_API
|
||||||
if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_NEW else LOGIN_METHOD_NOT_NEEDED
|
|
||||||
}
|
}
|
||||||
)
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||||
|
|
||||||
val idziennikLoginMethods = listOf(
|
|
||||||
LoginMethod(LOGIN_TYPE_IDZIENNIK, LOGIN_METHOD_IDZIENNIK_WEB, IdziennikLoginWeb::class.java)
|
|
||||||
.withIsPossible { _, _ -> true }
|
|
||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
|
||||||
|
|
||||||
LoginMethod(LOGIN_TYPE_IDZIENNIK, LOGIN_METHOD_IDZIENNIK_API, IdziennikLoginApi::class.java)
|
|
||||||
.withIsPossible { _, _ -> true }
|
|
||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_IDZIENNIK_WEB }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const val LOGIN_TYPE_EDUDZIENNIK = 5
|
const val LOGIN_TYPE_EDUDZIENNIK = 5
|
||||||
|
const val LOGIN_MODE_EDUDZIENNIK_WEB = 0
|
||||||
const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100
|
const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100
|
||||||
val edudziennikLoginMethods = listOf(
|
val edudziennikLoginMethods = listOf(
|
||||||
LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java)
|
LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java)
|
||||||
@ -140,6 +127,15 @@ val edudziennikLoginMethods = listOf(
|
|||||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const val LOGIN_TYPE_PODLASIE = 6
|
||||||
|
const val LOGIN_MODE_PODLASIE_API = 0
|
||||||
|
const val LOGIN_METHOD_PODLASIE_API = 100
|
||||||
|
val podlasieLoginMethods = listOf(
|
||||||
|
LoginMethod(LOGIN_TYPE_PODLASIE, LOGIN_METHOD_PODLASIE_API, PodlasieLoginApi::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 }
|
||||||
|
@ -12,6 +12,10 @@ object Regexes {
|
|||||||
"""color: (\w+);?""".toRegex()
|
"""color: (\w+);?""".toRegex()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val NOT_DIGITS by lazy {
|
||||||
|
"""[^0-9]""".toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
||||||
@ -40,7 +44,7 @@ object Regexes {
|
|||||||
"""\(([0-9A-ząęóżźńśłć]*?)\)$""".toRegex(DOT_MATCHES_ALL)
|
"""\(([0-9A-ząęóżźńśłć]*?)\)$""".toRegex(DOT_MATCHES_ALL)
|
||||||
}
|
}
|
||||||
val MOBIDZIENNIK_LUCKY_NUMBER by lazy {
|
val MOBIDZIENNIK_LUCKY_NUMBER by lazy {
|
||||||
"""class="szczesliwy_numerek".*>0*([0-9]+)(?:/0*[0-9]+)*</a>""".toRegex(DOT_MATCHES_ALL)
|
"""class="szczesliwy_numerek".*?>0?([0-9]+)/?0?([0-9]+)?</a>""".toRegex(DOT_MATCHES_ALL)
|
||||||
}
|
}
|
||||||
val MOBIDZIENNIK_CLASS_CALENDAR by lazy {
|
val MOBIDZIENNIK_CLASS_CALENDAR by lazy {
|
||||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||||
@ -80,6 +84,15 @@ object Regexes {
|
|||||||
val MOBIDZIENNIK_ATTENDANCE_ENTRIES by lazy {
|
val MOBIDZIENNIK_ATTENDANCE_ENTRIES by lazy {
|
||||||
"""font-size:.+?class=".*?">(.*?)</td>""".toRegex(DOT_MATCHES_ALL)
|
"""font-size:.+?class=".*?">(.*?)</td>""".toRegex(DOT_MATCHES_ALL)
|
||||||
}
|
}
|
||||||
|
val MOBIDZIENNIK_ATTENDANCE_COLUMNS by lazy {
|
||||||
|
"""<tr><td class="border-right1".+?/td>(.+?)</tr>""".toRegex(DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
val MOBIDZIENNIK_ATTENDANCE_COLUMN by lazy {
|
||||||
|
"""(<td.+?>)(.*?)</td>""".toRegex(DOT_MATCHES_ALL)
|
||||||
|
}
|
||||||
|
val MOBIDZIENNIK_ATTENDANCE_COLUMN_SPAN by lazy {
|
||||||
|
"""colspan="(\d+)"""".toRegex()
|
||||||
|
}
|
||||||
val MOBIDZIENNIK_ATTENDANCE_RANGE by lazy {
|
val MOBIDZIENNIK_ATTENDANCE_RANGE by lazy {
|
||||||
"""<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL)
|
"""<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL)
|
||||||
}
|
}
|
||||||
@ -142,12 +155,21 @@ object Regexes {
|
|||||||
val VULCAN_SHIFT_ANNOTATION by lazy {
|
val VULCAN_SHIFT_ANNOTATION by lazy {
|
||||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||||
}
|
}
|
||||||
|
val VULCAN_WEB_PERMISSIONS by lazy {
|
||||||
|
"""permissions: '([A-z0-9/=+\-_|]+?)'""".toRegex()
|
||||||
|
}
|
||||||
|
val VULCAN_WEB_SYMBOL_VALIDATE by lazy {
|
||||||
|
"""[A-z0-9]+""".toRegex(IGNORE_CASE)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
val LIBRUS_ATTACHMENT_KEY by lazy {
|
val LIBRUS_ATTACHMENT_KEY by lazy {
|
||||||
"""singleUseKey=([0-9A-z_]+)""".toRegex()
|
"""singleUseKey=([0-9A-z_]+)""".toRegex()
|
||||||
}
|
}
|
||||||
|
val LIBRUS_MESSAGE_ID by lazy {
|
||||||
|
"""/wiadomosci/[0-9]+/[0-9]+/([0-9]+?)/""".toRegex()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,29 +5,36 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik
|
package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import org.greenrobot.eventbus.EventBus
|
||||||
import pl.szczodrzynski.edziennik.R
|
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.edudziennik.Edudziennik
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.Idziennik
|
|
||||||
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.template.Template
|
import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
|
||||||
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.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
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.szkolny.SzkolnyApi
|
||||||
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
import pl.szczodrzynski.edziennik.data.api.task.IApiTask
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
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.entity.Teacher
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
|
||||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "EdziennikTask"
|
private const val TAG = "EdziennikTask"
|
||||||
|
|
||||||
|
var profile: Profile? = null
|
||||||
|
var loginStore: LoginStore? = null
|
||||||
|
|
||||||
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
|
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
|
||||||
fun sync() = EdziennikTask(-1, SyncRequest())
|
fun sync() = EdziennikTask(-1, SyncRequest())
|
||||||
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null, onlyEndpoints: List<Int>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments))
|
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null, onlyEndpoints: List<Int>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments))
|
||||||
@ -59,21 +66,64 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
// save the profile ID and name as the current task's
|
// save the profile ID and name as the current task's
|
||||||
taskName = app.getString(R.string.edziennik_notification_api_sync_title_format, profile.name)
|
taskName = app.getString(R.string.edziennik_notification_api_sync_title_format, profile.name)
|
||||||
}
|
}
|
||||||
|
EdziennikTask.profile = this.profile
|
||||||
|
EdziennikTask.loginStore = this.loginStore
|
||||||
}
|
}
|
||||||
|
|
||||||
private var edziennikInterface: EdziennikInterface? = null
|
private var edziennikInterface: EdziennikInterface? = null
|
||||||
|
|
||||||
internal fun run(app: App, taskCallback: EdziennikCallback) {
|
internal fun run(app: App, taskCallback: EdziennikCallback) {
|
||||||
if (profile?.archived == true) {
|
profile?.let { profile ->
|
||||||
taskCallback.onError(ApiError(TAG, ERROR_PROFILE_ARCHIVED))
|
if (profile.archived) {
|
||||||
return
|
d(TAG, "The profile $profileId is archived")
|
||||||
|
taskCallback.onError(ApiError(TAG, ERROR_PROFILE_ARCHIVED))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
else if (profile.shouldArchive()) {
|
||||||
|
d(TAG, "The profile $profileId's year ended on ${profile.dateYearEnd}, archiving")
|
||||||
|
ProfileArchiver(app, profile)
|
||||||
|
}
|
||||||
|
if (profile.isBeforeYear()) {
|
||||||
|
d(TAG, "The profile $profileId's school year has not started yet; aborting sync")
|
||||||
|
cancel()
|
||||||
|
taskCallback.onCompleted()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
profile.registerName?.let { registerName ->
|
||||||
|
var status = app.config.sync.registerAvailability[registerName]
|
||||||
|
if (status == null || status.nextCheckAt < currentTimeUnix()) {
|
||||||
|
val api = SzkolnyApi(app)
|
||||||
|
api.runCatching({
|
||||||
|
val availability = getRegisterAvailability()
|
||||||
|
app.config.sync.registerAvailability = availability
|
||||||
|
status = availability[registerName]
|
||||||
|
}, onError = {
|
||||||
|
taskCallback.onError(it.toApiError(TAG))
|
||||||
|
return
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status?.available != true
|
||||||
|
|| status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
|
||||||
|
if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
|
||||||
|
EventBus.getDefault().postSticky(
|
||||||
|
RegisterAvailabilityEvent(app.config.sync.registerAvailability)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
cancel()
|
||||||
|
taskCallback.onCompleted()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
edziennikInterface = when (loginStore.type) {
|
edziennikInterface = when (loginStore.type) {
|
||||||
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_IDZIENNIK -> Idziennik(app, profile, loginStore, taskCallback)
|
|
||||||
LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(app, profile, loginStore, taskCallback)
|
LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(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)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
@ -100,6 +150,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
|
d(TAG, "Task ${toString()} cancelling...")
|
||||||
edziennikInterface?.cancel()
|
edziennikInterface?.cancel()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2020-8-25.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.Intent
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class ProfileArchiver(val app: App, val profile: Profile) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "ProfileArchiver"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
if (profile.archiveId == null)
|
||||||
|
profile.archiveId = profile.id
|
||||||
|
d(TAG, "Processing ${profile.name}#${profile.id}, archiveId = ${profile.archiveId}")
|
||||||
|
|
||||||
|
profile.archived = true
|
||||||
|
app.db.profileDao().add(profile)
|
||||||
|
//app.db.metadataDao().setAllSeen(profile.id, true)
|
||||||
|
app.db.notificationDao().clear(profile.id)
|
||||||
|
app.db.endpointTimerDao().clear(profile.id)
|
||||||
|
d(TAG, "Archived profile ${profile.id} saved")
|
||||||
|
profile.archived = false
|
||||||
|
|
||||||
|
// guess the nearest school year
|
||||||
|
val today = Date.getToday()
|
||||||
|
profile.studentSchoolYearStart = when {
|
||||||
|
today.month <= profile.dateYearEnd.month -> today.year - 1
|
||||||
|
else -> today.year
|
||||||
|
}
|
||||||
|
|
||||||
|
// set default semester dates
|
||||||
|
profile.dateSemester1Start = Date(profile.studentSchoolYearStart, 9, 1)
|
||||||
|
profile.dateSemester2Start = Date(profile.studentSchoolYearStart + 1, 2, 1)
|
||||||
|
profile.dateYearEnd = Date(profile.studentSchoolYearStart + 1, 6, 30)
|
||||||
|
|
||||||
|
val oldId = profile.id
|
||||||
|
val newId = (app.db.profileDao().lastId ?: profile.id) + 1
|
||||||
|
profile.id = newId
|
||||||
|
profile.subname = "Nowy rok szkolny - ${profile.studentSchoolYearStart}"
|
||||||
|
profile.studentClassName = null
|
||||||
|
|
||||||
|
d(TAG, "New profile ID for ${profile.name}: ${profile.id}")
|
||||||
|
|
||||||
|
when (profile.loginStoreType) {
|
||||||
|
LOGIN_TYPE_LIBRUS -> {
|
||||||
|
profile.removeStudentData("isPremium")
|
||||||
|
profile.removeStudentData("pushDeviceId")
|
||||||
|
profile.removeStudentData("startPointsSemester1")
|
||||||
|
profile.removeStudentData("startPointsSemester2")
|
||||||
|
profile.removeStudentData("enablePointGrades")
|
||||||
|
profile.removeStudentData("enableDescriptiveGrades")
|
||||||
|
}
|
||||||
|
LOGIN_TYPE_MOBIDZIENNIK -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
LOGIN_TYPE_VULCAN -> {
|
||||||
|
// DataVulcan.isApiLoginValid() returns false so it will update the semester
|
||||||
|
profile.removeStudentData("currentSemesterEndDate")
|
||||||
|
profile.removeStudentData("studentSemesterId")
|
||||||
|
profile.removeStudentData("studentSemesterNumber")
|
||||||
|
profile.removeStudentData("semester1Id")
|
||||||
|
profile.removeStudentData("semester2Id")
|
||||||
|
profile.removeStudentData("studentClassId")
|
||||||
|
}
|
||||||
|
LOGIN_TYPE_IDZIENNIK -> {
|
||||||
|
profile.removeStudentData("schoolYearId")
|
||||||
|
}
|
||||||
|
LOGIN_TYPE_EDUDZIENNIK -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
LOGIN_TYPE_PODLASIE -> {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
d(TAG, "Processed student data: ${profile.studentData}")
|
||||||
|
|
||||||
|
app.db.profileDao().add(profile)
|
||||||
|
|
||||||
|
if (app.profileId == oldId) {
|
||||||
|
val intent = Intent(
|
||||||
|
Intent.ACTION_MAIN,
|
||||||
|
"profileId" to newId
|
||||||
|
)
|
||||||
|
app.sendBroadcast(intent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -110,7 +110,6 @@ class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStor
|
|||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
d(TAG, "Cancelled")
|
d(TAG, "Cancelled")
|
||||||
data.cancel()
|
data.cancel()
|
||||||
callback.onCompleted()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
|
@ -59,7 +59,7 @@ class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit
|
|||||||
profileList.add(profile)
|
profileList.add(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-14
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.helper
|
||||||
|
|
||||||
|
import im.wangchao.mhttp.Request
|
||||||
|
import im.wangchao.mhttp.Response
|
||||||
|
import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_FILE_DOWNLOAD
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.SYSTEM_USER_AGENT
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class DownloadAttachment(
|
||||||
|
fileUrl: String,
|
||||||
|
val onSuccess: (file: File) -> Unit,
|
||||||
|
val onProgress: (written: Long, total: Long) -> Unit,
|
||||||
|
val onError: (apiError: ApiError) -> Unit
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private const val TAG = "DownloadAttachment"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val targetFile = Utils.getStorageDir()
|
||||||
|
|
||||||
|
val callback = object : FileCallbackHandler(targetFile) {
|
||||||
|
override fun onSuccess(file: File?, response: Response?) {
|
||||||
|
if (file == null) {
|
||||||
|
onError(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(file)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
onError(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
||||||
|
try {
|
||||||
|
this@DownloadAttachment.onProgress(bytesWritten, bytesTotal)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
onError(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
||||||
|
.withThrowable(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url(fileUrl)
|
||||||
|
.userAgent(SYSTEM_USER_AGENT)
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
}
|
@ -1,175 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
|
|
||||||
|
|
||||||
import androidx.core.util.set
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_API
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Subject
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
|
||||||
|
|
||||||
class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
|
||||||
|
|
||||||
fun isWebLoginValid() = loginExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty() && webAuth.isNotNullNorEmpty()
|
|
||||||
fun isApiLoginValid() = apiExpiryTime-30 > currentTimeUnix() && apiBearer.isNotNullNorEmpty()
|
|
||||||
|
|
||||||
override fun satisfyLoginMethods() {
|
|
||||||
loginMethods.clear()
|
|
||||||
if (isWebLoginValid()) {
|
|
||||||
loginMethods += LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
app.cookieJar.set("iuczniowie.progman.pl", "ASP.NET_SessionId_iDziennik", webSessionId)
|
|
||||||
app.cookieJar.set("iuczniowie.progman.pl", ".ASPXAUTH", webAuth)
|
|
||||||
}
|
|
||||||
if (isApiLoginValid())
|
|
||||||
loginMethods += LOGIN_METHOD_IDZIENNIK_API
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun generateUserCode() = "$webSchoolName:$webUsername:$registerId"
|
|
||||||
|
|
||||||
private var mLoginExpiryTime: Long? = null
|
|
||||||
var loginExpiryTime: Long
|
|
||||||
get() { mLoginExpiryTime = mLoginExpiryTime ?: loginStore.getLoginData("loginExpiryTime", 0L); return mLoginExpiryTime ?: 0L }
|
|
||||||
set(value) { loginStore.putLoginData("loginExpiryTime", value); mLoginExpiryTime = value }
|
|
||||||
|
|
||||||
private var mApiExpiryTime: Long? = null
|
|
||||||
var apiExpiryTime: Long
|
|
||||||
get() { mApiExpiryTime = mApiExpiryTime ?: loginStore.getLoginData("apiExpiryTime", 0L); return mApiExpiryTime ?: 0L }
|
|
||||||
set(value) { loginStore.putLoginData("apiExpiryTime", value); mApiExpiryTime = value }
|
|
||||||
|
|
||||||
/* __ __ _
|
|
||||||
\ \ / / | |
|
|
||||||
\ \ /\ / /__| |__
|
|
||||||
\ \/ \/ / _ \ '_ \
|
|
||||||
\ /\ / __/ |_) |
|
|
||||||
\/ \/ \___|_._*/
|
|
||||||
private var mWebSchoolName: String? = null
|
|
||||||
var webSchoolName: String?
|
|
||||||
get() { mWebSchoolName = mWebSchoolName ?: loginStore.getLoginData("schoolName", null); return mWebSchoolName }
|
|
||||||
set(value) { loginStore.putLoginData("schoolName", value); mWebSchoolName = value }
|
|
||||||
private var mWebUsername: String? = null
|
|
||||||
var webUsername: String?
|
|
||||||
get() { mWebUsername = mWebUsername ?: loginStore.getLoginData("username", null); return mWebUsername }
|
|
||||||
set(value) { loginStore.putLoginData("username", value); mWebUsername = value }
|
|
||||||
private var mWebPassword: String? = null
|
|
||||||
var webPassword: String?
|
|
||||||
get() { mWebPassword = mWebPassword ?: loginStore.getLoginData("password", null); return mWebPassword }
|
|
||||||
set(value) { loginStore.putLoginData("password", value); mWebPassword = 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 mWebAuth: String? = null
|
|
||||||
var webAuth: String?
|
|
||||||
get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth }
|
|
||||||
set(value) { loginStore.putLoginData("webAuth", value); mWebAuth = value }
|
|
||||||
|
|
||||||
private var mWebSelectedRegister: Int? = null
|
|
||||||
var webSelectedRegister: Int
|
|
||||||
get() { mWebSelectedRegister = mWebSelectedRegister ?: loginStore.getLoginData("webSelectedRegister", 0); return mWebSelectedRegister ?: 0 }
|
|
||||||
set(value) { loginStore.putLoginData("webSelectedRegister", value); mWebSelectedRegister = value }
|
|
||||||
|
|
||||||
/* _
|
|
||||||
/\ (_)
|
|
||||||
/ \ _ __ _
|
|
||||||
/ /\ \ | '_ \| |
|
|
||||||
/ ____ \| |_) | |
|
|
||||||
/_/ \_\ .__/|_|
|
|
||||||
| |
|
|
||||||
|*/
|
|
||||||
private var mApiBearer: String? = null
|
|
||||||
var apiBearer: String?
|
|
||||||
get() { mApiBearer = mApiBearer ?: loginStore.getLoginData("apiBearer", null); return mApiBearer }
|
|
||||||
set(value) { loginStore.putLoginData("apiBearer", value); mApiBearer = 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 mRegisterId: Int? = null
|
|
||||||
var registerId: Int
|
|
||||||
get() { mRegisterId = mRegisterId ?: profile?.getStudentData("registerId", 0); return mRegisterId ?: 0 }
|
|
||||||
set(value) { profile?.putStudentData("registerId", value) ?: return; mRegisterId = value }
|
|
||||||
|
|
||||||
private var mSchoolYearId: Int? = null
|
|
||||||
var schoolYearId: Int
|
|
||||||
get() { mSchoolYearId = mSchoolYearId ?: profile?.getStudentData("schoolYearId", 0); return mSchoolYearId ?: 0 }
|
|
||||||
set(value) { profile?.putStudentData("schoolYearId", value) ?: return; mSchoolYearId = value }
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* _ _ _ _ _
|
|
||||||
| | | | | (_) |
|
|
||||||
| | | | |_ _| |___
|
|
||||||
| | | | __| | / __|
|
|
||||||
| |__| | |_| | \__ \
|
|
||||||
\____/ \__|_|_|__*/
|
|
||||||
fun getSubject(name: String, id: Long?, shortName: String): Subject {
|
|
||||||
var subject = if (id == null)
|
|
||||||
subjectList.singleOrNull { it.longName == name }
|
|
||||||
else
|
|
||||||
subjectList.singleOrNull { it.id == id }
|
|
||||||
|
|
||||||
if (subject == null) {
|
|
||||||
subject = Subject(profileId, id
|
|
||||||
?: name.crc16().toLong(), name, shortName)
|
|
||||||
subjectList[subject.id] = subject
|
|
||||||
}
|
|
||||||
return subject
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTeacher(firstName: String, lastName: String): Teacher {
|
|
||||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
|
||||||
return validateTeacher(teacher, firstName, lastName)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
|
||||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
|
||||||
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
|
||||||
val nameParts = nameLastFirst.split(" ")
|
|
||||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTeacherByFirstLast(nameFirstLast: String): Teacher {
|
|
||||||
val nameParts = nameFirstLast.split(" ")
|
|
||||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0], nameParts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTeacherByFDotLast(nameFDotLast: String): Teacher {
|
|
||||||
val nameParts = nameFDotLast.split(".")
|
|
||||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0][0], nameParts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getTeacherByFDotSpaceLast(nameFDotSpaceLast: String): Teacher {
|
|
||||||
val nameParts = nameFDotSpaceLast.split(".")
|
|
||||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0][0], nameParts[1])
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun validateTeacher(teacher: Teacher?, firstName: String, lastName: String): Teacher {
|
|
||||||
(teacher ?: Teacher(profileId, -1, firstName, lastName).apply {
|
|
||||||
id = shortName.crc16().toLong()
|
|
||||||
teacherList[id] = this
|
|
||||||
}).apply {
|
|
||||||
if (firstName.length > 1)
|
|
||||||
name = firstName
|
|
||||||
surname = lastName
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.App
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikData
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.firstlogin.IdziennikFirstLogin
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLogin
|
|
||||||
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.*
|
|
||||||
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 Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "Idziennik"
|
|
||||||
}
|
|
||||||
|
|
||||||
val internalErrorList = mutableListOf<Int>()
|
|
||||||
val data: DataIdziennik
|
|
||||||
private var afterLogin: (() -> Unit)? = null
|
|
||||||
|
|
||||||
init {
|
|
||||||
data = DataIdziennik(app, profile, loginStore).apply {
|
|
||||||
callback = wrapCallback(this@Idziennik.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(idziennikLoginMethods, IdziennikFeatures, 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(idziennikLoginMethods, it) }
|
|
||||||
afterLogin?.let { this.afterLogin = it }
|
|
||||||
IdziennikLogin(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() ?: IdziennikData(data) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getMessage(message: MessageFull) {
|
|
||||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
|
||||||
IdziennikWebGetMessage(data, message) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
|
||||||
login(LOGIN_METHOD_IDZIENNIK_API) {
|
|
||||||
IdziennikWebSendMessage(data, recipients, subject, text) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun markAllAnnouncementsAsRead() {}
|
|
||||||
override fun getAnnouncement(announcement: AnnouncementFull) {}
|
|
||||||
|
|
||||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
|
|
||||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
|
||||||
if (owner is Message) {
|
|
||||||
IdziennikWebGetAttachment(data, owner, attachmentId, attachmentName) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (owner is Event) {
|
|
||||||
IdziennikWebGetHomeworkAttachment(data, owner, attachmentId, attachmentName) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getRecipientList() {
|
|
||||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
|
||||||
IdziennikWebGetRecipientList(data) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getEvent(eventFull: EventFull) {
|
|
||||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
|
||||||
IdziennikWebGetHomework(data, eventFull) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun firstLogin() { IdziennikFirstLogin(data) { completed() } }
|
|
||||||
override fun cancel() {
|
|
||||||
d(TAG, "Cancelled")
|
|
||||||
data.cancel()
|
|
||||||
callback.onCompleted()
|
|
||||||
}
|
|
||||||
|
|
||||||
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_LOGIN_IDZIENNIK_WEB_NO_SESSION,
|
|
||||||
ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH,
|
|
||||||
ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER,
|
|
||||||
ERROR_IDZIENNIK_WEB_ACCESS_DENIED,
|
|
||||||
ERROR_IDZIENNIK_API_ACCESS_DENIED -> {
|
|
||||||
data.loginMethods.remove(LOGIN_METHOD_IDZIENNIK_WEB)
|
|
||||||
data.prepareFor(idziennikLoginMethods, LOGIN_METHOD_IDZIENNIK_WEB)
|
|
||||||
data.loginExpiryTime = 0
|
|
||||||
login()
|
|
||||||
}
|
|
||||||
ERROR_IDZIENNIK_API_NO_REGISTER -> {
|
|
||||||
data()
|
|
||||||
}
|
|
||||||
else -> callback.onError(apiError)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
|
||||||
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_TIMETABLE = 1030
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_HOMEWORK = 1061
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_MESSAGES_INBOX = 1110
|
|
||||||
const val ENDPOINT_IDZIENNIK_WEB_MESSAGES_SENT = 1120
|
|
||||||
const val ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER = 2010
|
|
||||||
const val ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX = 2110
|
|
||||||
const val ENDPOINT_IDZIENNIK_API_MESSAGES_SENT = 2120
|
|
||||||
|
|
||||||
val IdziennikFeatures = listOf(
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_TIMETABLE, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_GRADES, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_GRADES to LOGIN_METHOD_IDZIENNIK_WEB,
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_AGENDA, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_HOMEWORK, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_ATTENDANCE, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
|
||||||
|
|
||||||
/*Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_INBOX, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_MESSAGES_INBOX to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)).withPriority(2),
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_SENT, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_MESSAGES_SENT to LOGIN_METHOD_IDZIENNIK_WEB
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)).withPriority(2),*/
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_INBOX, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX to LOGIN_METHOD_IDZIENNIK_API
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_API)),
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_SENT, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT to LOGIN_METHOD_IDZIENNIK_API
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_API)),
|
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_LUCKY_NUMBER, listOf(
|
|
||||||
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER to LOGIN_METHOD_IDZIENNIK_API
|
|
||||||
), listOf(LOGIN_METHOD_IDZIENNIK_API))
|
|
||||||
)
|
|
@ -1,118 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-29.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonElement
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import com.google.gson.JsonParser
|
|
||||||
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.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import java.net.HttpURLConnection
|
|
||||||
|
|
||||||
open class IdziennikApi(open val data: DataIdziennik, open val lastSync: Long?) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "IdziennikApi"
|
|
||||||
}
|
|
||||||
|
|
||||||
val profileId
|
|
||||||
get() = data.profile?.id ?: -1
|
|
||||||
|
|
||||||
val profile
|
|
||||||
get() = data.profile
|
|
||||||
|
|
||||||
fun apiGet(tag: String, endpointTemplate: String, method: Int = GET, parameters: Map<String, Any> = emptyMap(), onSuccess: (json: JsonElement) -> Unit) {
|
|
||||||
val endpoint = endpointTemplate.replace("\$STUDENT_ID", data.studentId ?: "")
|
|
||||||
Utils.d(tag, "Request: Idziennik/API - $IDZIENNIK_API_URL/$endpoint")
|
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
if (text == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val json = try {
|
|
||||||
JsonParser().parse(text)
|
|
||||||
} catch (_: Exception) { null }
|
|
||||||
|
|
||||||
var error: String? = null
|
|
||||||
if (json == null) {
|
|
||||||
error = text
|
|
||||||
}
|
|
||||||
else if (json is JsonObject) {
|
|
||||||
error = if (response?.code() == 200) null else
|
|
||||||
json.getString("message") ?: json.toString()
|
|
||||||
}
|
|
||||||
error?.let { code ->
|
|
||||||
when (code) {
|
|
||||||
"Uczeń nie posiada aktywnej pozycji w dzienniku" -> ERROR_IDZIENNIK_API_NO_REGISTER
|
|
||||||
"Authorization has been denied for this request." -> ERROR_IDZIENNIK_API_ACCESS_DENIED
|
|
||||||
else -> ERROR_IDZIENNIK_API_OTHER
|
|
||||||
}.let { errorCode ->
|
|
||||||
data.error(ApiError(tag, errorCode)
|
|
||||||
.withApiResponse(text)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onSuccess(json!!)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_IDZIENNIK_API_REQUEST)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(e)
|
|
||||||
.withApiResponse(text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url("$IDZIENNIK_API_URL/$endpoint")
|
|
||||||
.userAgent(IDZIENNIK_API_USER_AGENT)
|
|
||||||
.addHeader("Authorization", "Bearer ${data.apiBearer}")
|
|
||||||
.apply {
|
|
||||||
when (method) {
|
|
||||||
GET -> get()
|
|
||||||
POST -> {
|
|
||||||
postJson()
|
|
||||||
val json = JsonObject()
|
|
||||||
parameters.map { (name, value) ->
|
|
||||||
when (value) {
|
|
||||||
is JsonObject -> json.add(name, value)
|
|
||||||
is JsonArray -> json.add(name, value)
|
|
||||||
is String -> json.addProperty(name, value)
|
|
||||||
is Int -> json.addProperty(name, value)
|
|
||||||
is Long -> json.addProperty(name, value)
|
|
||||||
is Float -> json.addProperty(name, value)
|
|
||||||
is Char -> json.addProperty(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setJsonBody(json)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.R
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiCurrentRegister
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiMessagesInbox
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiMessagesSent
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.*
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
|
|
||||||
class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikData"
|
|
||||||
}
|
|
||||||
|
|
||||||
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_IDZIENNIK_WEB_TIMETABLE -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
|
||||||
IdziennikWebTimetable(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_GRADES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
|
||||||
IdziennikWebGrades(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
|
||||||
IdziennikWebProposedGrades(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_EXAMS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
|
||||||
IdziennikWebExams(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_HOMEWORK -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
|
||||||
IdziennikWebHomework(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
|
||||||
IdziennikWebNotices(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
|
||||||
IdziennikWebAnnouncements(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
|
||||||
IdziennikWebAttendance(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
|
||||||
IdziennikApiCurrentRegister(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
|
||||||
IdziennikApiMessagesInbox(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
|
||||||
IdziennikApiMessagesSent(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
else -> onSuccess(endpointId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,238 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.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.callback.FileCallbackHandler
|
|
||||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebSwitchRegister
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
import java.io.File
|
|
||||||
import java.net.HttpURLConnection.HTTP_INTERNAL_ERROR
|
|
||||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
|
||||||
|
|
||||||
open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "IdziennikWeb"
|
|
||||||
}
|
|
||||||
|
|
||||||
val profileId
|
|
||||||
get() = data.profile?.id ?: -1
|
|
||||||
|
|
||||||
val profile
|
|
||||||
get() = data.profile
|
|
||||||
|
|
||||||
fun webApiGet(tag: String, endpoint: String, parameters: Map<String, Any> = emptyMap(), onSuccess: (json: JsonObject) -> Unit) {
|
|
||||||
d(tag, "Request: Idziennik/Web/API - $IDZIENNIK_WEB_URL/$endpoint")
|
|
||||||
|
|
||||||
val callback = object : JsonCallbackHandler() {
|
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
|
||||||
if (json == null && response?.parserErrorBody == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response?.code() == HTTP_INTERNAL_ERROR && endpoint == IDZIENNIK_WEB_GET_RECIPIENT_LIST) {
|
|
||||||
data.error(ApiError(tag, ERROR_IDZIENNIK_WEB_RECIPIENT_LIST_NO_PERMISSION)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(json))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response?.code() == HTTP_INTERNAL_ERROR && endpoint == IDZIENNIK_WEB_GRADES) {
|
|
||||||
// special override for accounts where displaying grades
|
|
||||||
// for another student requires switching it manually
|
|
||||||
if (data.registerId != data.webSelectedRegister) {
|
|
||||||
IdziennikWebSwitchRegister(data, data.registerId) {
|
|
||||||
webApiGet(tag, endpoint, parameters, onSuccess)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
when {
|
|
||||||
response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED
|
|
||||||
response?.code() == HTTP_INTERNAL_ERROR -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
|
||||||
response?.parserErrorBody != null -> when {
|
|
||||||
response.parserErrorBody.contains("Identyfikator zgłoszenia") -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
|
||||||
response.parserErrorBody.contains("Hasło dostępu do systemu wygasło") -> ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED
|
|
||||||
response.parserErrorBody.contains("Trwają prace konserwacyjne") -> ERROR_IDZIENNIK_WEB_MAINTENANCE
|
|
||||||
else -> ERROR_IDZIENNIK_WEB_OTHER
|
|
||||||
}
|
|
||||||
else -> null
|
|
||||||
}?.let { errorCode ->
|
|
||||||
data.error(ApiError(TAG, errorCode)
|
|
||||||
.withApiResponse(json?.toString() ?: response?.parserErrorBody)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json == null) {
|
|
||||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onSuccess(json)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_IDZIENNIK_WEB_API_REQUEST)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(e)
|
|
||||||
.withApiResponse(json))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url("$IDZIENNIK_WEB_URL/$endpoint")
|
|
||||||
.userAgent(IDZIENNIK_USER_AGENT)
|
|
||||||
.postJson()
|
|
||||||
.apply {
|
|
||||||
val json = JsonObject()
|
|
||||||
parameters.map { (name, value) ->
|
|
||||||
when (value) {
|
|
||||||
is JsonObject -> json.add(name, value)
|
|
||||||
is JsonArray -> json.add(name, value)
|
|
||||||
is String -> json.addProperty(name, value)
|
|
||||||
is Int -> json.addProperty(name, value)
|
|
||||||
is Long -> json.addProperty(name, value)
|
|
||||||
is Float -> json.addProperty(name, value)
|
|
||||||
is Char -> json.addProperty(name, value)
|
|
||||||
is Boolean -> json.addProperty(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
setJsonBody(json)
|
|
||||||
}
|
|
||||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
|
||||||
.allowErrorCode(HTTP_INTERNAL_ERROR)
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun webGet(tag: String, endpoint: String, parameters: Map<String, Any> = emptyMap(), onSuccess: (text: String) -> Unit) {
|
|
||||||
d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
|
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
if (text == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!text.contains("czyWyswietlicDostepMobilny")) {
|
|
||||||
when {
|
|
||||||
text.contains("Identyfikator zgłoszenia") -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
|
||||||
text.contains("Hasło dostępu do systemu wygasło") -> ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED
|
|
||||||
text.contains("Trwają prace konserwacyjne") -> ERROR_IDZIENNIK_WEB_MAINTENANCE
|
|
||||||
else -> ERROR_IDZIENNIK_WEB_OTHER
|
|
||||||
}.let { errorCode ->
|
|
||||||
data.error(ApiError(TAG, errorCode)
|
|
||||||
.withApiResponse(text)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onSuccess(text)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_IDZIENNIK_WEB_REQUEST)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(e)
|
|
||||||
.withApiResponse(text))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url("$IDZIENNIK_WEB_URL/$endpoint")
|
|
||||||
.userAgent(IDZIENNIK_USER_AGENT)
|
|
||||||
.apply {
|
|
||||||
if (parameters.isEmpty()) get()
|
|
||||||
else post()
|
|
||||||
|
|
||||||
parameters.map { (name, value) ->
|
|
||||||
addParameter(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun webGetFile(tag: String, endpoint: String, targetFile: File, parameters: Map<String, Any>,
|
|
||||||
onSuccess: (file: File) -> Unit, onProgress: (written: Long, total: Long) -> Unit) {
|
|
||||||
|
|
||||||
d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
|
|
||||||
|
|
||||||
val callback = object : FileCallbackHandler(targetFile) {
|
|
||||||
override fun onSuccess(file: File?, response: Response?) {
|
|
||||||
if (file == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onSuccess(file)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_FILE_REQUEST)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
|
|
||||||
try {
|
|
||||||
onProgress(bytesWritten, bytesTotal)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_FILE_REQUEST)
|
|
||||||
.withThrowable(e))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url("$IDZIENNIK_WEB_URL/$endpoint")
|
|
||||||
.userAgent(IDZIENNIK_USER_AGENT)
|
|
||||||
.apply {
|
|
||||||
parameters.forEach { (k, v) -> addParameter(k, v) }
|
|
||||||
}
|
|
||||||
.contentType("application/x-www-form-urlencoded")
|
|
||||||
.post()
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,92 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-29.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.DAY
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_CURRENT_REGISTER
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.getInt
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
|
||||||
|
|
||||||
class IdziennikApiCurrentRegister(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikApi(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikApiCurrentRegister"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
apiGet(TAG, IDZIENNIK_API_CURRENT_REGISTER) { json ->
|
|
||||||
if (json !is JsonObject) {
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER)
|
|
||||||
return@apiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
var nextSync = System.currentTimeMillis() + 14*DAY*1000
|
|
||||||
|
|
||||||
val settings = json.getJsonObject("ustawienia")?.apply {
|
|
||||||
getString("poczatekSemestru1")?.let { profile?.dateSemester1Start = Date.fromY_m_d(it) }
|
|
||||||
getString("koniecSemestru1")?.let { profile?.dateSemester2Start = Date.fromY_m_d(it).stepForward(0, 0, 1) }
|
|
||||||
getString("koniecSemestru2")?.let { profile?.dateYearEnd = Date.fromY_m_d(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getInt("szczesliwyNumerek")?.let { luckyNumber ->
|
|
||||||
val luckyNumberDate = Date.getToday()
|
|
||||||
settings.getString("godzinaPublikacjiSzczesliwegoLosu")
|
|
||||||
?.let { Time.fromH_m(it) }
|
|
||||||
?.let { publishTime ->
|
|
||||||
val now = Time.getNow()
|
|
||||||
if (publishTime.value < 150000 && now.value < publishTime.value) {
|
|
||||||
nextSync = luckyNumberDate.combineWith(publishTime)
|
|
||||||
luckyNumberDate.stepForward(0, 0, -1) // the lucky number is still for yesterday
|
|
||||||
}
|
|
||||||
else if (publishTime.value >= 150000 && now.value > publishTime.value) {
|
|
||||||
luckyNumberDate.stepForward(0, 0, 1) // the lucky number is already for tomorrow
|
|
||||||
nextSync = luckyNumberDate.combineWith(publishTime)
|
|
||||||
}
|
|
||||||
else if (publishTime.value < 150000) {
|
|
||||||
nextSync = luckyNumberDate
|
|
||||||
.clone()
|
|
||||||
.stepForward(0, 0, 1)
|
|
||||||
.combineWith(publishTime)
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
nextSync = luckyNumberDate.combineWith(publishTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val luckyNumberObject = LuckyNumber(
|
|
||||||
profileId = data.profileId,
|
|
||||||
date = luckyNumberDate,
|
|
||||||
number = luckyNumber
|
|
||||||
)
|
|
||||||
|
|
||||||
data.luckyNumberList.add(luckyNumberObject)
|
|
||||||
data.metadataList.add(
|
|
||||||
Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_LUCKY_NUMBER,
|
|
||||||
luckyNumberObject.date.value.toLong(),
|
|
||||||
true,
|
|
||||||
data.profile?.empty ?: false
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER, syncAt = nextSync)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,99 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-30.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_MESSAGES_INBOX
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.*
|
|
||||||
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.getBoolean
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikApi(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikApiMessagesInbox"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
apiGet(TAG, IDZIENNIK_API_MESSAGES_INBOX) { json ->
|
|
||||||
if (json !is JsonArray) {
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX)
|
|
||||||
return@apiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.asJsonObjectList().forEach { jMessage ->
|
|
||||||
val subject = jMessage.getString("tytul") ?: ""
|
|
||||||
if (subject.contains("(") && subject.startsWith("iDziennik - "))
|
|
||||||
return@forEach
|
|
||||||
if (subject.startsWith("Uwaga dla ucznia (klasa:"))
|
|
||||||
return@forEach
|
|
||||||
|
|
||||||
val messageIdStr = jMessage.getString("id")
|
|
||||||
val messageId = crc32((messageIdStr + "0").toByteArray())
|
|
||||||
|
|
||||||
var body = "[META:$messageIdStr;-1]"
|
|
||||||
body += jMessage.getString("tresc")?.replace("\n".toRegex(), "<br>")
|
|
||||||
|
|
||||||
val readDate = if (jMessage.getBoolean("odczytana") == true) Date.fromIso(jMessage.getString("wersjaRekordu")) else 0
|
|
||||||
val sentDate = Date.fromIso(jMessage.getString("dataWyslania"))
|
|
||||||
|
|
||||||
val sender = jMessage.getAsJsonObject("nadawca")
|
|
||||||
var firstName = sender.getString("imie")
|
|
||||||
var lastName = sender.getString("nazwisko")
|
|
||||||
if (firstName.isNullOrEmpty() || lastName.isNullOrEmpty()) {
|
|
||||||
firstName = "usunięty"
|
|
||||||
lastName = "użytkownik"
|
|
||||||
}
|
|
||||||
val rTeacher = data.getTeacher(
|
|
||||||
firstName,
|
|
||||||
lastName
|
|
||||||
)
|
|
||||||
rTeacher.loginId = /*sender.getString("id") + ":" + */sender.getString("usr")
|
|
||||||
rTeacher.setTeacherType(Teacher.TYPE_OTHER)
|
|
||||||
|
|
||||||
val message = Message(
|
|
||||||
profileId = profileId,
|
|
||||||
id = messageId,
|
|
||||||
type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
|
|
||||||
subject = subject,
|
|
||||||
body = body,
|
|
||||||
senderId = rTeacher.id,
|
|
||||||
addedDate = sentDate
|
|
||||||
)
|
|
||||||
|
|
||||||
val messageRecipient = MessageRecipient(
|
|
||||||
profileId,
|
|
||||||
-1 /* me */,
|
|
||||||
-1,
|
|
||||||
readDate,
|
|
||||||
/*messageId*/ messageId
|
|
||||||
)
|
|
||||||
|
|
||||||
data.messageList.add(message)
|
|
||||||
data.messageRecipientList.add(messageRecipient)
|
|
||||||
data.setSeenMetadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_MESSAGE,
|
|
||||||
message.id,
|
|
||||||
readDate > 0,
|
|
||||||
readDate > 0 || profile?.empty ?: false
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-30.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import pl.szczodrzynski.edziennik.DAY
|
|
||||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
|
||||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_MESSAGES_SENT
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
|
||||||
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.utils.Utils.crc32
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikApi(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikApiMessagesSent"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
apiGet(TAG, IDZIENNIK_API_MESSAGES_SENT) { json ->
|
|
||||||
if (json !is JsonArray) {
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT)
|
|
||||||
return@apiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.asJsonObjectList()?.forEach { jMessage ->
|
|
||||||
val messageIdStr = jMessage.get("id").asString
|
|
||||||
val messageId = crc32((messageIdStr + "1").toByteArray())
|
|
||||||
|
|
||||||
val subject = jMessage.get("tytul").asString
|
|
||||||
|
|
||||||
var body = "[META:$messageIdStr;-1]"
|
|
||||||
body += jMessage.get("tresc").asString.replace("\n".toRegex(), "<br>")
|
|
||||||
|
|
||||||
val sentDate = Date.fromIso(jMessage.get("dataWyslania").asString)
|
|
||||||
|
|
||||||
val message = Message(
|
|
||||||
profileId = profileId,
|
|
||||||
id = messageId,
|
|
||||||
type = TYPE_SENT,
|
|
||||||
subject = subject,
|
|
||||||
body = body,
|
|
||||||
senderId = null,
|
|
||||||
addedDate = sentDate
|
|
||||||
)
|
|
||||||
|
|
||||||
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
|
|
||||||
val recipient = recipientEl.asJsonObject
|
|
||||||
var firstName = recipient.get("imie").asString
|
|
||||||
var lastName = recipient.get("nazwisko").asString
|
|
||||||
if (firstName.isEmpty() || lastName.isEmpty()) {
|
|
||||||
firstName = "usunięty"
|
|
||||||
lastName = "użytkownik"
|
|
||||||
}
|
|
||||||
val rTeacher = data.getTeacher(firstName, lastName)
|
|
||||||
rTeacher.loginId = /*recipient.get("id").asString + ":" + */recipient.get("usr").asString
|
|
||||||
|
|
||||||
val messageRecipient = MessageRecipient(
|
|
||||||
profileId,
|
|
||||||
rTeacher.id,
|
|
||||||
-1,
|
|
||||||
-1,
|
|
||||||
/*messageId*/ messageId
|
|
||||||
)
|
|
||||||
data.messageRecipientIgnoreList.add(messageRecipient)
|
|
||||||
}
|
|
||||||
|
|
||||||
data.messageList.add(message)
|
|
||||||
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import com.google.gson.JsonArray
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_ANNOUNCEMENTS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
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.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.getLong
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikWebAnnouncements(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebAnnouncements"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
val param = JsonObject()
|
|
||||||
param.add("parametryFiltrow", JsonArray())
|
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_ANNOUNCEMENTS, mapOf(
|
|
||||||
"uczenId" to (data.studentId ?: ""),
|
|
||||||
"param" to param
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
for (jAnnouncementEl in json.getAsJsonArray("ListK")) {
|
|
||||||
val jAnnouncement = jAnnouncementEl.asJsonObject
|
|
||||||
// jAnnouncement
|
|
||||||
val announcementId = jAnnouncement.getLong("Id") ?: -1
|
|
||||||
|
|
||||||
val rTeacher = data.getTeacherByFirstLast(jAnnouncement.getString("Autor") ?: "")
|
|
||||||
val addedDate = jAnnouncement.getString("DataDodania")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull() ?: System.currentTimeMillis()
|
|
||||||
val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) }
|
|
||||||
|
|
||||||
val announcementObject = Announcement(
|
|
||||||
profileId = profileId,
|
|
||||||
id = announcementId,
|
|
||||||
subject = jAnnouncement.get("Temat").asString,
|
|
||||||
text = jAnnouncement.get("Tresc").asString,
|
|
||||||
startDate = startDate,
|
|
||||||
endDate = null,
|
|
||||||
teacherId = rTeacher.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
data.announcementList.add(announcementObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_ANNOUNCEMENT,
|
|
||||||
announcementObject.id,
|
|
||||||
profile?.empty ?: false,
|
|
||||||
profile?.empty ?: false
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,180 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.crc16
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_ATTENDANCE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ATTENDANCE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_BELATED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT_CUSTOM
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.getInt
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
|
||||||
|
|
||||||
class IdziennikWebAttendance(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebAttendance"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var attendanceYear = Date.getToday().year
|
|
||||||
private var attendanceMonth = Date.getToday().month
|
|
||||||
private var attendancePrevMonthChecked = false
|
|
||||||
|
|
||||||
init {
|
|
||||||
getAttendance()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getAttendance() {
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_ATTENDANCE, mapOf(
|
|
||||||
"idPozDziennika" to data.registerId,
|
|
||||||
"mc" to attendanceMonth,
|
|
||||||
"rok" to attendanceYear,
|
|
||||||
"dataTygodnia" to ""
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) {
|
|
||||||
val jAttendance = jAttendanceEl.asJsonObject
|
|
||||||
// jAttendance
|
|
||||||
val type = jAttendance.get("TypObecnosci").asInt
|
|
||||||
|
|
||||||
// skip "zajęcia nie odbyły się" and "Ferie"
|
|
||||||
if (type == 5 || type == 7)
|
|
||||||
continue
|
|
||||||
|
|
||||||
val date = Date.fromY_m_d(jAttendance.get("Data").asString)
|
|
||||||
val time = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
|
|
||||||
if (date.combineWith(time) > System.currentTimeMillis())
|
|
||||||
continue
|
|
||||||
|
|
||||||
val id = jAttendance.get("IdLesson").asString.crc16().toLong()
|
|
||||||
val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "")
|
|
||||||
val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString)
|
|
||||||
|
|
||||||
var baseType = TYPE_UNKNOWN
|
|
||||||
var typeName = "nieznany rodzaj"
|
|
||||||
var typeSymbol: String? = null
|
|
||||||
var typeColor: Long? = null
|
|
||||||
|
|
||||||
/* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosciUcznia_lmt637231494660000000.js */
|
|
||||||
/* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosci_lmt637231494660000000.css */
|
|
||||||
when (type) {
|
|
||||||
1 -> {
|
|
||||||
baseType = TYPE_ABSENT_EXCUSED
|
|
||||||
typeName = "nieobecność usprawiedliwiona"
|
|
||||||
typeColor = 0xffffe099
|
|
||||||
}
|
|
||||||
2 -> {
|
|
||||||
baseType = TYPE_BELATED
|
|
||||||
typeName = "spóźnienie"
|
|
||||||
typeColor = 0xffffffaa
|
|
||||||
}
|
|
||||||
3 -> {
|
|
||||||
baseType = TYPE_ABSENT
|
|
||||||
typeName = "nieobecność nieusprawiedliwiona"
|
|
||||||
typeColor = 0xffffad99
|
|
||||||
}
|
|
||||||
4, 9 -> {
|
|
||||||
baseType = TYPE_RELEASED
|
|
||||||
if (type == 4) {
|
|
||||||
typeName = "zwolnienie"
|
|
||||||
typeColor = 0xffa8beff
|
|
||||||
}
|
|
||||||
if (type == 9) {
|
|
||||||
typeName = "zwolniony / obecny"
|
|
||||||
typeSymbol = "zb"
|
|
||||||
typeColor = 0xffff69b4
|
|
||||||
}
|
|
||||||
}
|
|
||||||
8 -> {
|
|
||||||
baseType = TYPE_PRESENT_CUSTOM
|
|
||||||
typeName = "wycieczka"
|
|
||||||
typeSymbol = "w"
|
|
||||||
typeColor = null
|
|
||||||
}
|
|
||||||
0 -> {
|
|
||||||
baseType = TYPE_PRESENT
|
|
||||||
typeName = "obecny"
|
|
||||||
typeColor = 0xffccffcc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val semester = profile?.dateToSemester(date) ?: 1
|
|
||||||
|
|
||||||
val attendanceObject = Attendance(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
baseType = baseType,
|
|
||||||
typeName = typeName,
|
|
||||||
typeShort = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
|
|
||||||
typeSymbol = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
|
|
||||||
typeColor = typeColor?.toInt(),
|
|
||||||
date = date,
|
|
||||||
startTime = time,
|
|
||||||
semester = semester,
|
|
||||||
teacherId = rTeacher.id,
|
|
||||||
subjectId = rSubject.id
|
|
||||||
).also {
|
|
||||||
it.lessonTopic = jAttendance.getString("PrzedmiotTemat")
|
|
||||||
it.lessonNumber = jAttendance.getInt("Godzina")
|
|
||||||
}
|
|
||||||
|
|
||||||
data.attendanceList.add(attendanceObject)
|
|
||||||
if (attendanceObject.baseType != TYPE_PRESENT) {
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_ATTENDANCE,
|
|
||||||
attendanceObject.id,
|
|
||||||
profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
|
|
||||||
profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val attendanceDateValue = attendanceYear * 10000 + attendanceMonth * 100
|
|
||||||
if (profile?.empty == true && attendanceDateValue > profile?.getSemesterStart(1)?.value ?: 99999999) {
|
|
||||||
attendancePrevMonthChecked = true // do not need to check prev month later
|
|
||||||
attendanceMonth--
|
|
||||||
if (attendanceMonth < 1) {
|
|
||||||
attendanceMonth = 12
|
|
||||||
attendanceYear--
|
|
||||||
}
|
|
||||||
getAttendance()
|
|
||||||
} else if (!attendancePrevMonthChecked /* get also the previous month */) {
|
|
||||||
attendanceMonth--
|
|
||||||
if (attendanceMonth < 1) {
|
|
||||||
attendanceMonth = 12
|
|
||||||
attendanceYear--
|
|
||||||
}
|
|
||||||
attendancePrevMonthChecked = true
|
|
||||||
getAttendance()
|
|
||||||
} else {
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,127 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_EXAMS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
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.utils.models.Date
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class IdziennikWebExams(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebExams"
|
|
||||||
}
|
|
||||||
|
|
||||||
private var examsYear = Date.getToday().year
|
|
||||||
private var examsMonth = Date.getToday().month
|
|
||||||
private var examsMonthsChecked = 0
|
|
||||||
private var examsNextMonthChecked = false // TO DO temporary // no more // idk
|
|
||||||
|
|
||||||
init {
|
|
||||||
getExams()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getExams() {
|
|
||||||
val param = JsonObject().apply {
|
|
||||||
addProperty("strona", 1)
|
|
||||||
addProperty("iloscNaStrone", "99")
|
|
||||||
addProperty("iloscRekordow", -1)
|
|
||||||
addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
|
||||||
addProperty("kierunekSort", 0)
|
|
||||||
addProperty("maxIloscZaznaczonych", 0)
|
|
||||||
addProperty("panelFiltrow", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
|
||||||
"idP" to data.registerId,
|
|
||||||
"rok" to examsYear,
|
|
||||||
"miesiac" to examsMonth,
|
|
||||||
"param" to param
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { exam ->
|
|
||||||
val id = exam.getLong("_recordId") ?: return@forEach
|
|
||||||
val examDate = Date.fromY_m_d(exam.getString("data") ?: return@forEach)
|
|
||||||
val subjectName = exam.getString("przedmiot") ?: return@forEach
|
|
||||||
val subjectId = data.getSubject(subjectName, null, subjectName).id
|
|
||||||
val teacherName = exam.getString("wpisal") ?: return@forEach
|
|
||||||
val teacherId = data.getTeacherByLastFirst(teacherName).id
|
|
||||||
val topic = exam.getString("zakres")?.trim() ?: ""
|
|
||||||
|
|
||||||
val lessonList = data.db.timetableDao().getAllForDateNow(profileId, examDate)
|
|
||||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
|
|
||||||
|
|
||||||
val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) {
|
|
||||||
"sprawdzian/praca klasowa",
|
|
||||||
"sprawdzian",
|
|
||||||
"praca klasowa" -> Event.TYPE_EXAM
|
|
||||||
"kartkówka" -> Event.TYPE_SHORT_QUIZ
|
|
||||||
else -> Event.TYPE_EXAM
|
|
||||||
}
|
|
||||||
|
|
||||||
val eventObject = Event(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
date = examDate,
|
|
||||||
time = startTime,
|
|
||||||
topic = topic,
|
|
||||||
color = null,
|
|
||||||
type = eventType,
|
|
||||||
teacherId = teacherId,
|
|
||||||
subjectId = subjectId,
|
|
||||||
teamId = data.teamClass?.id ?: -1
|
|
||||||
)
|
|
||||||
|
|
||||||
data.eventList.add(eventObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_EVENT,
|
|
||||||
eventObject.id,
|
|
||||||
profile?.empty ?: false,
|
|
||||||
profile?.empty ?: false
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (profile?.empty == true && examsMonthsChecked < 3 /* how many months backwards to check? */) {
|
|
||||||
examsMonthsChecked++
|
|
||||||
examsMonth--
|
|
||||||
if (examsMonth < 1) {
|
|
||||||
examsMonth = 12
|
|
||||||
examsYear--
|
|
||||||
}
|
|
||||||
getExams()
|
|
||||||
} else if (!examsNextMonthChecked /* get also one month forward */) {
|
|
||||||
val showDate = Date.getToday().stepForward(0, 1, 0)
|
|
||||||
examsYear = showDate.year
|
|
||||||
examsMonth = showDate.month
|
|
||||||
examsNextMonthChecked = true
|
|
||||||
getExams()
|
|
||||||
} else {
|
|
||||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_EXAMS)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-28
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_ATTACHMENT
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
|
||||||
import pl.szczodrzynski.edziennik.get
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class IdziennikWebGetAttachment(override val data: DataIdziennik,
|
|
||||||
val owner: Any,
|
|
||||||
val attachmentId: Long,
|
|
||||||
val attachmentName: String,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "IdziennikWebGetAttachment"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
val message = owner as Message
|
|
||||||
|
|
||||||
val messageId = "\\[META:([A-z0-9]+);([0-9-]+)]".toRegex().find(message.body ?: "")?.get(2) ?: -1
|
|
||||||
val targetFile = File(Utils.getStorageDir(), attachmentName)
|
|
||||||
|
|
||||||
webGetFile(TAG, IDZIENNIK_WEB_GET_ATTACHMENT, targetFile, mapOf(
|
|
||||||
"id" to messageId,
|
|
||||||
"fileName" to attachmentName
|
|
||||||
), { file ->
|
|
||||||
val event = AttachmentGetEvent(
|
|
||||||
profileId,
|
|
||||||
owner,
|
|
||||||
attachmentId,
|
|
||||||
AttachmentGetEvent.TYPE_FINISHED,
|
|
||||||
file.absolutePath
|
|
||||||
)
|
|
||||||
|
|
||||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.ownerId}_${event.attachmentId}")
|
|
||||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(event)
|
|
||||||
|
|
||||||
onSuccess()
|
|
||||||
|
|
||||||
}) { written, _ ->
|
|
||||||
val event = AttachmentGetEvent(
|
|
||||||
profileId,
|
|
||||||
owner,
|
|
||||||
attachmentId,
|
|
||||||
AttachmentGetEvent.TYPE_PROGRESS,
|
|
||||||
bytesWritten = written
|
|
||||||
)
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,57 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2020-4-1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_HOMEWORK
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
|
||||||
import pl.szczodrzynski.edziennik.getBoolean
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
|
|
||||||
class IdziennikWebGetHomework(override val data: DataIdziennik,
|
|
||||||
val event: EventFull,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebGetHomework"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_GET_HOMEWORK, mapOf(
|
|
||||||
"idP" to data.registerId,
|
|
||||||
"idPD" to event.id
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
val homework = json.getJsonObject("praca") ?: return@webApiGet
|
|
||||||
|
|
||||||
if (homework.getBoolean("zalacznik", false)) {
|
|
||||||
event.attachmentIds = mutableListOf(event.id)
|
|
||||||
event.attachmentNames = mutableListOf("Załącznik do zadania")
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
event.attachmentIds = mutableListOf()
|
|
||||||
event.attachmentNames = mutableListOf()
|
|
||||||
}
|
|
||||||
event.homeworkBody = homework.getString("tresc")
|
|
||||||
|
|
||||||
data.eventList.add(event)
|
|
||||||
data.eventListReplace = true
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(EventGetEvent(event))
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2020-4-1.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Event
|
|
||||||
import pl.szczodrzynski.edziennik.get
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.set
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
class IdziennikWebGetHomeworkAttachment(override val data: DataIdziennik,
|
|
||||||
val owner: Any,
|
|
||||||
val attachmentId: Long,
|
|
||||||
val attachmentName: String,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "IdziennikWebGetHomeworkAttachment"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
val homework = owner as Event
|
|
||||||
|
|
||||||
/*val request = Request.Builder()
|
|
||||||
.url("")
|
|
||||||
.build()
|
|
||||||
data.app.http.newCall(request).enqueue(object : Callback {
|
|
||||||
override fun onFailure(call: Call, e: IOException) {
|
|
||||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
|
||||||
.withThrowable(e))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onResponse(call: Call, response: Response) {
|
|
||||||
val filename = response.header("content-disposition")?.substringAfter("\"")?.substringBeforeLast("\"")
|
|
||||||
|
|
||||||
val file: File = File(Utils.getStorageDir(), filename)
|
|
||||||
val sink = file.sink().buffer()
|
|
||||||
response.body()?.source()?.let {
|
|
||||||
sink.writeAll(it)
|
|
||||||
}
|
|
||||||
sink.close()
|
|
||||||
}
|
|
||||||
})*/
|
|
||||||
|
|
||||||
webGet(TAG, IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT) { text ->
|
|
||||||
val hiddenFields = JsonObject()
|
|
||||||
Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach {
|
|
||||||
hiddenFields[it[1]] = it[2]
|
|
||||||
}
|
|
||||||
|
|
||||||
webGetFile(TAG, IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT, Utils.getStorageDir(), mapOf(
|
|
||||||
"__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""),
|
|
||||||
"__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""),
|
|
||||||
"__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""),
|
|
||||||
"__EVENTTARGET" to "ctl00\$cphContent\$bt_pobraniePliku",
|
|
||||||
"ctl00\$dxComboUczniowie" to data.registerId,
|
|
||||||
"ctl00\$cphContent\$idPracyDomowej" to attachmentId
|
|
||||||
), { file ->
|
|
||||||
val event = AttachmentGetEvent(
|
|
||||||
profileId,
|
|
||||||
owner,
|
|
||||||
attachmentId,
|
|
||||||
AttachmentGetEvent.TYPE_FINISHED,
|
|
||||||
file.absolutePath
|
|
||||||
)
|
|
||||||
|
|
||||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.ownerId}_${event.attachmentId}")
|
|
||||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
|
||||||
|
|
||||||
homework.attachmentNames = mutableListOf(file.name)
|
|
||||||
data.eventList.add(homework)
|
|
||||||
data.eventListReplace = true
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(event)
|
|
||||||
onSuccess()
|
|
||||||
|
|
||||||
}) { written, _ ->
|
|
||||||
val event = AttachmentGetEvent(
|
|
||||||
profileId,
|
|
||||||
owner,
|
|
||||||
attachmentId,
|
|
||||||
AttachmentGetEvent.TYPE_PROGRESS,
|
|
||||||
bytesWritten = written
|
|
||||||
)
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(event)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,109 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-28
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_MESSAGE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
|
||||||
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.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikWebGetMessage(override val data: DataIdziennik,
|
|
||||||
private val message: MessageFull,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "IdziennikWebGetMessage"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
val metaPattern = "\\[META:([A-z0-9]+);([0-9-]+)]".toRegex()
|
|
||||||
val meta = metaPattern.find(message.body!!)
|
|
||||||
val messageIdString = meta?.get(1) ?: ""
|
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_GET_MESSAGE, parameters = mapOf(
|
|
||||||
"idWiadomosci" to messageIdString,
|
|
||||||
"typWiadomosci" to if (message.type == TYPE_SENT) 1 else 0
|
|
||||||
)) { json ->
|
|
||||||
json.getJsonObject("d")?.getJsonObject("Wiadomosc")?.also {
|
|
||||||
val id = it.getLong("_recordId")
|
|
||||||
message.body = message.body?.replace(metaPattern, "[META:$messageIdString;$id]")
|
|
||||||
|
|
||||||
message.clearAttachments()
|
|
||||||
it.getJsonArray("ListaZal")?.asJsonObjectList()?.forEach { attachment ->
|
|
||||||
message.addAttachment(
|
|
||||||
attachment.getLong("Id") ?: return@forEach,
|
|
||||||
attachment.getString("Nazwa") ?: return@forEach,
|
|
||||||
-1
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
message.recipients?.clear()
|
|
||||||
when (message.type) {
|
|
||||||
TYPE_RECEIVED -> {
|
|
||||||
val recipientObject = MessageRecipientFull(
|
|
||||||
profileId = profileId,
|
|
||||||
id = -1,
|
|
||||||
messageId = message.id
|
|
||||||
)
|
|
||||||
|
|
||||||
val readDateString = it.getString("DataOdczytania")
|
|
||||||
recipientObject.readDate = if (readDateString.isNullOrBlank()) System.currentTimeMillis()
|
|
||||||
else Date.fromIso(readDateString)
|
|
||||||
|
|
||||||
recipientObject.fullName = profile.accountName ?: profile.studentNameLong
|
|
||||||
|
|
||||||
data.messageRecipientList.add(recipientObject)
|
|
||||||
message.addRecipient(recipientObject)
|
|
||||||
}
|
|
||||||
|
|
||||||
TYPE_SENT -> {
|
|
||||||
it.getJsonArray("ListaOdbiorcow")?.asJsonObjectList()?.forEach { recipient ->
|
|
||||||
val recipientName = recipient.getString("NazwaOdbiorcy") ?: return@forEach
|
|
||||||
val teacher = data.getTeacherByLastFirst(recipientName)
|
|
||||||
|
|
||||||
val recipientObject = MessageRecipientFull(
|
|
||||||
profileId = profileId,
|
|
||||||
id = teacher.id,
|
|
||||||
messageId = message.id
|
|
||||||
)
|
|
||||||
|
|
||||||
recipientObject.readDate = recipient.getLong("Status") ?: return@forEach
|
|
||||||
recipientObject.fullName = teacher.fullName
|
|
||||||
|
|
||||||
data.messageRecipientList.add(recipientObject)
|
|
||||||
message.addRecipient(recipientObject)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!message.seen) {
|
|
||||||
message.seen = true
|
|
||||||
|
|
||||||
data.setSeenMetadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_MESSAGE,
|
|
||||||
message.id,
|
|
||||||
message.seen,
|
|
||||||
message.notified
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.messageList.add(message)
|
|
||||||
data.messageListReplace = true
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} ?: onSuccess() }
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-12-30.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import androidx.room.OnConflictStrategy
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_RECIPIENT_LIST
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
|
||||||
|
|
||||||
class IdziennikWebGetRecipientList(override val data: DataIdziennik,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebGetRecipientList"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_GET_RECIPIENT_LIST, mapOf(
|
|
||||||
"idP" to data.registerId
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getJsonArray("ListK_Pracownicy")?.asJsonObjectList()?.forEach { recipient ->
|
|
||||||
val name = recipient.getString("ImieNazwisko") ?: ": "
|
|
||||||
val (fullName, subject) = name.split(": ").let {
|
|
||||||
Pair(it.getOrNull(0), it.getOrNull(1))
|
|
||||||
}
|
|
||||||
val guid = recipient.getString("Id") ?: ""
|
|
||||||
// get teacher by ID or create it
|
|
||||||
val teacher = data.getTeacherByFirstLast(fullName ?: " ")
|
|
||||||
teacher.loginId = guid
|
|
||||||
teacher.setTeacherType(Teacher.TYPE_TEACHER)
|
|
||||||
// unset OTHER that is automatically set in IdziennikApiMessages*
|
|
||||||
teacher.unsetTeacherType(Teacher.TYPE_OTHER)
|
|
||||||
teacher.typeDescription = subject
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getJsonArray("ListK_Opiekunowie")?.asJsonObjectList()?.forEach { recipient ->
|
|
||||||
val name = recipient.getString("ImieNazwisko") ?: ": "
|
|
||||||
val (fullName, parentOf) = Regexes.IDZIENNIK_MESSAGES_RECIPIENT_PARENT.find(name)?.let {
|
|
||||||
Pair(it.groupValues.getOrNull(1), it.groupValues.getOrNull(2))
|
|
||||||
} ?: Pair(null, null)
|
|
||||||
val guid = recipient.getString("Id") ?: ""
|
|
||||||
// get teacher by ID or create it
|
|
||||||
val teacher = data.getTeacherByFirstLast(fullName ?: " ")
|
|
||||||
teacher.loginId = guid
|
|
||||||
teacher.setTeacherType(Teacher.TYPE_PARENT)
|
|
||||||
// unset OTHER that is automatically set in IdziennikApiMessages*
|
|
||||||
teacher.unsetTeacherType(Teacher.TYPE_OTHER)
|
|
||||||
teacher.typeDescription = parentOf
|
|
||||||
}
|
|
||||||
|
|
||||||
val event = RecipientListGetEvent(
|
|
||||||
data.profileId,
|
|
||||||
data.teacherList.filter { it.loginId != null }
|
|
||||||
)
|
|
||||||
|
|
||||||
profile?.lastReceiversSync = System.currentTimeMillis()
|
|
||||||
|
|
||||||
data.teacherOnConflictStrategy = OnConflictStrategy.REPLACE
|
|
||||||
EventBus.getDefault().postSticky(event)
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,178 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import android.graphics.Color
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GRADES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_GRADES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
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.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikWebGrades(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebGrades"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_GRADES, mapOf(
|
|
||||||
"idPozDziennika" to data.registerId
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.onEach { subjectJson ->
|
|
||||||
val subject = data.getSubject(
|
|
||||||
subjectJson.getString("Przedmiot") ?: return@onEach,
|
|
||||||
subjectJson.getLong("IdPrzedmiotu") ?: return@onEach,
|
|
||||||
subjectJson.getString("Przedmiot") ?: return@onEach
|
|
||||||
)
|
|
||||||
subjectJson.getJsonArray("Oceny")?.asJsonObjectList()?.forEach { grade ->
|
|
||||||
val id = grade.getLong("idK") ?: return@forEach
|
|
||||||
val category = grade.getString("Kategoria") ?: ""
|
|
||||||
val name = grade.getString("Ocena") ?: "?"
|
|
||||||
val semester = grade.getInt("Semestr") ?: 1
|
|
||||||
val teacher = data.getTeacherByLastFirst(grade.getString("Wystawil") ?: return@forEach)
|
|
||||||
|
|
||||||
val countToAverage = grade.getBoolean("DoSredniej") ?: true
|
|
||||||
var value = grade.getFloat("WartoscDoSred") ?: 0.0f
|
|
||||||
val weight = if (countToAverage)
|
|
||||||
grade.getFloat("Waga") ?: 0.0f
|
|
||||||
else
|
|
||||||
0.0f
|
|
||||||
|
|
||||||
val gradeColor = grade.getString("Kolor") ?: ""
|
|
||||||
var colorInt = 0xff2196f3.toInt()
|
|
||||||
if (gradeColor.isNotEmpty()) {
|
|
||||||
colorInt = Color.parseColor("#$gradeColor")
|
|
||||||
}
|
|
||||||
|
|
||||||
val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
|
|
||||||
|
|
||||||
val gradeObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
name = name,
|
|
||||||
type = TYPE_NORMAL,
|
|
||||||
value = value,
|
|
||||||
weight = weight,
|
|
||||||
color = colorInt,
|
|
||||||
category = category,
|
|
||||||
description = null,
|
|
||||||
comment = null,
|
|
||||||
semester = semester,
|
|
||||||
teacherId = teacher.id,
|
|
||||||
subjectId = subject.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
|
|
||||||
when (grade.getInt("Typ")) {
|
|
||||||
0 -> {
|
|
||||||
val history = grade.getJsonArray("Historia")?.asJsonObjectList()
|
|
||||||
if (history?.isNotEmpty() == true) {
|
|
||||||
var sum = gradeObject.value * gradeObject.weight
|
|
||||||
var count = gradeObject.weight
|
|
||||||
for (historyItem in history) {
|
|
||||||
val countToTheAverage = historyItem.getBoolean("DoSredniej") ?: false
|
|
||||||
value = historyItem.get("WartoscDoSred").asFloat
|
|
||||||
val weight = historyItem.get("Waga").asFloat
|
|
||||||
|
|
||||||
if (value > 0 && countToTheAverage) {
|
|
||||||
sum += value * weight
|
|
||||||
count += weight
|
|
||||||
}
|
|
||||||
|
|
||||||
val historyColor = historyItem.getString("Kolor") ?: ""
|
|
||||||
colorInt = 0xff2196f3.toInt()
|
|
||||||
if (historyColor.isNotEmpty()) {
|
|
||||||
colorInt = Color.parseColor("#$historyColor")
|
|
||||||
}
|
|
||||||
|
|
||||||
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
|
|
||||||
|
|
||||||
val historyObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = gradeObject.id * -1,
|
|
||||||
name = historyItem.getString("Ocena") ?: "",
|
|
||||||
type = TYPE_NORMAL,
|
|
||||||
value = value,
|
|
||||||
weight = if (value > 0f && countToTheAverage) weight * -1f else 0f,
|
|
||||||
color = colorInt,
|
|
||||||
category = historyItem.getString("Kategoria"),
|
|
||||||
description = historyItem.getString("Uzasadnienie"),
|
|
||||||
comment = null,
|
|
||||||
semester = historyItem.getInt("Semestr") ?: 1,
|
|
||||||
teacherId = teacher.id,
|
|
||||||
subjectId = subject.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
historyObject.parentId = gradeObject.id
|
|
||||||
|
|
||||||
data.gradeList.add(historyObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
historyObject.id,
|
|
||||||
true,
|
|
||||||
true
|
|
||||||
))
|
|
||||||
}
|
|
||||||
// update the current grade's value with an average of all historical grades and itself
|
|
||||||
if (sum > 0 && count > 0) {
|
|
||||||
gradeObject.value = sum / count
|
|
||||||
}
|
|
||||||
gradeObject.isImprovement = true // gradeObject is the improved grade. Originals are historyObjects
|
|
||||||
}
|
|
||||||
}
|
|
||||||
1 -> {
|
|
||||||
gradeObject.type = Grade.TYPE_SEMESTER1_FINAL
|
|
||||||
gradeObject.name = value.toInt().toString()
|
|
||||||
gradeObject.weight = 0f
|
|
||||||
}
|
|
||||||
2 -> {
|
|
||||||
gradeObject.type = Grade.TYPE_YEAR_FINAL
|
|
||||||
gradeObject.name = value.toInt().toString()
|
|
||||||
gradeObject.weight = 0f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.gradeList.add(gradeObject)
|
|
||||||
data.metadataList.add(
|
|
||||||
Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
id,
|
|
||||||
data.profile.empty,
|
|
||||||
data.profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.toRemove.addAll(listOf(
|
|
||||||
Grade.TYPE_NORMAL,
|
|
||||||
Grade.TYPE_SEMESTER1_FINAL,
|
|
||||||
Grade.TYPE_YEAR_FINAL
|
|
||||||
).map {
|
|
||||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
|
||||||
})
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_GRADES)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_IDZIENNIK_WEB_GRADES) }
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-25
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_HOMEWORK
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_HOMEWORK
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
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.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikWebHomework(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebHomework"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
val param = JsonObject().apply {
|
|
||||||
addProperty("strona", 1)
|
|
||||||
addProperty("iloscNaStrone", 997)
|
|
||||||
addProperty("iloscRekordow", -1)
|
|
||||||
addProperty("kolumnaSort", "DataZadania")
|
|
||||||
addProperty("kierunekSort", 0)
|
|
||||||
addProperty("maxIloscZaznaczonych", 0)
|
|
||||||
addProperty("panelFiltrow", 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_HOMEWORK, mapOf(
|
|
||||||
"idP" to data.registerId,
|
|
||||||
"data" to Date.getToday().stringY_m_d,
|
|
||||||
"wszystkie" to true,
|
|
||||||
"param" to param
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { homework ->
|
|
||||||
val id = homework.getLong("_recordId") ?: return@forEach
|
|
||||||
val eventDate = Date.fromY_m_d(homework.getString("dataO") ?: return@forEach)
|
|
||||||
val addedDate = Date.fromY_m_d(homework.getString("dataZ") ?: return@forEach)
|
|
||||||
val subjectName = homework.getString("przed") ?: return@forEach
|
|
||||||
val subjectId = data.getSubject(subjectName, null, subjectName).id
|
|
||||||
val teacherName = homework.getString("usr") ?: return@forEach
|
|
||||||
val teacherId = data.getTeacherByLastFirst(teacherName).id
|
|
||||||
val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
|
|
||||||
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
|
|
||||||
val topic = homework.getString("tytul")?.trim() ?: ""
|
|
||||||
|
|
||||||
val seen = when (profile?.empty) {
|
|
||||||
true -> true
|
|
||||||
else -> eventDate < Date.getToday()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val eventObject = Event(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
date = eventDate,
|
|
||||||
time = startTime,
|
|
||||||
topic = topic,
|
|
||||||
color = null,
|
|
||||||
type = Event.TYPE_HOMEWORK,
|
|
||||||
teacherId = teacherId,
|
|
||||||
subjectId = subjectId,
|
|
||||||
teamId = data.teamClass?.id ?: -1,
|
|
||||||
addedDate = addedDate.inMillis
|
|
||||||
)
|
|
||||||
|
|
||||||
data.eventList.add(eventObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_HOMEWORK,
|
|
||||||
eventObject.id,
|
|
||||||
seen,
|
|
||||||
seen
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_HOMEWORK)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,84 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.crc16
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_NOTICES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEGATIVE
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEUTRAL
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_POSITIVE
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikWebNotices(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebNotices"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_NOTICES, mapOf(
|
|
||||||
"idPozDziennika" to data.registerId
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
for (jNoticeEl in json.getAsJsonArray("SUwaga")) {
|
|
||||||
val jNotice = jNoticeEl.asJsonObject
|
|
||||||
// jNotice
|
|
||||||
val noticeId = jNotice.get("id").asString.crc16().toLong()
|
|
||||||
|
|
||||||
val rTeacher = data.getTeacherByLastFirst(jNotice.get("Nauczyciel").asString)
|
|
||||||
val addedDate = Date.fromY_m_d(jNotice.get("Data").asString)
|
|
||||||
|
|
||||||
var nType = TYPE_NEUTRAL
|
|
||||||
val jType = jNotice.get("Typ").asString
|
|
||||||
if (jType == "n") {
|
|
||||||
nType = TYPE_NEGATIVE
|
|
||||||
} else if (jType == "p") {
|
|
||||||
nType = TYPE_POSITIVE
|
|
||||||
}
|
|
||||||
|
|
||||||
val noticeObject = Notice(
|
|
||||||
profileId = profileId,
|
|
||||||
id = noticeId,
|
|
||||||
type = nType,
|
|
||||||
semester = jNotice.get("Semestr").asInt,
|
|
||||||
text = jNotice.getString("Tresc") ?: "",
|
|
||||||
category = null,
|
|
||||||
points = null,
|
|
||||||
teacherId = rTeacher.id,
|
|
||||||
addedDate = addedDate.inMillis
|
|
||||||
)
|
|
||||||
|
|
||||||
data.noticeList.add(noticeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_NOTICE,
|
|
||||||
noticeObject.id,
|
|
||||||
profile?.empty ?: false,
|
|
||||||
profile?.empty ?: false
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_NOTICES, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_NOTICES)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,152 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_MISSING_GRADES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
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_DESCRIPTIVE
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonArray
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
|
|
||||||
class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebProposedGrades"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { data.profile?.also { profile ->
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_MISSING_GRADES, mapOf(
|
|
||||||
"idPozDziennika" to data.registerId
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
val manager = data.app.gradesManager
|
|
||||||
|
|
||||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { subject ->
|
|
||||||
val subjectName = subject.getString("Przedmiot") ?: return@forEach
|
|
||||||
val subjectObject = data.getSubject(subjectName, null, subjectName)
|
|
||||||
|
|
||||||
val semester1Proposed = subject.getString("OcenaSem1") ?: ""
|
|
||||||
val semester1Value = manager.getGradeValue(semester1Proposed)
|
|
||||||
val semester1Id = subjectObject.id * (-100) - 1
|
|
||||||
val semester1Type =
|
|
||||||
if (semester1Value == 0f) TYPE_DESCRIPTIVE
|
|
||||||
else TYPE_SEMESTER1_PROPOSED
|
|
||||||
val semester1Name = when {
|
|
||||||
semester1Value == 0f -> " "
|
|
||||||
semester1Value % 1.0f == 0f -> semester1Value.toInt().toString()
|
|
||||||
else -> semester1Value.toString()
|
|
||||||
}
|
|
||||||
val semester1Color =
|
|
||||||
if (semester1Value == 0f) 0xff536dfe.toInt()
|
|
||||||
else -1
|
|
||||||
|
|
||||||
val semester2Proposed = subject.getString("OcenaSem2") ?: ""
|
|
||||||
val semester2Value = manager.getGradeValue(semester2Proposed)
|
|
||||||
val semester2Id = subjectObject.id * (-100) - 2
|
|
||||||
val semester2Type =
|
|
||||||
if (semester2Value == 0f) TYPE_DESCRIPTIVE
|
|
||||||
else TYPE_YEAR_PROPOSED
|
|
||||||
val semester2Name = when {
|
|
||||||
semester2Value == 0f -> " "
|
|
||||||
semester2Value % 1.0f == 0f -> semester2Value.toInt().toString()
|
|
||||||
else -> semester2Value.toString()
|
|
||||||
}
|
|
||||||
val semester2Color =
|
|
||||||
if (semester2Value == 0f) 0xffff4081.toInt()
|
|
||||||
else -1
|
|
||||||
|
|
||||||
if (semester1Proposed != "") {
|
|
||||||
val addedDate = if (data.profile.empty)
|
|
||||||
data.profile.dateSemester1Start.inMillis
|
|
||||||
else
|
|
||||||
System.currentTimeMillis()
|
|
||||||
|
|
||||||
val gradeObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = semester1Id,
|
|
||||||
name = semester1Name,
|
|
||||||
type = semester1Type,
|
|
||||||
value = semester1Value,
|
|
||||||
weight = 0f,
|
|
||||||
color = semester1Color,
|
|
||||||
category = if (semester1Value == 0f) "Ocena opisowa semestralna" else null,
|
|
||||||
description = if (semester1Value == 0f) semester1Proposed else null,
|
|
||||||
comment = null,
|
|
||||||
semester = 1,
|
|
||||||
teacherId = -1,
|
|
||||||
subjectId = subjectObject.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
|
|
||||||
data.gradeList.add(gradeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
gradeObject.id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (semester2Proposed != "") {
|
|
||||||
val addedDate = if (data.profile.empty)
|
|
||||||
data.profile.dateSemester2Start.inMillis
|
|
||||||
else
|
|
||||||
System.currentTimeMillis()
|
|
||||||
|
|
||||||
val gradeObject = Grade(
|
|
||||||
profileId = profileId,
|
|
||||||
id = semester2Id,
|
|
||||||
name = semester2Name,
|
|
||||||
type = semester2Type,
|
|
||||||
value = semester2Value,
|
|
||||||
weight = 0f,
|
|
||||||
color = semester2Color,
|
|
||||||
category = if (semester2Value == 0f) "Ocena opisowa końcoworoczna" else null,
|
|
||||||
description = if (semester2Value == 0f) semester2Proposed else null,
|
|
||||||
comment = null,
|
|
||||||
semester = 2,
|
|
||||||
teacherId = -1,
|
|
||||||
subjectId = subjectObject.id,
|
|
||||||
addedDate = addedDate
|
|
||||||
)
|
|
||||||
|
|
||||||
data.gradeList.add(gradeObject)
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_GRADE,
|
|
||||||
gradeObject.id,
|
|
||||||
profile.empty,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data.toRemove.addAll(listOf(TYPE_SEMESTER1_PROPOSED, TYPE_YEAR_PROPOSED).map {
|
|
||||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
|
||||||
})
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES)
|
|
||||||
}
|
|
||||||
} ?: onSuccess(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES) }
|
|
||||||
}
|
|
@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-12-30.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_SEND_MESSAGE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiMessagesSent
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
class IdziennikWebSendMessage(override val data: DataIdziennik,
|
|
||||||
val recipients: List<Teacher>,
|
|
||||||
val subject: String,
|
|
||||||
val text: String,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebSendMessage"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
val recipientsArray = JsonArray()
|
|
||||||
for (teacher in recipients) {
|
|
||||||
teacher.loginId?.let {
|
|
||||||
recipientsArray += it
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_SEND_MESSAGE, mapOf(
|
|
||||||
"Wiadomosc" to JsonObject(
|
|
||||||
"Tytul" to subject,
|
|
||||||
"Tresc" to text,
|
|
||||||
"Confirmation" to false,
|
|
||||||
"GuidMessage" to UUID.randomUUID().toString().toUpperCase(Locale.ROOT),
|
|
||||||
"Odbiorcy" to recipientsArray
|
|
||||||
)
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json.getBoolean("CzyJestBlad") != false) {
|
|
||||||
// TODO error
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
IdziennikApiMessagesSent(data, null) {
|
|
||||||
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
|
|
||||||
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
|
|
||||||
val event = MessageSentEvent(data.profileId, message, message?.addedDate)
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(event)
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import com.google.gson.JsonObject
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_HOME
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.get
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
|
|
||||||
class IdziennikWebSwitchRegister(override val data: DataIdziennik,
|
|
||||||
val registerId: Int,
|
|
||||||
val onSuccess: () -> Unit
|
|
||||||
) : IdziennikWeb(data, null) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebSwitchRegister"
|
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
|
||||||
val hiddenFields = data.loginStore.getLoginData("hiddenFields", JsonObject())
|
|
||||||
// TODO error checking
|
|
||||||
|
|
||||||
webGet(TAG, IDZIENNIK_WEB_HOME, mapOf(
|
|
||||||
"__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""),
|
|
||||||
"__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""),
|
|
||||||
"__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""),
|
|
||||||
"ctl00\$dxComboUczniowie" to registerId
|
|
||||||
)) { text ->
|
|
||||||
Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let {
|
|
||||||
val registerId = it[1].toIntOrNull() ?: return@let
|
|
||||||
data.webSelectedRegister = registerId
|
|
||||||
}
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,194 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-11-22
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
|
|
||||||
|
|
||||||
import androidx.core.util.set
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_TIMETABLE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
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.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 IdziennikWebTimetable(override val data: DataIdziennik,
|
|
||||||
override val lastSync: Long?,
|
|
||||||
val onSuccess: (endpointId: Int) -> Unit
|
|
||||||
) : IdziennikWeb(data, lastSync) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikWebTimetable"
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
|
|
||||||
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
|
||||||
"idPozDziennika" to data.registerId,
|
|
||||||
"pidRokSzkolny" to data.schoolYearId,
|
|
||||||
"data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
|
|
||||||
)) { result ->
|
|
||||||
val json = result.getJsonObject("d") ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
|
||||||
.withApiResponse(result))
|
|
||||||
return@webApiGet
|
|
||||||
}
|
|
||||||
|
|
||||||
json.getJsonArray("GodzinyLekcyjne")?.asJsonObjectList()?.forEachIndexed { index, range ->
|
|
||||||
val lessonRange = LessonRange(
|
|
||||||
profileId,
|
|
||||||
index + 1,
|
|
||||||
range.getString("Poczatek")?.let { Time.fromH_m(it) }
|
|
||||||
?: return@forEachIndexed,
|
|
||||||
range.getString("Koniec")?.let { Time.fromH_m(it) } ?: return@forEachIndexed
|
|
||||||
)
|
|
||||||
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
|
||||||
}
|
|
||||||
|
|
||||||
val dates = mutableSetOf<Int>()
|
|
||||||
val lessons = mutableListOf<Lesson>()
|
|
||||||
|
|
||||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
|
||||||
val subject = data.getSubject(
|
|
||||||
lesson.getString("Nazwa") ?: return@forEach,
|
|
||||||
lesson.getLong("Id"),
|
|
||||||
lesson.getString("Skrot") ?: ""
|
|
||||||
)
|
|
||||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
|
|
||||||
?: return@forEach)
|
|
||||||
|
|
||||||
val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
|
|
||||||
val newSubject = when (newSubjectName.isNullOrBlank()) {
|
|
||||||
true -> null
|
|
||||||
else -> data.getSubject(newSubjectName, null, newSubjectName)
|
|
||||||
}
|
|
||||||
|
|
||||||
val newTeacherName = lesson.getString("NauZastepujacy")
|
|
||||||
val newTeacher = when (newTeacherName.isNullOrBlank()) {
|
|
||||||
true -> null
|
|
||||||
else -> data.getTeacherByFDotLast(newTeacherName)
|
|
||||||
}
|
|
||||||
|
|
||||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
|
||||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1)
|
|
||||||
?: return@forEach]
|
|
||||||
val lessonDate = weekStart.clone().stepForward(0, 0, weekDay)
|
|
||||||
val classroom = lesson.getString("NazwaSali")
|
|
||||||
|
|
||||||
val type = lesson.getInt("TypZastepstwa") ?: -1
|
|
||||||
|
|
||||||
val lessonObject = Lesson(profileId, -1)
|
|
||||||
|
|
||||||
when (type) {
|
|
||||||
1, 2, 3, 4, 5 -> {
|
|
||||||
lessonObject.apply {
|
|
||||||
this.type = Lesson.TYPE_CHANGE
|
|
||||||
|
|
||||||
this.date = lessonDate
|
|
||||||
this.lessonNumber = lessonRange.lessonNumber
|
|
||||||
this.startTime = lessonRange.startTime
|
|
||||||
this.endTime = lessonRange.endTime
|
|
||||||
this.subjectId = newSubject?.id
|
|
||||||
this.teacherId = newTeacher?.id
|
|
||||||
this.teamId = data.teamClass?.id
|
|
||||||
this.classroom = classroom
|
|
||||||
|
|
||||||
this.oldDate = lessonDate
|
|
||||||
this.oldLessonNumber = lessonRange.lessonNumber
|
|
||||||
this.oldStartTime = lessonRange.startTime
|
|
||||||
this.oldEndTime = lessonRange.endTime
|
|
||||||
this.oldSubjectId = subject.id
|
|
||||||
this.oldTeacherId = teacher.id
|
|
||||||
this.oldTeamId = data.teamClass?.id
|
|
||||||
this.oldClassroom = classroom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0 -> {
|
|
||||||
lessonObject.apply {
|
|
||||||
this.type = Lesson.TYPE_CANCELLED
|
|
||||||
|
|
||||||
this.oldDate = lessonDate
|
|
||||||
this.oldLessonNumber = lessonRange.lessonNumber
|
|
||||||
this.oldStartTime = lessonRange.startTime
|
|
||||||
this.oldEndTime = lessonRange.endTime
|
|
||||||
this.oldSubjectId = subject.id
|
|
||||||
this.oldTeacherId = teacher.id
|
|
||||||
this.oldTeamId = data.teamClass?.id
|
|
||||||
this.oldClassroom = classroom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
lessonObject.apply {
|
|
||||||
this.type = Lesson.TYPE_NORMAL
|
|
||||||
|
|
||||||
this.date = lessonDate
|
|
||||||
this.lessonNumber = lessonRange.lessonNumber
|
|
||||||
this.startTime = lessonRange.startTime
|
|
||||||
this.endTime = lessonRange.endTime
|
|
||||||
this.subjectId = subject.id
|
|
||||||
this.teacherId = teacher.id
|
|
||||||
this.teamId = data.teamClass?.id
|
|
||||||
this.classroom = classroom
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lessonObject.id = lessonObject.buildId()
|
|
||||||
|
|
||||||
dates.add(lessonDate.value)
|
|
||||||
lessons.add(lessonObject)
|
|
||||||
|
|
||||||
val seen = profile.empty || lessonDate < Date.getToday()
|
|
||||||
|
|
||||||
if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
|
|
||||||
data.metadataList.add(Metadata(
|
|
||||||
profileId,
|
|
||||||
Metadata.TYPE_LESSON_CHANGE,
|
|
||||||
lessonObject.id,
|
|
||||||
seen,
|
|
||||||
seen
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val date: Date = weekStart.clone()
|
|
||||||
while (date <= weekEnd) {
|
|
||||||
if (!dates.contains(date.value)) {
|
|
||||||
lessons.add(Lesson(profileId, date.value.toLong()).apply {
|
|
||||||
this.type = Lesson.TYPE_NO_LESSONS
|
|
||||||
this.date = date.clone()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
date.stepForward(0, 0, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
|
||||||
|
|
||||||
data.lessonList.addAll(lessons)
|
|
||||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
|
||||||
|
|
||||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
|
||||||
onSuccess(ENDPOINT_IDZIENNIK_WEB_TIMETABLE)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.firstlogin
|
|
||||||
|
|
||||||
import org.greenrobot.eventbus.EventBus
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_SETTINGS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_IDZIENNIK
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLoginWeb
|
|
||||||
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.fixName
|
|
||||||
import pl.szczodrzynski.edziennik.get
|
|
||||||
import pl.szczodrzynski.edziennik.set
|
|
||||||
import pl.szczodrzynski.edziennik.swapFirstLastName
|
|
||||||
|
|
||||||
class IdziennikFirstLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikFirstLogin"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val web = IdziennikWeb(data, null)
|
|
||||||
private val profileList = mutableListOf<Profile>()
|
|
||||||
|
|
||||||
init {
|
|
||||||
val loginStoreId = data.loginStore.id
|
|
||||||
val loginStoreType = LOGIN_TYPE_IDZIENNIK
|
|
||||||
var firstProfileId = loginStoreId
|
|
||||||
|
|
||||||
IdziennikLoginWeb(data) {
|
|
||||||
web.webGet(TAG, IDZIENNIK_WEB_SETTINGS) { text ->
|
|
||||||
//val accounts = json.getJsonArray("accounts")
|
|
||||||
|
|
||||||
val isParent = Regexes.IDZIENNIK_LOGIN_FIRST_IS_PARENT.find(text)?.get(1) != "0"
|
|
||||||
val accountNameLong = if (isParent)
|
|
||||||
Regexes.IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME.find(text)?.get(1)?.swapFirstLastName()?.fixName()
|
|
||||||
else null
|
|
||||||
|
|
||||||
var schoolYearStart: Int? = null
|
|
||||||
var schoolYearEnd: Int? = null
|
|
||||||
var schoolYearName: String? = null
|
|
||||||
val schoolYearId = Regexes.IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR.find(text)?.let {
|
|
||||||
schoolYearName = it[2]+"/"+it[3]
|
|
||||||
schoolYearStart = it[2].toIntOrNull()
|
|
||||||
schoolYearEnd = it[3].toIntOrNull()
|
|
||||||
it[1].toIntOrNull()
|
|
||||||
} ?: run {
|
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR)
|
|
||||||
.withApiResponse(text))
|
|
||||||
return@webGet
|
|
||||||
}
|
|
||||||
|
|
||||||
Regexes.IDZIENNIK_LOGIN_FIRST_STUDENT.findAll(text)
|
|
||||||
.toMutableList()
|
|
||||||
.reversed()
|
|
||||||
.forEach { match ->
|
|
||||||
val registerId = match[1].toIntOrNull() ?: return@forEach
|
|
||||||
val studentId = match[2]
|
|
||||||
val firstName = match[3]
|
|
||||||
val lastName = match[4]
|
|
||||||
val className = match[5] + " " + match[6]
|
|
||||||
|
|
||||||
val studentNameLong = "$firstName $lastName".fixName()
|
|
||||||
val studentNameShort = "$firstName ${lastName[0]}.".fixName()
|
|
||||||
val accountName = if (accountNameLong == studentNameLong) null else accountNameLong
|
|
||||||
|
|
||||||
val profile = Profile(
|
|
||||||
firstProfileId++,
|
|
||||||
loginStoreId,
|
|
||||||
loginStoreType,
|
|
||||||
studentNameLong,
|
|
||||||
data.webUsername,
|
|
||||||
studentNameLong,
|
|
||||||
studentNameShort,
|
|
||||||
accountName
|
|
||||||
).apply {
|
|
||||||
schoolYearStart?.let { studentSchoolYearStart = it }
|
|
||||||
studentClassName = className
|
|
||||||
studentData["studentId"] = studentId
|
|
||||||
studentData["registerId"] = registerId
|
|
||||||
studentData["schoolYearId"] = schoolYearId
|
|
||||||
}
|
|
||||||
profileList.add(profile)
|
|
||||||
}
|
|
||||||
|
|
||||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
|
|
||||||
class IdziennikLoginApi(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikLoginApi"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { run {
|
|
||||||
if (data.isApiLoginValid()) {
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-26.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
|
|
||||||
|
|
||||||
import im.wangchao.mhttp.Request
|
|
||||||
import im.wangchao.mhttp.Response
|
|
||||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
|
||||||
import pl.szczodrzynski.edziennik.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
|
|
||||||
class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|
||||||
companion object {
|
|
||||||
private const val TAG = "IdziennikLoginWeb"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { run {
|
|
||||||
if (data.isWebLoginValid()) {
|
|
||||||
data.app.cookieJar.set("iuczniowie.progman.pl", "ASP.NET_SessionId_iDziennik", data.webSessionId)
|
|
||||||
data.app.cookieJar.set("iuczniowie.progman.pl", ".ASPXAUTH", data.webAuth)
|
|
||||||
onSuccess()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data.app.cookieJar.clear("iuczniowie.progman.pl")
|
|
||||||
if (data.webSchoolName != null && data.webUsername != null && data.webPassword != null) {
|
|
||||||
loginWithCredentials()
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
private fun loginWithCredentials() {
|
|
||||||
Utils.d(TAG, "Request: Idziennik/Login/Web - $IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
|
||||||
|
|
||||||
val loginCallback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
if (text.isNullOrEmpty()) {
|
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// login succeeded: there is a start page
|
|
||||||
if (text.contains("czyWyswietlicDostepMobilny")) {
|
|
||||||
val cookies = data.app.cookieJar.getAll("iuczniowie.progman.pl")
|
|
||||||
run {
|
|
||||||
data.webSessionId = cookies["ASP.NET_SessionId_iDziennik"] ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
|
|
||||||
data.webAuth = cookies[".ASPXAUTH"] ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
|
|
||||||
data.apiBearer = cookies["Bearer"]?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
|
|
||||||
data.loginExpiryTime = response.getUnixDate() + 30 * MINUTE /* after about 40 minutes the login didn't work already */
|
|
||||||
data.apiExpiryTime = response.getUnixDate() + 12 * HOUR /* actually it expires after 24 hours but I'm not sure when does the token refresh. */
|
|
||||||
|
|
||||||
val hiddenFields = JsonObject()
|
|
||||||
Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach {
|
|
||||||
hiddenFields[it[1]] = it[2]
|
|
||||||
}
|
|
||||||
data.loginStore.putLoginData("hiddenFields", hiddenFields)
|
|
||||||
|
|
||||||
Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let {
|
|
||||||
val registerId = it[1].toIntOrNull() ?: return@let
|
|
||||||
data.webSelectedRegister = registerId
|
|
||||||
}
|
|
||||||
|
|
||||||
data.profile?.let { profile ->
|
|
||||||
Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also {
|
|
||||||
val number = it[1].toIntOrNull() ?: return@also
|
|
||||||
val luckyNumberObject = LuckyNumber(
|
|
||||||
profileId = data.profileId,
|
|
||||||
date = Date.getToday(),
|
|
||||||
number = number
|
|
||||||
)
|
|
||||||
|
|
||||||
data.luckyNumberList.add(luckyNumberObject)
|
|
||||||
data.metadataList.add(
|
|
||||||
Metadata(
|
|
||||||
profile.id,
|
|
||||||
Metadata.TYPE_LUCKY_NUMBER,
|
|
||||||
luckyNumberObject.date.value.toLong(),
|
|
||||||
true,
|
|
||||||
profile.empty
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return@run null
|
|
||||||
}?.let { errorCode ->
|
|
||||||
data.error(ApiError(TAG, errorCode)
|
|
||||||
.withApiResponse(text)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
onSuccess()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
val errorText = Regexes.IDZIENNIK_LOGIN_ERROR.find(text)?.get(1)
|
|
||||||
when {
|
|
||||||
errorText?.contains("nieprawidłową nazwę szkoły") == true -> ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME
|
|
||||||
errorText?.contains("nieprawidłowy login lub hasło") == true -> ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN
|
|
||||||
text.contains("Identyfikator zgłoszenia") -> ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR
|
|
||||||
text.contains("Hasło dostępu do systemu wygasło") -> ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED
|
|
||||||
text.contains("Trwają prace konserwacyjne") -> ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE
|
|
||||||
else -> ERROR_LOGIN_IDZIENNIK_WEB_OTHER
|
|
||||||
}.let { errorCode ->
|
|
||||||
data.error(ApiError(TAG, errorCode)
|
|
||||||
.withApiResponse(text)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val getCallback = object : TextCallbackHandler() {
|
|
||||||
override fun onSuccess(text: String?, response: Response?) {
|
|
||||||
Request.builder()
|
|
||||||
.url("$IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
|
||||||
.userAgent(IDZIENNIK_USER_AGENT)
|
|
||||||
.addHeader("Origin", "https://iuczniowie.progman.pl")
|
|
||||||
.addHeader("Referer", "$IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
|
||||||
.apply {
|
|
||||||
Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text ?: return@apply).forEach {
|
|
||||||
addParameter(it[1], it[2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.addParameter("ctl00\$ContentPlaceHolder\$nazwaPrzegladarki", IDZIENNIK_USER_AGENT)
|
|
||||||
.addParameter("ctl00\$ContentPlaceHolder\$NazwaSzkoly", data.webSchoolName)
|
|
||||||
.addParameter("ctl00\$ContentPlaceHolder\$UserName", data.webUsername)
|
|
||||||
.addParameter("ctl00\$ContentPlaceHolder\$Password", data.webPassword)
|
|
||||||
.addParameter("ctl00\$ContentPlaceHolder\$captcha", "")
|
|
||||||
.addParameter("ctl00\$ContentPlaceHolder\$Logowanie", "Zaloguj")
|
|
||||||
.post()
|
|
||||||
.allowErrorCode(502)
|
|
||||||
.callback(loginCallback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url("$IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
|
||||||
.userAgent(IDZIENNIK_USER_AGENT)
|
|
||||||
.get()
|
|
||||||
.allowErrorCode(502)
|
|
||||||
.callback(getCallback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -120,7 +120,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
private var mApiLogin: String? = null
|
private var mApiLogin: String? = null
|
||||||
var apiLogin: String?
|
var apiLogin: String?
|
||||||
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
|
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
|
||||||
set(value) { profile?.putStudentData("accountLogin", value) ?: return; mApiLogin = value }
|
set(value) { profile?.putStudentData("accountLogin", value); mApiLogin = value }
|
||||||
/**
|
/**
|
||||||
* A Synergia password.
|
* A Synergia password.
|
||||||
* Used: for login (API Login Method) in Synergia mode.
|
* Used: for login (API Login Method) in Synergia mode.
|
||||||
@ -129,7 +129,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
private var mApiPassword: String? = null
|
private var mApiPassword: String? = null
|
||||||
var apiPassword: String?
|
var apiPassword: String?
|
||||||
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
|
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
|
||||||
set(value) { profile?.putStudentData("accountPassword", value) ?: return; mApiPassword = value }
|
set(value) { profile?.putStudentData("accountPassword", value); mApiPassword = value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A JST login Code.
|
* A JST login Code.
|
||||||
@ -138,8 +138,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
private var mApiCode: String? = null
|
private var mApiCode: String? = null
|
||||||
var apiCode: String?
|
var apiCode: String?
|
||||||
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
|
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
|
||||||
set(value) {
|
set(value) { profile?.putStudentData("accountCode", value); mApiCode = value }
|
||||||
loginStore.putLoginData("accountCode", value); mApiCode = value }
|
|
||||||
/**
|
/**
|
||||||
* A JST login PIN.
|
* A JST login PIN.
|
||||||
* Used only during first login in JST mode.
|
* Used only during first login in JST mode.
|
||||||
@ -147,8 +146,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
private var mApiPin: String? = null
|
private var mApiPin: String? = null
|
||||||
var apiPin: String?
|
var apiPin: String?
|
||||||
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
|
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
|
||||||
set(value) {
|
set(value) { profile?.putStudentData("accountPin", value); mApiPin = value }
|
||||||
loginStore.putLoginData("accountPin", value); mApiPin = value }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Synergia API access token.
|
* A Synergia API access token.
|
||||||
@ -277,4 +275,10 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
var timetableNotPublic: Boolean
|
var timetableNotPublic: Boolean
|
||||||
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
|
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
|
||||||
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
|
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set to false when Recaptcha helper doesn't provide a working token.
|
||||||
|
* When it's set to false uses Synergia for messages.
|
||||||
|
*/
|
||||||
|
var messagesLoginSuccessful: Boolean = true
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetMessage
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetMessage
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetRecipientList
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetRecipientList
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesSendMessage
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesSendMessage
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaGetHomework
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomeworkGetAttachment
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
|
||||||
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.interfaces.EdziennikCallback
|
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||||
@ -91,9 +89,8 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
|
|
||||||
override fun getMessage(message: MessageFull) {
|
override fun getMessage(message: MessageFull) {
|
||||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||||
LibrusMessagesGetMessage(data, message) {
|
if (data.messagesLoginSuccessful) LibrusMessagesGetMessage(data, message) { completed() }
|
||||||
completed()
|
else LibrusSynergiaGetMessage(data, message) { completed() }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,10 +121,9 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
|
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
|
||||||
when (owner) {
|
when (owner) {
|
||||||
is Message -> {
|
is Message -> {
|
||||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||||
LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) {
|
if (data.messagesLoginSuccessful) LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) { completed() }
|
||||||
completed()
|
LibrusSynergiaGetAttachment(data, owner, attachmentId, attachmentName) { completed() }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is EventFull -> {
|
is EventFull -> {
|
||||||
@ -161,7 +157,6 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
d(TAG, "Cancelled")
|
d(TAG, "Cancelled")
|
||||||
data.cancel()
|
data.cancel()
|
||||||
callback.onCompleted()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
|
@ -50,6 +50,8 @@ const val ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS = 1130
|
|||||||
const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010
|
const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010
|
||||||
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020
|
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020
|
||||||
const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030
|
const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030
|
||||||
|
const val ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_RECEIVED = 2040
|
||||||
|
const val ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_SENT = 2050
|
||||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010
|
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010
|
||||||
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020
|
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020
|
||||||
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030
|
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030
|
||||||
|
@ -36,11 +36,14 @@ class LibrusRecaptchaHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private var timeout: Job? = null
|
private var timeout: Job? = null
|
||||||
|
private var timedOut = false
|
||||||
|
|
||||||
inner class WebViewClient : android.webkit.WebViewClient() {
|
inner class WebViewClient : android.webkit.WebViewClient() {
|
||||||
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
|
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
|
||||||
timeout?.cancel()
|
timeout?.cancel()
|
||||||
onSuccess(url)
|
if (!timedOut) {
|
||||||
|
onSuccess(url)
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -50,6 +53,7 @@ class LibrusRecaptchaHelper(
|
|||||||
webView.loadDataWithBaseURL(url, html, "text/html", "UTF-8", null)
|
webView.loadDataWithBaseURL(url, html, "text/html", "UTF-8", null)
|
||||||
}
|
}
|
||||||
timeout = startCoroutineTimer(delayMillis = 10000L) {
|
timeout = startCoroutineTimer(delayMillis = 10000L) {
|
||||||
|
timedOut = true
|
||||||
onTimeout()
|
onTimeout()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.R
|
|||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.*
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetList
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetList
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaGetMessages
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomework
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomework
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaInfo
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaInfo
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
@ -201,17 +202,27 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||||
LibrusSynergiaInfo(data, lastSync, onSuccess)
|
LibrusSynergiaInfo(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
|
ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_RECEIVED -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
|
LibrusSynergiaGetMessages(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_SENT -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||||
|
LibrusSynergiaGetMessages(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MESSAGES
|
* MESSAGES
|
||||||
*/
|
*/
|
||||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
|
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
|
if (data.messagesLoginSuccessful) LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
|
||||||
|
else LibrusSynergiaGetMessages(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_LIBRUS_MESSAGES_SENT -> {
|
ENDPOINT_LIBRUS_MESSAGES_SENT -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||||
LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
|
if (data.messagesLoginSuccessful) LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
|
||||||
|
else LibrusSynergiaGetMessages(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> onSuccess(endpointId)
|
else -> onSuccess(endpointId)
|
||||||
|
@ -91,6 +91,8 @@ open class LibrusSynergia(open val data: DataLibrus, open val lastSync: Long?) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun redirectUrlGet(tag: String, url: String, onSuccess: (url: String) -> Unit) {
|
fun redirectUrlGet(tag: String, url: String, onSuccess: (url: String) -> Unit) {
|
||||||
|
d(tag, "Request: Librus/Synergia - $url")
|
||||||
|
|
||||||
val callback = object : TextCallbackHandler() {
|
val callback = object : TextCallbackHandler() {
|
||||||
override fun onSuccess(text: String?, response: Response) {
|
override fun onSuccess(text: String?, response: Response) {
|
||||||
val redirectUrl = response.headers().get("Location")
|
val redirectUrl = response.headers().get("Location")
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusSandboxDownloadAttachment
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
|
|
||||||
|
class LibrusSynergiaGetAttachment(override val data: DataLibrus,
|
||||||
|
val message: Message,
|
||||||
|
val attachmentId: Long,
|
||||||
|
val attachmentName: String,
|
||||||
|
val onSuccess: () -> Unit
|
||||||
|
) : LibrusSynergia(data, null) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusSynergiaGetAttachment"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
redirectUrlGet(TAG, "$LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL/${message.id}/$attachmentId") { url ->
|
||||||
|
LibrusSandboxDownloadAttachment(data, url, message, attachmentId, attachmentName, onSuccess)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,160 @@
|
|||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
|
||||||
|
import pl.szczodrzynski.edziennik.get
|
||||||
|
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||||
|
import pl.szczodrzynski.edziennik.singleOrNull
|
||||||
|
import pl.szczodrzynski.edziennik.swapFirstLastName
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class LibrusSynergiaGetMessage(override val data: DataLibrus,
|
||||||
|
private val messageObject: MessageFull,
|
||||||
|
val onSuccess: () -> Unit) : LibrusSynergia(data, null) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusSynergiaGetMessage"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val endpoint = when (messageObject.type) {
|
||||||
|
Message.TYPE_SENT -> "wiadomosci/1/6/${messageObject.id}/f0"
|
||||||
|
else -> "wiadomosci/1/5/${messageObject.id}/f0"
|
||||||
|
}
|
||||||
|
|
||||||
|
data.profile?.also { profile ->
|
||||||
|
synergiaGet(TAG, endpoint) { text ->
|
||||||
|
val doc = Jsoup.parse(text)
|
||||||
|
|
||||||
|
val messageElement = doc.select(".container-message tr")[0].child(1)
|
||||||
|
val detailsElement = messageElement.child(1)
|
||||||
|
val readElement = messageElement.children().last()
|
||||||
|
|
||||||
|
val body = messageElement.select(".container-message-content").html()
|
||||||
|
|
||||||
|
messageObject.apply {
|
||||||
|
this.body = body
|
||||||
|
|
||||||
|
clearAttachments()
|
||||||
|
if (messageElement.children().size >= 5) {
|
||||||
|
messageElement.child(3).select("tr").forEachIndexed { i, attachment ->
|
||||||
|
if (i == 0) return@forEachIndexed // Skip the header
|
||||||
|
val filename = attachment.child(0).text().trim()
|
||||||
|
val attachmentId = "wiadomosci\\\\/pobierz_zalacznik\\\\/[0-9]+?\\\\/([0-9]+)\"".toRegex()
|
||||||
|
.find(attachment.select("img").attr("onclick"))?.get(1)
|
||||||
|
?: return@forEachIndexed
|
||||||
|
addAttachment(attachmentId.toLong(), filename, -1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientList = mutableListOf<MessageRecipientFull>()
|
||||||
|
|
||||||
|
when (messageObject.type) {
|
||||||
|
Message.TYPE_RECEIVED -> {
|
||||||
|
val senderFullName = detailsElement.child(0).select(".left").text()
|
||||||
|
val senderGroupName = "\\[(.+?)]".toRegex().find(senderFullName)?.get(1)?.trim()
|
||||||
|
|
||||||
|
data.teacherList.singleOrNull { it.id == messageObject.senderId }?.apply {
|
||||||
|
setTeacherType(when (senderGroupName) {
|
||||||
|
/* https://api.librus.pl/2.0/Messages/Role */
|
||||||
|
"Pomoc techniczna Librus", "SuperAdministrator" -> Teacher.TYPE_SUPER_ADMIN
|
||||||
|
"Administrator szkoły" -> Teacher.TYPE_SCHOOL_ADMIN
|
||||||
|
"Dyrektor Szkoły" -> Teacher.TYPE_PRINCIPAL
|
||||||
|
"Nauczyciel" -> Teacher.TYPE_TEACHER
|
||||||
|
"Rodzic", "Opiekun" -> Teacher.TYPE_PARENT
|
||||||
|
"Sekretariat" -> Teacher.TYPE_SECRETARIAT
|
||||||
|
"Uczeń" -> Teacher.TYPE_STUDENT
|
||||||
|
"Pedagog/Psycholog szkolny" -> Teacher.TYPE_PEDAGOGUE
|
||||||
|
"Pracownik biblioteki" -> Teacher.TYPE_LIBRARIAN
|
||||||
|
"Inny specjalista" -> Teacher.TYPE_SPECIALIST
|
||||||
|
"Jednostka Nadrzędna" -> {
|
||||||
|
typeDescription = "Jednostka Nadrzędna"
|
||||||
|
Teacher.TYPE_OTHER
|
||||||
|
}
|
||||||
|
"Jednostka Samorządu Terytorialnego" -> {
|
||||||
|
typeDescription = "Jednostka Samorządu Terytorialnego"
|
||||||
|
Teacher.TYPE_OTHER
|
||||||
|
}
|
||||||
|
else -> Teacher.TYPE_OTHER
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
val readDateText = readElement.select(".left").text()
|
||||||
|
val readDate = when (readDateText.isNotNullNorEmpty()) {
|
||||||
|
true -> Date.fromIso(readDateText)
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipientFull(
|
||||||
|
profileId = profileId,
|
||||||
|
id = -1,
|
||||||
|
messageId = messageObject.id,
|
||||||
|
readDate = readDate
|
||||||
|
)
|
||||||
|
|
||||||
|
messageRecipientObject.fullName = profile.accountName
|
||||||
|
?: profile.studentNameLong
|
||||||
|
|
||||||
|
messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
Message.TYPE_SENT -> {
|
||||||
|
|
||||||
|
readElement.select("tr").forEachIndexed { i, receiver ->
|
||||||
|
if (i == 0) return@forEachIndexed // Skip the header
|
||||||
|
|
||||||
|
val receiverFullName = receiver.child(0).text()
|
||||||
|
val receiverName = receiverFullName.split('(')[0].swapFirstLastName()
|
||||||
|
|
||||||
|
val teacher = data.teacherList.singleOrNull { it.fullName == receiverName }
|
||||||
|
val receiverId = teacher?.id ?: -1
|
||||||
|
|
||||||
|
val readDate = when (val readDateText = receiver.child(1).text().trim()) {
|
||||||
|
"NIE" -> 0
|
||||||
|
else -> Date.fromIso(readDateText)
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipientFull(
|
||||||
|
profileId = profileId,
|
||||||
|
id = receiverId,
|
||||||
|
messageId = messageObject.id,
|
||||||
|
readDate = readDate
|
||||||
|
)
|
||||||
|
|
||||||
|
messageRecipientObject.fullName = receiverName
|
||||||
|
|
||||||
|
messageRecipientList.add(messageRecipientObject)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!messageObject.seen) {
|
||||||
|
data.setSeenMetadataList.add(Metadata(
|
||||||
|
messageObject.profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
messageObject.id,
|
||||||
|
true,
|
||||||
|
true
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
messageObject.recipients = messageRecipientList
|
||||||
|
data.messageRecipientList.addAll(messageRecipientList)
|
||||||
|
|
||||||
|
data.messageList.add(messageObject)
|
||||||
|
data.messageListReplace = true
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
} ?: onSuccess()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,116 @@
|
|||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
|
||||||
|
|
||||||
|
import org.jsoup.Jsoup
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_NOT_IMPLEMENTED
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class LibrusSynergiaGetMessages(override val data: DataLibrus,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
private val type: Int = Message.TYPE_RECEIVED,
|
||||||
|
archived: Boolean = false,
|
||||||
|
val onSuccess: (Int) -> Unit) : LibrusSynergia(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "LibrusSynergiaGetMessages"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
val endpoint = when (type) {
|
||||||
|
Message.TYPE_RECEIVED -> "wiadomosci/5"
|
||||||
|
Message.TYPE_SENT -> "wiadomosci/6"
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
val endpointId = when (type) {
|
||||||
|
Message.TYPE_RECEIVED -> ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_RECEIVED
|
||||||
|
else -> ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_SENT
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpoint != null) {
|
||||||
|
synergiaGet(TAG, endpoint) { text ->
|
||||||
|
val doc = Jsoup.parse(text)
|
||||||
|
|
||||||
|
fun getRecipientId(name: String): Long = data.teacherList.singleOrNull {
|
||||||
|
it.fullNameLastFirst == name
|
||||||
|
}?.id ?: {
|
||||||
|
val teacherObject = Teacher(
|
||||||
|
profileId,
|
||||||
|
-1 * Utils.crc16(name.swapFirstLastName().toByteArray()).toLong(),
|
||||||
|
name.splitName()?.second!!,
|
||||||
|
name.splitName()?.first!!
|
||||||
|
)
|
||||||
|
data.teacherList.put(teacherObject.id, teacherObject)
|
||||||
|
teacherObject.id
|
||||||
|
}.invoke()
|
||||||
|
|
||||||
|
doc.select(".decorated.stretch tbody > tr").forEach { messageElement ->
|
||||||
|
val url = messageElement.select("a").first().attr("href")
|
||||||
|
val id = Regexes.LIBRUS_MESSAGE_ID.find(url)?.get(1)?.toLong() ?: return@forEach
|
||||||
|
val subject = messageElement.child(3).text()
|
||||||
|
val sentDate = Date.fromIso(messageElement.child(4).text())
|
||||||
|
val recipientName = messageElement.child(2).text().split('(')[0].fixName()
|
||||||
|
val recipientId = getRecipientId(recipientName)
|
||||||
|
val read = messageElement.child(2).attr("style").isNullOrBlank()
|
||||||
|
|
||||||
|
val senderId = when (type) {
|
||||||
|
Message.TYPE_RECEIVED -> recipientId
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
val receiverId = when (type) {
|
||||||
|
Message.TYPE_RECEIVED -> -1
|
||||||
|
else -> recipientId
|
||||||
|
}
|
||||||
|
|
||||||
|
val notified = when (type) {
|
||||||
|
Message.TYPE_SENT -> true
|
||||||
|
else -> read || profile?.empty ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
val messageObject = Message(
|
||||||
|
profileId = profileId,
|
||||||
|
id = id,
|
||||||
|
type = type,
|
||||||
|
subject = subject,
|
||||||
|
body = null,
|
||||||
|
senderId = senderId,
|
||||||
|
addedDate = sentDate
|
||||||
|
)
|
||||||
|
|
||||||
|
val messageRecipientObject = MessageRecipient(
|
||||||
|
profileId,
|
||||||
|
receiverId,
|
||||||
|
-1,
|
||||||
|
if (read) 1 else 0,
|
||||||
|
id
|
||||||
|
)
|
||||||
|
|
||||||
|
messageObject.hasAttachments = !messageElement.child(1).select("img").isEmpty()
|
||||||
|
|
||||||
|
data.messageList.add(messageObject)
|
||||||
|
data.messageRecipientList.add(messageRecipientObject)
|
||||||
|
data.setSeenMetadataList.add(Metadata(
|
||||||
|
profileId,
|
||||||
|
Metadata.TYPE_MESSAGE,
|
||||||
|
id,
|
||||||
|
notified,
|
||||||
|
notified
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
when (type) {
|
||||||
|
Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
||||||
|
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, MainActivity.DRAWER_ITEM_MESSAGES)
|
||||||
|
}
|
||||||
|
onSuccess(endpointId)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
data.error(TAG, ERROR_NOT_IMPLEMENTED)
|
||||||
|
onSuccess(endpointId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -33,7 +33,7 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
val accounts = json.getJsonArray("accounts")
|
val accounts = json.getJsonArray("accounts")
|
||||||
|
|
||||||
if (accounts == null || accounts.size() < 1) {
|
if (accounts == null || accounts.size() < 1) {
|
||||||
EventBus.getDefault().post(FirstLoginFinishedEvent(listOf(), data.loginStore))
|
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore))
|
||||||
onSuccess()
|
onSuccess()
|
||||||
return@portalGet
|
return@portalGet
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
profileList.add(profile)
|
profileList.add(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,14 +116,15 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
).apply {
|
).apply {
|
||||||
studentData["isPremium"] = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true
|
studentData["isPremium"] = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true
|
||||||
studentData["accountId"] = account.getInt("Id") ?: 0
|
studentData["accountId"] = account.getInt("Id") ?: 0
|
||||||
studentData["accountLogin"] = login
|
studentData["accountLogin"] = data.apiLogin ?: login
|
||||||
|
studentData["accountPassword"] = data.apiPassword
|
||||||
studentData["accountToken"] = data.apiAccessToken
|
studentData["accountToken"] = data.apiAccessToken
|
||||||
studentData["accountTokenTime"] = data.apiTokenExpiryTime
|
studentData["accountTokenTime"] = data.apiTokenExpiryTime
|
||||||
studentData["accountRefreshToken"] = data.apiRefreshToken
|
studentData["accountRefreshToken"] = data.apiRefreshToken
|
||||||
}
|
}
|
||||||
profileList.add(profile)
|
profileList.add(profile)
|
||||||
|
|
||||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.getUnixDate
|
|||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
import java.net.HttpURLConnection.*
|
import java.net.HttpURLConnection.*
|
||||||
|
|
||||||
|
@Suppress("ConvertSecondaryConstructorToPrimary")
|
||||||
class LibrusLoginApi {
|
class LibrusLoginApi {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "LoginLibrusApi"
|
private const val TAG = "LoginLibrusApi"
|
||||||
|
@ -38,14 +38,18 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
|
|
||||||
text?.contains("grecaptcha.ready") == true -> {
|
text?.contains("grecaptcha.ready") == true -> {
|
||||||
val url = response?.request()?.url()?.toString() ?: run {
|
val url = response?.request()?.url()?.toString() ?: run {
|
||||||
data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
//data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||||
|
data.messagesLoginSuccessful = false
|
||||||
|
onSuccess()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
LibrusRecaptchaHelper(data.app, url, text, onSuccess = { newUrl ->
|
LibrusRecaptchaHelper(data.app, url, text, onSuccess = { newUrl ->
|
||||||
loginWithSynergia(newUrl)
|
loginWithSynergia(newUrl)
|
||||||
}, onTimeout = {
|
}, onTimeout = {
|
||||||
data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_TIMEOUT, response, text)
|
//data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_TIMEOUT, response, text)
|
||||||
|
data.messagesLoginSuccessful = false
|
||||||
|
onSuccess()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,7 +59,11 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||||
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||||
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
text?.contains("eAccessDeny") == true -> {
|
||||||
|
// data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
|
data.messagesLoginSuccessful = false
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||||
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||||
text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||||
|
@ -66,7 +66,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
override fun onSuccess(text: String, response: Response) {
|
override fun onSuccess(text: String, response: Response) {
|
||||||
val location = response.headers().get("Location")
|
val location = response.headers().get("Location")
|
||||||
if (location != null) {
|
if (location != null) {
|
||||||
val authMatcher = Pattern.compile("http://localhost/bar\\?code=([A-z0-9]+?)$", Pattern.DOTALL or Pattern.MULTILINE).matcher(location)
|
val authMatcher = Pattern.compile("$LIBRUS_REDIRECT_URL\\?code=([A-z0-9]+?)$", Pattern.DOTALL or Pattern.MULTILINE).matcher(location)
|
||||||
when {
|
when {
|
||||||
authMatcher.find() -> {
|
authMatcher.find() -> {
|
||||||
accessToken(authMatcher.group(1), null)
|
accessToken(authMatcher.group(1), null)
|
||||||
@ -127,7 +127,7 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
|||||||
.callback(object : JsonCallbackHandler() {
|
.callback(object : JsonCallbackHandler() {
|
||||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||||
val location = response.headers()?.get("Location")
|
val location = response.headers()?.get("Location")
|
||||||
if (location == "http://localhost/bar?command=close") {
|
if (location == "$LIBRUS_REDIRECT_URL?command=close") {
|
||||||
data.error(ApiError(TAG, ERROR_LIBRUS_PORTAL_MAINTENANCE)
|
data.error(ApiError(TAG, ERROR_LIBRUS_PORTAL_MAINTENANCE)
|
||||||
.withApiResponse(json)
|
.withApiResponse(json)
|
||||||
.withResponse(response))
|
.withResponse(response))
|
||||||
@ -146,12 +146,14 @@ 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
|
||||||
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
|
// this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set
|
||||||
code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL
|
code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL
|
||||||
|
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 ->
|
||||||
data.error(ApiError(TAG, errorCode)
|
data.error(ApiError(TAG, errorCode)
|
||||||
|
@ -130,7 +130,6 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
|||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
d(TAG, "Cancelled")
|
d(TAG, "Cancelled")
|
||||||
data.cancel()
|
data.cancel()
|
||||||
callback.onCompleted()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
|
@ -44,7 +44,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
|
|||||||
|
|
||||||
dataDays.remove(date.value)
|
dataDays.remove(date.value)
|
||||||
|
|
||||||
val subjectId = data.subjectList.singleOrNull { it.longName == lesson[5] }?.id ?: -1
|
val subjectId = data.subjectList.singleOrNull { it.longName == lesson[5].trim() }?.id ?: -1
|
||||||
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == (lesson[7]+" "+lesson[6]).fixName() }?.id ?: -1
|
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == (lesson[7]+" "+lesson[6]).fixName() }?.id ?: -1
|
||||||
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
|
val teamId = data.teamList.singleOrNull { it.name == lesson[8]+lesson[9] }?.id ?: -1
|
||||||
val classroom = lesson[11]
|
val classroom = lesson[11]
|
||||||
|
@ -91,8 +91,11 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
|
|||||||
|
|
||||||
Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult ->
|
Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult ->
|
||||||
val table = tableResult[1]
|
val table = tableResult[1]
|
||||||
|
|
||||||
val lessonDates = mutableListOf<Date>()
|
val lessonDates = mutableListOf<Date>()
|
||||||
val entries = mutableListOf<String>()
|
val entries = mutableListOf<String>()
|
||||||
|
val ranges = mutableListOf<MatchResult?>()
|
||||||
|
|
||||||
Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON_COUNT.findAll(table).forEach {
|
Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON_COUNT.findAll(table).forEach {
|
||||||
val date = Date.fromY_m_d(it[1])
|
val date = Date.fromY_m_d(it[1])
|
||||||
for (i in 0 until (it[2].toIntOrNull() ?: 0)) {
|
for (i in 0 until (it[2].toIntOrNull() ?: 0)) {
|
||||||
@ -101,96 +104,52 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
|
|||||||
}
|
}
|
||||||
Regexes.MOBIDZIENNIK_ATTENDANCE_ENTRIES.findAll(table).mapTo(entries) { it[1] }
|
Regexes.MOBIDZIENNIK_ATTENDANCE_ENTRIES.findAll(table).mapTo(entries) { it[1] }
|
||||||
|
|
||||||
|
Regexes.MOBIDZIENNIK_ATTENDANCE_COLUMNS.findAll(table).forEach { columns ->
|
||||||
|
var index = 0
|
||||||
|
Regexes.MOBIDZIENNIK_ATTENDANCE_COLUMN.findAll(columns[1]).forEach { column ->
|
||||||
|
if (column[1].contains("colspan")) {
|
||||||
|
val colspan =
|
||||||
|
Regexes.MOBIDZIENNIK_ATTENDANCE_COLUMN_SPAN.find(column[1])
|
||||||
|
?.get(1)
|
||||||
|
?.toIntOrNull() ?: 0
|
||||||
|
entries.addAll(index, List(colspan) { "" })
|
||||||
|
ranges.addAll(List(colspan) { null })
|
||||||
|
index += colspan
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
val range = Regexes.MOBIDZIENNIK_ATTENDANCE_RANGE.find(column[2])
|
||||||
|
ranges.add(range)
|
||||||
|
index++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val dateIterator = lessonDates.iterator()
|
val dateIterator = lessonDates.iterator()
|
||||||
val entriesIterator = entries.iterator()
|
val entriesIterator = entries.iterator()
|
||||||
Regexes.MOBIDZIENNIK_ATTENDANCE_RANGE.findAll(table).let { ranges ->
|
|
||||||
val count = ranges.count()
|
val count = ranges.count()
|
||||||
// verify the lesson count is the same as dates & entries
|
// verify the lesson count is the same as dates & entries
|
||||||
if (count != lessonDates.count() || count != entries.count())
|
if (count != lessonDates.count() || count != entries.count())
|
||||||
|
return@forEach
|
||||||
|
ranges.forEach { range ->
|
||||||
|
val lessonDate = dateIterator.next()
|
||||||
|
val entry = entriesIterator.next()
|
||||||
|
if (range == null || entry.isBlank())
|
||||||
return@forEach
|
return@forEach
|
||||||
ranges.forEach { range ->
|
val startTime = Time.fromH_m(range[1])
|
||||||
val lessonDate = dateIterator.next()
|
|
||||||
var entry = entriesIterator.next()
|
|
||||||
if (entry.isBlank())
|
|
||||||
return@forEach
|
|
||||||
val startTime = Time.fromH_m(range[1])
|
|
||||||
|
|
||||||
range[2].split(" / ").mapNotNull { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it) }.forEachIndexed { index, lesson ->
|
range[2].split(" / ").mapNotNull {
|
||||||
val topic = lesson[1].substringAfter(" - ", missingDelimiterValue = "").takeIf { it.isNotBlank() }
|
Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it)
|
||||||
if (topic?.startsWith("Lekcja odwołana: ") == true || entry.isEmpty())
|
}.forEachIndexed { index, lesson ->
|
||||||
return@forEachIndexed
|
processEntry(
|
||||||
val subjectName = lesson[1].substringBefore(" - ")
|
index,
|
||||||
//val team = lesson[3]
|
lesson,
|
||||||
val teacherName = lesson[3].fixName()
|
lessonDate,
|
||||||
|
startTime,
|
||||||
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1
|
entry,
|
||||||
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1
|
types,
|
||||||
|
typeSymbols
|
||||||
var typeSymbol = ""
|
)
|
||||||
for (symbol in typeSymbols) {
|
|
||||||
if (entry.startsWith(symbol) && symbol.length > typeSymbol.length)
|
|
||||||
typeSymbol = symbol
|
|
||||||
}
|
|
||||||
entry = entry.removePrefix(typeSymbol)
|
|
||||||
|
|
||||||
var isCounted = true
|
|
||||||
val baseType = when (typeSymbol) {
|
|
||||||
"." -> TYPE_PRESENT
|
|
||||||
"|" -> TYPE_ABSENT
|
|
||||||
"+" -> TYPE_ABSENT_EXCUSED
|
|
||||||
"s" -> TYPE_BELATED
|
|
||||||
"z" -> TYPE_RELEASED
|
|
||||||
else -> {
|
|
||||||
isCounted = false
|
|
||||||
when (typeSymbol) {
|
|
||||||
"e" -> TYPE_PRESENT_CUSTOM
|
|
||||||
"en" -> TYPE_ABSENT
|
|
||||||
"ep" -> TYPE_PRESENT_CUSTOM
|
|
||||||
else -> TYPE_UNKNOWN
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val typeName = types?.get(typeSymbol) ?: ""
|
|
||||||
|
|
||||||
val typeShort = when (baseType) {
|
|
||||||
TYPE_UNKNOWN -> typeSymbol
|
|
||||||
else -> data.app.attendanceManager.getTypeShort(baseType)
|
|
||||||
}
|
|
||||||
|
|
||||||
val semester = data.profile?.dateToSemester(lessonDate) ?: 1
|
|
||||||
|
|
||||||
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index
|
|
||||||
|
|
||||||
val attendanceObject = Attendance(
|
|
||||||
profileId = profileId,
|
|
||||||
id = id,
|
|
||||||
baseType = baseType,
|
|
||||||
typeName = typeName,
|
|
||||||
typeShort = typeShort,
|
|
||||||
typeSymbol = typeSymbol,
|
|
||||||
typeColor = null,
|
|
||||||
date = lessonDate,
|
|
||||||
startTime = startTime,
|
|
||||||
semester = semester,
|
|
||||||
teacherId = teacherId,
|
|
||||||
subjectId = subjectId
|
|
||||||
).also {
|
|
||||||
it.lessonTopic = topic
|
|
||||||
it.isCounted = isCounted
|
|
||||||
}
|
|
||||||
|
|
||||||
data.attendanceList.add(attendanceObject)
|
|
||||||
if (baseType != TYPE_PRESENT) {
|
|
||||||
data.metadataList.add(
|
|
||||||
Metadata(
|
|
||||||
data.profileId,
|
|
||||||
Metadata.TYPE_ATTENDANCE,
|
|
||||||
id,
|
|
||||||
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
|
|
||||||
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -200,4 +159,98 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
|
|||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun processEntry(
|
||||||
|
index: Int,
|
||||||
|
lesson: MatchResult,
|
||||||
|
lessonDate: Date,
|
||||||
|
startTime: Time,
|
||||||
|
entry: String,
|
||||||
|
types: Map<String?, String?>?,
|
||||||
|
typeSymbols: List<String>
|
||||||
|
) {
|
||||||
|
var entry = entry
|
||||||
|
|
||||||
|
val topic = lesson[1].substringAfter(" - ", missingDelimiterValue = "").takeIf { it.isNotBlank() }
|
||||||
|
if (topic?.startsWith("Lekcja odwołana: ") == true || entry.isEmpty())
|
||||||
|
return
|
||||||
|
val subjectName = lesson[1].substringBefore(" - ").trim()
|
||||||
|
//val team = lesson[3]
|
||||||
|
val teacherName = lesson[3].fixName()
|
||||||
|
|
||||||
|
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1
|
||||||
|
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1
|
||||||
|
|
||||||
|
var typeSymbol = ""
|
||||||
|
for (symbol in typeSymbols) {
|
||||||
|
if (entry.startsWith(symbol) && symbol.length > typeSymbol.length)
|
||||||
|
typeSymbol = symbol
|
||||||
|
}
|
||||||
|
entry = entry.removePrefix(typeSymbol)
|
||||||
|
|
||||||
|
var isCustom = false
|
||||||
|
val baseType = when (typeSymbol) {
|
||||||
|
"." -> TYPE_PRESENT
|
||||||
|
"|" -> TYPE_ABSENT
|
||||||
|
"+" -> TYPE_ABSENT_EXCUSED
|
||||||
|
"s" -> TYPE_BELATED
|
||||||
|
"z" -> TYPE_RELEASED
|
||||||
|
else -> {
|
||||||
|
isCustom = true
|
||||||
|
when (typeSymbol) {
|
||||||
|
"e" -> TYPE_PRESENT_CUSTOM
|
||||||
|
"en" -> TYPE_ABSENT
|
||||||
|
"ep" -> TYPE_PRESENT_CUSTOM
|
||||||
|
"+ₑ" -> TYPE_ABSENT_EXCUSED
|
||||||
|
else -> TYPE_UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val typeName = types?.get(typeSymbol) ?: ""
|
||||||
|
val typeColor = when (typeSymbol) {
|
||||||
|
"e" -> 0xff673ab7
|
||||||
|
"en" -> 0xffec407a
|
||||||
|
"ep" -> 0xff4caf50
|
||||||
|
"+ₑ" -> 0xff795548
|
||||||
|
else -> null
|
||||||
|
}?.toInt()
|
||||||
|
|
||||||
|
val typeShort = if (!isCustom)
|
||||||
|
data.app.attendanceManager.getTypeShort(baseType)
|
||||||
|
else
|
||||||
|
typeSymbol
|
||||||
|
|
||||||
|
val semester = data.profile?.dateToSemester(lessonDate) ?: 1
|
||||||
|
|
||||||
|
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index
|
||||||
|
|
||||||
|
val attendanceObject = Attendance(
|
||||||
|
profileId = profileId,
|
||||||
|
id = id,
|
||||||
|
baseType = baseType,
|
||||||
|
typeName = typeName,
|
||||||
|
typeShort = typeShort,
|
||||||
|
typeSymbol = typeSymbol,
|
||||||
|
typeColor = typeColor,
|
||||||
|
date = lessonDate,
|
||||||
|
startTime = startTime,
|
||||||
|
semester = semester,
|
||||||
|
teacherId = teacherId,
|
||||||
|
subjectId = subjectId
|
||||||
|
).also {
|
||||||
|
it.lessonTopic = topic
|
||||||
|
}
|
||||||
|
|
||||||
|
data.attendanceList.add(attendanceObject)
|
||||||
|
if (baseType != TYPE_PRESENT) {
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_ATTENDANCE,
|
||||||
|
id,
|
||||||
|
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
|
||||||
|
data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,16 +74,16 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik,
|
|||||||
message.senderId = null
|
message.senderId = null
|
||||||
|
|
||||||
content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
|
content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
|
||||||
val senderEl = recipientEl.select("td:eq(0)").first()
|
val senderEl = recipientEl.select("td:eq(1)")?.first() ?: return@forEach
|
||||||
val senderName = senderEl.text().fixName()
|
val senderName = senderEl.text().fixName()
|
||||||
|
|
||||||
val teacher = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }
|
val teacher = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }
|
||||||
val receiverId = teacher?.id ?: -1
|
val receiverId = teacher?.id ?: -1
|
||||||
|
|
||||||
var readDate = 0L
|
var readDate = 0L
|
||||||
val isReadEl = recipientEl.select("td:eq(2)").first()
|
val isReadEl = recipientEl.select("td:eq(4)")?.first() ?: return@forEach
|
||||||
if (isReadEl.ownText() != "NIE") {
|
if (isReadEl.html().contains("tak")) {
|
||||||
val readDateEl = recipientEl.select("td:eq(3) small").first()
|
val readDateEl = recipientEl.select("td:eq(5) small")?.first() ?: return@forEach
|
||||||
Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_DATE.find(readDateEl.ownText())?.let {
|
Regexes.MOBIDZIENNIK_MESSAGE_SENT_READ_DATE.find(readDateEl.ownText())?.let {
|
||||||
val date = Date(
|
val date = Date(
|
||||||
it[3].toIntOrNull() ?: 2019,
|
it[3].toIntOrNull() ?: 2019,
|
||||||
|
@ -56,20 +56,21 @@ class MobidziennikWebGetRecipientList(override val data: DataMobidziennik,
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processRecipient(listType: Int, listName: String, recipient: JsonObject) {
|
private fun processRecipient(listType: Int, listName: String, recipient: JsonObject) {
|
||||||
val id = recipient.getLong("id") ?: -1
|
val id = recipient.getString("id") ?: return
|
||||||
|
val idLong = id.replace(Regexes.NOT_DIGITS, "").toLongOrNull() ?: return
|
||||||
// get teacher by ID or create it
|
// get teacher by ID or create it
|
||||||
val teacher = data.teacherList[id] ?: Teacher(data.profileId, id).apply {
|
val teacher = data.teacherList[idLong] ?: Teacher(data.profileId, idLong).apply {
|
||||||
val fullName = recipient.getString("nazwa")?.fixName()
|
val fullName = recipient.getString("nazwa")?.fixName()
|
||||||
name = fullName ?: ""
|
name = fullName ?: ""
|
||||||
fullName?.splitName()?.let {
|
fullName?.splitName()?.let {
|
||||||
name = it.second
|
name = it.second
|
||||||
surname = it.first
|
surname = it.first
|
||||||
}
|
}
|
||||||
data.teacherList[id] = this
|
data.teacherList[idLong] = this
|
||||||
}
|
}
|
||||||
|
|
||||||
teacher.apply {
|
teacher.apply {
|
||||||
loginId = id.toString()
|
loginId = id
|
||||||
when (listType) {
|
when (listType) {
|
||||||
1 -> setTeacherType(Teacher.TYPE_PRINCIPAL)
|
1 -> setTeacherType(Teacher.TYPE_PRINCIPAL)
|
||||||
2 -> setTeacherType(Teacher.TYPE_TEACHER)
|
2 -> setTeacherType(Teacher.TYPE_TEACHER)
|
||||||
|
@ -46,7 +46,7 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
|
|||||||
when (e.tagName()) {
|
when (e.tagName()) {
|
||||||
"div" -> {
|
"div" -> {
|
||||||
Regexes.MOBIDZIENNIK_GRADES_SUBJECT_NAME.find(e.outerHtml())?.let {
|
Regexes.MOBIDZIENNIK_GRADES_SUBJECT_NAME.find(e.outerHtml())?.let {
|
||||||
subjectName = it[1]
|
subjectName = it[1].trim()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
"span" -> {
|
"span" -> {
|
||||||
|
@ -85,7 +85,7 @@ class MobidziennikFirstLogin(val data: DataMobidziennik, val onSuccess: () -> Un
|
|||||||
profileList.add(profile)
|
profileList.add(profile)
|
||||||
}
|
}
|
||||||
|
|
||||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||||
onSuccess()
|
onSuccess()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,119 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.*
|
||||||
|
import kotlin.text.replace
|
||||||
|
|
||||||
|
class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||||
|
|
||||||
|
fun isApiLoginValid() = apiToken.isNotNullNorEmpty()
|
||||||
|
|
||||||
|
override fun satisfyLoginMethods() {
|
||||||
|
loginMethods.clear()
|
||||||
|
if (isApiLoginValid())
|
||||||
|
loginMethods += LOGIN_METHOD_PODLASIE_API
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateUserCode(): String = "$schoolShortName:$loginShort:${studentId?.crc32()}"
|
||||||
|
|
||||||
|
/* _
|
||||||
|
/\ (_)
|
||||||
|
/ \ _ __ _
|
||||||
|
/ /\ \ | '_ \| |
|
||||||
|
/ ____ \| |_) | |
|
||||||
|
/_/ \_\ .__/|_|
|
||||||
|
| |
|
||||||
|
|*/
|
||||||
|
private var mApiToken: String? = null
|
||||||
|
var apiToken: String?
|
||||||
|
get() { mApiToken = mApiToken ?: loginStore.getLoginData("apiToken", null); return mApiToken }
|
||||||
|
set(value) { loginStore.putLoginData("apiToken", value); mApiToken = value }
|
||||||
|
|
||||||
|
private var mApiUrl: String? = null
|
||||||
|
var apiUrl: String?
|
||||||
|
get() { mApiUrl = mApiUrl ?: profile?.getStudentData("apiUrl", null); return mApiUrl }
|
||||||
|
set(value) { profile?.putStudentData("apiUrl", value) ?: return; mApiUrl = 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 mStudentLogin: String? = null
|
||||||
|
var studentLogin: String?
|
||||||
|
get() { mStudentLogin = mStudentLogin ?: profile?.getStudentData("studentLogin", null); return mStudentLogin }
|
||||||
|
set(value) { profile?.putStudentData("studentLogin", value) ?: return; mStudentLogin = 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 }
|
||||||
|
|
||||||
|
private var mClassName: String? = null
|
||||||
|
var className: String?
|
||||||
|
get() { mClassName = mClassName ?: profile?.getStudentData("className", null); return mClassName }
|
||||||
|
set(value) { profile?.putStudentData("className", value) ?: return; mClassName = value }
|
||||||
|
|
||||||
|
private var mSchoolYear: String? = null
|
||||||
|
var schoolYear: String?
|
||||||
|
get() { mSchoolYear = mSchoolYear ?: profile?.getStudentData("schoolYear", null); return mSchoolYear }
|
||||||
|
set(value) { profile?.putStudentData("schoolYear", value) ?: return; mSchoolYear = value }
|
||||||
|
|
||||||
|
private var mCurrentSemester: Int? = null
|
||||||
|
var currentSemester: Int
|
||||||
|
get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 0); return mCurrentSemester ?: 0 }
|
||||||
|
set(value) { profile?.putStudentData("currentSemester", value) ?: return; mCurrentSemester = value }
|
||||||
|
|
||||||
|
val schoolShortName: String?
|
||||||
|
get() = studentLogin?.split('@')?.get(1)?.replace(".podlaskie.pl", "")
|
||||||
|
|
||||||
|
val loginShort: String?
|
||||||
|
get() = studentLogin?.split('@')?.get(0)
|
||||||
|
|
||||||
|
fun getSubject(name: String): Subject {
|
||||||
|
val id = name.crc32()
|
||||||
|
return subjectList.singleOrNull { it.id == id } ?: run {
|
||||||
|
val subject = Subject(profileId, id, name, name)
|
||||||
|
subjectList.put(id, subject)
|
||||||
|
subject
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTeacher(firstName: String, lastName: String): Teacher {
|
||||||
|
val name = "$firstName $lastName".fixName()
|
||||||
|
return teacherList.singleOrNull { it.fullName == name } ?: run {
|
||||||
|
val id = name.crc32()
|
||||||
|
val teacher = Teacher(profileId, id, firstName, lastName)
|
||||||
|
teacherList.put(id, teacher)
|
||||||
|
teacher
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTeam(name: String? = null): Team {
|
||||||
|
if (name == "cała klasa" || name == null) return teamClass ?: run {
|
||||||
|
val id = className!!.crc32()
|
||||||
|
val teamCode = "$schoolShortName:$className"
|
||||||
|
val team = Team(profileId, id, className, Team.TYPE_CLASS, teamCode, -1)
|
||||||
|
teamList.put(id, team)
|
||||||
|
return team
|
||||||
|
} else {
|
||||||
|
val id = name.crc32()
|
||||||
|
val teamCode = "$schoolShortName:$name"
|
||||||
|
val team = Team(profileId, id, name, Team.TYPE_VIRTUAL, teamCode, -1)
|
||||||
|
teamList.put(id, team)
|
||||||
|
return team
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,166 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.helper.DownloadAttachment
|
||||||
|
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.login.PodlasieLogin
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
|
||||||
|
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.podlasieLoginMethods
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||||
|
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
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "Podlasie"
|
||||||
|
}
|
||||||
|
|
||||||
|
val internalErrorList = mutableListOf<Int>()
|
||||||
|
val data: DataPodlasie
|
||||||
|
|
||||||
|
init {
|
||||||
|
data = DataPodlasie(app, profile, loginStore).apply {
|
||||||
|
callback = wrapCallback(this@Podlasie.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(podlasieLoginMethods, PodlasieFeatures, featureIds, viewId, onlyEndpoints)
|
||||||
|
Utils.d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||||
|
Utils.d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||||
|
PodlasieLogin(data) {
|
||||||
|
PodlasieData(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) {
|
||||||
|
val fileUrl = attachmentName.substringAfter(":")
|
||||||
|
DownloadAttachment(fileUrl,
|
||||||
|
onSuccess = { file ->
|
||||||
|
val event = AttachmentGetEvent(
|
||||||
|
data.profileId,
|
||||||
|
owner,
|
||||||
|
attachmentId,
|
||||||
|
AttachmentGetEvent.TYPE_FINISHED,
|
||||||
|
file.absolutePath
|
||||||
|
)
|
||||||
|
|
||||||
|
val attachmentDataFile = File(Utils.getStorageDir(), ".${data.profileId}_${event.ownerId}_${event.attachmentId}")
|
||||||
|
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(event)
|
||||||
|
|
||||||
|
completed()
|
||||||
|
},
|
||||||
|
onProgress = { written, _ ->
|
||||||
|
val event = AttachmentGetEvent(
|
||||||
|
data.profileId,
|
||||||
|
owner,
|
||||||
|
attachmentId,
|
||||||
|
AttachmentGetEvent.TYPE_PROGRESS,
|
||||||
|
bytesWritten = written
|
||||||
|
)
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(event)
|
||||||
|
},
|
||||||
|
onError = { apiError ->
|
||||||
|
data.error(apiError)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRecipientList() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getEvent(eventFull: EventFull) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun firstLogin() {
|
||||||
|
PodlasieFirstLogin(data) {
|
||||||
|
completed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun cancel() {
|
||||||
|
Utils.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) {
|
||||||
|
// TODO Error handling
|
||||||
|
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,18 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.FEATURE_ALWAYS_NEEDED
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_PODLASIE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||||
|
|
||||||
|
const val ENDPOINT_PODLASIE_API_MAIN = 1001
|
||||||
|
|
||||||
|
val PodlasieFeatures = listOf(
|
||||||
|
Feature(LOGIN_TYPE_PODLASIE, FEATURE_ALWAYS_NEEDED, listOf(
|
||||||
|
ENDPOINT_PODLASIE_API_MAIN to LOGIN_METHOD_PODLASIE_API
|
||||||
|
), listOf(LOGIN_METHOD_PODLASIE_API))
|
||||||
|
)
|
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import im.wangchao.mhttp.Request
|
||||||
|
import im.wangchao.mhttp.RequestParams
|
||||||
|
import im.wangchao.mhttp.Response
|
||||||
|
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.getJsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.toHexString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import java.security.MessageDigest
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
open class PodlasieApi(open val data: DataPodlasie, open val lastSync: Long?) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "PodlasieApi"
|
||||||
|
}
|
||||||
|
|
||||||
|
val profileId
|
||||||
|
get() = data.profile?.id ?: -1
|
||||||
|
|
||||||
|
val profile
|
||||||
|
get() = data.profile
|
||||||
|
|
||||||
|
fun apiGet(tag: String, endpoint: String, onSuccess: (json: JsonObject) -> Unit) {
|
||||||
|
val url = PODLASIE_API_URL + endpoint
|
||||||
|
|
||||||
|
Utils.d(tag, "Request: Podlasie/Api - $url")
|
||||||
|
|
||||||
|
if (data.apiToken == null) {
|
||||||
|
data.error(tag, ERROR_PODLASIE_API_NO_TOKEN)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val callback = object : JsonCallbackHandler() {
|
||||||
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (json == null || response == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
|
.withResponse(response))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val error = json.getJsonObject("system_message")?.getInt("code")
|
||||||
|
|
||||||
|
error?.let { code ->
|
||||||
|
when (code) {
|
||||||
|
0 -> ERROR_PODLASIE_API_DATA_MISSING
|
||||||
|
4 -> ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT
|
||||||
|
5 -> ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN
|
||||||
|
200 -> null // Not an error
|
||||||
|
else -> ERROR_PODLASIE_API_OTHER
|
||||||
|
}?.let { errorCode ->
|
||||||
|
data.error(ApiError(tag, errorCode)
|
||||||
|
.withApiResponse(json)
|
||||||
|
.withResponse(response))
|
||||||
|
return@onSuccess
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(json)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_PODLASIE_API_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e)
|
||||||
|
.withApiResponse(json))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url(url)
|
||||||
|
.userAgent(SYSTEM_USER_AGENT)
|
||||||
|
.requestParams(RequestParams(mapOf(
|
||||||
|
"token" to data.apiToken,
|
||||||
|
"securityToken" to getSecurityToken(),
|
||||||
|
"mobileId" to data.app.deviceId,
|
||||||
|
"ver" to PODLASIE_API_VERSION
|
||||||
|
)))
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSecurityToken(): String {
|
||||||
|
val format = SimpleDateFormat("yyyy-MM-dd HH", Locale.ENGLISH)
|
||||||
|
.also { it.timeZone = TimeZone.getTimeZone("Europe/Warsaw") }.format(System.currentTimeMillis())
|
||||||
|
val instance = MessageDigest.getInstance("SHA-256")
|
||||||
|
val digest = instance.digest("-EYlwYu8u16miVd8tT?oO7cvoUVQrQN0vr!$format".toByteArray()).toHexString()
|
||||||
|
val digest2 = instance.digest((data.apiToken ?: "").toByteArray()).toHexString()
|
||||||
|
return instance.digest("$digest$digest2".toByteArray()).toHexString()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.R
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.ENDPOINT_PODLASIE_API_MAIN
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api.PodlasieApiMain
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
|
||||||
|
class PodlasieData(val data: DataPodlasie, val onSuccess: () -> Unit) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "PodlasieData"
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
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_PODLASIE_API_MAIN -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_data)
|
||||||
|
PodlasieApiMain(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
else -> onSuccess(endpointId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,75 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
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.getLong
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
class PodlasieApiEvents(val data: DataPodlasie, val rows: List<JsonObject>) {
|
||||||
|
init {
|
||||||
|
rows.forEach { event ->
|
||||||
|
val id = event.getLong("ExternalId") ?: return@forEach
|
||||||
|
val date = event.getString("DateFrom")?.let { Date.fromY_m_d(it) } ?: return@forEach
|
||||||
|
val time = event.getString("DateFrom")?.let { Time.fromY_m_d_H_m_s(it) }
|
||||||
|
?: return@forEach
|
||||||
|
|
||||||
|
val name = event.getString("Name")?.replace(""", "\"") ?: ""
|
||||||
|
val description = event.getString("Description")?.replace(""", "\"") ?: ""
|
||||||
|
|
||||||
|
val type = when (event.getString("Category")?.toLowerCase(Locale.getDefault())) {
|
||||||
|
"klasówka" -> Event.TYPE_EXAM
|
||||||
|
"praca domowa" -> Event.TYPE_HOMEWORK
|
||||||
|
"wycieczka" -> Event.TYPE_EXCURSION
|
||||||
|
else -> Event.TYPE_DEFAULT
|
||||||
|
}
|
||||||
|
|
||||||
|
val teacherFirstName = event.getString("PersonEnteringDataFirstName") ?: return@forEach
|
||||||
|
val teacherLastName = event.getString("PersonEnteringDataLastName") ?: return@forEach
|
||||||
|
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
|
||||||
|
|
||||||
|
val lessonList = data.db.timetableDao().getAllForDateNow(data.profileId, date)
|
||||||
|
val lesson = lessonList.firstOrNull { it.startTime == time }
|
||||||
|
|
||||||
|
val addedDate = event.getString("CreateDate")?.let { Date.fromIso(it) }
|
||||||
|
?: System.currentTimeMillis()
|
||||||
|
|
||||||
|
val eventObject = Event(
|
||||||
|
profileId = data.profileId,
|
||||||
|
id = id,
|
||||||
|
date = date,
|
||||||
|
time = time,
|
||||||
|
topic = name,
|
||||||
|
color = null,
|
||||||
|
type = type,
|
||||||
|
teacherId = teacher.id,
|
||||||
|
subjectId = lesson?.subjectId ?: -1,
|
||||||
|
teamId = data.teamClass?.id ?: -1,
|
||||||
|
addedDate = addedDate
|
||||||
|
).apply {
|
||||||
|
homeworkBody = description
|
||||||
|
}
|
||||||
|
|
||||||
|
data.eventList.add(eventObject)
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
if (type == Event.TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
|
||||||
|
id,
|
||||||
|
data.profile?.empty ?: false,
|
||||||
|
data.profile?.empty ?: false
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.future())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,121 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
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_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.Grade.Companion.TYPE_YEAR_FINAL
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.getLong
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
|
||||||
|
class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List<JsonObject>) {
|
||||||
|
init { data.profile?.also { profile ->
|
||||||
|
rows.forEach { grade ->
|
||||||
|
val id = grade.getLong("ExternalId") ?: return@forEach
|
||||||
|
val mark = grade.getString("Mark") ?: return@forEach
|
||||||
|
val proposedMark = grade.getString("ProposedMark") ?: "0"
|
||||||
|
val name = data.app.gradesManager.getGradeNumberName(mark)
|
||||||
|
val value = data.app.gradesManager.getGradeValue(name)
|
||||||
|
val semester = grade.getString("TermShortcut")?.length ?: return@forEach
|
||||||
|
|
||||||
|
val typeName = grade.getString("Type") ?: return@forEach
|
||||||
|
val type = when (typeName) {
|
||||||
|
"S" -> if (semester == 1) TYPE_SEMESTER1_FINAL else TYPE_SEMESTER2_FINAL
|
||||||
|
"Y", "R" -> TYPE_YEAR_FINAL
|
||||||
|
else -> return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
val subjectName = grade.getString("SchoolSubject") ?: return@forEach
|
||||||
|
val subject = data.getSubject(subjectName)
|
||||||
|
|
||||||
|
val addedDate = if (profile.empty) profile.getSemesterStart(semester).inMillis
|
||||||
|
else System.currentTimeMillis()
|
||||||
|
|
||||||
|
val gradeObject = Grade(
|
||||||
|
profileId = data.profileId,
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
type = type,
|
||||||
|
value = value,
|
||||||
|
weight = 0f,
|
||||||
|
color = -1,
|
||||||
|
category = null,
|
||||||
|
description = null,
|
||||||
|
comment = null,
|
||||||
|
semester = semester,
|
||||||
|
teacherId = -1,
|
||||||
|
subjectId = subject.id,
|
||||||
|
addedDate = addedDate
|
||||||
|
)
|
||||||
|
|
||||||
|
data.gradeList.add(gradeObject)
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_GRADE,
|
||||||
|
id,
|
||||||
|
profile.empty,
|
||||||
|
profile.empty
|
||||||
|
))
|
||||||
|
|
||||||
|
if (proposedMark != "0") {
|
||||||
|
val proposedName = data.app.gradesManager.getGradeNumberName(proposedMark)
|
||||||
|
val proposedValue = data.app.gradesManager.getGradeValue(proposedName)
|
||||||
|
|
||||||
|
val proposedType = when (typeName) {
|
||||||
|
"S" -> if (semester == 1) TYPE_SEMESTER1_PROPOSED else TYPE_SEMESTER2_PROPOSED
|
||||||
|
"Y", "R" -> TYPE_YEAR_PROPOSED
|
||||||
|
else -> return@forEach
|
||||||
|
}
|
||||||
|
|
||||||
|
val proposedGradeObject = Grade(
|
||||||
|
profileId = data.profileId,
|
||||||
|
id = id * (-1),
|
||||||
|
name = proposedName,
|
||||||
|
type = proposedType,
|
||||||
|
value = proposedValue,
|
||||||
|
weight = 0f,
|
||||||
|
color = -1,
|
||||||
|
category = null,
|
||||||
|
description = null,
|
||||||
|
comment = null,
|
||||||
|
semester = semester,
|
||||||
|
teacherId = -1,
|
||||||
|
subjectId = subject.id,
|
||||||
|
addedDate = addedDate
|
||||||
|
)
|
||||||
|
|
||||||
|
data.gradeList.add(proposedGradeObject)
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_GRADE,
|
||||||
|
proposedGradeObject.id,
|
||||||
|
profile.empty,
|
||||||
|
profile.empty
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.addAll(listOf(
|
||||||
|
TYPE_SEMESTER1_FINAL,
|
||||||
|
TYPE_SEMESTER1_PROPOSED,
|
||||||
|
TYPE_SEMESTER2_FINAL,
|
||||||
|
TYPE_SEMESTER2_PROPOSED,
|
||||||
|
TYPE_YEAR_FINAL,
|
||||||
|
TYPE_YEAR_PROPOSED
|
||||||
|
).map {
|
||||||
|
DataRemoveModel.Grades.allWithType(it)
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import android.graphics.Color
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Grade
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.getFloat
|
||||||
|
import pl.szczodrzynski.edziennik.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.getLong
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class PodlasieApiGrades(val data: DataPodlasie, val rows: List<JsonObject>) {
|
||||||
|
init {
|
||||||
|
rows.forEach { grade ->
|
||||||
|
val id = grade.getLong("ExternalId") ?: return@forEach
|
||||||
|
val name = grade.getString("Mark") ?: return@forEach
|
||||||
|
val value = data.app.gradesManager.getGradeValue(name)
|
||||||
|
val weight = grade.getFloat("Weight") ?: 0f
|
||||||
|
val includeToAverage = grade.getInt("IncludeToAverage") != 0
|
||||||
|
val color = grade.getString("Color")?.let { Color.parseColor(it) } ?: -1
|
||||||
|
val category = grade.getString("Category") ?: ""
|
||||||
|
val comment = grade.getString("Comment") ?: ""
|
||||||
|
val semester = grade.getString("TermShortcut")?.length ?: data.currentSemester
|
||||||
|
|
||||||
|
val teacherFirstName = grade.getString("TeacherFirstName") ?: return@forEach
|
||||||
|
val teacherLastName = grade.getString("TeacherLastName") ?: return@forEach
|
||||||
|
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
|
||||||
|
|
||||||
|
val subjectName = grade.getString("SchoolSubject") ?: return@forEach
|
||||||
|
val subject = data.getSubject(subjectName)
|
||||||
|
|
||||||
|
val addedDate = grade.getString("ReceivedDate")?.let { Date.fromY_m_d(it).inMillis }
|
||||||
|
?: System.currentTimeMillis()
|
||||||
|
|
||||||
|
val gradeObject = Grade(
|
||||||
|
profileId = data.profileId,
|
||||||
|
id = id,
|
||||||
|
name = name,
|
||||||
|
type = Grade.TYPE_NORMAL,
|
||||||
|
value = value,
|
||||||
|
weight = if (includeToAverage) weight else 0f,
|
||||||
|
color = color,
|
||||||
|
category = category,
|
||||||
|
description = null,
|
||||||
|
comment = comment,
|
||||||
|
semester = semester,
|
||||||
|
teacherId = teacher.id,
|
||||||
|
subjectId = subject.id,
|
||||||
|
addedDate = addedDate
|
||||||
|
)
|
||||||
|
|
||||||
|
data.gradeList.add(gradeObject)
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_GRADE,
|
||||||
|
id,
|
||||||
|
data.profile?.empty ?: false,
|
||||||
|
data.profile?.empty ?: false
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Grades.allWithType(Grade.TYPE_NORMAL))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-14
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.crc32
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
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.get
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class PodlasieApiHomework(val data: DataPodlasie, val rows: List<JsonObject>) {
|
||||||
|
init {
|
||||||
|
rows.reversed().forEach { homework ->
|
||||||
|
val id = homework.getString("ExternalId")?.crc32() ?: return@forEach
|
||||||
|
val topic = homework.getString("Title")?.replace(""", "\"") ?: ""
|
||||||
|
val description = homework.getString("Message")?.replace(""", "\"") ?: ""
|
||||||
|
val date = Date.getToday()
|
||||||
|
val addedDate = System.currentTimeMillis()
|
||||||
|
|
||||||
|
val eventObject = Event(
|
||||||
|
profileId = data.profileId,
|
||||||
|
id = id,
|
||||||
|
date = date,
|
||||||
|
time = null,
|
||||||
|
topic = topic,
|
||||||
|
color = null,
|
||||||
|
type = Event.TYPE_HOMEWORK,
|
||||||
|
teacherId = -1,
|
||||||
|
subjectId = -1,
|
||||||
|
teamId = data.teamClass?.id ?: -1,
|
||||||
|
addedDate = addedDate
|
||||||
|
).apply {
|
||||||
|
homeworkBody = description
|
||||||
|
}
|
||||||
|
|
||||||
|
eventObject.attachmentIds = mutableListOf()
|
||||||
|
eventObject.attachmentNames = mutableListOf()
|
||||||
|
homework.getString("Attachments")?.split(',')?.onEach { url ->
|
||||||
|
val filename = "&filename=(.*?)&".toRegex().find(url)?.get(1) ?: return@onEach
|
||||||
|
val ext = "&ext=(.*?)&".toRegex().find(url)?.get(1) ?: return@onEach
|
||||||
|
eventObject.attachmentIds?.add(url.crc32())
|
||||||
|
eventObject.attachmentNames?.add("$filename.$ext:$url")
|
||||||
|
}
|
||||||
|
|
||||||
|
data.eventList.add(eventObject)
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_HOMEWORK,
|
||||||
|
id,
|
||||||
|
data.profile?.empty ?: false,
|
||||||
|
data.profile?.empty ?: false
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
|
||||||
|
class PodlasieApiLuckyNumber(val data: DataPodlasie, val luckyNumber: Int) {
|
||||||
|
init {
|
||||||
|
val luckyNumberObject = LuckyNumber(
|
||||||
|
profileId = data.profileId,
|
||||||
|
date = Date.getToday(),
|
||||||
|
number = luckyNumber
|
||||||
|
)
|
||||||
|
|
||||||
|
data.luckyNumberList.add(luckyNumberObject)
|
||||||
|
data.metadataList.add(
|
||||||
|
Metadata(
|
||||||
|
data.profileId,
|
||||||
|
Metadata.TYPE_LUCKY_NUMBER,
|
||||||
|
luckyNumberObject.date.value.toLong(),
|
||||||
|
true,
|
||||||
|
data.profile?.empty ?: false
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.PODLASIE_API_USER_ENDPOINT
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.ENDPOINT_PODLASIE_API_MAIN
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
|
||||||
|
import pl.szczodrzynski.edziennik.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.getJsonArray
|
||||||
|
|
||||||
|
class PodlasieApiMain(override val data: DataPodlasie,
|
||||||
|
override val lastSync: Long?,
|
||||||
|
val onSuccess: (endpointId: Int) -> Unit) : PodlasieApi(data, lastSync) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "PodlasieApiTimetable"
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
apiGet(TAG, PODLASIE_API_USER_ENDPOINT) { json ->
|
||||||
|
data.getTeam() // Save the class team when it doesn't exist.
|
||||||
|
|
||||||
|
json.getInt("LuckyNumber")?.let { PodlasieApiLuckyNumber(data, it) }
|
||||||
|
json.getJsonArray("Teacher")?.asJsonObjectList()?.let { PodlasieApiTeachers(data, it) }
|
||||||
|
json.getJsonArray("Timetable")?.asJsonObjectList()?.let { PodlasieApiTimetable(data, it) }
|
||||||
|
json.getJsonArray("Marks")?.asJsonObjectList()?.let { PodlasieApiGrades(data, it) }
|
||||||
|
json.getJsonArray("MarkFinal")?.asJsonObjectList()?.let { PodlasieApiFinalGrades(data, it) }
|
||||||
|
json.getJsonArray("News")?.asJsonObjectList()?.let { PodlasieApiEvents(data, it) }
|
||||||
|
json.getJsonArray("Tasks")?.asJsonObjectList()?.let { PodlasieApiHomework(data, it) }
|
||||||
|
|
||||||
|
data.setSyncNext(ENDPOINT_PODLASIE_API_MAIN, SYNC_ALWAYS)
|
||||||
|
onSuccess(ENDPOINT_PODLASIE_API_MAIN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,40 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.getLong
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
|
||||||
|
class PodlasieApiTeachers(val data: DataPodlasie, val rows: List<JsonObject>) {
|
||||||
|
init {
|
||||||
|
rows.forEach { teacher ->
|
||||||
|
val id = teacher.getLong("ExternalId") ?: return@forEach
|
||||||
|
val firstName = teacher.getString("FirstName") ?: return@forEach
|
||||||
|
val lastName = teacher.getString("LastName") ?: return@forEach
|
||||||
|
val isEducator = teacher.getInt("Educator") == 1
|
||||||
|
|
||||||
|
val teacherObject = Teacher(
|
||||||
|
profileId = data.profileId,
|
||||||
|
id = id,
|
||||||
|
name = firstName,
|
||||||
|
surname = lastName,
|
||||||
|
loginId = null
|
||||||
|
)
|
||||||
|
|
||||||
|
data.teacherList.put(id, teacherObject)
|
||||||
|
|
||||||
|
val teamClass = data.teamClass
|
||||||
|
if (isEducator && teamClass != null) {
|
||||||
|
data.teamList.put(teamClass.id, teamClass.apply {
|
||||||
|
teacherId = id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,89 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
|
||||||
|
import pl.szczodrzynski.edziennik.getInt
|
||||||
|
import pl.szczodrzynski.edziennik.getString
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||||
|
|
||||||
|
class PodlasieApiTimetable(val data: DataPodlasie, rows: List<JsonObject>) {
|
||||||
|
init {
|
||||||
|
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)
|
||||||
|
|
||||||
|
val days = mutableListOf<Int>()
|
||||||
|
var startDate: Date? = null
|
||||||
|
var endDate: Date? = null
|
||||||
|
|
||||||
|
rows.forEach { lesson ->
|
||||||
|
val date = lesson.getString("Date")?.let { Date.fromY_m_d(it) } ?: return@forEach
|
||||||
|
|
||||||
|
if ((date > weekEnd || date < weekStart) && data.profile?.empty != true) return@forEach
|
||||||
|
if (startDate == null) startDate = date.clone()
|
||||||
|
endDate = date.clone()
|
||||||
|
if (date.value !in days) days += date.value
|
||||||
|
|
||||||
|
val lessonNumber = lesson.getInt("LessonNumber") ?: return@forEach
|
||||||
|
val startTime = lesson.getString("TimeFrom")?.let { Time.fromH_m_s(it) }
|
||||||
|
?: return@forEach
|
||||||
|
val endTime = lesson.getString("TimeTo")?.let { Time.fromH_m_s(it) } ?: return@forEach
|
||||||
|
val subject = lesson.getString("SchoolSubject")?.let { data.getSubject(it) }
|
||||||
|
?: return@forEach
|
||||||
|
|
||||||
|
val teacherFirstName = lesson.getString("TeacherFirstName") ?: return@forEach
|
||||||
|
val teacherLastName = lesson.getString("TeacherLastName") ?: return@forEach
|
||||||
|
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
|
||||||
|
|
||||||
|
val team = lesson.getString("Group")?.let { data.getTeam(it) } ?: return@forEach
|
||||||
|
val classroom = lesson.getString("Room")
|
||||||
|
|
||||||
|
Lesson(data.profileId, -1).also {
|
||||||
|
it.type = Lesson.TYPE_NORMAL
|
||||||
|
it.date = date
|
||||||
|
it.lessonNumber = lessonNumber
|
||||||
|
it.startTime = startTime
|
||||||
|
it.endTime = endTime
|
||||||
|
it.subjectId = subject.id
|
||||||
|
it.teacherId = teacher.id
|
||||||
|
it.teamId = team.id
|
||||||
|
it.classroom = classroom
|
||||||
|
|
||||||
|
it.id = it.buildId()
|
||||||
|
data.lessonList += it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startDate != null && endDate != null) {
|
||||||
|
if (weekEnd > endDate!!) endDate = weekEnd
|
||||||
|
|
||||||
|
while (startDate!! <= endDate!!) {
|
||||||
|
if (startDate!!.value !in days) {
|
||||||
|
val lessonDate = startDate!!.clone()
|
||||||
|
data.lessonList += Lesson(data.profileId, lessonDate.value.toLong()).apply {
|
||||||
|
type = Lesson.TYPE_NO_LESSONS
|
||||||
|
date = lessonDate
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startDate!!.stepForward(0, 0, 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin
|
||||||
|
|
||||||
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_PODLASIE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.PODLASIE_API_LOGOUT_DEVICES_ENDPOINT
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.PODLASIE_API_USER_ENDPOINT
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
|
|
||||||
|
class PodlasieFirstLogin(val data: DataPodlasie, val onSuccess: () -> Unit) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "PodlasieFirstLogin"
|
||||||
|
}
|
||||||
|
|
||||||
|
private val api = PodlasieApi(data, null)
|
||||||
|
|
||||||
|
init {
|
||||||
|
PodlasieLoginApi(data) {
|
||||||
|
doLogin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun doLogin() {
|
||||||
|
val loginStoreId = data.loginStore.id
|
||||||
|
val loginStoreType = LOGIN_TYPE_PODLASIE
|
||||||
|
|
||||||
|
if (data.loginStore.getLoginData("logoutDevices", false)) {
|
||||||
|
data.loginStore.removeLoginData("logoutDevices")
|
||||||
|
api.apiGet(TAG, PODLASIE_API_LOGOUT_DEVICES_ENDPOINT) {
|
||||||
|
doLogin()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
api.apiGet(TAG, PODLASIE_API_USER_ENDPOINT) { json ->
|
||||||
|
val uuid = json.getString("Uuid")
|
||||||
|
val login = json.getString("Login")
|
||||||
|
val firstName = json.getString("FirstName")
|
||||||
|
val lastName = json.getString("LastName")
|
||||||
|
val studentNameLong = "$firstName $lastName".fixName()
|
||||||
|
val studentNameShort = studentNameLong.getShortName()
|
||||||
|
val schoolName = json.getString("SchoolName")
|
||||||
|
val className = json.getString("SchoolClass")
|
||||||
|
val schoolYear = json.getString("ActualSchoolYear")?.replace(' ', '/')
|
||||||
|
val semester = json.getString("ActualTermShortcut")?.length
|
||||||
|
val apiUrl = json.getString("URL")
|
||||||
|
|
||||||
|
val profile = Profile(
|
||||||
|
loginStoreId,
|
||||||
|
loginStoreId,
|
||||||
|
loginStoreType,
|
||||||
|
studentNameLong,
|
||||||
|
login,
|
||||||
|
studentNameLong,
|
||||||
|
studentNameShort,
|
||||||
|
null
|
||||||
|
).apply {
|
||||||
|
studentData["studentId"] = uuid
|
||||||
|
studentData["studentLogin"] = login
|
||||||
|
studentData["schoolName"] = schoolName
|
||||||
|
studentData["className"] = className
|
||||||
|
studentData["schoolYear"] = schoolYear
|
||||||
|
studentData["currentSemester"] = semester ?: 1
|
||||||
|
studentData["apiUrl"] = apiUrl
|
||||||
|
|
||||||
|
schoolYear?.split('/')?.get(0)?.toInt()?.let {
|
||||||
|
studentSchoolYearStart = it
|
||||||
|
}
|
||||||
|
studentClassName = className
|
||||||
|
}
|
||||||
|
|
||||||
|
EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(profile), data.loginStore))
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,18 +1,17 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_API
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_WEB
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
|
||||||
class IdziennikLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
class PodlasieLogin(val data: DataPodlasie, val onSuccess: () -> Unit) {
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "IdziennikLogin"
|
const val TAG = "PodlasieLogin"
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cancelled = false
|
private var cancelled = false
|
||||||
@ -46,13 +45,9 @@ class IdziennikLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
Utils.d(TAG, "Using login method $loginMethodId")
|
Utils.d(TAG, "Using login method $loginMethodId")
|
||||||
when (loginMethodId) {
|
when (loginMethodId) {
|
||||||
LOGIN_METHOD_IDZIENNIK_WEB -> {
|
LOGIN_METHOD_PODLASIE_API -> {
|
||||||
data.startProgress(R.string.edziennik_progress_login_idziennik_web)
|
data.startProgress(R.string.edziennik_progress_login_podlasie_api)
|
||||||
IdziennikLoginWeb(data) { onSuccess(loginMethodId) }
|
PodlasieLoginApi(data) { onSuccess(loginMethodId) }
|
||||||
}
|
|
||||||
LOGIN_METHOD_IDZIENNIK_API -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_login_idziennik_api)
|
|
||||||
IdziennikLoginApi(data) { onSuccess(loginMethodId) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login
|
||||||
|
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_DATA_MISSING
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
|
||||||
|
class PodlasieLoginApi(val data: DataPodlasie, val onSuccess: () -> Unit) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "PodlasieLoginApi"
|
||||||
|
}
|
||||||
|
|
||||||
|
init { run {
|
||||||
|
if (data.isApiLoginValid()) {
|
||||||
|
onSuccess()
|
||||||
|
} else {
|
||||||
|
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
}
|
@ -100,7 +100,6 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
|||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
d(TAG, "Cancelled")
|
d(TAG, "Cancelled")
|
||||||
data.cancel()
|
data.cancel()
|
||||||
callback.onCompleted()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
|
@ -4,52 +4,50 @@
|
|||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject
|
||||||
import pl.szczodrzynski.edziennik.App
|
import pl.szczodrzynski.edziennik.App
|
||||||
|
import pl.szczodrzynski.edziennik.crc16
|
||||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_HEBE
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_WEB_MAIN
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
import pl.szczodrzynski.edziennik.data.db.entity.Profile
|
||||||
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
|
||||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.fslogin.realm.RealmData
|
||||||
import pl.szczodrzynski.edziennik.values
|
|
||||||
|
|
||||||
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||||
|
fun isWebMainLoginValid() = symbol.isNotNullNorEmpty()
|
||||||
fun isApiLoginValid() = currentSemesterEndDate-30 > currentTimeUnix()
|
&& (webExpiryTime[symbol]?.toLongOrNull() ?: 0) - 30 > currentTimeUnix()
|
||||||
&& apiCertificateKey.isNotNullNorEmpty()
|
&& webAuthCookie[symbol].isNotNullNorEmpty()
|
||||||
&& apiCertificatePrivate.isNotNullNorEmpty()
|
&& webRealmData != null
|
||||||
|
fun isHebeLoginValid() = hebePublicKey.isNotNullNorEmpty()
|
||||||
|
&& hebePrivateKey.isNotNullNorEmpty()
|
||||||
&& symbol.isNotNullNorEmpty()
|
&& symbol.isNotNullNorEmpty()
|
||||||
|
|
||||||
override fun satisfyLoginMethods() {
|
override fun satisfyLoginMethods() {
|
||||||
loginMethods.clear()
|
loginMethods.clear()
|
||||||
if (isApiLoginValid()) {
|
if (isWebMainLoginValid()) {
|
||||||
loginMethods += LOGIN_METHOD_VULCAN_API
|
loginMethods += LOGIN_METHOD_VULCAN_WEB_MAIN
|
||||||
|
}
|
||||||
|
if (isHebeLoginValid()) {
|
||||||
|
loginMethods += LOGIN_METHOD_VULCAN_HEBE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
override fun generateUserCode() = "$schoolCode:$studentId"
|
||||||
// during the first sync `profile.studentClassName` is already set
|
|
||||||
if (teamList.values().none { it.type == Team.TYPE_CLASS }) {
|
|
||||||
profile?.studentClassName?.also { name ->
|
|
||||||
val id = Utils.crc16(name.toByteArray()).toLong()
|
|
||||||
|
|
||||||
val teamObject = Team(
|
fun buildDeviceId(): String {
|
||||||
profileId,
|
val deviceId = app.deviceId.padStart(16, '0')
|
||||||
id,
|
val loginStoreId = loginStore.id.toString(16).padStart(4, '0')
|
||||||
name,
|
val symbol = symbol?.crc16()?.toString(16)?.take(2) ?: "00"
|
||||||
Team.TYPE_CLASS,
|
return deviceId.substring(0..7) +
|
||||||
"$schoolName:$name",
|
"-" + deviceId.substring(8..11) +
|
||||||
-1
|
"-" + deviceId.substring(12..15) +
|
||||||
)
|
"-" + loginStoreId +
|
||||||
teamList.put(id, teamObject)
|
"-" + symbol + "6f72616e7a"
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateUserCode() = "$schoolName:$studentId"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A UONET+ client symbol.
|
* A UONET+ client symbol.
|
||||||
*
|
*
|
||||||
@ -59,8 +57,8 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
*/
|
*/
|
||||||
private var mSymbol: String? = null
|
private var mSymbol: String? = null
|
||||||
var symbol: String?
|
var symbol: String?
|
||||||
get() { mSymbol = mSymbol ?: loginStore.getLoginData("deviceSymbol", null); return mSymbol }
|
get() { mSymbol = mSymbol ?: profile?.getStudentData("symbol", null); return mSymbol }
|
||||||
set(value) { loginStore.putLoginData("deviceSymbol", value); mSymbol = value }
|
set(value) { profile?.putStudentData("symbol", value); mSymbol = value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Group symbol/number of the student's school.
|
* Group symbol/number of the student's school.
|
||||||
@ -75,16 +73,26 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
set(value) { profile?.putStudentData("schoolSymbol", value) ?: return; mSchoolSymbol = value }
|
set(value) { profile?.putStudentData("schoolSymbol", value) ?: return; mSchoolSymbol = value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A school ID consisting of the [symbol] and [schoolSymbol].
|
* Short name of the school, used in some places.
|
||||||
|
*
|
||||||
|
* ListaUczniow/JednostkaSprawozdawczaSkrot, e.g. "SP Wilkow"
|
||||||
|
*/
|
||||||
|
private var mSchoolShort: String? = null
|
||||||
|
var schoolShort: String?
|
||||||
|
get() { mSchoolShort = mSchoolShort ?: profile?.getStudentData("schoolShort", null); return mSchoolShort }
|
||||||
|
set(value) { profile?.putStudentData("schoolShort", value) ?: return; mSchoolShort = value }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A school code consisting of the [symbol] and [schoolSymbol].
|
||||||
*
|
*
|
||||||
* [symbol]_[schoolSymbol]
|
* [symbol]_[schoolSymbol]
|
||||||
*
|
*
|
||||||
* e.g. "poznan_000088"
|
* e.g. "poznan_000088"
|
||||||
*/
|
*/
|
||||||
private var mSchoolName: String? = null
|
private var mSchoolCode: String? = null
|
||||||
var schoolName: String?
|
var schoolCode: String?
|
||||||
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
|
get() { mSchoolCode = mSchoolCode ?: profile?.getStudentData("schoolName", null); return mSchoolCode }
|
||||||
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
|
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolCode = value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ID of the student.
|
* ID of the student.
|
||||||
@ -124,6 +132,25 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
get() { mStudentSemesterId = mStudentSemesterId ?: profile?.getStudentData("studentSemesterId", 0); return mStudentSemesterId ?: 0 }
|
get() { mStudentSemesterId = mStudentSemesterId ?: profile?.getStudentData("studentSemesterId", 0); return mStudentSemesterId ?: 0 }
|
||||||
set(value) { profile?.putStudentData("studentSemesterId", value) ?: return; mStudentSemesterId = value }
|
set(value) { profile?.putStudentData("studentSemesterId", value) ?: return; mStudentSemesterId = value }
|
||||||
|
|
||||||
|
private var mStudentUnitId: Int? = null
|
||||||
|
var studentUnitId: Int
|
||||||
|
get() { mStudentUnitId = mStudentUnitId ?: profile?.getStudentData("studentUnitId", 0); return mStudentUnitId ?: 0 }
|
||||||
|
set(value) { profile?.putStudentData("studentUnitId", value) ?: return; mStudentUnitId = value }
|
||||||
|
|
||||||
|
private var mStudentConstituentId: Int? = null
|
||||||
|
var studentConstituentId: Int
|
||||||
|
get() { mStudentConstituentId = mStudentConstituentId ?: profile?.getStudentData("studentConstituentId", 0); return mStudentConstituentId ?: 0 }
|
||||||
|
set(value) { profile?.putStudentData("studentConstituentId", value) ?: return; mStudentConstituentId = value }
|
||||||
|
|
||||||
|
private var mSemester1Id: Int? = null
|
||||||
|
var semester1Id: Int
|
||||||
|
get() { mSemester1Id = mSemester1Id ?: profile?.getStudentData("semester1Id", 0); return mSemester1Id ?: 0 }
|
||||||
|
set(value) { profile?.putStudentData("semester1Id", value) ?: return; mSemester1Id = value }
|
||||||
|
private var mSemester2Id: Int? = null
|
||||||
|
var semester2Id: Int
|
||||||
|
get() { mSemester2Id = mSemester2Id ?: profile?.getStudentData("semester2Id", 0); return mSemester2Id ?: 0 }
|
||||||
|
set(value) { profile?.putStudentData("semester2Id", value) ?: return; mSemester2Id = value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ListaUczniow/OkresNumer, e.g. 1 or 2
|
* ListaUczniow/OkresNumer, e.g. 1 or 2
|
||||||
*/
|
*/
|
||||||
@ -154,45 +181,50 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
* After first login only 3 first characters are stored here.
|
* After first login only 3 first characters are stored here.
|
||||||
* This is later used to determine the API URL address.
|
* This is later used to determine the API URL address.
|
||||||
*/
|
*/
|
||||||
private var mApiToken: String? = null
|
private var mApiToken: Map<String?, String?>? = null
|
||||||
var apiToken: String?
|
var apiToken: Map<String?, String?> = mapOf()
|
||||||
get() { mApiToken = mApiToken ?: loginStore.getLoginData("deviceToken", null); return mApiToken }
|
get() { mApiToken = mApiToken ?: loginStore.getLoginData("apiToken", null)?.let { app.gson.fromJson(it, field.toMutableMap()::class.java) }; return mApiToken ?: mapOf() }
|
||||||
set(value) { loginStore.putLoginData("deviceToken", value); mApiToken = value }
|
set(value) { loginStore.putLoginData("apiToken", app.gson.toJson(value)); mApiToken = value }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mobile API registration PIN.
|
* A mobile API registration PIN.
|
||||||
*
|
*
|
||||||
* After first login, this is removed and/or set to null.
|
* After first login, this is removed and/or set to null.
|
||||||
*/
|
*/
|
||||||
private var mApiPin: String? = null
|
private var mApiPin: Map<String?, String?>? = null
|
||||||
var apiPin: String?
|
var apiPin: Map<String?, String?> = mapOf()
|
||||||
get() { mApiPin = mApiPin ?: loginStore.getLoginData("devicePin", null); return mApiPin }
|
get() { mApiPin = mApiPin ?: loginStore.getLoginData("apiPin", null)?.let { app.gson.fromJson(it, field.toMutableMap()::class.java) }; return mApiPin ?: mapOf() }
|
||||||
set(value) { loginStore.putLoginData("devicePin", value); mApiPin = value }
|
set(value) { loginStore.putLoginData("apiPin", app.gson.toJson(value)); mApiPin = value }
|
||||||
|
|
||||||
private var mApiCertificateKey: String? = null
|
/* _ _ _ _____ _____
|
||||||
var apiCertificateKey: String?
|
| | | | | | /\ | __ \_ _|
|
||||||
get() { mApiCertificateKey = mApiCertificateKey ?: loginStore.getLoginData("certificateKey", null); return mApiCertificateKey }
|
| |__| | ___| |__ ___ / \ | |__) || |
|
||||||
set(value) { loginStore.putLoginData("certificateKey", value); mApiCertificateKey = value }
|
| __ |/ _ \ '_ \ / _ \ / /\ \ | ___/ | |
|
||||||
|
| | | | __/ |_) | __/ / ____ \| | _| |_
|
||||||
|
|_| |_|\___|_.__/ \___| /_/ \_\_| |____*/
|
||||||
|
private var mHebePublicKey: String? = null
|
||||||
|
var hebePublicKey: String?
|
||||||
|
get() { mHebePublicKey = mHebePublicKey ?: loginStore.getLoginData("hebePublicKey", null); return mHebePublicKey }
|
||||||
|
set(value) { loginStore.putLoginData("hebePublicKey", value); mHebePublicKey = value }
|
||||||
|
|
||||||
/**
|
private var mHebePrivateKey: String? = null
|
||||||
* This is not meant for normal usage.
|
var hebePrivateKey: String?
|
||||||
*
|
get() { mHebePrivateKey = mHebePrivateKey ?: loginStore.getLoginData("hebePrivateKey", null); return mHebePrivateKey }
|
||||||
* It provides a backward compatibility (<4.0) in order
|
set(value) { loginStore.putLoginData("hebePrivateKey", value); mHebePrivateKey = value }
|
||||||
* to migrate and use private keys instead of PFX.
|
|
||||||
*/
|
|
||||||
private var mApiCertificatePfx: String? = null
|
|
||||||
var apiCertificatePfx: String?
|
|
||||||
get() { mApiCertificatePfx = mApiCertificatePfx ?: loginStore.getLoginData("certificatePfx", null); return mApiCertificatePfx }
|
|
||||||
set(value) { loginStore.putLoginData("certificatePfx", value); mApiCertificatePfx = value }
|
|
||||||
|
|
||||||
private var mApiCertificatePrivate: String? = null
|
private var mHebePublicHash: String? = null
|
||||||
var apiCertificatePrivate: String?
|
var hebePublicHash: String?
|
||||||
get() { mApiCertificatePrivate = mApiCertificatePrivate ?: loginStore.getLoginData("certificatePrivate", null); return mApiCertificatePrivate }
|
get() { mHebePublicHash = mHebePublicHash ?: loginStore.getLoginData("hebePublicHash", null); return mHebePublicHash }
|
||||||
set(value) { loginStore.putLoginData("certificatePrivate", value); mApiCertificatePrivate = value }
|
set(value) { loginStore.putLoginData("hebePublicHash", value); mHebePublicHash = value }
|
||||||
|
|
||||||
|
private var mHebeContext: String? = null
|
||||||
|
var hebeContext: String?
|
||||||
|
get() { mHebeContext = mHebeContext ?: profile?.getStudentData("hebeContext", null); return mHebeContext }
|
||||||
|
set(value) { profile?.putStudentData("hebeContext", value) ?: return; mHebeContext = value }
|
||||||
|
|
||||||
val apiUrl: String?
|
val apiUrl: String?
|
||||||
get() {
|
get() {
|
||||||
val url = when (apiToken?.substring(0, 3)) {
|
val url = when (apiToken[symbol]?.substring(0, 3)) {
|
||||||
"3S1" -> "https://lekcjaplus.vulcan.net.pl"
|
"3S1" -> "https://lekcjaplus.vulcan.net.pl"
|
||||||
"TA1" -> "https://uonetplus-komunikacja.umt.tarnow.pl"
|
"TA1" -> "https://uonetplus-komunikacja.umt.tarnow.pl"
|
||||||
"OP1" -> "https://uonetplus-komunikacja.eszkola.opolskie.pl"
|
"OP1" -> "https://uonetplus-komunikacja.eszkola.opolskie.pl"
|
||||||
@ -206,6 +238,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
"P01" -> "http://efeb-komunikacja.pro-hudson.win.vulcan.pl"
|
||||||
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
||||||
"P90" -> "http://efeb-komunikacja-pro-mwujakowska.neo.win.vulcan.pl"
|
"P90" -> "http://efeb-komunikacja-pro-mwujakowska.neo.win.vulcan.pl"
|
||||||
|
"KO1" -> "https://uonetplus-komunikacja.eduportal.koszalin.pl"
|
||||||
"FK1", "FS1" -> "http://api.fakelog.cf"
|
"FK1", "FS1" -> "http://api.fakelog.cf"
|
||||||
"SZ9" -> "http://hack.szkolny.eu"
|
"SZ9" -> "http://hack.szkolny.eu"
|
||||||
else -> null
|
else -> null
|
||||||
@ -213,8 +246,65 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
|||||||
return if (url != null) "$url/$symbol/" else loginStore.getLoginData("apiUrl", null)
|
return if (url != null) "$url/$symbol/" else loginStore.getLoginData("apiUrl", null)
|
||||||
}
|
}
|
||||||
|
|
||||||
val fullApiUrl: String?
|
val fullApiUrl: String
|
||||||
get() {
|
get() {
|
||||||
return "$apiUrl$schoolSymbol/"
|
return "$apiUrl$schoolSymbol/"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* __ __ _ ______ _____ _ _
|
||||||
|
\ \ / / | | | ____/ ____| | | (_)
|
||||||
|
\ \ /\ / /__| |__ | |__ | (___ | | ___ __ _ _ _ __
|
||||||
|
\ \/ \/ / _ \ '_ \ | __| \___ \ | | / _ \ / _` | | '_ \
|
||||||
|
\ /\ / __/ |_) | | | ____) | | |___| (_) | (_| | | | | |
|
||||||
|
\/ \/ \___|_.__/ |_| |_____/ |______\___/ \__, |_|_| |_|
|
||||||
|
__/ |
|
||||||
|
|__*/
|
||||||
|
var webRealmData: RealmData?
|
||||||
|
get() { mWebRealmData = mWebRealmData ?: loginStore.getLoginData("webRealmData", JsonObject()).let {
|
||||||
|
app.gson.fromJson(it, RealmData::class.java)
|
||||||
|
}; return mWebRealmData }
|
||||||
|
set(value) { loginStore.putLoginData("webRealmData", app.gson.toJsonTree(value) as JsonObject); mWebRealmData = value }
|
||||||
|
private var mWebRealmData: RealmData? = null
|
||||||
|
|
||||||
|
val webHost
|
||||||
|
get() = webRealmData?.host
|
||||||
|
|
||||||
|
var webEmail: String?
|
||||||
|
get() { mWebEmail = mWebEmail ?: loginStore.getLoginData("webEmail", null); return mWebEmail }
|
||||||
|
set(value) { loginStore.putLoginData("webEmail", value); mWebEmail = value }
|
||||||
|
private var mWebEmail: String? = null
|
||||||
|
var webUsername: String?
|
||||||
|
get() { mWebUsername = mWebUsername ?: loginStore.getLoginData("webUsername", null); return mWebUsername }
|
||||||
|
set(value) { loginStore.putLoginData("webUsername", value); mWebUsername = value }
|
||||||
|
private var mWebUsername: String? = null
|
||||||
|
var webPassword: String?
|
||||||
|
get() { mWebPassword = mWebPassword ?: loginStore.getLoginData("webPassword", null); return mWebPassword }
|
||||||
|
set(value) { loginStore.putLoginData("webPassword", value); mWebPassword = value }
|
||||||
|
private var mWebPassword: String? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expiry time of a certificate POSTed to a LoginEndpoint of the specific symbol.
|
||||||
|
* If the time passes, the certificate needs to be POSTed again (if valid)
|
||||||
|
* or re-generated.
|
||||||
|
*/
|
||||||
|
var webExpiryTime: Map<String, String?> = mapOf()
|
||||||
|
get() { mWebExpiryTime = mWebExpiryTime ?: loginStore.getLoginData("webExpiryTime", null)?.let { app.gson.fromJson(it, field.toMutableMap()::class.java) }; return mWebExpiryTime ?: mapOf() }
|
||||||
|
set(value) { loginStore.putLoginData("webExpiryTime", app.gson.toJson(value)); mWebExpiryTime = value }
|
||||||
|
private var mWebExpiryTime: Map<String, String?>? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* EfebSsoAuthCookie retrieved after posting a certificate
|
||||||
|
*/
|
||||||
|
var webAuthCookie: Map<String, String?> = mapOf()
|
||||||
|
get() { mWebAuthCookie = mWebAuthCookie ?: loginStore.getLoginData("webAuthCookie", null)?.let { app.gson.fromJson(it, field.toMutableMap()::class.java) }; return mWebAuthCookie ?: mapOf() }
|
||||||
|
set(value) { loginStore.putLoginData("webAuthCookie", app.gson.toJson(value)); mWebAuthCookie = value }
|
||||||
|
private var mWebAuthCookie: Map<String, String?>? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Permissions needed to get JSONs from home page
|
||||||
|
*/
|
||||||
|
var webPermissions: Map<String, String?> = mapOf()
|
||||||
|
get() { mWebPermissions = mWebPermissions ?: loginStore.getLoginData("webPermissions", null)?.let { app.gson.fromJson(it, field.toMutableMap()::class.java) }; return mWebPermissions ?: mapOf() }
|
||||||
|
set(value) { loginStore.putLoginData("webPermissions", app.gson.toJson(value)); mWebPermissions = value }
|
||||||
|
private var mWebPermissions: Map<String, String?>? = null
|
||||||
}
|
}
|
||||||
|
@ -10,9 +10,8 @@ import pl.szczodrzynski.edziennik.App
|
|||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.helper.OneDriveDownloadAttachment
|
import pl.szczodrzynski.edziennik.data.api.edziennik.helper.OneDriveDownloadAttachment
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiAttachments
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeMessagesChangeStatus
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeSendMessage
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiSendMessage
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin
|
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
|
||||||
@ -67,6 +66,11 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
|
private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
|
||||||
|
if (data.loginStore.mode == LOGIN_MODE_VULCAN_API) {
|
||||||
|
data.error(TAG, ERROR_VULCAN_API_DEPRECATED)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
||||||
if (internalErrorList.isNotEmpty()) {
|
if (internalErrorList.isNotEmpty()) {
|
||||||
d(TAG, " - Internal errors:")
|
d(TAG, " - Internal errors:")
|
||||||
@ -91,37 +95,21 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getMessage(message: MessageFull) {
|
override fun getMessage(message: MessageFull) {
|
||||||
login(LOGIN_METHOD_VULCAN_API) {
|
login(LOGIN_METHOD_VULCAN_HEBE) {
|
||||||
if (message.attachmentIds != null) {
|
if (message.seen) {
|
||||||
VulcanApiMessagesChangeStatus(data, message) {
|
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||||
completed()
|
completed()
|
||||||
}
|
|
||||||
return@login
|
return@login
|
||||||
}
|
}
|
||||||
val list = data.app.db.messageDao().getAllNow(data.profileId)
|
VulcanHebeMessagesChangeStatus(data, message) {
|
||||||
VulcanApiAttachments(data, list, message, MessageFull::class) { _ ->
|
completed()
|
||||||
list.forEach {
|
|
||||||
if (it.attachmentIds == null)
|
|
||||||
it.attachmentIds = mutableListOf()
|
|
||||||
data.messageList.add(it)
|
|
||||||
}
|
|
||||||
data.messageListReplace = true
|
|
||||||
|
|
||||||
if (message.seen) {
|
|
||||||
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
|
||||||
completed()
|
|
||||||
return@VulcanApiAttachments
|
|
||||||
}
|
|
||||||
VulcanApiMessagesChangeStatus(data, message) {
|
|
||||||
completed()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
||||||
login(LOGIN_METHOD_VULCAN_API) {
|
login(LOGIN_METHOD_VULCAN_HEBE) {
|
||||||
VulcanApiSendMessage(data, recipients, subject, text) {
|
VulcanHebeSendMessage(data, recipients, subject, text) {
|
||||||
completed()
|
completed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -157,7 +145,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
|
|
||||||
completed()
|
completed()
|
||||||
},
|
},
|
||||||
onProgress = { written, total ->
|
onProgress = { written, _ ->
|
||||||
val event = AttachmentGetEvent(
|
val event = AttachmentGetEvent(
|
||||||
data.profileId,
|
data.profileId,
|
||||||
owner,
|
owner,
|
||||||
@ -175,26 +163,16 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getEvent(eventFull: EventFull) {
|
override fun getEvent(eventFull: EventFull) {
|
||||||
login(LOGIN_METHOD_VULCAN_API) {
|
eventFull.homeworkBody = ""
|
||||||
val list = data.app.db.eventDao().getAllNow(data.profileId).filter { !it.addedManually }
|
|
||||||
VulcanApiAttachments(data, list, eventFull, EventFull::class) { _ ->
|
|
||||||
list.forEach {
|
|
||||||
it.homeworkBody = ""
|
|
||||||
data.eventList.add(it)
|
|
||||||
}
|
|
||||||
data.eventListReplace = true
|
|
||||||
|
|
||||||
EventBus.getDefault().postSticky(EventGetEvent(eventFull))
|
EventBus.getDefault().postSticky(EventGetEvent(eventFull))
|
||||||
completed()
|
completed()
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun firstLogin() { VulcanFirstLogin(data) { completed() } }
|
override fun firstLogin() { VulcanFirstLogin(data) { completed() } }
|
||||||
override fun cancel() {
|
override fun cancel() {
|
||||||
d(TAG, "Cancelled")
|
d(TAG, "Cancelled")
|
||||||
data.cancel()
|
data.cancel()
|
||||||
callback.onCompleted()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||||
|
@ -7,87 +7,82 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
|
|||||||
import pl.szczodrzynski.edziennik.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||||
|
|
||||||
const val ENDPOINT_VULCAN_API_UPDATE_SEMESTER = 1000
|
const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010
|
||||||
const val ENDPOINT_VULCAN_API_PUSH_CONFIG = 1005
|
|
||||||
const val ENDPOINT_VULCAN_API_DICTIONARIES = 1010
|
const val ENDPOINT_VULCAN_HEBE_MAIN = 3000
|
||||||
const val ENDPOINT_VULCAN_API_TIMETABLE = 1020
|
const val ENDPOINT_VULCAN_HEBE_PUSH_CONFIG = 3005
|
||||||
const val ENDPOINT_VULCAN_API_EVENTS = 1030
|
const val ENDPOINT_VULCAN_HEBE_ADDRESSBOOK = 3010
|
||||||
const val ENDPOINT_VULCAN_API_GRADES = 1040
|
const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020
|
||||||
const val ENDPOINT_VULCAN_API_GRADES_SUMMARY = 1050
|
const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030
|
||||||
const val ENDPOINT_VULCAN_API_HOMEWORK = 1060
|
const val ENDPOINT_VULCAN_HEBE_GRADES = 3040
|
||||||
const val ENDPOINT_VULCAN_API_NOTICES = 1070
|
const val ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY = 3050
|
||||||
const val ENDPOINT_VULCAN_API_ATTENDANCE = 1080
|
const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060
|
||||||
const val ENDPOINT_VULCAN_API_MESSAGES_INBOX = 1090
|
const val ENDPOINT_VULCAN_HEBE_NOTICES = 3070
|
||||||
const val ENDPOINT_VULCAN_API_MESSAGES_SENT = 1100
|
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_LUCKY_NUMBER = 3200
|
||||||
|
|
||||||
val VulcanFeatures = listOf(
|
val VulcanFeatures = listOf(
|
||||||
// timetable
|
// timetable
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_TIMETABLE, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_TIMETABLE, listOf(
|
||||||
ENDPOINT_VULCAN_API_TIMETABLE to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_TIMETABLE to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
// agenda
|
// agenda
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_AGENDA, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_AGENDA, listOf(
|
||||||
ENDPOINT_VULCAN_API_EVENTS to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_EXAMS to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
// grades
|
// grades
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_GRADES, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_GRADES, listOf(
|
||||||
ENDPOINT_VULCAN_API_GRADES to LOGIN_METHOD_VULCAN_API,
|
ENDPOINT_VULCAN_HEBE_GRADES to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
ENDPOINT_VULCAN_API_GRADES_SUMMARY to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
// homework
|
// homework
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf(
|
||||||
ENDPOINT_VULCAN_API_HOMEWORK to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_HOMEWORK to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
// behaviour
|
// behaviour
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_BEHAVIOUR, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_BEHAVIOUR, listOf(
|
||||||
ENDPOINT_VULCAN_API_NOTICES to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_NOTICES to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
// attendance
|
// attendance
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf(
|
||||||
ENDPOINT_VULCAN_API_ATTENDANCE to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_ATTENDANCE to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
// messages
|
// messages
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf(
|
||||||
ENDPOINT_VULCAN_API_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf(
|
||||||
ENDPOINT_VULCAN_API_MESSAGES_SENT to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)),
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
|
||||||
|
|
||||||
// push config
|
// push config
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_PUSH_CONFIG, listOf(
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_PUSH_CONFIG, listOf(
|
||||||
ENDPOINT_VULCAN_API_PUSH_CONFIG to LOGIN_METHOD_VULCAN_API
|
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG to LOGIN_METHOD_VULCAN_HEBE
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API)).withShouldSync { data ->
|
), listOf(LOGIN_METHOD_VULCAN_HEBE)).withShouldSync { data ->
|
||||||
!data.app.config.sync.tokenVulcanList.contains(data.profileId)
|
!data.app.config.sync.tokenVulcanList.contains(data.profileId)
|
||||||
},
|
},
|
||||||
|
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
|
/**
|
||||||
ENDPOINT_VULCAN_API_UPDATE_SEMESTER to LOGIN_METHOD_VULCAN_API,
|
* Lucky number - using WEB Main.
|
||||||
ENDPOINT_VULCAN_API_DICTIONARIES to LOGIN_METHOD_VULCAN_API
|
*/
|
||||||
), listOf(LOGIN_METHOD_VULCAN_API))
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_LUCKY_NUMBER, listOf(
|
||||||
/*Feature(LOGIN_TYPE_VULCAN, FEATURE_STUDENT_INFO, listOf(
|
ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS to LOGIN_METHOD_VULCAN_WEB_MAIN
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
), listOf(LOGIN_METHOD_VULCAN_WEB_MAIN))
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
.withShouldSync { data -> data.shouldSyncLuckyNumber() }
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_STUDENT_NUMBER, listOf(
|
.withPriority(2),
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
/**
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
* Lucky number - using Hebe API
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_SCHOOL_INFO, listOf(
|
*/
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_LUCKY_NUMBER, listOf(
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER to LOGIN_METHOD_VULCAN_HEBE
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_CLASS_INFO, listOf(
|
), listOf(LOGIN_METHOD_VULCAN_HEBE))
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
.withShouldSync { data -> data.shouldSyncLuckyNumber() }
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
.withPriority(1),
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_TEAM_INFO, listOf(
|
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_TEACHERS, listOf(
|
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_SUBJECTS, listOf(
|
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),
|
|
||||||
Feature(LOGIN_TYPE_VULCAN, FEATURE_CLASSROOMS, listOf(
|
|
||||||
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
|
|
||||||
), listOf(LOGIN_METHOD_VULCAN_WEB)),*/
|
|
||||||
|
|
||||||
|
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
|
||||||
|
ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE,
|
||||||
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE
|
||||||
|
), listOf(LOGIN_METHOD_VULCAN_HEBE))
|
||||||
)
|
)
|
||||||
|
@ -1,132 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-19
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.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.callback.JsonCallbackHandler
|
|
||||||
import io.github.wulkanowy.signer.android.signContent
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.*
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
|
||||||
import java.net.HttpURLConnection
|
|
||||||
import java.util.*
|
|
||||||
|
|
||||||
open class VulcanApi(open val data: DataVulcan, open val lastSync: Long?) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "VulcanApi"
|
|
||||||
}
|
|
||||||
|
|
||||||
val profileId
|
|
||||||
get() = data.profile?.id ?: -1
|
|
||||||
|
|
||||||
val profile
|
|
||||||
get() = data.profile
|
|
||||||
|
|
||||||
fun apiGet(
|
|
||||||
tag: String,
|
|
||||||
endpoint: String,
|
|
||||||
method: Int = POST,
|
|
||||||
parameters: Map<String, Any> = emptyMap(),
|
|
||||||
baseUrl: Boolean = false,
|
|
||||||
onSuccess: (json: JsonObject, response: Response?) -> Unit
|
|
||||||
) {
|
|
||||||
val url = "${if (baseUrl) data.apiUrl else data.fullApiUrl}$endpoint"
|
|
||||||
|
|
||||||
d(tag, "Request: Vulcan/Api - $url")
|
|
||||||
|
|
||||||
val finalPayload = JsonObject()
|
|
||||||
parameters.map { (name, value) ->
|
|
||||||
when (value) {
|
|
||||||
is JsonObject -> finalPayload.add(name, value)
|
|
||||||
is JsonArray -> finalPayload.add(name, value)
|
|
||||||
is String -> finalPayload.addProperty(name, value)
|
|
||||||
is Int -> finalPayload.addProperty(name, value)
|
|
||||||
is Long -> finalPayload.addProperty(name, value)
|
|
||||||
is Float -> finalPayload.addProperty(name, value)
|
|
||||||
is Char -> finalPayload.addProperty(name, value)
|
|
||||||
is Boolean -> finalPayload.addProperty(name, value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finalPayload.addProperty("RemoteMobileTimeKey", System.currentTimeMillis() / 1000)
|
|
||||||
finalPayload.addProperty("TimeKey", System.currentTimeMillis() / 1000 - 1)
|
|
||||||
finalPayload.addProperty("RequestId", UUID.randomUUID().toString())
|
|
||||||
finalPayload.addProperty("RemoteMobileAppVersion", VULCAN_API_APP_VERSION)
|
|
||||||
finalPayload.addProperty("RemoteMobileAppName", VULCAN_API_APP_NAME)
|
|
||||||
|
|
||||||
val callback = object : JsonCallbackHandler() {
|
|
||||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
|
||||||
if (json == null && response?.parserErrorBody == null) {
|
|
||||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response?.code() ?: 200 != 200) {
|
|
||||||
when (response?.code()) {
|
|
||||||
503 -> ERROR_VULCAN_API_MAINTENANCE
|
|
||||||
400 -> ERROR_VULCAN_API_BAD_REQUEST
|
|
||||||
else -> ERROR_VULCAN_API_OTHER
|
|
||||||
}.let { errorCode ->
|
|
||||||
data.error(ApiError(tag, errorCode)
|
|
||||||
.withResponse(response)
|
|
||||||
.withApiResponse(json?.toString() ?: response?.parserErrorBody))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (json == null) {
|
|
||||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
|
||||||
.withResponse(response))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
onSuccess(json, response)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
data.error(ApiError(tag, EXCEPTION_VULCAN_API_REQUEST)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(e)
|
|
||||||
.withApiResponse(json))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
|
||||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
|
||||||
.withResponse(response)
|
|
||||||
.withThrowable(throwable))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Request.builder()
|
|
||||||
.url(url)
|
|
||||||
.userAgent(VULCAN_API_USER_AGENT)
|
|
||||||
.addHeader("RequestCertificateKey", data.apiCertificateKey)
|
|
||||||
.addHeader("RequestSignatureValue",
|
|
||||||
try {
|
|
||||||
signContent(
|
|
||||||
data.apiCertificatePrivate ?: "",
|
|
||||||
finalPayload.toString()
|
|
||||||
)
|
|
||||||
} catch (e: Exception) {e.printStackTrace();""})
|
|
||||||
.apply {
|
|
||||||
when (method) {
|
|
||||||
GET -> get()
|
|
||||||
POST -> post()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.setJsonBody(finalPayload)
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN)
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
|
||||||
.allowErrorCode(HttpURLConnection.HTTP_UNAVAILABLE)
|
|
||||||
.callback(callback)
|
|
||||||
.build()
|
|
||||||
.enqueue()
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,9 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data
|
|||||||
|
|
||||||
import pl.szczodrzynski.edziennik.R
|
import pl.szczodrzynski.edziennik.R
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.*
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.*
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.*
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Message
|
||||||
import pl.szczodrzynski.edziennik.utils.Utils
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
|
||||||
class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
||||||
@ -14,8 +16,35 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
private const val TAG = "VulcanData"
|
private const val TAG = "VulcanData"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var firstSemesterSync = false
|
||||||
|
private val firstSemesterSyncExclude = listOf(
|
||||||
|
ENDPOINT_VULCAN_HEBE_MAIN,
|
||||||
|
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG,
|
||||||
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK,
|
||||||
|
ENDPOINT_VULCAN_HEBE_TIMETABLE,
|
||||||
|
ENDPOINT_VULCAN_HEBE_EXAMS,
|
||||||
|
ENDPOINT_VULCAN_HEBE_HOMEWORK,
|
||||||
|
ENDPOINT_VULCAN_HEBE_NOTICES,
|
||||||
|
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX,
|
||||||
|
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT,
|
||||||
|
ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER
|
||||||
|
)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
nextEndpoint(onSuccess)
|
if (data.studentSemesterNumber == 2 && data.profile?.empty != false) {
|
||||||
|
firstSemesterSync = true
|
||||||
|
// set to sync 1st semester first
|
||||||
|
data.studentSemesterId = data.semester1Id
|
||||||
|
data.studentSemesterNumber = 1
|
||||||
|
}
|
||||||
|
nextEndpoint {
|
||||||
|
if (firstSemesterSync) {
|
||||||
|
// at the end, set back 2nd semester
|
||||||
|
data.studentSemesterId = data.semester2Id
|
||||||
|
data.studentSemesterNumber = 2
|
||||||
|
}
|
||||||
|
onSuccess()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||||
@ -29,7 +58,21 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
}
|
}
|
||||||
val id = data.targetEndpointIds.firstKey()
|
val id = data.targetEndpointIds.firstKey()
|
||||||
val lastSync = data.targetEndpointIds.remove(id)
|
val lastSync = data.targetEndpointIds.remove(id)
|
||||||
useEndpoint(id, lastSync) { endpointId ->
|
useEndpoint(id, lastSync) {
|
||||||
|
if (firstSemesterSync && id !in firstSemesterSyncExclude) {
|
||||||
|
// sync 2nd semester after every endpoint
|
||||||
|
data.studentSemesterId = data.semester2Id
|
||||||
|
data.studentSemesterNumber = 2
|
||||||
|
useEndpoint(id, lastSync) {
|
||||||
|
// set 1st semester back for the next endpoint
|
||||||
|
data.studentSemesterId = data.semester1Id
|
||||||
|
data.studentSemesterNumber = 1
|
||||||
|
// progress further
|
||||||
|
data.progress(data.progressStep)
|
||||||
|
nextEndpoint(onSuccess)
|
||||||
|
}
|
||||||
|
return@useEndpoint
|
||||||
|
}
|
||||||
data.progress(data.progressStep)
|
data.progress(data.progressStep)
|
||||||
nextEndpoint(onSuccess)
|
nextEndpoint(onSuccess)
|
||||||
}
|
}
|
||||||
@ -38,53 +81,70 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
|
|||||||
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
|
||||||
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
|
||||||
when (endpointId) {
|
when (endpointId) {
|
||||||
ENDPOINT_VULCAN_API_UPDATE_SEMESTER -> {
|
ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||||
|
VulcanWebLuckyNumber(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_MAIN -> {
|
||||||
|
if (data.profile == null) {
|
||||||
|
onSuccess(ENDPOINT_VULCAN_HEBE_MAIN)
|
||||||
|
return
|
||||||
|
}
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||||
VulcanApiUpdateSemester(data, lastSync, onSuccess)
|
VulcanHebeMain(data, lastSync).getStudents(
|
||||||
|
profile = data.profile,
|
||||||
|
profileList = null
|
||||||
|
) {
|
||||||
|
onSuccess(ENDPOINT_VULCAN_HEBE_MAIN)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_PUSH_CONFIG -> {
|
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_push_config)
|
data.startProgress(R.string.edziennik_progress_endpoint_push_config)
|
||||||
VulcanApiPushConfig(data, lastSync, onSuccess)
|
VulcanHebePushConfig(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_DICTIONARIES -> {
|
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_dictionaries)
|
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||||
VulcanApiDictionaries(data, lastSync, onSuccess)
|
VulcanHebeAddressbook(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_GRADES -> {
|
ENDPOINT_VULCAN_HEBE_TIMETABLE -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
|
||||||
VulcanApiGrades(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_VULCAN_API_GRADES_SUMMARY -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
|
||||||
VulcanApiProposedGrades(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_VULCAN_API_EVENTS -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
|
||||||
VulcanApiEvents(data, isHomework = false, lastSync = lastSync, onSuccess = onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_VULCAN_API_HOMEWORK -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
|
||||||
VulcanApiEvents(data, isHomework = true, lastSync = lastSync, onSuccess = onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_VULCAN_API_NOTICES -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
|
||||||
VulcanApiNotices(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_VULCAN_API_ATTENDANCE -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
|
||||||
VulcanApiAttendance(data, lastSync, onSuccess)
|
|
||||||
}
|
|
||||||
ENDPOINT_VULCAN_API_TIMETABLE -> {
|
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||||
VulcanApiTimetable(data, lastSync, onSuccess)
|
VulcanHebeTimetable(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_MESSAGES_INBOX -> {
|
ENDPOINT_VULCAN_HEBE_EXAMS -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||||
|
VulcanHebeExams(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_GRADES -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||||
|
VulcanHebeGrades(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
||||||
|
VulcanHebeGradeSummary(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_HOMEWORK -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||||
|
VulcanHebeHomework(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_NOTICES -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||||
|
VulcanHebeNotices(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_ATTENDANCE -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||||
|
VulcanHebeAttendance(data, lastSync, onSuccess)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||||
VulcanApiMessagesInbox(data, lastSync, onSuccess)
|
VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_RECEIVED)
|
||||||
}
|
}
|
||||||
ENDPOINT_VULCAN_API_MESSAGES_SENT -> {
|
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT -> {
|
||||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||||
VulcanApiMessagesSent(data, lastSync, onSuccess)
|
VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_SENT)
|
||||||
|
}
|
||||||
|
ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER -> {
|
||||||
|
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||||
|
VulcanHebeLuckyNumber(data, lastSync, onSuccess)
|
||||||
}
|
}
|
||||||
else -> onSuccess(endpointId)
|
else -> onSuccess(endpointId)
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,416 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2021-2-20.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data
|
||||||
|
|
||||||
|
import android.os.Build
|
||||||
|
import androidx.core.util.set
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonElement
|
||||||
|
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.JsonCallbackHandler
|
||||||
|
import io.github.wulkanowy.signer.hebe.getSignatureHeaders
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
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.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Subject
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
|
||||||
|
import pl.szczodrzynski.edziennik.data.db.entity.Team
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URLEncoder
|
||||||
|
import java.time.Instant
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
import java.time.ZoneId
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanHebe"
|
||||||
|
}
|
||||||
|
|
||||||
|
val profileId
|
||||||
|
get() = data.profile?.id ?: -1
|
||||||
|
|
||||||
|
val profile
|
||||||
|
get() = data.profile
|
||||||
|
|
||||||
|
fun getDateTime(
|
||||||
|
json: JsonObject?,
|
||||||
|
key: String,
|
||||||
|
default: Long = System.currentTimeMillis()
|
||||||
|
): Long {
|
||||||
|
val date = json.getJsonObject(key)
|
||||||
|
return date.getLong("Timestamp") ?: return default
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getDate(json: JsonObject?, key: String): Date? {
|
||||||
|
val date = json.getJsonObject(key)
|
||||||
|
return date.getString("Date")?.let { Date.fromY_m_d(it) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTeacherId(json: JsonObject?, key: String): Long? {
|
||||||
|
val teacher = json.getJsonObject(key)
|
||||||
|
val teacherId = teacher.getLong("Id") ?: return null
|
||||||
|
if (data.teacherList[teacherId] == null) {
|
||||||
|
data.teacherList[teacherId] = Teacher(
|
||||||
|
data.profileId,
|
||||||
|
teacherId,
|
||||||
|
teacher.getString("Name") ?: "",
|
||||||
|
teacher.getString("Surname") ?: ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return teacherId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSubjectId(json: JsonObject?, key: String): Long? {
|
||||||
|
val subject = json.getJsonObject(key)
|
||||||
|
val subjectId = subject.getLong("Id") ?: return null
|
||||||
|
if (data.subjectList[subjectId] == null) {
|
||||||
|
data.subjectList[subjectId] = Subject(
|
||||||
|
data.profileId,
|
||||||
|
subjectId,
|
||||||
|
subject.getString("Name") ?: "",
|
||||||
|
subject.getString("Kod") ?: ""
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return subjectId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getTeamId(json: JsonObject?, key: String): Long? {
|
||||||
|
val team = json.getJsonObject(key)
|
||||||
|
val teamId = team.getLong("Id") ?: return null
|
||||||
|
if (data.teamList[teamId] == null) {
|
||||||
|
var name = team.getString("Shortcut")
|
||||||
|
?: team.getString("Name")
|
||||||
|
?: ""
|
||||||
|
name = "${profile?.studentClassName ?: ""} $name"
|
||||||
|
data.teamList[teamId] = Team(
|
||||||
|
data.profileId,
|
||||||
|
teamId,
|
||||||
|
name,
|
||||||
|
Team.TYPE_VIRTUAL,
|
||||||
|
"${data.schoolCode}:$name",
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return teamId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getClassId(json: JsonObject?, key: String): Long? {
|
||||||
|
val team = json.getJsonObject(key)
|
||||||
|
val teamId = team.getLong("Id") ?: return null
|
||||||
|
if (data.teamList[teamId] == null) {
|
||||||
|
val name = data.profile?.studentClassName
|
||||||
|
?: team.getString("Name")
|
||||||
|
?: ""
|
||||||
|
data.teamList[teamId] = Team(
|
||||||
|
data.profileId,
|
||||||
|
teamId,
|
||||||
|
name,
|
||||||
|
Team.TYPE_CLASS,
|
||||||
|
"${data.schoolCode}:$name",
|
||||||
|
-1
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return teamId
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getLessonRange(json: JsonObject?, key: String): LessonRange? {
|
||||||
|
val timeslot = json.getJsonObject(key)
|
||||||
|
val position = timeslot.getInt("Position") ?: return null
|
||||||
|
val start = timeslot.getString("Start") ?: return null
|
||||||
|
val end = timeslot.getString("End") ?: return null
|
||||||
|
val lessonRange = LessonRange(
|
||||||
|
data.profileId,
|
||||||
|
position,
|
||||||
|
Time.fromH_m(start),
|
||||||
|
Time.fromH_m(end)
|
||||||
|
)
|
||||||
|
data.lessonRanges[position] = lessonRange
|
||||||
|
return lessonRange
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSemester(json: JsonObject?): Int {
|
||||||
|
val periodId = json.getInt("PeriodId") ?: return 1
|
||||||
|
return if (periodId == data.semester1Id)
|
||||||
|
1
|
||||||
|
else
|
||||||
|
2
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isCurrentYear(date: Date): Boolean {
|
||||||
|
return profile?.let { profile ->
|
||||||
|
return@let date >= profile.dateSemester1Start
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun isCurrentYear(dateTime: Long): Boolean {
|
||||||
|
return profile?.let { profile ->
|
||||||
|
return@let dateTime >= profile.dateSemester1Start.inMillis
|
||||||
|
} ?: false
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> apiRequest(
|
||||||
|
tag: String,
|
||||||
|
endpoint: String,
|
||||||
|
method: Int = GET,
|
||||||
|
payload: JsonElement? = null,
|
||||||
|
baseUrl: Boolean = false,
|
||||||
|
firebaseToken: String? = null,
|
||||||
|
crossinline onSuccess: (json: T, response: Response?) -> Unit
|
||||||
|
) {
|
||||||
|
val url = "${if (baseUrl) data.apiUrl else data.fullApiUrl}$endpoint"
|
||||||
|
|
||||||
|
d(tag, "Request: Vulcan/Hebe - $url")
|
||||||
|
|
||||||
|
val privateKey = data.hebePrivateKey
|
||||||
|
val publicHash = data.hebePublicHash
|
||||||
|
|
||||||
|
if (privateKey == null || publicHash == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val timestamp = ZonedDateTime.now(ZoneId.of("GMT"))
|
||||||
|
val timestampMillis = timestamp.toInstant().toEpochMilli()
|
||||||
|
val timestampIso = timestamp.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss"))
|
||||||
|
|
||||||
|
val finalPayload = if (payload != null) {
|
||||||
|
JsonObject(
|
||||||
|
"AppName" to VULCAN_HEBE_APP_NAME,
|
||||||
|
"AppVersion" to VULCAN_HEBE_APP_VERSION,
|
||||||
|
"CertificateId" to publicHash,
|
||||||
|
"Envelope" to payload,
|
||||||
|
"FirebaseToken" to (firebaseToken ?: data.app.config.sync.tokenVulcanHebe),
|
||||||
|
"API" to 1,
|
||||||
|
"RequestId" to UUID.randomUUID().toString(),
|
||||||
|
"Timestamp" to timestampMillis,
|
||||||
|
"TimestampFormatted" to timestampIso
|
||||||
|
)
|
||||||
|
} else null
|
||||||
|
val jsonString = finalPayload?.toString()
|
||||||
|
|
||||||
|
val headers = getSignatureHeaders(
|
||||||
|
publicHash,
|
||||||
|
privateKey,
|
||||||
|
jsonString,
|
||||||
|
endpoint,
|
||||||
|
timestamp
|
||||||
|
)
|
||||||
|
|
||||||
|
val callback = object : JsonCallbackHandler() {
|
||||||
|
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||||
|
if (json == null) {
|
||||||
|
data.error(
|
||||||
|
ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
|
.withResponse(response)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val status = json.getJsonObject("Status")
|
||||||
|
val statusCode = status?.getInt("Code") ?: 0
|
||||||
|
if (statusCode != 0) {
|
||||||
|
val statusMessage = status?.getString("Message")
|
||||||
|
val errorCode = when (statusCode) {
|
||||||
|
-1 -> ERROR_VULCAN_HEBE_SERVER_ERROR
|
||||||
|
100 -> ERROR_VULCAN_HEBE_SIGNATURE_ERROR
|
||||||
|
101 -> ERROR_VULCAN_HEBE_INVALID_PAYLOAD
|
||||||
|
106 -> ERROR_VULCAN_HEBE_FIREBASE_ERROR
|
||||||
|
108 -> ERROR_VULCAN_HEBE_CERTIFICATE_GONE
|
||||||
|
200 -> when (true) {
|
||||||
|
statusMessage?.contains("Class") -> ERROR_LOGIN_VULCAN_NO_PUPILS
|
||||||
|
statusMessage?.contains("Token") -> ERROR_LOGIN_VULCAN_INVALID_TOKEN
|
||||||
|
else -> ERROR_VULCAN_HEBE_ENTITY_NOT_FOUND
|
||||||
|
}
|
||||||
|
201 -> ERROR_LOGIN_VULCAN_EXPIRED_TOKEN
|
||||||
|
203 -> when (json.getJsonObject("Envelope").getInt("AvailableRetries")) {
|
||||||
|
2 -> ERROR_LOGIN_VULCAN_INVALID_PIN_2_REMAINING
|
||||||
|
1 -> ERROR_LOGIN_VULCAN_INVALID_PIN_1_REMAINING
|
||||||
|
else -> ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING
|
||||||
|
}
|
||||||
|
204 -> ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING
|
||||||
|
else -> ERROR_VULCAN_HEBE_OTHER
|
||||||
|
}
|
||||||
|
data.error(
|
||||||
|
ApiError(tag, errorCode)
|
||||||
|
.withResponse(response)
|
||||||
|
.withApiResponse(json.toString())
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val envelope = if (json.get("Envelope").isJsonNull && null is T)
|
||||||
|
null as T
|
||||||
|
else when (T::class.java) {
|
||||||
|
JsonObject::class.java -> json.getJsonObject("Envelope") as T
|
||||||
|
JsonArray::class.java -> json.getJsonArray("Envelope") as T
|
||||||
|
java.lang.Boolean::class.java -> json.getBoolean("Envelope") as T
|
||||||
|
else -> {
|
||||||
|
data.error(
|
||||||
|
ApiError(tag, ERROR_RESPONSE_EMPTY)
|
||||||
|
.withResponse(response)
|
||||||
|
.withApiResponse(json)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
onSuccess(envelope, response)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(
|
||||||
|
ApiError(tag, EXCEPTION_VULCAN_HEBE_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e)
|
||||||
|
.withApiResponse(json)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(
|
||||||
|
ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url(url)
|
||||||
|
.userAgent(VULCAN_HEBE_USER_AGENT)
|
||||||
|
.addHeader("vOS", "Android")
|
||||||
|
.addHeader("vDeviceModel", Build.MODEL)
|
||||||
|
.addHeader("vAPI", "1")
|
||||||
|
.apply {
|
||||||
|
if (data.hebeContext != null)
|
||||||
|
addHeader("vContext", data.hebeContext)
|
||||||
|
headers.forEach {
|
||||||
|
addHeader(it.key, it.value)
|
||||||
|
}
|
||||||
|
when (method) {
|
||||||
|
GET -> get()
|
||||||
|
POST -> {
|
||||||
|
post()
|
||||||
|
setTextBody(jsonString, MediaTypeUtils.APPLICATION_JSON)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_UNAVAILABLE)
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> apiGet(
|
||||||
|
tag: String,
|
||||||
|
endpoint: String,
|
||||||
|
query: Map<String, String> = mapOf(),
|
||||||
|
baseUrl: Boolean = false,
|
||||||
|
firebaseToken: String? = null,
|
||||||
|
crossinline onSuccess: (json: T, response: Response?) -> Unit
|
||||||
|
) {
|
||||||
|
val queryPath = query.map {
|
||||||
|
it.key + "=" + URLEncoder.encode(it.value, "UTF-8").replace("+", "%20")
|
||||||
|
}.join("&")
|
||||||
|
apiRequest(
|
||||||
|
tag,
|
||||||
|
if (query.isNotEmpty()) "$endpoint?$queryPath" else endpoint,
|
||||||
|
baseUrl = baseUrl,
|
||||||
|
firebaseToken = firebaseToken,
|
||||||
|
onSuccess = onSuccess
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> apiPost(
|
||||||
|
tag: String,
|
||||||
|
endpoint: String,
|
||||||
|
payload: JsonElement,
|
||||||
|
baseUrl: Boolean = false,
|
||||||
|
firebaseToken: String? = null,
|
||||||
|
crossinline onSuccess: (json: T, response: Response?) -> Unit
|
||||||
|
) {
|
||||||
|
apiRequest(
|
||||||
|
tag,
|
||||||
|
endpoint,
|
||||||
|
method = POST,
|
||||||
|
payload,
|
||||||
|
baseUrl = baseUrl,
|
||||||
|
firebaseToken = firebaseToken,
|
||||||
|
onSuccess = onSuccess
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun apiGetList(
|
||||||
|
tag: String,
|
||||||
|
endpoint: String,
|
||||||
|
filterType: HebeFilterType? = null,
|
||||||
|
dateFrom: Date? = null,
|
||||||
|
dateTo: Date? = null,
|
||||||
|
lastSync: Long? = null,
|
||||||
|
folder: Int? = null,
|
||||||
|
params: Map<String, String> = mapOf(),
|
||||||
|
includeFilterType: Boolean = true,
|
||||||
|
onSuccess: (data: List<JsonObject>, response: Response?) -> Unit
|
||||||
|
) {
|
||||||
|
val url = if (includeFilterType && filterType != null)
|
||||||
|
"$endpoint/${filterType.endpoint}"
|
||||||
|
else endpoint
|
||||||
|
|
||||||
|
val query = params.toMutableMap()
|
||||||
|
|
||||||
|
when (filterType) {
|
||||||
|
HebeFilterType.BY_PUPIL -> {
|
||||||
|
query["unitId"] = data.studentUnitId.toString()
|
||||||
|
query["pupilId"] = data.studentId.toString()
|
||||||
|
query["periodId"] = data.studentSemesterId.toString()
|
||||||
|
}
|
||||||
|
HebeFilterType.BY_PERSON -> {
|
||||||
|
query["loginId"] = data.studentLoginId.toString()
|
||||||
|
}
|
||||||
|
HebeFilterType.BY_PERIOD -> {
|
||||||
|
query["periodId"] = data.studentSemesterId.toString()
|
||||||
|
query["pupilId"] = data.studentId.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dateFrom != null)
|
||||||
|
query["dateFrom"] = dateFrom.stringY_m_d
|
||||||
|
if (dateTo != null)
|
||||||
|
query["dateTo"] = dateTo.stringY_m_d
|
||||||
|
|
||||||
|
if (folder != null)
|
||||||
|
query["folder"] = folder.toString()
|
||||||
|
|
||||||
|
val semester1Start = profile?.dateSemester1Start?.inMillis
|
||||||
|
|
||||||
|
query["lastId"] = "-2147483648" // don't ask, it's just Vulcan
|
||||||
|
query["pageSize"] = "500"
|
||||||
|
query["lastSyncDate"] = LocalDateTime
|
||||||
|
.ofInstant(
|
||||||
|
Instant.ofEpochMilli(lastSync ?: semester1Start ?: 0),
|
||||||
|
ZoneId.systemDefault()
|
||||||
|
)
|
||||||
|
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||||
|
|
||||||
|
apiGet(tag, url, query) { json: JsonArray, response ->
|
||||||
|
onSuccess(json.map { it.asJsonObject }, response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,315 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) Kuba Szczodrzyński 2020-4-17.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data
|
||||||
|
|
||||||
|
import com.google.gson.JsonArray
|
||||||
|
import com.google.gson.JsonObject
|
||||||
|
import com.google.gson.JsonParser
|
||||||
|
import im.wangchao.mhttp.Request
|
||||||
|
import im.wangchao.mhttp.Response
|
||||||
|
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||||
|
import pl.droidsonroids.jspoon.Jspoon
|
||||||
|
import pl.szczodrzynski.edziennik.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.*
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.CufsCertificate
|
||||||
|
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||||
|
import pl.szczodrzynski.edziennik.utils.Utils
|
||||||
|
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||||
|
import java.io.File
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
|
||||||
|
open class VulcanWebMain(open val data: DataVulcan, open val lastSync: Long?) {
|
||||||
|
companion object {
|
||||||
|
const val TAG = "VulcanWebMain"
|
||||||
|
const val WEB_MAIN = 0
|
||||||
|
const val WEB_OLD = 1
|
||||||
|
const val WEB_NEW = 2
|
||||||
|
const val WEB_MESSAGES = 3
|
||||||
|
const val STATE_SUCCESS = 0
|
||||||
|
const val STATE_NO_REGISTER = 1
|
||||||
|
const val STATE_LOGGED_OUT = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
val profileId
|
||||||
|
get() = data.profile?.id ?: -1
|
||||||
|
|
||||||
|
val profile
|
||||||
|
get() = data.profile
|
||||||
|
|
||||||
|
private val certificateAdapter by lazy {
|
||||||
|
Jspoon.create().adapter(CufsCertificate::class.java)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun saveCertificate(xml: String) {
|
||||||
|
val file = File(data.app.filesDir, "cert_"+(data.webUsername ?: data.webEmail)+".xml")
|
||||||
|
file.writeText(xml)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun readCertificate(): String? {
|
||||||
|
val file = File(data.app.filesDir, "cert_"+(data.webUsername ?: data.webEmail)+".xml")
|
||||||
|
if (file.canRead())
|
||||||
|
return file.readText()
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
fun parseCertificate(xml: String): CufsCertificate {
|
||||||
|
val xmlParsed = xml
|
||||||
|
.replace("<[a-z]+?:".toRegex(), "<")
|
||||||
|
.replace("</[a-z]+?:".toRegex(), "</")
|
||||||
|
.replace("\\sxmlns.*?=\".+?\"".toRegex(), "")
|
||||||
|
|
||||||
|
return certificateAdapter.fromHtml(xmlParsed).also {
|
||||||
|
it.xml = xml
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun postCertificate(certificate: CufsCertificate, symbol: String, onResult: (symbol: String, state: Int) -> Unit): Boolean {
|
||||||
|
// check if the certificate is valid
|
||||||
|
if (Date.fromIso(certificate.expiryDate) < System.currentTimeMillis())
|
||||||
|
return false
|
||||||
|
|
||||||
|
val callback = object : TextCallbackHandler() {
|
||||||
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
|
if (response?.headers()?.get("Location")?.contains("LoginEndpoint.aspx") == true
|
||||||
|
|| response?.headers()?.get("Location")?.contains("?logout=true") == true) {
|
||||||
|
onResult(symbol, STATE_LOGGED_OUT)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (text?.contains("LoginEndpoint.aspx?logout=true") == true) {
|
||||||
|
onResult(symbol, STATE_NO_REGISTER)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!validateCallback(symbol, text, response, jsonResponse = false)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
data.webExpiryTime = data.webExpiryTime.toMutableMap().also { map ->
|
||||||
|
map[symbol] = (Date.fromIso(certificate.expiryDate) / 1000L).toString()
|
||||||
|
}
|
||||||
|
onResult(symbol, STATE_SUCCESS)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("https://uonetplus.${data.webHost}/$symbol/LoginEndpoint.aspx")
|
||||||
|
.withClient(data.app.httpLazy)
|
||||||
|
.userAgent(SYSTEM_USER_AGENT)
|
||||||
|
.post()
|
||||||
|
.addParameter("wa", "wsignin1.0")
|
||||||
|
.addParameter("wctx", certificate.targetUrl)
|
||||||
|
.addParameter("wresult", certificate.xml)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_UNAVAILABLE)
|
||||||
|
.allowErrorCode(429)
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getStartPage(symbol: String = data.symbol ?: "default", postErrors: Boolean = true, onSuccess: (html: String, schoolSymbols: List<String>) -> Unit) {
|
||||||
|
val callback = object : TextCallbackHandler() {
|
||||||
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
|
if (!validateCallback(symbol, text, response, jsonResponse = false) || text == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postErrors) {
|
||||||
|
when {
|
||||||
|
text.contains("status absolwenta") -> ERROR_VULCAN_WEB_GRADUATE_ACCOUNT
|
||||||
|
else -> null
|
||||||
|
}?.let { errorCode ->
|
||||||
|
data.error(ApiError(TAG, errorCode)
|
||||||
|
.withResponse(response)
|
||||||
|
.withApiResponse(text))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data.webPermissions = data.webPermissions.toMutableMap().also { map ->
|
||||||
|
val permissions = Regexes.VULCAN_WEB_PERMISSIONS.find(text)?.let { it[1] }
|
||||||
|
if (permissions?.isNotBlank() == true) {
|
||||||
|
val studentId = permissions.split("|")
|
||||||
|
.getOrNull(0)
|
||||||
|
?.base64DecodeToString()
|
||||||
|
?.toJsonObject()
|
||||||
|
?.getJsonArray("AuthInfos")
|
||||||
|
?.asJsonObjectList()
|
||||||
|
?.flatMap { authInfo ->
|
||||||
|
authInfo.getJsonArray("UczenIds")
|
||||||
|
?.map { it.asInt }
|
||||||
|
?: listOf()
|
||||||
|
}
|
||||||
|
?.firstOrNull()
|
||||||
|
?.toString()
|
||||||
|
data.app.cookieJar.set(
|
||||||
|
data.webHost ?: "vulcan.net.pl",
|
||||||
|
"idBiezacyUczen",
|
||||||
|
studentId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
map[symbol] = permissions
|
||||||
|
}
|
||||||
|
|
||||||
|
val schoolSymbols = mutableListOf<String>()
|
||||||
|
val clientUrl = "://uonetplus-uczen.${data.webHost}/$symbol/"
|
||||||
|
var clientIndex = text.indexOf(clientUrl)
|
||||||
|
var count = 0
|
||||||
|
while (clientIndex != -1 && count < 100) {
|
||||||
|
val startIndex = clientIndex + clientUrl.length
|
||||||
|
val endIndex = text.indexOfAny(charArrayOf('"', '/'), startIndex = startIndex)
|
||||||
|
val schoolSymbol = text.substring(startIndex, endIndex)
|
||||||
|
schoolSymbols += schoolSymbol
|
||||||
|
clientIndex = text.indexOf(clientUrl, startIndex = endIndex)
|
||||||
|
count++
|
||||||
|
}
|
||||||
|
schoolSymbols.removeAll {
|
||||||
|
it.toLowerCase() == "default"
|
||||||
|
|| !it.matches(Regexes.VULCAN_WEB_SYMBOL_VALIDATE)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (postErrors && schoolSymbols.isEmpty()) {
|
||||||
|
data.error(ApiError(TAG, ERROR_VULCAN_WEB_NO_SCHOOLS)
|
||||||
|
.withResponse(response)
|
||||||
|
.withApiResponse(text))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
onSuccess(text, schoolSymbols)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url("https://uonetplus.${data.webHost}/$symbol/Start.mvc/Index")
|
||||||
|
.userAgent(SYSTEM_USER_AGENT)
|
||||||
|
.get()
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||||
|
.allowErrorCode(HttpURLConnection.HTTP_UNAVAILABLE)
|
||||||
|
.allowErrorCode(429)
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateCallback(symbol: String, text: String?, response: Response?, jsonResponse: Boolean = true): Boolean {
|
||||||
|
if (text == null) {
|
||||||
|
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||||
|
.withResponse(response))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response?.code() !in 200..302 || (jsonResponse && !text.startsWith("{"))) {
|
||||||
|
when {
|
||||||
|
text.contains("The custom error module") -> ERROR_VULCAN_WEB_429
|
||||||
|
else -> ERROR_VULCAN_WEB_OTHER
|
||||||
|
}.let { errorCode ->
|
||||||
|
data.error(ApiError(TAG, errorCode)
|
||||||
|
.withApiResponse(text)
|
||||||
|
.withResponse(response))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val cookies = data.app.cookieJar.getAll(data.webHost ?: "vulcan.net.pl")
|
||||||
|
val authCookie = cookies["EfebSsoAuthCookie"]
|
||||||
|
if ((authCookie == null || authCookie == "null") && data.webAuthCookie[symbol] != null) {
|
||||||
|
data.app.cookieJar.set(data.webHost ?: "vulcan.net.pl", "EfebSsoAuthCookie", data.webAuthCookie[symbol])
|
||||||
|
}
|
||||||
|
else if (authCookie.isNotNullNorBlank() && authCookie != "null" && authCookie != data.webAuthCookie[symbol]) {
|
||||||
|
data.webAuthCookie = data.webAuthCookie.toMutableMap().also { map ->
|
||||||
|
map[symbol] = authCookie
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun webGetJson(
|
||||||
|
tag: String,
|
||||||
|
webType: Int,
|
||||||
|
endpoint: String,
|
||||||
|
method: Int = POST,
|
||||||
|
parameters: Map<String, Any?> = emptyMap(),
|
||||||
|
onSuccess: (json: JsonObject, response: Response?) -> Unit
|
||||||
|
) {
|
||||||
|
val url = "https://" + when (webType) {
|
||||||
|
WEB_MAIN -> "uonetplus"
|
||||||
|
WEB_OLD -> "uonetplus-opiekun"
|
||||||
|
WEB_NEW -> "uonetplus-uczen"
|
||||||
|
WEB_MESSAGES -> "uonetplus-uzytkownik"
|
||||||
|
else -> "uonetplus"
|
||||||
|
} + ".${data.webHost}/${data.symbol}/$endpoint"
|
||||||
|
|
||||||
|
Utils.d(tag, "Request: Vulcan/WebMain - $url")
|
||||||
|
|
||||||
|
val payload = JsonObject()
|
||||||
|
parameters.map { (name, value) ->
|
||||||
|
when (value) {
|
||||||
|
is JsonObject -> payload.add(name, value)
|
||||||
|
is JsonArray -> payload.add(name, value)
|
||||||
|
is String -> payload.addProperty(name, value)
|
||||||
|
is Int -> payload.addProperty(name, value)
|
||||||
|
is Long -> payload.addProperty(name, value)
|
||||||
|
is Float -> payload.addProperty(name, value)
|
||||||
|
is Char -> payload.addProperty(name, value)
|
||||||
|
is Boolean -> payload.addProperty(name, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val callback = object : TextCallbackHandler() {
|
||||||
|
override fun onSuccess(text: String?, response: Response?) {
|
||||||
|
if (!validateCallback(data.symbol ?: "default", text, response))
|
||||||
|
return
|
||||||
|
|
||||||
|
try {
|
||||||
|
val json = JsonParser().parse(text).asJsonObject
|
||||||
|
onSuccess(json, response)
|
||||||
|
} catch (e: Exception) {
|
||||||
|
data.error(ApiError(tag, EXCEPTION_VULCAN_WEB_REQUEST)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(e)
|
||||||
|
.withApiResponse(text))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||||
|
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||||
|
.withResponse(response)
|
||||||
|
.withThrowable(throwable))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Request.builder()
|
||||||
|
.url(url)
|
||||||
|
.userAgent(SYSTEM_USER_AGENT)
|
||||||
|
.apply {
|
||||||
|
when (method) {
|
||||||
|
GET -> get()
|
||||||
|
POST -> post()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.setJsonBody(payload)
|
||||||
|
.allowErrorCode(429)
|
||||||
|
.callback(callback)
|
||||||
|
.build()
|
||||||
|
.enqueue()
|
||||||
|
}
|
||||||
|
}
|
@ -1,124 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) Kuba Szczodrzyński 2020-4-6.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api
|
|
||||||
|
|
||||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
|
||||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.EventFull
|
|
||||||
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
|
|
||||||
import pl.szczodrzynski.edziennik.getJsonArray
|
|
||||||
import pl.szczodrzynski.edziennik.getLong
|
|
||||||
import pl.szczodrzynski.edziennik.getString
|
|
||||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
|
||||||
import kotlin.reflect.KClass
|
|
||||||
|
|
||||||
class VulcanApiAttachments(override val data: DataVulcan,
|
|
||||||
val list: List<*>,
|
|
||||||
val owner: Any?,
|
|
||||||
val ownerClass: KClass<*>,
|
|
||||||
val onSuccess: (list: List<*>) -> Unit
|
|
||||||
) : VulcanApi(data, null) {
|
|
||||||
companion object {
|
|
||||||
const val TAG = "VulcanApiAttachments"
|
|
||||||
}
|
|
||||||
|
|
||||||
init { run {
|
|
||||||
val endpoint = when (ownerClass) {
|
|
||||||
MessageFull::class -> VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS
|
|
||||||
EventFull::class -> VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS
|
|
||||||
else -> null
|
|
||||||
} ?: return@run
|
|
||||||
|
|
||||||
val idName = when (ownerClass) {
|
|
||||||
MessageFull::class -> "IdWiadomosc"
|
|
||||||
EventFull::class -> "IdZadanieDomowe"
|
|
||||||
else -> null
|
|
||||||
} ?: return@run
|
|
||||||
|
|
||||||
val startDate = profile?.getSemesterStart(profile?.currentSemester ?: 1)?.inUnix ?: 0
|
|
||||||
val endDate = Date.getToday().stepForward(0, 1, 0).inUnix
|
|
||||||
|
|
||||||
apiGet(TAG, endpoint, parameters = mapOf(
|
|
||||||
"DataPoczatkowa" to startDate,
|
|
||||||
"DataKoncowa" to endDate,
|
|
||||||
"LoginId" to data.studentLoginId,
|
|
||||||
"IdUczen" to data.studentId
|
|
||||||
)) { json, _ ->
|
|
||||||
|
|
||||||
json.getJsonArray("Data")?.asJsonObjectList()?.forEach { attachment ->
|
|
||||||
val id = attachment.getLong("Id") ?: return@forEach
|
|
||||||
val itemId = attachment.getLong(idName) ?: return@forEach
|
|
||||||
val url = attachment.getString("Url") ?: return@forEach
|
|
||||||
val fileName = "${attachment.getString("NazwaPliku")}:$url"
|
|
||||||
|
|
||||||
list.forEach {
|
|
||||||
if (it is MessageFull
|
|
||||||
&& it.profileId == profileId
|
|
||||||
&& it.id == itemId
|
|
||||||
&& it.attachmentIds?.contains(id) != true) {
|
|
||||||
if (it.attachmentIds == null)
|
|
||||||
it.attachmentIds = mutableListOf()
|
|
||||||
if (it.attachmentNames == null)
|
|
||||||
it.attachmentNames = mutableListOf()
|
|
||||||
it.attachmentIds?.add(id)
|
|
||||||
it.attachmentNames?.add(fileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (it is EventFull
|
|
||||||
&& it.profileId == profileId
|
|
||||||
&& it.id == itemId
|
|
||||||
&& it.attachmentIds?.contains(id) != true) {
|
|
||||||
if (it.attachmentIds == null)
|
|
||||||
it.attachmentIds = mutableListOf()
|
|
||||||
if (it.attachmentNames == null)
|
|
||||||
it.attachmentNames = mutableListOf()
|
|
||||||
it.attachmentIds?.add(id)
|
|
||||||
it.attachmentNames?.add(fileName)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (owner is MessageFull
|
|
||||||
&& it is MessageFull
|
|
||||||
&& owner.profileId == it.profileId
|
|
||||||
&& owner.id == it.id) {
|
|
||||||
owner.attachmentIds = it.attachmentIds
|
|
||||||
owner.attachmentNames = it.attachmentNames
|
|
||||||
}
|
|
||||||
|
|
||||||
if (owner is EventFull
|
|
||||||
&& it is EventFull
|
|
||||||
&& owner.profileId == it.profileId
|
|
||||||
&& owner.id == it.id) {
|
|
||||||
owner.attachmentIds = it.attachmentIds
|
|
||||||
owner.attachmentNames = it.attachmentNames
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*if (owner is MessageFull) {
|
|
||||||
list.forEach {
|
|
||||||
(it as? MessageFull)?.let { message ->
|
|
||||||
data.messageList.add(message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.messageListReplace = true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (owner is EventFull) {
|
|
||||||
list.forEach {
|
|
||||||
(it as? EventFull)?.let { it1 ->
|
|
||||||
it1.homeworkBody = ""
|
|
||||||
data.eventList.add(it1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
data.eventListReplace = true
|
|
||||||
}*/
|
|
||||||
|
|
||||||
onSuccess(list)
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user