Compare commits

...

32 Commits

Author SHA1 Message Date
85ac5769a1 [4.5.1-beta.1] Update build.gradle, signing and changelog. 2021-02-22 23:25:44 +01:00
93e3d5994a [Vulcan/Hebe] Restore sending date range when getting attendance. 2021-02-22 23:20:32 +01:00
0cf24c527b [Vulcan/Hebe] Fix logging tag in notices class. 2021-02-22 23:04:10 +01:00
97c5acd6ba [Vulcan/Hebe] Fix checking for current year. 2021-02-22 22:59:02 +01:00
30aeb70647 [Vulcan/Hebe] Add filtering data by current school year. 2021-02-22 22:54:13 +01:00
b599d679c4 [Vulcan/Hebe] Implement sending messages. 2021-02-22 22:43:36 +01:00
1eecd24d91 [Vulcan/Hebe] Add getting notices. 2021-02-22 22:40:28 +01:00
c698dfdb73 [Vulcan/Hebe] Add getting grade summary. 2021-02-22 21:33:42 +01:00
c7a44f5ced [Vulcan/Hebe] Implement push notifications. 2021-02-22 19:13:25 +01:00
c8ee6ff1e7 [Vulcan/Hebe] Add getting lucky number. 2021-02-22 18:49:53 +01:00
552acd4043 [Vulcan/Web] Fix web login. 2021-02-22 18:23:27 +01:00
ede101ea20 [Vulcan/Hebe] Add saving lesson topic in attendance. 2021-02-22 17:51:52 +01:00
13c2640ed5 [UI] Hide API deprecation message on other profiles. 2021-02-22 17:43:34 +01:00
dd0739fd4b Merge branch 'develop' into feature/vulcan-hebe 2021-02-22 17:36:48 +01:00
9023f13932 [Vulcan/Hebe] Add missing copyright to files. 2021-02-22 17:18:40 +01:00
f8456fb087 [Lab] Add archiver enabled checkbox. 2021-02-22 16:37:53 +01:00
9b48041cd9 [4.5] Update build.gradle, signing and changelog. 2021-02-22 00:03:52 +01:00
46cecf3474 Merge branch 'feature/vulcan-hebe' into develop 2021-02-21 23:57:25 +01:00
c27254bcad [Vulcan] Remove API login mode form. 2021-02-21 23:55:11 +01:00
80333cdea4 [Vulcan] Add API deprecation message. 2021-02-21 23:52:45 +01:00
6aee3ea420 [4.5-beta.2] Update build.gradle, signing and changelog. 2021-02-21 23:36:55 +01:00
a11a44b768 [Vulcan/Hebe] Add handling custom presence types. 2021-02-21 23:30:20 +01:00
e869107101 [Vulcan/Hebe] Add syncing both semesters during first sync. 2021-02-21 23:26:43 +01:00
5903bbe59d [Vulcan/Hebe] Fix getting attendance. 2021-02-21 23:03:06 +01:00
6c0ddd3e6d [Vulcan/Hebe] Add setting message status as read. 2021-02-21 22:55:26 +01:00
621a7ac642 [Vulcan/Hebe] Add getting attendance. 2021-02-21 22:28:54 +01:00
e86b47fb1b [Vulcan/Hebe] Add getting messages. 2021-02-21 21:50:44 +01:00
98fb7ac8c9 [Vulcan/Web] Fix Proguard rules for platform selection. 2021-02-21 19:15:53 +01:00
f49e39e858 [Vulcan/Hebe] Add getting teacher list and addressbook. 2021-02-21 19:13:47 +01:00
8fc57cd3f5 [Vulcan/Hebe] Fix getting classroom name. 2021-02-21 17:22:21 +01:00
a9eda087e0 [Extensions] Update Gson extensions to check type. 2021-02-21 17:20:13 +01:00
b08e4c2d3d [Gradle] Update OkHttp to 3.12.13. 2021-02-19 13:24:12 +01:00
40 changed files with 1156 additions and 117 deletions

View File

@ -151,7 +151,7 @@ dependencies {
implementation "com.jaredrummler:colorpicker:1.0.2"
implementation("com.squareup.okhttp3:okhttp") {
version {
strictly "3.12.2"
strictly "3.12.13"
}
}
implementation "com.theartofdev.edmodo:android-image-cropper:2.8.0" // do not update

View File

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

View File

@ -1,6 +1,8 @@
<h3>Wersja 4.5-beta.1, 2021-02-21</h3>
<h3>Wersja 4.5.1-beta.1, 2021-02-22</h3>
<ul>
<li>Vulcan: aplikacja Szkolny.eu zaktualizowana w związku z wygaszeniem aplikacji Dzienniczek+.</li>
<li>Vulcan: dodano wyświetlanie <b>szczęśliwego numerka.</b></li>
<li>Vulcan: przywrócono uwagi oraz wysyłanie wiadomości.</li>
<li>Vulcan: usunięto wyświetlanie zadań domowych i sprawdzianów z poprzednich lat.</li>
</ul>
<br>
<br>

View File

@ -9,7 +9,7 @@
/*secret password - removed for source code publication*/
static toys AES_IV[16] = {
0x35, 0x4c, 0x9d, 0x0e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
0x42, 0xe5, 0x9a, 0x4e, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
unsigned char *agony(unsigned int laugh, unsigned char *box, unsigned char *heat);

View File

@ -96,30 +96,30 @@ fun List<Teacher>.byNameFDotSpaceLast(nameFDotSpaceLast: String) = firstOrNull {
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (it.isJsonNull) null else it.asBoolean }
fun JsonObject?.getString(key: String): String? = get(key)?.let { if (it.isJsonNull) null else it.asString }
fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (it.isJsonNull) null else it.asInt }
fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (it.isJsonNull) null else it.asLong }
fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(it.isJsonNull) null else it.asFloat }
fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(it.isJsonNull) null else it.asCharacter }
fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean }
fun JsonObject?.getString(key: String): String? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asString }
fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt }
fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong }
fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat }
fun JsonObject?.getChar(key: String): Char? = get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter }
fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (it.isJsonNull) defaultValue else it.asBoolean } ?: defaultValue
fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (it.isJsonNull) defaultValue else it.asString } ?: defaultValue
fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (it.isJsonNull) defaultValue else it.asInt } ?: defaultValue
fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (it.isJsonNull) defaultValue else it.asLong } ?: defaultValue
fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(it.isJsonNull) defaultValue else it.asFloat } ?: defaultValue
fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(it.isJsonNull) defaultValue else it.asCharacter } ?: defaultValue
fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asBoolean } ?: defaultValue
fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asString } ?: defaultValue
fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asInt } ?: defaultValue
fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (!it.isJsonPrimitive) defaultValue else it.asLong } ?: defaultValue
fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asFloat } ?: defaultValue
fun JsonObject?.getChar(key: String, defaultValue: Char): Char = get(key)?.let { if(!it.isJsonPrimitive) defaultValue else it.asCharacter } ?: defaultValue
fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonObject) it.asJsonObject else defaultValue } ?: defaultValue
fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonArray) it.asJsonArray else defaultValue } ?: defaultValue
fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asBoolean }
fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asString }
fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asInt }
fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (it.isJsonNull) null else it.asLong }
fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asFloat }
fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(it.isJsonNull) null else it.asCharacter }
fun JsonArray.getBoolean(key: Int): Boolean? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asBoolean }
fun JsonArray.getString(key: Int): String? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asString }
fun JsonArray.getInt(key: Int): Int? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asInt }
fun JsonArray.getLong(key: Int): Long? = if (key >= size()) null else get(key)?.let { if (!it.isJsonPrimitive) null else it.asLong }
fun JsonArray.getFloat(key: Int): Float? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asFloat }
fun JsonArray.getChar(key: Int): Char? = if (key >= size()) null else get(key)?.let { if(!it.isJsonPrimitive) null else it.asCharacter }
fun JsonArray.getJsonObject(key: Int): JsonObject? = if (key >= size()) null else get(key)?.let { if (it.isJsonObject) it.asJsonObject else null }
fun JsonArray.getJsonArray(key: Int): JsonArray? = if (key >= size()) null else get(key)?.let { if (it.isJsonArray) it.asJsonArray else null }
@ -538,6 +538,12 @@ fun String.md5(): String {
return BigInteger(1, md.digest(toByteArray())).toString(16).padStart(32, '0')
}
fun String.sha1Hex(): String {
val md = MessageDigest.getInstance("SHA-1")
md.update(toByteArray())
return md.digest().joinToString("") { "%02x".format(it) }
}
fun String.sha256(): ByteArray {
val md = MessageDigest.getInstance("SHA-256")
md.update(toByteArray())

View File

@ -38,6 +38,7 @@ import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import pl.droidsonroids.gif.GifDrawable
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
import pl.szczodrzynski.edziennik.data.api.edziennik.EdziennikTask
import pl.szczodrzynski.edziennik.data.api.events.*
import pl.szczodrzynski.edziennik.data.api.models.ApiError
@ -64,6 +65,7 @@ import pl.szczodrzynski.edziennik.ui.modules.base.MainSnackbar
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
import pl.szczodrzynski.edziennik.ui.modules.debug.DebugFragment
import pl.szczodrzynski.edziennik.ui.modules.debug.LabFragment
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorDetailsDialog
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
@ -749,6 +751,11 @@ class MainActivity : AppCompatActivity(), CoroutineScope {
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
fun onApiTaskErrorEvent(event: ApiTaskErrorEvent) {
EventBus.getDefault().removeStickyEvent(event)
if (event.error.errorCode == ERROR_VULCAN_API_DEPRECATED) {
if (event.error.profileId != App.profileId)
return
ErrorDetailsDialog(this, listOf(event.error))
}
navView.toolbar.apply {
subtitleFormat = R.string.toolbar_subtitle
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread

View File

@ -105,6 +105,11 @@ class Config(val db: AppDb) : CoroutineScope, AbstractConfig {
get() { mWidgetConfigs = mWidgetConfigs ?: values.get("widgetConfigs", JsonObject()); return mWidgetConfigs ?: JsonObject() }
set(value) { set("widgetConfigs", value); mWidgetConfigs = value }
private var mArchiverEnabled: Boolean? = null
var archiverEnabled: Boolean
get() { mArchiverEnabled = mArchiverEnabled ?: values.get("archiverEnabled", true); return mArchiverEnabled ?: true }
set(value) { set("archiverEnabled", value); mArchiverEnabled = value }
private var rawEntries: List<ConfigEntry> = db.configDao().getAllNow()
private val profileConfigs: HashMap<Int, ProfileConfig> = hashMapOf()
init {

View File

@ -127,11 +127,20 @@ const val VULCAN_WEB_ENDPOINT_LUCKY_NUMBER = "Start.mvc/GetKidsLuckyNumbers"
const val VULCAN_WEB_ENDPOINT_REGISTER_DEVICE = "RejestracjaUrzadzeniaToken.mvc/Get"
const val VULCAN_HEBE_ENDPOINT_REGISTER_NEW = "api/mobile/register/new"
const val VULCAN_HEBE_ENDPOINT_MAIN = "api/mobile/register/hebe"
const val VULCAN_HEBE_ENDPOINT_PUSH_ALL = "api/mobile/push/all"
const val VULCAN_HEBE_ENDPOINT_TIMETABLE = "api/mobile/schedule"
const val VULCAN_HEBE_ENDPOINT_TIMETABLE_CHANGES = "api/mobile/schedule/changes"
const val VULCAN_HEBE_ENDPOINT_ADDRESSBOOK = "api/mobile/addressbook"
const val VULCAN_HEBE_ENDPOINT_EXAMS = "api/mobile/exam"
const val VULCAN_HEBE_ENDPOINT_GRADES = "api/mobile/grade"
const val VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY = "api/mobile/grade/summary"
const val VULCAN_HEBE_ENDPOINT_HOMEWORK = "api/mobile/homework"
const val VULCAN_HEBE_ENDPOINT_NOTICES = "api/mobile/note"
const val VULCAN_HEBE_ENDPOINT_ATTENDANCE = "api/mobile/lesson"
const val VULCAN_HEBE_ENDPOINT_MESSAGES = "api/mobile/message"
const val VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS = "api/mobile/message/status"
const val VULCAN_HEBE_ENDPOINT_MESSAGES_SEND = "api/mobile/message"
const val VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER = "api/mobile/school/lucky"
const val EDUDZIENNIK_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME}"

View File

@ -171,6 +171,7 @@ 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_VULCAN_HEBE_OTHER = 354
const val ERROR_VULCAN_API_DEPRECATED = 390
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402

View File

@ -121,11 +121,9 @@ val vulcanLoginMethods = listOf(
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java)
.withIsPossible { _, loginStore ->
loginStore.mode != LOGIN_MODE_VULCAN_HEBE
loginStore.mode == LOGIN_MODE_VULCAN_API
}
.withRequiredLoginMethod { _, loginStore ->
if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_MAIN else LOGIN_METHOD_NOT_NEEDED
},
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_HEBE, VulcanLoginHebe::class.java)
.withIsPossible { _, loginStore ->

View File

@ -13,6 +13,8 @@ import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanData
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiAttachments
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiMessagesChangeStatus
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.VulcanApiSendMessage
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeMessagesChangeStatus
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeSendMessage
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.firstlogin.VulcanFirstLogin
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login.VulcanLogin
import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
@ -91,6 +93,20 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
}
override fun getMessage(message: MessageFull) {
if (loginStore.mode != LOGIN_MODE_VULCAN_API) {
login(LOGIN_METHOD_VULCAN_HEBE) {
if (message.seen) {
EventBus.getDefault().postSticky(MessageGetEvent(message))
completed()
return@login
}
VulcanHebeMessagesChangeStatus(data, message) {
completed()
}
}
return
}
login(LOGIN_METHOD_VULCAN_API) {
if (message.attachmentIds != null) {
VulcanApiMessagesChangeStatus(data, message) {
@ -120,6 +136,15 @@ class Vulcan(val app: App, val profile: Profile?, val loginStore: LoginStore, va
}
override fun sendMessage(recipients: List<Teacher>, subject: String, text: String) {
if (loginStore.mode != LOGIN_MODE_VULCAN_API) {
login(LOGIN_METHOD_VULCAN_HEBE) {
VulcanHebeSendMessage(data, recipients, subject, text) {
completed()
}
}
return
}
login(LOGIN_METHOD_VULCAN_API) {
VulcanApiSendMessage(data, recipients, subject, text) {
completed()

View File

@ -19,12 +19,22 @@ const val ENDPOINT_VULCAN_API_NOTICES = 1070
const val ENDPOINT_VULCAN_API_ATTENDANCE = 1080
const val ENDPOINT_VULCAN_API_MESSAGES_INBOX = 1090
const val ENDPOINT_VULCAN_API_MESSAGES_SENT = 1100
const val ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS = 2010
const val ENDPOINT_VULCAN_HEBE_MAIN = 3000
const val ENDPOINT_VULCAN_HEBE_PUSH_CONFIG = 3005
const val ENDPOINT_VULCAN_HEBE_ADDRESSBOOK = 3010
const val ENDPOINT_VULCAN_HEBE_TIMETABLE = 3020
const val ENDPOINT_VULCAN_HEBE_EXAMS = 3030
const val ENDPOINT_VULCAN_HEBE_GRADES = 3040
const val ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY = 3050
const val ENDPOINT_VULCAN_HEBE_HOMEWORK = 3060
const val ENDPOINT_VULCAN_HEBE_NOTICES = 3070
const val ENDPOINT_VULCAN_HEBE_ATTENDANCE = 3080
const val ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX = 3090
const val ENDPOINT_VULCAN_HEBE_MESSAGES_SENT = 3100
const val ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER = 3200
val VulcanFeatures = listOf(
// timetable
@ -47,7 +57,8 @@ val VulcanFeatures = listOf(
ENDPOINT_VULCAN_API_GRADES_SUMMARY to LOGIN_METHOD_VULCAN_API
), listOf(LOGIN_METHOD_VULCAN_API)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_GRADES, listOf(
ENDPOINT_VULCAN_HEBE_GRADES to LOGIN_METHOD_VULCAN_HEBE
ENDPOINT_VULCAN_HEBE_GRADES to LOGIN_METHOD_VULCAN_HEBE,
ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
// homework
Feature(LOGIN_TYPE_VULCAN, FEATURE_HOMEWORK, listOf(
@ -60,10 +71,16 @@ val VulcanFeatures = listOf(
Feature(LOGIN_TYPE_VULCAN, FEATURE_BEHAVIOUR, listOf(
ENDPOINT_VULCAN_API_NOTICES to LOGIN_METHOD_VULCAN_API
), listOf(LOGIN_METHOD_VULCAN_API)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_BEHAVIOUR, listOf(
ENDPOINT_VULCAN_HEBE_NOTICES to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
// attendance
Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf(
ENDPOINT_VULCAN_API_ATTENDANCE to LOGIN_METHOD_VULCAN_API
), listOf(LOGIN_METHOD_VULCAN_API)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_ATTENDANCE, listOf(
ENDPOINT_VULCAN_HEBE_ATTENDANCE to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
// messages
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf(
ENDPOINT_VULCAN_API_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_API
@ -71,6 +88,12 @@ val VulcanFeatures = listOf(
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf(
ENDPOINT_VULCAN_API_MESSAGES_SENT to LOGIN_METHOD_VULCAN_API
), listOf(LOGIN_METHOD_VULCAN_API)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_INBOX, listOf(
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_MESSAGES_SENT, listOf(
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE)),
// push config
Feature(LOGIN_TYPE_VULCAN, FEATURE_PUSH_CONFIG, listOf(
@ -78,18 +101,37 @@ val VulcanFeatures = listOf(
), listOf(LOGIN_METHOD_VULCAN_API)).withShouldSync { data ->
!data.app.config.sync.tokenVulcanList.contains(data.profileId)
},
Feature(LOGIN_TYPE_VULCAN, FEATURE_PUSH_CONFIG, listOf(
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE)).withShouldSync { data ->
!data.app.config.sync.tokenVulcanList.contains(data.profileId)
},
/**
* Lucky number - using WEB Main.
*/
Feature(LOGIN_TYPE_VULCAN, FEATURE_LUCKY_NUMBER, listOf(
ENDPOINT_VULCAN_WEB_LUCKY_NUMBERS to LOGIN_METHOD_VULCAN_WEB_MAIN
), listOf(LOGIN_METHOD_VULCAN_WEB_MAIN)).withShouldSync { data -> data.shouldSyncLuckyNumber() },
), listOf(LOGIN_METHOD_VULCAN_WEB_MAIN))
.withShouldSync { data -> data.shouldSyncLuckyNumber() }
.withPriority(2),
/**
* Lucky number - using Hebe API
*/
Feature(LOGIN_TYPE_VULCAN, FEATURE_LUCKY_NUMBER, listOf(
ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE))
.withShouldSync { data -> data.shouldSyncLuckyNumber() }
.withPriority(1),
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
ENDPOINT_VULCAN_API_UPDATE_SEMESTER to LOGIN_METHOD_VULCAN_API,
ENDPOINT_VULCAN_API_DICTIONARIES to LOGIN_METHOD_VULCAN_API
), listOf(LOGIN_METHOD_VULCAN_API))
), listOf(LOGIN_METHOD_VULCAN_API)),
Feature(LOGIN_TYPE_VULCAN, FEATURE_ALWAYS_NEEDED, listOf(
ENDPOINT_VULCAN_HEBE_MAIN to LOGIN_METHOD_VULCAN_HEBE,
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK to LOGIN_METHOD_VULCAN_HEBE
), listOf(LOGIN_METHOD_VULCAN_HEBE))
/*Feature(LOGIN_TYPE_VULCAN, FEATURE_STUDENT_INFO, listOf(
ENDPOINT_VULCAN_API to LOGIN_METHOD_VULCAN_WEB
), listOf(LOGIN_METHOD_VULCAN_WEB)),

View File

@ -5,13 +5,13 @@
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.data.api.ERROR_VULCAN_API_DEPRECATED
import pl.szczodrzynski.edziennik.data.api.LOGIN_MODE_VULCAN_API
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.*
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.api.*
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeExams
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeGrades
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeHomework
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.VulcanHebeTimetable
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe.*
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.web.VulcanWebLuckyNumber
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.utils.Utils
class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
@ -19,9 +19,38 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
private const val TAG = "VulcanData"
}
init {
nextEndpoint(onSuccess)
}
private var firstSemesterSync = false
private val firstSemesterSyncExclude = listOf(
ENDPOINT_VULCAN_HEBE_MAIN,
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK,
ENDPOINT_VULCAN_HEBE_TIMETABLE,
ENDPOINT_VULCAN_HEBE_EXAMS,
ENDPOINT_VULCAN_HEBE_HOMEWORK,
ENDPOINT_VULCAN_HEBE_NOTICES,
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX,
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
)
init { run {
if (data.loginStore.mode == LOGIN_MODE_VULCAN_API) {
data.error(TAG, ERROR_VULCAN_API_DEPRECATED)
return@run
}
if (data.studentSemesterNumber == 2 && data.profile?.empty != false) {
firstSemesterSync = true
// set to sync 1st semester first
data.studentSemesterId = data.semester1Id
data.studentSemesterNumber = 1
}
nextEndpoint {
if (firstSemesterSync) {
// at the end, set back 2nd semester
data.studentSemesterId = data.semester2Id
data.studentSemesterNumber = 2
}
onSuccess()
}
}}
private fun nextEndpoint(onSuccess: () -> Unit) {
if (data.targetEndpointIds.isEmpty()) {
@ -34,7 +63,21 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
}
val id = data.targetEndpointIds.firstKey()
val lastSync = data.targetEndpointIds.remove(id)
useEndpoint(id, lastSync) { endpointId ->
useEndpoint(id, lastSync) {
if (firstSemesterSync && id !in firstSemesterSyncExclude) {
// sync 2nd semester after every endpoint
data.studentSemesterId = data.semester2Id
data.studentSemesterNumber = 2
useEndpoint(id, lastSync) {
// set 1st semester back for the next endpoint
data.studentSemesterId = data.semester1Id
data.studentSemesterNumber = 1
// progress further
data.progress(data.progressStep)
nextEndpoint(onSuccess)
}
return@useEndpoint
}
data.progress(data.progressStep)
nextEndpoint(onSuccess)
}
@ -95,6 +138,27 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
VulcanWebLuckyNumber(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_MAIN -> {
if (data.profile == null) {
onSuccess(ENDPOINT_VULCAN_HEBE_MAIN)
return
}
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
VulcanHebeMain(data, lastSync).getStudents(
profile = data.profile,
profileList = null
) {
onSuccess(ENDPOINT_VULCAN_HEBE_MAIN)
}
}
ENDPOINT_VULCAN_HEBE_PUSH_CONFIG -> {
data.startProgress(R.string.edziennik_progress_endpoint_push_config)
VulcanHebePushConfig(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_ADDRESSBOOK -> {
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
VulcanHebeAddressbook(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_TIMETABLE -> {
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
VulcanHebeTimetable(data, lastSync, onSuccess)
@ -107,10 +171,34 @@ class VulcanData(val data: DataVulcan, val onSuccess: () -> Unit) {
data.startProgress(R.string.edziennik_progress_endpoint_grades)
VulcanHebeGrades(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY -> {
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
VulcanHebeGradeSummary(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_HOMEWORK -> {
data.startProgress(R.string.edziennik_progress_endpoint_homework)
VulcanHebeHomework(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_NOTICES -> {
data.startProgress(R.string.edziennik_progress_endpoint_notices)
VulcanHebeNotices(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_ATTENDANCE -> {
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
VulcanHebeAttendance(data, lastSync, onSuccess)
}
ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_RECEIVED)
}
ENDPOINT_VULCAN_HEBE_MESSAGES_SENT -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
VulcanHebeMessages(data, lastSync, onSuccess).getMessages(Message.TYPE_SENT)
}
ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER -> {
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
VulcanHebeLuckyNumber(data, lastSync, onSuccess)
}
else -> onSuccess(endpointId)
}
}

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-20.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data
import android.os.Build
@ -42,9 +46,13 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
val profile
get() = data.profile
fun getDateTime(json: JsonObject?, key: String): Long {
fun getDateTime(
json: JsonObject?,
key: String,
default: Long = System.currentTimeMillis()
): Long {
val date = json.getJsonObject(key)
return date.getLong("Timestamp") ?: return System.currentTimeMillis()
return date.getLong("Timestamp") ?: return default
}
fun getDate(json: JsonObject?, key: String): Date? {
@ -142,6 +150,18 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
2
}
fun isCurrentYear(date: Date): Boolean {
return profile?.let { profile ->
return@let date >= profile.dateSemester1Start
} ?: false
}
fun isCurrentYear(dateTime: Long): Boolean {
return profile?.let { profile ->
return@let dateTime >= profile.dateSemester1Start.inMillis
} ?: false
}
inline fun <reified T> apiRequest(
tag: String,
endpoint: String,
@ -193,7 +213,8 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
val callback = object : JsonCallbackHandler() {
override fun onSuccess(json: JsonObject?, response: Response?) {
if (json == null) {
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
data.error(
ApiError(TAG, ERROR_RESPONSE_EMPTY)
.withResponse(response)
)
return
@ -201,27 +222,34 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
val status = json.getJsonObject("Status")
if (status?.getInt("Code") != 0) {
data.error(ApiError(tag, ERROR_VULCAN_HEBE_OTHER)
.withResponse(response)
.withApiResponse(json.toString()))
data.error(
ApiError(tag, ERROR_VULCAN_HEBE_OTHER)
.withResponse(response)
.withApiResponse(json.toString())
)
}
val envelope = when (T::class.java) {
JsonObject::class.java -> json.getJsonObject("Envelope")
JsonArray::class.java -> json.getJsonArray("Envelope")
val envelope = if (json.get("Envelope").isJsonNull && null is T)
null as T
else when (T::class.java) {
JsonObject::class.java -> json.getJsonObject("Envelope") as T
JsonArray::class.java -> json.getJsonArray("Envelope") as T
java.lang.Boolean::class.java -> json.getBoolean("Envelope") as T
else -> {
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
.withResponse(response)
.withApiResponse(json)
data.error(
ApiError(tag, ERROR_RESPONSE_EMPTY)
.withResponse(response)
.withApiResponse(json)
)
return
}
}
try {
onSuccess(envelope as T, response)
onSuccess(envelope, response)
} catch (e: Exception) {
data.error(ApiError(tag, EXCEPTION_VULCAN_HEBE_REQUEST)
data.error(
ApiError(tag, EXCEPTION_VULCAN_HEBE_REQUEST)
.withResponse(response)
.withThrowable(e)
.withApiResponse(json)
@ -230,7 +258,8 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
}
override fun onFailure(response: Response?, throwable: Throwable?) {
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
data.error(
ApiError(tag, ERROR_REQUEST_FAILURE)
.withResponse(response)
.withThrowable(throwable)
)
@ -346,10 +375,15 @@ open class VulcanHebe(open val data: DataVulcan, open val lastSync: Long?) {
if (folder != null)
query["folder"] = folder.toString()
val semester1Start = profile?.dateSemester1Start?.inMillis
query["lastId"] = "-2147483648" // don't ask, it's just Vulcan
query["pageSize"] = "500"
query["lastSyncDate"] = LocalDateTime
.ofInstant(Instant.ofEpochMilli(lastSync ?: 0), ZoneId.systemDefault())
.ofInstant(
Instant.ofEpochMilli(lastSync ?: semester1Start ?: 0),
ZoneId.systemDefault()
)
.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
apiGet(tag, url, query) { json: JsonArray, response ->

View File

@ -144,7 +144,7 @@ open class VulcanWebMain(open val data: DataVulcan, open val lastSync: Long?) {
var count = 0
while (clientIndex != -1 && count < 100) {
val startIndex = clientIndex + clientUrl.length
val endIndex = text.indexOf('/', startIndex = startIndex)
val endIndex = text.indexOf('"', startIndex = startIndex)
val schoolSymbol = text.substring(startIndex, endIndex)
schoolSymbols += schoolSymbol
clientIndex = text.indexOf(clientUrl, startIndex = endIndex)

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-20.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
enum class HebeFilterType(val endpoint: String) {

View File

@ -0,0 +1,122 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import androidx.core.util.set
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ADDRESSBOOK
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_ADDRESSBOOK
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_EDUCATOR
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_OTHER
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_PARENT
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_PARENTS_COUNCIL
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_STUDENT
import pl.szczodrzynski.edziennik.data.db.entity.Teacher.Companion.TYPE_TEACHER
import kotlin.text.replace
class VulcanHebeAddressbook(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebeAddressbook"
}
private fun String.removeUnitName(unitName: String?): String {
return (unitName ?: data.schoolShort)?.let {
this.replace("($it)", "").trim()
} ?: this
}
init {
apiGetList(
TAG,
VULCAN_HEBE_ENDPOINT_ADDRESSBOOK,
HebeFilterType.BY_PERSON,
lastSync = lastSync,
includeFilterType = false
) { list, _ ->
list.forEach { person ->
val id = person.getString("Id") ?: return@forEach
val loginId = person.getString("LoginId") ?: return@forEach
val idType = id.split("-")
.getOrNull(0)
val idLong = id.split("-")
.getOrNull(1)
?.toLongOrNull()
?: return@forEach
val typeBase = when (idType) {
"e" -> TYPE_TEACHER
"c" -> TYPE_PARENT
"p" -> TYPE_STUDENT
else -> TYPE_OTHER
}
val name = person.getString("Name") ?: ""
val surname = person.getString("Surname") ?: ""
val namePrefix = "$surname $name - "
val teacher = data.teacherList[idLong] ?: Teacher(
data.profileId,
idLong,
name,
surname,
loginId
).also {
data.teacherList[idLong] = it
}
person.getJsonArray("Roles")?.asJsonObjectList()?.onEach { role ->
var roleText: String? = null
val unitName = role.getString("ConstituentUnitSymbol")
val personType = when (role.getInt("RoleOrder")) {
0 -> { /* Wychowawca */
roleText = role.getString("ClassSymbol")
?.removeUnitName(unitName)
TYPE_EDUCATOR
}
1 -> TYPE_TEACHER /* Nauczyciel */
2 -> return@onEach /* Pracownik */
3 -> { /* Rada rodziców */
roleText = role.getString("Address")
?.removeUnitName(unitName)
?.removePrefix(namePrefix)
?.trim()
TYPE_PARENTS_COUNCIL
}
5 -> {
roleText = role.getString("RoleName")
?.plus(" - ")
?.plus(
role.getString("Address")
?.removeUnitName(unitName)
?.removePrefix(namePrefix)
?.trim()
)
TYPE_STUDENT
}
else -> TYPE_OTHER
}
teacher.setTeacherType(personType)
teacher.typeDescription = roleText
}
if (teacher.type == 0)
teacher.setTeacherType(typeBase)
}
data.setSyncNext(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK, 2 * DAY)
onSuccess(ENDPOINT_VULCAN_HEBE_ADDRESSBOOK)
}
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2021-2-21
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_ATTENDANCE
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_ATTENDANCE
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.Attendance
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
class VulcanHebeAttendance(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebeAttendance"
}
init {
val semesterNumber = data.studentSemesterNumber
val startDate = profile?.getSemesterStart(semesterNumber)
val endDate = profile?.getSemesterEnd(semesterNumber)
apiGetList(
TAG,
VULCAN_HEBE_ENDPOINT_ATTENDANCE,
HebeFilterType.BY_PUPIL,
dateFrom = startDate,
dateTo = endDate,
lastSync = lastSync
) { list, _ ->
list.forEach { attendance ->
val id = attendance.getLong("AuxPresenceId") ?: return@forEach
val type = attendance.getJsonObject("PresenceType") ?: return@forEach
val baseType = getBaseType(type)
val typeName = type.getString("Name") ?: return@forEach
val typeCategoryId = type.getLong("CategoryId") ?: return@forEach
val typeSymbol = type.getString("Symbol") ?: return@forEach
val typeShort = when (typeCategoryId.toInt()) {
6, 8 -> typeSymbol
else -> data.app.attendanceManager.getTypeShort(baseType)
}
val typeColor = when (typeCategoryId.toInt()) {
1 -> 0xffffffff // obecność
2 -> 0xffffa687 // nieobecność
3 -> 0xfffcc150 // nieobecność usprawiedliwiona
4 -> 0xffede049 // spóźnienie
5 -> 0xffbbdd5f // spóźnienie usprawiedliwione
6 -> 0xffa9c9fd // nieobecny z przyczyn szkolnych
7 -> 0xffddbbe5 // zwolniony
8 -> 0xffffffff // usunięty wpis
else -> null
}?.toInt()
val date = getDate(attendance, "Day") ?: return@forEach
val lessonRange = getLessonRange(attendance, "TimeSlot")
val startTime = lessonRange?.startTime
val semester = profile?.dateToSemester(date) ?: return@forEach
val teacherId = attendance.getJsonObject("TeacherPrimary")?.getLong("Id") ?: -1
val subjectId = attendance.getJsonObject("Subject")?.getLong("Id") ?: -1
val addedDate = getDateTime(attendance, "DateModify")
val lessonNumber = lessonRange?.lessonNumber
val isCounted = attendance.getBoolean("CalculatePresence")
?: (baseType != Attendance.TYPE_RELEASED)
val attendanceObject = Attendance(
profileId = profileId,
id = id,
baseType = baseType,
typeName = typeName,
typeShort = typeShort,
typeSymbol = typeSymbol,
typeColor = typeColor,
date = date,
startTime = startTime,
semester = semester,
teacherId = teacherId,
subjectId = subjectId,
addedDate = addedDate
).also {
it.lessonTopic = attendance.getString("Topic")
it.lessonNumber = lessonNumber
it.isCounted = isCounted
}
data.attendanceList.add(attendanceObject)
if (baseType != Attendance.TYPE_PRESENT) {
data.metadataList.add(
Metadata(
profileId,
Metadata.TYPE_ATTENDANCE,
attendanceObject.id,
profile?.empty ?: true
|| baseType == Attendance.TYPE_PRESENT_CUSTOM
|| baseType == Attendance.TYPE_UNKNOWN,
profile?.empty ?: true
|| baseType == Attendance.TYPE_PRESENT_CUSTOM
|| baseType == Attendance.TYPE_UNKNOWN
)
)
}
}
data.setSyncNext(ENDPOINT_VULCAN_HEBE_ATTENDANCE, SYNC_ALWAYS)
onSuccess(ENDPOINT_VULCAN_HEBE_ATTENDANCE)
}
}
fun getBaseType(attendanceType: JsonObject): Int {
val absent = attendanceType.getBoolean("Absence") ?: false
val excused = attendanceType.getBoolean("AbsenceJustified") ?: false
return if (absent) {
if (excused)
Attendance.TYPE_ABSENT_EXCUSED
else
Attendance.TYPE_ABSENT
} else {
val belated = attendanceType.getBoolean("Late") ?: false
val released = attendanceType.getBoolean("LegalAbsence") ?: false
val present = attendanceType.getBoolean("Presence") ?: true
if (belated)
if (excused)
Attendance.TYPE_BELATED_EXCUSED
else
Attendance.TYPE_BELATED
else if (released)
Attendance.TYPE_RELEASED
else if (present)
if (attendanceType.getInt("CategoryId") != 1)
Attendance.TYPE_PRESENT_CUSTOM
else
Attendance.TYPE_PRESENT
else
Attendance.TYPE_UNKNOWN
}
}
}

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import pl.szczodrzynski.edziennik.*
@ -36,6 +40,8 @@ class VulcanHebeExams(
?: -1
val topic = exam.getString("Content")?.trim() ?: ""
if (!isCurrentYear(eventDate)) return@forEach
val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime

View File

@ -0,0 +1,88 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-22.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import pl.szczodrzynski.edziennik.DAY
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.Grade
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils
class VulcanHebeGradeSummary(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebeGradeSummary"
}
init {
val entries = mapOf(
"Entry_1" to
if (data.studentSemesterNumber == 1)
Grade.TYPE_SEMESTER1_PROPOSED
else Grade.TYPE_SEMESTER2_PROPOSED,
"Entry_2" to
if (data.studentSemesterNumber == 1)
Grade.TYPE_SEMESTER1_FINAL
else Grade.TYPE_SEMESTER2_FINAL
)
apiGetList(
TAG,
VULCAN_HEBE_ENDPOINT_GRADE_SUMMARY,
HebeFilterType.BY_PUPIL,
lastSync = lastSync
) { list, _ ->
list.forEach { grade ->
val subjectId = getSubjectId(grade, "Subject") ?: return@forEach
val addedDate = getDateTime(grade, "DateModify")
entries.onEach { (key, type) ->
val id = subjectId * -100 - type
val entry = grade.getString(key) ?: return@onEach
val value = Utils.getGradeValue(entry)
val color = Utils.getVulcanGradeColor(entry)
val gradeObject = Grade(
profileId = profileId,
id = id,
name = entry,
type = type,
value = value,
weight = 0f,
color = color,
category = "",
description = null,
comment = null,
semester = data.studentSemesterNumber,
teacherId = -1,
subjectId = subjectId,
addedDate = addedDate
)
data.gradeList.add(gradeObject)
data.metadataList.add(
Metadata(
profileId,
Metadata.TYPE_GRADE,
id,
profile?.empty ?: true,
profile?.empty ?: true
)
)
}
}
data.setSyncNext(ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY, 1 * DAY)
onSuccess(ENDPOINT_VULCAN_HEBE_GRADE_SUMMARY)
}
}
}

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-20.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import pl.szczodrzynski.edziennik.*

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_HOMEWORK
@ -34,6 +38,8 @@ class VulcanHebeHomework(
val teamId = data.teamClass?.id ?: -1
val topic = exam.getString("Content")?.trim() ?: ""
if (!isCurrentYear(eventDate)) return@forEach
val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime

View File

@ -0,0 +1,72 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-22.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
import pl.szczodrzynski.edziennik.utils.models.Week
class VulcanHebeLuckyNumber(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebeLuckyNumber"
}
init {
apiGet(
TAG,
VULCAN_HEBE_ENDPOINT_LUCKY_NUMBER,
query = mapOf(
"constituentId" to data.studentConstituentId.toString(),
"day" to Date.getToday().stringY_m_d
)
) { lucky: JsonObject?, _ ->
// sync tomorrow if lucky number set or is weekend or afternoon
var nextSync = Date.getToday().stepForward(0, 0, 1).inMillis
if (lucky == null) {
if (Date.getToday().weekDay <= Week.FRIDAY && Time.getNow().hour < 12) {
// working days morning, sync always
nextSync = SYNC_ALWAYS
}
}
else {
val luckyNumberDate = Date.fromY_m_d(lucky.getString("Day")) ?: Date.getToday()
val luckyNumber = lucky.getInt("Number") ?: -1
val luckyNumberObject = LuckyNumber(
profileId = profileId,
date = luckyNumberDate,
number = luckyNumber
)
data.luckyNumberList.add(luckyNumberObject)
data.metadataList.add(
Metadata(
profileId,
Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(),
true,
profile?.empty ?: false
)
)
}
data.setSyncNext(ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER, syncAt = nextSync)
onSuccess(ENDPOINT_VULCAN_HEBE_LUCKY_NUMBER)
}
}
}

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-20.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import com.google.gson.JsonArray
@ -76,7 +80,7 @@ class VulcanHebeMain(
}
val schoolSymbol = unit.getString("Symbol") ?: return@forEach
val schoolShort = unit.getString("Short") ?: return@forEach
val schoolShort = constituentUnit.getString("Short") ?: return@forEach
val schoolCode = "${data.symbol}_$schoolSymbol"
val studentUnitId = unit.getInt("Id") ?: return@forEach

View File

@ -0,0 +1,133 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import androidx.core.util.set
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.*
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
import pl.szczodrzynski.navlib.crc16
import kotlin.text.replace
class VulcanHebeMessages(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebeMessagesInbox"
}
private fun getPersonId(json: JsonObject): Long {
val senderLoginId = json.getInt("LoginId") ?: return -1
/*if (senderLoginId == data.studentLoginId)
return -1*/
val senderName = json.getString("Address") ?: return -1
val senderNameSplit = senderName.splitName()
val senderLoginIdStr = senderLoginId.toString()
val teacher = data.teacherList.singleOrNull { it.loginId == senderLoginIdStr }
?: Teacher(
profileId,
-1 * crc16(senderName).toLong(),
senderNameSplit?.second ?: "",
senderNameSplit?.first ?: "",
senderLoginIdStr
).also {
it.setTeacherType(Teacher.TYPE_OTHER)
data.teacherList[it.id] = it
}
return teacher.id
}
fun getMessages(messageType: Int) {
val folder = when (messageType) {
TYPE_RECEIVED -> 1
TYPE_SENT -> 2
TYPE_DELETED -> 3
else -> 1
}
val endpointId = when (messageType) {
TYPE_RECEIVED -> ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
TYPE_SENT -> ENDPOINT_VULCAN_HEBE_MESSAGES_SENT
else -> ENDPOINT_VULCAN_HEBE_MESSAGES_INBOX
}
apiGetList(
TAG,
VULCAN_HEBE_ENDPOINT_MESSAGES,
HebeFilterType.BY_PERSON,
folder = folder,
lastSync = lastSync
) { list, _ ->
list.forEach { message ->
val id = message.getLong("Id") ?: return@forEach
val subject = message.getString("Subject") ?: return@forEach
val body = message.getString("Content") ?: return@forEach
val sender = message.getJsonObject("Sender") ?: return@forEach
val sentDate = getDateTime(message, "DateSent")
val readDate = getDateTime(message, "DateRead", default = 0)
if (!isCurrentYear(sentDate)) return@forEach
val messageObject = Message(
profileId = profileId,
id = id,
type = messageType,
subject = subject,
body = body.replace("\n", "<br>"),
senderId = if (messageType == TYPE_RECEIVED) getPersonId(sender) else null,
addedDate = sentDate
)
val receivers = message.getJsonArray("Receiver")
?.asJsonObjectList()
?: return@forEach
val receiverReadDate =
if (receivers.size == 1) readDate
else -1
for (receiver in receivers) {
val messageRecipientObject = MessageRecipient(
profileId,
if (messageType == TYPE_SENT) getPersonId(receiver) else -1,
-1,
receiverReadDate,
id
)
data.messageRecipientList.add(messageRecipientObject)
}
data.messageList.add(messageObject)
data.setSeenMetadataList.add(
Metadata(
profileId,
Metadata.TYPE_MESSAGE,
id,
readDate > 0 || messageType == TYPE_SENT,
readDate > 0 || messageType == TYPE_SENT
)
)
}
data.setSyncNext(
endpointId,
if (messageType == TYPE_RECEIVED) SYNC_ALWAYS else 1 * DAY,
if (messageType == TYPE_RECEIVED) null else DRAWER_ITEM_MESSAGES
)
onSuccess(endpointId)
}
}
}

View File

@ -0,0 +1,66 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.JsonObject
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.full.MessageFull
class VulcanHebeMessagesChangeStatus(
override val data: DataVulcan,
private val messageObject: MessageFull,
val onSuccess: () -> Unit
) : VulcanHebe(data, null) {
companion object {
const val TAG = "VulcanHebeMessagesChangeStatus"
}
init {
apiPost(
TAG,
VULCAN_HEBE_ENDPOINT_MESSAGES_STATUS,
payload = JsonObject(
"MessageId" to messageObject.id,
"LoginId" to data.studentLoginId,
"Status" to 1
)
) { _: Boolean, _ ->
if (!messageObject.seen) {
data.setSeenMetadataList.add(
Metadata(
profileId,
Metadata.TYPE_MESSAGE,
messageObject.id,
true,
true
)
)
messageObject.seen = true
}
if (messageObject.type != Message.TYPE_SENT) {
val messageRecipientObject = MessageRecipient(
profileId,
-1,
-1,
System.currentTimeMillis(),
messageObject.id
)
data.messageRecipientList.add(messageRecipientObject)
}
EventBus.getDefault().postSticky(MessageGetEvent(messageObject))
onSuccess()
}
}
}

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) Kacper Ziubryniewicz 2021-2-22
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_NOTICES
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_NOTICES
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Notice
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
class VulcanHebeNotices(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebeNotices"
}
init {
apiGetList(
TAG,
VULCAN_HEBE_ENDPOINT_NOTICES,
HebeFilterType.BY_PUPIL,
lastSync = lastSync
) { list, _ ->
list.forEach { notice ->
val id = notice.getLong("Id") ?: return@forEach
val type = when (notice.getBoolean("Positive")) {
true -> Notice.TYPE_POSITIVE
else -> Notice.TYPE_NEUTRAL
}
val date = getDate(notice, "DateValid") ?: return@forEach
val semester = profile?.dateToSemester(date) ?: return@forEach
val text = notice.getString("Content") ?: ""
val category = notice.getJsonObject("Category")?.getString("Name")
val points = notice.getFloat("Points")
val teacherId = getTeacherId(notice, "Creator") ?: -1
val addedDate = getDateTime(notice, "DateModify")
if (!isCurrentYear(date)) return@forEach
val noticeObject = Notice(
profileId = profileId,
id = id,
type = type,
semester = semester,
text = text,
category = category,
points = points,
teacherId = teacherId,
addedDate = addedDate
)
data.noticeList.add(noticeObject)
data.metadataList.add(
Metadata(
profileId,
Metadata.TYPE_NOTICE,
id,
profile?.empty ?: true,
profile?.empty ?: true
)
)
}
data.setSyncNext(ENDPOINT_VULCAN_HEBE_NOTICES, SYNC_ALWAYS)
onSuccess(ENDPOINT_VULCAN_HEBE_NOTICES)
}
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-22.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import com.google.gson.JsonPrimitive
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_PUSH_ALL
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.ENDPOINT_VULCAN_HEBE_PUSH_CONFIG
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
class VulcanHebePushConfig(
override val data: DataVulcan,
override val lastSync: Long?,
val onSuccess: (endpointId: Int) -> Unit
) : VulcanHebe(data, lastSync) {
companion object {
const val TAG = "VulcanHebePushConfig"
}
init {
apiPost(
TAG,
VULCAN_HEBE_ENDPOINT_PUSH_ALL,
payload = JsonPrimitive("on")
) { _: Boolean, _ ->
// sync always: this endpoint has .shouldSync set
data.setSyncNext(ENDPOINT_VULCAN_HEBE_PUSH_CONFIG, SYNC_ALWAYS)
data.app.config.sync.tokenVulcanList =
data.app.config.sync.tokenVulcanList + profileId
onSuccess(ENDPOINT_VULCAN_HEBE_PUSH_CONFIG)
}
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-22.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import com.google.gson.JsonObject
import org.greenrobot.eventbus.EventBus
import pl.szczodrzynski.edziennik.*
import pl.szczodrzynski.edziennik.data.api.VULCAN_HEBE_ENDPOINT_MESSAGES_SEND
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.DataVulcan
import pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.VulcanHebe
import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
import pl.szczodrzynski.edziennik.data.db.entity.Message
import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.data.db.entity.Teacher
class VulcanHebeSendMessage(
override val data: DataVulcan,
val recipients: List<Teacher>,
val subject: String,
val text: String,
val onSuccess: () -> Unit
) : VulcanHebe(data, null) {
companion object {
const val TAG = "VulcanHebeSendMessage"
}
init {
val recipientsArray = JsonArray()
recipients.forEach { teacher ->
recipientsArray += JsonObject(
"Address" to teacher.fullNameLastFirst,
"LoginId" to (teacher.loginId?.toIntOrNull() ?: return@forEach),
"Initials" to teacher.initialsLastFirst,
"AddressHash" to teacher.fullNameLastFirst.sha1Hex()
)
}
val senderName = (profile?.accountName ?: profile?.studentNameLong)
?.swapFirstLastName() ?: ""
val sender = JsonObject(
"Address" to senderName,
"LoginId" to data.studentLoginId.toString(),
"Initials" to senderName.getNameInitials(),
"AddressHash" to senderName.sha1Hex()
)
apiPost(
TAG,
VULCAN_HEBE_ENDPOINT_MESSAGES_SEND,
payload = JsonObject(
"Status" to 1,
"Sender" to sender,
"DateSent" to null,
"DateRead" to null,
"Content" to text,
"Receiver" to recipientsArray,
"Id" to 0,
"Subject" to subject,
"Attachments" to null,
"Self" to null
)
) { json: JsonObject, _ ->
val messageId = json.getLong("Id")
if (messageId == null) {
// TODO error
return@apiPost
}
VulcanHebeMessages(data, null) {
val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == messageId }
val event = MessageSentEvent(data.profileId, message, message?.addedDate)
EventBus.getDefault().postSticky(event)
onSuccess()
}.getMessages(Message.TYPE_SENT)
}
}
}

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-21.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.data.hebe
import com.google.gson.JsonObject
@ -119,7 +123,7 @@ class VulcanHebeTimetable(
val startTime = lessonRange?.startTime
val endTime = lessonRange?.endTime
val teacherId = getTeacherId(json, "TeacherPrimary")
val classroom = json.getString("Room")
val classroom = json.getJsonObject("Room").getString("Code")
val subjectId = getSubjectId(json, "Subject")
val teamId = getTeamId(json, "Distribution")
@ -168,7 +172,7 @@ class VulcanHebeTimetable(
val changeStartTime = changeLessonRange?.startTime
val changeEndTime = changeLessonRange?.endTime
val changeTeacherId = getTeacherId(changeJson, "TeacherPrimary") ?: teacherId
val changeClassroom = changeJson.getString("Room") ?: classroom
val changeClassroom = changeJson.getJsonObject("Room").getString("Code") ?: classroom
val changeSubjectId = getSubjectId(changeJson, "Subject") ?: subjectId
val changeTeamId = getTeamId(json, "Distribution")

View File

@ -1,3 +1,7 @@
/*
* Copyright (c) Kuba Szczodrzyński 2021-2-20.
*/
package pl.szczodrzynski.edziennik.data.api.edziennik.vulcan.login
import com.google.gson.JsonObject

View File

@ -46,6 +46,6 @@ object Signing {
/*fun provideKey(param1: String, param2: Long): ByteArray {*/
fun pleaseStopRightNow(param1: String, param2: Long): ByteArray {
return "$param1.MTIzNDU2Nzg5MDQLA8n9Ff===.$param2".sha256()
return "$param1.MTIzNDU2Nzg5MD8+8LPFtX===.$param2".sha256()
}
}

View File

@ -103,7 +103,9 @@ open class Profile(
dateSemester2Start.year -= diff
dateYearEnd.year -= diff
}
return Date.getToday() >= dateYearEnd && Date.getToday().year > studentSchoolYearStart
return App.config.archiverEnabled
&& Date.getToday() >= dateYearEnd
&& Date.getToday().year > studentSchoolYearStart
}
fun isBeforeYear() = false && Date.getToday() < dateSemester1Start

View File

@ -11,6 +11,7 @@ import androidx.room.Entity
import androidx.room.Ignore
import pl.szczodrzynski.edziennik.R
import pl.szczodrzynski.edziennik.fixName
import pl.szczodrzynski.edziennik.getNameInitials
import pl.szczodrzynski.edziennik.join
import java.util.*
@ -180,6 +181,9 @@ open class Teacher {
@delegate:Ignore
val fullNameLastFirst by lazy { "$surname $name".fixName() }
@delegate:Ignore
val initialsLastFirst by lazy { fullNameLastFirst.getNameInitials() }
val shortName: String
get() = (if (name == null || name?.length == 0) "" else name!![0].toString()) + "." + surname

View File

@ -29,6 +29,7 @@ class SzkolnyVulcanFirebase(val app: App, val profiles: List<Profile>, val messa
val data = message.data.getString("data")?.toJsonObject() ?: return@run
val type = data.getString("table") ?: return@run
val studentId = data.getInt("pupilid")
val loginId = data.getInt("loginid")
/* pl.vulcan.uonetmobile.auxilary.enums.CDCPushEnum */
val viewIdPair = when (type.toLowerCase(Locale.ROOT)) {
@ -42,8 +43,9 @@ class SzkolnyVulcanFirebase(val app: App, val profiles: List<Profile>, val messa
}
val tasks = profiles.filter {
it.loginStoreType == LOGIN_TYPE_VULCAN &&
it.getStudentData("studentId", 0) == studentId
it.loginStoreType == LOGIN_TYPE_VULCAN
&& (it.getStudentData("studentId", 0) == studentId
|| it.getStudentData("studentLoginId", 0) == loginId)
}.map {
EdziennikTask.syncProfile(it.id, listOf(viewIdPair))
}

View File

@ -45,6 +45,8 @@ class LabPageFragment : LazyFragment(), CoroutineScope {
}
override fun onPageCreated(): Boolean {
b.app = app
b.last10unseen.onClick {
launch(Dispatchers.Default) {
val events = app.db.eventDao().getAllNow(App.profileId)

View File

@ -130,65 +130,13 @@ object LoginInfo {
registerName = R.string.login_type_vulcan,
registerLogo = R.drawable.login_logo_vulcan,
loginModes = listOf(
Mode(
loginMode = LOGIN_MODE_VULCAN_API,
name = R.string.login_mode_vulcan_api,
icon = R.drawable.login_mode_vulcan_api,
hintText = R.string.login_mode_vulcan_api_hint,
guideText = R.string.login_mode_vulcan_api_guide,
isRecommended = true,
credentials = listOf(
FormField(
keyName = "deviceToken",
name = R.string.login_hint_token,
icon = CommunityMaterial.Icon.cmd_code_braces,
emptyText = R.string.login_error_no_token,
invalidText = R.string.login_error_incorrect_token,
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_INVALID_TOKEN to R.string.login_error_incorrect_token
),
isRequired = true,
validationRegex = "[A-Z0-9]{5,12}",
caseMode = FormField.CaseMode.UPPER_CASE
),
FormField(
keyName = "symbol",
name = R.string.login_hint_symbol,
icon = CommunityMaterial.Icon2.cmd_school,
emptyText = R.string.login_error_no_symbol,
invalidText = R.string.login_error_incorrect_symbol,
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_INVALID_SYMBOL to R.string.login_error_incorrect_symbol
),
isRequired = true,
validationRegex = "[a-z0-9_-]+",
caseMode = FormField.CaseMode.LOWER_CASE
),
FormField(
keyName = "devicePin",
name = R.string.login_hint_pin,
icon = CommunityMaterial.Icon2.cmd_lock,
emptyText = R.string.login_error_no_pin,
invalidText = R.string.login_error_incorrect_pin,
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_INVALID_PIN to R.string.login_error_incorrect_pin
),
isRequired = true,
validationRegex = "[0-9]+",
caseMode = FormField.CaseMode.LOWER_CASE
)
),
errorCodes = mapOf(
ERROR_LOGIN_VULCAN_EXPIRED_TOKEN to R.string.login_error_expired_token
)
),
Mode(
loginMode = LOGIN_MODE_VULCAN_HEBE,
name = R.string.login_mode_vulcan_api,
icon = R.drawable.login_mode_vulcan_hebe,
hintText = R.string.login_mode_vulcan_api_hint,
guideText = R.string.login_mode_vulcan_api_guide,
isTesting = true,
isRecommended = true,
credentials = listOf(
FormField(
keyName = "deviceToken",

View File

@ -7,6 +7,10 @@
xmlns:android="http://schemas.android.com/apk/res/android"
tools:ignore="HardcodedText">
<data>
<variable name="app" type="pl.szczodrzynski.edziennik.App"/>
</data>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -74,6 +78,12 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox" />
<com.google.android.material.checkbox.MaterialCheckBox
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:checked="@={app.config.archiverEnabled}"
android:text="Archiver enabled" />
</LinearLayout>
</ScrollView>
</layout>

View File

@ -130,6 +130,7 @@
<string name="error_341" translatable="false">ERROR_VULCAN_API_BAD_REQUEST</string>
<string name="error_342" translatable="false">ERROR_VULCAN_API_OTHER</string>
<string name="error_343" translatable="false">ERROR_VULCAN_ATTACHMENT_DOWNLOAD</string>
<string name="error_390" translatable="false">ERROR_VULCAN_API_DEPRECATED</string>
<string name="error_401" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN</string>
<string name="error_402" translatable="false">ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME</string>
@ -318,6 +319,7 @@
<string name="error_341_reason">VULCAN®: błąd żądania, zgłoś błąd</string>
<string name="error_342_reason">VULCAN®: inny błąd, wyślij zgłoszenie</string>
<string name="error_343_reason">VULCAN®: nie znaleziono adresu załącznika</string>
<string name="error_390_reason">W związku z wygaszeniem aplikacji Dzienniczek+ przez firmę Vulcan, należy zalogować się ponownie.\n\nAby móc dalej korzystać z aplikacji Szkolny.eu, otwórz Ustawienia i wybierz opcję Dodaj nowego ucznia.\nNastępnie zaloguj się do dziennika Vulcan zgodnie z instrukcją.\n\nPrzepraszamy za niedogodności.</string>
<string name="error_401_reason">Nieprawidłowe dane logowania</string>
<string name="error_402_reason">Nieprawidłowa nazwa szkoły</string>

View File

@ -5,8 +5,8 @@ buildscript {
kotlin_version = '1.4.30'
release = [
versionName: "4.5-beta.1",
versionCode: 4050001
versionName: "4.5.1-beta.1",
versionCode: 4050101
]
setup = [