Merge branch 'develop'

This commit is contained in:
Kuba Szczodrzyński 2020-05-17 17:52:28 +02:00
commit 9cc98fcf08
374 changed files with 11854 additions and 6507 deletions

View File

@ -145,7 +145,11 @@ dependencies {
implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true} implementation("com.github.ozodrukh:CircularReveal:2.0.1@aar") {transitive = true}
implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update implementation "com.heinrichreimersoftware:material-intro:1.5.8" // do not update
implementation "com.jaredrummler:colorpicker:1.0.2" implementation "com.jaredrummler:colorpicker:1.0.2"
implementation "com.squareup.okhttp3:okhttp:3.12.2" implementation("com.squareup.okhttp3:okhttp") {
version {
strictly "3.12.2"
}
}
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update
implementation "com.wdullaer:materialdatetimepicker:4.1.2" implementation "com.wdullaer:materialdatetimepicker:4.1.2"
implementation "com.yuyh.json:jsonviewer:1.0.6" implementation "com.yuyh.json:jsonviewer:1.0.6"
@ -201,6 +205,11 @@ dependencies {
implementation 'com.qifan.powerpermission:powerpermission:1.0.0' implementation 'com.qifan.powerpermission:powerpermission:1.0.0'
implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.0.0' implementation 'com.qifan.powerpermission:powerpermission-coroutines:1.0.0'
implementation 'com.github.kuba2k2.FSLogin:lib:master-SNAPSHOT'
implementation 'pl.droidsonroids:jspoon:1.3.2'
implementation "com.squareup.retrofit2:converter-scalars:2.8.1"
implementation "pl.droidsonroids.retrofit2:converter-jspoon:1.3.2"
} }
repositories { repositories {
mavenCentral() mavenCentral()

View File

@ -66,3 +66,4 @@
-keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; } -keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.request.** { *; }
-keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; } -keepclassmembernames class pl.szczodrzynski.edziennik.data.api.szkolny.response.** { *; }
-keepclassmembernames class pl.szczodrzynski.edziennik.ui.modules.login.LoginInfo.Platform { *; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -24,7 +24,6 @@
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:networkSecurityConfig="@xml/network_security_config" android:networkSecurityConfig="@xml/network_security_config"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:theme="@style/AppTheme.Dark" android:theme="@style/AppTheme.Dark"
android:usesCleartextTraffic="true" android:usesCleartextTraffic="true"
@ -135,9 +134,6 @@
android:configChanges="orientation|screenSize" android:configChanges="orientation|screenSize"
android:launchMode="singleTop" android:launchMode="singleTop"
android:theme="@style/AppTheme.Light" /> android:theme="@style/AppTheme.Light" />
<activity android:name=".ui.modules.login.LoginLibrusCaptchaActivity"
android:theme="@android:style/Theme.Dialog"
android:excludeFromRecents="true"/>
<activity android:name=".ui.modules.home.CounterActivity" <activity android:name=".ui.modules.home.CounterActivity"
android:theme="@style/AppTheme.Black" /> android:theme="@style/AppTheme.Black" />
<activity android:name=".ui.modules.feedback.FeedbackActivity" <activity android:name=".ui.modules.feedback.FeedbackActivity"

View File

@ -1,30 +1,11 @@
<h3>Wersja 4.0, 2020-04-19</h3> <h3>Wersja 4.2, 2020-05-16</h3>
<ul> <ul>
<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 &#x1F44F;</li> <li>Naprawiony błąd braku dostępu do Wiadomości w Librusie.</li>
<li><b>Przebudowaliśmy cały moduł synchronizacji</b>, co oznacza większą stabilność aplikacji, szybkość oraz poprawność pobieranych danych</li> <li>Vulcan: wyświetlane dane z 1 semestru w dzienniku.</li>
<li>Udoskonalony wygląd Szkolnego - sprawi, że korzystanie z aplikacji będzie jeszcze przyjemniejsze</li> <li>Odświeżone logo aplikacji.</li>
<li>Wyszukiwarka wiadomości, pozwalająca na łatwe znalezienie potrzebnej konwersacji.</li> <li>Obsługa dziennika <b>Podlaskiej Platformy Edukacyjnej</b> (Prymus).</li>
<li>Możliwość pobierania załączników do zadań domowych oraz wiadomości w każdym dzienniku.</li> <li>Poprawione liczenie i wyświetlanie niektórych rodzajów frekwencji.</li>
<li>Nowa <b>Strona główna</b> - ładniejszy wygląd oraz możliwość przestawiania kart na każdym profilu</li> <li>Nowy ekran logowania.</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 <b>Oceny</b> - z możliwością zmiany wartości plusów oraz minusów oraz wyłączenia niektórych ocen ze średniej</li>
<li>Opcja wyłączenia wybranych powiadomień z aplikacji</li>
<li>Znaczki nieprzeczytanych informacji na obrazkach profili.</li>
<br>
<br>
<li>Udoskonalone tłumaczenie na j.angielski (dzięki @Predator)</li>
<li>Nowe okienka informacji o wydarzeniach oraz lekcjach</li>
<li>Nowe, przyjemniejsze powiadomienia</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: <b>poprawione obliczanie frekwencji</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>Łatwiejsze dodawanie własnych wydarzeń</li>
<li>Poprawiliśmy synchronizację w tle na niektórych telefonach</li>
<li>Usunąłem denerwujący brak zaznaczenia w lewym menu</li>
<li>Znaczna ilość błędów z poprzednich wersji już nie występuje</li>
</ul> </ul>
<br> <br>
<br> <br>

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/ /*secret password - removed for source code publication*/
static toys AES_IV[16] = { static toys AES_IV[16] = {
0x38, 0xd4, 0x73, 0xaf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0x3b, 0xa6, 0xd4, 0x50, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat); unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -66,6 +66,7 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
val timetableManager by lazy { TimetableManager(this) } val timetableManager by lazy { TimetableManager(this) }
val eventManager by lazy { EventManager(this) } val eventManager by lazy { EventManager(this) }
val permissionManager by lazy { PermissionManager(this) } val permissionManager by lazy { PermissionManager(this) }
val attendanceManager by lazy { AttendanceManager(this) }
val db val db
get() = App.db get() = App.db
@ -100,9 +101,9 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
.followSslRedirects(true) .followSslRedirects(true)
.retryOnConnectionFailure(true) .retryOnConnectionFailure(true)
.cookieJar(cookieJar) .cookieJar(cookieJar)
.connectTimeout(20, TimeUnit.SECONDS) .connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(5, TimeUnit.SECONDS) .writeTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS) .readTimeout(30, TimeUnit.SECONDS)
builder.installHttpsSupport(this) builder.installHttpsSupport(this)
if (debugMode || BuildConfig.DEBUG) { if (debugMode || BuildConfig.DEBUG) {
@ -172,6 +173,8 @@ class App : MultiDexApplication(), Configuration.Provider, CoroutineScope {
} }
devMode = BuildConfig.DEBUG devMode = BuildConfig.DEBUG
if (BuildConfig.DEBUG)
debugMode = true
Signing.getCert(this) Signing.getCert(this)

View File

@ -1245,3 +1245,5 @@ val SwipeRefreshLayout.onScrollListener: RecyclerView.OnScrollListener
operator fun <K, V> Iterable<Pair<K, V>>.get(key: K): V? { operator fun <K, V> Iterable<Pair<K, V>>.get(key: K): V? {
return firstOrNull { it.first == key }?.second return firstOrNull { it.first == key }?.second
} }
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }

View File

@ -18,6 +18,7 @@ import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu import androidx.appcompat.widget.PopupMenu
import androidx.core.graphics.ColorUtils import androidx.core.graphics.ColorUtils
import androidx.core.view.isVisible
import androidx.lifecycle.Observer import androidx.lifecycle.Observer
import androidx.navigation.NavOptions import androidx.navigation.NavOptions
import com.danimahardhika.cafebar.CafeBar import com.danimahardhika.cafebar.CafeBar
@ -294,6 +295,13 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) mainSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar) errorSnackbar.setCoordinator(b.navView.coordinator, b.navView.bottomBar)
if (BuildConfig.VERSION_NAME.contains("nightly")) {
b.nightlyText.isVisible = true
b.nightlyText.text = "Nightly\n"+BuildConfig.VERSION_NAME.substringAfterLast(".")
}
else
b.nightlyText.isVisible = false
navLoading = true navLoading = true
b.navView.apply { b.navView.apply {

View File

@ -30,6 +30,7 @@ class ProfileConfig(val db: AppDb, val profileId: Int, rawEntries: List<ConfigEn
val grades by lazy { ProfileConfigGrades(this) } val grades by lazy { ProfileConfigGrades(this) }
val ui by lazy { ProfileConfigUI(this) } val ui by lazy { ProfileConfigUI(this) }
val sync by lazy { ProfileConfigSync(this) } val sync by lazy { ProfileConfigSync(this) }
val attendance by lazy { ProfileConfigAttendance(this) }
/* /*
val timetable by lazy { ConfigTimetable(this) } val timetable by lazy { ConfigTimetable(this) }
val grades by lazy { ConfigGrades(this) }*/ val grades by lazy { ConfigGrades(this) }*/

View File

@ -0,0 +1,30 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-4-29.
*/
package pl.szczodrzynski.edziennik.config
import pl.szczodrzynski.edziennik.config.utils.get
import pl.szczodrzynski.edziennik.config.utils.set
class ProfileConfigAttendance(private val config: ProfileConfig) {
private var mAttendancePageSelection: Int? = null
var attendancePageSelection: Int
get() { mAttendancePageSelection = mAttendancePageSelection ?: config.values.get("attendancePageSelection", 1); return mAttendancePageSelection ?: 1 }
set(value) { config.set("attendancePageSelection", value); mAttendancePageSelection = value }
private var mUseSymbols: Boolean? = null
var useSymbols: Boolean
get() { mUseSymbols = mUseSymbols ?: config.values.get("useSymbols", false); return mUseSymbols ?: false }
set(value) { config.set("useSymbols", value); mUseSymbols = value }
private var mGroupConsecutiveDays: Boolean? = null
var groupConsecutiveDays: Boolean
get() { mGroupConsecutiveDays = mGroupConsecutiveDays ?: config.values.get("groupConsecutiveDays", true); return mGroupConsecutiveDays ?: true }
set(value) { config.set("groupConsecutiveDays", value); mGroupConsecutiveDays = value }
private var mShowPresenceInMonth: Boolean? = null
var showPresenceInMonth: Boolean
get() { mShowPresenceInMonth = mShowPresenceInMonth ?: config.values.get("showPresenceInMonth", false); return mShowPresenceInMonth ?: false }
set(value) { config.set("showPresenceInMonth", value); mShowPresenceInMonth = value }
}

View File

@ -57,6 +57,7 @@ const val LIBRUS_MESSAGES_URL = "https://wiadomosci.librus.pl/module"
const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action=" const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action="
const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile" const val LIBRUS_SYNERGIA_HOMEWORK_ATTACHMENT_URL = "https://synergia.librus.pl/homework/downloadFile"
const val LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL = "https://synergia.librus.pl/wiadomosci/pobierz_zalacznik"
const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT
const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik" const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik"
@ -113,5 +114,11 @@ const val VULCAN_API_ENDPOINT_MESSAGES_ADD = "mobile-api/Uczen.v3.Uczen/DodajWia
const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken" const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"
const val VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/WiadomosciZalacznik" const val VULCAN_API_ENDPOINT_MESSAGES_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/WiadomosciZalacznik"
const val VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ZadaniaDomoweZalacznik" const val VULCAN_API_ENDPOINT_HOMEWORK_ATTACHMENTS = "mobile-api/Uczen.v3.Uczen/ZadaniaDomoweZalacznik"
const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers"
const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get"
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}" const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"
const val PODLASIE_API_VERSION = "1.0.31"
const val PODLASIE_API_URL = "https://cpdklaser.zeto.bialystok.pl/api"
const val PODLASIE_API_USER_ENDPOINT = "/pobierzDaneUcznia"

View File

@ -127,6 +127,7 @@ const val ERROR_LIBRUS_API_DEVICE_REGISTERED = 185
const val ERROR_LIBRUS_MESSAGES_NOT_FOUND = 186 const val ERROR_LIBRUS_MESSAGES_NOT_FOUND = 186
const val ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST = 187 const val ERROR_LOGIN_LIBRUS_API_INVALID_REQUEST = 187
const val ERROR_LIBRUS_MESSAGES_ATTACHMENT_NOT_FOUND = 188 const val ERROR_LIBRUS_MESSAGES_ATTACHMENT_NOT_FOUND = 188
const val ERROR_LOGIN_LIBRUS_MESSAGES_TIMEOUT = 189
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201 const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202 const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202
@ -159,6 +160,16 @@ const val ERROR_VULCAN_API_MAINTENANCE = 340
const val ERROR_VULCAN_API_BAD_REQUEST = 341 const val ERROR_VULCAN_API_BAD_REQUEST = 341
const val ERROR_VULCAN_API_OTHER = 342 const val ERROR_VULCAN_API_OTHER = 342
const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343 const val ERROR_VULCAN_ATTACHMENT_DOWNLOAD = 343
const val ERROR_VULCAN_WEB_DATA_MISSING = 344
const val ERROR_VULCAN_WEB_429 = 345
const val ERROR_VULCAN_WEB_OTHER = 346
const val ERROR_VULCAN_WEB_NO_CERTIFICATE = 347
const val ERROR_VULCAN_WEB_NO_REGISTER = 348
const val ERROR_VULCAN_WEB_CERTIFICATE_EXPIRED = 349
const val ERROR_VULCAN_WEB_LOGGED_OUT = 350
const val ERROR_VULCAN_WEB_CERTIFICATE_POST_FAILED = 351
const val ERROR_VULCAN_WEB_GRADUATE_ACCOUNT = 352
const val ERROR_VULCAN_WEB_NO_SCHOOLS = 353
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402 const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
@ -189,6 +200,12 @@ const val ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS = 521
const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522 const val ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED = 522
const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530 const val ERROR_EDUDZIENNIK_WEB_TEAM_MISSING = 530
const val ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN = 601
const val ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT = 602
const val ERROR_PODLASIE_API_NO_TOKEN = 630
const val ERROR_PODLASIE_API_OTHER = 631
const val ERROR_PODLASIE_API_DATA_MISSING = 632
const val ERROR_TEMPLATE_WEB_OTHER = 801 const val ERROR_TEMPLATE_WEB_OTHER = 801
const val EXCEPTION_API_TASK = 900 const val EXCEPTION_API_TASK = 900
@ -209,5 +226,8 @@ const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920 const val EXCEPTION_EDUDZIENNIK_WEB_REQUEST = 920
const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921 const val EXCEPTION_EDUDZIENNIK_FILE_REQUEST = 921
const val ERROR_ONEDRIVE_DOWNLOAD = 930 const val ERROR_ONEDRIVE_DOWNLOAD = 930
const val EXCEPTION_VULCAN_WEB_LOGIN = 931
const val EXCEPTION_VULCAN_WEB_REQUEST = 932
const val EXCEPTION_PODLASIE_API_REQUEST = 940
const val LOGIN_NO_ARGUMENTS = 1201 const val LOGIN_NO_ARGUMENTS = 1201

View File

@ -13,9 +13,11 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginPor
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginSynergia import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLoginSynergia
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginApi2 import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginApi2
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.login.MobidziennikLoginWeb
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLoginApi
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginApi
import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb import pl.szczodrzynski.edziennik.data.api.edziennik.template.login.TemplateLoginWeb
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginApi
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLoginWebMain
import pl.szczodrzynski.edziennik.data.api.models.LoginMethod import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
// librus // librus
@ -27,7 +29,6 @@ import pl.szczodrzynski.edziennik.data.api.models.LoginMethod
const val SYNERGIA_API_ENABLED = false const val SYNERGIA_API_ENABLED = false
const val LOGIN_TYPE_IDZIENNIK = 3 const val LOGIN_TYPE_IDZIENNIK = 3
const val LOGIN_TYPE_TEMPLATE = 21 const val LOGIN_TYPE_TEMPLATE = 21
@ -103,11 +104,11 @@ const val LOGIN_METHOD_VULCAN_WEB_OLD = 300
const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400 const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400
const val LOGIN_METHOD_VULCAN_API = 500 const val LOGIN_METHOD_VULCAN_API = 500
val vulcanLoginMethods = listOf( val vulcanLoginMethods = listOf(
/*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java) LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java)
.withIsPossible { _, _ -> false } .withIsPossible { _, loginStore -> loginStore.hasLoginData("webHost") }
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }, .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java) /*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java)
.withIsPossible { _, _ -> false } .withIsPossible { _, _ -> false }
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN }, .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },
@ -118,7 +119,7 @@ val vulcanLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java) LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java)
.withIsPossible { _, _ -> true } .withIsPossible { _, _ -> true }
.withRequiredLoginMethod { _, loginStore -> .withRequiredLoginMethod { _, loginStore ->
if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_NEW else LOGIN_METHOD_NOT_NEEDED if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_MAIN else LOGIN_METHOD_NOT_NEEDED
} }
) )
@ -133,6 +134,7 @@ val idziennikLoginMethods = listOf(
) )
const val LOGIN_TYPE_EDUDZIENNIK = 5 const val LOGIN_TYPE_EDUDZIENNIK = 5
const val LOGIN_MODE_EDUDZIENNIK_WEB = 0
const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100 const val LOGIN_METHOD_EDUDZIENNIK_WEB = 100
val edudziennikLoginMethods = listOf( val edudziennikLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java) LoginMethod(LOGIN_TYPE_EDUDZIENNIK, LOGIN_METHOD_EDUDZIENNIK_WEB, EdudziennikLoginWeb::class.java)
@ -140,6 +142,15 @@ val edudziennikLoginMethods = listOf(
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
) )
const val LOGIN_TYPE_PODLASIE = 6
const val LOGIN_MODE_PODLASIE_API = 0
const val LOGIN_METHOD_PODLASIE_API = 100
val podlasieLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_PODLASIE, LOGIN_METHOD_PODLASIE_API, PodlasieLoginApi::class.java)
.withIsPossible { _, _ -> true }
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }
)
val templateLoginMethods = listOf( val templateLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java) LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
.withIsPossible { _, _ -> true } .withIsPossible { _, _ -> true }

View File

@ -68,6 +68,9 @@ object Regexes {
} }
val MOBIDZIENNIK_ATTENDANCE_TYPES by lazy {
"""Legenda:.+?normal;">(.+?)</span>""".toRegex(DOT_MATCHES_ALL)
}
val MOBIDZIENNIK_ATTENDANCE_TABLE by lazy { val MOBIDZIENNIK_ATTENDANCE_TABLE by lazy {
"""<table .+?id="obecnosci_tabela">(.+?)</table>""".toRegex(DOT_MATCHES_ALL) """<table .+?id="obecnosci_tabela">(.+?)</table>""".toRegex(DOT_MATCHES_ALL)
} }
@ -81,7 +84,7 @@ object Regexes {
"""<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL) """<span>([0-9:]+) - .+? (.+?)</span></a>""".toRegex(DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_ATTENDANCE_LESSON by lazy { val MOBIDZIENNIK_ATTENDANCE_LESSON by lazy {
"""<strong>(.+?) - (.*?)</strong>.+?<small>.+?\((.+?), .+?(.+?)\)""".toRegex(DOT_MATCHES_ALL) """<strong>(.+?)</strong>\s*<small>\s*\((.+?),\s*(.+?)\)""".toRegex(DOT_MATCHES_ALL)
} }
val MOBIDZIENNIK_HOMEWORK_ROW by lazy { val MOBIDZIENNIK_HOMEWORK_ROW by lazy {
@ -139,12 +142,21 @@ object Regexes {
val VULCAN_SHIFT_ANNOTATION by lazy { val VULCAN_SHIFT_ANNOTATION by lazy {
"""\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex() """\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
} }
val VULCAN_WEB_PERMISSIONS by lazy {
"""permissions: '([A-z0-9/=+\-_]+?)'""".toRegex()
}
val VULCAN_WEB_SYMBOL_VALIDATE by lazy {
"""[A-z0-9]+""".toRegex(IGNORE_CASE)
}
val LIBRUS_ATTACHMENT_KEY by lazy { val LIBRUS_ATTACHMENT_KEY by lazy {
"""singleUseKey=([0-9A-z_]+)""".toRegex() """singleUseKey=([0-9A-z_]+)""".toRegex()
} }
val LIBRUS_MESSAGE_ID by lazy {
"""/wiadomosci/[0-9]+/[0-9]+/([0-9]+?)/""".toRegex()
}

View File

@ -12,6 +12,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.Edudziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.Idziennik import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.Idziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.Librus
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.Mobidziennik
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.Podlasie
import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template import pl.szczodrzynski.edziennik.data.api.edziennik.template.Template
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.Vulcan
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
@ -19,6 +20,7 @@ import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.api.task.IApiTask import pl.szczodrzynski.edziennik.data.api.task.IApiTask
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull import pl.szczodrzynski.edziennik.data.db.full.EventFull
@ -28,6 +30,9 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
companion object { companion object {
private const val TAG = "EdziennikTask" private const val TAG = "EdziennikTask"
var profile: Profile? = null
var loginStore: LoginStore? = null
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore)) fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
fun sync() = EdziennikTask(-1, SyncRequest()) fun sync() = EdziennikTask(-1, SyncRequest())
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null, onlyEndpoints: List<Int>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments)) fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null, onlyEndpoints: List<Int>? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments))
@ -59,6 +64,8 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
// save the profile ID and name as the current task's // save the profile ID and name as the current task's
taskName = app.getString(R.string.edziennik_notification_api_sync_title_format, profile.name) taskName = app.getString(R.string.edziennik_notification_api_sync_title_format, profile.name)
} }
EdziennikTask.profile = this.profile
EdziennikTask.loginStore = this.loginStore
} }
private var edziennikInterface: EdziennikInterface? = null private var edziennikInterface: EdziennikInterface? = null
@ -74,6 +81,7 @@ open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTa
LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback) LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
LOGIN_TYPE_IDZIENNIK -> Idziennik(app, profile, loginStore, taskCallback) LOGIN_TYPE_IDZIENNIK -> Idziennik(app, profile, loginStore, taskCallback)
LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(app, profile, loginStore, taskCallback) LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(app, profile, loginStore, taskCallback)
LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback) LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback)
else -> null else -> null
} }

View File

@ -45,24 +45,25 @@ class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
val addedDate = Date.fromIsoHm(dateString) val addedDate = Date.fromIsoHm(dateString)
val announcementObject = Announcement( val announcementObject = Announcement(
profileId, profileId = profileId,
id, id = id,
subject, subject = subject,
null, text = null,
startDate, startDate = startDate,
null, endDate = null,
teacher.id, teacherId = teacher.id,
longId addedDate = addedDate
) ).also {
it.idString = longId
}
data.announcementIgnoreList.add(announcementObject) data.announcementList.add(announcementObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }
} }

View File

@ -39,12 +39,12 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map { val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map {
val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim()) val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim())
val symbol = type?.get(1)?.trim() val symbol = type?.get(1)?.trim() ?: "?"
val name = type?.get(2)?.trim() val name = type?.get(2)?.trim() ?: "nieznany rodzaj"
return@map Triple( return@map Triple(
symbol, symbol,
name, name,
when (name?.toLowerCase(Locale.ROOT)) { when (name.toLowerCase(Locale.ROOT)) {
"obecność" -> Attendance.TYPE_PRESENT "obecność" -> Attendance.TYPE_PRESENT
"nieobecność" -> Attendance.TYPE_ABSENT "nieobecność" -> Attendance.TYPE_ABSENT
"spóźnienie" -> Attendance.TYPE_BELATED "spóźnienie" -> Attendance.TYPE_BELATED
@ -52,7 +52,7 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
"dzień wolny" -> Attendance.TYPE_DAY_FREE "dzień wolny" -> Attendance.TYPE_DAY_FREE
"brak zajęć" -> Attendance.TYPE_DAY_FREE "brak zajęć" -> Attendance.TYPE_DAY_FREE
"oddelegowany" -> Attendance.TYPE_RELEASED "oddelegowany" -> Attendance.TYPE_RELEASED
else -> Attendance.TYPE_CUSTOM else -> Attendance.TYPE_UNKNOWN
} }
) )
} ?: emptyList() } ?: emptyList()
@ -62,38 +62,42 @@ class EdudziennikWebAttendance(override val data: DataEdudziennik,
val lessonNumber = attendanceElement[2].toInt() val lessonNumber = attendanceElement[2].toInt()
val attendanceSymbol = attendanceElement[3] val attendanceSymbol = attendanceElement[3]
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date) val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber } val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber }
val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32() val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32()
val (_, name, type) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol } val (typeSymbol, typeName, baseType) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol }
?: return@forEach ?: return@forEach
val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime
?: return@forEach ?: return@forEach
val attendanceObject = Attendance( val attendanceObject = Attendance(
profileId, profileId = profileId,
id, id = id,
lesson?.displayTeacherId ?: -1, baseType = baseType,
lesson?.displaySubjectId ?: -1, typeName = typeName,
profile.currentSemester, typeShort = data.app.attendanceManager.getTypeShort(baseType),
name, typeSymbol = typeSymbol,
date, typeColor = null,
lesson?.displayStartTime ?: startTime, date = date,
type startTime = lesson?.displayStartTime ?: startTime,
) semester = profile.currentSemester,
teacherId = lesson?.displayTeacherId ?: -1,
subjectId = lesson?.displaySubjectId ?: -1
).also {
it.lessonNumber = lessonNumber
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if(type != Attendance.TYPE_PRESENT) { if (baseType != Attendance.TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
profile.empty, profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
profile.empty, profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -57,8 +57,7 @@ class EdudziennikWebEvents(override val data: DataEdudziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -46,7 +46,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
if (dateString.isBlank()) return@forEach if (dateString.isBlank()) return@forEach
val date = Date.fromY_m_d(dateString) val date = Date.fromY_m_d(dateString)
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date) val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime
val eventTypeElement = examElement.child(3).child(0) val eventTypeElement = examElement.child(3).child(0)
@ -74,8 +74,7 @@ class EdudziennikWebExams(override val data: DataEdudziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -126,7 +126,8 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacher.id, teacherId = teacher.id,
subjectId = subject.id subjectId = subject.id,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -135,8 +136,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }
@ -168,8 +168,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
proposedGradeObject.id, proposedGradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
@ -201,8 +200,7 @@ class EdudziennikWebGrades(override val data: DataEdudziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
finalGradeObject.id, finalGradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -43,7 +43,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
val subjectName = subjectElement.text() val subjectName = subjectElement.text()
val subject = data.getSubject(subjectId, subjectName) val subject = data.getSubject(subjectId, subjectName)
val lessons = data.app.db.timetableDao().getForDateNow(profileId, date) val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
val teacherName = homeworkElement.child(2).text() val teacherName = homeworkElement.child(2).text()
@ -72,8 +72,7 @@ class EdudziennikWebHomework(override val data: DataEdudziennik,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -24,9 +24,9 @@ class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text -> webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text ->
text.toIntOrNull()?.also { luckyNumber -> text.toIntOrNull()?.also { luckyNumber ->
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
profileId, profileId = profileId,
Date.getToday(), date = Date.getToday(),
luckyNumber number = luckyNumber
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -35,8 +35,7 @@ class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }

View File

@ -41,12 +41,15 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
val description = noteElement.child(3).text() val description = noteElement.child(3).text()
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
id, id = id,
description, type = Notice.TYPE_NEUTRAL,
profile.currentSemester, semester = profile.currentSemester,
Notice.TYPE_NEUTRAL, text = description,
teacher.id category = null,
points = null,
teacherId = teacher.id,
addedDate = addedDate
) )
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
@ -55,8 +58,7 @@ class EdudziennikWebNotes(override val data: DataEdudziennik,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -124,8 +124,7 @@ class EdudziennikWebTimetable(override val data: DataEdudziennik,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -59,7 +59,7 @@ class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit
profileList.add(profile) profileList.add(profile)
} }
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore)) EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
onSuccess() onSuccess()
} }
} }

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-14
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.helper
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.FileCallbackHandler
import pl.szczodrzynski.edziennik.data.api.ERROR_FILE_DOWNLOAD
import pl.szczodrzynski.edziennik.data.api.ERROR_REQUEST_FAILURE
import pl.szczodrzynski.edziennik.data.api.SYSTEM_USER_AGENT
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils
import java.io.File
class DownloadAttachment(
fileUrl: String,
val onSuccess: (file: File) -> Unit,
val onProgress: (written: Long, total: Long) -> Unit,
val onError: (apiError: ApiError) -> Unit
) {
companion object {
private const val TAG = "DownloadAttachment"
}
init {
val targetFile = Utils.getStorageDir()
val callback = object : FileCallbackHandler(targetFile) {
override fun onSuccess(file: File?, response: Response?) {
if (file == null) {
onError(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withResponse(response))
return
}
try {
onSuccess(file)
} catch (e: Exception) {
onError(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withResponse(response)
.withThrowable(e))
}
}
override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
try {
this@DownloadAttachment.onProgress(bytesWritten, bytesTotal)
} catch (e: Exception) {
onError(ApiError(TAG, ERROR_FILE_DOWNLOAD)
.withThrowable(e))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
Request.builder()
.url(fileUrl)
.userAgent(SYSTEM_USER_AGENT)
.callback(callback)
.build()
.enqueue()
}
}

View File

@ -68,9 +68,9 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
data.profileId, profileId = data.profileId,
luckyNumberDate, date = luckyNumberDate,
luckyNumber number = luckyNumber
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -80,8 +80,7 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -69,7 +69,8 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED, type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
subject = subject, subject = subject,
body = body, body = body,
senderId = rTeacher.id senderId = rTeacher.id,
addedDate = sentDate
) )
val messageRecipient = MessageRecipient( val messageRecipient = MessageRecipient(
@ -87,8 +88,7 @@ class IdziennikApiMessagesInbox(override val data: DataIdziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
readDate > 0, readDate > 0,
readDate > 0 || profile?.empty ?: false, readDate > 0 || profile?.empty ?: false
sentDate
)) ))
} }

View File

@ -51,7 +51,8 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
type = TYPE_SENT, type = TYPE_SENT,
subject = subject, subject = subject,
body = body, body = body,
senderId = null senderId = null,
addedDate = sentDate
) )
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) { for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
@ -76,7 +77,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
} }
data.messageList.add(message) data.messageList.add(message)
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate)) data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true))
} }
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES) data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)

View File

@ -52,14 +52,14 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) } val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) }
val announcementObject = Announcement( val announcementObject = Announcement(
profileId, profileId = profileId,
announcementId, id = announcementId,
jAnnouncement.get("Temat").asString, subject = jAnnouncement.get("Temat").asString,
jAnnouncement.get("Tresc").asString, text = jAnnouncement.get("Tresc").asString,
startDate, startDate = startDate,
null, endDate = null,
rTeacher.id, teacherId = rTeacher.id,
null addedDate = addedDate
) )
data.announcementList.add(announcementObject) data.announcementList.add(announcementObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
@ -67,8 +67,7 @@ class IdziennikWebAnnouncements(override val data: DataIdziennik,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
announcementObject.id, announcementObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate
)) ))
} }

View File

@ -12,10 +12,18 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNI
import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb 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.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.* import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_BELATED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT_CUSTOM
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time import pl.szczodrzynski.edziennik.utils.models.Time
@ -51,71 +59,97 @@ class IdziennikWebAttendance(override val data: DataIdziennik,
for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) { for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) {
val jAttendance = jAttendanceEl.asJsonObject val jAttendance = jAttendanceEl.asJsonObject
// jAttendance // jAttendance
val attendanceTypeIdziennik = jAttendance.get("TypObecnosci").asInt val type = jAttendance.get("TypObecnosci").asInt
if (attendanceTypeIdziennik == 5 || attendanceTypeIdziennik == 7)
continue // skip "zajęcia nie odbyły się" and "Ferie"
val attendanceDate = Date.fromY_m_d(jAttendance.get("Data").asString) if (type == 5 || type == 7)
val attendanceTime = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
if (attendanceDate.combineWith(attendanceTime) > System.currentTimeMillis())
continue continue
val attendanceId = jAttendance.get("IdLesson").asString.crc16().toLong() val date = Date.fromY_m_d(jAttendance.get("Data").asString)
val time = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
if (date.combineWith(time) > System.currentTimeMillis())
continue
val id = jAttendance.get("IdLesson").asString.crc16().toLong()
val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "") val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "")
val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString) val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString)
var attendanceName = "obecność" var baseType = TYPE_UNKNOWN
var attendanceType = Attendance.TYPE_CUSTOM var typeName = "nieznany rodzaj"
var typeSymbol: String? = null
var typeColor: Long? = null
when (attendanceTypeIdziennik) { /* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosciUcznia_lmt637231494660000000.js */
1 /* nieobecność usprawiedliwiona */ -> { /* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosci_lmt637231494660000000.css */
attendanceName = "nieobecność usprawiedliwiona" when (type) {
attendanceType = TYPE_ABSENT_EXCUSED 1 -> {
baseType = TYPE_ABSENT_EXCUSED
typeName = "nieobecność usprawiedliwiona"
typeColor = 0xffffe099
} }
2 /* spóźnienie */ -> { 2 -> {
attendanceName = "spóźnienie" baseType = TYPE_BELATED
attendanceType = TYPE_BELATED typeName = "spóźnienie"
typeColor = 0xffffffaa
} }
3 /* nieobecność nieusprawiedliwiona */ -> { 3 -> {
attendanceName = "nieobecność nieusprawiedliwiona" baseType = TYPE_ABSENT
attendanceType = TYPE_ABSENT typeName = "nieobecność nieusprawiedliwiona"
typeColor = 0xffffad99
} }
4 /* zwolnienie */, 9 /* zwolniony / obecny */ -> { 4, 9 -> {
attendanceType = TYPE_RELEASED baseType = TYPE_RELEASED
if (attendanceTypeIdziennik == 4) if (type == 4) {
attendanceName = "zwolnienie" typeName = "zwolnienie"
if (attendanceTypeIdziennik == 9) typeColor = 0xffa8beff
attendanceName = "zwolnienie / obecność"
} }
0 /* obecny */, 8 /* Wycieczka */ -> { if (type == 9) {
attendanceType = TYPE_PRESENT typeName = "zwolniony / obecny"
if (attendanceTypeIdziennik == 8) typeSymbol = "zb"
attendanceName = "wycieczka" typeColor = 0xffff69b4
}
}
8 -> {
baseType = TYPE_PRESENT_CUSTOM
typeName = "wycieczka"
typeSymbol = "w"
typeColor = null
}
0 -> {
baseType = TYPE_PRESENT
typeName = "obecny"
typeColor = 0xffccffcc
} }
} }
val semester = profile?.dateToSemester(attendanceDate) ?: 1 val semester = profile?.dateToSemester(date) ?: 1
val attendanceObject = Attendance( val attendanceObject = Attendance(
profileId, profileId = profileId,
attendanceId, id = id,
rTeacher.id, baseType = baseType,
rSubject.id, typeName = typeName,
semester, typeShort = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
attendanceName, typeSymbol = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
attendanceDate, typeColor = typeColor?.toInt(),
attendanceTime, date = date,
attendanceType startTime = time,
) semester = semester,
teacherId = rTeacher.id,
subjectId = rSubject.id
).also {
it.lessonTopic = jAttendance.getString("PrzedmiotTemat")
it.lessonNumber = jAttendance.getInt("Godzina")
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if (attendanceObject.type != TYPE_PRESENT) { if (attendanceObject.baseType != TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
attendanceObject.id, attendanceObject.id,
profile?.empty ?: false, profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
profile?.empty ?: false, profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -68,7 +68,7 @@ class IdziennikWebExams(override val data: DataIdziennik,
val teacherId = data.getTeacherByLastFirst(teacherName).id val teacherId = data.getTeacherByLastFirst(teacherName).id
val topic = exam.getString("zakres")?.trim() ?: "" val topic = exam.getString("zakres")?.trim() ?: ""
val lessonList = data.db.timetableDao().getForDateNow(profileId, examDate) val lessonList = data.db.timetableDao().getAllForDateNow(profileId, examDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) { val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) {
@ -98,8 +98,7 @@ class IdziennikWebExams(override val data: DataIdziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
eventObject.id, eventObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -94,8 +94,7 @@ class IdziennikWebGetMessage(override val data: DataIdziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
message.seen, message.seen,
message.notified, message.notified
message.addedDate
)) ))
} }

View File

@ -63,6 +63,8 @@ class IdziennikWebGrades(override val data: DataIdziennik,
colorInt = Color.parseColor("#$gradeColor") colorInt = Color.parseColor("#$gradeColor")
} }
val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
val gradeObject = Grade( val gradeObject = Grade(
profileId = profileId, profileId = profileId,
id = id, id = id,
@ -76,7 +78,9 @@ class IdziennikWebGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacher.id, teacherId = teacher.id,
subjectId = subject.id) subjectId = subject.id,
addedDate = addedDate
)
when (grade.getInt("Typ")) { when (grade.getInt("Typ")) {
0 -> { 0 -> {
@ -100,6 +104,8 @@ class IdziennikWebGrades(override val data: DataIdziennik,
colorInt = Color.parseColor("#$historyColor") colorInt = Color.parseColor("#$historyColor")
} }
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
val historyObject = Grade( val historyObject = Grade(
profileId = profileId, profileId = profileId,
id = gradeObject.id * -1, id = gradeObject.id * -1,
@ -113,19 +119,18 @@ class IdziennikWebGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = historyItem.getInt("Semestr") ?: 1, semester = historyItem.getInt("Semestr") ?: 1,
teacherId = teacher.id, teacherId = teacher.id,
subjectId = subject.id) subjectId = subject.id,
addedDate = addedDate
)
historyObject.parentId = gradeObject.id historyObject.parentId = gradeObject.id
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
data.gradeList.add(historyObject) data.gradeList.add(historyObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
historyObject.id, historyObject.id,
true, true,
true, true
addedDate
)) ))
} }
// update the current grade's value with an average of all historical grades and itself // update the current grade's value with an average of all historical grades and itself
@ -147,8 +152,6 @@ class IdziennikWebGrades(override val data: DataIdziennik,
} }
} }
val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
data.metadataList.add( data.metadataList.add(
Metadata( Metadata(
@ -156,8 +159,7 @@ class IdziennikWebGrades(override val data: DataIdziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
data.profile.empty, data.profile.empty,
data.profile.empty, data.profile.empty
addedDate
)) ))
} }
} }

View File

@ -57,7 +57,7 @@ class IdziennikWebHomework(override val data: DataIdziennik,
val subjectId = data.getSubject(subjectName, null, subjectName).id val subjectId = data.getSubject(subjectName, null, subjectName).id
val teacherName = homework.getString("usr") ?: return@forEach val teacherName = homework.getString("usr") ?: return@forEach
val teacherId = data.getTeacherByLastFirst(teacherName).id val teacherId = data.getTeacherByLastFirst(teacherName).id
val lessonList = data.db.timetableDao().getForDateNow(profileId, eventDate) val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
val topic = homework.getString("tytul")?.trim() ?: "" val topic = homework.getString("tytul")?.trim() ?: ""
@ -77,7 +77,8 @@ class IdziennikWebHomework(override val data: DataIdziennik,
type = Event.TYPE_HOMEWORK, type = Event.TYPE_HOMEWORK,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = data.teamClass?.id ?: -1 teamId = data.teamClass?.id ?: -1,
addedDate = addedDate.inMillis
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -86,8 +87,7 @@ class IdziennikWebHomework(override val data: DataIdziennik,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
eventObject.id, eventObject.id,
seen, seen,
seen, seen
addedDate.inMillis
)) ))
} }

View File

@ -13,9 +13,12 @@ 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.ApiError
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Notice import pl.szczodrzynski.edziennik.data.db.entity.Notice
import pl.szczodrzynski.edziennik.data.db.entity.Notice.* import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEGATIVE
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEUTRAL
import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_POSITIVE
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.getJsonObject import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
class IdziennikWebNotices(override val data: DataIdziennik, class IdziennikWebNotices(override val data: DataIdziennik,
@ -53,20 +56,24 @@ class IdziennikWebNotices(override val data: DataIdziennik,
} }
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
noticeId, id = noticeId,
jNotice.get("Tresc").asString, type = nType,
jNotice.get("Semestr").asInt, semester = jNotice.get("Semestr").asInt,
nType, text = jNotice.getString("Tresc") ?: "",
rTeacher.id) category = null,
points = null,
teacherId = rTeacher.id,
addedDate = addedDate.inMillis
)
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
noticeObject.id, noticeObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate.inMillis
)) ))
} }

View File

@ -76,6 +76,11 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
else -1 else -1
if (semester1Proposed != "") { if (semester1Proposed != "") {
val addedDate = if (data.profile.empty)
data.profile.dateSemester1Start.inMillis
else
System.currentTimeMillis()
val gradeObject = Grade( val gradeObject = Grade(
profileId = profileId, profileId = profileId,
id = semester1Id, id = semester1Id,
@ -89,26 +94,26 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = 1, semester = 1,
teacherId = -1, teacherId = -1,
subjectId = subjectObject.id subjectId = subjectObject.id,
addedDate = addedDate
) )
val addedDate = if (data.profile.empty)
data.profile.dateSemester1Start.inMillis
else
System.currentTimeMillis()
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }
if (semester2Proposed != "") { if (semester2Proposed != "") {
val addedDate = if (data.profile.empty)
data.profile.dateSemester2Start.inMillis
else
System.currentTimeMillis()
val gradeObject = Grade( val gradeObject = Grade(
profileId = profileId, profileId = profileId,
id = semester2Id, id = semester2Id,
@ -122,22 +127,17 @@ class IdziennikWebProposedGrades(override val data: DataIdziennik,
comment = null, comment = null,
semester = 2, semester = 2,
teacherId = -1, teacherId = -1,
subjectId = subjectObject.id subjectId = subjectObject.id,
addedDate = addedDate
) )
val addedDate = if (data.profile.empty)
data.profile.dateSemester2Start.inMillis
else
System.currentTimeMillis()
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }
} }

View File

@ -59,7 +59,7 @@ class IdziennikWebSendMessage(override val data: DataIdziennik,
IdziennikApiMessagesSent(data, null) { IdziennikApiMessagesSent(data, null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -165,8 +165,7 @@ class IdziennikWebTimetable(override val data: DataIdziennik,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -89,7 +89,7 @@ class IdziennikFirstLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
profileList.add(profile) profileList.add(profile)
} }
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore)) EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
onSuccess() onSuccess()
} }
} }

View File

@ -74,9 +74,9 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also { Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also {
val number = it[1].toIntOrNull() ?: return@also val number = it[1].toIntOrNull() ?: return@also
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
data.profileId, profileId = data.profileId,
Date.getToday(), date = Date.getToday(),
number number = number
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -86,8 +86,7 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
profile.empty, profile.empty
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -120,7 +120,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiLogin: String? = null private var mApiLogin: String? = null
var apiLogin: String? var apiLogin: String?
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin } get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
set(value) { profile?.putStudentData("accountLogin", value) ?: return; mApiLogin = value } set(value) { profile?.putStudentData("accountLogin", value); mApiLogin = value }
/** /**
* A Synergia password. * A Synergia password.
* Used: for login (API Login Method) in Synergia mode. * Used: for login (API Login Method) in Synergia mode.
@ -129,7 +129,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPassword: String? = null private var mApiPassword: String? = null
var apiPassword: String? var apiPassword: String?
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword } get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
set(value) { profile?.putStudentData("accountPassword", value) ?: return; mApiPassword = value } set(value) { profile?.putStudentData("accountPassword", value); mApiPassword = value }
/** /**
* A JST login Code. * A JST login Code.
@ -138,8 +138,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiCode: String? = null private var mApiCode: String? = null
var apiCode: String? var apiCode: String?
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode } get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
set(value) { set(value) { profile?.putStudentData("accountCode", value); mApiCode = value }
loginStore.putLoginData("accountCode", value); mApiCode = value }
/** /**
* A JST login PIN. * A JST login PIN.
* Used only during first login in JST mode. * Used only during first login in JST mode.
@ -147,8 +146,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPin: String? = null private var mApiPin: String? = null
var apiPin: String? var apiPin: String?
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin } get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
set(value) { set(value) { profile?.putStudentData("accountPin", value); mApiPin = value }
loginStore.putLoginData("accountPin", value); mApiPin = value }
/** /**
* A Synergia API access token. * A Synergia API access token.
@ -277,4 +275,10 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
var timetableNotPublic: Boolean var timetableNotPublic: Boolean
get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false } get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value } set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
/**
* Set to false when Recaptcha helper doesn't provide a working token.
* When it's set to false uses Synergia for messages.
*/
var messagesLoginSuccessful: Boolean = true
} }

View File

@ -13,9 +13,7 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.Librus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetMessage import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetMessage
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetRecipientList import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetRecipientList
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesSendMessage import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesSendMessage
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaGetHomework import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomeworkGetAttachment
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin import pl.szczodrzynski.edziennik.data.api.edziennik.librus.firstlogin.LibrusFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin import pl.szczodrzynski.edziennik.data.api.edziennik.librus.login.LibrusLogin
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
@ -91,9 +89,8 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
override fun getMessage(message: MessageFull) { override fun getMessage(message: MessageFull) {
login(LOGIN_METHOD_LIBRUS_MESSAGES) { login(LOGIN_METHOD_LIBRUS_MESSAGES) {
LibrusMessagesGetMessage(data, message) { if (data.messagesLoginSuccessful) LibrusMessagesGetMessage(data, message) { completed() }
completed() else LibrusSynergiaGetMessage(data, message) { completed() }
}
} }
} }
@ -124,10 +121,9 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) { override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
when (owner) { when (owner) {
is Message -> { is Message -> {
login(LOGIN_METHOD_LIBRUS_MESSAGES) { login(LOGIN_METHOD_LIBRUS_SYNERGIA) {
LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) { if (data.messagesLoginSuccessful) LibrusMessagesGetAttachment(data, owner, attachmentId, attachmentName) { completed() }
completed() LibrusSynergiaGetAttachment(data, owner, attachmentId, attachmentName) { completed() }
}
} }
} }
is EventFull -> { is EventFull -> {

View File

@ -50,6 +50,8 @@ const val ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS = 1130
const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010 const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020 const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020
const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030 const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030
const val ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_RECEIVED = 2040
const val ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_SENT = 2050
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010 const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020 const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030 const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030

View File

@ -0,0 +1,56 @@
/*
* Copyright (c) Kuba Szczodrzyński 2020-5-8.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.librus
import android.content.Context
import android.webkit.WebView
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import pl.szczodrzynski.edziennik.startCoroutineTimer
import kotlin.coroutines.CoroutineContext
class LibrusRecaptchaHelper(
val context: Context,
url: String,
html: String,
val onSuccess: (url: String) -> Unit,
val onTimeout: () -> Unit
) : CoroutineScope {
companion object {
private const val TAG = "LibrusRecaptchaHelper"
}
private val job: Job = Job()
override val coroutineContext: CoroutineContext
get() = job + Dispatchers.Default
private val webView by lazy {
WebView(context).also {
it.settings.javaScriptEnabled = true
it.webViewClient = WebViewClient()
}
}
private var timeout: Job? = null
inner class WebViewClient : android.webkit.WebViewClient() {
override fun shouldOverrideUrlLoading(view: WebView, url: String): Boolean {
timeout?.cancel()
onSuccess(url)
return true
}
}
init {
launch(Dispatchers.Main) {
webView.loadDataWithBaseURL(url, html, "text/html", "UTF-8", null)
}
timeout = startCoroutineTimer(delayMillis = 10000L) {
onTimeout()
}
}
}

View File

@ -8,6 +8,7 @@ import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api.* import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetList import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetList
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaGetMessages
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomework import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaHomework
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaInfo import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.LibrusSynergiaInfo
import pl.szczodrzynski.edziennik.data.db.entity.Message import pl.szczodrzynski.edziennik.data.db.entity.Message
@ -201,17 +202,27 @@ class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_student_info) data.startProgress(R.string.edziennik_progress_endpoint_student_info)
LibrusSynergiaInfo(data, lastSync, onSuccess) LibrusSynergiaInfo(data, lastSync, onSuccess)
} }
ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_RECEIVED -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
LibrusSynergiaGetMessages(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
}
ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_SENT -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
LibrusSynergiaGetMessages(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
}
/** /**
* MESSAGES * MESSAGES
*/ */
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> { ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox) data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess) if (data.messagesLoginSuccessful) LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
else LibrusSynergiaGetMessages(data, type = Message.TYPE_RECEIVED, lastSync = lastSync, onSuccess = onSuccess)
} }
ENDPOINT_LIBRUS_MESSAGES_SENT -> { ENDPOINT_LIBRUS_MESSAGES_SENT -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox) data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess) if (data.messagesLoginSuccessful) LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
else LibrusSynergiaGetMessages(data, type = Message.TYPE_SENT, lastSync = lastSync, onSuccess = onSuccess)
} }
else -> onSuccess(endpointId) else -> onSuccess(endpointId)

View File

@ -91,6 +91,8 @@ open class LibrusSynergia(open val data: DataLibrus, open val lastSync: Long?) {
} }
fun redirectUrlGet(tag: String, url: String, onSuccess: (url: String) -> Unit) { fun redirectUrlGet(tag: String, url: String, onSuccess: (url: String) -> Unit) {
d(tag, "Request: Librus/Synergia - $url")
val callback = object : TextCallbackHandler() { val callback = object : TextCallbackHandler() {
override fun onSuccess(text: String?, response: Response) { override fun onSuccess(text: String?, response: Response) {
val redirectUrl = response.headers().get("Location") val redirectUrl = response.headers().get("Location")

View File

@ -37,8 +37,7 @@ class LibrusApiAnnouncementMarkAsRead(override val data: DataLibrus,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
announcement.id, announcement.id,
announcement.seen, announcement.seen,
announcement.notified, announcement.notified
announcement.addedDate
)) ))
onSuccess() onSuccess()
} }

View File

@ -38,15 +38,17 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
val read = announcement.getBoolean("WasRead") ?: false val read = announcement.getBoolean("WasRead") ?: false
val announcementObject = Announcement( val announcementObject = Announcement(
profileId, profileId = profileId,
id, id = id,
subject, subject = subject,
text, text = text,
startDate, startDate = startDate,
endDate, endDate = endDate,
teacherId, teacherId = teacherId,
longId addedDate = addedDate
) ).also {
it.idString = longId
}
data.announcementList.add(announcementObject) data.announcementList.add(announcementObject)
data.setSeenMetadataList.add(Metadata( data.setSeenMetadataList.add(Metadata(
@ -54,8 +56,7 @@ class LibrusApiAnnouncements(override val data: DataLibrus,
Metadata.TYPE_ANNOUNCEMENT, Metadata.TYPE_ANNOUNCEMENT,
id, id,
read, read,
profile.empty || read, profile.empty || read
addedDate
)) ))
} }

View File

@ -26,25 +26,39 @@ class LibrusApiAttendanceTypes(override val data: DataLibrus,
attendanceTypes?.forEach { attendanceType -> attendanceTypes?.forEach { attendanceType ->
val id = attendanceType.getLong("Id") ?: return@forEach val id = attendanceType.getLong("Id") ?: return@forEach
val name = attendanceType.getString("Name") ?: ""
val color = attendanceType.getString("ColorRGB")?.let { Color.parseColor("#$it") } ?: -1
val standardId = when (attendanceType.getBoolean("Standard") ?: false) { val typeName = attendanceType.getString("Name") ?: ""
true -> id val typeSymbol = attendanceType.getString("Short") ?: ""
false -> attendanceType.getJsonObject("StandardType")?.getLong("Id") ?: id val typeColor = attendanceType.getString("ColorRGB")?.let { Color.parseColor("#$it") }
}
val type = when (standardId) { val isStandard = attendanceType.getBoolean("Standard") ?: false
val baseType = when (attendanceType.getJsonObject("StandardType")?.getLong("Id") ?: id) {
1L -> Attendance.TYPE_ABSENT 1L -> Attendance.TYPE_ABSENT
2L -> Attendance.TYPE_BELATED 2L -> Attendance.TYPE_BELATED
3L -> Attendance.TYPE_ABSENT_EXCUSED 3L -> Attendance.TYPE_ABSENT_EXCUSED
4L -> Attendance.TYPE_RELEASED 4L -> Attendance.TYPE_RELEASED
/*100*/else -> Attendance.TYPE_PRESENT /*100*/else -> when (isStandard) {
true -> Attendance.TYPE_PRESENT
false -> Attendance.TYPE_PRESENT_CUSTOM
}
}
val typeShort = when (isStandard) {
true -> data.app.attendanceManager.getTypeShort(baseType)
false -> typeSymbol
} }
data.attendanceTypes.put(id, AttendanceType(profileId, id, name, type, color)) data.attendanceTypes.put(id, AttendanceType(
profileId,
id,
baseType,
typeName,
typeShort,
typeSymbol,
typeColor
))
} }
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 4*DAY) data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 2*DAY)
onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES) onSuccess(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES)
} }
} }

View File

@ -13,7 +13,6 @@ import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.utils.models.Date import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
class LibrusApiAttendances(override val data: DataLibrus, class LibrusApiAttendances(override val data: DataLibrus,
override val lastSync: Long?, override val lastSync: Long?,
@ -42,9 +41,9 @@ class LibrusApiAttendances(override val data: DataLibrus,
val lessonDate = Date.fromY_m_d(attendance.getString("Date")) val lessonDate = Date.fromY_m_d(attendance.getString("Date"))
val teacherId = attendance.getJsonObject("AddedBy")?.getLong("Id") val teacherId = attendance.getJsonObject("AddedBy")?.getLong("Id")
val semester = attendance.getInt("Semester") ?: return@forEach val semester = attendance.getInt("Semester") ?: return@forEach
val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
val typeObject = data.attendanceTypes[type] ?: null val typeId = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
val topic = typeObject?.name ?: "" val type = data.attendanceTypes[typeId] ?: null
val startTime = data.lessonRanges.get(lessonNo)?.startTime val startTime = data.lessonRanges.get(lessonNo)?.startTime
@ -52,29 +51,34 @@ class LibrusApiAttendances(override val data: DataLibrus,
data.librusLessons.singleOrNull { it.lessonId == lessonId } data.librusLessons.singleOrNull { it.lessonId == lessonId }
else null else null
val attendanceObject = Attendance(
profileId,
id,
teacherId ?: lesson?.teacherId ?: -1,
lesson?.subjectId ?: -1,
semester,
topic,
lessonDate,
startTime ?: Time(0, 0, 0),
typeObject?.type ?: Attendance.TYPE_CUSTOM
)
val addedDate = Date.fromIso(attendance.getString("AddDate") ?: return@forEach) val addedDate = Date.fromIso(attendance.getString("AddDate") ?: return@forEach)
val attendanceObject = Attendance(
profileId = profileId,
id = id,
baseType = type?.baseType ?: Attendance.TYPE_UNKNOWN,
typeName = type?.typeName ?: "nieznany rodzaj",
typeShort = type?.typeShort ?: "?",
typeSymbol = type?.typeSymbol ?: "?",
typeColor = type?.typeColor,
date = lessonDate,
startTime = startTime,
semester = semester,
teacherId = teacherId ?: lesson?.teacherId ?: -1,
subjectId = lesson?.subjectId ?: -1,
addedDate = addedDate
).also {
it.lessonNumber = lessonNo
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if(typeObject?.type != Attendance.TYPE_PRESENT) { if(type?.baseType != Attendance.TYPE_PRESENT) {
data.metadataList.add(Metadata( data.metadataList.add(Metadata(
profileId, profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
profile?.empty ?: false, profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN,
profile?.empty ?: false, profile?.empty ?: false || type?.baseType == Attendance.TYPE_PRESENT_CUSTOM || type?.baseType == Attendance.TYPE_UNKNOWN
addedDate
)) ))
} }
} }

View File

@ -55,7 +55,8 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = 1, semester = 1,
teacherId = -1, teacherId = -1,
subjectId = 1 subjectId = 1,
addedDate = profile.getSemesterStart(1).inMillis
) )
data.gradeList.add(semester1StartGradeObject) data.gradeList.add(semester1StartGradeObject)
@ -64,8 +65,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
semester1StartGradeObject.id, semester1StartGradeObject.id,
true, true,
true, true
profile.getSemesterStart(1).inMillis
)) ))
} }
@ -83,7 +83,8 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = 2, semester = 2,
teacherId = -1, teacherId = -1,
subjectId = 1 subjectId = 1,
addedDate = profile.getSemesterStart(2).inMillis
) )
data.gradeList.add(semester2StartGradeObject) data.gradeList.add(semester2StartGradeObject)
@ -92,8 +93,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
semester2StartGradeObject.id, semester2StartGradeObject.id,
true, true,
true, true
profile.getSemesterStart(2).inMillis
)) ))
} }
@ -155,7 +155,8 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
comment = if (text != null) description.join(" - ") else null, comment = if (text != null) description.join(" - ") else null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = 1 subjectId = 1,
addedDate = addedDate
).apply { ).apply {
valueMax = valueTo valueMax = valueTo
} }
@ -166,8 +167,7 @@ class LibrusApiBehaviourGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -65,7 +65,8 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -74,8 +75,7 @@ class LibrusApiDescriptiveGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -35,7 +35,7 @@ class LibrusApiEvents(override val data: DataLibrus,
events?.forEach { event -> events?.forEach { event ->
val id = event.getLong("Id") ?: return@forEach val id = event.getLong("Id") ?: return@forEach
val eventDate = Date.fromY_m_d(event.getString("Date")) val eventDate = Date.fromY_m_d(event.getString("Date"))
val topic = event.getString("Content")?.trim() ?: "" var topic = event.getString("Content")?.trim() ?: ""
val type = event.getJsonObject("Category")?.getLong("Id") ?: -1 val type = event.getJsonObject("Category")?.getLong("Id") ?: -1
val teacherId = event.getJsonObject("CreatedBy")?.getLong("Id") ?: -1 val teacherId = event.getJsonObject("CreatedBy")?.getLong("Id") ?: -1
val subjectId = event.getJsonObject("Subject")?.getLong("Id") ?: -1 val subjectId = event.getJsonObject("Subject")?.getLong("Id") ?: -1
@ -46,6 +46,12 @@ class LibrusApiEvents(override val data: DataLibrus,
val startTime = lessonRange?.startTime ?: Time.fromH_m(event.getString("TimeFrom")) val startTime = lessonRange?.startTime ?: Time.fromH_m(event.getString("TimeFrom"))
val addedDate = Date.fromIso(event.getString("AddDate")) val addedDate = Date.fromIso(event.getString("AddDate"))
event.getJsonObject("onlineLessonUrl")?.let { onlineLesson ->
val text = onlineLesson.getString("text")?.let { "$it - " } ?: ""
val url = onlineLesson.getString("url")
topic += "\n\n$text$url"
}
val eventObject = Event( val eventObject = Event(
profileId = profileId, profileId = profileId,
id = id, id = id,
@ -56,7 +62,8 @@ class LibrusApiEvents(override val data: DataLibrus,
type = type, type = type,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = teamId teamId = teamId,
addedDate = addedDate
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -66,8 +73,7 @@ class LibrusApiEvents(override val data: DataLibrus,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate
)) ))
} }

View File

@ -79,7 +79,8 @@ class LibrusApiGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
grade.getJsonObject("Improvement")?.also { grade.getJsonObject("Improvement")?.also {
@ -98,8 +99,7 @@ class LibrusApiGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -43,7 +43,8 @@ class LibrusApiHomework(override val data: DataLibrus,
type = -1, type = -1,
teacherId = teacherId, teacherId = teacherId,
subjectId = -1, subjectId = -1,
teamId = -1 teamId = -1,
addedDate = addedDate.inMillis
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -52,8 +53,7 @@ class LibrusApiHomework(override val data: DataLibrus,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate.inMillis
)) ))
} }

View File

@ -33,9 +33,9 @@ class LibrusApiLuckyNumber(override val data: DataLibrus,
val luckyNumberDate = Date.fromY_m_d(luckyNumberEl.getString("LuckyNumberDay")) ?: Date.getToday() val luckyNumberDate = Date.fromY_m_d(luckyNumberEl.getString("LuckyNumberDay")) ?: Date.getToday()
val luckyNumber = luckyNumberEl.getInt("LuckyNumber") ?: -1 val luckyNumber = luckyNumberEl.getInt("LuckyNumber") ?: -1
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
profileId, profileId = profileId,
luckyNumberDate, date = luckyNumberDate,
luckyNumber number = luckyNumber
) )
if (luckyNumberDate >= Date.getToday()) if (luckyNumberDate >= Date.getToday())
@ -50,8 +50,7 @@ class LibrusApiLuckyNumber(override val data: DataLibrus,
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -46,12 +46,15 @@ class LibrusApiNotices(override val data: DataLibrus,
val semester = profile?.dateToSemester(addedDate) ?: 1 val semester = profile?.dateToSemester(addedDate) ?: 1
val noticeObject = Notice( val noticeObject = Notice(
profileId, profileId = profileId,
id, id = id,
categoryText + "\n" + text, type = type,
semester, semester = semester,
type, text = text,
teacherId category = categoryText,
points = null,
teacherId = teacherId,
addedDate = addedDate.inMillis
) )
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
@ -61,8 +64,7 @@ class LibrusApiNotices(override val data: DataLibrus,
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
addedDate.inMillis
)) ))
} }

View File

@ -56,7 +56,8 @@ class LibrusApiPointGrades(override val data: DataLibrus,
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
).apply { ).apply {
valueMax = category?.valueTo ?: 0f valueMax = category?.valueTo ?: 0f
} }
@ -67,8 +68,7 @@ class LibrusApiPointGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -58,8 +58,7 @@ class LibrusApiPtMeetings(override val data: DataLibrus,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -43,15 +43,15 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
val timeTo = teacherAbsence.getString("TimeTo")?.let { Time.fromH_m_s(it) } val timeTo = teacherAbsence.getString("TimeTo")?.let { Time.fromH_m_s(it) }
val teacherAbsenceObject = TeacherAbsence( val teacherAbsenceObject = TeacherAbsence(
profileId, profileId = profileId,
id, id = id,
teacherId, type = type,
type, name = name,
name, dateFrom = dateFrom,
dateFrom, dateTo = dateTo,
dateTo, timeFrom = timeFrom,
timeFrom, timeTo = timeTo,
timeTo teacherId = teacherId
) )
data.teacherAbsenceList.add(teacherAbsenceObject) data.teacherAbsenceList.add(teacherAbsenceObject)
@ -60,8 +60,7 @@ class LibrusApiTeacherFreeDays(override val data: DataLibrus,
Metadata.TYPE_TEACHER_ABSENCE, Metadata.TYPE_TEACHER_ABSENCE,
id, id,
true, true,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }

View File

@ -60,7 +60,8 @@ class LibrusApiTextGrades(override val data: DataLibrus,
comment = grade.getString("Phrase") /* whatever it is */, comment = grade.getString("Phrase") /* whatever it is */,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = addedDate
) )
data.gradeList.add(gradeObject) data.gradeList.add(gradeObject)
@ -69,8 +70,7 @@ class LibrusApiTextGrades(override val data: DataLibrus,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
profile.empty, profile.empty,
profile.empty, profile.empty
addedDate
)) ))
} }

View File

@ -198,8 +198,7 @@ class LibrusApiTimetables(override val data: DataLibrus,
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
lessonObject.id, lessonObject.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
data.lessonList.add(lessonObject) data.lessonList.add(lessonObject)

View File

@ -97,7 +97,8 @@ class LibrusMessagesGetList(override val data: DataLibrus,
type = type, type = type,
subject = subject, subject = subject,
body = null, body = null,
senderId = senderId senderId = senderId,
addedDate = sentDate
) )
val messageRecipientObject = MessageRecipient( val messageRecipientObject = MessageRecipient(
@ -120,8 +121,7 @@ class LibrusMessagesGetList(override val data: DataLibrus,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
id, id,
notified, notified,
notified, notified
sentDate
)) ))
} }

View File

@ -150,8 +150,7 @@ class LibrusMessagesGetMessage(override val data: DataLibrus,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
messageObject.id, messageObject.id,
true, true,
true, true
messageObject.addedDate
)) ))
} }

View File

@ -50,7 +50,7 @@ class LibrusMessagesSendMessage(override val data: DataLibrus,
LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = null) { LibrusMessagesGetList(data, type = Message.TYPE_SENT, lastSync = null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.id == id }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -0,0 +1,24 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
import pl.szczodrzynski.edziennik.data.api.LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusSandboxDownloadAttachment
import pl.szczodrzynski.edziennik.data.db.entity.Message
class LibrusSynergiaGetAttachment(override val data: DataLibrus,
val message: Message,
val attachmentId: Long,
val attachmentName: String,
val onSuccess: () -> Unit
) : LibrusSynergia(data, null) {
companion object {
const val TAG = "LibrusSynergiaGetAttachment"
}
init {
redirectUrlGet(TAG, "$LIBRUS_SYNERGIA_MESSAGES_ATTACHMENT_URL/${message.id}/$attachmentId") { url ->
LibrusSandboxDownloadAttachment(data, url, message, attachmentId, attachmentName, onSuccess)
}
}
}

View File

@ -0,0 +1,160 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
import org.greenrobot.eventbus.EventBus
import org.jsoup.Jsoup
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
import pl.szczodrzynski.edziennik.get
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
import pl.szczodrzynski.edziennik.singleOrNull
import pl.szczodrzynski.edziennik.swapFirstLastName
import pl.szczodrzynski.edziennik.utils.models.Date
class LibrusSynergiaGetMessage(override val data: DataLibrus,
private val messageObject: MessageFull,
val onSuccess: () -> Unit) : LibrusSynergia(data, null) {
companion object {
const val TAG = "LibrusSynergiaGetMessage"
}
init {
val endpoint = when (messageObject.type) {
Message.TYPE_SENT -> "wiadomosci/1/6/${messageObject.id}/f0"
else -> "wiadomosci/1/5/${messageObject.id}/f0"
}
data.profile?.also { profile ->
synergiaGet(TAG, endpoint) { text ->
val doc = Jsoup.parse(text)
val messageElement = doc.select(".container-message tr")[0].child(1)
val detailsElement = messageElement.child(1)
val readElement = messageElement.children().last()
val body = messageElement.select(".container-message-content").html()
messageObject.apply {
this.body = body
clearAttachments()
if (messageElement.children().size >= 5) {
messageElement.child(3).select("tr").forEachIndexed { i, attachment ->
if (i == 0) return@forEachIndexed // Skip the header
val filename = attachment.child(0).text().trim()
val attachmentId = "wiadomosci\\\\/pobierz_zalacznik\\\\/[0-9]+?\\\\/([0-9]+)\"".toRegex()
.find(attachment.select("img").attr("onclick"))?.get(1)
?: return@forEachIndexed
addAttachment(attachmentId.toLong(), filename, -1)
}
}
}
val messageRecipientList = mutableListOf<MessageRecipientFull>()
when (messageObject.type) {
Message.TYPE_RECEIVED -> {
val senderFullName = detailsElement.child(0).select(".left").text()
val senderGroupName = "\\[(.+?)]".toRegex().find(senderFullName)?.get(1)?.trim()
data.teacherList.singleOrNull { it.id == messageObject.senderId }?.apply {
setTeacherType(when (senderGroupName) {
/* https://api.librus.pl/2.0/Messages/Role */
"Pomoc techniczna Librus", "SuperAdministrator" -> Teacher.TYPE_SUPER_ADMIN
"Administrator szkoły" -> Teacher.TYPE_SCHOOL_ADMIN
"Dyrektor Szkoły" -> Teacher.TYPE_PRINCIPAL
"Nauczyciel" -> Teacher.TYPE_TEACHER
"Rodzic", "Opiekun" -> Teacher.TYPE_PARENT
"Sekretariat" -> Teacher.TYPE_SECRETARIAT
"Uczeń" -> Teacher.TYPE_STUDENT
"Pedagog/Psycholog szkolny" -> Teacher.TYPE_PEDAGOGUE
"Pracownik biblioteki" -> Teacher.TYPE_LIBRARIAN
"Inny specjalista" -> Teacher.TYPE_SPECIALIST
"Jednostka Nadrzędna" -> {
typeDescription = "Jednostka Nadrzędna"
Teacher.TYPE_OTHER
}
"Jednostka Samorządu Terytorialnego" -> {
typeDescription = "Jednostka Samorządu Terytorialnego"
Teacher.TYPE_OTHER
}
else -> Teacher.TYPE_OTHER
})
}
val readDateText = readElement.select(".left").text()
val readDate = when (readDateText.isNotNullNorEmpty()) {
true -> Date.fromIso(readDateText)
else -> 0
}
val messageRecipientObject = MessageRecipientFull(
profileId = profileId,
id = -1,
messageId = messageObject.id,
readDate = readDate
)
messageRecipientObject.fullName = profile.accountName
?: profile.studentNameLong
messageRecipientList.add(messageRecipientObject)
}
Message.TYPE_SENT -> {
readElement.select("tr").forEachIndexed { i, receiver ->
if (i == 0) return@forEachIndexed // Skip the header
val receiverFullName = receiver.child(0).text()
val receiverName = receiverFullName.split('(')[0].swapFirstLastName()
val teacher = data.teacherList.singleOrNull { it.fullName == receiverName }
val receiverId = teacher?.id ?: -1
val readDate = when (val readDateText = receiver.child(1).text().trim()) {
"NIE" -> 0
else -> Date.fromIso(readDateText)
}
val messageRecipientObject = MessageRecipientFull(
profileId = profileId,
id = receiverId,
messageId = messageObject.id,
readDate = readDate
)
messageRecipientObject.fullName = receiverName
messageRecipientList.add(messageRecipientObject)
}
}
}
if (!messageObject.seen) {
data.setSeenMetadataList.add(Metadata(
messageObject.profileId,
Metadata.TYPE_MESSAGE,
messageObject.id,
true,
true
))
}
messageObject.recipients = messageRecipientList
data.messageRecipientList.addAll(messageRecipientList)
data.messageList.add(messageObject)
data.messageListReplace = true
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
onSuccess()
}
} ?: onSuccess()
}
}

View File

@ -0,0 +1,116 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia
import org.jsoup.Jsoup
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.ERROR_NOT_IMPLEMENTED
import pl.szczodrzynski.edziennik.data.api.Regexes
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusSynergia
import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.utils.Utils
import pl.szczodrzynski.edziennik.utils.models.Date
class LibrusSynergiaGetMessages(override val data: DataLibrus,
override val lastSync: Long?,
private val type: Int = Message.TYPE_RECEIVED,
archived: Boolean = false,
val onSuccess: (Int) -> Unit) : LibrusSynergia(data, lastSync) {
companion object {
const val TAG = "LibrusSynergiaGetMessages"
}
init {
val endpoint = when (type) {
Message.TYPE_RECEIVED -> "wiadomosci/5"
Message.TYPE_SENT -> "wiadomosci/6"
else -> null
}
val endpointId = when (type) {
Message.TYPE_RECEIVED -> ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_RECEIVED
else -> ENDPOINT_LIBRUS_SYNERGIA_MESSAGES_SENT
}
if (endpoint != null) {
synergiaGet(TAG, endpoint) { text ->
val doc = Jsoup.parse(text)
fun getRecipientId(name: String): Long = data.teacherList.singleOrNull {
it.fullNameLastFirst == name
}?.id ?: {
val teacherObject = Teacher(
profileId,
-1 * Utils.crc16(name.swapFirstLastName().toByteArray()).toLong(),
name.splitName()?.second!!,
name.splitName()?.first!!
)
data.teacherList.put(teacherObject.id, teacherObject)
teacherObject.id
}.invoke()
doc.select(".decorated.stretch tbody > tr").forEach { messageElement ->
val url = messageElement.select("a").first().attr("href")
val id = Regexes.LIBRUS_MESSAGE_ID.find(url)?.get(1)?.toLong() ?: return@forEach
val subject = messageElement.child(3).text()
val sentDate = Date.fromIso(messageElement.child(4).text())
val recipientName = messageElement.child(2).text().split('(')[0].fixName()
val recipientId = getRecipientId(recipientName)
val read = messageElement.child(2).attr("style").isNullOrBlank()
val senderId = when (type) {
Message.TYPE_RECEIVED -> recipientId
else -> null
}
val receiverId = when (type) {
Message.TYPE_RECEIVED -> -1
else -> recipientId
}
val notified = when (type) {
Message.TYPE_SENT -> true
else -> read || profile?.empty ?: false
}
val messageObject = Message(
profileId = profileId,
id = id,
type = type,
subject = subject,
body = null,
senderId = senderId,
addedDate = sentDate
)
val messageRecipientObject = MessageRecipient(
profileId,
receiverId,
-1,
if (read) 1 else 0,
id
)
messageObject.hasAttachments = !messageElement.child(1).select("img").isEmpty()
data.messageList.add(messageObject)
data.messageRecipientList.add(messageRecipientObject)
data.setSeenMetadataList.add(Metadata(
profileId,
Metadata.TYPE_MESSAGE,
id,
notified,
notified
))
}
when (type) {
Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, MainActivity.DRAWER_ITEM_MESSAGES)
}
onSuccess(endpointId)
}
} else {
data.error(TAG, ERROR_NOT_IMPLEMENTED)
onSuccess(endpointId)
}
}
}

View File

@ -58,7 +58,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
elements[9].select("input").attr("onclick") elements[9].select("input").attr("onclick")
)?.get(1)?.toLong() ?: return@forEachIndexed )?.get(1)?.toLong() ?: return@forEachIndexed
val lessons = data.db.timetableDao().getForDateNow(profileId, eventDate) val lessons = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime val startTime = lessons.firstOrNull { it.subjectId == subjectId }?.startTime
val seen = when (profile.empty) { val seen = when (profile.empty) {
@ -76,7 +76,8 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
type = Event.TYPE_HOMEWORK, type = Event.TYPE_HOMEWORK,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = data.teamClass?.id ?: -1 teamId = data.teamClass?.id ?: -1,
addedDate = addedDate.inMillis
) )
data.eventList.add(eventObject) data.eventList.add(eventObject)
@ -85,8 +86,7 @@ class LibrusSynergiaHomework(override val data: DataLibrus,
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
seen, seen,
seen, seen
addedDate.inMillis
)) ))
} }
} }

View File

@ -33,7 +33,7 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
val accounts = json.getJsonArray("accounts") val accounts = json.getJsonArray("accounts")
if (accounts == null || accounts.size() < 1) { if (accounts == null || accounts.size() < 1) {
EventBus.getDefault().post(FirstLoginFinishedEvent(listOf(), data.loginStore)) EventBus.getDefault().postSticky(FirstLoginFinishedEvent(listOf(), data.loginStore))
onSuccess() onSuccess()
return@portalGet return@portalGet
} }
@ -81,7 +81,7 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
profileList.add(profile) profileList.add(profile)
} }
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore)) EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
onSuccess() onSuccess()
} }
} }
@ -116,14 +116,15 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
).apply { ).apply {
studentData["isPremium"] = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true studentData["isPremium"] = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true
studentData["accountId"] = account.getInt("Id") ?: 0 studentData["accountId"] = account.getInt("Id") ?: 0
studentData["accountLogin"] = login studentData["accountLogin"] = data.apiLogin ?: login
studentData["accountPassword"] = data.apiPassword
studentData["accountToken"] = data.apiAccessToken studentData["accountToken"] = data.apiAccessToken
studentData["accountTokenTime"] = data.apiTokenExpiryTime studentData["accountTokenTime"] = data.apiTokenExpiryTime
studentData["accountRefreshToken"] = data.apiRefreshToken studentData["accountRefreshToken"] = data.apiRefreshToken
} }
profileList.add(profile) profileList.add(profile)
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore)) EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
onSuccess() onSuccess()
} }
} }

View File

@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.getUnixDate
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
import java.net.HttpURLConnection.* import java.net.HttpURLConnection.*
@Suppress("ConvertSecondaryConstructorToPrimary")
class LibrusLoginApi { class LibrusLoginApi {
companion object { companion object {
private const val TAG = "LoginLibrusApi" private const val TAG = "LoginLibrusApi"

View File

@ -10,6 +10,7 @@ import im.wangchao.mhttp.body.MediaTypeUtils
import im.wangchao.mhttp.callback.TextCallbackHandler import im.wangchao.mhttp.callback.TextCallbackHandler
import pl.szczodrzynski.edziennik.data.api.* import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus import pl.szczodrzynski.edziennik.data.api.edziennik.librus.DataLibrus
import pl.szczodrzynski.edziennik.data.api.edziennik.librus.LibrusRecaptchaHelper
import pl.szczodrzynski.edziennik.data.api.models.ApiError import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.getUnixDate import pl.szczodrzynski.edziennik.getUnixDate
import pl.szczodrzynski.edziennik.utils.Utils.d import pl.szczodrzynski.edziennik.utils.Utils.d
@ -35,17 +36,39 @@ class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
onSuccess() onSuccess()
} }
text?.contains("grecaptcha.ready") == true -> {
val url = response?.request()?.url()?.toString() ?: run {
//data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
data.messagesLoginSuccessful = false
onSuccess()
return
}
LibrusRecaptchaHelper(data.app, url, text, onSuccess = { newUrl ->
loginWithSynergia(newUrl)
}, onTimeout = {
//data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_TIMEOUT, response, text)
data.messagesLoginSuccessful = false
onSuccess()
})
}
text?.contains("<status>ok</status>") == true -> { text?.contains("<status>ok</status>") == true -> {
saveSessionId(response, text) saveSessionId(response, text)
onSuccess() onSuccess()
} }
text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text) text?.contains("<message>Niepoprawny login i/lub hasło.</message>") == true -> data.error(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_INVALID_LOGIN, response, text)
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text) text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text) text?.contains("eAccessDeny") == true -> {
// data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
data.messagesLoginSuccessful = false
onSuccess()
}
text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text) text?.contains("OffLine") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_MAINTENANCE, response, text)
text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text) text?.contains("<status>error</status>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ERROR, response, text)
text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text) text?.contains("<type>eVarWhitThisNameNotExists</type>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
text?.contains("<error>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text) text?.contains("<error>") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
else -> data.error(TAG, ERROR_LIBRUS_MESSAGES_OTHER, response, text)
} }
} }

View File

@ -146,12 +146,14 @@ class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
} }
val error = if (response.code() == 200) null else val error = if (response.code() == 200) null else
json.getJsonArray("errors")?.getString(0) json.getJsonArray("errors")?.getString(0)
?: json.getJsonObject("errors")?.entrySet()?.firstOrNull()?.value?.asString
error?.let { code -> error?.let { code ->
when { when {
code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED code.contains("Sesja logowania wygasła") -> ERROR_LOGIN_LIBRUS_PORTAL_CSRF_EXPIRED
code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN code.contains("Upewnij się, że nie") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
// this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set // this doesn't work anyway: `errors` is an object with `g-recaptcha-response` set
code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL code.contains("robotem") -> ERROR_CAPTCHA_LIBRUS_PORTAL
code.contains("Podany adres e-mail jest nieprawidłowy.") -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_LOGIN
else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR else -> ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR
}.let { errorCode -> }.let { errorCode ->
data.error(ApiError(TAG, errorCode) data.error(ApiError(TAG, errorCode)

View File

@ -6,7 +6,10 @@ 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.edziennik.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.* import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>) { class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>) {
@ -23,7 +26,7 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>)
val id = cols[0].toLong() val id = cols[0].toLong()
val lessonId = cols[1].toLong() val lessonId = cols[1].toLong()
data.mobiLessons.singleOrNull { it.id == lessonId }?.let { lesson -> data.mobiLessons.singleOrNull { it.id == lessonId }?.let { lesson ->
val type = when (cols[4]) { val baseType = when (cols[4]) {
"2" -> TYPE_ABSENT "2" -> TYPE_ABSENT
"5" -> TYPE_ABSENT_EXCUSED "5" -> TYPE_ABSENT_EXCUSED
"4" -> TYPE_RELEASED "4" -> TYPE_RELEASED
@ -31,16 +34,37 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>)
} }
val semester = data.profile?.dateToSemester(lesson.date) ?: 1 val semester = data.profile?.dateToSemester(lesson.date) ?: 1
val typeName = when (baseType) {
TYPE_ABSENT -> "nieobecność"
TYPE_ABSENT_EXCUSED -> "nieobecność usprawiedliwiona"
TYPE_RELEASED -> "zwolnienie"
TYPE_PRESENT -> "obecność"
else -> "nieznany rodzaj"
}
val typeSymbol = when (baseType) {
TYPE_ABSENT -> "|"
TYPE_ABSENT_EXCUSED -> "+"
TYPE_RELEASED -> "z"
TYPE_PRESENT -> "."
else -> "?"
}
val attendanceObject = Attendance( val attendanceObject = Attendance(
data.profileId, profileId = data.profileId,
id, id = id,
lesson.teacherId, baseType = baseType,
lesson.subjectId, typeName = typeName,
semester, typeShort = data.app.attendanceManager.getTypeShort(baseType),
lesson.topic, typeSymbol = typeSymbol,
lesson.date, typeColor = null,
lesson.startTime, date = lesson.date,
type) startTime = lesson.startTime,
semester = semester,
teacherId = lesson.teacherId,
subjectId = lesson.subjectId
).also {
it.lessonTopic = lesson.topic
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
data.metadataList.add( data.metadataList.add(
@ -48,9 +72,8 @@ class MobidziennikApiAttendance(val data: DataMobidziennik, rows: List<String>)
data.profileId, data.profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -60,7 +60,9 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
type = type, type = type,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = teamId) teamId = teamId,
addedDate = addedDate
)
data.eventList.add(eventObject) data.eventList.add(eventObject)
data.metadataList.add( data.metadataList.add(
@ -69,8 +71,7 @@ class MobidziennikApiEvents(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
addedDate
)) ))
} }
} }

View File

@ -79,7 +79,9 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
comment = null, comment = null,
semester = semester, semester = semester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId) subjectId = subjectId,
addedDate = addedDate
)
if (data.profile?.empty == true) { if (data.profile?.empty == true) {
addedDate = data.profile.dateSemester1Start.inMillis addedDate = data.profile.dateSemester1Start.inMillis
@ -92,8 +94,7 @@ class MobidziennikApiGrades(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
addedDate
)) ))
addedDate++ addedDate++
} }

View File

@ -40,7 +40,8 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
type = Event.TYPE_HOMEWORK, type = Event.TYPE_HOMEWORK,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId, subjectId = subjectId,
teamId = teamId) teamId = teamId
)
data.eventList.add(eventObject) data.eventList.add(eventObject)
data.metadataList.add( data.metadataList.add(
@ -49,8 +50,7 @@ class MobidziennikApiHomework(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_HOMEWORK, Metadata.TYPE_HOMEWORK,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -33,12 +33,16 @@ class MobidziennikApiNotices(val data: DataMobidziennik, rows: List<String>) {
val addedDate = Date.fromYmd(cols[7]).inMillis val addedDate = Date.fromYmd(cols[7]).inMillis
val noticeObject = Notice( val noticeObject = Notice(
data.profileId, profileId = data.profileId,
id, id = id,
text, type = type,
semester, semester = semester,
type, text = text,
teacherId) category = null,
points = null,
teacherId = teacherId,
addedDate = addedDate
)
data.noticeList.add(noticeObject) data.noticeList.add(noticeObject)
data.metadataList.add( data.metadataList.add(
@ -47,8 +51,7 @@ class MobidziennikApiNotices(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_NOTICE, Metadata.TYPE_NOTICE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false,
data.profile?.empty ?: false, data.profile?.empty ?: false
addedDate
)) ))
} }
}} }}

View File

@ -8,9 +8,9 @@ import android.util.SparseArray
import androidx.core.util.set import androidx.core.util.set
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.DataMobidziennik
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.data.db.entity.LessonRange import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Lesson
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName
import pl.szczodrzynski.edziennik.keys import pl.szczodrzynski.edziennik.keys
import pl.szczodrzynski.edziennik.singleOrNull import pl.szczodrzynski.edziennik.singleOrNull
@ -97,8 +97,7 @@ class MobidziennikApiTimetable(val data: DataMobidziennik, rows: List<String>) {
Metadata.TYPE_LESSON_CHANGE, Metadata.TYPE_LESSON_CHANGE,
it.id, it.id,
seen, seen,
seen, seen
System.currentTimeMillis()
)) ))
} }
data.lessonList += it data.lessonList += it

View File

@ -17,9 +17,9 @@ class MobidziennikLuckyNumberExtractor(val data: DataMobidziennik, text: String)
val luckyNumber = it.groupValues[1].toInt() val luckyNumber = it.groupValues[1].toInt()
val luckyNumberObject = LuckyNumber( val luckyNumberObject = LuckyNumber(
data.profileId, profileId = data.profileId,
Date.getToday(), date = Date.getToday(),
luckyNumber number = luckyNumber
) )
data.luckyNumberList.add(luckyNumberObject) data.luckyNumberList.add(luckyNumberObject)
@ -29,8 +29,7 @@ class MobidziennikLuckyNumberExtractor(val data: DataMobidziennik, text: String)
Metadata.TYPE_LUCKY_NUMBER, Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(), luckyNumberObject.date.value.toLong(),
true, true,
data.profile?.empty ?: false, data.profile?.empty ?: false
System.currentTimeMillis()
)) ))
} catch (_: Exception){} } catch (_: Exception){}
} }

View File

@ -11,7 +11,13 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.ENDPOINT_MOBID
import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb import pl.szczodrzynski.edziennik.data.api.edziennik.mobidziennik.data.MobidziennikWeb
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Attendance import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.* import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_BELATED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT_CUSTOM
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN
import pl.szczodrzynski.edziennik.data.db.entity.Metadata import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.fixName import pl.szczodrzynski.edziennik.fixName
@ -71,6 +77,18 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
val types = Regexes.MOBIDZIENNIK_ATTENDANCE_TYPES
.find(text)
?.get(1)
?.split("<br/>")
?.map {
it.trimEnd(',')
.split(" ", limit = 2)
.let { it.getOrNull(0) to it.getOrNull(1) }
}
?.toMap()
val typeSymbols = types?.keys?.filterNotNull() ?: listOf()
Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult -> Regexes.MOBIDZIENNIK_ATTENDANCE_TABLE.findAll(text).forEach { tableResult ->
val table = tableResult[1] val table = tableResult[1]
val lessonDates = mutableListOf<Date>() val lessonDates = mutableListOf<Date>()
@ -92,55 +110,90 @@ class MobidziennikWebAttendance(override val data: DataMobidziennik,
return@forEach return@forEach
ranges.forEach { range -> ranges.forEach { range ->
val lessonDate = dateIterator.next() val lessonDate = dateIterator.next()
val entry = entriesIterator.next() var entry = entriesIterator.next()
if (entry.isBlank()) if (entry.isBlank())
return@forEach return@forEach
val startTime = Time.fromH_m(range[1]) val startTime = Time.fromH_m(range[1])
val entryIterator = entry.iterator()
range[2].split(" / ").mapNotNull { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it) }.forEachIndexed { index, lesson -> range[2].split(" / ").mapNotNull { Regexes.MOBIDZIENNIK_ATTENDANCE_LESSON.find(it) }.forEachIndexed { index, lesson ->
val topic = lesson[2] val topic = lesson[1].substringAfter(" - ", missingDelimiterValue = "").takeIf { it.isNotBlank() }
if (topic.startsWith("Lekcja odwołana: ") || !entryIterator.hasNext()) if (topic?.startsWith("Lekcja odwołana: ") == true || entry.isEmpty())
return@forEachIndexed return@forEachIndexed
val subjectName = lesson[1] val subjectName = lesson[1].substringBefore(" - ")
//val team = lesson[3] //val team = lesson[3]
val teacherName = lesson[4].fixName() val teacherName = lesson[3].fixName()
val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1 val teacherId = data.teacherList.singleOrNull { it.fullNameLastFirst == teacherName }?.id ?: -1
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1 val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id ?: -1
val type = when (entryIterator.nextChar()) { var typeSymbol = ""
'.' -> TYPE_PRESENT for (symbol in typeSymbols) {
'|' -> TYPE_ABSENT if (entry.startsWith(symbol) && symbol.length > typeSymbol.length)
'+' -> TYPE_ABSENT_EXCUSED typeSymbol = symbol
's' -> TYPE_BELATED
'z' -> TYPE_RELEASED
else -> TYPE_PRESENT
} }
entry = entry.removePrefix(typeSymbol)
var isCounted = true
val baseType = when (typeSymbol) {
"." -> TYPE_PRESENT
"|" -> TYPE_ABSENT
"+" -> TYPE_ABSENT_EXCUSED
"s" -> TYPE_BELATED
"z" -> TYPE_RELEASED
else -> {
isCounted = false
when (typeSymbol) {
"e" -> TYPE_PRESENT_CUSTOM
"en" -> TYPE_ABSENT
"ep" -> TYPE_PRESENT_CUSTOM
else -> TYPE_UNKNOWN
}
}
}
val typeName = types?.get(typeSymbol) ?: ""
val typeColor = when (typeSymbol) {
"e" -> 0xff673ab7
"en" -> 0xffec407a
"ep" -> 0xff4caf50
else -> null
}?.toInt()
val typeShort = if (isCounted)
data.app.attendanceManager.getTypeShort(baseType)
else
typeSymbol
val semester = data.profile?.dateToSemester(lessonDate) ?: 1 val semester = data.profile?.dateToSemester(lessonDate) ?: 1
val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index val id = lessonDate.combineWith(startTime) / 6L * 10L + (lesson[0].hashCode() and 0xFFFF) + index
val attendanceObject = Attendance( val attendanceObject = Attendance(
data.profileId, profileId = profileId,
id, id = id,
teacherId, baseType = baseType,
subjectId, typeName = typeName,
semester, typeShort = typeShort,
topic, typeSymbol = typeSymbol,
lessonDate, typeColor = typeColor,
startTime, date = lessonDate,
type) startTime = startTime,
semester = semester,
teacherId = teacherId,
subjectId = subjectId
).also {
it.lessonTopic = topic
it.isCounted = isCounted
}
data.attendanceList.add(attendanceObject) data.attendanceList.add(attendanceObject)
if (type != TYPE_PRESENT) { if (baseType != TYPE_PRESENT) {
data.metadataList.add( data.metadataList.add(
Metadata( Metadata(
data.profileId, data.profileId,
Metadata.TYPE_ATTENDANCE, Metadata.TYPE_ATTENDANCE,
id, id,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
data.profile?.empty ?: false, data.profile?.empty ?: false || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
System.currentTimeMillis()
)) ))
} }
} }

View File

@ -89,8 +89,8 @@ class MobidziennikWebCalendar(override val data: DataMobidziennik,
Metadata.TYPE_EVENT, Metadata.TYPE_EVENT,
eventObject.id, eventObject.id,
profile?.empty ?: false, profile?.empty ?: false,
profile?.empty ?: false, profile?.empty ?: false
System.currentTimeMillis() /* no addedDate here though */ /* no addedDate here though */
)) ))
} }
} }

View File

@ -139,8 +139,7 @@ class MobidziennikWebGetMessage(override val data: DataMobidziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
true, true,
true, true
message.addedDate
)) ))
} }

View File

@ -125,7 +125,8 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
comment = null, comment = null,
semester = gradeSemester, semester = gradeSemester,
teacherId = teacherId, teacherId = teacherId,
subjectId = subjectId subjectId = subjectId,
addedDate = gradeAddedDateMillis
) )
gradeObject.classAverage = gradeClassAverage gradeObject.classAverage = gradeClassAverage
@ -137,8 +138,7 @@ class MobidziennikWebGrades(override val data: DataMobidziennik,
Metadata.TYPE_GRADE, Metadata.TYPE_GRADE,
gradeObject.id, gradeObject.id,
profile.empty, profile.empty,
profile.empty, profile.empty
gradeAddedDateMillis
)) ))
} }
} }

View File

@ -77,11 +77,12 @@ class MobidziennikWebMessagesAll(override val data: DataMobidziennik,
type = type, type = type,
subject = subject, subject = subject,
body = null, body = null,
senderId = senderId senderId = senderId,
addedDate = addedDate
) )
data.messageList.add(message) data.messageList.add(message)
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, addedDate)) data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true))
} }
// sync every 7 days as we probably don't expect more than // sync every 7 days as we probably don't expect more than

View File

@ -63,7 +63,8 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
type = Message.TYPE_RECEIVED, type = Message.TYPE_RECEIVED,
subject = subject, subject = subject,
body = null, body = null,
senderId = senderId senderId = senderId,
addedDate = addedDate
) )
if (hasAttachments) if (hasAttachments)
@ -76,8 +77,7 @@ class MobidziennikWebMessagesInbox(override val data: DataMobidziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
isRead, isRead,
isRead || profile?.empty ?: false, isRead || profile?.empty ?: false
addedDate
)) ))
} }

View File

@ -78,7 +78,8 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
type = Message.TYPE_SENT, type = Message.TYPE_SENT,
subject = subject, subject = subject,
body = null, body = null,
senderId = null senderId = null,
addedDate = addedDate
) )
if (hasAttachments) if (hasAttachments)
@ -91,8 +92,7 @@ class MobidziennikWebMessagesSent(override val data: DataMobidziennik,
Metadata.TYPE_MESSAGE, Metadata.TYPE_MESSAGE,
message.id, message.id,
true, true,
true, true
addedDate
)) ))
} }

View File

@ -45,7 +45,7 @@ class MobidziennikWebSendMessage(override val data: DataMobidziennik,
MobidziennikWebMessagesAll(data, null) { MobidziennikWebMessagesAll(data, null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject } val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id } val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
val event = MessageSentEvent(data.profileId, message, metadata?.addedDate) val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event) EventBus.getDefault().postSticky(event)
onSuccess() onSuccess()

View File

@ -85,7 +85,7 @@ class MobidziennikFirstLogin(val data: DataMobidziennik, val onSuccess: () -> Un
profileList.add(profile) profileList.add(profile)
} }
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore)) EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
onSuccess() onSuccess()
} }
} }

View File

@ -0,0 +1,119 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API
import pl.szczodrzynski.edziennik.data.api.models.Data
import pl.szczodrzynski.edziennik.data.db.entity.*
import kotlin.text.replace
class DataPodlasie(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
fun isApiLoginValid() = apiToken.isNotNullNorEmpty()
override fun satisfyLoginMethods() {
loginMethods.clear()
if (isApiLoginValid())
loginMethods += LOGIN_METHOD_PODLASIE_API
}
override fun generateUserCode(): String = "$schoolShortName:$loginShort:${studentId?.crc32()}"
/* _
/\ (_)
/ \ _ __ _
/ /\ \ | '_ \| |
/ ____ \| |_) | |
/_/ \_\ .__/|_|
| |
|*/
private var mApiToken: String? = null
var apiToken: String?
get() { mApiToken = mApiToken ?: loginStore.getLoginData("apiToken", null); return mApiToken }
set(value) { loginStore.putLoginData("apiToken", value); mApiToken = value }
private var mApiUrl: String? = null
var apiUrl: String?
get() { mApiUrl = mApiUrl ?: profile?.getStudentData("apiUrl", null); return mApiUrl }
set(value) { profile?.putStudentData("apiUrl", value) ?: return; mApiUrl = value }
/* ____ _ _
/ __ \| | | |
| | | | |_| |__ ___ _ __
| | | | __| '_ \ / _ \ '__|
| |__| | |_| | | | __/ |
\____/ \__|_| |_|\___|*/
private var mStudentId: String? = null
var studentId: String?
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
private var mStudentLogin: String? = null
var studentLogin: String?
get() { mStudentLogin = mStudentLogin ?: profile?.getStudentData("studentLogin", null); return mStudentLogin }
set(value) { profile?.putStudentData("studentLogin", value) ?: return; mStudentLogin = value }
private var mSchoolName: String? = null
var schoolName: String?
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
private var mClassName: String? = null
var className: String?
get() { mClassName = mClassName ?: profile?.getStudentData("className", null); return mClassName }
set(value) { profile?.putStudentData("className", value) ?: return; mClassName = value }
private var mSchoolYear: String? = null
var schoolYear: String?
get() { mSchoolYear = mSchoolYear ?: profile?.getStudentData("schoolYear", null); return mSchoolYear }
set(value) { profile?.putStudentData("schoolYear", value) ?: return; mSchoolYear = value }
private var mCurrentSemester: Int? = null
var currentSemester: Int
get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 0); return mCurrentSemester ?: 0 }
set(value) { profile?.putStudentData("currentSemester", value) ?: return; mCurrentSemester = value }
val schoolShortName: String?
get() = studentLogin?.split('@')?.get(1)?.replace(".podlaskie.pl", "")
val loginShort: String?
get() = studentLogin?.split('@')?.get(0)
fun getSubject(name: String): Subject {
val id = name.crc32()
return subjectList.singleOrNull { it.id == id } ?: run {
val subject = Subject(profileId, id, name, name)
subjectList.put(id, subject)
subject
}
}
fun getTeacher(firstName: String, lastName: String): Teacher {
val name = "$firstName $lastName".fixName()
return teacherList.singleOrNull { it.fullName == name } ?: run {
val id = name.crc32()
val teacher = Teacher(profileId, id, firstName, lastName)
teacherList.put(id, teacher)
teacher
}
}
fun getTeam(name: String? = null): Team {
if (name == "cała klasa" || name == null) return teamClass ?: run {
val id = className!!.crc32()
val teamCode = "$schoolShortName:$className"
val team = Team(profileId, id, className, Team.TYPE_CLASS, teamCode, -1)
teamList.put(id, team)
return team
} else {
val id = name.crc32()
val teamCode = "$schoolShortName:$name"
val team = Team(profileId, id, name, Team.TYPE_VIRTUAL, teamCode, -1)
teamList.put(id, team)
return team
}
}
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie
import com.google.gson.JsonObject
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.App
import pl.szczodrzynski.edziennik.data.api.edziennik.helper.DownloadAttachment
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.PodlasieData
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.firstlogin.PodlasieFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.login.PodlasieLogin
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.data.api.podlasieLoginMethods
import pl.szczodrzynski.edziennik.data.api.prepare
import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
import pl.szczodrzynski.edziennik.data.db.full.EventFull
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.utils.Utils
import java.io.File
class Podlasie(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
companion object {
const val TAG = "Podlasie"
}
val internalErrorList = mutableListOf<Int>()
val data: DataPodlasie
init {
data = DataPodlasie(app, profile, loginStore).apply {
callback = wrapCallback(this@Podlasie.callback)
satisfyLoginMethods()
}
}
private fun completed() {
data.saveData()
callback.onCompleted()
}
/* _______ _ _ _ _ _
|__ __| | /\ | | (_) | | |
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
__/ |
|__*/
override fun sync(featureIds: List<Int>, viewId: Int?, onlyEndpoints: List<Int>?, arguments: JsonObject?) {
data.arguments = arguments
data.prepare(podlasieLoginMethods, PodlasieFeatures, featureIds, viewId, onlyEndpoints)
Utils.d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
Utils.d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
PodlasieLogin(data) {
PodlasieData(data) {
completed()
}
}
}
override fun getMessage(message: MessageFull) {
}
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
}
override fun markAllAnnouncementsAsRead() {
}
override fun getAnnouncement(announcement: AnnouncementFull) {
}
override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
val fileUrl = attachmentName.substringAfter(":")
DownloadAttachment(fileUrl,
onSuccess = { file ->
val event = AttachmentGetEvent(
data.profileId,
owner,
attachmentId,
AttachmentGetEvent.TYPE_FINISHED,
file.absolutePath
)
val attachmentDataFile = File(Utils.getStorageDir(), ".${data.profileId}_${event.ownerId}_${event.attachmentId}")
Utils.writeStringToFile(attachmentDataFile, event.fileName)
EventBus.getDefault().postSticky(event)
completed()
},
onProgress = { written, _ ->
val event = AttachmentGetEvent(
data.profileId,
owner,
attachmentId,
AttachmentGetEvent.TYPE_PROGRESS,
bytesWritten = written
)
EventBus.getDefault().postSticky(event)
},
onError = { apiError ->
data.error(apiError)
})
}
override fun getRecipientList() {
}
override fun getEvent(eventFull: EventFull) {
}
override fun firstLogin() {
PodlasieFirstLogin(data) {
completed()
}
}
override fun cancel() {
Utils.d(TAG, "Cancelled")
data.cancel()
callback.onCompleted()
}
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
return object : EdziennikCallback {
override fun onCompleted() {
callback.onCompleted()
}
override fun onProgress(step: Float) {
callback.onProgress(step)
}
override fun onStartProgress(stringRes: Int) {
callback.onStartProgress(stringRes)
}
override fun onError(apiError: ApiError) {
// TODO Error handling
when (apiError.errorCode) {
in internalErrorList -> {
// finish immediately if the same error occurs twice during the same sync
callback.onError(apiError)
}
else -> callback.onError(apiError)
}
}
}
}
}

View File

@ -0,0 +1,18 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie
import pl.szczodrzynski.edziennik.data.api.FEATURE_ALWAYS_NEEDED
import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_PODLASIE_API
import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_PODLASIE
import pl.szczodrzynski.edziennik.data.api.models.Feature
const val ENDPOINT_PODLASIE_API_MAIN = 1001
val PodlasieFeatures = listOf(
Feature(LOGIN_TYPE_PODLASIE, FEATURE_ALWAYS_NEEDED, listOf(
ENDPOINT_PODLASIE_API_MAIN to LOGIN_METHOD_PODLASIE_API
), listOf(LOGIN_METHOD_PODLASIE_API))
)

View File

@ -0,0 +1,108 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data
import com.google.gson.JsonObject
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.RequestParams
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.JsonCallbackHandler
import pl.szczodrzynski.edziennik.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.toHexString
import pl.szczodrzynski.edziennik.utils.Utils
import java.security.MessageDigest
import java.text.SimpleDateFormat
import java.util.*
open class PodlasieApi(open val data: DataPodlasie, open val lastSync: Long?) {
companion object {
const val TAG = "PodlasieApi"
}
val profileId
get() = data.profile?.id ?: -1
val profile
get() = data.profile
fun apiGet(tag: String, endpoint: String, onSuccess: (json: JsonObject) -> Unit) {
val url = PODLASIE_API_URL + endpoint
Utils.d(tag, "Request: Podlasie/Api - $url")
if (data.apiToken == null) {
data.error(tag, ERROR_PODLASIE_API_NO_TOKEN)
return
}
val callback = object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response?) {
if (json == null || response == null) {
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response))
return
}
val error = json.getJsonObject("system_message")?.getInt("code")
error?.let { code ->
when (code) {
0 -> ERROR_PODLASIE_API_DATA_MISSING
4 -> ERROR_LOGIN_PODLASIE_API_DEVICE_LIMIT
5 -> ERROR_LOGIN_PODLASIE_API_INVALID_TOKEN
200 -> null // Not an error
else -> ERROR_PODLASIE_API_OTHER
}?.let { errorCode ->
data.error(ApiError(tag, errorCode)
.withApiResponse(json)
.withResponse(response))
return@onSuccess
}
}
try {
onSuccess(json)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_PODLASIE_API_REQUEST)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json))
}
}
override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable))
}
}
Request.builder()
.url(url)
.userAgent(SYSTEM_USER_AGENT)
.requestParams(RequestParams(mapOf(
"token" to data.apiToken,
"securityToken" to getSecurityToken(),
"mobileId" to data.app.deviceId,
"ver" to PODLASIE_API_VERSION
)))
.callback(callback)
.build()
.enqueue()
}
private fun getSecurityToken(): String {
val format = SimpleDateFormat("yyyy-MM-dd HH", Locale.ENGLISH)
.also { it.timeZone = TimeZone.getTimeZone("Europe/Warsaw") }.format(System.currentTimeMillis())
val instance = MessageDigest.getInstance("SHA-256")
val digest = instance.digest("-EYlwYu8u16miVd8tT?oO7cvoUVQrQN0vr!$format".toByteArray()).toHexString()
val digest2 = instance.digest(data.apiToken!!.toByteArray()).toHexString()
return instance.digest("$digest$digest2".toByteArray()).toHexString()
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-12
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.ENDPOINT_PODLASIE_API_MAIN
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api.PodlasieApiMain
import pl.szczodrzynski.edziennik.utils.Utils
class PodlasieData(val data: DataPodlasie, val onSuccess: () -> Unit) {
companion object {
const val TAG = "PodlasieData"
}
init {
nextEndpoint(onSuccess)
}
private fun nextEndpoint(onSuccess: () -> Unit) {
if (data.targetEndpointIds.isEmpty()) {
onSuccess()
return
}
if (data.cancelled) {
onSuccess()
return
}
val id = data.targetEndpointIds.firstKey()
val lastSync = data.targetEndpointIds.remove(id)
useEndpoint(id, lastSync) {
data.progress(data.progressStep)
nextEndpoint(onSuccess)
}
}
private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
when (endpointId) {
ENDPOINT_PODLASIE_API_MAIN -> {
data.startProgress(R.string.edziennik_progress_endpoint_data)
PodlasieApiMain(data, lastSync, onSuccess)
}
else -> onSuccess(endpointId)
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
import java.util.*
class PodlasieApiEvents(val data: DataPodlasie, val rows: List<JsonObject>) {
init {
rows.forEach { event ->
val id = event.getLong("ExternalId") ?: return@forEach
val date = event.getString("DateFrom")?.let { Date.fromY_m_d(it) } ?: return@forEach
val time = event.getString("DateFrom")?.let { Time.fromY_m_d_H_m_s(it) }
?: return@forEach
val name = event.getString("Name")?.replace("&#34;", "\"") ?: ""
val description = event.getString("Description")?.replace("&#34;", "\"") ?: ""
val type = when (event.getString("Category")?.toLowerCase(Locale.getDefault())) {
"klasówka" -> Event.TYPE_EXAM
"praca domowa" -> Event.TYPE_HOMEWORK
"wycieczka" -> Event.TYPE_EXCURSION
else -> Event.TYPE_DEFAULT
}
val teacherFirstName = event.getString("PersonEnteringDataFirstName") ?: return@forEach
val teacherLastName = event.getString("PersonEnteringDataLastName") ?: return@forEach
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
val lessonList = data.db.timetableDao().getAllForDateNow(data.profileId, date)
val lesson = lessonList.firstOrNull { it.startTime == time }
val addedDate = event.getString("CreateDate")?.let { Date.fromIso(it) }
?: System.currentTimeMillis()
val eventObject = Event(
profileId = data.profileId,
id = id,
date = date,
time = time,
topic = name,
color = null,
type = type,
teacherId = teacher.id,
subjectId = lesson?.subjectId ?: -1,
teamId = data.teamClass?.id ?: -1,
addedDate = addedDate
).apply {
homeworkBody = description
}
data.eventList.add(eventObject)
data.metadataList.add(
Metadata(
data.profileId,
if (type == Event.TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
id,
data.profile?.empty ?: false,
data.profile?.empty ?: false
))
}
data.toRemove.add(DataRemoveModel.Events.future())
}
}

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_FINAL
import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
class PodlasieApiFinalGrades(val data: DataPodlasie, val rows: List<JsonObject>) {
init { data.profile?.also { profile ->
rows.forEach { grade ->
val id = grade.getLong("ExternalId") ?: return@forEach
val mark = grade.getString("Mark") ?: return@forEach
val proposedMark = grade.getString("ProposedMark") ?: "0"
val name = data.app.gradesManager.getGradeNumberName(mark)
val value = data.app.gradesManager.getGradeValue(name)
val semester = grade.getString("TermShortcut")?.length ?: return@forEach
val typeName = grade.getString("Type") ?: return@forEach
val type = when (typeName) {
"S" -> if (semester == 1) TYPE_SEMESTER1_FINAL else TYPE_SEMESTER2_FINAL
"Y", "R" -> TYPE_YEAR_FINAL
else -> return@forEach
}
val subjectName = grade.getString("SchoolSubject") ?: return@forEach
val subject = data.getSubject(subjectName)
val addedDate = if (profile.empty) profile.getSemesterStart(semester).inMillis
else System.currentTimeMillis()
val gradeObject = Grade(
profileId = data.profileId,
id = id,
name = name,
type = type,
value = value,
weight = 0f,
color = -1,
category = null,
description = null,
comment = null,
semester = semester,
teacherId = -1,
subjectId = subject.id,
addedDate = addedDate
)
data.gradeList.add(gradeObject)
data.metadataList.add(
Metadata(
data.profileId,
Metadata.TYPE_GRADE,
id,
profile.empty,
profile.empty
))
if (proposedMark != "0") {
val proposedName = data.app.gradesManager.getGradeNumberName(proposedMark)
val proposedValue = data.app.gradesManager.getGradeValue(proposedName)
val proposedType = when (typeName) {
"S" -> if (semester == 1) TYPE_SEMESTER1_PROPOSED else TYPE_SEMESTER2_PROPOSED
"Y", "R" -> TYPE_YEAR_PROPOSED
else -> return@forEach
}
val proposedGradeObject = Grade(
profileId = data.profileId,
id = id * (-1),
name = proposedName,
type = proposedType,
value = proposedValue,
weight = 0f,
color = -1,
category = null,
description = null,
comment = null,
semester = semester,
teacherId = -1,
subjectId = subject.id,
addedDate = addedDate
)
data.gradeList.add(proposedGradeObject)
data.metadataList.add(
Metadata(
data.profileId,
Metadata.TYPE_GRADE,
proposedGradeObject.id,
profile.empty,
profile.empty
))
}
}
data.toRemove.addAll(listOf(
TYPE_SEMESTER1_FINAL,
TYPE_SEMESTER1_PROPOSED,
TYPE_SEMESTER2_FINAL,
TYPE_SEMESTER2_PROPOSED,
TYPE_YEAR_FINAL,
TYPE_YEAR_PROPOSED
).map {
DataRemoveModel.Grades.allWithType(it)
})
}}
}

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-13
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
import android.graphics.Color
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.getFloat
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.getLong
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date
class PodlasieApiGrades(val data: DataPodlasie, val rows: List<JsonObject>) {
init {
rows.forEach { grade ->
val id = grade.getLong("ExternalId") ?: return@forEach
val name = grade.getString("Mark") ?: return@forEach
val value = data.app.gradesManager.getGradeValue(name)
val weight = grade.getFloat("Weight") ?: 0f
val includeToAverage = grade.getInt("IncludeToAverage") != 0
val color = grade.getString("Color")?.let { Color.parseColor(it) } ?: -1
val category = grade.getString("Category") ?: ""
val comment = grade.getString("Comment") ?: ""
val semester = grade.getString("TermShortcut")?.length ?: data.currentSemester
val teacherFirstName = grade.getString("TeacherFirstName") ?: return@forEach
val teacherLastName = grade.getString("TeacherLastName") ?: return@forEach
val teacher = data.getTeacher(teacherFirstName, teacherLastName)
val subjectName = grade.getString("SchoolSubject") ?: return@forEach
val subject = data.getSubject(subjectName)
val addedDate = grade.getString("ReceivedDate")?.let { Date.fromY_m_d(it).inMillis }
?: System.currentTimeMillis()
val gradeObject = Grade(
profileId = data.profileId,
id = id,
name = name,
type = Grade.TYPE_NORMAL,
value = value,
weight = if (includeToAverage) weight else 0f,
color = color,
category = category,
description = null,
comment = comment,
semester = semester,
teacherId = teacher.id,
subjectId = subject.id,
addedDate = addedDate
)
data.gradeList.add(gradeObject)
data.metadataList.add(
Metadata(
data.profileId,
Metadata.TYPE_GRADE,
id,
data.profile?.empty ?: false,
data.profile?.empty ?: false
))
}
data.toRemove.add(DataRemoveModel.Grades.allWithType(Grade.TYPE_NORMAL))
}
}

View File

@ -0,0 +1,64 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2020-5-14
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.data.api
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.crc32
import pl.szczodrzynski.edziennik.data.api.edziennik.podlasie.DataPodlasie
import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
import pl.szczodrzynski.edziennik.data.db.entity.Event
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.get
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date
class PodlasieApiHomework(val data: DataPodlasie, val rows: List<JsonObject>) {
init {
rows.reversed().forEach { homework ->
val id = homework.getString("ExternalId")?.crc32() ?: return@forEach
val topic = homework.getString("Title")?.replace("&#34;", "\"") ?: ""
val description = homework.getString("Message")?.replace("&#34;", "\"") ?: ""
val date = Date.getToday()
val addedDate = System.currentTimeMillis()
val eventObject = Event(
profileId = data.profileId,
id = id,
date = date,
time = null,
topic = topic,
color = null,
type = Event.TYPE_HOMEWORK,
teacherId = -1,
subjectId = -1,
teamId = data.teamClass?.id ?: -1,
addedDate = addedDate
).apply {
homeworkBody = description
}
eventObject.attachmentIds = mutableListOf()
eventObject.attachmentNames = mutableListOf()
homework.getString("Attachments")?.split(',')?.onEach { url ->
val filename = "&filename=(.*?)&".toRegex().find(url)?.get(1) ?: return@onEach
val ext = "&ext=(.*?)&".toRegex().find(url)?.get(1) ?: return@onEach
eventObject.attachmentIds?.add(url.crc32())
eventObject.attachmentNames?.add("$filename.$ext:$url")
}
data.eventList.add(eventObject)
data.metadataList.add(
Metadata(
data.profileId,
Metadata.TYPE_HOMEWORK,
id,
data.profile?.empty ?: false,
data.profile?.empty ?: false
))
}
data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
}
}

Some files were not shown because too many files have changed in this diff Show More