mirror of
https://github.com/szkolny-eu/szkolny-android.git
synced 2025-06-22 10:03:03 +02:00
Compare commits
71 Commits
v3.9.16-de
...
v4.0-beta.
Author | SHA1 | Date | |
---|---|---|---|
de6b77baba | |||
c8e3a3d258 | |||
52ef24ae7b | |||
1553173300 | |||
f5b2c24ee3 | |||
2ddbc6bbac | |||
eae7189981 | |||
f292b3637d | |||
aff0b361a2 | |||
9f78b86c57 | |||
4950627850 | |||
5265f3eb6a | |||
3cca5e8e9a | |||
e9ca109c57 | |||
344da53888 | |||
62ae3c4c4b | |||
6f95eb3c3f | |||
f350a86946 | |||
868e529e62 | |||
62d82c88a1 | |||
a86e995113 | |||
5e2c7e89ab | |||
4a38906194 | |||
cc3e6d97dd | |||
90d6fb56d1 | |||
9b5cf3f636 | |||
3723abbbbb | |||
a626427788 | |||
35d88f8c78 | |||
c65872b29b | |||
e472d34f4d | |||
1257596104 | |||
5dd6519d27 | |||
e607577407 | |||
ade12e729f | |||
eee83ebb94 | |||
39ff47e866 | |||
6c81a506e9 | |||
a24620de31 | |||
70de47408a | |||
04103d1c84 | |||
d20102c3bd | |||
f165ee32e5 | |||
60ad2e81f3 | |||
5ca8b642da | |||
f40cd7f26c | |||
e04b519e9b | |||
658e59bed6 | |||
cb5eb19abc | |||
d336531ca8 | |||
30ee71f4e3 | |||
844d5b33bc | |||
e3741f1c75 | |||
21a6e4d8c6 | |||
ec14ba76c9 | |||
90e7b1e9c7 | |||
a09d943344 | |||
52ac40c826 | |||
8f8eb64364 | |||
fe40ab0ab4 | |||
5991ef820f | |||
d67c2a90b1 | |||
e85d6fbc3b | |||
62a9604bd2 | |||
0aae2174c1 | |||
b66bd6fec9 | |||
b399a3f5ad | |||
1f5927eec0 | |||
2d838e7003 | |||
f242c30476 | |||
2cf204ff79 |
45
.idea/jarRepositories.xml
generated
Normal file
45
.idea/jarRepositories.xml
generated
Normal file
@ -0,0 +1,45 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="RemoteRepositoriesConfiguration">
|
||||
<remote-repository>
|
||||
<option name="id" value="central" />
|
||||
<option name="name" value="Maven Central repository" />
|
||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="jboss.community" />
|
||||
<option name="name" value="JBoss Community repository" />
|
||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven2" />
|
||||
<option name="name" value="maven2" />
|
||||
<option name="url" value="https://kotlin.bintray.com/kotlinx/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven3" />
|
||||
<option name="name" value="maven3" />
|
||||
<option name="url" value="https://dl.bintray.com/wulkanowy/wulkanowy" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="BintrayJCenter" />
|
||||
<option name="name" value="BintrayJCenter" />
|
||||
<option name="url" value="https://jcenter.bintray.com/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="maven" />
|
||||
<option name="name" value="maven" />
|
||||
<option name="url" value="https://jitpack.io" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="Google" />
|
||||
<option name="name" value="Google" />
|
||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
||||
</remote-repository>
|
||||
<remote-repository>
|
||||
<option name="id" value="MavenRepo" />
|
||||
<option name="name" value="MavenRepo" />
|
||||
<option name="url" value="https://repo.maven.apache.org/maven2/" />
|
||||
</remote-repository>
|
||||
</component>
|
||||
</project>
|
BIN
app/libs/java-json.jar
Normal file
BIN
app/libs/java-json.jar
Normal file
Binary file not shown.
13
app/sampledata/format-bold/ic_format_bold.xml
Normal file
13
app/sampledata/format-bold/ic_format_bold.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-12-28.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M13.5,15.5H10V12.5H13.5A1.5,1.5 0,0 1,15 14A1.5,1.5 0,0 1,13.5 15.5M10,6.5H13A1.5,1.5 0,0 1,14.5 8A1.5,1.5 0,0 1,13 9.5H10M15.6,10.79C16.57,10.11 17.25,9 17.25,8C17.25,5.74 15.5,4 13.25,4H7V18H14.04C16.14,18 17.75,16.3 17.75,14.21C17.75,12.69 16.89,11.39 15.6,10.79Z"/>
|
||||
</vector>
|
13
app/sampledata/format/ic_format_italic.xml
Normal file
13
app/sampledata/format/ic_format_italic.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-12-28.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M10,4V7H12.21L8.79,15H6V18H14V15H11.79L15.21,7H18V4H10Z"/>
|
||||
</vector>
|
13
app/sampledata/format/ic_format_underline.xml
Normal file
13
app/sampledata/format/ic_format_underline.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!--
|
||||
~ Copyright (c) Kuba Szczodrzyński 2019-12-28.
|
||||
-->
|
||||
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M5,21H19V19H5V21M12,17A6,6 0,0 0,18 11V3H15.5V11A3.5,3.5 0,0 1,12 14.5A3.5,3.5 0,0 1,8.5 11V3H6V11A6,6 0,0 0,12 17Z"/>
|
||||
</vector>
|
@ -12,7 +12,7 @@
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/SplashTheme"
|
||||
android:theme="@style/AppTheme.Dark"
|
||||
android:usesCleartextTraffic="true"
|
||||
tools:ignore="UnusedAttribute">
|
||||
<activity
|
||||
@ -32,11 +32,6 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name=".ui.modules.messages.MessagesComposeActivity"
|
||||
android:configChanges="orientation|screenSize"
|
||||
android:label="@string/messages_compose_title"
|
||||
android:theme="@style/AppTheme.Black" />
|
||||
<activity
|
||||
android:name=".ui.modules.feedback.FeedbackActivity"
|
||||
android:configChanges="orientation|screenSize|keyboardHidden"
|
||||
@ -99,12 +94,6 @@
|
||||
__/ |
|
||||
|_
|
||||
-->
|
||||
<activity
|
||||
android:name=".widgets.timetable.LessonDetailsActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
android:noHistory="true"
|
||||
android:theme="@style/AppTheme.NoDisplay" />
|
||||
<activity android:name=".widgets.timetable.LessonDialogActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:excludeFromRecents="true"
|
||||
@ -122,6 +111,9 @@
|
||||
android:name=".ui.modules.webpush.WebPushConfigActivity"
|
||||
android:configChanges="orientation|keyboardHidden"
|
||||
android:theme="@style/AppTheme.Dark" />
|
||||
<activity
|
||||
android:name=".ui.modules.home.CounterActivityOld"
|
||||
android:theme="@style/AppTheme.Black" />
|
||||
<activity
|
||||
android:name=".ui.modules.home.CounterActivity"
|
||||
android:theme="@style/AppTheme.Black" />
|
||||
|
@ -1,53 +1,38 @@
|
||||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
* {
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: #{bg-color}; color: #{text-color};
|
||||
}
|
||||
|
||||
a {
|
||||
color: #{link-color};
|
||||
}
|
||||
|
||||
a:active {
|
||||
color: #{link-color-active};
|
||||
}
|
||||
|
||||
ol {
|
||||
list-style-position: inside;
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
li:not(:first-child) {
|
||||
padding-top: 8px;
|
||||
}
|
||||
</style>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<h3>Wersja 4.0, 2019-jeszcze-nie-wiem-kiedy</h3>
|
||||
<h3>Wersja 4.0-beta.1, 2020-01-02</h3>
|
||||
<ul>
|
||||
<li>UWAGA. To jest wersja in-development. Wiele funkcji może nie działać prawidłowo (lub wcale), co oznacza tylko że nie zostały jeszcze przeniesione
|
||||
z wersji 3.x. Proszę o cierpliwość oraz <b>nie udostępnianie</b> tej wersji <u>nikomu</u>.</li>
|
||||
<li>Bardzo dużo zmian</li>
|
||||
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkosć oraz poprawność pobieranych danych.</li>
|
||||
<li><b><u>Wysyłanie wiadomości</u></b> - funkcja, na którą czekał każdy. Od teraz w Szkolnym można wysyłać oraz odpowiadać na wiadomości do nauczycieli 👏</li>
|
||||
<li>Udoskonalony wygląd Szkolnego - sprawi, że korzystanie z aplikacji będzie jeszcze przyjemniejsze</li>
|
||||
<li>Nowa <b>Strona główna</b> - ładniejszy wygląd oraz możliwość przestawiania kart na każdym profilu</li>
|
||||
<li>Nowy <b>Plan lekcji</b> - z doskonałą obsługą lekcji przesuniętych oraz dwóch lekcji o tej samej godzinie</li>
|
||||
<li>Nowe okienka informacji o wydarzeniach oraz lekcjach</li>
|
||||
<li>Łatwiejsze dodawanie własnych wydarzeń</li>
|
||||
<li>Dużo poprawek w widoku <b>Wiadomości</b> oraz <b>Ogłoszeń</b></li>
|
||||
<li>Częściowa <b>Obsługa dziennika EduDziennik</b></li>
|
||||
<li>Librus: opcja logowania w dziennikach <b>Jednostek Samorządu Terytorialnego</b> oraz <b>Oświata w Radomiu</b></li>
|
||||
<li>Librus: obsługa Zadań domowych bez posiadania Mobilnych dodatków (przez system Synergia)</li>
|
||||
<li>Lepsze <b>przekazywanie powiadomień na komputer</b> oraz łatwiejsze parowanie</li>
|
||||
<li>Poprawiliśmy synchronizację w tle na niektórych telefonach</li>
|
||||
<li>Znaczna ilość błędów z poprzednich wersji już nie występuje</li>
|
||||
</ul>
|
||||
|
||||
<!--<i>
|
||||
<h3>Plany na następne wersje:</h3>
|
||||
<ul>
|
||||
<li>Widget kalendarza ze sprawdzianami, ulepszenie widoku kalendarza w aplikacji</li>
|
||||
<li>Wsparcie dla systemu Synergia w jednostkach samorządu terytorialnego - aplikacja Nasze Szkoły</li>
|
||||
<li>Wsparcie dla Librusa w systemie Oświata w Radomiu</li>
|
||||
<li>EduDziennik</li>
|
||||
<li>Mobireg</li>
|
||||
<li>Możliwość edycji planu lekcji</li>
|
||||
</ul>
|
||||
</i>-->
|
||||
|
||||
</body>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<b>Uwaga.</b> Ponieważ to wersja <i>beta</i>, niektóre funkcje mogą nie działać prawidłowo.<br>
|
||||
Staramy się usuwać takie przypadki, jednak na chwilę obecną mogą występować błędy w:
|
||||
<ul>
|
||||
<li>Wysyłanie wiadomości może czasami nie działać - proszę o zgłaszanie wszystkich błędów na naszym serwerze Discord</li>
|
||||
<li>Widget powiadomień</li>
|
||||
<li>Terminarz - brak informacji o odwołanych lekcjach w dialogu</li>
|
||||
<li>Brak generowania blokowego planu lekcji</li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
<i>Okazja ograniczona czasowo:</i> Poczuj prawdziwą zimę, włączając w Ustawieniach widok padającego śniegu!
|
||||
<br>
|
||||
<br>
|
||||
<br>
|
||||
Dzięki za korzystanie ze Szkolnego!<br>
|
||||
<i>© Kuba Szczodrzyński, Kacper Ziubryniewicz 2020</i>
|
||||
|
@ -9,7 +9,7 @@
|
||||
|
||||
/*secret password - removed for source code publication*/
|
||||
static toys AES_IV[16] = {
|
||||
0x97, 0x0e, 0x93, 0xd3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
0x6c, 0x53, 0xa9, 0x71, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);
|
||||
|
||||
|
@ -67,8 +67,9 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing;
|
||||
import pl.szczodrzynski.edziennik.config.Config;
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing;
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.AppDb;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
@ -438,6 +439,11 @@ public class App extends androidx.multidex.MultiDexApplication implements Config
|
||||
"Vulcan"
|
||||
);
|
||||
|
||||
if (config.getRunSync()) {
|
||||
config.setRunSync(false);
|
||||
EdziennikTask.Companion.sync().enqueue(this);
|
||||
}
|
||||
|
||||
try {
|
||||
final long startTime = System.currentTimeMillis();
|
||||
FirebaseInstanceId.getInstance().getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
|
@ -4,6 +4,7 @@ import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.res.ColorStateList
|
||||
import android.content.res.Resources
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffColorFilter
|
||||
@ -15,6 +16,7 @@ import android.text.*
|
||||
import android.text.style.ForegroundColorSpan
|
||||
import android.text.style.StrikethroughSpan
|
||||
import android.text.style.StyleSpan
|
||||
import android.util.Base64
|
||||
import android.util.Base64.NO_WRAP
|
||||
import android.util.Base64.encodeToString
|
||||
import android.util.LongSparseArray
|
||||
@ -42,8 +44,10 @@ import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.navlib.getColorFromRes
|
||||
import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.math.BigInteger
|
||||
import java.nio.charset.Charset
|
||||
import java.security.MessageDigest
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
@ -97,12 +101,31 @@ fun Bundle?.getString(key: String, defaultValue: String): String {
|
||||
return this?.getString(key, defaultValue) ?: defaultValue
|
||||
}
|
||||
|
||||
fun String.fixName(): String {
|
||||
return this.fixWhiteSpaces().toProperCase()
|
||||
/**
|
||||
* ` The quick BROWN_fox Jumps OveR THE LAZy-DOG. `
|
||||
*
|
||||
* converts to
|
||||
*
|
||||
* `The Quick Brown_fox Jumps Over The Lazy-Dog.`
|
||||
*/
|
||||
fun String?.fixName(): String {
|
||||
return this?.fixWhiteSpaces()?.toProperCase() ?: ""
|
||||
}
|
||||
|
||||
/**
|
||||
* `The quick BROWN_fox Jumps OveR THE LAZy-DOG.`
|
||||
*
|
||||
* converts to
|
||||
*
|
||||
* `The Quick Brown_fox Jumps Over The Lazy-Dog.`
|
||||
*/
|
||||
fun String.toProperCase(): String = changeStringCase(this)
|
||||
|
||||
/**
|
||||
* `John Smith` -> `Smith John`
|
||||
*
|
||||
* `JOHN SMith` -> `SMith JOHN`
|
||||
*/
|
||||
fun String.swapFirstLastName(): String {
|
||||
return this.split(" ").let {
|
||||
if (it.size > 1)
|
||||
@ -112,15 +135,13 @@ fun String.swapFirstLastName(): String {
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getFirstLastName(): Pair<String, String>? {
|
||||
fun String.splitName(): Pair<String, String>? {
|
||||
return this.split(" ").let {
|
||||
if (it.size >= 2) Pair(it[0], it[1])
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
fun String.getLastFirstName() = this.getFirstLastName()
|
||||
|
||||
fun changeStringCase(s: String): String {
|
||||
val delimiters = " '-/"
|
||||
val sb = StringBuilder()
|
||||
@ -150,33 +171,66 @@ fun String.getShortName(): String {
|
||||
}
|
||||
}
|
||||
|
||||
fun List<String>.join(delimiter: String): String {
|
||||
return this.joinToString(delimiter)
|
||||
/**
|
||||
* "John Smith" -> "JS"
|
||||
*
|
||||
* "JOHN SMith" -> "JS"
|
||||
*
|
||||
* "John" -> "J"
|
||||
*
|
||||
* "John " -> "J"
|
||||
*
|
||||
* "John Smith " -> "JS"
|
||||
*
|
||||
* " " -> ""
|
||||
*
|
||||
* " " -> ""
|
||||
*/
|
||||
fun String?.getNameInitials(): String {
|
||||
if (this.isNullOrBlank()) return ""
|
||||
return this.toUpperCase().fixWhiteSpaces().split(" ").take(2).map { it[0] }.joinToString("")
|
||||
}
|
||||
|
||||
fun colorFromName(context: Context, name: String?): Int {
|
||||
fun List<String>.join(delimiter: String): String {
|
||||
return concat(delimiter).toString()
|
||||
}
|
||||
|
||||
fun colorFromName(name: String?): Int {
|
||||
var crc = (name ?: "").crc16()
|
||||
crc = (crc and 0xff) or (crc shr 8)
|
||||
crc %= 16
|
||||
val color = when (crc) {
|
||||
13 -> R.color.md_red_500
|
||||
4 -> R.color.md_pink_A400
|
||||
2 -> R.color.md_purple_A400
|
||||
9 -> R.color.md_deep_purple_A700
|
||||
5 -> R.color.md_indigo_500
|
||||
1 -> R.color.md_indigo_A700
|
||||
6 -> R.color.md_cyan_A200
|
||||
14 -> R.color.md_teal_400
|
||||
15 -> R.color.md_green_500
|
||||
7 -> R.color.md_yellow_A700
|
||||
3 -> R.color.md_deep_orange_A400
|
||||
8 -> R.color.md_deep_orange_A700
|
||||
10 -> R.color.md_brown_500
|
||||
12 -> R.color.md_grey_400
|
||||
11 -> R.color.md_blue_grey_400
|
||||
else -> R.color.md_light_green_A700
|
||||
}
|
||||
return context.getColorFromRes(color)
|
||||
return when (crc) {
|
||||
13 -> 0xffF44336
|
||||
4 -> 0xffF50057
|
||||
2 -> 0xffD500F9
|
||||
9 -> 0xff6200EA
|
||||
5 -> 0xff3F51B5
|
||||
1 -> 0xff304FFE
|
||||
6 -> 0xff18FFFF
|
||||
14 -> 0xff26A69A
|
||||
15 -> 0xff4CAF50
|
||||
7 -> 0xffFFD600
|
||||
3 -> 0xffFF3D00
|
||||
8 -> 0xffDD2C00
|
||||
10 -> 0xff795548
|
||||
12 -> 0xffBDBDBD
|
||||
11 -> 0xff78909C
|
||||
else -> 0xff64DD17
|
||||
}.toInt()
|
||||
}
|
||||
|
||||
fun colorFromCssName(name: String): Int {
|
||||
return when (name) {
|
||||
"red" -> 0xffff0000
|
||||
"green" -> 0xff008000
|
||||
"blue" -> 0xff0000ff
|
||||
"violet" -> 0xffee82ee
|
||||
"brown" -> 0xffa52a2a
|
||||
"orange" -> 0xffffa500
|
||||
"black" -> 0xff000000
|
||||
"white" -> 0xffffffff
|
||||
else -> -1
|
||||
}.toInt()
|
||||
}
|
||||
|
||||
fun MutableList<Profile>.filterOutArchived(): MutableList<Profile> {
|
||||
@ -228,6 +282,21 @@ fun <T> SparseArray<T>.values(): List<T> {
|
||||
return result
|
||||
}
|
||||
|
||||
fun <K, V> List<Pair<K, V>>.keys(): List<K> {
|
||||
val result = mutableListOf<K>()
|
||||
forEach { pair ->
|
||||
result += pair.first
|
||||
}
|
||||
return result
|
||||
}
|
||||
fun <K, V> List<Pair<K, V>>.values(): List<V> {
|
||||
val result = mutableListOf<V>()
|
||||
forEach { pair ->
|
||||
result += pair.second
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T> List<T>.toSparseArray(destination: SparseArray<T>, key: (T) -> Int) {
|
||||
forEach {
|
||||
destination.put(key(it), it)
|
||||
@ -410,6 +479,29 @@ fun CharSequence?.asItalicSpannable(): Spannable {
|
||||
spannable.setSpan(StyleSpan(Typeface.ITALIC), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return spannable
|
||||
}
|
||||
fun CharSequence?.asBoldSpannable(): Spannable {
|
||||
val spannable = SpannableString(this)
|
||||
spannable.setSpan(StyleSpan(Typeface.BOLD), 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
return spannable
|
||||
}
|
||||
fun CharSequence.asSpannable(vararg spans: Any, substring: String? = null, ignoreCase: Boolean = false): Spannable {
|
||||
val spannable = SpannableString(this)
|
||||
if (substring == null) {
|
||||
spans.forEach {
|
||||
spannable.setSpan(it, 0, spannable.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
}
|
||||
else if (substring.isNotEmpty()) {
|
||||
var index = indexOf(substring, ignoreCase = ignoreCase)
|
||||
while (index >= 0) {
|
||||
spans.forEach {
|
||||
spannable.setSpan(it, index, index + substring.length, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE)
|
||||
}
|
||||
index = indexOf(substring, startIndex = index + 1, ignoreCase = ignoreCase);
|
||||
}
|
||||
}
|
||||
return spannable
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new read-only list only of those given elements, that are not empty.
|
||||
@ -417,7 +509,7 @@ fun CharSequence?.asItalicSpannable(): Spannable {
|
||||
*/
|
||||
fun <T : CharSequence> listOfNotEmpty(vararg elements: T): List<T> = elements.filterNot { it.isEmpty() }
|
||||
|
||||
fun List<CharSequence?>.concat(delimiter: String? = null): CharSequence {
|
||||
fun List<CharSequence?>.concat(delimiter: CharSequence? = null): CharSequence {
|
||||
if (this.isEmpty()) {
|
||||
return ""
|
||||
}
|
||||
@ -426,11 +518,13 @@ fun List<CharSequence?>.concat(delimiter: String? = null): CharSequence {
|
||||
return this[0] ?: ""
|
||||
}
|
||||
|
||||
var spanned = false
|
||||
for (piece in this) {
|
||||
if (piece is Spanned) {
|
||||
spanned = true
|
||||
break
|
||||
var spanned = delimiter is Spanned
|
||||
if (!spanned) {
|
||||
for (piece in this) {
|
||||
if (piece is Spanned) {
|
||||
spanned = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -478,8 +572,44 @@ fun JsonObject(vararg properties: Pair<String, Any?>): JsonObject {
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonArray(vararg properties: Any?): JsonArray {
|
||||
return JsonArray().apply {
|
||||
for (property in properties) {
|
||||
when (property) {
|
||||
is JsonElement -> add(property as JsonElement?)
|
||||
is String -> add(property as String?)
|
||||
is Char -> add(property as Char?)
|
||||
is Number -> add(property as Number?)
|
||||
is Boolean -> add(property as Boolean?)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun Bundle(vararg properties: Pair<String, Any?>): Bundle {
|
||||
return Bundle().apply {
|
||||
for (property in properties) {
|
||||
when (property.second) {
|
||||
is String -> putString(property.first, property.second as String?)
|
||||
is Char -> putChar(property.first, property.second as Char)
|
||||
is Int -> putInt(property.first, property.second as Int)
|
||||
is Long -> putLong(property.first, property.second as Long)
|
||||
is Float -> putFloat(property.first, property.second as Float)
|
||||
is Short -> putShort(property.first, property.second as Short)
|
||||
is Double -> putDouble(property.first, property.second as Double)
|
||||
is Boolean -> putBoolean(property.first, property.second as Boolean)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun JsonArray?.isNullOrEmpty(): Boolean = (this?.size() ?: 0) == 0
|
||||
fun JsonArray.isEmpty(): Boolean = this.size() == 0
|
||||
operator fun JsonArray.plusAssign(o: JsonElement) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: String) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: Char) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: Number) = this.add(o)
|
||||
operator fun JsonArray.plusAssign(o: Boolean) = this.add(o)
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
inline fun <T : View> T.onClick(crossinline onClickListener: (v: T) -> Unit) {
|
||||
@ -576,52 +706,65 @@ operator fun StringBuilder.plusAssign(str: String?) {
|
||||
this.append(str)
|
||||
}
|
||||
|
||||
fun Context.timeTill(time: Int, delimiter: String = " "): String {
|
||||
fun Context.timeTill(time: Int, delimiter: String = " ", countInSeconds: Boolean = false): String {
|
||||
val parts = mutableListOf<Pair<Int, Int>>()
|
||||
|
||||
val hours = time / 3600
|
||||
val minutes = (time - hours*3600) / 60
|
||||
val seconds = time - minutes*60 - hours*3600
|
||||
|
||||
var prefixAdded = false
|
||||
if (hours > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to hours; prefixAdded = true
|
||||
parts += R.plurals.time_till_hours to hours
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to minutes; prefixAdded = true
|
||||
parts += R.plurals.time_till_minutes to minutes
|
||||
}
|
||||
if (hours == 0 && minutes < 10) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to seconds; prefixAdded = true
|
||||
parts += R.plurals.time_till_seconds to seconds
|
||||
if (!countInSeconds) {
|
||||
var prefixAdded = false
|
||||
if (hours > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to hours
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_till_hours to hours
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to minutes
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_till_minutes to minutes
|
||||
}
|
||||
if (hours == 0 && minutes < 10) {
|
||||
if (!prefixAdded) parts += R.plurals.time_till_text to seconds
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_till_seconds to seconds
|
||||
}
|
||||
} else {
|
||||
parts += R.plurals.time_till_text to time
|
||||
parts += R.plurals.time_till_seconds to time
|
||||
}
|
||||
|
||||
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||
}
|
||||
|
||||
fun Context.timeLeft(time: Int, delimiter: String = " "): String {
|
||||
fun Context.timeLeft(time: Int, delimiter: String = " ", countInSeconds: Boolean = false): String {
|
||||
val parts = mutableListOf<Pair<Int, Int>>()
|
||||
|
||||
val hours = time / 3600
|
||||
val minutes = (time - hours*3600) / 60
|
||||
val seconds = time - minutes*60 - hours*3600
|
||||
|
||||
var prefixAdded = false
|
||||
if (hours > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to hours
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_hours to hours
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to minutes
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_minutes to minutes
|
||||
}
|
||||
if (hours == 0 && minutes < 10) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to seconds
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_seconds to seconds
|
||||
if (!countInSeconds) {
|
||||
var prefixAdded = false
|
||||
if (hours > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to hours
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_hours to hours
|
||||
}
|
||||
if (minutes > 0) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to minutes
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_minutes to minutes
|
||||
}
|
||||
if (hours == 0 && minutes < 10) {
|
||||
if (!prefixAdded) parts += R.plurals.time_left_text to seconds
|
||||
prefixAdded = true
|
||||
parts += R.plurals.time_left_seconds to seconds
|
||||
}
|
||||
} else {
|
||||
parts += R.plurals.time_left_text to time
|
||||
parts += R.plurals.time_left_seconds to time
|
||||
}
|
||||
|
||||
return parts.joinToString(delimiter) { resources.getQuantityString(it.first, it.second, it.second) }
|
||||
@ -641,3 +784,98 @@ fun Drawable.setTintColor(color: Int): Drawable {
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
inline fun <T> List<T>.ifNotEmpty(block: (List<T>) -> Unit) {
|
||||
if (!isEmpty())
|
||||
block(this)
|
||||
}
|
||||
|
||||
val String.firstLettersName: String
|
||||
get() {
|
||||
var nameShort = ""
|
||||
this.split(" ").forEach {
|
||||
if (it.isBlank())
|
||||
return@forEach
|
||||
nameShort += it[0].toLowerCase()
|
||||
}
|
||||
return nameShort
|
||||
}
|
||||
|
||||
val Throwable.stackTraceString: String
|
||||
get() {
|
||||
val sw = StringWriter()
|
||||
printStackTrace(PrintWriter(sw))
|
||||
return sw.toString()
|
||||
}
|
||||
|
||||
inline fun <T> LongSparseArray<T>.filter(predicate: (T) -> Boolean): List<T> {
|
||||
val destination = ArrayList<T>()
|
||||
this.forEach { _, element -> if (predicate(element)) destination.add(element) }
|
||||
return destination
|
||||
}
|
||||
|
||||
fun CharSequence.replace(oldValue: String, newValue: CharSequence, ignoreCase: Boolean = false): CharSequence =
|
||||
splitToSequence(oldValue, ignoreCase = ignoreCase).toList().concat(newValue)
|
||||
|
||||
fun Int.toColorStateList(): ColorStateList {
|
||||
val states = arrayOf(
|
||||
intArrayOf( android.R.attr.state_enabled ),
|
||||
intArrayOf(-android.R.attr.state_enabled ),
|
||||
intArrayOf(-android.R.attr.state_checked ),
|
||||
intArrayOf( android.R.attr.state_pressed )
|
||||
)
|
||||
|
||||
val colors = intArrayOf(
|
||||
this,
|
||||
this,
|
||||
this,
|
||||
this
|
||||
)
|
||||
|
||||
return ColorStateList(states, colors);
|
||||
}
|
||||
|
||||
fun SpannableStringBuilder.appendText(text: CharSequence): SpannableStringBuilder {
|
||||
append(text)
|
||||
return this
|
||||
}
|
||||
fun SpannableStringBuilder.appendSpan(text: CharSequence, what: Any, flags: Int): SpannableStringBuilder {
|
||||
val start: Int = length
|
||||
append(text)
|
||||
setSpan(what, start, length, flags)
|
||||
return this
|
||||
}
|
||||
|
||||
fun joinNotNullStrings(delimiter: String = "", vararg parts: String?): String {
|
||||
var first = true
|
||||
val sb = StringBuilder()
|
||||
for (part in parts) {
|
||||
if (part == null)
|
||||
continue
|
||||
if (!first)
|
||||
sb += delimiter
|
||||
first = false
|
||||
sb += part
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun String.notEmptyOrNull(): String? {
|
||||
return if (isEmpty())
|
||||
null
|
||||
else
|
||||
this
|
||||
}
|
||||
|
||||
fun String.base64Encode(): String {
|
||||
return encodeToString(toByteArray(), NO_WRAP)
|
||||
}
|
||||
fun ByteArray.base64Encode(): String {
|
||||
return encodeToString(this, NO_WRAP)
|
||||
}
|
||||
fun String.base64Decode(): ByteArray {
|
||||
return Base64.decode(this, Base64.DEFAULT)
|
||||
}
|
||||
fun String.base64DecodeToString(): String {
|
||||
return Base64.decode(this, Base64.DEFAULT).toString(Charset.defaultCharset())
|
||||
}
|
||||
|
@ -9,7 +9,10 @@ import android.content.IntentFilter
|
||||
import android.content.pm.PackageManager
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.*
|
||||
import android.os.AsyncTask
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.os.Environment
|
||||
import android.provider.Settings
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
@ -20,6 +23,7 @@ import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.NavOptions
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import com.danimahardhika.cafebar.CafeBar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.IconicsColor
|
||||
@ -36,13 +40,11 @@ import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.data.api.events.*
|
||||
import pl.szczodrzynski.edziennik.data.api.szkolny.interceptor.Signing
|
||||
import pl.szczodrzynski.edziennik.data.api.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
@ -52,17 +54,20 @@ import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.MainSnackbar
|
||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragmentV2
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessageFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesComposeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesListFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
||||
@ -119,6 +124,7 @@ class MainActivity : AppCompatActivity() {
|
||||
const val TARGET_HELP = 502
|
||||
const val TARGET_FEEDBACK = 120
|
||||
const val TARGET_MESSAGES_DETAILS = 503
|
||||
const val TARGET_MESSAGES_COMPOSE = 504
|
||||
const val TARGET_WEB_PUSH = 140
|
||||
|
||||
const val HOME_ID = DRAWER_ITEM_HOME
|
||||
@ -127,7 +133,7 @@ class MainActivity : AppCompatActivity() {
|
||||
val list: MutableList<NavTarget> = mutableListOf()
|
||||
|
||||
// home item
|
||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragmentV2::class)
|
||||
list += NavTarget(DRAWER_ITEM_HOME, R.string.menu_home_page, HomeFragment::class)
|
||||
.withTitle(R.string.app_name)
|
||||
.withIcon(CommunityMaterial.Icon2.cmd_home_outline)
|
||||
.isInDrawer(true)
|
||||
@ -210,7 +216,8 @@ class MainActivity : AppCompatActivity() {
|
||||
list += NavTarget(TARGET_GRADES_EDITOR, R.string.menu_grades_editor, GradesEditorFragment::class)
|
||||
list += NavTarget(TARGET_HELP, R.string.menu_help, HelpFragment::class)
|
||||
list += NavTarget(TARGET_FEEDBACK, R.string.menu_feedback, FeedbackFragment::class)
|
||||
list += NavTarget(TARGET_MESSAGES_DETAILS, R.string.menu_message, MessageFragment::class)
|
||||
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_WEB_PUSH, R.string.menu_web_push, WebPushFragment::class)
|
||||
list += NavTarget(DRAWER_ITEM_DEBUG, R.string.menu_debug, DebugFragment::class)
|
||||
|
||||
@ -222,6 +229,7 @@ class MainActivity : AppCompatActivity() {
|
||||
val navView: NavView by lazy { b.navView }
|
||||
val drawer: NavDrawer by lazy { navView.drawer }
|
||||
val bottomSheet: NavBottomSheet by lazy { navView.bottomSheet }
|
||||
val mainSnackbar: MainSnackbar by lazy { MainSnackbar(this) }
|
||||
val errorSnackbar: ErrorSnackbar by lazy { ErrorSnackbar(this) }
|
||||
|
||||
val swipeRefreshLayout: SwipeRefreshLayoutNoTouch by lazy { b.swipeRefreshLayout }
|
||||
@ -232,10 +240,11 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
private val fragmentManager by lazy { supportFragmentManager }
|
||||
private lateinit var navTarget: NavTarget
|
||||
private var navArguments: Bundle? = null
|
||||
val navTargetId
|
||||
get() = navTarget.id
|
||||
|
||||
private val navBackStack = mutableListOf<NavTarget>()
|
||||
private val navBackStack = mutableListOf<Pair<NavTarget, Bundle?>>()
|
||||
private var navLoading = true
|
||||
|
||||
/* ____ _____ _
|
||||
@ -257,6 +266,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
Log.d(TAG, Signing.appPassword)
|
||||
|
||||
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
|
||||
|
||||
navLoading = true
|
||||
@ -426,16 +436,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
// WHAT'S NEW DIALOG
|
||||
if (app.config.appVersion < BuildConfig.VERSION_CODE) {
|
||||
ServerRequest(app, app.requestScheme + APP_URL + "main.php?just_updated", "MainActivity/JU")
|
||||
.run { e, result ->
|
||||
Handler(Looper.getMainLooper()).post {
|
||||
try {
|
||||
ChangelogDialog().show(supportFragmentManager, "whats_new")
|
||||
} catch (e2: Exception) {
|
||||
e2.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
ChangelogDialog(this)
|
||||
if (app.config.appVersion < 170) {
|
||||
//Intent intent = new Intent(this, ChangelogIntroActivity.class);
|
||||
//startActivity(intent);
|
||||
@ -560,7 +561,7 @@ class MainActivity : AppCompatActivity() {
|
||||
).enqueue(this)
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncStartedEvent(event: ApiTaskStartedEvent) {
|
||||
fun onApiTaskStartedEvent(event: ApiTaskStartedEvent) {
|
||||
swipeRefreshLayout.isRefreshing = true
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
@ -571,7 +572,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncProgressEvent(event: ApiTaskProgressEvent) {
|
||||
fun onApiTaskProgressEvent(event: ApiTaskProgressEvent) {
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = null
|
||||
@ -584,8 +585,8 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncProfileFinishedEvent(event: ApiTaskFinishedEvent) {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onApiTaskFinishedEvent(event: ApiTaskFinishedEvent) {
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = R.string.toolbar_subtitle
|
||||
@ -594,17 +595,18 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncFinishedEvent(event: ApiTaskAllFinishedEvent) {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onApiTaskAllFinishedEvent(event: ApiTaskAllFinishedEvent) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = R.string.toolbar_subtitle
|
||||
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
||||
subtitle = "Gotowe"
|
||||
}
|
||||
mainSnackbar.dismiss()
|
||||
errorSnackbar.addError(event.error).show()
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
@ -808,6 +810,10 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
AsyncTask.execute {
|
||||
app.profileLoadById(id)
|
||||
MessagesFragment.pageSelection = -1
|
||||
MessagesListFragment.tapPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
MessagesListFragment.topPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
MessagesListFragment.bottomPositions = intArrayOf(RecyclerView.NO_POSITION, RecyclerView.NO_POSITION)
|
||||
|
||||
this.runOnUiThread {
|
||||
if (app.profile == null) {
|
||||
@ -833,7 +839,7 @@ class MainActivity : AppCompatActivity() {
|
||||
loadId = DRAWER_ITEM_HOME
|
||||
}
|
||||
val target = navTargetList
|
||||
.singleOrNull { it.id == loadId }
|
||||
.firstOrNull { it.id == loadId }
|
||||
if (target == null) {
|
||||
Toast.makeText(this, getString(R.string.error_invalid_fragment, id), Toast.LENGTH_LONG).show()
|
||||
loadTarget(navTargetList.first(), arguments)
|
||||
@ -843,7 +849,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
private fun loadTarget(target: NavTarget, arguments: Bundle? = null) {
|
||||
d("NavDebug", "loadItem(id = ${target.id})")
|
||||
d("NavDebug", "loadTarget(target = $target, arguments = $arguments)")
|
||||
|
||||
bottomSheet.close()
|
||||
bottomSheet.removeAllContextual()
|
||||
@ -870,7 +876,7 @@ class MainActivity : AppCompatActivity() {
|
||||
)
|
||||
}
|
||||
else {
|
||||
navBackStack.lastIndexOf(target).let {
|
||||
navBackStack.keys().lastIndexOf(target).let {
|
||||
if (it == -1)
|
||||
return@let target
|
||||
// pop the back stack up until that target
|
||||
@ -901,8 +907,9 @@ class MainActivity : AppCompatActivity() {
|
||||
R.anim.task_open_enter,
|
||||
R.anim.task_open_exit
|
||||
)
|
||||
navBackStack.add(navTarget)
|
||||
navBackStack.add(navTarget to arguments)
|
||||
navTarget = target
|
||||
navArguments = arguments
|
||||
}
|
||||
}
|
||||
|
||||
@ -917,7 +924,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
d("NavDebug", "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:")
|
||||
navBackStack.forEachIndexed { index, target2 ->
|
||||
d("NavDebug", " - $index: ${target2.fragmentClass?.java?.simpleName}")
|
||||
d("NavDebug", " - $index: ${target2.first.fragmentClass?.java?.simpleName}")
|
||||
}
|
||||
|
||||
transaction.replace(R.id.fragment, fragment)
|
||||
@ -942,11 +949,18 @@ class MainActivity : AppCompatActivity() {
|
||||
return false
|
||||
}
|
||||
// TODO back stack argument support
|
||||
if (navTarget.popToHome) {
|
||||
loadTarget(HOME_ID)
|
||||
}
|
||||
else {
|
||||
loadTarget(navBackStack.last())
|
||||
when {
|
||||
navTarget.popToHome -> {
|
||||
loadTarget(HOME_ID)
|
||||
}
|
||||
navTarget.popTo != null -> {
|
||||
loadTarget(navTarget.popTo ?: HOME_ID)
|
||||
}
|
||||
else -> {
|
||||
navBackStack.last().let {
|
||||
loadTarget(it.first, it.second)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
@ -961,6 +975,8 @@ class MainActivity : AppCompatActivity() {
|
||||
* that something has changed in the bottom sheet.
|
||||
*/
|
||||
fun gainAttention() {
|
||||
if (app.config.ui.bottomSheetOpened || true)
|
||||
return
|
||||
b.navView.postDelayed({
|
||||
navView.gainAttentionOnBottomBar()
|
||||
}, 2000)
|
||||
@ -1084,4 +1100,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun snackbar(text: String, actionText: String? = null, onClick: (() -> Unit)? = null) = mainSnackbar.snackbar(text, actionText, onClick)
|
||||
fun snackbarDismiss() = mainSnackbar.dismiss()
|
||||
}
|
||||
|
@ -43,6 +43,8 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
super.onReceive(context, intent)
|
||||
}
|
||||
|
||||
private val ignoreCancelled = true
|
||||
|
||||
override fun onUpdate(context: Context, appWidgetManager: AppWidgetManager, appWidgetIds: IntArray) {
|
||||
val thisWidget = ComponentName(context, WidgetTimetable::class.java)
|
||||
|
||||
@ -122,7 +124,7 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
val method = declaredMethods[m]
|
||||
if (method.name == "setDrawableParameters") {
|
||||
method.isAccessible = true
|
||||
method.invoke(views, R.id.widgetTimetableListView, true, -1, colorFilter.toInt(), mode, -1)
|
||||
method.invoke(views, R.id.widgetTimetableBackground, true, -1, colorFilter.toInt(), mode, -1)
|
||||
method.invoke(views, R.id.widgetTimetableHeader, true, -1, colorFilter.toInt(), mode, -1)
|
||||
break
|
||||
}
|
||||
@ -185,12 +187,30 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
// search for lessons to display
|
||||
val timetableDate = Date.getToday()
|
||||
var checkedDays = 0
|
||||
var lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||
var lessons = lessonList.filter {
|
||||
it.profileId == profile.id
|
||||
&& it.displayDate == timetableDate
|
||||
&& it.displayEndTime > now
|
||||
&& !(it.isCancelled && ignoreCancelled)
|
||||
}
|
||||
while ((lessons.isEmpty() || lessons.none {
|
||||
it.displayDate != today || (it.displayDate == today && it.displayEndTime != null && it.displayEndTime!! >= now)
|
||||
it.type != Lesson.TYPE_NO_LESSONS
|
||||
&& (it.displayDate != today
|
||||
|| (it.displayDate == today
|
||||
&& it.displayEndTime != null
|
||||
&& it.displayEndTime!! >= now))
|
||||
}) && checkedDays < 7) {
|
||||
|
||||
timetableDate.stepForward(0, 0, 1)
|
||||
lessons = lessonList.filter { it.profileId == profile.id && it.displayDate == timetableDate && it.type != Lesson.TYPE_NO_LESSONS }
|
||||
lessons = lessonList.filter {
|
||||
it.profileId == profile.id
|
||||
&& it.displayDate == timetableDate
|
||||
&& !(it.isCancelled && ignoreCancelled)
|
||||
}
|
||||
|
||||
if (lessons.isEmpty() && timetableDate.weekDay <= 5)
|
||||
break
|
||||
|
||||
checkedDays++
|
||||
}
|
||||
|
||||
@ -199,6 +219,32 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
if (lessons.isNotEmpty())
|
||||
displayingDate = timetableDate
|
||||
profileId = profile.id
|
||||
if (lessons.isEmpty()) {
|
||||
views.setViewVisibility(R.id.widgetTimetableListView, View.GONE)
|
||||
views.setViewVisibility(R.id.widgetTimetableNoTimetable, View.VISIBLE)
|
||||
}
|
||||
if (lessons.size == 1 && lessons[0].type == Lesson.TYPE_NO_LESSONS) {
|
||||
views.setViewVisibility(R.id.widgetTimetableListView, View.GONE)
|
||||
views.setViewVisibility(R.id.widgetTimetableNoLessons, View.VISIBLE)
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (lessons.isEmpty()) {
|
||||
val separator = ItemWidgetTimetableModel()
|
||||
separator.profileId = profile.id
|
||||
separator.bigStyle = widgetConfig.bigStyle
|
||||
separator.darkTheme = widgetConfig.darkTheme
|
||||
separator.isNoTimetableItem = true;
|
||||
models.add(separator)
|
||||
}
|
||||
if (lessons.size == 1 && lessons[0].type == Lesson.TYPE_NO_LESSONS) {
|
||||
val separator = ItemWidgetTimetableModel()
|
||||
separator.profileId = profile.id
|
||||
separator.bigStyle = widgetConfig.bigStyle
|
||||
separator.darkTheme = widgetConfig.darkTheme
|
||||
separator.isNoLessonsItem = true;
|
||||
models.add(separator)
|
||||
}
|
||||
}
|
||||
|
||||
// get all events for the current date
|
||||
@ -298,13 +344,6 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
val pendingOpenIntent = PendingIntent.getActivity(app, appWidgetId, openIntent, 0)
|
||||
views.setOnClickPendingIntent(R.id.widgetTimetableHeader, pendingOpenIntent)
|
||||
|
||||
if (lessonList.isEmpty()) {
|
||||
views.setViewVisibility(R.id.widgetTimetableLoading, View.VISIBLE)
|
||||
views.setRemoteAdapter(R.id.widgetTimetableListView, Intent())
|
||||
views.setTextViewText(R.id.widgetTimetableLoading, app.getString(R.string.widget_timetable_no_lessons))
|
||||
return
|
||||
}
|
||||
|
||||
timetables!!.put(appWidgetId, models)
|
||||
|
||||
// apply the list service to the list view
|
||||
@ -315,7 +354,7 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
|
||||
// create an intent used to display the lesson details dialog
|
||||
val intentTemplate = Intent(app, LessonDialogActivity::class.java)
|
||||
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
|
||||
intentTemplate.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK /*or Intent.FLAG_ACTIVITY_CLEAR_TASK*/)
|
||||
val pendingIntentTimetable = PendingIntent.getActivity(app, appWidgetId, intentTemplate, 0)
|
||||
views.setPendingIntentTemplate(R.id.widgetTimetableListView, pendingIntentTimetable)
|
||||
|
||||
@ -336,11 +375,8 @@ class WidgetTimetable : AppWidgetProvider() {
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
|
||||
val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
|
||||
private val TAG = "WidgetTimetable"
|
||||
private val modeInt = 0
|
||||
const val ACTION_SYNC_DATA = "ACTION_SYNC_DATA"
|
||||
private const val TAG = "WidgetTimetable"
|
||||
|
||||
var timetables: SparseArray<List<ItemWidgetTimetableModel>>? = null
|
||||
|
||||
|
@ -64,6 +64,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
get() { mAppRateSnackbarTime = mAppRateSnackbarTime ?: values.get("appRateSnackbarTime", 0L); return mAppRateSnackbarTime ?: 0L }
|
||||
set(value) { set("appRateSnackbarTime", value); mAppRateSnackbarTime = value }
|
||||
|
||||
private var mRunSync: Boolean? = null
|
||||
var runSync: Boolean
|
||||
get() { mRunSync = mRunSync ?: values.get("runSync", false); return mRunSync ?: false }
|
||||
set(value) { set("runSync", value); mRunSync = value }
|
||||
|
||||
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
|
||||
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
|
||||
init {
|
||||
@ -76,6 +81,9 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
|
||||
fun getFor(profileId: Int): ProfileConfig {
|
||||
return profileConfigs[profileId] ?: ProfileConfig(db, profileId, rawEntries)
|
||||
}
|
||||
fun forProfile(): ProfileConfig {
|
||||
return profileConfigs[App.profileId] ?: ProfileConfig(db, App.profileId, rawEntries)
|
||||
}
|
||||
|
||||
fun setProfile(profileId: Int) {
|
||||
}
|
||||
|
@ -59,4 +59,9 @@ class ConfigUI(private val config: Config) {
|
||||
var snowfall: Boolean
|
||||
get() { mSnowfall = mSnowfall ?: config.values.get("snowfall", false); return mSnowfall ?: false }
|
||||
set(value) { config.set("snowfall", value); mSnowfall = value }
|
||||
|
||||
private var mBottomSheetOpened: Boolean? = null
|
||||
var bottomSheetOpened: Boolean
|
||||
get() { mBottomSheetOpened = mBottomSheetOpened ?: config.values.get("bottomSheetOpened", false); return mBottomSheetOpened ?: false }
|
||||
set(value) { config.set("bottomSheetOpened", value); mBottomSheetOpened = value }
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ class ApiService : Service() {
|
||||
SzkolnyTask.sync(syncingProfiles),
|
||||
NotifyTask()
|
||||
)
|
||||
private val allTaskList = mutableListOf<IApiTask>()
|
||||
private val taskQueue = mutableListOf<IApiTask>()
|
||||
private val errorList = mutableListOf<ApiError>()
|
||||
|
||||
@ -73,7 +74,7 @@ class ApiService : Service() {
|
||||
override fun onCompleted() {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||
EventBus.getDefault().postSticky(ApiTaskFinishedEvent(taskProfileId))
|
||||
clearTask()
|
||||
|
||||
notification.setIdle().post()
|
||||
@ -84,7 +85,7 @@ class ApiService : Service() {
|
||||
lastEventTime = System.currentTimeMillis()
|
||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||
apiError.profileId = taskProfileId
|
||||
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
||||
EventBus.getDefault().postSticky(ApiTaskErrorEvent(apiError))
|
||||
errorList.add(apiError)
|
||||
apiError.throwable?.printStackTrace()
|
||||
if (apiError.isCritical) {
|
||||
@ -194,7 +195,7 @@ class ApiService : Service() {
|
||||
*/
|
||||
private fun stopIfTaskFrozen() {
|
||||
if (checkIfTaskFrozen()) {
|
||||
stopSelf()
|
||||
allCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
@ -213,7 +214,7 @@ class ApiService : Service() {
|
||||
}
|
||||
|
||||
private fun allCompleted() {
|
||||
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
||||
EventBus.getDefault().postSticky(ApiTaskAllFinishedEvent())
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
@ -228,6 +229,11 @@ class ApiService : Service() {
|
||||
EventBus.getDefault().removeStickyEvent(task)
|
||||
d(TAG, task.toString())
|
||||
|
||||
// fix for duplicated tasks, thank you EventBus
|
||||
if (task in allTaskList)
|
||||
return
|
||||
allTaskList += task
|
||||
|
||||
if (task is EdziennikTask) {
|
||||
when (task.request) {
|
||||
is EdziennikTask.SyncRequest -> app.db.profileDao().idsForSyncNow.forEach {
|
||||
@ -270,7 +276,7 @@ class ApiService : Service() {
|
||||
serviceClosed = true
|
||||
taskCancelled = true
|
||||
taskRunning?.cancel()
|
||||
stopSelf()
|
||||
allCompleted()
|
||||
}
|
||||
|
||||
/* _____ _ _ _
|
||||
|
@ -69,6 +69,10 @@ const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/po
|
||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
||||
const val IDZIENNIK_WEB_MESSAGES_LIST = "mod_komunikator/WS_wiadomosci.asmx/PobierzListeWiadomosci"
|
||||
const val IDZIENNIK_WEB_GET_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/PobierzWiadomosc"
|
||||
const val IDZIENNIK_WEB_GET_RECIPIENT_LIST = "mod_komunikator/WS_wiadomosci.asmx/pobierzListeOdbiorcowPanelRodzic"
|
||||
const val IDZIENNIK_WEB_SEND_MESSAGE = "mod_komunikator/WS_wiadomosci.asmx/WyslijWiadomosc"
|
||||
const val IDZIENNIK_WEB_GET_ATTACHMENT = "mod_komunikator/Download.ashx"
|
||||
|
||||
val IDZIENNIK_API_USER_AGENT = SYSTEM_USER_AGENT
|
||||
const val IDZIENNIK_API_URL = "https://iuczniowie.progman.pl/idziennik/api"
|
||||
@ -100,4 +104,7 @@ const val VULCAN_API_ENDPOINT_ATTENDANCE = "mobile-api/Uczen.v3.Uczen/Frekwencje
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_RECEIVED = "mobile-api/Uczen.v3.Uczen/WiadomosciOdebrane"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/WiadomosciWyslane"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_ADD = "mobile-api/Uczen.v3.Uczen/DodajWiadomosc"
|
||||
const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"
|
||||
|
||||
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
|
||||
|
@ -45,6 +45,10 @@ class DataNotifications(val data: Data) {
|
||||
return@run
|
||||
}
|
||||
|
||||
val today = Date.getToday()
|
||||
val todayValue = today.value
|
||||
profile.currentSemester = profile.dateToSemester(today)
|
||||
|
||||
for (lesson in app.db.timetableDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.getString(R.string.notification_lesson_change_format, lesson.getDisplayChangeType(app), if (lesson.displayDate == null) "" else lesson.displayDate!!.formattedString, lesson.changeSubjectName)
|
||||
data.notifications += Notification(
|
||||
@ -90,10 +94,6 @@ class DataNotifications(val data: Data) {
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
}
|
||||
|
||||
val today = Date.getToday()
|
||||
val todayValue = today.value
|
||||
profile.currentSemester = profile.dateToSemester(today)
|
||||
|
||||
for (grade in app.db.gradeDao().getNotNotifiedNow(profileId)) {
|
||||
val gradeName = when (grade.type) {
|
||||
TYPE_SEMESTER1_PROPOSED, TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name)
|
||||
|
@ -81,3 +81,32 @@ fun Data.prepare(loginMethods: List<LoginMethod>, features: List<Feature>, featu
|
||||
progressCount = targetLoginMethodIds.size + targetEndpointIds.size
|
||||
progressStep = if (progressCount <= 0) 0f else 100f / progressCount.toFloat()
|
||||
}
|
||||
|
||||
fun Data.prepareFor(loginMethods: List<LoginMethod>, loginMethodId: Int) {
|
||||
val possibleLoginMethods = this.loginMethods.toMutableList()
|
||||
|
||||
loginMethods.forEach {
|
||||
if (it.isPossible(profile, loginStore))
|
||||
possibleLoginMethods += it.loginMethodId
|
||||
}
|
||||
|
||||
targetEndpointIds.clear()
|
||||
targetLoginMethodIds.clear()
|
||||
|
||||
// check the login method for any dependencies
|
||||
var requiredLoginMethod: Int? = loginMethodId
|
||||
while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) {
|
||||
loginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let {
|
||||
if (requiredLoginMethod != null)
|
||||
targetLoginMethodIds.add(requiredLoginMethod!!)
|
||||
requiredLoginMethod = it.requiredLoginMethod(profile, loginStore)
|
||||
}
|
||||
}
|
||||
|
||||
// sort and distinct every login method
|
||||
targetLoginMethodIds = targetLoginMethodIds.toHashSet().toMutableList()
|
||||
targetLoginMethodIds.sort()
|
||||
|
||||
progressCount = 0
|
||||
progressStep = 0f
|
||||
}
|
||||
|
@ -31,6 +31,9 @@ const val CODE_SYNERGIA_NOT_ACTIVATED = 32
|
||||
const val CODE_LIBRUS_DISCONNECTED = 31
|
||||
const val CODE_PROFILE_ARCHIVED = 30*/
|
||||
|
||||
const val ERROR_APP_CRASH = 1
|
||||
const val ERROR_MESSAGE_NOT_SENT = 10
|
||||
|
||||
const val ERROR_REQUEST_FAILURE = 50
|
||||
const val ERROR_REQUEST_HTTP_400 = 51
|
||||
const val ERROR_REQUEST_HTTP_401 = 52
|
||||
@ -38,10 +41,13 @@ const val ERROR_REQUEST_HTTP_403 = 53
|
||||
const val ERROR_REQUEST_HTTP_404 = 54
|
||||
const val ERROR_REQUEST_HTTP_405 = 55
|
||||
const val ERROR_REQUEST_HTTP_410 = 56
|
||||
const val ERROR_REQUEST_HTTP_500 = 57
|
||||
const val ERROR_REQUEST_HTTP_424 = 57
|
||||
const val ERROR_REQUEST_HTTP_500 = 58
|
||||
const val ERROR_REQUEST_HTTP_503 = 59
|
||||
const val ERROR_REQUEST_FAILURE_HOSTNAME_NOT_FOUND = 60
|
||||
const val ERROR_REQUEST_FAILURE_TIMEOUT = 61
|
||||
const val ERROR_REQUEST_FAILURE_NO_INTERNET = 62
|
||||
const val ERROR_REQUEST_FAILURE_SSL_ERROR = 63
|
||||
const val ERROR_RESPONSE_EMPTY = 100
|
||||
const val ERROR_LOGIN_DATA_MISSING = 101
|
||||
const val ERROR_PROFILE_MISSING = 105
|
||||
@ -157,6 +163,15 @@ const val ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR = 440
|
||||
const val ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA = 441
|
||||
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_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN = 501
|
||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER = 510
|
||||
const val ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID = 511
|
||||
const val ERROR_EDUDZIENNIK_WEB_TIMETABLE_NOT_PUBLIC = 520
|
||||
const val ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS = 521
|
||||
const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522
|
||||
const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530
|
||||
|
||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||
|
||||
@ -175,5 +190,7 @@ 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_FILE_REQUEST = 921
|
||||
|
||||
const val LOGIN_NO_ARGUMENTS = 1201
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
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
|
||||
@ -130,6 +131,14 @@ val idziennikLoginMethods = listOf(
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_IDZIENNIK_WEB }
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_EDUDZIENNIK = 5
|
||||
const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100
|
||||
val edudziennikLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
|
||||
)
|
||||
|
||||
val templateLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
|
@ -4,76 +4,91 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api
|
||||
|
||||
import kotlin.text.RegexOption.DOT_MATCHES_ALL
|
||||
|
||||
object Regexes {
|
||||
val STYLE_CSS_COLOR by lazy {
|
||||
"""color: \w+?;?"?""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
||||
"""<div.*?>\n*\s*(.+?)\s*\n*(?:<.*?)??</div>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""<div.*?>\n*\s*(.+?)\s*\n*(?:<.*?)??</div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_COLOR by lazy {
|
||||
"""background-color:([#A-Fa-f0-9]+);""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""background-color:([#A-Fa-f0-9]+);""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_CATEGORY by lazy {
|
||||
"""> (.+?):</span>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""> (.+?):</span>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_CLASS_AVERAGE by lazy {
|
||||
"""Średnia ocen:.*<strong>([0-9]*\.?[0-9]*)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""Średnia ocen:.*<strong>([0-9]*\.?[0-9]*)</strong>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_ADDED_DATE by lazy {
|
||||
"""Wpisano:.*<strong>.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""Wpisano:.*<strong>.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)</strong>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_COUNT_TO_AVG by lazy {
|
||||
"""Liczona do średniej:.*?<strong>nie<br/?></strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""Liczona do średniej:.*?<strong>nie<br/?></strong>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_DETAILS by lazy {
|
||||
"""<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?(?:<small>\((.+?)\)</small>.*?)?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>.*?(?:Komentarz:.*?<strong>(.+?)</strong>)?</span>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?(?:<small>\((.+?)\)</small>.*?)?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>.*?(?:Komentarz:.*?<strong>(.+?)</strong>)?</span>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_EVENT_TYPE by lazy {
|
||||
"""\(([0-9A-ząęóżźńśłć]*?)\)$""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""\(([0-9A-ząęóżźńśłć]*?)\)$""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_LUCKY_NUMBER by lazy {
|
||||
"""class="szczesliwy_numerek".*>0*([0-9]+)(?:/0*[0-9]+)*</a>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""class="szczesliwy_numerek".*>0*([0-9]+)(?:/0*[0-9]+)*</a>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_CLASS_CALENDAR by lazy {
|
||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MESSAGE_READ_DATE by lazy {
|
||||
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""czas przeczytania:.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_SENT_READ_DATE by lazy {
|
||||
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
""".+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_MESSAGE_ATTACHMENT by lazy {
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""href="https://.+?\.mobidziennik.pl/.+?&(?:amp;)?zalacznik=([0-9]+)"(?:.+?<small.+?\(([0-9.]+)\s(M|K|G|)B\))*""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_MESSAGE_RECIPIENTS_JSON by lazy {
|
||||
"""odbiorcy: (\[.+?\]),${'$'}""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
|
||||
|
||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||
"""<input type="hidden".+?name="([A-z0-9_]+)?".+?value="([A-z0-9_+-/=]+)?".+?>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""<input type="hidden".+?name="([A-z0-9_]+)?".+?value="([A-z0-9_+-/=]+)?".+?>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_ERROR by lazy {
|
||||
"""id="spanErrorMessage">(.*?)</""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""id="spanErrorMessage">(.*?)</""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME by lazy {
|
||||
"""Imię i nazwisko:.+?">(.+?)</div>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""Imię i nazwisko:.+?">(.+?)</div>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_IS_PARENT by lazy {
|
||||
"""id="ctl00_CzyRodzic" value="([01])" />""".toRegex()
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR by lazy {
|
||||
"""name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9/]+)<""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9/]+)<""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT_SELECT by lazy {
|
||||
"""<select.*?name="ctl00\${"$"}dxComboUczniowie".*?</select>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""<select.*?name="ctl00\${"$"}dxComboUczniowie".*?</select>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_MESSAGES_RECIPIENT_PARENT by lazy {
|
||||
"""(.+?)\s\((.+)\)""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val VULCAN_SHITFT_ANNOTATION by lazy {
|
||||
val VULCAN_SHIFT_ANNOTATION by lazy {
|
||||
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
|
||||
}
|
||||
|
||||
@ -82,4 +97,75 @@ object Regexes {
|
||||
val LIBRUS_ATTACHMENT_KEY by lazy {
|
||||
"""singleUseKey=([0-9A-f_]+)""".toRegex()
|
||||
}
|
||||
|
||||
|
||||
|
||||
val EDUDZIENNIK_STUDENTS_START by lazy {
|
||||
"""<li><a href="/Students/([\w-_]+?)/start/">(.*?)</a>""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_ACCOUNT_NAME_START by lazy {
|
||||
"""<span id='user_dn'>(.*?)</span>""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_SUBJECTS_START by lazy {
|
||||
"""<a class="menu-course" href="/Students/[\w-_]+?/Courses/([\w-_]+)/">(.+?)</a>""".toRegex()
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_ATTENDANCE_ENTRIES by lazy {
|
||||
"""<td id="([\d-]+?):(\d+?)".*?>(.+?)</td>""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_ATTENDANCE_TYPES by lazy {
|
||||
"""<div class="info">.*?<p>(.*?)</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_ATTENDANCE_TYPE by lazy {
|
||||
"""\((.+?)\) (.+)""".toRegex()
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION by lazy {
|
||||
"""<div class="desc">.*?<p>(.*?)</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_SUBJECT_ID by lazy {
|
||||
"""/Courses/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_GRADE_ID by lazy {
|
||||
"""/Grades/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_EXAM_ID by lazy {
|
||||
"""/Evaluations/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_EVENT_TYPE_ID by lazy {
|
||||
"""/GradeLabels/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_ANNOUNCEMENT_ID by lazy {
|
||||
"""/Announcement/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_HOMEWORK_ID by lazy {
|
||||
"""/Homework/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_TEACHER_ID by lazy {
|
||||
"""/Teachers/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_EVENT_ID by lazy {
|
||||
"""/KlassEvent/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
val EDUDZIENNIK_NOTE_ID by lazy {
|
||||
"""/RegistryNotes/([\w-_]+?)/""".toRegex()
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_SCHOOL_DETAIL_ID by lazy {
|
||||
"""<a id="School_detail".*?/School/([\w-_]+?)/""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_SCHOOL_DETAIL_NAME by lazy {
|
||||
"""</li>.*?<p>(.*?)</p>.*?<li>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_CLASS_DETAIL_ID by lazy {
|
||||
"""<a id="Klass_detail".*?/Klass/([\w-_]+?)/""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
val EDUDZIENNIK_CLASS_DETAIL_NAME by lazy {
|
||||
"""<a id="Klass_detail".*?>(.*?)</a>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val EDUDZIENNIK_TEACHERS by lazy {
|
||||
"""<div class="teacher">.*?<p>(.+?) (.+?)</p>""".toRegex(DOT_MATCHES_ALL)
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
/**
|
||||
* Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
|
||||
*
|
||||
* Use https://codepen.io/kubasz/pen/RwwwbGN to easily generate the student data getters/setters
|
||||
*/
|
||||
class DataEdudziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
fun isWebLoginValid() = webSessionIdExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty()
|
||||
|
||||
override fun satisfyLoginMethods() {
|
||||
loginMethods.clear()
|
||||
if (isWebLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
}
|
||||
}
|
||||
|
||||
private var mLoginEmail: String? = null
|
||||
var loginEmail: String?
|
||||
get() { mLoginEmail = mLoginEmail ?: loginStore.getLoginData("email", null); return mLoginEmail }
|
||||
set(value) { loginStore.putLoginData("email", value); mLoginEmail = value }
|
||||
|
||||
private var mLoginPassword: String? = null
|
||||
var loginPassword: String?
|
||||
get() { mLoginPassword = mLoginPassword ?: loginStore.getLoginData("password", null); return mLoginPassword }
|
||||
set(value) { loginStore.putLoginData("password", value); mLoginPassword = value }
|
||||
|
||||
private var mStudentId: String? = null
|
||||
var studentId: String?
|
||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
||||
|
||||
private var mSchoolId: String? = null
|
||||
var schoolId: String?
|
||||
get() { mSchoolId = mSchoolId ?: profile?.getStudentData("schoolId", null); return mSchoolId }
|
||||
set(value) { profile?.putStudentData("schoolId", value) ?: return; mSchoolId = value }
|
||||
|
||||
private var mClassId: String? = null
|
||||
var classId: String?
|
||||
get() { mClassId = mClassId ?: profile?.getStudentData("classId", null); return mClassId }
|
||||
set(value) { profile?.putStudentData("classId", value) ?: return; mClassId = value }
|
||||
|
||||
/* __ __ _
|
||||
\ \ / / | |
|
||||
\ \ /\ / /__| |__
|
||||
\ \/ \/ / _ \ '_ \
|
||||
\ /\ / __/ |_) |
|
||||
\/ \/ \___|_._*/
|
||||
private var mWebSessionId: String? = null
|
||||
var webSessionId: String?
|
||||
get() { mWebSessionId = mWebSessionId ?: loginStore.getLoginData("webSessionId", null); return mWebSessionId }
|
||||
set(value) { loginStore.putLoginData("webSessionId", value); mWebSessionId = value }
|
||||
|
||||
private var mWebSessionIdExpiryTime: Long? = null
|
||||
var webSessionIdExpiryTime: Long
|
||||
get() { mWebSessionIdExpiryTime = mWebSessionIdExpiryTime ?: loginStore.getLoginData("webSessionIdExpiryTime", 0L); return mWebSessionIdExpiryTime ?: 0L }
|
||||
set(value) { loginStore.putLoginData("webSessionIdExpiryTime", value); mWebSessionIdExpiryTime = value }
|
||||
|
||||
/* ____ _ _
|
||||
/ __ \| | | |
|
||||
| | | | |_| |__ ___ _ __
|
||||
| | | | __| '_ \ / _ \ '__|
|
||||
| |__| | |_| | | | __/ |
|
||||
\____/ \__|_| |_|\___|*/
|
||||
private var 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 mTimetableNotPublic: Boolean? = null
|
||||
var timetableNotPublic: Boolean
|
||||
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
|
||||
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
|
||||
|
||||
val studentEndpoint: String
|
||||
get() = "Students/$studentId/"
|
||||
|
||||
val schoolEndpoint: String
|
||||
get() = "Schools/$schoolId/"
|
||||
|
||||
val classStudentEndpoint: String
|
||||
get() = "Class/$studentId/"
|
||||
|
||||
val schoolClassEndpoint: String
|
||||
get() = "Schools/$classId/"
|
||||
|
||||
val studentAndClassEndpoint: String
|
||||
get() = "Students/$studentId/Klass/$classId/"
|
||||
|
||||
val studentAndClassesEndpoint: String
|
||||
get() = "Students/$studentId/Classes/$classId/"
|
||||
|
||||
val timetableEndpoint: String
|
||||
get() = "Plan/$studentId/"
|
||||
|
||||
val studentAndTeacherClassEndpoint: String
|
||||
get() = "Students/$studentId/Teachers/$classId/"
|
||||
|
||||
val courseStudentEndpoint: String
|
||||
get() = "Course/$studentId/"
|
||||
|
||||
fun getSubject(longId: String, name: String): Subject {
|
||||
val id = longId.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, longId: String? = null): Teacher {
|
||||
val name = "$firstName $lastName".fixName()
|
||||
val id = name.crc32()
|
||||
return teacherList.singleOrNull { it.id == id }?.also {
|
||||
if (longId != null && it.loginId == null) it.loginId = longId
|
||||
} ?: run {
|
||||
val teacher = Teacher(profileId, id, firstName, lastName, longId)
|
||||
teacherList.put(id, teacher)
|
||||
teacher
|
||||
}
|
||||
}
|
||||
|
||||
fun getTeacherByFirstLast(nameFirstLast: String, longId: String? = null): Teacher {
|
||||
val nameParts = nameFirstLast.split(" ")
|
||||
return getTeacher(nameParts[0], nameParts[1], longId)
|
||||
}
|
||||
|
||||
fun getTeacherByLastFirst(nameLastFirst: String, longId: String? = null): Teacher {
|
||||
val nameParts = nameLastFirst.split(" ")
|
||||
return getTeacher(nameParts[1], nameParts[0], longId)
|
||||
}
|
||||
|
||||
fun getEventType(longId: String, name: String): EventType {
|
||||
val id = longId.crc16().toLong()
|
||||
return eventTypes.singleOrNull { it.id == id } ?: run {
|
||||
val eventType = EventType(profileId, id, name, colorFromName(name))
|
||||
eventTypes.put(id, eventType)
|
||||
eventType
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetAnnouncement
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin.EdudziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
companion object {
|
||||
private const val TAG = "Edudziennik"
|
||||
}
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataEdudziennik
|
||||
private var afterLogin: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
data = DataEdudziennik(app, profile, loginStore).apply {
|
||||
callback = wrapCallback(this@Edudziennik.callback)
|
||||
satisfyLoginMethods()
|
||||
}
|
||||
}
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notify {
|
||||
callback.onCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|__ __| | /\ | | (_) | | |
|
||||
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
|
||||
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
|
||||
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(edudziennikLoginMethods, EdudziennikFeatures, featureIds, viewId)
|
||||
login()
|
||||
}
|
||||
|
||||
private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
|
||||
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
|
||||
if (internalErrorList.isNotEmpty()) {
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
}
|
||||
loginMethodId?.let { data.prepareFor(edudziennikLoginMethods, it) }
|
||||
afterLogin?.let { this.afterLogin = it }
|
||||
EdudziennikLogin(data) {
|
||||
data()
|
||||
}
|
||||
}
|
||||
|
||||
private fun data() {
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
if (internalErrorList.isNotEmpty()) {
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
}
|
||||
afterLogin?.invoke() ?: EdudziennikData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {}
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {}
|
||||
override fun markAllAnnouncementsAsRead() {}
|
||||
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
||||
EdudziennikLoginWeb(data) {
|
||||
EdudziennikWebGetAnnouncement(data, announcement) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {}
|
||||
override fun getRecipientList() {}
|
||||
|
||||
override fun firstLogin() { EdudziennikFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
return object : EdziennikCallback {
|
||||
override fun onCompleted() { callback.onCompleted() }
|
||||
override fun onProgress(step: Float) { callback.onProgress(step) }
|
||||
override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
|
||||
override fun onError(apiError: ApiError) {
|
||||
if (apiError.errorCode in internalErrorList) {
|
||||
// finish immediately if the same error occurs twice during the same sync
|
||||
callback.onError(apiError)
|
||||
return
|
||||
}
|
||||
internalErrorList.add(apiError.errorCode)
|
||||
when (apiError.errorCode) {
|
||||
ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED -> {
|
||||
login()
|
||||
}
|
||||
ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID -> {
|
||||
login()
|
||||
}
|
||||
ERROR_EDUDZIENNIK_WEB_TIMETABLE_NOT_PUBLIC -> {
|
||||
data.timetableNotPublic = true
|
||||
data()
|
||||
}
|
||||
else -> callback.onError(apiError)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Feature
|
||||
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_START = 1000
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_TEACHERS = 1001
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_GRADES = 1011
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE = 1012
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_EXAMS = 1013
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE = 1014
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS = 1015
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK = 1016
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_EVENTS = 1017
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_NOTES = 1018
|
||||
const val ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER = 1030
|
||||
|
||||
val EdudziennikFeatures = listOf(
|
||||
/* School and team info and subjects */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_START to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Teachers */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TEACHERS, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Timetable */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TIMETABLE, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Grades */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Agenda */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_AGENDA, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS to LOGIN_METHOD_EDUDZIENNIK_WEB,
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB,
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Homework */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Behaviour */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Attendance */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ATTENDANCE, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Announcements */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
|
||||
|
||||
/* Lucky number */
|
||||
Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER to LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB))
|
||||
)
|
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class EdudziennikData(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikData"
|
||||
}
|
||||
|
||||
init {
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||
if (data.targetEndpointIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (data.cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useEndpoint(data.targetEndpointIds.removeAt(0)) {
|
||||
data.progress(data.progressStep)
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId")
|
||||
when (endpointId) {
|
||||
ENDPOINT_EDUDZIENNIK_WEB_START -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_data)
|
||||
EdudziennikWebStart(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TEACHERS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||
EdudziennikWebTeachers(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
EdudziennikWebGrades(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
EdudziennikWebTimetable(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EXAMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||
EdudziennikWebExams(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
EdudziennikWebAttendance(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
EdudziennikWebAnnouncements(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
EdudziennikWebHomework(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_EVENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||
EdudziennikWebEvents(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_NOTES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
EdudziennikWebNotes(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
EdudziennikWebLuckyNumber(data, onSuccess)
|
||||
}
|
||||
else -> onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
open class EdudziennikWeb(open val data: DataEdudziennik) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWeb"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun webGet(tag: String, endpoint: String, xhr: Boolean = false, onSuccess: (text: String) -> Unit) {
|
||||
val url = "https://dziennikel.appspot.com/" + when (endpoint.endsWith('/') || endpoint.contains('?') || endpoint.isEmpty()) {
|
||||
true -> endpoint
|
||||
else -> "$endpoint/"
|
||||
}
|
||||
|
||||
d(tag, "Request: Edudziennik/Web - $url")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text == null || response == null) {
|
||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(text)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_WEB_REQUEST)
|
||||
.withThrowable(e)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
val error = when (response?.code()) {
|
||||
402 -> ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS
|
||||
403 -> ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED
|
||||
else -> ERROR_REQUEST_FAILURE
|
||||
}
|
||||
data.error(ApiError(tag, error)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("sessionid")
|
||||
.value(data.webSessionId!!)
|
||||
.domain("dziennikel.appspot.com")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name("semester")
|
||||
.value((profile?.currentSemester ?: 1).toString())
|
||||
.domain("dziennikel.appspot.com")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(EDUDZIENNIK_USER_AGENT)
|
||||
.apply {
|
||||
if (xhr) header("X-Requested-With", "XMLHttpRequest")
|
||||
}
|
||||
.get()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-26
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ANNOUNCEMENT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.splitName
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebAnnouncements"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.schoolClassEndpoint + "Announcements") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
if (doc.getElementsByClass("message").text().trim() != "Brak ogłoszeń.") {
|
||||
doc.select("table.list tbody tr").forEach { announcementElement ->
|
||||
val titleElement = announcementElement.child(0).child(0)
|
||||
|
||||
val longId = EDUDZIENNIK_ANNOUNCEMENT_ID.find(titleElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val id = longId.crc32()
|
||||
val subject = titleElement.text()
|
||||
|
||||
val teacherName = announcementElement.child(1).text()
|
||||
val teacher = teacherName.splitName()?.let { (teacherFirstName, teacherLastName) ->
|
||||
data.getTeacher(teacherFirstName, teacherLastName)
|
||||
} ?: return@forEach
|
||||
|
||||
val dateString = announcementElement.getElementsByClass("datetime").first().text()
|
||||
val startDate = Date.fromY_m_d(dateString)
|
||||
val addedDate = Date.fromIsoHm(dateString)
|
||||
|
||||
val announcementObject = Announcement(
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
null,
|
||||
startDate,
|
||||
null,
|
||||
teacher.id,
|
||||
longId
|
||||
)
|
||||
|
||||
data.announcementIgnoreList.add(announcementObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_ENTRIES
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPE
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import java.util.*
|
||||
|
||||
class EdudziennikWebAttendance(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebAttendance"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentEndpoint + "Presence") { text ->
|
||||
|
||||
val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map {
|
||||
val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim())
|
||||
val symbol = type?.get(1)?.trim()
|
||||
val name = type?.get(2)?.trim()
|
||||
return@map Triple(
|
||||
symbol,
|
||||
name,
|
||||
when (name?.toLowerCase(Locale.ROOT)) {
|
||||
"obecność" -> Attendance.TYPE_PRESENT
|
||||
"nieobecność" -> Attendance.TYPE_ABSENT
|
||||
"spóźnienie" -> Attendance.TYPE_BELATED
|
||||
"nieobecność usprawiedliwiona" -> Attendance.TYPE_ABSENT_EXCUSED
|
||||
"dzień wolny" -> Attendance.TYPE_DAY_FREE
|
||||
"brak zajęć" -> Attendance.TYPE_DAY_FREE
|
||||
"oddelegowany" -> Attendance.TYPE_RELEASED
|
||||
else -> Attendance.TYPE_CUSTOM
|
||||
}
|
||||
)
|
||||
} ?: emptyList()
|
||||
|
||||
EDUDZIENNIK_ATTENDANCE_ENTRIES.findAll(text).forEach { attendanceElement ->
|
||||
val date = Date.fromY_m_d(attendanceElement[1])
|
||||
val lessonNumber = attendanceElement[2].toInt()
|
||||
val attendanceSymbol = attendanceElement[3]
|
||||
|
||||
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date)
|
||||
val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber }
|
||||
|
||||
val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32()
|
||||
|
||||
val (_, name, type) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol }
|
||||
?: return@forEach
|
||||
|
||||
val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime
|
||||
?: return@forEach
|
||||
|
||||
val attendanceObject = Attendance(
|
||||
profileId,
|
||||
id,
|
||||
lesson?.displayTeacherId ?: -1,
|
||||
lesson?.displaySubjectId ?: -1,
|
||||
profile.currentSemester,
|
||||
name,
|
||||
date,
|
||||
lesson?.displayStartTime ?: startTime,
|
||||
type
|
||||
)
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-1
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EVENTS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebEvents(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebEvents"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentAndClassesEndpoint + "KlassEvent", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.getElementsByTag("tr").forEach { eventElement ->
|
||||
val date = Date.fromY_m_d(eventElement.child(1).text())
|
||||
|
||||
val titleElement = eventElement.child(2).child(0)
|
||||
val title = titleElement.text().trim()
|
||||
|
||||
val id = EDUDZIENNIK_EVENT_ID.find(titleElement.attr("href"))?.get(1)?.crc32()
|
||||
?: return@forEach
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
null,
|
||||
title,
|
||||
-1,
|
||||
Event.TYPE_CLASS_EVENT,
|
||||
false,
|
||||
-1,
|
||||
-1,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_CLASS_EVENT))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EVENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_TYPE_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EXAM_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebExams(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebExams"
|
||||
}
|
||||
|
||||
init { profile?.also { profile ->
|
||||
webGet(TAG, data.studentAndClassEndpoint + "Evaluations", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.select("tr").forEach { examElement ->
|
||||
val id = EDUDZIENNIK_EXAM_ID.find(examElement.child(0).child(0).attr("href"))
|
||||
?.get(1)?.crc32() ?: return@forEach
|
||||
val topic = examElement.child(0).text().trim()
|
||||
|
||||
val subjectElement = examElement.child(1).child(0)
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val subjectName = subjectElement.text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
val dateString = examElement.child(2).text().trim()
|
||||
if (dateString.isBlank()) return@forEach
|
||||
val date = Date.fromY_m_d(dateString)
|
||||
|
||||
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date)
|
||||
val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime
|
||||
|
||||
val eventTypeElement = examElement.child(3).child(0)
|
||||
val eventTypeId = EDUDZIENNIK_EVENT_TYPE_ID.find(eventTypeElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val eventTypeName = eventTypeElement.text()
|
||||
val eventType = data.getEventType(eventTypeId, eventTypeName)
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
eventType.id.toInt(),
|
||||
false,
|
||||
-1,
|
||||
subject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptTypes(listOf(
|
||||
Event.TYPE_HOMEWORK,
|
||||
Event.TYPE_CLASS_EVENT
|
||||
)))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-26
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebGetAnnouncement(
|
||||
override val data: DataEdudziennik,
|
||||
private val announcement: AnnouncementFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebGetAnnouncement"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, "Announcement/${announcement.idString}") { text ->
|
||||
val description = Regexes.EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION.find(text)?.get(1)?.trim() ?: ""
|
||||
|
||||
announcement.text = description
|
||||
|
||||
EventBus.getDefault().postSticky(AnnouncementGetEvent(announcement))
|
||||
|
||||
data.announcementList.add(announcement)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-25
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import android.graphics.Color
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.colorFromCssName
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebGrades(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebGrades"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.studentEndpoint + "start") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
val subjects = doc.select("#student_grades tbody").firstOrNull()?.children()
|
||||
|
||||
subjects?.forEach { subjectElement ->
|
||||
if (subjectElement.id().isBlank()) return@forEach
|
||||
|
||||
val subjectId = subjectElement.id().trim()
|
||||
val subjectName = subjectElement.child(0).text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
val gradeType = when {
|
||||
subjectElement.select("#sum").text().isNotBlank() -> TYPE_POINT_SUM
|
||||
else -> TYPE_NORMAL
|
||||
}
|
||||
|
||||
val gradeCountToAverage = subjectElement.select("#avg").text().isNotBlank()
|
||||
|
||||
val grades = subjectElement.select(".grade[data-edited]")
|
||||
val gradesInfo = subjectElement.select(".grade-tip")
|
||||
|
||||
val gradeValues = if (grades.isNotEmpty()) {
|
||||
subjects.select(".avg-$subjectId .grade-tip > p").first()
|
||||
.text().split('+').map {
|
||||
val split = it.split('*')
|
||||
val weight = split[0].trim().toFloat()
|
||||
val value = split[1].trim().toFloat()
|
||||
|
||||
Pair(value, weight)
|
||||
}
|
||||
} else emptyList()
|
||||
|
||||
grades.forEachIndexed { index, gradeElement ->
|
||||
val id = Regexes.EDUDZIENNIK_GRADE_ID.find(gradeElement.attr("href"))?.get(1)?.crc32()
|
||||
?: return@forEachIndexed
|
||||
val (value, weight) = gradeValues[index]
|
||||
val name = gradeElement.text().trim().let {
|
||||
if (it.contains(',') || it.contains('.')) {
|
||||
val replaced = it.replace(',', '.')
|
||||
val float = replaced.toFloatOrNull()
|
||||
|
||||
if (float != null && float % 1 == 0f) float.toInt().toString()
|
||||
else it
|
||||
} else it
|
||||
}
|
||||
|
||||
val info = gradesInfo[index]
|
||||
val fullName = info.child(0).text().trim()
|
||||
val columnName = info.child(4).text().trim()
|
||||
val comment = info.ownText()
|
||||
|
||||
val description = columnName + if (comment.isNotBlank()) " - $comment" else ""
|
||||
|
||||
val (teacherLastName, teacherFirstName) = info.child(1).text().split(' ')
|
||||
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
|
||||
|
||||
val addedDate = info.child(2).text().split(' ').let {
|
||||
val day = it[0].toInt()
|
||||
val month = Utils.monthFromName(it[1])
|
||||
val year = it[2].toInt()
|
||||
|
||||
Date(year, month, day).inMillis
|
||||
}
|
||||
|
||||
val color = Regexes.STYLE_CSS_COLOR.find(gradeElement.attr("style"))?.get(1)?.let {
|
||||
if (it.startsWith('#')) Color.parseColor(it)
|
||||
else colorFromCssName(it)
|
||||
} ?: -1
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
fullName,
|
||||
color,
|
||||
description,
|
||||
name,
|
||||
value,
|
||||
if (gradeCountToAverage) weight else 0f,
|
||||
profile.currentSemester,
|
||||
teacher.id,
|
||||
subject.id
|
||||
).apply {
|
||||
type = gradeType
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
val proposed = subjectElement.select(".proposal").firstOrNull()?.text()?.trim()
|
||||
|
||||
if (proposed != null && proposed.isNotBlank()) {
|
||||
val proposedGradeObject = Grade(
|
||||
profileId,
|
||||
(-1 * subject.id) - 1,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
proposed,
|
||||
proposed.toFloatOrNull() ?: 0f,
|
||||
0f,
|
||||
profile.currentSemester,
|
||||
-1,
|
||||
subject.id
|
||||
).apply {
|
||||
type = when (semester) {
|
||||
1 -> TYPE_SEMESTER1_PROPOSED
|
||||
else -> TYPE_SEMESTER2_PROPOSED
|
||||
}
|
||||
}
|
||||
|
||||
data.gradeList.add(proposedGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
proposedGradeObject.id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
val final = subjectElement.select(".final").firstOrNull()?.text()?.trim()
|
||||
|
||||
if (final != null && final.isNotBlank()) {
|
||||
val finalGradeObject = Grade(
|
||||
profileId,
|
||||
(-1 * subject.id) - 2,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
final,
|
||||
final.toFloatOrNull() ?: 0f,
|
||||
0f,
|
||||
profile.currentSemester,
|
||||
-1,
|
||||
subject.id
|
||||
).apply {
|
||||
type = when (semester) {
|
||||
1 -> TYPE_SEMESTER1_FINAL
|
||||
else -> TYPE_SEMESTER2_FINAL
|
||||
}
|
||||
}
|
||||
|
||||
data.gradeList.add(finalGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
data.profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
finalGradeObject.id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
if (!subjects.isNullOrEmpty()) {
|
||||
data.toRemove.addAll(listOf(
|
||||
TYPE_NORMAL,
|
||||
TYPE_POINT_SUM,
|
||||
TYPE_SEMESTER1_PROPOSED,
|
||||
TYPE_SEMESTER2_PROPOSED,
|
||||
TYPE_SEMESTER1_FINAL,
|
||||
TYPE_SEMESTER2_FINAL
|
||||
).map {
|
||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
||||
})
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}}
|
||||
}
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_HOMEWORK_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.splitName
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebHomework(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebHomework"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.courseStudentEndpoint + "Homework", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
if (doc.getElementsByClass("message").text().trim() != "Brak prac domowych") {
|
||||
doc.getElementsByTag("tr").forEach { homeworkElement ->
|
||||
val dateElement = homeworkElement.getElementsByClass("date").first().child(0)
|
||||
val id = EDUDZIENNIK_HOMEWORK_ID.find(dateElement.attr("href"))?.get(1)?.crc32()
|
||||
?: return@forEach
|
||||
val date = Date.fromY_m_d(dateElement.text())
|
||||
|
||||
val subjectElement = homeworkElement.child(1).child(0)
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEach
|
||||
val subjectName = subjectElement.text()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date)
|
||||
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
|
||||
|
||||
val teacherName = homeworkElement.child(2).text()
|
||||
val teacher = teacherName.splitName()?.let { (teacherFirstName, teacherLastName) ->
|
||||
data.getTeacher(teacherFirstName, teacherLastName)
|
||||
} ?: return@forEach
|
||||
|
||||
val topic = homeworkElement.child(4).text()
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
date,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacher.id,
|
||||
subject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebLuckyNumber"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text ->
|
||||
text.toIntOrNull()?.also { luckyNumber ->
|
||||
val luckyNumberObject = LuckyNumber(
|
||||
profileId,
|
||||
Date.getToday(),
|
||||
luckyNumber
|
||||
)
|
||||
|
||||
data.luckyNumberList.add(luckyNumberObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LUCKY_NUMBER,
|
||||
luckyNumberObject.date.value.toLong(),
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2020-1-1
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_NOTE_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_NOTES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class EdudziennikWebNotes(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "EdudziennikWebNotes"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
webGet(TAG, data.classStudentEndpoint + "RegistryNotesStudent", xhr = true) { text ->
|
||||
val doc = Jsoup.parseBodyFragment("<table>" + text.trim() + "</table>")
|
||||
|
||||
doc.getElementsByTag("tr").forEach { noteElement ->
|
||||
val dateElement = noteElement.getElementsByClass("date").first().child(0)
|
||||
val addedDate = Date.fromY_m_d(dateElement.text()).inMillis
|
||||
|
||||
val id = EDUDZIENNIK_NOTE_ID.find(dateElement.attr("href"))?.get(0)?.crc32()
|
||||
?: return@forEach
|
||||
|
||||
val teacherName = noteElement.child(1).text()
|
||||
val teacher = data.getTeacherByFirstLast(teacherName)
|
||||
|
||||
val description = noteElement.child(3).text()
|
||||
|
||||
val noticeObject = Notice(
|
||||
profileId,
|
||||
id,
|
||||
description,
|
||||
profile.currentSemester,
|
||||
Notice.TYPE_NEUTRAL,
|
||||
teacher.id
|
||||
)
|
||||
|
||||
data.noticeList.add(noticeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_NOTICE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_NOTES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.crc32
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_EDUDZIENNIK_WEB_TEAM_MISSING
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECTS_START
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_START
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.firstLettersName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebStart(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebStart"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, data.studentEndpoint + "start") { text ->
|
||||
getSchoolAndTeam(text)
|
||||
getSubjects(text)
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_START, MONTH)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSchoolAndTeam(text: String) {
|
||||
val schoolId = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_ID.find(text)?.get(1)?.trim()
|
||||
val schoolLongName = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_NAME.find(text)?.get(1)?.trim()
|
||||
data.schoolId = schoolId
|
||||
|
||||
val classId = Regexes.EDUDZIENNIK_CLASS_DETAIL_ID.find(text)?.get(1)?.trim()
|
||||
val className = Regexes.EDUDZIENNIK_CLASS_DETAIL_NAME.find(text)?.get(1)?.trim()
|
||||
data.classId = classId
|
||||
|
||||
if (classId == null || className == null || schoolId == null || schoolLongName == null) {
|
||||
data.error(ApiError(TAG, ERROR_EDUDZIENNIK_WEB_TEAM_MISSING)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
|
||||
val schoolName = schoolId.crc32().toString() + schoolLongName.firstLettersName + "_edu"
|
||||
data.schoolName = schoolName
|
||||
|
||||
val teamId = classId.crc32()
|
||||
val teamCode = "$schoolName:$className"
|
||||
|
||||
val teamObject = Team(
|
||||
data.profileId,
|
||||
teamId,
|
||||
className,
|
||||
Team.TYPE_CLASS,
|
||||
teamCode,
|
||||
-1
|
||||
)
|
||||
|
||||
data.teamClass = teamObject
|
||||
data.teamList.put(teamObject.id, teamObject)
|
||||
}
|
||||
|
||||
private fun getSubjects(text: String) {
|
||||
EDUDZIENNIK_SUBJECTS_START.findAll(text).forEach {
|
||||
val id = it[1].trim()
|
||||
val name = it[2].trim()
|
||||
data.getSubject(id, name)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-25
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHERS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TEACHERS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
|
||||
class EdudziennikWebTeachers(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebTeachers"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, data.studentAndTeacherClassEndpoint + "grid") { text ->
|
||||
EDUDZIENNIK_TEACHERS.findAll(text).forEach {
|
||||
val lastName = it[1].trim()
|
||||
val firstName = it[2].trim()
|
||||
data.getTeacher(firstName, lastName)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS, MONTH)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_EDUDZIENNIK_WEB_TIMETABLE_NOT_PUBLIC
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHER_ID
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.splitName
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class EdudziennikWebTimetable(override val data: DataEdudziennik,
|
||||
val onSuccess: () -> Unit) : EdudziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikWebTimetable"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
|
||||
val currentWeekStart = Week.getWeekStart()
|
||||
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
currentWeekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
|
||||
|
||||
val weekStart = Date.fromY_m_d(getDate)
|
||||
val weekEnd = weekStart.clone().stepForward(0, 0, 6)
|
||||
|
||||
webGet(TAG, data.timetableEndpoint + "print?date=$getDate") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
val dataDays = mutableListOf<Int>()
|
||||
val dataStart = weekStart.clone()
|
||||
while (dataStart <= weekEnd) {
|
||||
dataDays += dataStart.value
|
||||
dataStart.stepForward(0, 0, 1)
|
||||
}
|
||||
|
||||
val table = doc.select("#Schedule tbody").first()
|
||||
|
||||
if (table.text().trim() == "Brak planu lekcji.") {
|
||||
val today = Date.getToday()
|
||||
val schoolYearStart = if (today.month >= 9) today.year else today.year - 1
|
||||
|
||||
if (weekStart >= Date(schoolYearStart, 9, 1)) {
|
||||
data.error(ApiError(TAG, ERROR_EDUDZIENNIK_WEB_TIMETABLE_NOT_PUBLIC)
|
||||
.withApiResponse(text))
|
||||
onSuccess()
|
||||
return@webGet
|
||||
}
|
||||
} else {
|
||||
table.children().forEach { row ->
|
||||
val rowElements = row.children()
|
||||
|
||||
val lessonNumber = rowElements[0].text().toInt()
|
||||
|
||||
val times = rowElements[1].text().split('-')
|
||||
val startTime = Time.fromH_m(times[0].trim())
|
||||
val endTime = Time.fromH_m(times[1].trim())
|
||||
|
||||
data.lessonRanges.singleOrNull {
|
||||
it.lessonNumber == lessonNumber && it.startTime == startTime && it.endTime == endTime
|
||||
} ?: run {
|
||||
data.lessonRanges.put(lessonNumber, LessonRange(profileId, lessonNumber, startTime, endTime))
|
||||
}
|
||||
|
||||
rowElements.subList(2, rowElements.size).forEachIndexed { index, lesson ->
|
||||
val course = lesson.select(".course").firstOrNull() ?: return@forEachIndexed
|
||||
val info = course.select("span > span")
|
||||
|
||||
if (info.isEmpty()) return@forEachIndexed
|
||||
|
||||
val type = when (course.hasClass("substitute")) {
|
||||
true -> Lesson.TYPE_CHANGE
|
||||
else -> Lesson.TYPE_NORMAL
|
||||
}
|
||||
|
||||
/* Getting subject */
|
||||
|
||||
val subjectElement = info[0].child(0)
|
||||
val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
|
||||
?: return@forEachIndexed
|
||||
val subjectName = subjectElement.text().trim()
|
||||
val subject = data.getSubject(subjectId, subjectName)
|
||||
|
||||
/* Getting teacher */
|
||||
|
||||
val teacherId = if (info.size >= 2) {
|
||||
val teacherElement = info[1].child(0)
|
||||
val teacherLongId = EDUDZIENNIK_TEACHER_ID.find(teacherElement.attr("href"))?.get(1)
|
||||
val teacherName = teacherElement.text().trim()
|
||||
teacherName.splitName()?.let { (teacherLastName, teacherFirstName) ->
|
||||
data.getTeacher(teacherFirstName, teacherLastName, teacherLongId)
|
||||
}?.id ?: -1
|
||||
} else -1
|
||||
|
||||
val lessonObject = Lesson(profileId, -1).also {
|
||||
it.type = type
|
||||
it.date = weekStart.clone().stepForward(0, 0, index)
|
||||
it.lessonNumber = lessonNumber
|
||||
it.startTime = startTime
|
||||
it.endTime = endTime
|
||||
it.subjectId = subject.id
|
||||
it.teacherId = teacherId
|
||||
|
||||
it.id = it.buildId()
|
||||
}
|
||||
|
||||
data.lessonNewList.add(lessonObject)
|
||||
dataDays.remove(lessonObject.date!!.value)
|
||||
|
||||
if (type != Lesson.TYPE_NORMAL) {
|
||||
val seen = profile.empty || lessonObject.date!! < Date.getToday()
|
||||
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonObject.id,
|
||||
seen,
|
||||
seen,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (day in dataDays) {
|
||||
val lessonDate = Date.fromValue(day)
|
||||
data.lessonNewList += Lesson(profileId, lessonDate.value.toLong()).apply {
|
||||
type = Lesson.TYPE_NO_LESSONS
|
||||
date = lessonDate
|
||||
}
|
||||
}
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
if (data.timetableNotPublic) data.timetableNotPublic = false
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ACCOUNT_NAME_START
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_STUDENTS_START
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getShortName
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikFirstLogin"
|
||||
}
|
||||
|
||||
private val web = EdudziennikWeb(data)
|
||||
private val profileList = mutableListOf<Profile>()
|
||||
|
||||
init {
|
||||
EdudziennikLoginWeb(data) {
|
||||
web.webGet(TAG, "") { text ->
|
||||
val accountName = EDUDZIENNIK_ACCOUNT_NAME_START.find(text)?.get(1)?.fixName()
|
||||
|
||||
EDUDZIENNIK_STUDENTS_START.findAll(text).forEach {
|
||||
val studentId = it[1]
|
||||
val studentName = it[2].fixName()
|
||||
|
||||
if (studentId.isBlank() || studentName.isBlank()) return@forEach
|
||||
|
||||
val profile = Profile()
|
||||
profile.studentNameLong = studentName
|
||||
profile.studentNameShort = studentName.getShortName()
|
||||
profile.accountNameLong = if (studentName == accountName) null else accountName
|
||||
profile.studentSchoolYear = Utils.getCurrentSchoolYear()
|
||||
profile.name = studentName
|
||||
profile.subname = data.loginEmail
|
||||
profile.empty = true
|
||||
profile.putStudentData("studentId", studentId)
|
||||
profileList.add(profile)
|
||||
}
|
||||
|
||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class EdudziennikLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikLogin"
|
||||
}
|
||||
|
||||
private var cancelled = false
|
||||
|
||||
init {
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextLoginMethod(onSuccess: () -> Unit) {
|
||||
if (data.targetLoginMethodIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId ->
|
||||
data.progress(data.progressStep)
|
||||
if (usedMethodId != -1)
|
||||
data.loginMethods.add(usedMethodId)
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) {
|
||||
// this should never be true
|
||||
if (data.loginMethods.contains(loginMethodId)) {
|
||||
onSuccess(-1)
|
||||
return
|
||||
}
|
||||
Utils.d(TAG, "Using login method $loginMethodId")
|
||||
when (loginMethodId) {
|
||||
LOGIN_METHOD_EDUDZIENNIK_WEB -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_edudziennik_web)
|
||||
EdudziennikLoginWeb(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-22
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "EdudziennikLoginWeb"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.isWebLoginValid()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("dziennikel.appspot.com")
|
||||
if (data.loginEmail.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
private fun loginWithCredentials() {
|
||||
d(TAG, "Request: Edudziennik/Login/Web - https://dziennikel.appspot.com/login/?next=/")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text == null || response == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
val url = response.raw().request().url().toString()
|
||||
|
||||
if (!url.contains("Student")) {
|
||||
when {
|
||||
text.contains("Wprowadzono nieprawidłową nazwę użytkownika lub hasło.") -> ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN
|
||||
else -> ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val cookies = data.app.cookieJar.getForDomain("dziennikel.appspot.com")
|
||||
val sessionId = cookies.firstOrNull { it.name() == "sessionid" }?.value()
|
||||
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
|
||||
data.webSessionId = sessionId
|
||||
data.webSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("https://dziennikel.appspot.com/login/?next=/")
|
||||
.userAgent(EDUDZIENNIK_USER_AGENT)
|
||||
.contentType("application/x-www-form-urlencoded")
|
||||
.addParameter("email", data.loginEmail)
|
||||
.addParameter("password", data.loginPassword)
|
||||
.addParameter("auth_method", "password")
|
||||
.addParameter("next", "/")
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -6,19 +6,23 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
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.IdziennikWebGetAttachment
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebGetMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebGetRecipientList
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebSendMessage
|
||||
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.idziennikLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -28,6 +32,7 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataIdziennik
|
||||
private var afterLogin: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
data = DataIdziennik(app, profile, loginStore).apply {
|
||||
@ -54,33 +59,69 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId)
|
||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
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) {
|
||||
IdziennikData(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 getMessage(message: MessageFull) {
|
||||
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
IdziennikFirstLogin(data) {
|
||||
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(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
||||
IdziennikWebGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getRecipientList() {
|
||||
login(LOGIN_METHOD_IDZIENNIK_WEB) {
|
||||
IdziennikWebGetRecipientList(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() { IdziennikFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
@ -88,28 +129,29 @@ class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
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 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) {
|
||||
in internalErrorList -> {
|
||||
// finish immediately if the same error occurs twice during the same sync
|
||||
callback.onError(apiError)
|
||||
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()
|
||||
}
|
||||
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
||||
internalErrorList.add(apiError.errorCode)
|
||||
loginStore.removeLoginData("refreshToken") // force a clean login
|
||||
//loginLibrus()
|
||||
ERROR_IDZIENNIK_API_NO_REGISTER -> {
|
||||
data()
|
||||
}
|
||||
else -> callback.onError(apiError)
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ open class IdziennikApi(open val data: DataIdziennik) {
|
||||
}
|
||||
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 ->
|
||||
@ -107,6 +108,7 @@ open class IdziennikApi(open val data: DataIdziennik) {
|
||||
}
|
||||
}
|
||||
}
|
||||
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
|
||||
.callback(callback)
|
||||
|
@ -8,12 +8,14 @@ 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.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
|
||||
|
||||
@ -156,4 +158,54 @@ open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
.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) }
|
||||
}
|
||||
.post()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
||||
|
@ -5,17 +5,18 @@
|
||||
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.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_DELETED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.getBoolean
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc32
|
||||
@ -51,11 +52,18 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
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(
|
||||
sender.getString("imie") ?: "",
|
||||
sender.getString("nazwisko") ?: ""
|
||||
firstName,
|
||||
lastName
|
||||
)
|
||||
rTeacher.loginId = sender.getString("id") + ":" + sender.getString("usr")
|
||||
rTeacher.loginId = /*sender.getString("id") + ":" + */sender.getString("usr")
|
||||
rTeacher.setTeacherType(Teacher.TYPE_OTHER)
|
||||
|
||||
val message = Message(
|
||||
profileId,
|
||||
@ -77,7 +85,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
|
||||
data.messageIgnoreList.add(message)
|
||||
data.messageRecipientList.add(messageRecipient)
|
||||
data.messageMetadataList.add(Metadata(
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
message.id,
|
||||
|
@ -7,11 +7,11 @@ 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.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
@ -62,7 +62,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
||||
lastName = "użytkownik"
|
||||
}
|
||||
val rTeacher = data.getTeacher(firstName, lastName)
|
||||
rTeacher.loginId = recipient.get("id").asString + ":" + recipient.get("usr").asString
|
||||
rTeacher.loginId = /*recipient.get("id").asString + ":" + */recipient.get("usr").asString
|
||||
|
||||
val messageRecipient = MessageRecipient(
|
||||
profileId,
|
||||
|
@ -54,7 +54,8 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
|
||||
jAnnouncement.get("Tresc").asString,
|
||||
startDate,
|
||||
null,
|
||||
rTeacher.id
|
||||
rTeacher.id,
|
||||
null
|
||||
)
|
||||
data.announcementList.add(announcementObject)
|
||||
data.metadataList.add(Metadata(
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.io.File
|
||||
|
||||
class IdziennikWebGetAttachment(
|
||||
override val data: DataIdziennik, val message: Message, val attachmentId: Long,
|
||||
val attachmentName: String, val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikWebGetAttachment"
|
||||
}
|
||||
|
||||
init {
|
||||
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,
|
||||
message.id,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_FINISHED,
|
||||
file.absolutePath
|
||||
)
|
||||
|
||||
val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.messageId}_${event.attachmentId}")
|
||||
Utils.writeStringToFile(attachmentDataFile, event.fileName)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
|
||||
onSuccess()
|
||||
|
||||
}) { written, _ ->
|
||||
val event = AttachmentGetEvent(
|
||||
profileId,
|
||||
message.id,
|
||||
attachmentId,
|
||||
AttachmentGetEvent.TYPE_PROGRESS,
|
||||
bytesWritten = written
|
||||
)
|
||||
|
||||
EventBus.getDefault().post(event)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* 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.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebGetMessage(
|
||||
override val data: DataIdziennik,
|
||||
private val message: MessageFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : IdziennikWeb(data) {
|
||||
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, -1, message.id)
|
||||
|
||||
val readDateString = it.getString("DataOdczytania")
|
||||
recipientObject.readDate = if (readDateString.isNullOrBlank()) System.currentTimeMillis()
|
||||
else Date.fromIso(readDateString)
|
||||
|
||||
recipientObject.fullName = profile.accountNameLong ?: 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, teacher.id, 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,
|
||||
message.addedDate
|
||||
))
|
||||
}
|
||||
|
||||
EventBus.getDefault().postSticky(MessageGetEvent(message))
|
||||
|
||||
data.messageList.add(message)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
/*
|
||||
* 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.modules.teachers.Teacher
|
||||
|
||||
class IdziennikWebGetRecipientList(
|
||||
override val data: DataIdziennik, val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@ 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.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
@ -23,7 +24,7 @@ class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
private const val TAG = "IdziennikWebGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
init { data.profile?.also { profile ->
|
||||
webApiGet(TAG, IDZIENNIK_WEB_GRADES, mapOf(
|
||||
"idPozDziennika" to data.registerId
|
||||
)) { result ->
|
||||
@ -123,12 +124,12 @@ class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
}
|
||||
1 -> {
|
||||
gradeObject.type = Grade.TYPE_SEMESTER1_FINAL
|
||||
gradeObject.name = name
|
||||
gradeObject.name = value.toInt().toString()
|
||||
gradeObject.weight = 0f
|
||||
}
|
||||
2 -> {
|
||||
gradeObject.type = Grade.TYPE_YEAR_FINAL
|
||||
gradeObject.name = name
|
||||
gradeObject.name = value.toInt().toString()
|
||||
gradeObject.weight = 0f
|
||||
}
|
||||
}
|
||||
@ -141,15 +142,22 @@ class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
data.profile?.empty ?: false,
|
||||
data.profile?.empty ?: false,
|
||||
data.profile.empty,
|
||||
data.profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
||||
|
@ -4,13 +4,14 @@
|
||||
|
||||
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.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_PROPOSED
|
||||
@ -106,8 +107,11 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
}
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}}
|
||||
} ?: onSuccess() }
|
||||
}
|
||||
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.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) {
|
||||
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) {
|
||||
val message = data.messageIgnoreList.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, metadata?.addedDate)
|
||||
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,12 +6,12 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus
|
||||
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_PORTAL
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
import pl.szczodrzynski.edziennik.data.api.models.Data
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
@ -149,7 +149,8 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiCode: String? = null
|
||||
var apiCode: String?
|
||||
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
|
||||
set(value) { loginStore.putLoginData("accountCode", value) ?: return; mApiCode = value }
|
||||
set(value) {
|
||||
loginStore.putLoginData("accountCode", value); mApiCode = value }
|
||||
/**
|
||||
* A JST login PIN.
|
||||
* Used only during first login in JST mode.
|
||||
@ -157,7 +158,8 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
private var mApiPin: String? = null
|
||||
var apiPin: String?
|
||||
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
|
||||
set(value) { loginStore.putLoginData("accountPin", value) ?: return; mApiPin = value }
|
||||
set(value) {
|
||||
loginStore.putLoginData("accountPin", value); mApiPin = value }
|
||||
|
||||
/**
|
||||
* A Synergia API access token.
|
||||
@ -256,6 +258,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
var startPointsSemester1: Int
|
||||
get() { mStartPointsSemester1 = mStartPointsSemester1 ?: profile?.getStudentData("startPointsSemester1", 0); return mStartPointsSemester1 ?: 0 }
|
||||
set(value) { profile?.putStudentData("startPointsSemester1", value) ?: return; mStartPointsSemester1 = value }
|
||||
|
||||
private var mStartPointsSemester2: Int? = null
|
||||
var startPointsSemester2: Int
|
||||
get() { mStartPointsSemester2 = mStartPointsSemester2 ?: profile?.getStudentData("startPointsSemester2", 0); return mStartPointsSemester2 ?: 0 }
|
||||
@ -265,8 +268,14 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
var enablePointGrades: Boolean
|
||||
get() { mEnablePointGrades = mEnablePointGrades ?: profile?.getStudentData("enablePointGrades", true); return mEnablePointGrades ?: true }
|
||||
set(value) { profile?.putStudentData("enablePointGrades", value) ?: return; mEnablePointGrades = value }
|
||||
|
||||
private var mEnableDescriptiveGrades: Boolean? = null
|
||||
var enableDescriptiveGrades: Boolean
|
||||
get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true }
|
||||
set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value }
|
||||
|
||||
private var mTimetableNotPublic: Boolean? = null
|
||||
var timetableNotPublic: Boolean
|
||||
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
|
||||
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
|
||||
}
|
||||
|
@ -8,18 +8,23 @@ import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api.LibrusApiAnnouncementMarkAsRead
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetAttachment
|
||||
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.LibrusMessagesSendMessage
|
||||
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.login.*
|
||||
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.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -29,6 +34,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataLibrus
|
||||
private var afterLogin: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
data = DataLibrus(app, profile, loginStore).apply {
|
||||
@ -58,12 +64,14 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
login()
|
||||
}
|
||||
|
||||
private fun 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(librusLoginMethods, it) }
|
||||
afterLogin?.let { this.afterLogin = it }
|
||||
LibrusLogin(data) {
|
||||
data()
|
||||
}
|
||||
@ -75,57 +83,60 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
d(TAG, " - Internal errors:")
|
||||
internalErrorList.forEach { d(TAG, " - code $it") }
|
||||
}
|
||||
LibrusData(data) {
|
||||
afterLogin?.invoke() ?: LibrusData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
LibrusLoginPortal(data) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusLoginMessages(data) {
|
||||
LibrusMessagesGetMessage(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesGetMessage(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesSendMessage(data, recipients, subject, text) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
LibrusLoginPortal(data) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
|
||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
||||
login(LOGIN_METHOD_LIBRUS_API) {
|
||||
LibrusApiAnnouncementMarkAsRead(data, announcement) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
LibrusLoginPortal(data) {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusLoginMessages(data) {
|
||||
LibrusMessagesGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
LibrusFirstLogin(data) {
|
||||
completed()
|
||||
override fun getRecipientList() {
|
||||
login(LOGIN_METHOD_LIBRUS_MESSAGES) {
|
||||
LibrusMessagesGetRecipientList(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() { LibrusFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
@ -133,18 +144,9 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
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 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
|
||||
@ -155,30 +157,26 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
when (apiError.errorCode) {
|
||||
ERROR_LIBRUS_PORTAL_ACCESS_DENIED -> {
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_PORTAL)
|
||||
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_PORTAL)
|
||||
data.targetLoginMethodIds.sort()
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_PORTAL)
|
||||
data.portalTokenExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
ERROR_LIBRUS_API_ACCESS_DENIED,
|
||||
ERROR_LIBRUS_API_TOKEN_EXPIRED -> {
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_API)
|
||||
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_API)
|
||||
data.targetLoginMethodIds.sort()
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_API)
|
||||
data.apiTokenExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED -> {
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||
data.targetLoginMethodIds.sort()
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_SYNERGIA)
|
||||
data.synergiaSessionIdExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
ERROR_LIBRUS_MESSAGES_ACCESS_DENIED -> {
|
||||
data.loginMethods.remove(LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||
data.targetLoginMethodIds.add(LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||
data.targetLoginMethodIds.sort()
|
||||
data.prepareFor(librusLoginMethods, LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||
data.messagesSessionIdExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
@ -204,7 +202,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
}
|
||||
// TODO PORTAL CAPTCHA
|
||||
ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC -> {
|
||||
loginStore.putLoginData("timetableNotPublic", true)
|
||||
data.timetableNotPublic = true
|
||||
data()
|
||||
}
|
||||
ERROR_LIBRUS_API_LUCKY_NUMBER_NOT_ACTIVE,
|
||||
|
@ -89,6 +89,19 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiBehaviourGradeCategories(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiDescriptiveGradeCategories(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiTextGradeCategories(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_categories)
|
||||
LibrusApiPointGradeCategories(data, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADE_COMMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||
LibrusApiGradeComments(data, onSuccess)
|
||||
@ -97,6 +110,7 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grade_comments)
|
||||
LibrusApiBehaviourGradeComments(data, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
LibrusApiGrades(data, onSuccess)
|
||||
@ -105,7 +119,18 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_behaviour_grades)
|
||||
LibrusApiBehaviourGrades(data, onSuccess)
|
||||
}
|
||||
// TODO grades
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_descriptive_grades)
|
||||
LibrusApiDescriptiveGrades(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_descriptive_grades)
|
||||
LibrusApiTextGrades(data, onSuccess)
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_point_grades)
|
||||
LibrusApiPointGrades(data, onSuccess)
|
||||
}
|
||||
|
||||
ENDPOINT_LIBRUS_API_EVENT_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_event_types)
|
||||
|
@ -5,6 +5,7 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
@ -12,6 +13,8 @@ import im.wangchao.mhttp.callback.FileCallbackHandler
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import org.json.JSONObject
|
||||
import org.json.XML
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.parser.Parser
|
||||
@ -38,10 +41,10 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun messagesGet(tag: String, endpoint: String, method: Int = POST,
|
||||
fun messagesGet(tag: String, module: String, method: Int = POST,
|
||||
parameters: Map<String, Any>? = null, onSuccess: (doc: Document) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_MESSAGES_URL/$endpoint")
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_MESSAGES_URL/$module")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
@ -107,22 +110,92 @@ open class LibrusMessages(open val data: DataLibrus) {
|
||||
transformer.transform(DOMSource(doc), StreamResult(stringWriter))
|
||||
val requestXml = stringWriter.toString()
|
||||
|
||||
/*val requestXml = xml("service") {
|
||||
"header" { }
|
||||
"data" {
|
||||
for ((key, value) in parameters.orEmpty()) {
|
||||
key {
|
||||
-value.toString()
|
||||
Request.builder()
|
||||
.url("$LIBRUS_MESSAGES_URL/$module")
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> post()
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun messagesGetJson(tag: String, module: String, method: Int = POST,
|
||||
parameters: Map<String, Any>? = null, onSuccess: (json: JsonObject?) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_MESSAGES_URL/$module")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text.isNullOrEmpty()) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
when {
|
||||
text.contains("<message>Niepoprawny login i/lub hasło.</message>") -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
|
||||
text.contains("stop.png") -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
text.contains("eAccessDeny") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("OffLine") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
|
||||
text.contains("<status>error</status>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
|
||||
text.contains("<type>eVarWhitThisNameNotExists</type>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text.contains("<error>") -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
|
||||
}
|
||||
|
||||
try {
|
||||
val json: JSONObject? = XML.toJSONObject(text)
|
||||
onSuccess(JsonParser().parse(json?.toString() ?: "{}")?.asJsonObject)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
}.toString(PrintOptions(
|
||||
singleLineTextElements = true,
|
||||
useSelfClosingTags = true
|
||||
))*/
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(data.messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
|
||||
|
||||
val docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
|
||||
val doc = docBuilder.newDocument()
|
||||
val serviceElement = doc.createElement("service")
|
||||
val headerElement = doc.createElement("header")
|
||||
val dataElement = doc.createElement("data")
|
||||
for ((key, value) in parameters.orEmpty()) {
|
||||
val element = doc.createElement(key)
|
||||
element.appendChild(doc.createTextNode(value.toString()))
|
||||
dataElement.appendChild(element)
|
||||
}
|
||||
serviceElement.appendChild(headerElement)
|
||||
serviceElement.appendChild(dataElement)
|
||||
doc.appendChild(serviceElement)
|
||||
val transformer = TransformerFactory.newInstance().newTransformer()
|
||||
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes")
|
||||
val stringWriter = StringWriter()
|
||||
transformer.transform(DOMSource(doc), StreamResult(stringWriter))
|
||||
val requestXml = stringWriter.toString()
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_MESSAGES_URL/$endpoint")
|
||||
.url("$LIBRUS_MESSAGES_URL/$module")
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
|
||||
.apply {
|
||||
|
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-27
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.POST
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
|
||||
class LibrusApiAnnouncementMarkAsRead(
|
||||
override val data: DataLibrus,
|
||||
private val announcement: AnnouncementFull,
|
||||
val onSuccess: () -> Unit
|
||||
) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAnnouncementMarkAsRead"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "SchoolNotices/MarkAsRead/${announcement.idString}", method = POST) {
|
||||
announcement.seen = true
|
||||
|
||||
EventBus.getDefault().postSticky(AnnouncementGetEvent(announcement))
|
||||
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
announcement.id,
|
||||
announcement.seen,
|
||||
announcement.notified,
|
||||
announcement.addedDate
|
||||
))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -24,7 +24,8 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
val announcements = json.getJsonArray("SchoolNotices").asJsonObjectList()
|
||||
|
||||
announcements?.forEach { announcement ->
|
||||
val id = announcement.getString("Id")?.crc32() ?: return@forEach
|
||||
val longId = announcement.getString("Id") ?: return@forEach
|
||||
val id = longId.crc32()
|
||||
val subject = announcement.getString("Subject") ?: ""
|
||||
val text = announcement.getString("Content") ?: ""
|
||||
val startDate = Date.fromY_m_d(announcement.getString("StartDate"))
|
||||
@ -41,11 +42,12 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
text,
|
||||
startDate,
|
||||
endDate,
|
||||
teacherId
|
||||
teacherId,
|
||||
longId
|
||||
)
|
||||
|
||||
data.announcementList.add(announcementObject)
|
||||
data.metadataList.add(Metadata(
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
id,
|
||||
|
@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
@ -23,56 +24,60 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
|
||||
|
||||
private val nameFormat by lazy { DecimalFormat("#.##") }
|
||||
|
||||
init { data.profile?.let { profile ->
|
||||
init { data.profile?.also { profile ->
|
||||
apiGet(TAG, "BehaviourGrades/Points") { json ->
|
||||
|
||||
val semester1StartGradeObject = Grade(
|
||||
profileId,
|
||||
-101,
|
||||
data.app.getString(R.string.grade_start_points),
|
||||
0xffbdbdbd.toInt(),
|
||||
data.app.getString(R.string.grade_start_points_format, 1),
|
||||
nameFormat.format(data.startPointsSemester1),
|
||||
data.startPointsSemester1.toFloat(),
|
||||
-1f,
|
||||
1,
|
||||
-1,
|
||||
1
|
||||
).apply { type = Grade.TYPE_BEHAVIOUR }
|
||||
if (data.startPointsSemester1 > 0) {
|
||||
val semester1StartGradeObject = Grade(
|
||||
profileId,
|
||||
-101,
|
||||
data.app.getString(R.string.grade_start_points),
|
||||
0xffbdbdbd.toInt(),
|
||||
data.app.getString(R.string.grade_start_points_format, 1),
|
||||
nameFormat.format(data.startPointsSemester1),
|
||||
data.startPointsSemester1.toFloat(),
|
||||
-1f,
|
||||
1,
|
||||
-1,
|
||||
1
|
||||
).apply { type = Grade.TYPE_POINT_SUM }
|
||||
|
||||
data.gradeList.add(semester1StartGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
semester1StartGradeObject.id,
|
||||
true,
|
||||
true,
|
||||
profile.getSemesterStart(1).inMillis
|
||||
))
|
||||
data.gradeList.add(semester1StartGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
semester1StartGradeObject.id,
|
||||
true,
|
||||
true,
|
||||
profile.getSemesterStart(1).inMillis
|
||||
))
|
||||
}
|
||||
|
||||
val semester2StartGradeObject = Grade(
|
||||
profileId,
|
||||
-102,
|
||||
data.app.getString(R.string.grade_start_points),
|
||||
0xffbdbdbd.toInt(),
|
||||
data.app.getString(R.string.grade_start_points_format, 2),
|
||||
nameFormat.format(data.startPointsSemester2),
|
||||
data.startPointsSemester2.toFloat(),
|
||||
-1f,
|
||||
2,
|
||||
-1,
|
||||
1
|
||||
).apply { type = Grade.TYPE_BEHAVIOUR }
|
||||
if (data.startPointsSemester2 > 0) {
|
||||
val semester2StartGradeObject = Grade(
|
||||
profileId,
|
||||
-102,
|
||||
data.app.getString(R.string.grade_start_points),
|
||||
0xffbdbdbd.toInt(),
|
||||
data.app.getString(R.string.grade_start_points_format, 2),
|
||||
nameFormat.format(data.startPointsSemester2),
|
||||
data.startPointsSemester2.toFloat(),
|
||||
-1f,
|
||||
2,
|
||||
-1,
|
||||
1
|
||||
).apply { type = Grade.TYPE_POINT_SUM }
|
||||
|
||||
data.gradeList.add(semester2StartGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
semester2StartGradeObject.id,
|
||||
true,
|
||||
true,
|
||||
profile.getSemesterStart(2).inMillis
|
||||
))
|
||||
data.gradeList.add(semester2StartGradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
semester2StartGradeObject.id,
|
||||
true,
|
||||
true,
|
||||
profile.getSemesterStart(2).inMillis
|
||||
))
|
||||
}
|
||||
|
||||
json.getJsonArray("Grades")?.asJsonObjectList()?.forEach { grade ->
|
||||
val id = grade.getLong("Id") ?: return@forEach
|
||||
@ -128,7 +133,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
|
||||
teacherId,
|
||||
1
|
||||
).apply {
|
||||
type = Grade.TYPE_BEHAVIOUR
|
||||
type = Grade.TYPE_POINT_SUM
|
||||
valueMax = valueTo
|
||||
}
|
||||
|
||||
@ -143,8 +148,9 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Grades.semesterWithType(profile.currentSemester, Grade.TYPE_POINT_SUM))
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}}
|
||||
} ?: onSuccess() }
|
||||
}
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import android.graphics.Color
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
|
||||
class LibrusApiDescriptiveGradeCategories(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiDescriptiveGradeCategories"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "DescriptiveTextGrades/Skills") { json ->
|
||||
json.getJsonArray("Skills")?.asJsonObjectList()?.forEach { category ->
|
||||
val id = category.getLong("Id") ?: return@forEach
|
||||
val name = category.getString("Name") ?: ""
|
||||
val color = category.getJsonObject("Color")?.getInt("Id")
|
||||
?.let { data.getColor(it) } ?: Color.BLUE
|
||||
|
||||
val gradeCategoryObject = GradeCategory(
|
||||
profileId,
|
||||
id,
|
||||
-1f,
|
||||
color,
|
||||
name
|
||||
).apply {
|
||||
type = GradeCategory.TYPE_DESCRIPTIVE
|
||||
}
|
||||
|
||||
data.gradeCategories.put(id, gradeCategoryObject)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADE_CATEGORIES, 1 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_DESCRIPTIVE_TEXT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_TEXT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiDescriptiveGrades(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiDescriptiveGrades"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
apiGet(TAG, "BaseTextGrades") { json ->
|
||||
|
||||
json.getJsonArray("Grades")?.asJsonObjectList()?.forEach { grade ->
|
||||
val id = grade.getLong("Id") ?: return@forEach
|
||||
val teacherId = grade.getJsonObject("AddedBy")?.getLong("Id") ?: return@forEach
|
||||
val semester = grade.getInt("Semester") ?: return@forEach
|
||||
val subjectId = grade.getJsonObject("Subject")?.getLong("Id") ?: return@forEach
|
||||
val description = grade.getString("Grade")
|
||||
|
||||
val categoryId = grade.getJsonObject("Skill")?.getLong("Id")
|
||||
?: grade.getJsonObject("Category")?.getLong("Id")
|
||||
?: return@forEach
|
||||
val type = when (grade.getJsonObject("Category")) {
|
||||
null -> TYPE_DESCRIPTIVE_TEXT
|
||||
else -> TYPE_TEXT
|
||||
}
|
||||
|
||||
val category = data.gradeCategories.singleOrNull {
|
||||
it.categoryId == categoryId && it.type == when (type) {
|
||||
TYPE_DESCRIPTIVE_TEXT -> GradeCategory.TYPE_DESCRIPTIVE
|
||||
else -> GradeCategory.TYPE_TEXT
|
||||
}
|
||||
}
|
||||
|
||||
val addedDate = Date.fromIso(grade.getString("AddDate") ?: return@forEach)
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
category?.text ?: "",
|
||||
category?.color ?: -1,
|
||||
description,
|
||||
" ",
|
||||
0f,
|
||||
0f,
|
||||
semester,
|
||||
teacherId,
|
||||
subjectId
|
||||
).apply {
|
||||
this.type = type
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.addAll(listOf(
|
||||
TYPE_DESCRIPTIVE_TEXT,
|
||||
TYPE_TEXT
|
||||
).map {
|
||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
||||
})
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -70,7 +70,10 @@ class LibrusApiEvents(override val data: DataLibrus,
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
|
||||
data.toRemove.add(DataRemoveModel.Events.futureExceptTypes(listOf(
|
||||
Event.TYPE_HOMEWORK,
|
||||
Event.TYPE_PT_MEETING
|
||||
)))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
|
@ -4,8 +4,10 @@ import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
@ -17,7 +19,7 @@ class LibrusApiGrades(override val data: DataLibrus,
|
||||
const val TAG = "LibrusApiGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
init { data.profile?.also { profile ->
|
||||
apiGet(TAG, "Grades") { json ->
|
||||
val grades = json.getJsonArray("Grades").asJsonObjectList()
|
||||
|
||||
@ -68,15 +70,15 @@ class LibrusApiGrades(override val data: DataLibrus,
|
||||
|
||||
when {
|
||||
grade.getBoolean("IsConstituent") ?: false ->
|
||||
gradeObject.type = Grade.TYPE_NORMAL
|
||||
gradeObject.type = TYPE_NORMAL
|
||||
grade.getBoolean("IsSemester") ?: false -> // semester final
|
||||
gradeObject.type = if (gradeObject.semester == 1) Grade.TYPE_SEMESTER1_FINAL else Grade.TYPE_SEMESTER2_FINAL
|
||||
gradeObject.type = if (gradeObject.semester == 1) TYPE_SEMESTER1_FINAL else TYPE_SEMESTER2_FINAL
|
||||
grade.getBoolean("IsSemesterProposition") ?: false -> // semester proposed
|
||||
gradeObject.type = if (gradeObject.semester == 1) Grade.TYPE_SEMESTER1_PROPOSED else Grade.TYPE_SEMESTER2_PROPOSED
|
||||
gradeObject.type = if (gradeObject.semester == 1) TYPE_SEMESTER1_PROPOSED else TYPE_SEMESTER2_PROPOSED
|
||||
grade.getBoolean("IsFinal") ?: false -> // year final
|
||||
gradeObject.type = Grade.TYPE_YEAR_FINAL
|
||||
gradeObject.type = TYPE_YEAR_FINAL
|
||||
grade.getBoolean("IsFinalProposition") ?: false -> // year final
|
||||
gradeObject.type = Grade.TYPE_YEAR_PROPOSED
|
||||
gradeObject.type = TYPE_YEAR_PROPOSED
|
||||
}
|
||||
|
||||
grade.getJsonObject("Improvement")?.also {
|
||||
@ -94,14 +96,25 @@ class LibrusApiGrades(override val data: DataLibrus,
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.addAll(listOf(
|
||||
TYPE_NORMAL,
|
||||
TYPE_SEMESTER1_FINAL,
|
||||
TYPE_SEMESTER2_FINAL,
|
||||
TYPE_SEMESTER1_PROPOSED,
|
||||
TYPE_SEMESTER2_PROPOSED,
|
||||
TYPE_YEAR_FINAL,
|
||||
TYPE_YEAR_PROPOSED
|
||||
).map {
|
||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
||||
})
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
||||
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import android.graphics.Color
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
|
||||
class LibrusApiPointGradeCategories(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiPointGradeCategories"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "PointGrades/Categories") { json ->
|
||||
json.getJsonArray("Categories")?.asJsonObjectList()?.forEach { category ->
|
||||
val id = category.getLong("Id") ?: return@forEach
|
||||
val name = category.getString("Name") ?: ""
|
||||
val color = category.getJsonObject("Color")?.getInt("Id")
|
||||
?.let { data.getColor(it) } ?: Color.BLUE
|
||||
val countToAverage = category.getBoolean("CountToTheAverage") ?: true
|
||||
val weight = if (countToAverage) category.getFloat("Weight") ?: 0f else 0f
|
||||
val valueFrom = category.getFloat("ValueFrom") ?: 0f
|
||||
val valueTo = category.getFloat("ValueTo") ?: 0f
|
||||
|
||||
val gradeCategoryObject = GradeCategory(
|
||||
profileId,
|
||||
id,
|
||||
weight,
|
||||
color,
|
||||
name
|
||||
).apply {
|
||||
type = GradeCategory.TYPE_POINT
|
||||
setValueRange(valueFrom, valueTo)
|
||||
}
|
||||
|
||||
data.gradeCategories.put(id, gradeCategoryObject)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_POINT_GRADE_CATEGORIES, 1 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_POINT_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_POINT_AVG
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiPointGrades(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiPointGrades"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
apiGet(TAG, "PointGrades") { json ->
|
||||
|
||||
json.getJsonArray("Grades")?.asJsonObjectList()?.forEach { grade ->
|
||||
val id = grade.getLong("Id") ?: return@forEach
|
||||
val teacherId = grade.getJsonObject("AddedBy")?.getLong("Id") ?: return@forEach
|
||||
val semester = grade.getInt("Semester") ?: return@forEach
|
||||
val subjectId = grade.getJsonObject("Subject")?.getLong("Id") ?: return@forEach
|
||||
val name = grade.getString("Grade") ?: return@forEach
|
||||
val value = grade.getFloat("GradeValue") ?: 0f
|
||||
|
||||
val categoryId = grade.getJsonObject("Category")?.getLong("Id") ?: return@forEach
|
||||
|
||||
val category = data.gradeCategories.singleOrNull {
|
||||
it.categoryId == categoryId && it.type == GradeCategory.TYPE_POINT
|
||||
}
|
||||
|
||||
val addedDate = Date.fromIso(grade.getString("AddDate") ?: return@forEach)
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
category?.text ?: "",
|
||||
category?.color ?: -1,
|
||||
"",
|
||||
name,
|
||||
value,
|
||||
category?.weight ?: 0f,
|
||||
semester,
|
||||
teacherId,
|
||||
subjectId
|
||||
).apply {
|
||||
type = TYPE_POINT_AVG
|
||||
valueMax = category?.valueTo ?: 0f
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Grades.semesterWithType(profile.currentSemester, TYPE_POINT_AVG))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_POINT_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_PT_MEETINGS
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
@ -61,6 +62,8 @@ class LibrusApiPtMeetings(override val data: DataLibrus,
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_PT_MEETING))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_PT_MEETINGS, 12*HOUR)
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -26,12 +26,7 @@ class LibrusApiSchools(override val data: DataLibrus,
|
||||
|
||||
// create the school's short name using first letters of each long name's word
|
||||
// append the town name and save to student data
|
||||
var schoolNameShort = ""
|
||||
schoolNameLong?.split(" ")?.forEach {
|
||||
if (it.isBlank())
|
||||
return@forEach
|
||||
schoolNameShort += it[0].toLowerCase()
|
||||
}
|
||||
val schoolNameShort = schoolNameLong?.firstLettersName
|
||||
val schoolTown = school?.getString("Town")?.toLowerCase(Locale.getDefault())
|
||||
data.schoolName = schoolId.toString() + schoolNameShort + "_" + schoolTown
|
||||
|
||||
|
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import android.graphics.Color
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
|
||||
class LibrusApiTextGradeCategories(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiTextGradeCategories"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "TextGrades/Categories") { json ->
|
||||
json.getJsonArray("Categories")?.asJsonObjectList()?.forEach { category ->
|
||||
val id = category.getLong("Id") ?: return@forEach
|
||||
val name = category.getString("Name") ?: ""
|
||||
val color = category.getJsonObject("Color")?.getInt("Id")
|
||||
?.let { data.getColor(it) } ?: Color.BLUE
|
||||
|
||||
val gradeCategoryObject = GradeCategory(
|
||||
profileId,
|
||||
id,
|
||||
-1f,
|
||||
color,
|
||||
name
|
||||
).apply {
|
||||
type = GradeCategory.TYPE_TEXT
|
||||
}
|
||||
|
||||
data.gradeCategories.put(id, gradeCategoryObject)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TEXT_GRADE_CATEGORIES, 1 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-12-29
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.ENDPOINT_LIBRUS_API_TEXT_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_DESCRIPTIVE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.GradeCategory
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiTextGrades(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiTextGrades"
|
||||
}
|
||||
|
||||
init { data.profile?.also { profile ->
|
||||
apiGet(TAG, "DescriptiveGrades") { json ->
|
||||
|
||||
json.getJsonArray("Grades")?.asJsonObjectList()?.forEach { grade ->
|
||||
val id = grade.getLong("Id") ?: return@forEach
|
||||
val teacherId = grade.getJsonObject("AddedBy")?.getLong("Id") ?: return@forEach
|
||||
val semester = grade.getInt("Semester") ?: return@forEach
|
||||
val subjectId = grade.getJsonObject("Subject")?.getLong("Id") ?: return@forEach
|
||||
val description = grade.getString("RealGradeValue") ?: grade.getString("Map") ?: ""
|
||||
|
||||
val categoryId = grade.getJsonObject("Skill")?.getLong("Id") ?: return@forEach
|
||||
|
||||
val category = data.gradeCategories.singleOrNull {
|
||||
it.categoryId == categoryId && it.type == GradeCategory.TYPE_DESCRIPTIVE
|
||||
}
|
||||
|
||||
val addedDate = Date.fromIso(grade.getString("AddDate") ?: return@forEach)
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
category?.text ?: "",
|
||||
category?.color ?: -1,
|
||||
"",
|
||||
description,
|
||||
0f,
|
||||
0f,
|
||||
semester,
|
||||
teacherId,
|
||||
subjectId
|
||||
).apply {
|
||||
type = TYPE_DESCRIPTIVE
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Grades.semesterWithType(profile.currentSemester, TYPE_DESCRIPTIVE))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TEXT_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
@ -69,6 +69,8 @@ class LibrusApiTimetables(override val data: DataLibrus,
|
||||
|
||||
d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
|
||||
|
||||
if (data.timetableNotPublic) data.timetableNotPublic = false
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TIMETABLES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
|
@ -25,7 +25,14 @@ class LibrusApiUsers(override val data: DataLibrus,
|
||||
val firstName = user.getString("FirstName")?.fixName() ?: ""
|
||||
val lastName = user.getString("LastName")?.fixName() ?: ""
|
||||
|
||||
data.teacherList.put(id, Teacher(profileId, id, firstName, lastName))
|
||||
val teacher = Teacher(profileId, id, firstName, lastName)
|
||||
|
||||
if (user.getBoolean("IsSchoolAdministrator") == true)
|
||||
teacher.setTeacherType(Teacher.TYPE_SCHOOL_ADMIN)
|
||||
if (user.getBoolean("IsPedagogue") == true)
|
||||
teacher.setTeacherType(Teacher.TYPE_PEDAGOGUE)
|
||||
|
||||
data.teacherList.put(id, teacher)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_USERS, 4*DAY)
|
||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
@ -51,12 +52,12 @@ class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int
|
||||
val recipientFirstName = element.select(when (type) {
|
||||
TYPE_RECEIVED -> "senderFirstName"
|
||||
else -> "receiverFirstName"
|
||||
}).text().trim()
|
||||
}).text().fixName()
|
||||
|
||||
val recipientLastName = element.select(when (type) {
|
||||
TYPE_RECEIVED -> "senderLastName"
|
||||
else -> "receiverLastName"
|
||||
}).text().trim()
|
||||
}).text().fixName()
|
||||
|
||||
val recipientId = data.teacherList.singleOrNull {
|
||||
it.name == recipientFirstName && it.surname == recipientLastName
|
||||
|
@ -14,7 +14,10 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import pl.szczodrzynski.edziennik.notEmptyOrNull
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import java.nio.charset.Charset
|
||||
@ -56,11 +59,45 @@ class LibrusMessagesGetMessage(
|
||||
|
||||
when (messageObject.type) {
|
||||
TYPE_RECEIVED -> {
|
||||
val senderLoginId = message.select("senderId").text()
|
||||
data.teacherList.singleOrNull { it.id == messageObject.senderId }?.loginId = senderLoginId
|
||||
val senderLoginId = message.select("senderId").text().notEmptyOrNull()
|
||||
val senderGroupId = message.select("senderGroupId").text().toIntOrNull()
|
||||
val userClass = message.select("userClass").text().notEmptyOrNull()
|
||||
data.teacherList.singleOrNull { it.id == messageObject.senderId }?.apply {
|
||||
loginId = senderLoginId
|
||||
setTeacherType(when (senderGroupId) {
|
||||
/* https://api.librus.pl/2.0/Messages/Role */
|
||||
0, 1, 99 -> Teacher.TYPE_SUPER_ADMIN
|
||||
2 -> Teacher.TYPE_SCHOOL_ADMIN
|
||||
3 -> Teacher.TYPE_PRINCIPAL
|
||||
4 -> Teacher.TYPE_TEACHER
|
||||
5, 9 -> {
|
||||
if (typeDescription == null)
|
||||
typeDescription = userClass
|
||||
Teacher.TYPE_PARENT
|
||||
}
|
||||
7 -> Teacher.TYPE_SECRETARIAT
|
||||
8 -> {
|
||||
if (typeDescription == null)
|
||||
typeDescription = userClass
|
||||
Teacher.TYPE_STUDENT
|
||||
}
|
||||
10 -> Teacher.TYPE_PEDAGOGUE
|
||||
11 -> Teacher.TYPE_LIBRARIAN
|
||||
12 -> Teacher.TYPE_SPECIALIST
|
||||
21 -> {
|
||||
typeDescription = "Jednostka Nadrzędna"
|
||||
Teacher.TYPE_OTHER
|
||||
}
|
||||
50 -> {
|
||||
typeDescription = "Jednostka Samorządu Terytorialnego"
|
||||
Teacher.TYPE_OTHER
|
||||
}
|
||||
else -> Teacher.TYPE_OTHER
|
||||
})
|
||||
}
|
||||
|
||||
val readDateText = message.select("readDate").text()
|
||||
val readDate = when (readDateText.isNotEmpty()) {
|
||||
val readDate = when (readDateText.isNotNullNorEmpty()) {
|
||||
true -> Date.fromIso(readDateText)
|
||||
else -> 0
|
||||
}
|
||||
@ -73,7 +110,7 @@ class LibrusMessagesGetMessage(
|
||||
messageObject.id
|
||||
)
|
||||
|
||||
messageRecipientObject.fullName = profile.accountNameLong ?: profile.studentNameLong
|
||||
messageRecipientObject.fullName = profile.accountNameLong ?: profile.studentNameLong ?: ""
|
||||
|
||||
messageRecipientList.add(messageRecipientObject)
|
||||
}
|
||||
@ -90,7 +127,7 @@ class LibrusMessagesGetMessage(
|
||||
teacher?.loginId = receiverLoginId
|
||||
|
||||
val readDateText = message.select("readed").text()
|
||||
val readDate = when (readDateText.isNotEmpty()) {
|
||||
val readDate = when (readDateText.isNotNullNorEmpty()) {
|
||||
true -> Date.fromIso(readDateText)
|
||||
else -> 0
|
||||
}
|
||||
@ -111,7 +148,7 @@ class LibrusMessagesGetMessage(
|
||||
}
|
||||
|
||||
if (!messageObject.seen) {
|
||||
data.messageMetadataList.add(Metadata(
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
messageObject.profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
messageObject.id,
|
||||
|
@ -0,0 +1,174 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-31.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages
|
||||
|
||||
import androidx.core.util.set
|
||||
import androidx.room.OnConflictStrategy
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
class LibrusMessagesGetRecipientList(
|
||||
override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusMessagesGetRecipientList"
|
||||
}
|
||||
|
||||
private val listTypes = mutableListOf<Pair<String, String>>()
|
||||
|
||||
init {
|
||||
messagesGet(TAG, "Receivers/action/GetTypes", parameters = mapOf(
|
||||
"includeClass" to 1
|
||||
)) { doc ->
|
||||
doc.select("response GetTypes data list ArrayItem")?.forEach {
|
||||
val id = it.getElementsByTag("id")?.firstOrNull()?.ownText() ?: return@forEach
|
||||
val name = it.getElementsByTag("name")?.firstOrNull()?.ownText() ?: return@forEach
|
||||
listTypes += id to name
|
||||
}
|
||||
|
||||
getLists()
|
||||
}
|
||||
}
|
||||
|
||||
private fun getLists() {
|
||||
if (listTypes.isEmpty()) {
|
||||
finish()
|
||||
return
|
||||
}
|
||||
val type = listTypes.removeAt(0)
|
||||
if (type.first == "contactsGroups") {
|
||||
getLists()
|
||||
return
|
||||
}
|
||||
messagesGetJson(TAG, "Receivers/action/GetListForType", parameters = mapOf(
|
||||
"receiverType" to type.first
|
||||
)) { json ->
|
||||
val dataEl = json?.getJsonObject("response")?.getJsonObject("GetListForType")?.get("data")
|
||||
if (dataEl is JsonObject) {
|
||||
val listEl = dataEl.get("ArrayItem")
|
||||
if (listEl is JsonArray) {
|
||||
listEl.asJsonObjectList()?.forEach { item ->
|
||||
processElement(item, type.first, type.second)
|
||||
}
|
||||
}
|
||||
if (listEl is JsonObject) {
|
||||
processElement(listEl, type.first, type.second)
|
||||
}
|
||||
}
|
||||
|
||||
getLists()
|
||||
}
|
||||
}
|
||||
|
||||
private fun processElement(element: JsonObject, typeId: String, typeName: String, listName: String? = null) {
|
||||
val listEl = element.getJsonObject("list")?.get("ArrayItem")
|
||||
if (listEl is JsonArray) {
|
||||
listEl.asJsonObjectList()?.let { list ->
|
||||
val label = element.getString("label") ?: ""
|
||||
list.forEach { item ->
|
||||
processElement(item, typeId, typeName, label)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
if (listEl is JsonObject) {
|
||||
val label = element.getString("label") ?: ""
|
||||
processElement(listEl, typeId, typeName, label)
|
||||
return
|
||||
}
|
||||
processRecipient(element, typeId, typeName, listName)
|
||||
}
|
||||
|
||||
private fun processRecipient(recipient: JsonObject, typeId: String, typeName: String, listName: String? = null) {
|
||||
val id = recipient.getLong("id") ?: return
|
||||
val label = recipient.getString("label") ?: return
|
||||
|
||||
val fullNameLastFirst: String
|
||||
val description: String?
|
||||
if (typeId == "parentsCouncil" || typeId == "schoolParentsCouncil") {
|
||||
val delimiterIndex = label.lastIndexOf(" - ")
|
||||
if (delimiterIndex == -1) {
|
||||
fullNameLastFirst = label.fixName()
|
||||
description = null
|
||||
}
|
||||
else {
|
||||
fullNameLastFirst = label.substring(0, delimiterIndex).fixName()
|
||||
description = label.substring(delimiterIndex+3)
|
||||
}
|
||||
}
|
||||
else {
|
||||
fullNameLastFirst = label.fixName()
|
||||
description = null
|
||||
}
|
||||
|
||||
var typeDescription: String? = null
|
||||
val type = when (typeId) {
|
||||
"tutors" -> Teacher.TYPE_EDUCATOR
|
||||
"teachers" -> Teacher.TYPE_TEACHER
|
||||
"classParents" -> Teacher.TYPE_PARENT
|
||||
"guardians" -> Teacher.TYPE_PARENT
|
||||
"parentsCouncil" -> {
|
||||
typeDescription = joinNotNullStrings(": ", listName, description)
|
||||
Teacher.TYPE_PARENTS_COUNCIL
|
||||
}
|
||||
"schoolParentsCouncil" -> {
|
||||
typeDescription = joinNotNullStrings(": ", listName, description)
|
||||
Teacher.TYPE_SCHOOL_PARENTS_COUNCIL
|
||||
}
|
||||
"pedagogue" -> Teacher.TYPE_PEDAGOGUE
|
||||
"librarian" -> Teacher.TYPE_LIBRARIAN
|
||||
"admin" -> Teacher.TYPE_SCHOOL_ADMIN
|
||||
"secretary" -> Teacher.TYPE_SECRETARIAT
|
||||
"sadmin" -> Teacher.TYPE_SUPER_ADMIN
|
||||
else -> {
|
||||
typeDescription = typeName
|
||||
Teacher.TYPE_OTHER
|
||||
}
|
||||
}
|
||||
|
||||
// get teacher by fullName AND type or create it
|
||||
val teacher = data.teacherList.singleOrNull {
|
||||
it.fullNameLastFirst == fullNameLastFirst && ((type != Teacher.TYPE_SCHOOL_ADMIN && type != Teacher.TYPE_PEDAGOGUE) || it.isType(type))
|
||||
} ?: Teacher(data.profileId, id).apply {
|
||||
if (typeId == "sadmin" && id == 2L) {
|
||||
name = "Pomoc"
|
||||
surname = "Techniczna LIBRUS"
|
||||
}
|
||||
else {
|
||||
name = fullNameLastFirst
|
||||
fullNameLastFirst.splitName()?.let {
|
||||
name = it.second
|
||||
surname = it.first
|
||||
}
|
||||
}
|
||||
data.teacherList[id] = this
|
||||
}
|
||||
|
||||
teacher.apply {
|
||||
this.loginId = id.toString()
|
||||
this.setTeacherType(type)
|
||||
if (this.typeDescription.isNullOrBlank())
|
||||
this.typeDescription = typeDescription
|
||||
}
|
||||
}
|
||||
|
||||
private fun finish() {
|
||||
val event = RecipientListGetEvent(
|
||||
data.profileId,
|
||||
data.teacherList.filter { it.loginId != null }
|
||||
)
|
||||
|
||||
profile?.lastReceiversSync = System.currentTimeMillis()
|
||||
|
||||
data.teacherOnConflictStrategy = OnConflictStrategy.REPLACE
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2020-1-2.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.base64Encode
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
|
||||
class LibrusMessagesSendMessage(
|
||||
override val data: DataLibrus,
|
||||
val recipients: List<Teacher>,
|
||||
val subject: String,
|
||||
val text: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : LibrusMessages(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusMessages"
|
||||
}
|
||||
|
||||
init {
|
||||
val params = mapOf<String, Any>(
|
||||
"topic" to subject.base64Encode(),
|
||||
"message" to text.base64Encode(),
|
||||
"receivers" to recipients
|
||||
.filter { it.loginId != null }
|
||||
.joinToString(",") { it.loginId ?: "" },
|
||||
"actions" to "<Actions/>".base64Encode()
|
||||
)
|
||||
|
||||
messagesGetJson(TAG, "SendMessage", parameters = params) { json ->
|
||||
|
||||
val response = json.getJsonObject("response").getJsonObject("SendMessage")
|
||||
val id = response.getLong("data")
|
||||
|
||||
if (response.getString("status") != "ok" || id == null) {
|
||||
val message = response.getString("message")
|
||||
// TODO error
|
||||
return@messagesGetJson
|
||||
}
|
||||
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_SENT) {
|
||||
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id }
|
||||
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
|
||||
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)
|
||||
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -23,14 +23,14 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
||||
const val TAG = "LibrusSynergiaHomework"
|
||||
}
|
||||
|
||||
init {
|
||||
init { data.profile?.also { profile ->
|
||||
synergiaGet(TAG, "moje_zadania", method = POST, parameters = mapOf(
|
||||
"dataOd" to
|
||||
if (data.profile?.empty != false)
|
||||
profile!!.getSemesterStart(1).stringY_m_d
|
||||
if (!data.profile.empty)
|
||||
profile.getSemesterStart(1).stringY_m_d
|
||||
else
|
||||
Date.getToday().stringY_m_d,
|
||||
"dataDo" to profile!!.getSemesterEnd(profile?.currentSemester ?: 2).stringY_m_d,
|
||||
"dataDo" to Date.getToday().stepForward(0, 0, 7).stringY_m_d,
|
||||
"przedmiot" to -1
|
||||
|
||||
)) { text ->
|
||||
@ -65,7 +65,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
||||
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
||||
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
||||
|
||||
val seen = when (profile?.empty) {
|
||||
val seen = when (profile.empty) {
|
||||
true -> true
|
||||
else -> eventDate < Date.getToday()
|
||||
}
|
||||
@ -102,5 +102,5 @@ class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () ->
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
} ?: onSuccess() }
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
|
||||
class LibrusSynergiaMarkAllAnnouncementsAsRead(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusSynergia(data) {
|
||||
companion object {
|
||||
@ -14,6 +15,7 @@ class LibrusSynergiaMarkAllAnnouncementsAsRead(override val data: DataLibrus, va
|
||||
|
||||
init {
|
||||
synergiaGet(TAG, "ogloszenia") {
|
||||
data.app.db.metadataDao().setAllSeen(profileId, Metadata.TYPE_ANNOUNCEMENT, true)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
@ -2,10 +2,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.ERROR_NO_STUDENTS_IN_ACCOUNT
|
||||
import pl.szczodrzynski.edziennik.data.api.FAKE_LIBRUS_ACCOUNTS
|
||||
import pl.szczodrzynski.edziennik.data.api.LIBRUS_ACCOUNTS_URL
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_MODE_LIBRUS_EMAIL
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusPortal
|
||||
@ -13,8 +10,6 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginApi
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPortal
|
||||
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.models.AppError.CODE_LIBRUS_DISCONNECTED
|
||||
import pl.szczodrzynski.edziennik.data.api.models.AppError.CODE_SYNERGIA_NOT_ACTIVATED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
@ -46,8 +41,8 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
|
||||
val state = account.getString("state")
|
||||
when (state) {
|
||||
"requiring_an_action" -> CODE_LIBRUS_DISCONNECTED
|
||||
"need-activation" -> CODE_SYNERGIA_NOT_ACTIVATED
|
||||
"requiring_an_action" -> ERROR_LIBRUS_PORTAL_SYNERGIA_DISCONNECTED
|
||||
"need-activation" -> ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED
|
||||
else -> null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
|
@ -59,7 +59,7 @@ class SynergiaTokenExtractor(override val data: DataLibrus, val onSuccess: () ->
|
||||
data.apiTokenExpiryTime = response.getUnixDate() + 6 * 60 * 60
|
||||
|
||||
// TODO remove this
|
||||
data.profile?.studentNameLong = json.getString("studentName")
|
||||
data.profile?.studentNameLong = json.getString("studentName") ?: ""
|
||||
val nameParts = json.getString("studentName")?.split(" ")
|
||||
data.profile?.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||
|
||||
|
@ -6,22 +6,23 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.data.api.*
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.MobidziennikWebGetAttachment
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.MobidziennikWebGetMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.MobidziennikWebGetRecipientList
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web.MobidziennikWebSendMessage
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.firstlogin.MobidziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.mobidziennikLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -33,6 +34,7 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataMobidziennik
|
||||
private var afterLogin: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
data = DataMobidziennik(app, profile, loginStore).apply {
|
||||
@ -59,41 +61,69 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(mobidziennikLoginMethods, MobidziennikFeatures, featureIds, viewId)
|
||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
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(mobidziennikLoginMethods, it) }
|
||||
afterLogin?.let { this.afterLogin = it }
|
||||
MobidziennikLogin(data) {
|
||||
MobidziennikData(data) {
|
||||
completed()
|
||||
}
|
||||
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() ?: MobidziennikData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
MobidziennikLoginWeb(data) {
|
||||
login(LOGIN_METHOD_MOBIDZIENNIK_WEB) {
|
||||
MobidziennikWebGetMessage(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
||||
login(LOGIN_METHOD_MOBIDZIENNIK_WEB) {
|
||||
MobidziennikWebSendMessage(data, recipients, subject, text) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {}
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
MobidziennikLoginWeb(data) {
|
||||
login(LOGIN_METHOD_MOBIDZIENNIK_WEB) {
|
||||
MobidziennikWebGetAttachment(data, message, attachmentId, attachmentName) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
MobidziennikFirstLogin(data) {
|
||||
completed()
|
||||
override fun getRecipientList() {
|
||||
login(LOGIN_METHOD_MOBIDZIENNIK_WEB) {
|
||||
MobidziennikWebGetRecipientList(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() { MobidziennikFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
@ -101,28 +131,25 @@ class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginSto
|
||||
|
||||
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 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) {
|
||||
in internalErrorList -> {
|
||||
// finish immediately if the same error occurs twice during the same sync
|
||||
callback.onError(apiError)
|
||||
}
|
||||
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
||||
internalErrorList.add(apiError.errorCode)
|
||||
loginStore.removeLoginData("refreshToken") // force a clean login
|
||||
//loginLibrus()
|
||||
ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED,
|
||||
ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY,
|
||||
ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE,
|
||||
ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID -> {
|
||||
data.loginMethods.remove(LOGIN_METHOD_MOBIDZIENNIK_WEB)
|
||||
data.prepareFor(mobidziennikLoginMethods, LOGIN_METHOD_MOBIDZIENNIK_WEB)
|
||||
data.webSessionIdExpiryTime = 0
|
||||
login()
|
||||
}
|
||||
else -> callback.onError(apiError)
|
||||
}
|
||||
|
@ -26,8 +26,15 @@ open class MobidziennikWeb(open val data: DataMobidziennik) {
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun webGet(tag: String, endpoint: String, method: Int = GET, onSuccess: (text: String) -> Unit) {
|
||||
val url = "https://${data.loginServerName}.mobidziennik.pl$endpoint"
|
||||
fun webGet(
|
||||
tag: String,
|
||||
endpoint: String,
|
||||
method: Int = GET,
|
||||
parameters: List<Pair<String, Any>> = emptyList(),
|
||||
fullUrl: String? = null,
|
||||
onSuccess: (text: String) -> Unit
|
||||
) {
|
||||
val url = fullUrl ?: "https://${data.loginServerName}.mobidziennik.pl$endpoint"
|
||||
|
||||
d(tag, "Request: Mobidziennik/Web - $url")
|
||||
|
||||
@ -91,6 +98,15 @@ open class MobidziennikWeb(open val data: DataMobidziennik) {
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(MOBIDZIENNIK_USER_AGENT)
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> post()
|
||||
}
|
||||
parameters.map { (name, value) ->
|
||||
addParameter(name, value)
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
|
@ -5,12 +5,13 @@
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
|
||||
class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
|
||||
init { run {
|
||||
init { data.profile?.also { profile -> run {
|
||||
data.db.gradeDao().getDetails(
|
||||
data.profileId,
|
||||
data.gradeAddedDates,
|
||||
@ -73,6 +74,17 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
|
||||
subjectId)
|
||||
gradeObject.type = type
|
||||
|
||||
data.toRemove.addAll(listOf(
|
||||
TYPE_NORMAL,
|
||||
TYPE_SEMESTER1_FINAL,
|
||||
TYPE_SEMESTER2_FINAL,
|
||||
TYPE_SEMESTER1_PROPOSED,
|
||||
TYPE_SEMESTER2_PROPOSED,
|
||||
TYPE_YEAR_FINAL,
|
||||
TYPE_YEAR_PROPOSED
|
||||
).map {
|
||||
DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
|
||||
})
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
@ -85,5 +97,5 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
|
||||
))
|
||||
addedDate++
|
||||
}
|
||||
}}
|
||||
}}}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipientFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.monthFromName
|
||||
@ -67,7 +68,7 @@ class MobidziennikWebGetMessage(
|
||||
message.id
|
||||
)
|
||||
|
||||
recipient.fullName = profile?.accountNameLong ?: profile?.studentNameLong
|
||||
recipient.fullName = profile?.accountNameLong ?: profile?.studentNameLong ?: ""
|
||||
|
||||
messageRecipientList.add(recipient)
|
||||
} else {
|
||||
@ -76,7 +77,7 @@ class MobidziennikWebGetMessage(
|
||||
|
||||
content.select("table.spis tr:has(td)")?.forEach { recipientEl ->
|
||||
val senderEl = recipientEl.select("td:eq(0)").first()
|
||||
val senderName = senderEl.text()
|
||||
val senderName = senderEl.text().fixName()
|
||||
|
||||
val teacher = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }
|
||||
val receiverId = teacher?.id ?: -1
|
||||
@ -117,7 +118,7 @@ class MobidziennikWebGetMessage(
|
||||
|
||||
// this needs to be at the end
|
||||
message.apply {
|
||||
this.body = body.html()
|
||||
this.body = body.html().replace("\n", "<br>")
|
||||
|
||||
clearAttachments()
|
||||
content.select("ul li").map { it.select("a").first() }.forEach {
|
||||
@ -136,7 +137,7 @@ class MobidziennikWebGetMessage(
|
||||
}
|
||||
|
||||
if (!message.seen) { // TODO discover why this monstrosity instead of MetadataDao.setSeen
|
||||
data.messageMetadataList.add(Metadata(
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
message.profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
message.id,
|
||||
|
@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web
|
||||
|
||||
import androidx.core.util.set
|
||||
import androidx.room.OnConflictStrategy
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
class MobidziennikWebGetRecipientList(
|
||||
override val data: DataMobidziennik, val onSuccess: () -> Unit) : MobidziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "MobidziennikWebGetRecipientList"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, "/mobile/dodajwiadomosc") { text ->
|
||||
Regexes.MOBIDZIENNIK_MESSAGE_RECIPIENTS_JSON.find(text)?.let { match ->
|
||||
val recipientLists = JsonParser().parse(match[1]).asJsonArray
|
||||
recipientLists?.asJsonObjectList()?.forEach { list ->
|
||||
val listType = list.getString("typ")?.toIntOrNull() ?: -1
|
||||
val listName = list.getString("nazwa") ?: ""
|
||||
list.getJsonArray("dane")?.asJsonObjectList()?.forEach { recipient ->
|
||||
if (recipient.getBoolean("lista") == true) {
|
||||
recipient.getJsonArray("dane")?.asJsonObjectList()?.forEach {
|
||||
processRecipient(listType, recipient.getString("nazwa") ?: "", it)
|
||||
}
|
||||
}
|
||||
else
|
||||
processRecipient(listType, listName, recipient)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val event = RecipientListGetEvent(
|
||||
data.profileId,
|
||||
data.teacherList.filter { it.loginId != null }
|
||||
)
|
||||
|
||||
profile?.lastReceiversSync = System.currentTimeMillis()
|
||||
|
||||
data.teacherOnConflictStrategy = OnConflictStrategy.REPLACE
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private fun processRecipient(listType: Int, listName: String, recipient: JsonObject) {
|
||||
val id = recipient.getLong("id") ?: -1
|
||||
// get teacher by ID or create it
|
||||
val teacher = data.teacherList[id] ?: Teacher(data.profileId, id).apply {
|
||||
val fullName = recipient.getString("nazwa")?.fixName()
|
||||
name = fullName ?: ""
|
||||
fullName?.splitName()?.let {
|
||||
name = it.second
|
||||
surname = it.first
|
||||
}
|
||||
data.teacherList[id] = this
|
||||
}
|
||||
|
||||
teacher.apply {
|
||||
loginId = id.toString()
|
||||
when (listType) {
|
||||
1 -> setTeacherType(Teacher.TYPE_PRINCIPAL)
|
||||
2 -> setTeacherType(Teacher.TYPE_TEACHER)
|
||||
3 -> setTeacherType(Teacher.TYPE_PARENT)
|
||||
4 -> setTeacherType(Teacher.TYPE_STUDENT)
|
||||
//5 -> Użytkownicy zewnętrzni
|
||||
//6 -> Samorządy klasowe
|
||||
7 -> setTeacherType(Teacher.TYPE_PARENTS_COUNCIL) // Rady oddziałowe rodziców
|
||||
8 -> {
|
||||
setTeacherType(Teacher.TYPE_EDUCATOR)
|
||||
typeDescription = listName
|
||||
}
|
||||
9 -> setTeacherType(Teacher.TYPE_PEDAGOGUE)
|
||||
10 -> setTeacherType(Teacher.TYPE_SPECIALIST)
|
||||
else -> when (listName) {
|
||||
"Administratorzy" -> setTeacherType(Teacher.TYPE_SCHOOL_ADMIN)
|
||||
"Sekretarka" -> setTeacherType(Teacher.TYPE_SECRETARIAT)
|
||||
"Wsparcie techniczne mobiDziennik" -> setTeacherType(Teacher.TYPE_SUPER_ADMIN)
|
||||
else -> {
|
||||
setTeacherType(Teacher.TYPE_OTHER)
|
||||
typeDescription = listName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBIDZIENNIK_WEB_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
@ -25,8 +26,10 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
|
||||
private const val TAG = "MobidziennikWebGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
webGet(TAG, "/dziennik/oceny?semestr=${profile?.currentSemester ?: 1}") { text ->
|
||||
init { data.profile?.also { profile ->
|
||||
val currentSemester = profile.currentSemester
|
||||
|
||||
webGet(TAG, "/dziennik/oceny?semestr=$currentSemester") { text ->
|
||||
MobidziennikLuckyNumberExtractor(data, text)
|
||||
|
||||
val doc = Jsoup.parse(text)
|
||||
@ -90,7 +93,7 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
|
||||
)
|
||||
val time = Time.fromH_m_s(it[4])
|
||||
gradeAddedDateMillis = gradeAddedDate.combineWith(time)
|
||||
gradeSemester = profile?.dateToSemester(gradeAddedDate) ?: 1
|
||||
gradeSemester = profile.dateToSemester(gradeAddedDate)
|
||||
}
|
||||
|
||||
if (Regexes.MOBIDZIENNIK_GRADES_COUNT_TO_AVG.containsMatchIn(html)) {
|
||||
@ -129,8 +132,8 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
gradeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
profile.empty,
|
||||
profile.empty,
|
||||
gradeAddedDateMillis
|
||||
))
|
||||
}
|
||||
@ -143,8 +146,9 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
|
||||
}
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Grades.semesterWithType(currentSemester, Grade.TYPE_NORMAL))
|
||||
data.setSyncNext(ENDPOINT_MOBIDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
@ -14,6 +14,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@ -55,14 +56,15 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik,
|
||||
|
||||
if (type == TYPE_RECEIVED) {
|
||||
// search sender teacher
|
||||
val senderName = senderEl.text()
|
||||
val senderName = senderEl.text().fixName()
|
||||
senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id ?: -1
|
||||
data.messageRecipientList.add(MessageRecipient(profileId, -1, id))
|
||||
} else {
|
||||
// TYPE_SENT, so multiple recipients possible
|
||||
val recipientNames = senderEl.text().split(", ")
|
||||
for (recipientName in recipientNames) {
|
||||
val recipientId = data.teacherList.singleOrNull { it.fullNameLastFirst == recipientName }?.id ?: -1
|
||||
val name = recipientName.fixName()
|
||||
val recipientId = data.teacherList.singleOrNull { it.fullNameLastFirst == name }?.id ?: -1
|
||||
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, recipientId, id))
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
@ -48,7 +49,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
|
||||
val addedDate = Date.fromIsoHm(addedDateEl.text())
|
||||
|
||||
val senderEl = item.select("td:eq(2)").first()
|
||||
val senderName = senderEl.ownText()
|
||||
val senderName = senderEl.ownText().fixName()
|
||||
val senderId = data.teacherList.singleOrNull { it.fullNameLastFirst == senderName }?.id ?: -1
|
||||
data.messageRecipientIgnoreList.add(MessageRecipient(profileId, -1, id))
|
||||
|
||||
@ -68,7 +69,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
|
||||
message.setHasAttachments()
|
||||
|
||||
data.messageIgnoreList.add(message)
|
||||
data.messageMetadataList.add(
|
||||
data.setSeenMetadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.web
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.data.api.POST
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
|
||||
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
class MobidziennikWebSendMessage(
|
||||
override val data: DataMobidziennik,
|
||||
val recipients: List<Teacher>,
|
||||
val subject: String,
|
||||
val text: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : MobidziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "MobidziennikWebSendMessage"
|
||||
}
|
||||
|
||||
init {
|
||||
val params = mutableListOf<Pair<String, Any>>(
|
||||
"nazwa" to subject,
|
||||
"tresc" to text
|
||||
)
|
||||
for (teacher in recipients) {
|
||||
teacher.loginId?.let {
|
||||
params += "odbiorcy[]" to it
|
||||
}
|
||||
}
|
||||
|
||||
webGet(TAG, endpoint = "/dziennik/dodajwiadomosc", method = POST, parameters = params) { text ->
|
||||
|
||||
if (!text.contains(">Wiadomość została wysłana.<")) {
|
||||
// TODO error
|
||||
return@webGet
|
||||
}
|
||||
|
||||
// TODO create MobidziennikWebMessagesSent and replace this
|
||||
MobidziennikWebMessagesAll(data) {
|
||||
val message = data.messageIgnoreList.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, metadata?.addedDate)
|
||||
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.Mobidzie
|
||||
import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class MobidziennikFirstLogin(val data: DataMobidziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
@ -39,12 +39,11 @@ class MobidziennikFirstLogin(val data: DataMobidziennik, val onSuccess: () -> Un
|
||||
if (student1.size == 2)
|
||||
return@forEach
|
||||
|
||||
val today = Date.getToday()
|
||||
val profile = Profile()
|
||||
profile.studentNameLong = "${student1[2]} ${student1[4]}".fixName()
|
||||
profile.studentNameShort = "${student1[2]} ${student1[4][0]}.".fixName()
|
||||
profile.accountNameLong = if (accountNameLong == profile.studentNameLong) null else accountNameLong
|
||||
profile.studentSchoolYear = "${today.year}/${today.year+1}"
|
||||
profile.studentSchoolYear = Utils.getCurrentSchoolYear()
|
||||
profile.name = profile.studentNameLong
|
||||
profile.subname = data.loginUsername
|
||||
profile.empty = true
|
||||
|
@ -15,10 +15,12 @@ import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||
import pl.szczodrzynski.edziennik.data.api.templateLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -67,14 +69,26 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore,
|
||||
|
||||
}
|
||||
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
|
||||
}
|
||||
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun getRecipientList() {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
TemplateFirstLogin(data) {
|
||||
completed()
|
||||
|
@ -171,7 +171,7 @@ class DataVulcan(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
|
||||
"P02" -> "http://efeb-komunikacja.pro-hudsonrc.win.vulcan.pl"
|
||||
"P90" -> "http://efeb-komunikacja-pro-mwujakowska.neo.win.vulcan.pl"
|
||||
"FK1", "FS1" -> "http://api.fakelog.cf"
|
||||
"SZ9" -> "http://vulcan.szkolny.eu"
|
||||
"SZ9" -> "http://hack.szkolny.eu"
|
||||
else -> null
|
||||
}
|
||||
return if (url != null) "$url/$symbol" else loginStore.getLoginData("apiUrl", null)
|
||||
|
@ -6,21 +6,24 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.data.api.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_VULCAN_API
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus
|
||||
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.login.VulcanLogin
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.data.api.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.prepare
|
||||
import pl.szczodrzynski.edziennik.data.api.prepareFor
|
||||
import pl.szczodrzynski.edziennik.data.api.vulcanLoginMethods
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.AnnouncementFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
@ -30,6 +33,7 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataVulcan
|
||||
private var afterLogin: (() -> Unit)? = null
|
||||
|
||||
init {
|
||||
data = DataVulcan(app, profile, loginStore).apply {
|
||||
@ -56,18 +60,44 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?, arguments: JsonObject?) {
|
||||
data.arguments = arguments
|
||||
data.prepare(vulcanLoginMethods, VulcanFeatures, featureIds, viewId)
|
||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
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(vulcanLoginMethods, it) }
|
||||
afterLogin?.let { this.afterLogin = it }
|
||||
VulcanLogin(data) {
|
||||
VulcanData(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() ?: VulcanData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
login(LOGIN_METHOD_VULCAN_API) {
|
||||
VulcanApiMessagesChangeStatus(data, message) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(message: MessageFull) {
|
||||
VulcanLoginApi(data) {
|
||||
VulcanApiMessagesChangeStatus(data, message) {
|
||||
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
|
||||
login(LOGIN_METHOD_VULCAN_API) {
|
||||
VulcanApiSendMessage(data, recipients, subject, text) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
@ -77,16 +107,19 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
}
|
||||
|
||||
override fun getAnnouncement(announcement: AnnouncementFull) {
|
||||
|
||||
}
|
||||
|
||||
override fun getAttachment(message: Message, attachmentId: Long, attachmentName: String) {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
VulcanFirstLogin(data) {
|
||||
completed()
|
||||
}
|
||||
override fun getRecipientList() {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() { VulcanFirstLogin(data) { completed() } }
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
@ -94,29 +127,17 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|
||||
|
||||
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 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) {
|
||||
in internalErrorList -> {
|
||||
// finish immediately if the same error occurs twice during the same sync
|
||||
callback.onError(apiError)
|
||||
}
|
||||
CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> {
|
||||
internalErrorList.add(apiError.errorCode)
|
||||
loginStore.removeLoginData("refreshToken") // force a clean login
|
||||
//loginLibrus()
|
||||
}
|
||||
else -> callback.onError(apiError)
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,9 @@ open class VulcanApi(open val data: DataVulcan) {
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun apiGet(
|
||||
tag: String,
|
||||
endpoint: String,
|
||||
|
@ -9,6 +9,7 @@ import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_GRADES
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
|
||||
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
@ -109,6 +110,7 @@ class VulcanApiGrades(override val data: DataVulcan, val onSuccess: () -> Unit)
|
||||
))
|
||||
}
|
||||
|
||||
data.toRemove.add(DataRemoveModel.Grades.semesterWithType(data.studentSemesterNumber, Grade.TYPE_NORMAL))
|
||||
data.setSyncNext(ENDPOINT_VULCAN_API_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ class VulcanApiMessagesChangeStatus(
|
||||
)) { _, _ ->
|
||||
|
||||
if (!messageObject.seen) {
|
||||
data.messageMetadataList.add(Metadata(
|
||||
data.setSeenMetadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
messageObject.id,
|
||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import kotlin.text.replace
|
||||
|
||||
class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
companion object {
|
||||
@ -26,11 +27,11 @@ class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () ->
|
||||
init {
|
||||
data.profile?.also { profile ->
|
||||
|
||||
val startDate: String = when (profile.empty) {
|
||||
true -> profile.getSemesterStart(profile.currentSemester).stringY_m_d
|
||||
else -> Date.getToday().stepForward(0, -1, 0).stringY_m_d
|
||||
val startDate = when (profile.empty) {
|
||||
true -> profile.getSemesterStart(profile.currentSemester).inUnix
|
||||
else -> Date.getToday().stepForward(0, -2, 0).inUnix
|
||||
}
|
||||
val endDate: String = profile.getSemesterEnd(profile.currentSemester).stringY_m_d
|
||||
val endDate = Date.getToday().stepForward(0, 1, 0).inUnix
|
||||
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_RECEIVED, parameters = mapOf(
|
||||
"DataPoczatkowa" to startDate,
|
||||
@ -49,7 +50,7 @@ class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () ->
|
||||
|
||||
val senderName = message.getString("Nadawca") ?: ""
|
||||
|
||||
senderName.getLastFirstName()?.let { (senderLastName, senderFirstName) ->
|
||||
senderName.splitName()?.let { (senderLastName, senderFirstName) ->
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16(senderName.toByteArray()).toLong(),
|
||||
@ -71,7 +72,7 @@ class VulcanApiMessagesInbox(override val data: DataVulcan, val onSuccess: () ->
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
body,
|
||||
body.replace("\n", "<br>"),
|
||||
TYPE_RECEIVED,
|
||||
senderId,
|
||||
-1
|
||||
|
@ -17,6 +17,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import kotlin.text.replace
|
||||
|
||||
class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () -> Unit) : VulcanApi(data) {
|
||||
companion object {
|
||||
@ -25,11 +26,12 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
|
||||
init {
|
||||
data.profile?.also { profile ->
|
||||
val startDate: Long = when (profile.empty) {
|
||||
|
||||
val startDate = when (profile.empty) {
|
||||
true -> profile.getSemesterStart(profile.currentSemester).inUnix
|
||||
else -> Date.getToday().stepForward(0, -1, 0).inUnix
|
||||
else -> Date.getToday().stepForward(0, -2, 0).inUnix
|
||||
}
|
||||
val endDate: Long = profile.getSemesterEnd(profile.currentSemester).inUnix
|
||||
val endDate = Date.getToday().stepForward(0, 1, 0).inUnix
|
||||
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_SENT, parameters = mapOf(
|
||||
"DataPoczatkowa" to startDate,
|
||||
@ -54,7 +56,7 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
?: {
|
||||
val receiverName = receiver.getString("Nazwa") ?: ""
|
||||
|
||||
receiverName.getLastFirstName()?.let { (receiverLastName, receiverFirstName) ->
|
||||
receiverName.splitName()?.let { (receiverLastName, receiverFirstName) ->
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16(receiverName.toByteArray()).toLong(),
|
||||
@ -90,7 +92,7 @@ class VulcanApiMessagesSent(override val data: DataVulcan, val onSuccess: () ->
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
body,
|
||||
body.replace("\n", "<br>"),
|
||||
TYPE_SENT,
|
||||
-1,
|
||||
-1
|
||||
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-12-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_MESSAGES_ADD
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanApi
|
||||
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
class VulcanApiSendMessage(
|
||||
override val data: DataVulcan,
|
||||
val recipients: List<Teacher>,
|
||||
val subject: String,
|
||||
val text: String,
|
||||
val onSuccess: () -> Unit
|
||||
) : VulcanApi(data) {
|
||||
companion object {
|
||||
private const val TAG = "VulcanApiSendMessage"
|
||||
}
|
||||
|
||||
init {
|
||||
val recipientsArray = JsonArray()
|
||||
for (teacher in recipients) {
|
||||
teacher.loginId?.let {
|
||||
recipientsArray += JsonObject(
|
||||
"LoginId" to it,
|
||||
"Nazwa" to "${teacher.fullNameLastFirst} - pracownik"
|
||||
)
|
||||
}
|
||||
}
|
||||
val params = mapOf(
|
||||
"NadawcaWiadomosci" to (profile?.accountNameLong ?: profile?.studentNameLong ?: ""),
|
||||
"Tytul" to subject,
|
||||
"Tresc" to text,
|
||||
"Adresaci" to recipientsArray,
|
||||
"LoginId" to data.studentLoginId,
|
||||
"IdUczen" to data.studentId
|
||||
)
|
||||
|
||||
apiGet(TAG, VULCAN_API_ENDPOINT_MESSAGES_ADD, parameters = params) { json, _ ->
|
||||
val messageId = json.getJsonObject("Data").getLong("WiadomoscId")
|
||||
|
||||
if (messageId == null) {
|
||||
// TODO error
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
VulcanApiMessagesSent(data) {
|
||||
val message = data.messageIgnoreList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
|
||||
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == messageId }
|
||||
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate)
|
||||
|
||||
EventBus.getDefault().postSticky(event)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api
|
||||
|
||||
import androidx.core.util.set
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes
|
||||
import pl.szczodrzynski.edziennik.data.api.Regexes.VULCAN_SHIFT_ANNOTATION
|
||||
import pl.szczodrzynski.edziennik.data.api.VULCAN_API_ENDPOINT_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
|
||||
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_API_TIMETABLE
|
||||
@ -144,7 +144,7 @@ class VulcanApiTimetable(override val data: DataVulcan, val onSuccess: () -> Uni
|
||||
}
|
||||
|
||||
if (type == Lesson.TYPE_SHIFTED_SOURCE || type == Lesson.TYPE_SHIFTED_TARGET) {
|
||||
val shift = Regexes.VULCAN_SHITFT_ANNOTATION.find(changeAnnotation)
|
||||
val shift = VULCAN_SHIFT_ANNOTATION.find(changeAnnotation)
|
||||
val oldLessonNumber = shift?.get(2)?.toInt()
|
||||
val oldLessonDate = shift?.get(3)?.let { Date.fromd_m_Y(it) }
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user