)(.*?)""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_ATTENDANCE_COLUMN_SPAN by lazy {
+ """colspan="(\d+)"""".toRegex()
+ }
+ val MOBIDZIENNIK_ATTENDANCE_RANGE by lazy {
+ """([0-9:]+) - .+? (.+?) """.toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_ATTENDANCE_LESSON by lazy {
+ """(.+?) \s*\s*\((.+?),\s*(.+?)\)""".toRegex(DOT_MATCHES_ALL)
+ }
+
+ val MOBIDZIENNIK_HOMEWORK_ROW by lazy {
+ """class="rowRolling">(.+?\s*)""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_HOMEWORK_ITEM by lazy {
+ """ (.+?): \s*(.+?)\s*
""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_HOMEWORK_BODY by lazy {
+ """Treść:(.+?)""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_HOMEWORK_ID by lazy {
+ """zadanieFormularz\(([0-9]+),""".toRegex(DOT_MATCHES_ALL)
+ }
+ val MOBIDZIENNIK_HOMEWORK_ATTACHMENT by lazy {
+ """zalacznik(_zadania)?=([0-9]+)'.+?word-break">(.+?)""".toRegex(DOT_MATCHES_ALL)
+ }
+
+
+
+ val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
+ """ """.toRegex(DOT_MATCHES_ALL)
+ }
+ val IDZIENNIK_LOGIN_ERROR by lazy {
+ """id="spanErrorMessage">(.*?)""".toRegex(DOT_MATCHES_ALL)
+ }
+ val IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME by lazy {
+ """Imię i nazwisko:.+?">(.+?)""".toRegex(DOT_MATCHES_ALL)
+ }
+ val IDZIENNIK_LOGIN_FIRST_IS_PARENT by lazy {
+ """id="ctl00_CzyRodzic" value="([01])" />""".toRegex()
+ }
+ val IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR by lazy {
+ """name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9]+)/([0-9]+)<""".toRegex(DOT_MATCHES_ALL)
+ }
+ val IDZIENNIK_LOGIN_FIRST_STUDENT_SELECT by lazy {
+ """""".toRegex(DOT_MATCHES_ALL)
+ }
+ val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
+ """(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)""".toRegex(DOT_MATCHES_ALL)
+ }
+ val IDZIENNIK_MESSAGES_RECIPIENT_PARENT by lazy {
+ """(.+?)\s\((.+)\)""".toRegex()
+ }
+ /*Szczęśliwy los na dzisiaj to 19 . Los na jutro to 22 */
+ val IDZIENNIK_WEB_LUCKY_NUMBER by lazy {
+ """dzisiaj to ([0-9]+) """.toRegex()
+ }
+ val IDZIENNIK_WEB_SELECTED_REGISTER by lazy {
+ """selected="selected" value="([0-9]+)" data-id-ucznia""".toRegex()
+ }
+
+
+
+ val VULCAN_SHIFT_ANNOTATION by lazy {
+ """\(przeniesiona (z|na) lekcj[ię] ([0-9]+), (.+)\)""".toRegex()
+ }
+ val VULCAN_WEB_PERMISSIONS by lazy {
+ """permissions: '([A-z0-9/=+\-_]+?)'""".toRegex()
+ }
+ val VULCAN_WEB_SYMBOL_VALIDATE by lazy {
+ """[A-z0-9]+""".toRegex(IGNORE_CASE)
+ }
+
+
+
+ val LIBRUS_ATTACHMENT_KEY by lazy {
+ """singleUseKey=([0-9A-z_]+)""".toRegex()
+ }
+ val LIBRUS_MESSAGE_ID by lazy {
+ """/wiadomosci/[0-9]+/[0-9]+/([0-9]+?)/""".toRegex()
+ }
+
+
+
+ val EDUDZIENNIK_STUDENTS_START by lazy {
+ """(.*?) """.toRegex()
+ }
+ val EDUDZIENNIK_ACCOUNT_NAME_START by lazy {
+ """(.*?) """.toRegex()
+ }
+ val EDUDZIENNIK_SUBJECTS_START by lazy {
+ """""".toRegex()
+ }
+
+ val EDUDZIENNIK_ATTENDANCE_ENTRIES by lazy {
+ """(.+?) """.toRegex()
+ }
+ val EDUDZIENNIK_ATTENDANCE_TYPES by lazy {
+ """.*?
(.*?)
""".toRegex(DOT_MATCHES_ALL)
+ }
+ val EDUDZIENNIK_ATTENDANCE_TYPE by lazy {
+ """\((.+?)\) (.+)""".toRegex()
+ }
+
+ val EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION by lazy {
+ """
.*?
(.*?)
""".toRegex(DOT_MATCHES_ALL)
+ }
+ val EDUDZIENNIK_HOMEWORK_DESCRIPTION by lazy {
+ """
(.*?)
""".toRegex(DOT_MATCHES_ALL)
+ }
+
+ val EDUDZIENNIK_SUBJECT_ID by lazy {
+ """/Courses/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_GRADE_ID by lazy {
+ """/Grades/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_EXAM_ID by lazy {
+ """/Evaluations/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_EVENT_TYPE_ID by lazy {
+ """/GradeLabels/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_ANNOUNCEMENT_ID by lazy {
+ """/Announcement/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_HOMEWORK_ID by lazy {
+ """/Homework/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_TEACHER_ID by lazy {
+ """/Teachers/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_EVENT_ID by lazy {
+ """/KlassEvent/([\w-_]+?)/""".toRegex()
+ }
+ val EDUDZIENNIK_NOTE_ID by lazy {
+ """/RegistryNotes/([\w-_]+?)/""".toRegex()
+ }
+
+ val EDUDZIENNIK_SCHOOL_DETAIL_ID by lazy {
+ """
.*?(.*?)
.*?""".toRegex(DOT_MATCHES_ALL)
+ }
+ val EDUDZIENNIK_CLASS_DETAIL_ID by lazy {
+ """(.*?) """.toRegex(DOT_MATCHES_ALL)
+ }
+
+ val EDUDZIENNIK_TEACHERS by lazy {
+ """.*?
(.+?) (.+?)
""".toRegex(DOT_MATCHES_ALL)
+ }
+
+
+
+
+ val LINKIFY_DATE_YMD by lazy {
+ """(1\d{3}|20\d{2})[\-./](1[0-2]|0?\d)[\-./]([1-2]\d|3[0-1]|0?\d)""".toRegex()
+ }
+ val LINKIFY_DATE_DMY by lazy {
+ """(?>? = null, onlyEndpoints: List
? = null, arguments: JsonObject? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds, onlyEndpoints, arguments))
+ fun syncProfileList(profileList: List) = EdziennikTask(-1, SyncProfileListRequest(profileList))
+ fun messageGet(profileId: Int, message: MessageFull) = EdziennikTask(profileId, MessageGetRequest(message))
+ fun messageSend(profileId: Int, recipients: List, subject: String, text: String) = EdziennikTask(profileId, MessageSendRequest(recipients, subject, text))
+ fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
+ fun announcementGet(profileId: Int, announcement: AnnouncementFull) = EdziennikTask(profileId, AnnouncementGetRequest(announcement))
+ fun attachmentGet(profileId: Int, owner: Any, attachmentId: Long, attachmentName: String) = EdziennikTask(profileId, AttachmentGetRequest(owner, attachmentId, attachmentName))
+ fun recipientListGet(profileId: Int) = EdziennikTask(profileId, RecipientListGetRequest())
+ fun eventGet(profileId: Int, event: EventFull) = EdziennikTask(profileId, EventGetRequest(event))
+ }
+
+ private lateinit var loginStore: LoginStore
+
+ override fun prepare(app: App) {
+ if (request is FirstLoginRequest) {
+ // get the requested profile and login store
+ this.profile = null
+ loginStore = request.loginStore
+ // save the profile ID and name as the current task's
+ taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
+ } else {
+ // get the requested profile and login store
+ val profile = app.db.profileDao().getByIdNow(profileId) ?: return
+ this.profile = profile
+ val loginStore = app.db.loginStoreDao().getByIdNow(profile.loginStoreId) ?: return
+ this.loginStore = loginStore
+ // save the profile ID and name as the current task's
+ 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
+
+ internal fun run(app: App, taskCallback: EdziennikCallback) {
+ profile?.let { profile ->
+ if (profile.archived) {
+ d(TAG, "The profile $profileId is archived")
+ taskCallback.onError(ApiError(TAG, ERROR_PROFILE_ARCHIVED))
+ return
+ }
+ else if (profile.shouldArchive()) {
+ d(TAG, "The profile $profileId's year ended on ${profile.dateYearEnd}, archiving")
+ ProfileArchiver(app, profile)
+ }
+ if (profile.isBeforeYear()) {
+ d(TAG, "The profile $profileId's school year has not started yet; aborting sync")
+ cancel()
+ taskCallback.onCompleted()
+ return
+ }
+
+ profile.registerName?.let { registerName ->
+ var status = app.config.sync.registerAvailability[registerName]
+ if (status == null || status.nextCheck < currentTimeUnix()) {
+ val api = SzkolnyApi(app)
+ api.runCatching({
+ val availability = getRegisterAvailability()
+ app.config.sync.registerAvailability = availability
+ status = availability[registerName]
+ }, onError = {
+ taskCallback.onError(it.toApiError(TAG))
+ return
+ })
+ }
+
+ if (status?.available != true
+ || status?.minVersionCode ?: BuildConfig.VERSION_CODE > BuildConfig.VERSION_CODE) {
+ if (EventBus.getDefault().hasSubscriberForEvent(RegisterAvailabilityEvent::class.java)) {
+ EventBus.getDefault().postSticky(
+ RegisterAvailabilityEvent(app.config.sync.registerAvailability)
+ )
+ }
+ cancel()
+ taskCallback.onCompleted()
+ return
+ }
+ }
+ }
+
+ edziennikInterface = when (loginStore.type) {
+ LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
+ LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
+ LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
+ LOGIN_TYPE_IDZIENNIK -> Idziennik(app, profile, loginStore, taskCallback)
+ LOGIN_TYPE_EDUDZIENNIK -> Edudziennik(app, profile, loginStore, taskCallback)
+ LOGIN_TYPE_PODLASIE -> Podlasie(app, profile, loginStore, taskCallback)
+ LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback)
+ else -> null
+ }
+ if (edziennikInterface == null) {
+ return
+ }
+
+ when (request) {
+ is SyncProfileRequest -> edziennikInterface?.sync(
+ featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) }
+ ?: Features.getAllIds(),
+ viewId = request.viewIds?.get(0)?.first,
+ onlyEndpoints = request.onlyEndpoints,
+ arguments = request.arguments)
+ is MessageGetRequest -> edziennikInterface?.getMessage(request.message)
+ is MessageSendRequest -> edziennikInterface?.sendMessage(request.recipients, request.subject, request.text)
+ is FirstLoginRequest -> edziennikInterface?.firstLogin()
+ is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
+ is AnnouncementGetRequest -> edziennikInterface?.getAnnouncement(request.announcement)
+ is AttachmentGetRequest -> edziennikInterface?.getAttachment(request.owner, request.attachmentId, request.attachmentName)
+ is RecipientListGetRequest -> edziennikInterface?.getRecipientList()
+ is EventGetRequest -> edziennikInterface?.getEvent(request.event)
+ }
+ }
+
+ override fun cancel() {
+ d(TAG, "Task ${toString()} cancelling...")
+ edziennikInterface?.cancel()
+ }
+
+ override fun toString(): String {
+ return "EdziennikTask(profileId=$profileId, request=$request, edziennikInterface=$edziennikInterface)"
+ }
+
+ data class FirstLoginRequest(val loginStore: LoginStore)
+ class SyncRequest
+ data class SyncProfileRequest(val viewIds: List>? = null, val onlyEndpoints: List? = null, val arguments: JsonObject? = null)
+ data class SyncProfileListRequest(val profileList: List)
+ data class MessageGetRequest(val message: MessageFull)
+ data class MessageSendRequest(val recipients: List, val subject: String, val text: String)
+ class AnnouncementsReadRequest
+ data class AnnouncementGetRequest(val announcement: AnnouncementFull)
+ data class AttachmentGetRequest(val owner: Any, val attachmentId: Long, val attachmentName: String)
+ class RecipientListGetRequest
+ data class EventGetRequest(val event: EventFull)
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt
new file mode 100644
index 00000000..15da9765
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/ProfileArchiver.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-8-25.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik
+
+import android.content.Intent
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.Intent
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.utils.Utils.d
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class ProfileArchiver(val app: App, val profile: Profile) {
+ companion object {
+ private const val TAG = "ProfileArchiver"
+ }
+
+ init {
+ if (profile.archiveId == null)
+ profile.archiveId = profile.id
+ d(TAG, "Processing ${profile.name}#${profile.id}, archiveId = ${profile.archiveId}")
+
+ profile.archived = true
+ app.db.profileDao().add(profile)
+ //app.db.metadataDao().setAllSeen(profile.id, true)
+ app.db.notificationDao().clear(profile.id)
+ app.db.endpointTimerDao().clear(profile.id)
+ d(TAG, "Archived profile ${profile.id} saved")
+ profile.archived = false
+
+ // guess the nearest school year
+ val today = Date.getToday()
+ profile.studentSchoolYearStart = when {
+ today.month <= profile.dateYearEnd.month -> today.year - 1
+ else -> today.year
+ }
+
+ // set default semester dates
+ profile.dateSemester1Start = Date(profile.studentSchoolYearStart, 9, 1)
+ profile.dateSemester2Start = Date(profile.studentSchoolYearStart + 1, 2, 1)
+ profile.dateYearEnd = Date(profile.studentSchoolYearStart + 1, 6, 30)
+
+ val oldId = profile.id
+ val newId = (app.db.profileDao().lastId ?: profile.id) + 1
+ profile.id = newId
+ profile.subname = "Nowy rok szkolny - ${profile.studentSchoolYearStart}"
+ profile.studentClassName = null
+
+ d(TAG, "New profile ID for ${profile.name}: ${profile.id}")
+
+ when (profile.loginStoreType) {
+ LOGIN_TYPE_LIBRUS -> {
+ profile.removeStudentData("isPremium")
+ profile.removeStudentData("pushDeviceId")
+ profile.removeStudentData("startPointsSemester1")
+ profile.removeStudentData("startPointsSemester2")
+ profile.removeStudentData("enablePointGrades")
+ profile.removeStudentData("enableDescriptiveGrades")
+ }
+ LOGIN_TYPE_MOBIDZIENNIK -> {
+
+ }
+ LOGIN_TYPE_VULCAN -> {
+ // DataVulcan.isApiLoginValid() returns false so it will update the semester
+ profile.removeStudentData("currentSemesterEndDate")
+ profile.removeStudentData("studentSemesterId")
+ profile.removeStudentData("studentSemesterNumber")
+ profile.removeStudentData("semester1Id")
+ profile.removeStudentData("semester2Id")
+ profile.removeStudentData("studentClassId")
+ }
+ LOGIN_TYPE_IDZIENNIK -> {
+ profile.removeStudentData("schoolYearId")
+ }
+ LOGIN_TYPE_EDUDZIENNIK -> {
+
+ }
+ LOGIN_TYPE_PODLASIE -> {
+
+ }
+ }
+
+ d(TAG, "Processed student data: ${profile.studentData}")
+
+ app.db.profileDao().add(profile)
+
+ if (app.profileId == oldId) {
+ val intent = Intent(
+ Intent.ACTION_MAIN,
+ "profileId" to newId
+ )
+ app.sendBroadcast(intent)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt
new file mode 100644
index 00000000..40601249
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/DataEdudziennik.kt
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
+
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
+import pl.szczodrzynski.edziennik.data.api.models.Data
+import pl.szczodrzynski.edziennik.data.db.entity.*
+
+/**
+ * Use http://patorjk.com/software/taag/#p=display&f=Big for the ascii art
+ *
+ * Use https://codepen.io/kubasz/pen/RwwwbGN to easily generate the student data getters/setters
+ */
+class DataEdudziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
+
+ fun isWebLoginValid() = webSessionIdExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty()
+
+ override fun satisfyLoginMethods() {
+ loginMethods.clear()
+ if (isWebLoginValid()) {
+ loginMethods += LOGIN_METHOD_EDUDZIENNIK_WEB
+ }
+ }
+
+ override fun generateUserCode() = "$schoolName:$loginEmail:${studentId?.crc32()}"
+
+ private var mLoginEmail: String? = null
+ var loginEmail: String?
+ get() { mLoginEmail = mLoginEmail ?: loginStore.getLoginData("email", null); return mLoginEmail }
+ set(value) { loginStore.putLoginData("email", value); mLoginEmail = value }
+
+ private var mLoginPassword: String? = null
+ var loginPassword: String?
+ get() { mLoginPassword = mLoginPassword ?: loginStore.getLoginData("password", null); return mLoginPassword }
+ set(value) { loginStore.putLoginData("password", value); mLoginPassword = value }
+
+ private var mStudentId: String? = null
+ var studentId: String?
+ get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
+ set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
+
+ private var mSchoolId: String? = null
+ var schoolId: String?
+ get() { mSchoolId = mSchoolId ?: profile?.getStudentData("schoolId", null); return mSchoolId }
+ set(value) { profile?.putStudentData("schoolId", value) ?: return; mSchoolId = value }
+
+ private var mClassId: String? = null
+ var classId: String?
+ get() { mClassId = mClassId ?: profile?.getStudentData("classId", null); return mClassId }
+ set(value) { profile?.putStudentData("classId", value) ?: return; mClassId = value }
+
+ /* __ __ _
+ \ \ / / | |
+ \ \ /\ / /__| |__
+ \ \/ \/ / _ \ '_ \
+ \ /\ / __/ |_) |
+ \/ \/ \___|_._*/
+ private var mWebSessionId: String? = null
+ var webSessionId: String?
+ get() { mWebSessionId = mWebSessionId ?: loginStore.getLoginData("webSessionId", null); return mWebSessionId }
+ set(value) { loginStore.putLoginData("webSessionId", value); mWebSessionId = value }
+
+ private var mWebSessionIdExpiryTime: Long? = null
+ var webSessionIdExpiryTime: Long
+ get() { mWebSessionIdExpiryTime = mWebSessionIdExpiryTime ?: loginStore.getLoginData("webSessionIdExpiryTime", 0L); return mWebSessionIdExpiryTime ?: 0L }
+ set(value) { loginStore.putLoginData("webSessionIdExpiryTime", value); mWebSessionIdExpiryTime = value }
+
+ /* ____ _ _
+ / __ \| | | |
+ | | | | |_| |__ ___ _ __
+ | | | | __| '_ \ / _ \ '__|
+ | |__| | |_| | | | __/ |
+ \____/ \__|_| |_|\___|*/
+ private var mCurrentSemester: Int? = null
+ var currentSemester: Int
+ get() { mCurrentSemester = mCurrentSemester ?: profile?.getStudentData("currentSemester", 1); return mCurrentSemester ?: 1 }
+ set(value) { profile?.putStudentData("currentSemester", value) ?: return; mCurrentSemester = value }
+
+ private var mSchoolName: String? = null
+ var schoolName: String?
+ get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
+ set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
+
+ val studentEndpoint: String
+ get() = "Students/$studentId/"
+
+ val schoolEndpoint: String
+ get() = "Schools/$schoolId/"
+
+ val classStudentEndpoint: String
+ get() = "Class/$studentId/"
+
+ val schoolClassEndpoint: String
+ get() = "Schools/$classId/"
+
+ val studentAndClassEndpoint: String
+ get() = "Students/$studentId/Klass/$classId/"
+
+ val studentAndClassesEndpoint: String
+ get() = "Students/$studentId/Classes/$classId/"
+
+ val timetableEndpoint: String
+ get() = "Plan/$studentId/"
+
+ val studentAndTeacherClassEndpoint: String
+ get() = "Students/$studentId/Teachers/$classId/"
+
+ val courseStudentEndpoint: String
+ get() = "Course/$studentId/"
+
+ fun getSubject(longId: String, name: String): Subject {
+ val id = longId.crc32()
+ return subjectList.singleOrNull { it.id == id } ?: run {
+ val subject = Subject(profileId, id, name, name)
+ subjectList.put(id, subject)
+ subject
+ }
+ }
+
+ fun getTeacher(firstName: String, lastName: String, longId: String? = null): Teacher {
+ val name = "$firstName $lastName".fixName()
+ val id = name.crc32()
+ return teacherList.singleOrNull { it.id == id }?.also {
+ if (longId != null && it.loginId == null) it.loginId = longId
+ } ?: run {
+ val teacher = Teacher(profileId, id, firstName, lastName, longId)
+ teacherList.put(id, teacher)
+ teacher
+ }
+ }
+
+ fun getTeacherByFirstLast(nameFirstLast: String, longId: String? = null): Teacher {
+ val nameParts = nameFirstLast.split(" ")
+ return getTeacher(nameParts[0], nameParts[1], longId)
+ }
+
+ fun getTeacherByLastFirst(nameLastFirst: String, longId: String? = null): Teacher {
+ val nameParts = nameLastFirst.split(" ")
+ return getTeacher(nameParts[1], nameParts[0], longId)
+ }
+
+ fun getEventType(longId: String, name: String): EventType {
+ val id = longId.crc16().toLong()
+ return eventTypes.singleOrNull { it.id == id } ?: run {
+ val eventType = EventType(profileId, id, name, colorFromName(name))
+ eventTypes.put(id, eventType)
+ eventType
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/Edudziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/Edudziennik.kt
new file mode 100644
index 00000000..23d9d3b1
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/Edudziennik.kt
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikData
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetAnnouncement
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.EdudziennikWebGetHomework
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin.EdudziennikFirstLogin
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLogin
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
+import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
+import pl.szczodrzynski.edziennik.data.db.full.EventFull
+import pl.szczodrzynski.edziennik.data.db.full.MessageFull
+import pl.szczodrzynski.edziennik.utils.Utils.d
+
+class Edudziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
+ companion object {
+ private const val TAG = "Edudziennik"
+ }
+
+ val internalErrorList = mutableListOf()
+ val data: DataEdudziennik
+ private var afterLogin: (() -> Unit)? = null
+
+ init {
+ data = DataEdudziennik(app, profile, loginStore).apply {
+ callback = wrapCallback(this@Edudziennik.callback)
+ satisfyLoginMethods()
+ }
+ }
+
+ private fun completed() {
+ data.saveData()
+ callback.onCompleted()
+ }
+
+ /* _______ _ _ _ _ _
+ |__ __| | /\ | | (_) | | |
+ | | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
+ | | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
+ | | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
+ |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
+ __/ |
+ |__*/
+ override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) {
+ data.arguments = arguments
+ data.prepare(edudziennikLoginMethods, EdudziennikFeatures, featureIds, viewId, onlyEndpoints)
+ login()
+ }
+
+ private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
+ d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
+ if (internalErrorList.isNotEmpty()) {
+ d(TAG, " - Internal errors:")
+ internalErrorList.forEach { d(TAG, " - code $it") }
+ }
+ loginMethodId?.let { data.prepareFor(edudziennikLoginMethods, it) }
+ afterLogin?.let { this.afterLogin = it }
+ EdudziennikLogin(data) {
+ data()
+ }
+ }
+
+ private fun data() {
+ d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
+ if (internalErrorList.isNotEmpty()) {
+ d(TAG, " - Internal errors:")
+ internalErrorList.forEach { d(TAG, " - code $it") }
+ }
+ afterLogin?.invoke() ?: EdudziennikData(data) {
+ completed()
+ }
+ }
+
+ override fun getMessage(message: MessageFull) {}
+ override fun sendMessage(recipients: List, subject: String, text: String) {}
+ override fun markAllAnnouncementsAsRead() {}
+
+ override fun getAnnouncement(announcement: AnnouncementFull) {
+ EdudziennikLoginWeb(data) {
+ EdudziennikWebGetAnnouncement(data, announcement) {
+ completed()
+ }
+ }
+ }
+
+ override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {}
+ override fun getRecipientList() {}
+
+ override fun getEvent(eventFull: EventFull) {
+ EdudziennikLoginWeb(data) {
+ EdudziennikWebGetHomework(data, eventFull) {
+ completed()
+ }
+ }
+ }
+
+ override fun firstLogin() { EdudziennikFirstLogin(data) { completed() } }
+ override fun cancel() {
+ d(TAG, "Cancelled")
+ data.cancel()
+ }
+
+ private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
+ return object : EdziennikCallback {
+ override fun onCompleted() { callback.onCompleted() }
+ override fun onProgress(step: Float) { callback.onProgress(step) }
+ override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
+ override fun onError(apiError: ApiError) {
+ if (apiError.errorCode in internalErrorList) {
+ // finish immediately if the same error occurs twice during the same sync
+ callback.onError(apiError)
+ return
+ }
+ internalErrorList.add(apiError.errorCode)
+ when (apiError.errorCode) {
+ ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED -> {
+ login()
+ }
+ ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID -> {
+ login()
+ }
+ ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS -> {
+ data()
+ }
+ else -> callback.onError(apiError)
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/EdudziennikFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/EdudziennikFeatures.kt
new file mode 100644
index 00000000..c3fd17ed
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/EdudziennikFeatures.kt
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-23
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik
+
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.models.Feature
+
+const val ENDPOINT_EDUDZIENNIK_WEB_START = 1000
+const val ENDPOINT_EDUDZIENNIK_WEB_TEACHERS = 1001
+const val ENDPOINT_EDUDZIENNIK_WEB_GRADES = 1011
+const val ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE = 1012
+const val ENDPOINT_EDUDZIENNIK_WEB_EXAMS = 1013
+const val ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE = 1014
+const val ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS = 1015
+const val ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK = 1016
+const val ENDPOINT_EDUDZIENNIK_WEB_EVENTS = 1017
+const val ENDPOINT_EDUDZIENNIK_WEB_NOTES = 1018
+const val ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER = 1030
+
+val EdudziennikFeatures = listOf(
+ /* School and team info and subjects */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_STUDENT_INFO, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_START to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Teachers */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TEACHERS, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_TEACHERS to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Timetable */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_TIMETABLE, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Grades */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_GRADES, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_GRADES to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Agenda */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_AGENDA, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_EXAMS to LOGIN_METHOD_EDUDZIENNIK_WEB,
+ ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB,
+ ENDPOINT_EDUDZIENNIK_WEB_EVENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Homework */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_HOMEWORK, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Behaviour */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_BEHAVIOUR, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_NOTES to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Attendance */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ATTENDANCE, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Announcements */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB)),
+
+ /* Lucky number */
+ Feature(LOGIN_TYPE_EDUDZIENNIK, FEATURE_LUCKY_NUMBER, listOf(
+ ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER to LOGIN_METHOD_EDUDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_EDUDZIENNIK_WEB))
+)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/EdudziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/EdudziennikData.kt
new file mode 100644
index 00000000..7eb58d1c
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/EdudziennikData.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
+
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web.*
+import pl.szczodrzynski.edziennik.utils.Utils
+
+class EdudziennikData(val data: DataEdudziennik, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "EdudziennikData"
+ }
+
+ init {
+ nextEndpoint(onSuccess)
+ }
+
+ private fun nextEndpoint(onSuccess: () -> Unit) {
+ if (data.targetEndpointIds.isEmpty()) {
+ onSuccess()
+ return
+ }
+ if (data.cancelled) {
+ onSuccess()
+ return
+ }
+ val id = data.targetEndpointIds.firstKey()
+ val lastSync = data.targetEndpointIds.remove(id)
+ useEndpoint(id, lastSync) { endpointId ->
+ data.progress(data.progressStep)
+ nextEndpoint(onSuccess)
+ }
+ }
+
+ private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
+ Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
+ when (endpointId) {
+ ENDPOINT_EDUDZIENNIK_WEB_START -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_data)
+ EdudziennikWebStart(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_TEACHERS -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_teachers)
+ EdudziennikWebTeachers(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_GRADES -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_grades)
+ EdudziennikWebGrades(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_timetable)
+ EdudziennikWebTimetable(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_EXAMS -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_exams)
+ EdudziennikWebExams(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_attendance)
+ EdudziennikWebAttendance(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_announcements)
+ EdudziennikWebAnnouncements(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_homework)
+ EdudziennikWebHomework(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_EVENTS -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_events)
+ EdudziennikWebEvents(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_NOTES -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_notices)
+ EdudziennikWebNotes(data, lastSync, onSuccess)
+ }
+ ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
+ EdudziennikWebLuckyNumber(data, lastSync, onSuccess)
+ }
+ else -> onSuccess(endpointId)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/EdudziennikWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/EdudziennikWeb.kt
new file mode 100644
index 00000000..f5adfc5d
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/EdudziennikWeb.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data
+
+import im.wangchao.mhttp.Request
+import im.wangchao.mhttp.Response
+import im.wangchao.mhttp.callback.TextCallbackHandler
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.utils.Utils.d
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+open class EdudziennikWeb(open val data: DataEdudziennik, open val lastSync: Long?) {
+ companion object {
+ private const val TAG = "EdudziennikWeb"
+ }
+
+ val profileId
+ get() = data.profile?.id ?: -1
+
+ val profile
+ get() = data.profile
+
+ fun webGet(tag: String, endpoint: String, xhr: Boolean = false, semester: Int? = null, onSuccess: (text: String) -> Unit) {
+ val url = "https://dziennikel.appspot.com/" + when (endpoint.endsWith('/') || endpoint.contains('?') || endpoint.isEmpty()) {
+ true -> endpoint
+ else -> "$endpoint/"
+ } + (semester?.let { "?semester=" + if(it == -1) "all" else it } ?: "")
+
+ d(tag, "Request: Edudziennik/Web - $url")
+
+ val callback = object : TextCallbackHandler() {
+ override fun onSuccess(text: String?, response: Response?) {
+ if (text == null || response == null) {
+ data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
+ .withResponse(response))
+ return
+ }
+
+ if (semester == null && url.contains("start")) {
+ profile?.also { profile ->
+ val cookies = data.app.cookieJar.getAll("dziennikel.appspot.com")
+ val semesterCookie = cookies["semester"]?.toIntOrNull()
+
+ semesterCookie?.let { data.currentSemester = it }
+
+ if (semesterCookie == 2 && profile.dateSemester2Start > Date.getToday())
+ profile.dateSemester2Start = Date.getToday().stepForward(0, 0, -1)
+ }
+ }
+
+ try {
+ onSuccess(text)
+ } catch (e: Exception) {
+ data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_WEB_REQUEST)
+ .withThrowable(e)
+ .withResponse(response)
+ .withApiResponse(text))
+ }
+ }
+
+ override fun onFailure(response: Response?, throwable: Throwable?) {
+ val error = when (response?.code()) {
+ 402 -> ERROR_EDUDZIENNIK_WEB_LIMITED_ACCESS
+ 403 -> ERROR_EDUDZIENNIK_WEB_SESSION_EXPIRED
+ else -> ERROR_REQUEST_FAILURE
+ }
+ data.error(ApiError(tag, error)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ }
+
+ data.app.cookieJar.set("dziennikel.appspot.com", "sessionid", data.webSessionId)
+
+ Request.builder()
+ .url(url)
+ .userAgent(EDUDZIENNIK_USER_AGENT)
+ .apply {
+ if (xhr) header("X-Requested-With", "XMLHttpRequest")
+ }
+ .get()
+ .callback(callback)
+ .build()
+ .enqueue()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebAnnouncements.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebAnnouncements.kt
new file mode 100644
index 00000000..32ca353c
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebAnnouncements.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-26
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ANNOUNCEMENT_ID
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.db.entity.Announcement
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebAnnouncements(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ const val TAG = "EdudziennikWebAnnouncements"
+ }
+
+ init { data.profile?.also { profile ->
+ webGet(TAG, data.schoolClassEndpoint + "Announcements") { text ->
+ val doc = Jsoup.parse(text)
+
+ if (doc.getElementsByClass("message").text().trim() != "Brak ogłoszeń.") {
+ doc.select("table.list tbody tr").forEach { announcementElement ->
+ val titleElement = announcementElement.child(0).child(0)
+
+ val longId = EDUDZIENNIK_ANNOUNCEMENT_ID.find(titleElement.attr("href"))?.get(1)
+ ?: return@forEach
+ val id = longId.crc32()
+ val subject = titleElement.text()
+
+ val teacherName = announcementElement.child(1).text()
+ val teacher = data.getTeacherByFirstLast(teacherName)
+
+ val dateString = announcementElement.getElementsByClass("datetime").first().text()
+ val startDate = Date.fromY_m_d(dateString)
+ val addedDate = Date.fromIsoHm(dateString)
+
+ val announcementObject = Announcement(
+ profileId = profileId,
+ id = id,
+ subject = subject,
+ text = null,
+ startDate = startDate,
+ endDate = null,
+ teacherId = teacher.id,
+ addedDate = addedDate
+ ).also {
+ it.idString = longId
+ }
+
+ data.announcementList.add(announcementObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_ANNOUNCEMENT,
+ id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+ }
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS)
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ANNOUNCEMENTS) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebAttendance.kt
new file mode 100644
index 00000000..7fe18171
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebAttendance.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-24
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_ENTRIES
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPE
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ATTENDANCE_TYPES
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.singleOrNull
+import pl.szczodrzynski.edziennik.utils.models.Date
+import java.util.*
+
+class EdudziennikWebAttendance(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "EdudziennikWebAttendance"
+ }
+
+ private var requestSemester: Int? = null
+
+ init {
+ if (profile?.empty == true && data.currentSemester == 2) requestSemester = 1
+ getAttendances()
+ }
+
+ private fun getAttendances() { data.profile?.also { profile ->
+ webGet(TAG, data.studentEndpoint + "Presence", semester = requestSemester) { text ->
+
+ val attendanceTypes = EDUDZIENNIK_ATTENDANCE_TYPES.find(text)?.get(1)?.split(',')?.map {
+ val type = EDUDZIENNIK_ATTENDANCE_TYPE.find(it.trim())
+ val symbol = type?.get(1)?.trim() ?: "?"
+ val name = type?.get(2)?.trim() ?: "nieznany rodzaj"
+ return@map Triple(
+ symbol,
+ name,
+ when (name.toLowerCase(Locale.ROOT)) {
+ "obecność" -> Attendance.TYPE_PRESENT
+ "nieobecność" -> Attendance.TYPE_ABSENT
+ "spóźnienie" -> Attendance.TYPE_BELATED
+ "nieobecność usprawiedliwiona" -> Attendance.TYPE_ABSENT_EXCUSED
+ "dzień wolny" -> Attendance.TYPE_DAY_FREE
+ "brak zajęć" -> Attendance.TYPE_DAY_FREE
+ "oddelegowany" -> Attendance.TYPE_RELEASED
+ else -> Attendance.TYPE_UNKNOWN
+ }
+ )
+ } ?: emptyList()
+
+ EDUDZIENNIK_ATTENDANCE_ENTRIES.findAll(text).forEach { attendanceElement ->
+ val date = Date.fromY_m_d(attendanceElement[1])
+ val lessonNumber = attendanceElement[2].toInt()
+ val attendanceSymbol = attendanceElement[3]
+
+ val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
+ val lesson = lessons.firstOrNull { it.lessonNumber == lessonNumber }
+
+ val id = "${date.stringY_m_d}:$lessonNumber:$attendanceSymbol".crc32()
+
+ val (typeSymbol, typeName, baseType) = attendanceTypes.firstOrNull { (symbol, _, _) -> symbol == attendanceSymbol }
+ ?: return@forEach
+
+ val startTime = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNumber }?.startTime
+ ?: return@forEach
+
+ val attendanceObject = Attendance(
+ profileId = profileId,
+ id = id,
+ baseType = baseType,
+ typeName = typeName,
+ typeShort = data.app.attendanceManager.getTypeShort(baseType),
+ typeSymbol = typeSymbol,
+ typeColor = null,
+ date = date,
+ startTime = lesson?.displayStartTime ?: startTime,
+ semester = profile.currentSemester,
+ teacherId = lesson?.displayTeacherId ?: -1,
+ subjectId = lesson?.displaySubjectId ?: -1
+ ).also {
+ it.lessonNumber = lessonNumber
+ }
+
+ data.attendanceList.add(attendanceObject)
+ if (baseType != Attendance.TYPE_PRESENT) {
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_ATTENDANCE,
+ id,
+ profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN,
+ profile.empty || baseType == Attendance.TYPE_PRESENT_CUSTOM || baseType == Attendance.TYPE_UNKNOWN
+ ))
+ }
+ }
+
+ if (profile.empty && requestSemester == 1 && data.currentSemester == 2) {
+ requestSemester = null
+ getAttendances()
+ } else {
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE)
+ }
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_ATTENDANCE) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebEvents.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebEvents.kt
new file mode 100644
index 00000000..35c68478
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebEvents.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2020-1-1
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_ID
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EVENTS
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Event
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebEvents(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ const val TAG = "EdudziennikWebEvents"
+ }
+
+ init { data.profile?.also { profile ->
+ webGet(TAG, data.studentAndClassesEndpoint + "KlassEvent", xhr = true) { text ->
+ val doc = Jsoup.parseBodyFragment("")
+
+ doc.getElementsByTag("tr").forEach { eventElement ->
+ val date = Date.fromY_m_d(eventElement.child(1).text())
+
+ val titleElement = eventElement.child(2).child(0)
+ val title = titleElement.text().trim()
+
+ val id = EDUDZIENNIK_EVENT_ID.find(titleElement.attr("href"))?.get(1)?.crc32()
+ ?: return@forEach
+
+ val eventObject = Event(
+ profileId = profileId,
+ id = id,
+ date = date,
+ time = null,
+ topic = title,
+ color = null,
+ type = Event.TYPE_CLASS_EVENT,
+ teacherId = -1,
+ subjectId = -1,
+ teamId = data.teamClass?.id ?: -1
+ )
+
+ data.eventList.add(eventObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_EVENT,
+ id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+
+ data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_CLASS_EVENT))
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EVENTS, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS)
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EVENTS) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt
new file mode 100644
index 00000000..f6abf637
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebExams.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-24
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EVENT_TYPE_ID
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_EXAM_ID
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_EXAMS
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Event
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebExams(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ const val TAG = "EdudziennikWebExams"
+ }
+
+ init { profile?.also { profile ->
+ webGet(TAG, data.studentAndClassEndpoint + "Evaluations", xhr = true) { text ->
+ val doc = Jsoup.parseBodyFragment("")
+
+ doc.select("tr").forEach { examElement ->
+ val id = EDUDZIENNIK_EXAM_ID.find(examElement.child(0).child(0).attr("href"))
+ ?.get(1)?.crc32() ?: return@forEach
+ val topic = examElement.child(0).text().trim()
+
+ val subjectElement = examElement.child(1).child(0)
+ val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
+ ?: return@forEach
+ val subjectName = subjectElement.text().trim()
+ val subject = data.getSubject(subjectId, subjectName)
+
+ val dateString = examElement.child(2).text().trim()
+ if (dateString.isBlank()) return@forEach
+ val date = Date.fromY_m_d(dateString)
+
+ val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
+ val startTime = lessons.firstOrNull { it.displaySubjectId == subject.id }?.displayStartTime
+
+ val eventTypeElement = examElement.child(3).child(0)
+ val eventTypeId = EDUDZIENNIK_EVENT_TYPE_ID.find(eventTypeElement.attr("href"))?.get(1)
+ ?: return@forEach
+ val eventTypeName = eventTypeElement.text()
+ val eventType = data.getEventType(eventTypeId, eventTypeName)
+
+ val eventObject = Event(
+ profileId = profileId,
+ id = id,
+ date = date,
+ time = startTime,
+ topic = topic,
+ color = null,
+ type = eventType.id,
+ teacherId = -1,
+ subjectId = subject.id,
+ teamId = data.teamClass?.id ?: -1
+ )
+
+ data.eventList.add(eventObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_EVENT,
+ id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+
+ data.toRemove.add(DataRemoveModel.Events.futureExceptTypes(listOf(
+ Event.TYPE_HOMEWORK,
+ Event.TYPE_CLASS_EVENT
+ )))
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_EXAMS)
+ }
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGetAnnouncement.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGetAnnouncement.kt
new file mode 100644
index 00000000..5d915e64
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGetAnnouncement.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-26
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.AnnouncementGetEvent
+import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
+import pl.szczodrzynski.edziennik.get
+
+class EdudziennikWebGetAnnouncement(override val data: DataEdudziennik,
+ private val announcement: AnnouncementFull,
+ val onSuccess: () -> Unit
+) : EdudziennikWeb(data, null) {
+ companion object {
+ const val TAG = "EdudziennikWebGetAnnouncement"
+ }
+
+ init {
+ webGet(TAG, "Announcement/${announcement.idString}") { text ->
+ val description = Regexes.EDUDZIENNIK_ANNOUNCEMENT_DESCRIPTION.find(text)?.get(1)?.trim() ?: ""
+
+ announcement.text = description
+
+ EventBus.getDefault().postSticky(AnnouncementGetEvent(announcement))
+
+ data.announcementList.add(announcement)
+ onSuccess()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGetHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGetHomework.kt
new file mode 100644
index 00000000..84171699
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGetHomework.kt
@@ -0,0 +1,45 @@
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import android.text.Html
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
+import pl.szczodrzynski.edziennik.data.db.full.EventFull
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.isNotNullNorEmpty
+
+class EdudziennikWebGetHomework(
+ override val data: DataEdudziennik,
+ val event: EventFull,
+ val onSuccess: () -> Unit
+) : EdudziennikWeb(data, null) {
+ companion object {
+ const val TAG = "EdudziennikWebGetHomework"
+ }
+
+ init {
+ if (event.attachmentNames.isNotNullNorEmpty()) {
+ val id = event.attachmentNames!![0]
+
+ webGet(TAG, "Homework/$id") { text ->
+ val description = Regexes.EDUDZIENNIK_HOMEWORK_DESCRIPTION.find(text)?.get(1)?.trim()
+
+ if (description != null) event.topic = Html.fromHtml(description).toString()
+
+ event.homeworkBody = ""
+ event.attachmentNames = null
+
+ data.eventList += event
+ data.eventListReplace = true
+
+ EventBus.getDefault().postSticky(EventGetEvent(event))
+ onSuccess()
+ }
+ } else {
+ EventBus.getDefault().postSticky(EventGetEvent(event))
+ onSuccess()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt
new file mode 100644
index 00000000..459f13aa
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebGrades.kt
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-25
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import android.graphics.Color
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.colorFromCssName
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_GRADES
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Grade
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_POINT_SUM
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_FINAL
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_FINAL
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER2_PROPOSED
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.Utils
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebGrades(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "EdudziennikWebGrades"
+ }
+
+ private var requestSemester: Int? = null
+
+ init {
+ if (profile?.empty == true && data.currentSemester == 2) requestSemester = 1
+ getGrades()
+ }
+
+ private fun getGrades() { data.profile?.also { profile ->
+ webGet(TAG, data.studentEndpoint + "start", semester = requestSemester) { text ->
+ val semester = requestSemester ?: data.currentSemester
+
+ val doc = Jsoup.parse(text)
+ val subjects = doc.select("#student_grades tbody").firstOrNull()?.children()
+
+ subjects?.forEach { subjectElement ->
+ if (subjectElement.id().isBlank()) return@forEach
+
+ val subjectId = subjectElement.id().trim()
+ val subjectName = subjectElement.child(0).text().trim()
+ val subject = data.getSubject(subjectId, subjectName)
+
+ val gradeType = when {
+ subjectElement.select("#sum").text().isNotBlank() -> TYPE_POINT_SUM
+ else -> TYPE_NORMAL
+ }
+
+ val gradeCountToAverage = subjectElement.select("#avg").text().isNotBlank()
+
+ val grades = subjectElement.select(".grade[data-edited]")
+ val gradesInfo = subjectElement.select(".grade-tip")
+
+ val gradeValues = if (grades.isNotEmpty()) {
+ subjects.select(".avg-$subjectId .grade-tip > p").first()
+ .text().split('+').map {
+ val split = it.split('*')
+ val value = split[1].trim().toFloatOrNull()
+ val weight = value?.let { split[0].trim().toFloatOrNull() } ?: 0f
+
+ Pair(value ?: 0f, weight)
+ }
+ } else emptyList()
+
+ grades.forEachIndexed { index, gradeElement ->
+ val id = Regexes.EDUDZIENNIK_GRADE_ID.find(gradeElement.attr("href"))?.get(1)?.crc32()
+ ?: return@forEachIndexed
+ val (value, weight) = gradeValues[index]
+ val name = gradeElement.text().trim().let {
+ if (it.contains(',') || it.contains('.')) {
+ val replaced = it.replace(',', '.')
+ val float = replaced.toFloatOrNull()
+
+ if (float != null && float % 1 == 0f) float.toInt().toString()
+ else it
+ } else it
+ }
+
+ val info = gradesInfo[index]
+ val fullName = info.child(0).text().trim()
+ val columnName = info.child(4).text().trim()
+ val comment = info.ownText()
+
+ val description = columnName + if (comment.isNotBlank()) " - $comment" else null
+
+ val teacherName = info.child(1).text()
+ val teacher = data.getTeacherByLastFirst(teacherName)
+
+ val addedDate = info.child(2).text().split(' ').let {
+ val day = it[0].toInt()
+ val month = Utils.monthFromName(it[1])
+ val year = it[2].toInt()
+
+ Date(year, month, day).inMillis
+ }
+
+ val color = Regexes.STYLE_CSS_COLOR.find(gradeElement.attr("style"))?.get(1)?.let {
+ if (it.startsWith('#')) Color.parseColor(it)
+ else colorFromCssName(it)
+ } ?: -1
+
+ val gradeObject = Grade(
+ profileId = profileId,
+ id = id,
+ name = name,
+ type = gradeType,
+ value = value,
+ weight = if (gradeCountToAverage) weight else 0f,
+ color = color,
+ category = fullName,
+ description = description,
+ comment = null,
+ semester = semester,
+ teacherId = teacher.id,
+ subjectId = subject.id,
+ addedDate = addedDate
+ )
+
+ data.gradeList.add(gradeObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_GRADE,
+ id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+
+ val proposed = subjectElement.select(".proposal").firstOrNull()?.text()?.trim()
+
+ if (proposed != null && proposed.isNotBlank()) {
+ val proposedGradeObject = Grade(
+ profileId = profileId,
+ id = (-1 * subject.id) - 1,
+ name = proposed,
+ type = when (semester) {
+ 1 -> TYPE_SEMESTER1_PROPOSED
+ else -> TYPE_SEMESTER2_PROPOSED
+ },
+ value = proposed.toFloatOrNull() ?: 0f,
+ weight = 0f,
+ color = -1,
+ category = null,
+ description = null,
+ comment = null,
+ semester = semester,
+ teacherId = -1,
+ subjectId = subject.id
+ )
+
+ data.gradeList.add(proposedGradeObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_GRADE,
+ proposedGradeObject.id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+
+ val final = subjectElement.select(".final").firstOrNull()?.text()?.trim()
+
+ if (final != null && final.isNotBlank()) {
+ val finalGradeObject = Grade(
+ profileId = profileId,
+ id = (-1 * subject.id) - 2,
+ name = final,
+ type = when (semester) {
+ 1 -> TYPE_SEMESTER1_FINAL
+ else -> TYPE_SEMESTER2_FINAL
+ },
+ value = final.toFloatOrNull() ?: 0f,
+ weight = 0f,
+ color = -1,
+ category = null,
+ description = null,
+ comment = null,
+ semester = semester,
+ teacherId = -1,
+ subjectId = subject.id
+ )
+
+ data.gradeList.add(finalGradeObject)
+ data.metadataList.add(Metadata(
+ data.profileId,
+ Metadata.TYPE_GRADE,
+ finalGradeObject.id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+ }
+
+ if (!subjects.isNullOrEmpty()) {
+ data.toRemove.addAll(listOf(
+ TYPE_NORMAL,
+ TYPE_POINT_SUM,
+ TYPE_SEMESTER1_PROPOSED,
+ TYPE_SEMESTER2_PROPOSED,
+ TYPE_SEMESTER1_FINAL,
+ TYPE_SEMESTER2_FINAL
+ ).map {
+ DataRemoveModel.Grades.semesterWithType(semester, it)
+ })
+ }
+
+ if (profile.empty && requestSemester == 1 && data.currentSemester == 2) {
+ requestSemester = null
+ getGrades()
+ } else {
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_GRADES)
+ }
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_GRADES) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt
new file mode 100644
index 00000000..169a5127
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebHomework.kt
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-29
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_HOMEWORK_ID
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Event
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebHomework(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ const val TAG = "EdudziennikWebHomework"
+ }
+
+ init { data.profile?.also { profile ->
+ webGet(TAG, data.courseStudentEndpoint + "Homework", xhr = true) { text ->
+ val doc = Jsoup.parseBodyFragment("")
+
+ if (doc.getElementsByClass("message").text().trim() != "Brak prac domowych") {
+ doc.getElementsByTag("tr").forEach { homeworkElement ->
+ val dateElement = homeworkElement.getElementsByClass("date").first().child(0)
+ val idStr = EDUDZIENNIK_HOMEWORK_ID.find(dateElement.attr("href"))?.get(1) ?: return@forEach
+ val id = idStr.crc32()
+ val date = Date.fromY_m_d(dateElement.text())
+
+ val subjectElement = homeworkElement.child(1).child(0)
+ val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
+ ?: return@forEach
+ val subjectName = subjectElement.text()
+ val subject = data.getSubject(subjectId, subjectName)
+
+ val lessons = data.app.db.timetableDao().getAllForDateNow(profileId, date)
+ val startTime = lessons.firstOrNull { it.subjectId == subject.id }?.displayStartTime
+
+ val teacherName = homeworkElement.child(2).text()
+ val teacher = data.getTeacherByFirstLast(teacherName)
+
+ val topic = homeworkElement.child(4).text()?.trim()
+
+ val eventObject = Event(
+ profileId = profileId,
+ id = id,
+ date = date,
+ time = startTime,
+ topic = topic ?: "",
+ color = null,
+ type = Event.TYPE_HOMEWORK,
+ teacherId = teacher.id,
+ subjectId = subject.id,
+ teamId = data.teamClass?.id ?: -1
+ )
+
+ eventObject.attachmentNames = mutableListOf(idStr)
+
+ data.eventList.add(eventObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_HOMEWORK,
+ id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+ }
+
+ data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK)
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_HOMEWORK) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebLuckyNumber.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebLuckyNumber.kt
new file mode 100644
index 00000000..db8164c8
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebLuckyNumber.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-23
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebLuckyNumber(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "EdudziennikWebLuckyNumber"
+ }
+
+ init { data.profile?.also { profile ->
+ webGet(TAG, data.schoolEndpoint + "Lucky", xhr = true) { text ->
+ text.toIntOrNull()?.also { luckyNumber ->
+ val luckyNumberObject = LuckyNumber(
+ profileId = profileId,
+ date = Date.getToday(),
+ number = luckyNumber
+ )
+
+ data.luckyNumberList.add(luckyNumberObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_LUCKY_NUMBER,
+ luckyNumberObject.date.value.toLong(),
+ true,
+ profile.empty
+ ))
+ }
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER)
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_LUCKY_NUMBER) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebNotes.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebNotes.kt
new file mode 100644
index 00000000..35a78168
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebNotes.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2020-1-1
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_NOTE_ID
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_NOTES
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.Notice
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class EdudziennikWebNotes(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ const val TAG = "EdudziennikWebNotes"
+ }
+
+ init { data.profile?.also { profile ->
+ webGet(TAG, data.classStudentEndpoint + "RegistryNotesStudent", xhr = true) { text ->
+ val doc = Jsoup.parseBodyFragment("")
+
+ doc.getElementsByTag("tr").forEach { noteElement ->
+ val dateElement = noteElement.getElementsByClass("date").first().child(0)
+ val addedDate = Date.fromY_m_d(dateElement.text()).inMillis
+
+ val id = EDUDZIENNIK_NOTE_ID.find(dateElement.attr("href"))?.get(0)?.crc32()
+ ?: return@forEach
+
+ val teacherName = noteElement.child(1).text()
+ val teacher = data.getTeacherByFirstLast(teacherName)
+
+ val description = noteElement.child(3).text()
+
+ val noticeObject = Notice(
+ profileId = profileId,
+ id = id,
+ type = Notice.TYPE_NEUTRAL,
+ semester = profile.currentSemester,
+ text = description,
+ category = null,
+ points = null,
+ teacherId = teacher.id,
+ addedDate = addedDate
+ )
+
+ data.noticeList.add(noticeObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_NOTICE,
+ id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_NOTES, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES)
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_NOTES) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt
new file mode 100644
index 00000000..66cb7a59
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebStart.kt
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-23
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import pl.szczodrzynski.edziennik.MONTH
+import pl.szczodrzynski.edziennik.crc32
+import pl.szczodrzynski.edziennik.data.api.ERROR_EDUDZIENNIK_WEB_TEAM_MISSING
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECTS_START
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_START
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Team
+import pl.szczodrzynski.edziennik.firstLettersName
+import pl.szczodrzynski.edziennik.get
+
+class EdudziennikWebStart(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "EdudziennikWebStart"
+ }
+
+ init {
+ webGet(TAG, data.studentEndpoint + "start") { text ->
+ getSchoolAndTeam(text)
+ getSubjects(text)
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_START, MONTH)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_START)
+ }
+ }
+
+ private fun getSchoolAndTeam(text: String) {
+ val schoolId = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_ID.find(text)?.get(1)?.trim()
+ val schoolLongName = Regexes.EDUDZIENNIK_SCHOOL_DETAIL_NAME.find(text)?.get(1)?.trim()
+ data.schoolId = schoolId
+
+ val classId = Regexes.EDUDZIENNIK_CLASS_DETAIL_ID.find(text)?.get(1)?.trim()
+ val className = Regexes.EDUDZIENNIK_CLASS_DETAIL_NAME.find(text)?.get(1)?.trim()
+ data.classId = classId
+
+ if (classId == null || className == null || schoolId == null || schoolLongName == null) {
+ data.error(ApiError(TAG, ERROR_EDUDZIENNIK_WEB_TEAM_MISSING)
+ .withApiResponse(text))
+ return
+ }
+
+ val schoolName = schoolId.crc32().toString() + schoolLongName.firstLettersName + "_edu"
+ data.schoolName = schoolName
+
+ val teamId = classId.crc32()
+ val teamCode = "$schoolName:$className"
+
+ val teamObject = Team(
+ data.profileId,
+ teamId,
+ className,
+ Team.TYPE_CLASS,
+ teamCode,
+ -1
+ )
+
+ data.teamClass = teamObject
+ data.teamList.put(teamObject.id, teamObject)
+ }
+
+ private fun getSubjects(text: String) {
+ EDUDZIENNIK_SUBJECTS_START.findAll(text).forEach {
+ val id = it[1].trim()
+ val name = it[2].trim()
+ data.getSubject(id, name)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTeachers.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTeachers.kt
new file mode 100644
index 00000000..d2f3ba15
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTeachers.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-25
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import pl.szczodrzynski.edziennik.MONTH
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHERS
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TEACHERS
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.get
+
+class EdudziennikWebTeachers(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "EdudziennikWebTeachers"
+ }
+
+ init {
+ webGet(TAG, data.studentAndTeacherClassEndpoint + "grid") { text ->
+ EDUDZIENNIK_TEACHERS.findAll(text).forEach {
+ val lastName = it[1].trim()
+ val firstName = it[2].trim()
+ data.getTeacher(firstName, lastName)
+ }
+
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS, MONTH)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TEACHERS)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt
new file mode 100644
index 00000000..94db15ef
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/data/web/EdudziennikWebTimetable.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-23
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.web
+
+import org.jsoup.Jsoup
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_SUBJECT_ID
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_TEACHER_ID
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Lesson
+import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.singleOrNull
+import pl.szczodrzynski.edziennik.utils.Utils.d
+import pl.szczodrzynski.edziennik.utils.models.Date
+import pl.szczodrzynski.edziennik.utils.models.Time
+import pl.szczodrzynski.edziennik.utils.models.Week
+
+class EdudziennikWebTimetable(override val data: DataEdudziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : EdudziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "EdudziennikWebTimetable"
+ }
+
+ init { data.profile?.also { profile ->
+
+ val currentWeekStart = Week.getWeekStart()
+
+ if (Date.getToday().weekDay > 4) {
+ currentWeekStart.stepForward(0, 0, 7)
+ }
+
+ val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
+
+ val weekStart = Date.fromY_m_d(getDate)
+ val weekEnd = weekStart.clone().stepForward(0, 0, 6)
+
+ webGet(TAG, data.timetableEndpoint + "print?date=$getDate") { text ->
+ val doc = Jsoup.parse(text)
+
+ val dataDays = mutableListOf()
+ val dataStart = weekStart.clone()
+ while (dataStart <= weekEnd) {
+ dataDays += dataStart.value
+ dataStart.stepForward(0, 0, 1)
+ }
+
+ val table = doc.select("#Schedule tbody").first()
+
+ if (!table.text().contains("Brak planu lekcji.")) {
+ table.children().forEach { row ->
+ val rowElements = row.children()
+
+ val lessonNumber = rowElements[0].text().toInt()
+
+ val times = rowElements[1].text().split('-')
+ val startTime = Time.fromH_m(times[0].trim())
+ val endTime = Time.fromH_m(times[1].trim())
+
+ data.lessonRanges.singleOrNull {
+ it.lessonNumber == lessonNumber && it.startTime == startTime && it.endTime == endTime
+ } ?: run {
+ data.lessonRanges.put(lessonNumber, LessonRange(profileId, lessonNumber, startTime, endTime))
+ }
+
+ rowElements.subList(2, rowElements.size).forEachIndexed { index, lesson ->
+ val course = lesson.select(".course").firstOrNull() ?: return@forEachIndexed
+ val info = course.select("span > span")
+
+ if (info.isEmpty()) return@forEachIndexed
+
+ val type = when (course.hasClass("substitute")) {
+ true -> Lesson.TYPE_CHANGE
+ else -> Lesson.TYPE_NORMAL
+ }
+
+ /* Getting subject */
+
+ val subjectElement = info[0].child(0)
+ val subjectId = EDUDZIENNIK_SUBJECT_ID.find(subjectElement.attr("href"))?.get(1)
+ ?: return@forEachIndexed
+ val subjectName = subjectElement.text().trim()
+ val subject = data.getSubject(subjectId, subjectName)
+
+ /* Getting teacher */
+
+ val teacherId = if (info.size >= 2) {
+ val teacherElement = info[1].child(0)
+ val teacherLongId = EDUDZIENNIK_TEACHER_ID.find(teacherElement.attr("href"))?.get(1)
+ val teacherName = teacherElement.text().trim()
+ data.getTeacherByLastFirst(teacherName, teacherLongId).id
+ } else null
+
+ val lessonObject = Lesson(profileId, -1).also {
+ it.type = type
+ it.date = weekStart.clone().stepForward(0, 0, index)
+ it.lessonNumber = lessonNumber
+ it.startTime = startTime
+ it.endTime = endTime
+ it.subjectId = subject.id
+ it.teacherId = teacherId
+ it.teamId = data.teamClass?.id
+
+ it.id = it.buildId()
+ }
+
+ data.lessonList.add(lessonObject)
+ dataDays.remove(lessonObject.date!!.value)
+
+ if (type != Lesson.TYPE_NORMAL) {
+ val seen = profile.empty || lessonObject.date!! < Date.getToday()
+
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_LESSON_CHANGE,
+ lessonObject.id,
+ seen,
+ seen
+ ))
+ }
+ }
+ }
+ }
+
+ for (day in dataDays) {
+ val lessonDate = Date.fromValue(day)
+ data.lessonList += Lesson(profileId, lessonDate.value.toLong()).apply {
+ type = Lesson.TYPE_NO_LESSONS
+ date = lessonDate
+ }
+ }
+
+ d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
+
+ data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
+ data.setSyncNext(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE)
+ }
+ } ?: onSuccess(ENDPOINT_EDUDZIENNIK_WEB_TIMETABLE) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/firstlogin/EdudziennikFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/firstlogin/EdudziennikFirstLogin.kt
new file mode 100644
index 00000000..a93632b1
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/firstlogin/EdudziennikFirstLogin.kt
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.firstlogin
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_EDUDZIENNIK
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_ACCOUNT_NAME_START
+import pl.szczodrzynski.edziennik.data.api.Regexes.EDUDZIENNIK_STUDENTS_START
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.data.EdudziennikWeb
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login.EdudziennikLoginWeb
+import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.fixName
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.getShortName
+import pl.szczodrzynski.edziennik.set
+
+class EdudziennikFirstLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "EdudziennikFirstLogin"
+ }
+
+ private val web = EdudziennikWeb(data, null)
+ private val profileList = mutableListOf()
+
+ init {
+ val loginStoreId = data.loginStore.id
+ val loginStoreType = LOGIN_TYPE_EDUDZIENNIK
+ var firstProfileId = loginStoreId
+
+ EdudziennikLoginWeb(data) {
+ web.webGet(TAG, "") { text ->
+ val accountNameLong = EDUDZIENNIK_ACCOUNT_NAME_START.find(text)?.get(1)?.fixName()
+
+ EDUDZIENNIK_STUDENTS_START.findAll(text).forEach {
+ val studentId = it[1]
+ val studentNameLong = it[2].fixName()
+
+ if (studentId.isBlank() || studentNameLong.isBlank()) return@forEach
+
+ val studentNameShort = studentNameLong.getShortName()
+ val accountName = if (accountNameLong == studentNameLong) null else accountNameLong
+
+ val profile = Profile(
+ firstProfileId++,
+ loginStoreId,
+ loginStoreType,
+ studentNameLong,
+ data.loginEmail,
+ studentNameLong,
+ studentNameShort,
+ accountName
+ ).apply {
+ studentData["studentId"] = studentId
+ }
+ profileList.add(profile)
+ }
+
+ EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
+ onSuccess()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/login/EdudziennikLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/login/EdudziennikLogin.kt
new file mode 100644
index 00000000..1cb2fd07
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/login/EdudziennikLogin.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
+
+import pl.szczodrzynski.edziennik.R
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_EDUDZIENNIK_WEB
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.utils.Utils
+
+class EdudziennikLogin(val data: DataEdudziennik, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "EdudziennikLogin"
+ }
+
+ private var cancelled = false
+
+ init {
+ nextLoginMethod(onSuccess)
+ }
+
+ private fun nextLoginMethod(onSuccess: () -> Unit) {
+ if (data.targetLoginMethodIds.isEmpty()) {
+ onSuccess()
+ return
+ }
+ if (cancelled) {
+ onSuccess()
+ return
+ }
+ useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId ->
+ data.progress(data.progressStep)
+ if (usedMethodId != -1)
+ data.loginMethods.add(usedMethodId)
+ nextLoginMethod(onSuccess)
+ }
+ }
+
+ private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) {
+ // this should never be true
+ if (data.loginMethods.contains(loginMethodId)) {
+ onSuccess(-1)
+ return
+ }
+ Utils.d(TAG, "Using login method $loginMethodId")
+ when (loginMethodId) {
+ LOGIN_METHOD_EDUDZIENNIK_WEB -> {
+ data.startProgress(R.string.edziennik_progress_login_edudziennik_web)
+ EdudziennikLoginWeb(data) { onSuccess(loginMethodId) }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/login/EdudziennikLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/login/EdudziennikLoginWeb.kt
new file mode 100644
index 00000000..6b1615a2
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/edudziennik/login/EdudziennikLoginWeb.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.login
+
+import im.wangchao.mhttp.Request
+import im.wangchao.mhttp.Response
+import im.wangchao.mhttp.callback.TextCallbackHandler
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.edudziennik.DataEdudziennik
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.getUnixDate
+import pl.szczodrzynski.edziennik.isNotNullNorEmpty
+import pl.szczodrzynski.edziennik.utils.Utils.d
+
+class EdudziennikLoginWeb(val data: DataEdudziennik, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "EdudziennikLoginWeb"
+ }
+
+ init { run {
+ if (data.isWebLoginValid()) {
+ onSuccess()
+ }
+ else {
+ data.app.cookieJar.clear("dziennikel.appspot.com")
+ if (data.loginEmail.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) {
+ loginWithCredentials()
+ }
+ else {
+ data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
+ }
+ }
+ }}
+
+ private fun loginWithCredentials() {
+ d(TAG, "Request: Edudziennik/Login/Web - https://dziennikel.appspot.com/login/?next=/")
+
+ val callback = object : TextCallbackHandler() {
+ override fun onSuccess(text: String?, response: Response?) {
+ if (text == null || response == null) {
+ data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
+ .withResponse(response))
+ return
+ }
+
+ val url = response.raw().request().url().toString()
+
+ if (!url.contains("Student")) {
+ when {
+ text.contains("Wprowadzono nieprawidłową nazwę użytkownika lub hasło.") -> ERROR_LOGIN_EDUDZIENNIK_WEB_INVALID_LOGIN
+ else -> ERROR_LOGIN_EDUDZIENNIK_WEB_OTHER
+ }.let { errorCode ->
+ data.error(ApiError(TAG, errorCode)
+ .withApiResponse(text)
+ .withResponse(response))
+ return
+ }
+ }
+
+ val cookies = data.app.cookieJar.getAll("dziennikel.appspot.com")
+ val sessionId = cookies["sessionid"]
+
+ if (sessionId == null) {
+ data.error(ApiError(TAG, ERROR_LOGIN_EDUDZIENNIK_WEB_NO_SESSION_ID)
+ .withResponse(response)
+ .withApiResponse(text))
+ return
+ }
+
+ data.webSessionId = sessionId
+ data.webSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */
+ onSuccess()
+ }
+
+ override fun onFailure(response: Response?, throwable: Throwable?) {
+ data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ }
+
+ Request.builder()
+ .url("https://dziennikel.appspot.com/login/?next=/")
+ .userAgent(EDUDZIENNIK_USER_AGENT)
+ .contentType("application/x-www-form-urlencoded")
+ .addParameter("email", data.loginEmail)
+ .addParameter("password", data.loginPassword)
+ .addParameter("auth_method", "password")
+ .addParameter("next", "/")
+ .post()
+ .callback(callback)
+ .build()
+ .enqueue()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/helper/DownloadAttachment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/helper/DownloadAttachment.kt
new file mode 100644
index 00000000..a968818a
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/helper/DownloadAttachment.kt
@@ -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()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/helper/OneDriveDownloadAttachment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/helper/OneDriveDownloadAttachment.kt
new file mode 100644
index 00000000..25b78527
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/helper/OneDriveDownloadAttachment.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-4-7.
+ */
+
+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 im.wangchao.mhttp.callback.TextCallbackHandler
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.ERROR_ONEDRIVE_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 OneDriveDownloadAttachment(
+ app: App,
+ 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 = "OneDriveDownloadAttachment"
+ }
+
+ init {
+ Request.builder()
+ .url(fileUrl)
+ .userAgent(SYSTEM_USER_AGENT)
+ .withClient(app.httpLazy)
+ .callback(object : TextCallbackHandler() {
+ override fun onSuccess(text: String, response: Response) {
+ val location = response.headers().get("Location")
+ // https://onedrive.live.com/redir?resid=D75496A2EB87531C!706&authkey=!ABjZeh3pHMqj11Q
+ if (location?.contains("onedrive.live.com/redir?resid=") != true) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withApiResponse(text)
+ .withResponse(response))
+ return
+ }
+ val url = location
+ .replace("onedrive.live.com/redir?resid=", "storage.live.com/items/")
+ .replace("?", "&")
+ .replaceFirst("&", "?")
+ downloadFile(url)
+ }
+
+ override fun onFailure(response: Response, throwable: Throwable) {
+ onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ })
+ .build()
+ .enqueue()
+ }
+
+ private fun downloadFile(url: String) {
+ val targetFile = Utils.getStorageDir()
+
+ val callback = object : FileCallbackHandler(targetFile) {
+ override fun onSuccess(file: File?, response: Response?) {
+ if (file == null) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withResponse(response))
+ return
+ }
+
+ try {
+ onSuccess(file)
+ } catch (e: Exception) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withResponse(response)
+ .withThrowable(e))
+ }
+ }
+
+ override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
+ try {
+ this@OneDriveDownloadAttachment.onProgress(bytesWritten, bytesTotal)
+ } catch (e: Exception) {
+ onError(ApiError(TAG, ERROR_ONEDRIVE_DOWNLOAD)
+ .withThrowable(e))
+ }
+ }
+
+ override fun onFailure(response: Response?, throwable: Throwable?) {
+ onError(ApiError(TAG, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ }
+
+ Request.builder()
+ .url(url)
+ .userAgent(SYSTEM_USER_AGENT)
+ .callback(callback)
+ .build()
+ .enqueue()
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt
similarity index 84%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt
index a774129d..3e974539 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/DataIdziennik.kt
@@ -2,18 +2,17 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
import androidx.core.util.set
-import okhttp3.Cookie
import pl.szczodrzynski.edziennik.*
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_API
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_WEB
-import pl.szczodrzynski.edziennik.api.v2.models.Data
-import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
-import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
-import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
-import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_API
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_WEB
+import pl.szczodrzynski.edziennik.data.api.models.Data
+import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.data.db.entity.Subject
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
@@ -24,23 +23,15 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
loginMethods.clear()
if (isWebLoginValid()) {
loginMethods += LOGIN_METHOD_IDZIENNIK_WEB
- app.cookieJar.saveFromResponse(null, listOf(
- Cookie.Builder()
- .name("ASP.NET_SessionId_iDziennik")
- .value(webSessionId!!)
- .domain("iuczniowie.progman.pl")
- .secure().httpOnly().build(),
- Cookie.Builder()
- .name(".ASPXAUTH")
- .value(webAuth!!)
- .domain("iuczniowie.progman.pl")
- .secure().httpOnly().build()
- ))
+ app.cookieJar.set("iuczniowie.progman.pl", "ASP.NET_SessionId_iDziennik", webSessionId)
+ app.cookieJar.set("iuczniowie.progman.pl", ".ASPXAUTH", webAuth)
}
if (isApiLoginValid())
loginMethods += LOGIN_METHOD_IDZIENNIK_API
}
+ override fun generateUserCode() = "$webSchoolName:$webUsername:$registerId"
+
private var mLoginExpiryTime: Long? = null
var loginExpiryTime: Long
get() { mLoginExpiryTime = mLoginExpiryTime ?: loginStore.getLoginData("loginExpiryTime", 0L); return mLoginExpiryTime ?: 0L }
@@ -79,6 +70,11 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth }
set(value) { loginStore.putLoginData("webAuth", value); mWebAuth = value }
+ private var mWebSelectedRegister: Int? = null
+ var webSelectedRegister: Int
+ get() { mWebSelectedRegister = mWebSelectedRegister ?: loginStore.getLoginData("webSelectedRegister", 0); return mWebSelectedRegister ?: 0 }
+ set(value) { loginStore.putLoginData("webSelectedRegister", value); mWebSelectedRegister = value }
+
/* _
/\ (_)
/ \ _ __ _
@@ -128,7 +124,8 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
subjectList.singleOrNull { it.id == id }
if (subject == null) {
- subject = Subject(profileId, id ?: name.crc16().toLong(), name, shortName)
+ subject = Subject(profileId, id
+ ?: name.crc16().toLong(), name, shortName)
subjectList[subject.id] = subject
}
return subject
@@ -138,10 +135,12 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
return validateTeacher(teacher, firstName, lastName)
}
+
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
return validateTeacher(teacher, firstNameChar.toString(), lastName)
}
+
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
val nameParts = nameLastFirst.split(" ")
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/Idziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/Idziennik.kt
new file mode 100644
index 00000000..e1550632
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/Idziennik.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-25.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.App
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikData
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.firstlogin.IdziennikFirstLogin
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLogin
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikCallback
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.*
+import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
+import pl.szczodrzynski.edziennik.data.db.full.EventFull
+import pl.szczodrzynski.edziennik.data.db.full.MessageFull
+import pl.szczodrzynski.edziennik.utils.Utils.d
+
+class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
+ companion object {
+ private const val TAG = "Idziennik"
+ }
+
+ val internalErrorList = mutableListOf()
+ val data: DataIdziennik
+ private var afterLogin: (() -> Unit)? = null
+
+ init {
+ data = DataIdziennik(app, profile, loginStore).apply {
+ callback = wrapCallback(this@Idziennik.callback)
+ satisfyLoginMethods()
+ }
+ }
+
+ private fun completed() {
+ data.saveData()
+ callback.onCompleted()
+ }
+
+ /* _______ _ _ _ _ _
+ |__ __| | /\ | | (_) | | |
+ | | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
+ | | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
+ | | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
+ |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
+ __/ |
+ |__*/
+ override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) {
+ data.arguments = arguments
+ data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId, onlyEndpoints)
+ login()
+ }
+
+ private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
+ d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
+ if (internalErrorList.isNotEmpty()) {
+ d(TAG, " - Internal errors:")
+ internalErrorList.forEach { d(TAG, " - code $it") }
+ }
+ loginMethodId?.let { data.prepareFor(idziennikLoginMethods, it) }
+ afterLogin?.let { this.afterLogin = it }
+ IdziennikLogin(data) {
+ data()
+ }
+ }
+
+ private fun data() {
+ d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
+ if (internalErrorList.isNotEmpty()) {
+ d(TAG, " - Internal errors:")
+ internalErrorList.forEach { d(TAG, " - code $it") }
+ }
+ afterLogin?.invoke() ?: IdziennikData(data) {
+ completed()
+ }
+ }
+
+ override fun getMessage(message: MessageFull) {
+ login(LOGIN_METHOD_IDZIENNIK_WEB) {
+ IdziennikWebGetMessage(data, message) {
+ completed()
+ }
+ }
+ }
+
+ override fun sendMessage(recipients: List, subject: String, text: String) {
+ login(LOGIN_METHOD_IDZIENNIK_API) {
+ IdziennikWebSendMessage(data, recipients, subject, text) {
+ completed()
+ }
+ }
+ }
+
+ override fun markAllAnnouncementsAsRead() {}
+ override fun getAnnouncement(announcement: AnnouncementFull) {}
+
+ override fun getAttachment(owner: Any, attachmentId: Long, attachmentName: String) {
+ login(LOGIN_METHOD_IDZIENNIK_WEB) {
+ if (owner is Message) {
+ IdziennikWebGetAttachment(data, owner, attachmentId, attachmentName) {
+ completed()
+ }
+ }
+ else if (owner is Event) {
+ IdziennikWebGetHomeworkAttachment(data, owner, attachmentId, attachmentName) {
+ completed()
+ }
+ }
+ }
+ }
+
+ override fun getRecipientList() {
+ login(LOGIN_METHOD_IDZIENNIK_WEB) {
+ IdziennikWebGetRecipientList(data) {
+ completed()
+ }
+ }
+ }
+
+ override fun getEvent(eventFull: EventFull) {
+ login(LOGIN_METHOD_IDZIENNIK_WEB) {
+ IdziennikWebGetHomework(data, eventFull) {
+ completed()
+ }
+ }
+ }
+
+ override fun firstLogin() { IdziennikFirstLogin(data) { completed() } }
+ override fun cancel() {
+ d(TAG, "Cancelled")
+ data.cancel()
+ }
+
+ private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
+ return object : EdziennikCallback {
+ override fun onCompleted() { callback.onCompleted() }
+ override fun onProgress(step: Float) { callback.onProgress(step) }
+ override fun onStartProgress(stringRes: Int) { callback.onStartProgress(stringRes) }
+ override fun onError(apiError: ApiError) {
+ if (apiError.errorCode in internalErrorList) {
+ // finish immediately if the same error occurs twice during the same sync
+ callback.onError(apiError)
+ return
+ }
+ internalErrorList.add(apiError.errorCode)
+ when (apiError.errorCode) {
+ ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION,
+ ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH,
+ ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER,
+ ERROR_IDZIENNIK_WEB_ACCESS_DENIED,
+ ERROR_IDZIENNIK_API_ACCESS_DENIED -> {
+ data.loginMethods.remove(LOGIN_METHOD_IDZIENNIK_WEB)
+ data.prepareFor(idziennikLoginMethods, LOGIN_METHOD_IDZIENNIK_WEB)
+ data.loginExpiryTime = 0
+ login()
+ }
+ ERROR_IDZIENNIK_API_NO_REGISTER -> {
+ data()
+ }
+ else -> callback.onError(apiError)
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/IdziennikFeatures.kt
similarity index 88%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/IdziennikFeatures.kt
index c83c9690..02aaabb2 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/IdziennikFeatures.kt
@@ -2,15 +2,16 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik
-import pl.szczodrzynski.edziennik.api.v2.*
-import pl.szczodrzynski.edziennik.api.v2.models.Feature
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.models.Feature
const val ENDPOINT_IDZIENNIK_WEB_TIMETABLE = 1030
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
+const val ENDPOINT_IDZIENNIK_WEB_HOMEWORK = 1061
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
@@ -34,6 +35,10 @@ val IdziennikFeatures = listOf(
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
+ Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_HOMEWORK, listOf(
+ ENDPOINT_IDZIENNIK_WEB_HOMEWORK to LOGIN_METHOD_IDZIENNIK_WEB
+ ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
+
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikApi.kt
similarity index 89%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikApi.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikApi.kt
index 66a87dfa..8da75603 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikApi.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikApi.kt
@@ -2,7 +2,7 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-29.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data
import com.google.gson.JsonArray
import com.google.gson.JsonElement
@@ -11,14 +11,14 @@ import com.google.gson.JsonParser
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.TextCallbackHandler
-import pl.szczodrzynski.edziennik.api.v2.*
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.Utils
import java.net.HttpURLConnection
-open class IdziennikApi(open val data: DataIdziennik) {
+open class IdziennikApi(open val data: DataIdziennik, open val lastSync: Long?) {
companion object {
const val TAG = "IdziennikApi"
}
@@ -55,6 +55,7 @@ open class IdziennikApi(open val data: DataIdziennik) {
}
error?.let { code ->
when (code) {
+ "Uczeń nie posiada aktywnej pozycji w dzienniku" -> ERROR_IDZIENNIK_API_NO_REGISTER
"Authorization has been denied for this request." -> ERROR_IDZIENNIK_API_ACCESS_DENIED
else -> ERROR_IDZIENNIK_API_OTHER
}.let { errorCode ->
@@ -107,6 +108,7 @@ open class IdziennikApi(open val data: DataIdziennik) {
}
}
}
+ .allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
.allowErrorCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
.callback(callback)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikData.kt
similarity index 55%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikData.kt
index 64064a83..8acb04cb 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikData.kt
@@ -2,14 +2,14 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data
import pl.szczodrzynski.edziennik.R
-import pl.szczodrzynski.edziennik.api.v2.idziennik.*
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiCurrentRegister
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiMessagesInbox
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiMessagesSent
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.web.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiCurrentRegister
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiMessagesInbox
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiMessagesSent
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.*
import pl.szczodrzynski.edziennik.utils.Utils
class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
@@ -30,56 +30,62 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
onSuccess()
return
}
- useEndpoint(data.targetEndpointIds.removeAt(0)) {
+ val id = data.targetEndpointIds.firstKey()
+ val lastSync = data.targetEndpointIds.remove(id)
+ useEndpoint(id, lastSync) { endpointId ->
data.progress(data.progressStep)
nextEndpoint(onSuccess)
}
}
- private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) {
- Utils.d(TAG, "Using endpoint $endpointId")
+ private fun useEndpoint(endpointId: Int, lastSync: Long?, onSuccess: (endpointId: Int) -> Unit) {
+ Utils.d(TAG, "Using endpoint $endpointId. Last sync time = $lastSync")
when (endpointId) {
ENDPOINT_IDZIENNIK_WEB_TIMETABLE -> {
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
- IdziennikWebTimetable(data, onSuccess)
+ IdziennikWebTimetable(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_WEB_GRADES -> {
data.startProgress(R.string.edziennik_progress_endpoint_grades)
- IdziennikWebGrades(data, onSuccess)
+ IdziennikWebGrades(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES -> {
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
- IdziennikWebProposedGrades(data, onSuccess)
+ IdziennikWebProposedGrades(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_WEB_EXAMS -> {
data.startProgress(R.string.edziennik_progress_endpoint_exams)
- IdziennikWebExams(data, onSuccess)
+ IdziennikWebExams(data, lastSync, onSuccess)
+ }
+ ENDPOINT_IDZIENNIK_WEB_HOMEWORK -> {
+ data.startProgress(R.string.edziennik_progress_endpoint_homework)
+ IdziennikWebHomework(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
data.startProgress(R.string.edziennik_progress_endpoint_notices)
- IdziennikWebNotices(data, onSuccess)
+ IdziennikWebNotices(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS -> {
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
- IdziennikWebAnnouncements(data, onSuccess)
+ IdziennikWebAnnouncements(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE -> {
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
- IdziennikWebAttendance(data, onSuccess)
+ IdziennikWebAttendance(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
- IdziennikApiCurrentRegister(data, onSuccess)
+ IdziennikApiCurrentRegister(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
- IdziennikApiMessagesInbox(data, onSuccess)
+ IdziennikApiMessagesInbox(data, lastSync, onSuccess)
}
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT -> {
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
- IdziennikApiMessagesSent(data, onSuccess)
+ IdziennikApiMessagesSent(data, lastSync, onSuccess)
}
- else -> onSuccess()
+ else -> onSuccess(endpointId)
}
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt
similarity index 61%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikWeb.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt
index 2bae8843..b871cd37 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikWeb.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/IdziennikWeb.kt
@@ -2,22 +2,25 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
+import im.wangchao.mhttp.callback.FileCallbackHandler
import im.wangchao.mhttp.callback.JsonCallbackHandler
import im.wangchao.mhttp.callback.TextCallbackHandler
-import pl.szczodrzynski.edziennik.api.v2.*
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web.IdziennikWebSwitchRegister
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
import pl.szczodrzynski.edziennik.utils.Utils.d
+import java.io.File
import java.net.HttpURLConnection.HTTP_INTERNAL_ERROR
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
-open class IdziennikWeb(open val data: DataIdziennik) {
+open class IdziennikWeb(open val data: DataIdziennik, open val lastSync: Long?) {
companion object {
const val TAG = "IdziennikWeb"
}
@@ -39,6 +42,24 @@ open class IdziennikWeb(open val data: DataIdziennik) {
return
}
+ if (response?.code() == HTTP_INTERNAL_ERROR && endpoint == IDZIENNIK_WEB_GET_RECIPIENT_LIST) {
+ data.error(ApiError(tag, ERROR_IDZIENNIK_WEB_RECIPIENT_LIST_NO_PERMISSION)
+ .withResponse(response)
+ .withApiResponse(json))
+ return
+ }
+
+ if (response?.code() == HTTP_INTERNAL_ERROR && endpoint == IDZIENNIK_WEB_GRADES) {
+ // special override for accounts where displaying grades
+ // for another student requires switching it manually
+ if (data.registerId != data.webSelectedRegister) {
+ IdziennikWebSwitchRegister(data, data.registerId) {
+ webApiGet(tag, endpoint, parameters, onSuccess)
+ }
+ return
+ }
+ }
+
when {
response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED
response?.code() == HTTP_INTERNAL_ERROR -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
@@ -94,6 +115,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
is Long -> json.addProperty(name, value)
is Float -> json.addProperty(name, value)
is Char -> json.addProperty(name, value)
+ is Boolean -> json.addProperty(name, value)
}
}
setJsonBody(json)
@@ -105,7 +127,7 @@ open class IdziennikWeb(open val data: DataIdziennik) {
.enqueue()
}
- fun webGet(tag: String, endpoint: String, onSuccess: (text: String) -> Unit) {
+ fun webGet(tag: String, endpoint: String, parameters: Map = emptyMap(), onSuccess: (text: String) -> Unit) {
d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
val callback = object : TextCallbackHandler() {
@@ -150,7 +172,65 @@ open class IdziennikWeb(open val data: DataIdziennik) {
Request.builder()
.url("$IDZIENNIK_WEB_URL/$endpoint")
.userAgent(IDZIENNIK_USER_AGENT)
- .get()
+ .apply {
+ if (parameters.isEmpty()) get()
+ else post()
+
+ parameters.map { (name, value) ->
+ addParameter(name, value)
+ }
+ }
+ .callback(callback)
+ .build()
+ .enqueue()
+ }
+
+ fun webGetFile(tag: String, endpoint: String, targetFile: File, parameters: Map,
+ onSuccess: (file: File) -> Unit, onProgress: (written: Long, total: Long) -> Unit) {
+
+ d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
+
+ val callback = object : FileCallbackHandler(targetFile) {
+ override fun onSuccess(file: File?, response: Response?) {
+ if (file == null) {
+ data.error(ApiError(TAG, ERROR_FILE_DOWNLOAD)
+ .withResponse(response))
+ return
+ }
+
+ try {
+ onSuccess(file)
+ } catch (e: Exception) {
+ data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_FILE_REQUEST)
+ .withResponse(response)
+ .withThrowable(e))
+ }
+ }
+
+ override fun onProgress(bytesWritten: Long, bytesTotal: Long) {
+ try {
+ onProgress(bytesWritten, bytesTotal)
+ } catch (e: Exception) {
+ data.error(ApiError(tag, EXCEPTION_EDUDZIENNIK_FILE_REQUEST)
+ .withThrowable(e))
+ }
+ }
+
+ override fun onFailure(response: Response?, throwable: Throwable?) {
+ data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
+ .withResponse(response)
+ .withThrowable(throwable))
+ }
+ }
+
+ Request.builder()
+ .url("$IDZIENNIK_WEB_URL/$endpoint")
+ .userAgent(IDZIENNIK_USER_AGENT)
+ .apply {
+ parameters.forEach { (k, v) -> addParameter(k, v) }
+ }
+ .contentType("application/x-www-form-urlencoded")
+ .post()
.callback(callback)
.build()
.enqueue()
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiCurrentRegister.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiCurrentRegister.kt
similarity index 67%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiCurrentRegister.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiCurrentRegister.kt
index 2366e625..d5e59596 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiCurrentRegister.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiCurrentRegister.kt
@@ -2,16 +2,16 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-29.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.DAY
-import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_CURRENT_REGISTER
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
-import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
-import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_CURRENT_REGISTER
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
+import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.getInt
import pl.szczodrzynski.edziennik.getJsonObject
import pl.szczodrzynski.edziennik.getString
@@ -19,27 +19,26 @@ import pl.szczodrzynski.edziennik.utils.models.Date
import pl.szczodrzynski.edziennik.utils.models.Time
class IdziennikApiCurrentRegister(override val data: DataIdziennik,
- val onSuccess: () -> Unit) : IdziennikApi(data) {
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikApi(data, lastSync) {
companion object {
private const val TAG = "IdziennikApiCurrentRegister"
}
init {
- data.profile?.luckyNumber = -1
- data.profile?.luckyNumberDate = null
-
apiGet(TAG, IDZIENNIK_API_CURRENT_REGISTER) { json ->
if (json !is JsonObject) {
- onSuccess()
+ onSuccess(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER)
return@apiGet
}
var nextSync = System.currentTimeMillis() + 14*DAY*1000
val settings = json.getJsonObject("ustawienia")?.apply {
- profile?.dateSemester1Start = getString("poczatekSemestru1")?.let { Date.fromY_m_d(it) }
- profile?.dateSemester2Start = getString("koniecSemestru1")?.let { Date.fromY_m_d(it).stepForward(0, 0, 1) }
- profile?.dateYearEnd = getString("koniecSemestru2")?.let { Date.fromY_m_d(it) }
+ getString("poczatekSemestru1")?.let { profile?.dateSemester1Start = Date.fromY_m_d(it) }
+ getString("koniecSemestru1")?.let { profile?.dateSemester2Start = Date.fromY_m_d(it).stepForward(0, 0, 1) }
+ getString("koniecSemestru2")?.let { profile?.dateYearEnd = Date.fromY_m_d(it) }
}
json.getInt("szczesliwyNumerek")?.let { luckyNumber ->
@@ -69,9 +68,9 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
val luckyNumberObject = LuckyNumber(
- data.profileId,
- Date.getToday(),
- luckyNumber
+ profileId = data.profileId,
+ date = luckyNumberDate,
+ number = luckyNumber
)
data.luckyNumberList.add(luckyNumberObject)
@@ -80,15 +79,14 @@ class IdziennikApiCurrentRegister(override val data: DataIdziennik,
profileId,
Metadata.TYPE_LUCKY_NUMBER,
luckyNumberObject.date.value.toLong(),
- data.profile?.empty ?: false,
- data.profile?.empty ?: false,
- System.currentTimeMillis()
+ true,
+ data.profile?.empty ?: false
))
}
data.setSyncNext(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER, syncAt = nextSync)
- onSuccess()
+ onSuccess(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER)
}
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiMessagesInbox.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiMessagesInbox.kt
new file mode 100644
index 00000000..622068e2
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiMessagesInbox.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-30.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api
+
+import com.google.gson.JsonArray
+import pl.szczodrzynski.edziennik.asJsonObjectList
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_MESSAGES_INBOX
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
+import pl.szczodrzynski.edziennik.data.db.entity.*
+import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_DELETED
+import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
+import pl.szczodrzynski.edziennik.getBoolean
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.utils.Utils.crc32
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class IdziennikApiMessagesInbox(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikApi(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikApiMessagesInbox"
+ }
+
+ init {
+ apiGet(TAG, IDZIENNIK_API_MESSAGES_INBOX) { json ->
+ if (json !is JsonArray) {
+ onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX)
+ return@apiGet
+ }
+
+ json.asJsonObjectList().forEach { jMessage ->
+ val subject = jMessage.getString("tytul") ?: ""
+ if (subject.contains("(") && subject.startsWith("iDziennik - "))
+ return@forEach
+ if (subject.startsWith("Uwaga dla ucznia (klasa:"))
+ return@forEach
+
+ val messageIdStr = jMessage.getString("id")
+ val messageId = crc32((messageIdStr + "0").toByteArray())
+
+ var body = "[META:$messageIdStr;-1]"
+ body += jMessage.getString("tresc")?.replace("\n".toRegex(), " ")
+
+ val readDate = if (jMessage.getBoolean("odczytana") == true) Date.fromIso(jMessage.getString("wersjaRekordu")) else 0
+ val sentDate = Date.fromIso(jMessage.getString("dataWyslania"))
+
+ val sender = jMessage.getAsJsonObject("nadawca")
+ var firstName = sender.getString("imie")
+ var lastName = sender.getString("nazwisko")
+ if (firstName.isNullOrEmpty() || lastName.isNullOrEmpty()) {
+ firstName = "usunięty"
+ lastName = "użytkownik"
+ }
+ val rTeacher = data.getTeacher(
+ firstName,
+ lastName
+ )
+ rTeacher.loginId = /*sender.getString("id") + ":" + */sender.getString("usr")
+ rTeacher.setTeacherType(Teacher.TYPE_OTHER)
+
+ val message = Message(
+ profileId = profileId,
+ id = messageId,
+ type = if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
+ subject = subject,
+ body = body,
+ senderId = rTeacher.id,
+ addedDate = sentDate
+ )
+
+ val messageRecipient = MessageRecipient(
+ profileId,
+ -1 /* me */,
+ -1,
+ readDate,
+ /*messageId*/ messageId
+ )
+
+ data.messageList.add(message)
+ data.messageRecipientList.add(messageRecipient)
+ data.setSeenMetadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_MESSAGE,
+ message.id,
+ readDate > 0,
+ readDate > 0 || profile?.empty ?: false
+ ))
+ }
+
+ data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiMessagesSent.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiMessagesSent.kt
similarity index 61%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiMessagesSent.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiMessagesSent.kt
index 6c809d8b..87b3264d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/api/IdziennikApiMessagesSent.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/api/IdziennikApiMessagesSent.kt
@@ -2,25 +2,27 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-30.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api
import com.google.gson.JsonArray
import pl.szczodrzynski.edziennik.DAY
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
-import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_SENT
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
import pl.szczodrzynski.edziennik.asJsonObjectList
-import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
-import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
-import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
-import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_API_MESSAGES_SENT
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikApi
+import pl.szczodrzynski.edziennik.data.db.entity.Message
+import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
+import pl.szczodrzynski.edziennik.data.db.entity.MessageRecipient
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.utils.Utils.crc32
import pl.szczodrzynski.edziennik.utils.models.Date
class IdziennikApiMessagesSent(override val data: DataIdziennik,
- val onSuccess: () -> Unit) : IdziennikApi(data) {
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikApi(data, lastSync) {
companion object {
private const val TAG = "IdziennikApiMessagesSent"
}
@@ -28,7 +30,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
init {
apiGet(TAG, IDZIENNIK_API_MESSAGES_SENT) { json ->
if (json !is JsonArray) {
- onSuccess()
+ onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT)
return@apiGet
}
@@ -44,13 +46,13 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
val sentDate = Date.fromIso(jMessage.get("dataWyslania").asString)
val message = Message(
- profileId,
- messageId,
- subject,
- body,
- TYPE_SENT,
- -1,
- -1
+ profileId = profileId,
+ id = messageId,
+ type = TYPE_SENT,
+ subject = subject,
+ body = body,
+ senderId = null,
+ addedDate = sentDate
)
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
@@ -62,7 +64,7 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
lastName = "użytkownik"
}
val rTeacher = data.getTeacher(firstName, lastName)
- rTeacher.loginId = recipient.get("id").asString + ":" + recipient.get("usr").asString
+ rTeacher.loginId = /*recipient.get("id").asString + ":" + */recipient.get("usr").asString
val messageRecipient = MessageRecipient(
profileId,
@@ -74,12 +76,12 @@ class IdziennikApiMessagesSent(override val data: DataIdziennik,
data.messageRecipientIgnoreList.add(messageRecipient)
}
- data.messageIgnoreList.add(message)
- data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
+ data.messageList.add(message)
+ data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true))
}
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
- onSuccess()
+ onSuccess(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT)
}
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebAnnouncements.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebAnnouncements.kt
new file mode 100644
index 00000000..531cbeeb
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebAnnouncements.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-28.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import com.google.gson.JsonArray
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_ANNOUNCEMENTS
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Announcement
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.getJsonObject
+import pl.szczodrzynski.edziennik.getLong
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class IdziennikWebAnnouncements(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikWebAnnouncements"
+ }
+
+ init {
+ val param = JsonObject()
+ param.add("parametryFiltrow", JsonArray())
+
+ webApiGet(TAG, IDZIENNIK_WEB_ANNOUNCEMENTS, mapOf(
+ "uczenId" to (data.studentId ?: ""),
+ "param" to param
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ for (jAnnouncementEl in json.getAsJsonArray("ListK")) {
+ val jAnnouncement = jAnnouncementEl.asJsonObject
+ // jAnnouncement
+ val announcementId = jAnnouncement.getLong("Id") ?: -1
+
+ val rTeacher = data.getTeacherByFirstLast(jAnnouncement.getString("Autor") ?: "")
+ val addedDate = jAnnouncement.getString("DataDodania")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull() ?: System.currentTimeMillis()
+ val startDate = jAnnouncement.getString("DataWydarzenia")?.replace("[^\\d]".toRegex(), "")?.toLongOrNull()?.let { Date.fromMillis(it) }
+
+ val announcementObject = Announcement(
+ profileId = profileId,
+ id = announcementId,
+ subject = jAnnouncement.get("Temat").asString,
+ text = jAnnouncement.get("Tresc").asString,
+ startDate = startDate,
+ endDate = null,
+ teacherId = rTeacher.id,
+ addedDate = addedDate
+ )
+ data.announcementList.add(announcementObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_ANNOUNCEMENT,
+ announcementObject.id,
+ profile?.empty ?: false,
+ profile?.empty ?: false
+ ))
+ }
+
+ data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebAttendance.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebAttendance.kt
new file mode 100644
index 00000000..e77c9eac
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebAttendance.kt
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-28.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import pl.szczodrzynski.edziennik.crc16
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_ATTENDANCE
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_ATTENDANCE
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_ABSENT_EXCUSED
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_BELATED
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_PRESENT_CUSTOM
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_RELEASED
+import pl.szczodrzynski.edziennik.data.db.entity.Attendance.Companion.TYPE_UNKNOWN
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.getInt
+import pl.szczodrzynski.edziennik.getJsonObject
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.utils.models.Date
+import pl.szczodrzynski.edziennik.utils.models.Time
+
+class IdziennikWebAttendance(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikWebAttendance"
+ }
+
+ private var attendanceYear = Date.getToday().year
+ private var attendanceMonth = Date.getToday().month
+ private var attendancePrevMonthChecked = false
+
+ init {
+ getAttendance()
+ }
+
+ private fun getAttendance() {
+ webApiGet(TAG, IDZIENNIK_WEB_ATTENDANCE, mapOf(
+ "idPozDziennika" to data.registerId,
+ "mc" to attendanceMonth,
+ "rok" to attendanceYear,
+ "dataTygodnia" to ""
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) {
+ val jAttendance = jAttendanceEl.asJsonObject
+ // jAttendance
+ val type = jAttendance.get("TypObecnosci").asInt
+
+ // skip "zajęcia nie odbyły się" and "Ferie"
+ if (type == 5 || type == 7)
+ continue
+
+ val date = Date.fromY_m_d(jAttendance.get("Data").asString)
+ val time = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
+ if (date.combineWith(time) > System.currentTimeMillis())
+ continue
+
+ val id = jAttendance.get("IdLesson").asString.crc16().toLong()
+ val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "")
+ val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString)
+
+ var baseType = TYPE_UNKNOWN
+ var typeName = "nieznany rodzaj"
+ var typeSymbol: String? = null
+ var typeColor: Long? = null
+
+ /* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosciUcznia_lmt637231494660000000.js */
+ /* https://iuczniowie.progman.pl/idziennik/mod_panelRodzica/obecnosci/obecnosci_lmt637231494660000000.css */
+ when (type) {
+ 1 -> {
+ baseType = TYPE_ABSENT_EXCUSED
+ typeName = "nieobecność usprawiedliwiona"
+ typeColor = 0xffffe099
+ }
+ 2 -> {
+ baseType = TYPE_BELATED
+ typeName = "spóźnienie"
+ typeColor = 0xffffffaa
+ }
+ 3 -> {
+ baseType = TYPE_ABSENT
+ typeName = "nieobecność nieusprawiedliwiona"
+ typeColor = 0xffffad99
+ }
+ 4, 9 -> {
+ baseType = TYPE_RELEASED
+ if (type == 4) {
+ typeName = "zwolnienie"
+ typeColor = 0xffa8beff
+ }
+ if (type == 9) {
+ typeName = "zwolniony / obecny"
+ typeSymbol = "zb"
+ typeColor = 0xffff69b4
+ }
+ }
+ 8 -> {
+ baseType = TYPE_PRESENT_CUSTOM
+ typeName = "wycieczka"
+ typeSymbol = "w"
+ typeColor = null
+ }
+ 0 -> {
+ baseType = TYPE_PRESENT
+ typeName = "obecny"
+ typeColor = 0xffccffcc
+ }
+ }
+
+ val semester = profile?.dateToSemester(date) ?: 1
+
+ val attendanceObject = Attendance(
+ profileId = profileId,
+ id = id,
+ baseType = baseType,
+ typeName = typeName,
+ typeShort = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
+ typeSymbol = typeSymbol ?: data.app.attendanceManager.getTypeShort(baseType),
+ typeColor = typeColor?.toInt(),
+ date = date,
+ startTime = time,
+ semester = semester,
+ teacherId = rTeacher.id,
+ subjectId = rSubject.id
+ ).also {
+ it.lessonTopic = jAttendance.getString("PrzedmiotTemat")
+ it.lessonNumber = jAttendance.getInt("Godzina")
+ }
+
+ data.attendanceList.add(attendanceObject)
+ if (attendanceObject.baseType != TYPE_PRESENT) {
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_ATTENDANCE,
+ attendanceObject.id,
+ profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN,
+ profile?.empty ?: false || baseType == TYPE_PRESENT_CUSTOM || baseType == TYPE_UNKNOWN
+ ))
+ }
+ }
+
+ val attendanceDateValue = attendanceYear * 10000 + attendanceMonth * 100
+ if (profile?.empty == true && attendanceDateValue > profile?.getSemesterStart(1)?.value ?: 99999999) {
+ attendancePrevMonthChecked = true // do not need to check prev month later
+ attendanceMonth--
+ if (attendanceMonth < 1) {
+ attendanceMonth = 12
+ attendanceYear--
+ }
+ getAttendance()
+ } else if (!attendancePrevMonthChecked /* get also the previous month */) {
+ attendanceMonth--
+ if (attendanceMonth < 1) {
+ attendanceMonth = 12
+ attendanceYear--
+ }
+ attendancePrevMonthChecked = true
+ getAttendance()
+ } else {
+ data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebExams.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebExams.kt
new file mode 100644
index 00000000..25c06945
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebExams.kt
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-28.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_EXAMS
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Event
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.utils.models.Date
+import java.util.*
+
+class IdziennikWebExams(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikWebExams"
+ }
+
+ private var examsYear = Date.getToday().year
+ private var examsMonth = Date.getToday().month
+ private var examsMonthsChecked = 0
+ private var examsNextMonthChecked = false // TO DO temporary // no more // idk
+
+ init {
+ getExams()
+ }
+
+ private fun getExams() {
+ val param = JsonObject().apply {
+ addProperty("strona", 1)
+ addProperty("iloscNaStrone", "99")
+ addProperty("iloscRekordow", -1)
+ addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
+ addProperty("kierunekSort", 0)
+ addProperty("maxIloscZaznaczonych", 0)
+ addProperty("panelFiltrow", 0)
+ }
+
+ webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
+ "idP" to data.registerId,
+ "rok" to examsYear,
+ "miesiac" to examsMonth,
+ "param" to param
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { exam ->
+ val id = exam.getLong("_recordId") ?: return@forEach
+ val examDate = Date.fromY_m_d(exam.getString("data") ?: return@forEach)
+ val subjectName = exam.getString("przedmiot") ?: return@forEach
+ val subjectId = data.getSubject(subjectName, null, subjectName).id
+ val teacherName = exam.getString("wpisal") ?: return@forEach
+ val teacherId = data.getTeacherByLastFirst(teacherName).id
+ val topic = exam.getString("zakres")?.trim() ?: ""
+
+ val lessonList = data.db.timetableDao().getAllForDateNow(profileId, examDate)
+ val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.startTime
+
+ val eventType = when (exam.getString("rodzaj")?.toLowerCase(Locale.getDefault())) {
+ "sprawdzian/praca klasowa",
+ "sprawdzian",
+ "praca klasowa" -> Event.TYPE_EXAM
+ "kartkówka" -> Event.TYPE_SHORT_QUIZ
+ else -> Event.TYPE_EXAM
+ }
+
+ val eventObject = Event(
+ profileId = profileId,
+ id = id,
+ date = examDate,
+ time = startTime,
+ topic = topic,
+ color = null,
+ type = eventType,
+ teacherId = teacherId,
+ subjectId = subjectId,
+ teamId = data.teamClass?.id ?: -1
+ )
+
+ data.eventList.add(eventObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_EVENT,
+ eventObject.id,
+ profile?.empty ?: false,
+ profile?.empty ?: false
+ ))
+ }
+
+ if (profile?.empty == true && examsMonthsChecked < 3 /* how many months backwards to check? */) {
+ examsMonthsChecked++
+ examsMonth--
+ if (examsMonth < 1) {
+ examsMonth = 12
+ examsYear--
+ }
+ getExams()
+ } else if (!examsNextMonthChecked /* get also one month forward */) {
+ val showDate = Date.getToday().stepForward(0, 1, 0)
+ examsYear = showDate.year
+ examsMonth = showDate.month
+ examsNextMonthChecked = true
+ getExams()
+ } else {
+ data.toRemove.add(DataRemoveModel.Events.futureExceptType(Event.TYPE_HOMEWORK))
+
+ data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_EXAMS)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetAttachment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetAttachment.kt
new file mode 100644
index 00000000..b7a462f6
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetAttachment.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-28
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_ATTACHMENT
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
+import pl.szczodrzynski.edziennik.data.db.entity.Message
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.utils.Utils
+import java.io.File
+
+class IdziennikWebGetAttachment(override val data: DataIdziennik,
+ val owner: Any,
+ val attachmentId: Long,
+ val attachmentName: String,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ const val TAG = "IdziennikWebGetAttachment"
+ }
+
+ init {
+ val message = owner as Message
+
+ val messageId = "\\[META:([A-z0-9]+);([0-9-]+)]".toRegex().find(message.body ?: "")?.get(2) ?: -1
+ val targetFile = File(Utils.getStorageDir(), attachmentName)
+
+ webGetFile(TAG, IDZIENNIK_WEB_GET_ATTACHMENT, targetFile, mapOf(
+ "id" to messageId,
+ "fileName" to attachmentName
+ ), { file ->
+ val event = AttachmentGetEvent(
+ profileId,
+ owner,
+ attachmentId,
+ AttachmentGetEvent.TYPE_FINISHED,
+ file.absolutePath
+ )
+
+ val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.ownerId}_${event.attachmentId}")
+ Utils.writeStringToFile(attachmentDataFile, event.fileName)
+
+ EventBus.getDefault().postSticky(event)
+
+ onSuccess()
+
+ }) { written, _ ->
+ val event = AttachmentGetEvent(
+ profileId,
+ owner,
+ attachmentId,
+ AttachmentGetEvent.TYPE_PROGRESS,
+ bytesWritten = written
+ )
+
+ EventBus.getDefault().postSticky(event)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetHomework.kt
new file mode 100644
index 00000000..12d804db
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetHomework.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-4-1.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_HOMEWORK
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.EventGetEvent
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.full.EventFull
+import pl.szczodrzynski.edziennik.getBoolean
+import pl.szczodrzynski.edziennik.getJsonObject
+import pl.szczodrzynski.edziennik.getString
+
+class IdziennikWebGetHomework(override val data: DataIdziennik,
+ val event: EventFull,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ private const val TAG = "IdziennikWebGetHomework"
+ }
+
+ init {
+ webApiGet(TAG, IDZIENNIK_WEB_GET_HOMEWORK, mapOf(
+ "idP" to data.registerId,
+ "idPD" to event.id
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ val homework = json.getJsonObject("praca") ?: return@webApiGet
+
+ if (homework.getBoolean("zalacznik", false)) {
+ event.attachmentIds = mutableListOf(event.id)
+ event.attachmentNames = mutableListOf("Załącznik do zadania")
+ }
+ else {
+ event.attachmentIds = mutableListOf()
+ event.attachmentNames = mutableListOf()
+ }
+ event.homeworkBody = homework.getString("tresc")
+
+ data.eventList.add(event)
+ data.eventListReplace = true
+
+ EventBus.getDefault().postSticky(EventGetEvent(event))
+ onSuccess()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetHomeworkAttachment.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetHomeworkAttachment.kt
new file mode 100644
index 00000000..f4a60f98
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetHomeworkAttachment.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2020-4-1.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import com.google.gson.JsonObject
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.AttachmentGetEvent
+import pl.szczodrzynski.edziennik.data.db.entity.Event
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.getString
+import pl.szczodrzynski.edziennik.set
+import pl.szczodrzynski.edziennik.utils.Utils
+import java.io.File
+
+class IdziennikWebGetHomeworkAttachment(override val data: DataIdziennik,
+ val owner: Any,
+ val attachmentId: Long,
+ val attachmentName: String,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ const val TAG = "IdziennikWebGetHomeworkAttachment"
+ }
+
+ init {
+ val homework = owner as Event
+
+ /*val request = Request.Builder()
+ .url("")
+ .build()
+ data.app.http.newCall(request).enqueue(object : Callback {
+ override fun onFailure(call: Call, e: IOException) {
+ data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
+ .withThrowable(e))
+ }
+
+ override fun onResponse(call: Call, response: Response) {
+ val filename = response.header("content-disposition")?.substringAfter("\"")?.substringBeforeLast("\"")
+
+ val file: File = File(Utils.getStorageDir(), filename)
+ val sink = file.sink().buffer()
+ response.body()?.source()?.let {
+ sink.writeAll(it)
+ }
+ sink.close()
+ }
+ })*/
+
+ webGet(TAG, IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT) { text ->
+ val hiddenFields = JsonObject()
+ Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach {
+ hiddenFields[it[1]] = it[2]
+ }
+
+ webGetFile(TAG, IDZIENNIK_WEB_GET_HOMEWORK_ATTACHMENT, Utils.getStorageDir(), mapOf(
+ "__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""),
+ "__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""),
+ "__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""),
+ "__EVENTTARGET" to "ctl00\$cphContent\$bt_pobraniePliku",
+ "ctl00\$dxComboUczniowie" to data.registerId,
+ "ctl00\$cphContent\$idPracyDomowej" to attachmentId
+ ), { file ->
+ val event = AttachmentGetEvent(
+ profileId,
+ owner,
+ attachmentId,
+ AttachmentGetEvent.TYPE_FINISHED,
+ file.absolutePath
+ )
+
+ val attachmentDataFile = File(Utils.getStorageDir(), ".${profileId}_${event.ownerId}_${event.attachmentId}")
+ Utils.writeStringToFile(attachmentDataFile, event.fileName)
+
+ homework.attachmentNames = mutableListOf(file.name)
+ data.eventList.add(homework)
+ data.eventListReplace = true
+
+ EventBus.getDefault().postSticky(event)
+ onSuccess()
+
+ }) { written, _ ->
+ val event = AttachmentGetEvent(
+ profileId,
+ owner,
+ attachmentId,
+ AttachmentGetEvent.TYPE_PROGRESS,
+ bytesWritten = written
+ )
+
+ EventBus.getDefault().postSticky(event)
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetMessage.kt
new file mode 100644
index 00000000..bd1808df
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetMessage.kt
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-12-28
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_MESSAGE
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.MessageGetEvent
+import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_RECEIVED
+import pl.szczodrzynski.edziennik.data.db.entity.Message.Companion.TYPE_SENT
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.full.MessageFull
+import pl.szczodrzynski.edziennik.data.db.full.MessageRecipientFull
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class IdziennikWebGetMessage(override val data: DataIdziennik,
+ private val message: MessageFull,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ const val TAG = "IdziennikWebGetMessage"
+ }
+
+ init { data.profile?.also { profile ->
+ val metaPattern = "\\[META:([A-z0-9]+);([0-9-]+)]".toRegex()
+ val meta = metaPattern.find(message.body!!)
+ val messageIdString = meta?.get(1) ?: ""
+
+ webApiGet(TAG, IDZIENNIK_WEB_GET_MESSAGE, parameters = mapOf(
+ "idWiadomosci" to messageIdString,
+ "typWiadomosci" to if (message.type == TYPE_SENT) 1 else 0
+ )) { json ->
+ json.getJsonObject("d")?.getJsonObject("Wiadomosc")?.also {
+ val id = it.getLong("_recordId")
+ message.body = message.body?.replace(metaPattern, "[META:$messageIdString;$id]")
+
+ message.clearAttachments()
+ it.getJsonArray("ListaZal")?.asJsonObjectList()?.forEach { attachment ->
+ message.addAttachment(
+ attachment.getLong("Id") ?: return@forEach,
+ attachment.getString("Nazwa") ?: return@forEach,
+ -1
+ )
+ }
+
+ message.recipients?.clear()
+ when (message.type) {
+ TYPE_RECEIVED -> {
+ val recipientObject = MessageRecipientFull(
+ profileId = profileId,
+ id = -1,
+ messageId = message.id
+ )
+
+ val readDateString = it.getString("DataOdczytania")
+ recipientObject.readDate = if (readDateString.isNullOrBlank()) System.currentTimeMillis()
+ else Date.fromIso(readDateString)
+
+ recipientObject.fullName = profile.accountName ?: profile.studentNameLong
+
+ data.messageRecipientList.add(recipientObject)
+ message.addRecipient(recipientObject)
+ }
+
+ TYPE_SENT -> {
+ it.getJsonArray("ListaOdbiorcow")?.asJsonObjectList()?.forEach { recipient ->
+ val recipientName = recipient.getString("NazwaOdbiorcy") ?: return@forEach
+ val teacher = data.getTeacherByLastFirst(recipientName)
+
+ val recipientObject = MessageRecipientFull(
+ profileId = profileId,
+ id = teacher.id,
+ messageId = message.id
+ )
+
+ recipientObject.readDate = recipient.getLong("Status") ?: return@forEach
+ recipientObject.fullName = teacher.fullName
+
+ data.messageRecipientList.add(recipientObject)
+ message.addRecipient(recipientObject)
+ }
+ }
+ }
+
+ if (!message.seen) {
+ message.seen = true
+
+ data.setSeenMetadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_MESSAGE,
+ message.id,
+ message.seen,
+ message.notified
+ ))
+ }
+
+ data.messageList.add(message)
+ data.messageListReplace = true
+
+ EventBus.getDefault().postSticky(MessageGetEvent(message))
+ onSuccess()
+ }
+ }
+ } ?: onSuccess() }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetRecipientList.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetRecipientList.kt
new file mode 100644
index 00000000..a14efc24
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGetRecipientList.kt
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-12-30.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import androidx.room.OnConflictStrategy
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GET_RECIPIENT_LIST
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.events.RecipientListGetEvent
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
+
+class IdziennikWebGetRecipientList(override val data: DataIdziennik,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ private const val TAG = "IdziennikWebGetRecipientList"
+ }
+
+ init {
+ webApiGet(TAG, IDZIENNIK_WEB_GET_RECIPIENT_LIST, mapOf(
+ "idP" to data.registerId
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ json.getJsonArray("ListK_Pracownicy")?.asJsonObjectList()?.forEach { recipient ->
+ val name = recipient.getString("ImieNazwisko") ?: ": "
+ val (fullName, subject) = name.split(": ").let {
+ Pair(it.getOrNull(0), it.getOrNull(1))
+ }
+ val guid = recipient.getString("Id") ?: ""
+ // get teacher by ID or create it
+ val teacher = data.getTeacherByFirstLast(fullName ?: " ")
+ teacher.loginId = guid
+ teacher.setTeacherType(Teacher.TYPE_TEACHER)
+ // unset OTHER that is automatically set in IdziennikApiMessages*
+ teacher.unsetTeacherType(Teacher.TYPE_OTHER)
+ teacher.typeDescription = subject
+ }
+
+ json.getJsonArray("ListK_Opiekunowie")?.asJsonObjectList()?.forEach { recipient ->
+ val name = recipient.getString("ImieNazwisko") ?: ": "
+ val (fullName, parentOf) = Regexes.IDZIENNIK_MESSAGES_RECIPIENT_PARENT.find(name)?.let {
+ Pair(it.groupValues.getOrNull(1), it.groupValues.getOrNull(2))
+ } ?: Pair(null, null)
+ val guid = recipient.getString("Id") ?: ""
+ // get teacher by ID or create it
+ val teacher = data.getTeacherByFirstLast(fullName ?: " ")
+ teacher.loginId = guid
+ teacher.setTeacherType(Teacher.TYPE_PARENT)
+ // unset OTHER that is automatically set in IdziennikApiMessages*
+ teacher.unsetTeacherType(Teacher.TYPE_OTHER)
+ teacher.typeDescription = parentOf
+ }
+
+ val event = RecipientListGetEvent(
+ data.profileId,
+ data.teacherList.filter { it.loginId != null }
+ )
+
+ profile?.lastReceiversSync = System.currentTimeMillis()
+
+ data.teacherOnConflictStrategy = OnConflictStrategy.REPLACE
+ EventBus.getDefault().postSticky(event)
+ onSuccess()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt
similarity index 57%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebGrades.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt
index e99387f6..90e17401 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebGrades.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebGrades.kt
@@ -2,28 +2,32 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
import android.graphics.Color
import pl.szczodrzynski.edziennik.*
-import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
-import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_GRADES
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_GRADES
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
-import pl.szczodrzynski.edziennik.api.v2.models.ApiError
-import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
-import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
-import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_GRADES
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_GRADES
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Grade
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_NORMAL
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.utils.models.Date
class IdziennikWebGrades(override val data: DataIdziennik,
- val onSuccess: () -> Unit) : IdziennikWeb(data) {
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
companion object {
private const val TAG = "IdziennikWebGrades"
}
- init {
+ init { data.profile?.also { profile ->
webApiGet(TAG, IDZIENNIK_WEB_GRADES, mapOf(
"idPozDziennika" to data.registerId
)) { result ->
@@ -59,18 +63,24 @@ class IdziennikWebGrades(override val data: DataIdziennik,
colorInt = Color.parseColor("#$gradeColor")
}
+ val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
+
val gradeObject = Grade(
- profileId,
- id,
- category,
- colorInt,
- "",
- name,
- value,
- weight,
- semester,
- teacher.id,
- subject.id)
+ profileId = profileId,
+ id = id,
+ name = name,
+ type = TYPE_NORMAL,
+ value = value,
+ weight = weight,
+ color = colorInt,
+ category = category,
+ description = null,
+ comment = null,
+ semester = semester,
+ teacherId = teacher.id,
+ subjectId = subject.id,
+ addedDate = addedDate
+ )
when (grade.getInt("Typ")) {
0 -> {
@@ -88,30 +98,39 @@ class IdziennikWebGrades(override val data: DataIdziennik,
count += weight
}
- val historyObject = Grade(
- profileId,
- gradeObject.id * -1,
- historyItem.get("Kategoria").asString,
- Color.parseColor("#" + historyItem.get("Kolor").asString),
- historyItem.get("Uzasadnienie").asString,
- historyItem.get("Ocena").asString,
- value,
- if (value > 0f && countToTheAverage) weight * -1f else 0f,
- historyItem.get("Semestr").asInt,
- teacher.id,
- subject.id)
- historyObject.parentId = gradeObject.id
+ val historyColor = historyItem.getString("Kolor") ?: ""
+ colorInt = 0xff2196f3.toInt()
+ if (historyColor.isNotEmpty()) {
+ colorInt = Color.parseColor("#$historyColor")
+ }
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
+ val historyObject = Grade(
+ profileId = profileId,
+ id = gradeObject.id * -1,
+ name = historyItem.getString("Ocena") ?: "",
+ type = TYPE_NORMAL,
+ value = value,
+ weight = if (value > 0f && countToTheAverage) weight * -1f else 0f,
+ color = colorInt,
+ category = historyItem.getString("Kategoria"),
+ description = historyItem.getString("Uzasadnienie"),
+ comment = null,
+ semester = historyItem.getInt("Semestr") ?: 1,
+ teacherId = teacher.id,
+ subjectId = subject.id,
+ addedDate = addedDate
+ )
+ historyObject.parentId = gradeObject.id
+
data.gradeList.add(historyObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_GRADE,
historyObject.id,
true,
- true,
- addedDate
+ true
))
}
// update the current grade's value with an average of all historical grades and itself
@@ -123,33 +142,37 @@ class IdziennikWebGrades(override val data: DataIdziennik,
}
1 -> {
gradeObject.type = Grade.TYPE_SEMESTER1_FINAL
- gradeObject.name = name
+ gradeObject.name = value.toInt().toString()
gradeObject.weight = 0f
}
2 -> {
gradeObject.type = Grade.TYPE_YEAR_FINAL
- gradeObject.name = name
+ gradeObject.name = value.toInt().toString()
gradeObject.weight = 0f
}
}
- val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
-
data.gradeList.add(gradeObject)
data.metadataList.add(
Metadata(
profileId,
Metadata.TYPE_GRADE,
id,
- data.profile?.empty ?: false,
- data.profile?.empty ?: false,
- addedDate
+ data.profile.empty,
+ data.profile.empty
))
}
}
+ data.toRemove.addAll(listOf(
+ Grade.TYPE_NORMAL,
+ Grade.TYPE_SEMESTER1_FINAL,
+ Grade.TYPE_YEAR_FINAL
+ ).map {
+ DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
+ })
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
- onSuccess()
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_GRADES)
}
- }
+ } ?: onSuccess(ENDPOINT_IDZIENNIK_WEB_GRADES) }
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebHomework.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebHomework.kt
new file mode 100644
index 00000000..10b4a0c3
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebHomework.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-11-25
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_HOMEWORK
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_HOMEWORK
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Event
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.utils.models.Date
+
+class IdziennikWebHomework(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikWebHomework"
+ }
+
+ init {
+ val param = JsonObject().apply {
+ addProperty("strona", 1)
+ addProperty("iloscNaStrone", 997)
+ addProperty("iloscRekordow", -1)
+ addProperty("kolumnaSort", "DataZadania")
+ addProperty("kierunekSort", 0)
+ addProperty("maxIloscZaznaczonych", 0)
+ addProperty("panelFiltrow", 0)
+ }
+
+ webApiGet(TAG, IDZIENNIK_WEB_HOMEWORK, mapOf(
+ "idP" to data.registerId,
+ "data" to Date.getToday().stringY_m_d,
+ "wszystkie" to true,
+ "param" to param
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ json.getJsonArray("ListK")?.asJsonObjectList()?.forEach { homework ->
+ val id = homework.getLong("_recordId") ?: return@forEach
+ val eventDate = Date.fromY_m_d(homework.getString("dataO") ?: return@forEach)
+ val addedDate = Date.fromY_m_d(homework.getString("dataZ") ?: return@forEach)
+ val subjectName = homework.getString("przed") ?: return@forEach
+ val subjectId = data.getSubject(subjectName, null, subjectName).id
+ val teacherName = homework.getString("usr") ?: return@forEach
+ val teacherId = data.getTeacherByLastFirst(teacherName).id
+ val lessonList = data.db.timetableDao().getAllForDateNow(profileId, eventDate)
+ val startTime = lessonList.firstOrNull { it.subjectId == subjectId }?.displayStartTime
+ val topic = homework.getString("tytul")?.trim() ?: ""
+
+ val seen = when (profile?.empty) {
+ true -> true
+ else -> eventDate < Date.getToday()
+ }
+
+
+ val eventObject = Event(
+ profileId = profileId,
+ id = id,
+ date = eventDate,
+ time = startTime,
+ topic = topic,
+ color = null,
+ type = Event.TYPE_HOMEWORK,
+ teacherId = teacherId,
+ subjectId = subjectId,
+ teamId = data.teamClass?.id ?: -1,
+ addedDate = addedDate.inMillis
+ )
+
+ data.eventList.add(eventObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_HOMEWORK,
+ eventObject.id,
+ seen,
+ seen
+ ))
+ }
+
+ data.toRemove.add(DataRemoveModel.Events.futureWithType(Event.TYPE_HOMEWORK))
+
+ data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_HOMEWORK, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_HOMEWORK)
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebNotices.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebNotices.kt
similarity index 51%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebNotices.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebNotices.kt
index 7cdaf3af..64108bfd 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebNotices.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebNotices.kt
@@ -2,24 +2,29 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
-import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
-import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_NOTICES
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES
-import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
-import pl.szczodrzynski.edziennik.api.v2.models.ApiError
import pl.szczodrzynski.edziennik.crc16
-import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
-import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
-import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
-import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_NOTICES
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.Notice
+import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEGATIVE
+import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_NEUTRAL
+import pl.szczodrzynski.edziennik.data.db.entity.Notice.Companion.TYPE_POSITIVE
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
import pl.szczodrzynski.edziennik.getJsonObject
+import pl.szczodrzynski.edziennik.getString
import pl.szczodrzynski.edziennik.utils.models.Date
class IdziennikWebNotices(override val data: DataIdziennik,
- val onSuccess: () -> Unit) : IdziennikWeb(data) {
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
companion object {
private const val TAG = "IdziennikWebNotices"
}
@@ -51,25 +56,29 @@ class IdziennikWebNotices(override val data: DataIdziennik,
}
val noticeObject = Notice(
- profileId,
- noticeId,
- jNotice.get("Tresc").asString,
- jNotice.get("Semestr").asInt,
- nType,
- rTeacher.id)
+ profileId = profileId,
+ id = noticeId,
+ type = nType,
+ semester = jNotice.get("Semestr").asInt,
+ text = jNotice.getString("Tresc") ?: "",
+ category = null,
+ points = null,
+ teacherId = rTeacher.id,
+ addedDate = addedDate.inMillis
+ )
+
data.noticeList.add(noticeObject)
data.metadataList.add(Metadata(
profileId,
Metadata.TYPE_NOTICE,
noticeObject.id,
profile?.empty ?: false,
- profile?.empty ?: false,
- addedDate.inMillis
+ profile?.empty ?: false
))
}
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_NOTICES, SYNC_ALWAYS)
- onSuccess()
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_NOTICES)
}
}
}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt
new file mode 100644
index 00000000..b23e9f98
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebProposedGrades.kt
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-28.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import pl.szczodrzynski.edziennik.asJsonObjectList
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_MISSING_GRADES
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Grade
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_DESCRIPTIVE
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_SEMESTER1_PROPOSED
+import pl.szczodrzynski.edziennik.data.db.entity.Grade.Companion.TYPE_YEAR_PROPOSED
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.getJsonArray
+import pl.szczodrzynski.edziennik.getJsonObject
+import pl.szczodrzynski.edziennik.getString
+
+class IdziennikWebProposedGrades(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikWebProposedGrades"
+ }
+
+ init { data.profile?.also { profile ->
+ webApiGet(TAG, IDZIENNIK_WEB_MISSING_GRADES, mapOf(
+ "idPozDziennika" to data.registerId
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+ val manager = data.app.gradesManager
+
+ json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { subject ->
+ val subjectName = subject.getString("Przedmiot") ?: return@forEach
+ val subjectObject = data.getSubject(subjectName, null, subjectName)
+
+ val semester1Proposed = subject.getString("OcenaSem1") ?: ""
+ val semester1Value = manager.getGradeValue(semester1Proposed)
+ val semester1Id = subjectObject.id * (-100) - 1
+ val semester1Type =
+ if (semester1Value == 0f) TYPE_DESCRIPTIVE
+ else TYPE_SEMESTER1_PROPOSED
+ val semester1Name = when {
+ semester1Value == 0f -> " "
+ semester1Value % 1.0f == 0f -> semester1Value.toInt().toString()
+ else -> semester1Value.toString()
+ }
+ val semester1Color =
+ if (semester1Value == 0f) 0xff536dfe.toInt()
+ else -1
+
+ val semester2Proposed = subject.getString("OcenaSem2") ?: ""
+ val semester2Value = manager.getGradeValue(semester2Proposed)
+ val semester2Id = subjectObject.id * (-100) - 2
+ val semester2Type =
+ if (semester2Value == 0f) TYPE_DESCRIPTIVE
+ else TYPE_YEAR_PROPOSED
+ val semester2Name = when {
+ semester2Value == 0f -> " "
+ semester2Value % 1.0f == 0f -> semester2Value.toInt().toString()
+ else -> semester2Value.toString()
+ }
+ val semester2Color =
+ if (semester2Value == 0f) 0xffff4081.toInt()
+ else -1
+
+ if (semester1Proposed != "") {
+ val addedDate = if (data.profile.empty)
+ data.profile.dateSemester1Start.inMillis
+ else
+ System.currentTimeMillis()
+
+ val gradeObject = Grade(
+ profileId = profileId,
+ id = semester1Id,
+ name = semester1Name,
+ type = semester1Type,
+ value = semester1Value,
+ weight = 0f,
+ color = semester1Color,
+ category = if (semester1Value == 0f) "Ocena opisowa semestralna" else null,
+ description = if (semester1Value == 0f) semester1Proposed else null,
+ comment = null,
+ semester = 1,
+ teacherId = -1,
+ subjectId = subjectObject.id,
+ addedDate = addedDate
+ )
+
+ data.gradeList.add(gradeObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_GRADE,
+ gradeObject.id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+
+ if (semester2Proposed != "") {
+ val addedDate = if (data.profile.empty)
+ data.profile.dateSemester2Start.inMillis
+ else
+ System.currentTimeMillis()
+
+ val gradeObject = Grade(
+ profileId = profileId,
+ id = semester2Id,
+ name = semester2Name,
+ type = semester2Type,
+ value = semester2Value,
+ weight = 0f,
+ color = semester2Color,
+ category = if (semester2Value == 0f) "Ocena opisowa końcoworoczna" else null,
+ description = if (semester2Value == 0f) semester2Proposed else null,
+ comment = null,
+ semester = 2,
+ teacherId = -1,
+ subjectId = subjectObject.id,
+ addedDate = addedDate
+ )
+
+ data.gradeList.add(gradeObject)
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_GRADE,
+ gradeObject.id,
+ profile.empty,
+ profile.empty
+ ))
+ }
+ }
+
+ data.toRemove.addAll(listOf(TYPE_SEMESTER1_PROPOSED, TYPE_YEAR_PROPOSED).map {
+ DataRemoveModel.Grades.semesterWithType(profile.currentSemester, it)
+ })
+ data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES)
+ }
+ } ?: onSuccess(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES) }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSendMessage.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSendMessage.kt
new file mode 100644
index 00000000..343ebcac
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSendMessage.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-12-30.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_SEND_MESSAGE
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.api.IdziennikApiMessagesSent
+import pl.szczodrzynski.edziennik.data.api.events.MessageSentEvent
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Message
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
+import java.util.*
+
+class IdziennikWebSendMessage(override val data: DataIdziennik,
+ val recipients: List,
+ val subject: String,
+ val text: String,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ private const val TAG = "IdziennikWebSendMessage"
+ }
+
+ init {
+ val recipientsArray = JsonArray()
+ for (teacher in recipients) {
+ teacher.loginId?.let {
+ recipientsArray += it
+ }
+ }
+
+ webApiGet(TAG, IDZIENNIK_WEB_SEND_MESSAGE, mapOf(
+ "Wiadomosc" to JsonObject(
+ "Tytul" to subject,
+ "Tresc" to text,
+ "Confirmation" to false,
+ "GuidMessage" to UUID.randomUUID().toString().toUpperCase(Locale.ROOT),
+ "Odbiorcy" to recipientsArray
+ )
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ if (json.getBoolean("CzyJestBlad") != false) {
+ // TODO error
+ return@webApiGet
+ }
+
+ IdziennikApiMessagesSent(data, null) {
+ val message = data.messageList.firstOrNull { it.type == Message.TYPE_SENT && it.subject == subject }
+ val metadata = data.metadataList.firstOrNull { it.thingType == Metadata.TYPE_MESSAGE && it.thingId == message?.id }
+ val event = MessageSentEvent(data.profileId, message, message?.addedDate)
+
+ EventBus.getDefault().postSticky(event)
+ onSuccess()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt
new file mode 100644
index 00000000..f225f177
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebSwitchRegister.kt
@@ -0,0 +1,36 @@
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import com.google.gson.JsonObject
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_HOME
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.getString
+
+class IdziennikWebSwitchRegister(override val data: DataIdziennik,
+ val registerId: Int,
+ val onSuccess: () -> Unit
+) : IdziennikWeb(data, null) {
+ companion object {
+ private const val TAG = "IdziennikWebSwitchRegister"
+ }
+
+ init {
+ val hiddenFields = data.loginStore.getLoginData("hiddenFields", JsonObject())
+ // TODO error checking
+
+ webGet(TAG, IDZIENNIK_WEB_HOME, mapOf(
+ "__VIEWSTATE" to hiddenFields.getString("__VIEWSTATE", ""),
+ "__VIEWSTATEGENERATOR" to hiddenFields.getString("__VIEWSTATEGENERATOR", ""),
+ "__EVENTVALIDATION" to hiddenFields.getString("__EVENTVALIDATION", ""),
+ "ctl00\$dxComboUczniowie" to registerId
+ )) { text ->
+ Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let {
+ val registerId = it[1].toIntOrNull() ?: return@let
+ data.webSelectedRegister = registerId
+ }
+ onSuccess()
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebTimetable.kt
new file mode 100644
index 00000000..e7d293c4
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/data/web/IdziennikWebTimetable.kt
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) Kacper Ziubryniewicz 2019-11-22
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.web
+
+import androidx.core.util.set
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_TIMETABLE
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.api.models.DataRemoveModel
+import pl.szczodrzynski.edziennik.data.db.entity.Lesson
+import pl.szczodrzynski.edziennik.data.db.entity.LessonRange
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
+import pl.szczodrzynski.edziennik.data.db.entity.SYNC_ALWAYS
+import pl.szczodrzynski.edziennik.utils.Utils.d
+import pl.szczodrzynski.edziennik.utils.models.Date
+import pl.szczodrzynski.edziennik.utils.models.Time
+import pl.szczodrzynski.edziennik.utils.models.Week
+
+class IdziennikWebTimetable(override val data: DataIdziennik,
+ override val lastSync: Long?,
+ val onSuccess: (endpointId: Int) -> Unit
+) : IdziennikWeb(data, lastSync) {
+ companion object {
+ private const val TAG = "IdziennikWebTimetable"
+ }
+
+ init { data.profile?.also { profile ->
+ val currentWeekStart = Week.getWeekStart()
+
+ if (Date.getToday().weekDay > 4) {
+ currentWeekStart.stepForward(0, 0, 7)
+ }
+
+ val getDate = data.arguments?.getString("weekStart") ?: currentWeekStart.stringY_m_d
+
+ val weekStart = Date.fromY_m_d(getDate)
+ val weekEnd = weekStart.clone().stepForward(0, 0, 6)
+
+ webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
+ "idPozDziennika" to data.registerId,
+ "pidRokSzkolny" to data.schoolYearId,
+ "data" to "${weekStart.stringY_m_d}T10:00:00.000Z"
+ )) { result ->
+ val json = result.getJsonObject("d") ?: run {
+ data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
+ .withApiResponse(result))
+ return@webApiGet
+ }
+
+ json.getJsonArray("GodzinyLekcyjne")?.asJsonObjectList()?.forEachIndexed { index, range ->
+ val lessonRange = LessonRange(
+ profileId,
+ index + 1,
+ range.getString("Poczatek")?.let { Time.fromH_m(it) }
+ ?: return@forEachIndexed,
+ range.getString("Koniec")?.let { Time.fromH_m(it) } ?: return@forEachIndexed
+ )
+ data.lessonRanges[lessonRange.lessonNumber] = lessonRange
+ }
+
+ val dates = mutableSetOf()
+ val lessons = mutableListOf()
+
+ json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
+ val subject = data.getSubject(
+ lesson.getString("Nazwa") ?: return@forEach,
+ lesson.getLong("Id"),
+ lesson.getString("Skrot") ?: ""
+ )
+ val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel")
+ ?: return@forEach)
+
+ val newSubjectName = lesson.getString("PrzedmiotZastepujacy")
+ val newSubject = when (newSubjectName.isNullOrBlank()) {
+ true -> null
+ else -> data.getSubject(newSubjectName, null, newSubjectName)
+ }
+
+ val newTeacherName = lesson.getString("NauZastepujacy")
+ val newTeacher = when (newTeacherName.isNullOrBlank()) {
+ true -> null
+ else -> data.getTeacherByFDotLast(newTeacherName)
+ }
+
+ val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
+ val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1)
+ ?: return@forEach]
+ val lessonDate = weekStart.clone().stepForward(0, 0, weekDay)
+ val classroom = lesson.getString("NazwaSali")
+
+ val type = lesson.getInt("TypZastepstwa") ?: -1
+
+ val lessonObject = Lesson(profileId, -1)
+
+ when (type) {
+ 1, 2, 3, 4, 5 -> {
+ lessonObject.apply {
+ this.type = Lesson.TYPE_CHANGE
+
+ this.date = lessonDate
+ this.lessonNumber = lessonRange.lessonNumber
+ this.startTime = lessonRange.startTime
+ this.endTime = lessonRange.endTime
+ this.subjectId = newSubject?.id
+ this.teacherId = newTeacher?.id
+ this.teamId = data.teamClass?.id
+ this.classroom = classroom
+
+ this.oldDate = lessonDate
+ this.oldLessonNumber = lessonRange.lessonNumber
+ this.oldStartTime = lessonRange.startTime
+ this.oldEndTime = lessonRange.endTime
+ this.oldSubjectId = subject.id
+ this.oldTeacherId = teacher.id
+ this.oldTeamId = data.teamClass?.id
+ this.oldClassroom = classroom
+ }
+ }
+ 0 -> {
+ lessonObject.apply {
+ this.type = Lesson.TYPE_CANCELLED
+
+ this.oldDate = lessonDate
+ this.oldLessonNumber = lessonRange.lessonNumber
+ this.oldStartTime = lessonRange.startTime
+ this.oldEndTime = lessonRange.endTime
+ this.oldSubjectId = subject.id
+ this.oldTeacherId = teacher.id
+ this.oldTeamId = data.teamClass?.id
+ this.oldClassroom = classroom
+ }
+ }
+ else -> {
+ lessonObject.apply {
+ this.type = Lesson.TYPE_NORMAL
+
+ this.date = lessonDate
+ this.lessonNumber = lessonRange.lessonNumber
+ this.startTime = lessonRange.startTime
+ this.endTime = lessonRange.endTime
+ this.subjectId = subject.id
+ this.teacherId = teacher.id
+ this.teamId = data.teamClass?.id
+ this.classroom = classroom
+ }
+ }
+ }
+
+ lessonObject.id = lessonObject.buildId()
+
+ dates.add(lessonDate.value)
+ lessons.add(lessonObject)
+
+ val seen = profile.empty || lessonDate < Date.getToday()
+
+ if (lessonObject.type != Lesson.TYPE_NORMAL && lessonDate >= Date.getToday()) {
+ data.metadataList.add(Metadata(
+ profileId,
+ Metadata.TYPE_LESSON_CHANGE,
+ lessonObject.id,
+ seen,
+ seen
+ ))
+ }
+ }
+
+ val date: Date = weekStart.clone()
+ while (date <= weekEnd) {
+ if (!dates.contains(date.value)) {
+ lessons.add(Lesson(profileId, date.value.toLong()).apply {
+ this.type = Lesson.TYPE_NO_LESSONS
+ this.date = date.clone()
+ })
+ }
+
+ date.stepForward(0, 0, 1)
+ }
+
+ d(TAG, "Clearing lessons between ${weekStart.stringY_m_d} and ${weekEnd.stringY_m_d} - timetable downloaded for $getDate")
+
+ data.lessonList.addAll(lessons)
+ data.toRemove.add(DataRemoveModel.Timetable.between(weekStart, weekEnd))
+
+ data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
+ onSuccess(ENDPOINT_IDZIENNIK_WEB_TIMETABLE)
+ }
+ }}
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/firstlogin/IdziennikFirstLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/firstlogin/IdziennikFirstLogin.kt
new file mode 100644
index 00000000..1a07c609
--- /dev/null
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/firstlogin/IdziennikFirstLogin.kt
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) Kuba Szczodrzyński 2019-10-27.
+ */
+
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.firstlogin
+
+import org.greenrobot.eventbus.EventBus
+import pl.szczodrzynski.edziennik.data.api.ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR
+import pl.szczodrzynski.edziennik.data.api.IDZIENNIK_WEB_SETTINGS
+import pl.szczodrzynski.edziennik.data.api.LOGIN_TYPE_IDZIENNIK
+import pl.szczodrzynski.edziennik.data.api.Regexes
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.data.IdziennikWeb
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login.IdziennikLoginWeb
+import pl.szczodrzynski.edziennik.data.api.events.FirstLoginFinishedEvent
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.fixName
+import pl.szczodrzynski.edziennik.get
+import pl.szczodrzynski.edziennik.set
+import pl.szczodrzynski.edziennik.swapFirstLastName
+
+class IdziennikFirstLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
+ companion object {
+ private const val TAG = "IdziennikFirstLogin"
+ }
+
+ private val web = IdziennikWeb(data, null)
+ private val profileList = mutableListOf()
+
+ init {
+ val loginStoreId = data.loginStore.id
+ val loginStoreType = LOGIN_TYPE_IDZIENNIK
+ var firstProfileId = loginStoreId
+
+ IdziennikLoginWeb(data) {
+ web.webGet(TAG, IDZIENNIK_WEB_SETTINGS) { text ->
+ //val accounts = json.getJsonArray("accounts")
+
+ val isParent = Regexes.IDZIENNIK_LOGIN_FIRST_IS_PARENT.find(text)?.get(1) != "0"
+ val accountNameLong = if (isParent)
+ Regexes.IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME.find(text)?.get(1)?.swapFirstLastName()?.fixName()
+ else null
+
+ var schoolYearStart: Int? = null
+ var schoolYearEnd: Int? = null
+ var schoolYearName: String? = null
+ val schoolYearId = Regexes.IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR.find(text)?.let {
+ schoolYearName = it[2]+"/"+it[3]
+ schoolYearStart = it[2].toIntOrNull()
+ schoolYearEnd = it[3].toIntOrNull()
+ it[1].toIntOrNull()
+ } ?: run {
+ data.error(ApiError(TAG, ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR)
+ .withApiResponse(text))
+ return@webGet
+ }
+
+ Regexes.IDZIENNIK_LOGIN_FIRST_STUDENT.findAll(text)
+ .toMutableList()
+ .reversed()
+ .forEach { match ->
+ val registerId = match[1].toIntOrNull() ?: return@forEach
+ val studentId = match[2]
+ val firstName = match[3]
+ val lastName = match[4]
+ val className = match[5] + " " + match[6]
+
+ val studentNameLong = "$firstName $lastName".fixName()
+ val studentNameShort = "$firstName ${lastName[0]}.".fixName()
+ val accountName = if (accountNameLong == studentNameLong) null else accountNameLong
+
+ val profile = Profile(
+ firstProfileId++,
+ loginStoreId,
+ loginStoreType,
+ studentNameLong,
+ data.webUsername,
+ studentNameLong,
+ studentNameShort,
+ accountName
+ ).apply {
+ schoolYearStart?.let { studentSchoolYearStart = it }
+ studentClassName = className
+ studentData["studentId"] = studentId
+ studentData["registerId"] = registerId
+ studentData["schoolYearId"] = schoolYearId
+ }
+ profileList.add(profile)
+ }
+
+ EventBus.getDefault().postSticky(FirstLoginFinishedEvent(profileList, data.loginStore))
+ onSuccess()
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLogin.kt
similarity index 85%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLogin.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLogin.kt
index ff6adb6e..e1cef5c1 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLogin.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLogin.kt
@@ -2,12 +2,12 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.login
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
import pl.szczodrzynski.edziennik.R
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_API
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_WEB
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_API
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_IDZIENNIK_WEB
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
import pl.szczodrzynski.edziennik.utils.Utils
class IdziennikLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginApi.kt
similarity index 71%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginApi.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginApi.kt
index 4782b980..2afe481d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginApi.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginApi.kt
@@ -2,9 +2,9 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.login
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
class IdziennikLoginApi(val data: DataIdziennik, val onSuccess: () -> Unit) {
companion object {
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt
similarity index 61%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt
index 88729206..a2fd4d03 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/idziennik/login/IdziennikLoginWeb.kt
@@ -2,20 +2,19 @@
* Copyright (c) Kuba Szczodrzyński 2019-10-26.
*/
-package pl.szczodrzynski.edziennik.api.v2.idziennik.login
+package pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.login
import im.wangchao.mhttp.Request
import im.wangchao.mhttp.Response
import im.wangchao.mhttp.callback.TextCallbackHandler
-import okhttp3.Cookie
-import pl.szczodrzynski.edziennik.HOUR
-import pl.szczodrzynski.edziennik.MINUTE
-import pl.szczodrzynski.edziennik.api.v2.*
-import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
-import pl.szczodrzynski.edziennik.api.v2.models.ApiError
-import pl.szczodrzynski.edziennik.get
-import pl.szczodrzynski.edziennik.getUnixDate
+import pl.szczodrzynski.edziennik.*
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.idziennik.DataIdziennik
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.LuckyNumber
+import pl.szczodrzynski.edziennik.data.db.entity.Metadata
import pl.szczodrzynski.edziennik.utils.Utils
+import pl.szczodrzynski.edziennik.utils.models.Date
class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
companion object {
@@ -24,22 +23,12 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
init { run {
if (data.isWebLoginValid()) {
- data.app.cookieJar.saveFromResponse(null, listOf(
- Cookie.Builder()
- .name("ASP.NET_SessionId_iDziennik")
- .value(data.webSessionId!!)
- .domain("iuczniowie.progman.pl")
- .secure().httpOnly().build(),
- Cookie.Builder()
- .name(".ASPXAUTH")
- .value(data.webAuth!!)
- .domain("iuczniowie.progman.pl")
- .secure().httpOnly().build()
- ))
+ data.app.cookieJar.set("iuczniowie.progman.pl", "ASP.NET_SessionId_iDziennik", data.webSessionId)
+ data.app.cookieJar.set("iuczniowie.progman.pl", ".ASPXAUTH", data.webAuth)
onSuccess()
}
else {
- data.app.cookieJar.clearForDomain("iuczniowie.progman.pl")
+ data.app.cookieJar.clear("iuczniowie.progman.pl")
if (data.webSchoolName != null && data.webUsername != null && data.webPassword != null) {
loginWithCredentials()
}
@@ -62,13 +51,54 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
// login succeeded: there is a start page
if (text.contains("czyWyswietlicDostepMobilny")) {
- val cookies = data.app.cookieJar.getForDomain("iuczniowie.progman.pl")
+ val cookies = data.app.cookieJar.getAll("iuczniowie.progman.pl")
run {
- data.webSessionId = cookies.singleOrNull { it.name() == "ASP.NET_SessionId_iDziennik" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
- data.webAuth = cookies.singleOrNull { it.name() == ".ASPXAUTH" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
- data.apiBearer = cookies.singleOrNull { it.name() == "Bearer" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
+ data.webSessionId = cookies["ASP.NET_SessionId_iDziennik"] ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
+ data.webAuth = cookies[".ASPXAUTH"] ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
+ data.apiBearer = cookies["Bearer"]?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
data.loginExpiryTime = response.getUnixDate() + 30 * MINUTE /* after about 40 minutes the login didn't work already */
data.apiExpiryTime = response.getUnixDate() + 12 * HOUR /* actually it expires after 24 hours but I'm not sure when does the token refresh. */
+
+ val hiddenFields = JsonObject()
+ Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text).forEach {
+ hiddenFields[it[1]] = it[2]
+ }
+ data.loginStore.putLoginData("hiddenFields", hiddenFields)
+
+ Regexes.IDZIENNIK_WEB_SELECTED_REGISTER.find(text)?.let {
+ val registerId = it[1].toIntOrNull() ?: return@let
+ data.webSelectedRegister = registerId
+ }
+
+ // for profiles created after archiving
+ data.schoolYearId = Regexes.IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR.find(text)?.let {
+ it[1].toIntOrNull()
+ } ?: data.schoolYearId
+ data.profile?.studentClassName = Regexes.IDZIENNIK_LOGIN_FIRST_STUDENT.findAll(text)
+ .firstOrNull { it[1].toIntOrNull() == data.registerId }
+ ?.let { "${it[5]} ${it[6]}" } ?: data.profile?.studentClassName
+
+ data.profile?.let { profile ->
+ Regexes.IDZIENNIK_WEB_LUCKY_NUMBER.find(text)?.also {
+ val number = it[1].toIntOrNull() ?: return@also
+ val luckyNumberObject = LuckyNumber(
+ profileId = data.profileId,
+ date = Date.getToday(),
+ number = number
+ )
+
+ data.luckyNumberList.add(luckyNumberObject)
+ data.metadataList.add(
+ Metadata(
+ profile.id,
+ Metadata.TYPE_LUCKY_NUMBER,
+ luckyNumberObject.date.value.toLong(),
+ true,
+ profile.empty
+ ))
+ }
+ }
+
return@run null
}?.let { errorCode ->
data.error(ApiError(TAG, errorCode)
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/DataLibrus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt
similarity index 83%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/DataLibrus.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt
index a18b4511..e77dd50d 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/DataLibrus.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/DataLibrus.kt
@@ -2,18 +2,17 @@
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
*/
-package pl.szczodrzynski.edziennik.api.v2.librus
+package pl.szczodrzynski.edziennik.data.api.edziennik.librus
-import okhttp3.Cookie
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_API
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_MESSAGES
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_PORTAL
-import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_SYNERGIA
-import pl.szczodrzynski.edziennik.api.v2.models.Data
import pl.szczodrzynski.edziennik.currentTimeUnix
-import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
-import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_API
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_MESSAGES
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_PORTAL
+import pl.szczodrzynski.edziennik.data.api.LOGIN_METHOD_LIBRUS_SYNERGIA
+import pl.szczodrzynski.edziennik.data.api.models.Data
+import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
@@ -31,26 +30,16 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
loginMethods += LOGIN_METHOD_LIBRUS_API
if (isSynergiaLoginValid()) {
loginMethods += LOGIN_METHOD_LIBRUS_SYNERGIA
- app.cookieJar.saveFromResponse(null, listOf(
- Cookie.Builder()
- .name("DZIENNIKSID")
- .value(synergiaSessionId!!)
- .domain("synergia.librus.pl")
- .secure().httpOnly().build()
- ))
+ app.cookieJar.set("synergia.librus.pl", "DZIENNIKSID", synergiaSessionId)
}
if (isMessagesLoginValid()) {
loginMethods += LOGIN_METHOD_LIBRUS_MESSAGES
- app.cookieJar.saveFromResponse(null, listOf(
- Cookie.Builder()
- .name("DZIENNIKSID")
- .value(messagesSessionId!!)
- .domain("wiadomosci.librus.pl")
- .secure().httpOnly().build()
- ))
+ app.cookieJar.set("wiadomosci.librus.pl", "DZIENNIKSID", messagesSessionId)
}
}
+ override fun generateUserCode() = "$schoolName:$apiLogin"
+
fun getColor(id: Int?): Int {
return when (id) {
1 -> 0xFFF0E68C
@@ -131,7 +120,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiLogin: String? = null
var apiLogin: String?
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.
* Used: for login (API Login Method) in Synergia mode.
@@ -140,7 +129,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiPassword: String? = null
var apiPassword: String?
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.
@@ -148,16 +137,16 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
*/
private var mApiCode: String? = null
var apiCode: String?
- get() { mApiCode = mApiCode ?: profile?.getStudentData("accountCode", null); return mApiCode }
- set(value) { profile?.putStudentData("accountCode", value) ?: return; mApiCode = value }
+ get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
+ set(value) { profile?.putStudentData("accountCode", value); mApiCode = value }
/**
* A JST login PIN.
* Used only during first login in JST mode.
*/
private var mApiPin: String? = null
var apiPin: String?
- get() { mApiPin = mApiPin ?: profile?.getStudentData("accountPin", null); return mApiPin }
- set(value) { profile?.putStudentData("accountPin", value) ?: return; mApiPin = value }
+ get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
+ set(value) { profile?.putStudentData("accountPin", value); mApiPin = value }
/**
* A Synergia API access token.
@@ -168,7 +157,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiAccessToken: String? = null
var apiAccessToken: String?
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
- set(value) { profile?.putStudentData("accountToken", value) ?: return; mApiAccessToken = value }
+ set(value) { mApiAccessToken = value; profile?.putStudentData("accountToken", value) ?: return; }
/**
* A Synergia API refresh token.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@@ -176,7 +165,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiRefreshToken: String? = null
var apiRefreshToken: String?
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
- set(value) { profile?.putStudentData("accountRefreshToken", value) ?: return; mApiRefreshToken = value }
+ set(value) { mApiRefreshToken = value; profile?.putStudentData("accountRefreshToken", value) ?: return; }
/**
* The expiry time for [apiAccessToken], as a UNIX timestamp.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@@ -185,7 +174,17 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiTokenExpiryTime: Long? = null
var apiTokenExpiryTime: Long
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
- set(value) { profile?.putStudentData("accountTokenTime", value) ?: return; mApiTokenExpiryTime = value }
+ set(value) { mApiTokenExpiryTime = value; profile?.putStudentData("accountTokenTime", value) ?: return; }
+
+ /**
+ * A push device ID, generated by Librus when registering
+ * a FCM token. I don't really know if this has any use,
+ * but it may be worthy to save that ID.
+ */
+ private var mPushDeviceId: Int? = null
+ var pushDeviceId: Int
+ get() { mPushDeviceId = mPushDeviceId ?: profile?.getStudentData("pushDeviceId", 0); return mPushDeviceId ?: 0 }
+ set(value) { mPushDeviceId = value; profile?.putStudentData("pushDeviceId", value) ?: return; }
/* _____ _
/ ____| (_)
@@ -256,6 +255,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
var startPointsSemester1: Int
get() { mStartPointsSemester1 = mStartPointsSemester1 ?: profile?.getStudentData("startPointsSemester1", 0); return mStartPointsSemester1 ?: 0 }
set(value) { profile?.putStudentData("startPointsSemester1", value) ?: return; mStartPointsSemester1 = value }
+
private var mStartPointsSemester2: Int? = null
var startPointsSemester2: Int
get() { mStartPointsSemester2 = mStartPointsSemester2 ?: profile?.getStudentData("startPointsSemester2", 0); return mStartPointsSemester2 ?: 0 }
@@ -265,8 +265,20 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
var enablePointGrades: Boolean
get() { mEnablePointGrades = mEnablePointGrades ?: profile?.getStudentData("enablePointGrades", true); return mEnablePointGrades ?: true }
set(value) { profile?.putStudentData("enablePointGrades", value) ?: return; mEnablePointGrades = value }
+
private var mEnableDescriptiveGrades: Boolean? = null
var enableDescriptiveGrades: Boolean
get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true }
set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value }
-}
\ No newline at end of file
+
+ private var mTimetableNotPublic: Boolean? = null
+ var timetableNotPublic: Boolean
+ get() { mTimetableNotPublic = mTimetableNotPublic ?: profile?.getStudentData("timetableNotPublic", false); return mTimetableNotPublic ?: false }
+ set(value) { profile?.putStudentData("timetableNotPublic", value) ?: return; mTimetableNotPublic = value }
+
+ /**
+ * 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
+}
diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt
similarity index 51%
rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt
rename to app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt
index 626a4a33..abf3ac5f 100644
--- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt
+++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/api/edziennik/librus/Librus.kt
@@ -2,25 +2,30 @@
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
*/
-package pl.szczodrzynski.edziennik.api.v2.librus
+package pl.szczodrzynski.edziennik.data.api.edziennik.librus
import com.google.gson.JsonObject
import pl.szczodrzynski.edziennik.App
-import pl.szczodrzynski.edziennik.api.v2.*
-import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
-import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
-import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData
-import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetMessage
-import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
-import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
-import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLogin
-import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
-import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginMessages
-import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia
-import pl.szczodrzynski.edziennik.api.v2.models.ApiError
-import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
-import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageFull
-import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
+import pl.szczodrzynski.edziennik.data.api.*
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.LibrusData
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.api.LibrusApiAnnouncementMarkAsRead
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetAttachment
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetMessage
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesGetRecipientList
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.messages.LibrusMessagesSendMessage
+import pl.szczodrzynski.edziennik.data.api.edziennik.librus.data.synergia.*
+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.interfaces.EdziennikCallback
+import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface
+import pl.szczodrzynski.edziennik.data.api.models.ApiError
+import pl.szczodrzynski.edziennik.data.db.entity.LoginStore
+import pl.szczodrzynski.edziennik.data.db.entity.Message
+import pl.szczodrzynski.edziennik.data.db.entity.Profile
+import pl.szczodrzynski.edziennik.data.db.entity.Teacher
+import pl.szczodrzynski.edziennik.data.db.full.AnnouncementFull
+import pl.szczodrzynski.edziennik.data.db.full.EventFull
+import pl.szczodrzynski.edziennik.data.db.full.MessageFull
import pl.szczodrzynski.edziennik.utils.Utils.d
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
@@ -30,6 +35,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
val internalErrorList = mutableListOf()
val data: DataLibrus
+ private var afterLogin: (() -> Unit)? = null
init {
data = DataLibrus(app, profile, loginStore).apply {
@@ -40,9 +46,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
private fun completed() {
data.saveData()
- data.notifyAndSyncEvents {
- callback.onCompleted()
- }
+ callback.onCompleted()
}
/* _______ _ _ _ _ _
@@ -53,18 +57,20 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
__/ |
|__*/
- override fun sync(featureIds: List, viewId: Int?, arguments: JsonObject?) {
+ override fun sync(featureIds: List, viewId: Int?, onlyEndpoints: List?, arguments: JsonObject?) {
data.arguments = arguments
- data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
+ data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId, onlyEndpoints)
login()
}
- private fun login() {
+ private fun login(loginMethodId: Int? = null, afterLogin: (() -> Unit)? = null) {
d(TAG, "Trying to login with ${data.targetLoginMethodIds}")
if (internalErrorList.isNotEmpty()) {
d(TAG, " - Internal errors:")
internalErrorList.forEach { d(TAG, " - code $it") }
}
+ loginMethodId?.let { data.prepareFor(librusLoginMethods, it) }
+ afterLogin?.let { this.afterLogin = it }
LibrusLogin(data) {
data()
}
@@ -76,39 +82,78 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va
d(TAG, " - Internal errors:")
internalErrorList.forEach { d(TAG, " - code $it") }
}
- LibrusData(data) {
+ afterLogin?.invoke() ?: LibrusData(data) {
completed()
}
}
override fun getMessage(message: MessageFull) {
- LibrusLoginApi(data) {
- LibrusLoginSynergia(data) {
- LibrusLoginMessages(data) {
- LibrusMessagesGetMessage(data, message) {
- completed()
- }
- }
+ login(LOGIN_METHOD_LIBRUS_MESSAGES) {
+ if (data.messagesLoginSuccessful) LibrusMessagesGetMessage(data, message) { completed() }
+ else LibrusSynergiaGetMessage(data, message) { completed() }
+ }
+ }
+
+ override fun sendMessage(recipients: List