diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt index cc4709ce..ae9db1e7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt @@ -145,6 +145,7 @@ const val ERROR_IDZIENNIK_WEB_MAINTENANCE = 432 const val ERROR_IDZIENNIK_WEB_SERVER_ERROR = 433 const val ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 434 const val ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR = 440 +const val ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA = 441 const val ERROR_TEMPLATE_WEB_OTHER = 801 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt index faa2f517..61629c3d 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/DataIdziennik.kt @@ -4,15 +4,16 @@ package pl.szczodrzynski.edziennik.api.v2.idziennik +import androidx.core.util.set import okhttp3.Cookie -import pl.szczodrzynski.edziennik.App +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.currentTimeUnix import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile -import pl.szczodrzynski.edziennik.isNotNullNorEmpty +import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject +import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) { @@ -106,4 +107,65 @@ class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data( var schoolYearId: Int get() { mSchoolYearId = mSchoolYearId ?: profile?.getStudentData("schoolYearId", 0); return mSchoolYearId ?: 0 } set(value) { profile?.putStudentData("schoolYearId", value) ?: return; mSchoolYearId = value } + + + + /* _ _ _ _ _ + | | | | | (_) | + | | | | |_ _| |___ + | | | | __| | / __| + | |__| | |_| | \__ \ + \____/ \__|_|_|__*/ + fun getSubject(name: String, id: Long?, shortName: String): Subject { + var subject = if (id == null) + subjectList.singleOrNull { it.longName == name } + else + subjectList.singleOrNull { it.id == id } + + if (subject == null) { + subject = Subject(profileId, id ?: name.crc16().toLong(), name, shortName) + subjectList[subject.id] = subject + } + return subject + } + + fun getTeacher(firstName: String, lastName: String): Teacher { + val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" } + return validateTeacher(teacher, firstName, lastName) + } + fun getTeacher(firstNameChar: Char, lastName: String): Teacher { + val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" } + return validateTeacher(teacher, firstNameChar.toString(), lastName) + } + fun getTeacherByLastFirst(nameLastFirst: String): Teacher { + val nameParts = nameLastFirst.split(" ") + return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0]) + } + + fun getTeacherByFirstLast(nameFirstLast: String): Teacher { + val nameParts = nameFirstLast.split(" ") + return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0], nameParts[1]) + } + + fun getTeacherByFDotLast(nameFDotLast: String): Teacher { + val nameParts = nameFDotLast.split(".") + return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0][0], nameParts[1]) + } + + fun getTeacherByFDotSpaceLast(nameFDotSpaceLast: String): Teacher { + val nameParts = nameFDotSpaceLast.split(".") + return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0][0], nameParts[1]) + } + + private fun validateTeacher(teacher: Teacher?, firstName: String, lastName: String): Teacher { + (teacher ?: Teacher(profileId, -1, firstName, lastName).apply { + id = shortName.crc16().toLong() + teacherList[id] = this + }).apply { + if (firstName.length > 1) + name = firstName + surname = lastName + return this + } + } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt index c3a01ea1..eac360e4 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/IdziennikFeatures.kt @@ -7,18 +7,60 @@ package pl.szczodrzynski.edziennik.api.v2.idziennik import pl.szczodrzynski.edziennik.api.v2.* import pl.szczodrzynski.edziennik.api.v2.models.Feature -const val ENDPOINT_IDZIENNIK_WEB_SAMPLE = 9991 -const val ENDPOINT_IDZIENNIK_WEB_SAMPLE_2 = 9992 -const val ENDPOINT_IDZIENNIK_API_SAMPLE = 9993 +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_NOTICES = 1070 +const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080 +const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090 +const val ENDPOINT_IDZIENNIK_WEB_MESSAGES_INBOX = 1110 +const val ENDPOINT_IDZIENNIK_WEB_MESSAGES_SENT = 1120 +const val ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER = 2010 +const val ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX = 2110 +const val ENDPOINT_IDZIENNIK_API_MESSAGES_SENT = 2120 val IdziennikFeatures = listOf( - Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_STUDENT_INFO, listOf( - ENDPOINT_IDZIENNIK_WEB_SAMPLE to LOGIN_METHOD_IDZIENNIK_WEB - ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), - Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_SCHOOL_INFO, listOf( - ENDPOINT_IDZIENNIK_WEB_SAMPLE_2 to LOGIN_METHOD_IDZIENNIK_WEB + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_TIMETABLE, listOf( + ENDPOINT_IDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_IDZIENNIK_WEB ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_GRADES, listOf( - ENDPOINT_IDZIENNIK_API_SAMPLE to LOGIN_METHOD_IDZIENNIK_API + ENDPOINT_IDZIENNIK_WEB_GRADES to LOGIN_METHOD_IDZIENNIK_WEB, + ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_AGENDA, listOf( + ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf( + ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_ATTENDANCE, listOf( + ENDPOINT_IDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf( + ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_INBOX, listOf( + ENDPOINT_IDZIENNIK_WEB_MESSAGES_INBOX to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_SENT, listOf( + ENDPOINT_IDZIENNIK_WEB_MESSAGES_SENT to LOGIN_METHOD_IDZIENNIK_WEB + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_INBOX, listOf( + ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX to LOGIN_METHOD_IDZIENNIK_API + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_SENT, listOf( + ENDPOINT_IDZIENNIK_API_MESSAGES_SENT to LOGIN_METHOD_IDZIENNIK_API + ), listOf(LOGIN_METHOD_IDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( + ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER to LOGIN_METHOD_IDZIENNIK_API ), listOf(LOGIN_METHOD_IDZIENNIK_API)) ) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt index 4873a275..84d93d37 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/IdziennikData.kt @@ -4,7 +4,10 @@ package pl.szczodrzynski.edziennik.api.v2.idziennik.data +import pl.szczodrzynski.edziennik.R import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik +import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE +import pl.szczodrzynski.edziennik.api.v2.idziennik.data.web.IdziennikWebTimetable import pl.szczodrzynski.edziennik.utils.Utils class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) { @@ -35,10 +38,10 @@ class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) { private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) { Utils.d(TAG, "Using endpoint $endpointId") when (endpointId) { - /*ENDPOINT_IDZIENNIK_WEB_SAMPLE -> { - data.startProgress(R.string.edziennik_progress_endpoint_student_info) - IdziennikWebSample(data) { onSuccess() } - }*/ + ENDPOINT_IDZIENNIK_WEB_TIMETABLE -> { + data.startProgress(R.string.edziennik_progress_endpoint_timetable) + IdziennikWebTimetable(data) { onSuccess() } + } else -> onSuccess() } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebTimetable.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebTimetable.kt new file mode 100644 index 00000000..c9cf7f5f --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/data/web/IdziennikWebTimetable.kt @@ -0,0 +1,128 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-27. + */ + +package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web + +import androidx.core.util.set +import pl.szczodrzynski.edziennik.* +import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA +import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_TIMETABLE +import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik +import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE +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.lessons.Lesson +import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange +import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CANCELLED +import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CHANGE +import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange +import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata +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, + val onSuccess: () -> Unit) : IdziennikWeb(data) { + companion object { + private const val TAG = "IdziennikWebTimetable" + } + + init { + val weekStart = Week.getWeekStart() + if (Date.getToday().weekDay > 4) { + weekStart.stepForward(0, 0, 7) + } + + 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()?.forEach { range -> + val lessonRange = LessonRange( + profileId, + range.getInt("LiczbaP") ?: return@forEach, + range.getString("Poczatek")?.let { Time.fromH_m(it) } ?: return@forEach, + range.getString("Koniec")?.let { Time.fromH_m(it) } ?: return@forEach + ) + data.lessonRanges[lessonRange.lessonNumber] = lessonRange + } + + 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 weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach + val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach] + + val lessonObject = Lesson( + profileId, + weekDay, + lessonRange.startTime, + lessonRange.endTime + ).apply { + subjectId = subject.id + teacherId = teacher.id + teamId = data.teamClass?.id ?: -1 + classroomName = lesson.getString("NazwaSali") ?: "" + } + + data.lessonList.add(lessonObject) + + val type = lesson.getInt("TypZastepstwa") ?: -1 + if (type != -1) { + // we have a lesson change to process + val lessonChangeObject = LessonChange( + profileId, + weekStart.clone().stepForward(0, 0, weekDay), + lessonObject.startTime, + lessonObject.endTime + ) + + lessonChangeObject.teamId = lessonObject.teamId + lessonChangeObject.teacherId = lessonObject.teacherId + lessonChangeObject.subjectId = lessonObject.subjectId + lessonChangeObject.classroomName = lessonObject.classroomName + when (type) { + 0 -> lessonChangeObject.type = TYPE_CANCELLED + 1, 2, 3, 4, 5 -> { + lessonChangeObject.type = TYPE_CHANGE + val newTeacher = lesson.getString("NauZastepujacy") + val newSubject = lesson.getString("PrzedmiotZastepujacy") + if (newTeacher != null) { + lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id + } + if (newSubject != null) { + lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id + } + } + } + + data.lessonChangeList.add(lessonChangeObject) + data.metadataList.add(Metadata( + profileId, + Metadata.TYPE_LESSON_CHANGE, + lessonChangeObject.id, + profile?.empty ?: false, + profile?.empty ?: false, + System.currentTimeMillis() + )) + } + } + + data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS) + onSuccess() + } + } +} diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt index d03c254e..775200c6 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/idziennik/login/IdziennikLoginWeb.kt @@ -62,9 +62,9 @@ class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) { if (text.contains("czyWyswietlicDostepMobilny")) { val cookies = data.app.cookieJar.getForDomain("iuczniowie.progman.pl") run { - data.webSessionId = cookies.singleOrNull { it.name() == "ASP.NET_SessionId_iDziennik" }?.name() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION - data.webAuth = cookies.singleOrNull { it.name() == ".ASPXAUTH" }?.name() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH - data.apiBearer = cookies.singleOrNull { it.name() == "Bearer" }?.name() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER + 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.loginExpiryTime = response.getUnixDate() + 45 * 60 /* 45 min */ return@run null }?.let { errorCode -> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 05e64564..10533021 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -975,4 +975,5 @@ Według systemu Polski English + Pobieranie planu lekcji...