From ddf4fb0b461e6f669f9851eb57ca9b713901ca68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kuba=20Szczodrzy=C5=84ski?= Date: Sat, 5 Oct 2019 23:42:37 +0200 Subject: [PATCH] [APIv2] Add Mobidziennik login & API prototype. Refactor some classes --- .../edziennik/api/v2/ApiService.kt | 5 +- .../edziennik/api/v2/Constants.kt | 10 +- .../edziennik/api/v2/Endpoints.kt | 48 ++--- .../szczodrzynski/edziennik/api/v2/Errors.kt | 16 +- .../edziennik/api/v2/Features.kt | 31 ++-- .../edziennik/api/v2/LoginMethods.kt | 21 ++- .../v2/events/requests/SyncProfileRequest.kt | 4 +- .../api/v2/events/requests/SyncViewRequest.kt | 4 +- .../api/v2/interfaces/EdziennikCallback.kt | 4 +- .../api/v2/interfaces/EndpointCallback.kt | 4 +- .../edziennik/api/v2/librus/Librus.kt | 6 +- .../api/v2/librus/data/DataLibrus.kt | 3 +- .../edziennik/api/v2/librus/data/LibrusApi.kt | 2 +- .../api/v2/librus/login/LibrusLoginApi.kt | 2 +- .../v2/librus/login/LibrusLoginSynergia.kt | 2 +- .../api/v2/mobidziennik/Mobidziennik.kt | 173 ++++++++++++++++++ .../v2/mobidziennik/MobidziennikFeatures.kt | 107 +++++++++++ .../v2/mobidziennik/data/DataMobidziennik.kt | 69 +++++++ .../v2/mobidziennik/data/MobidziennikData.kt | 81 ++++++++ .../v2/mobidziennik/data/MobidziennikWeb.kt | 93 ++++++++++ .../mobidziennik/login/MobidziennikLogin.kt | 53 ++++++ .../login/MobidziennikLoginWeb.kt | 102 +++++++++++ .../edziennik/api/v2/models/Data.kt | 2 +- .../api/v2/models/{Endpoint.kt => Feature.kt} | 7 +- .../edziennik/api/v2/models/LoginMethod.kt | 2 +- .../edziennik/api/v2/template/Template.kt | 6 +- .../data/db/modules/login/LoginStore.java | 2 +- .../data/db/modules/profiles/ProfileFull.kt | 2 +- .../ui/modules/home/HomeFragment.java | 18 +- app/src/main/res/layout/fragment_home.xml | 4 +- app/src/main/res/values/strings.xml | 9 + .../internal/cookie/PersistentCookieJar.java | 21 +++ 32 files changed, 830 insertions(+), 83 deletions(-) create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/MobidziennikFeatures.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/DataMobidziennik.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikData.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikWeb.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLogin.kt create mode 100644 app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLoginWeb.kt rename app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/{Endpoint.kt => Feature.kt} (82%) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt index 231aa893..e90eed55 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/ApiService.kt @@ -18,6 +18,7 @@ import pl.szczodrzynski.edziennik.api.v2.events.requests.* import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.api.v2.librus.Librus +import pl.szczodrzynski.edziennik.api.v2.mobidziennik.Mobidziennik import pl.szczodrzynski.edziennik.api.v2.models.ApiError import pl.szczodrzynski.edziennik.api.v2.models.ApiTask import pl.szczodrzynski.edziennik.api.v2.template.Template @@ -151,6 +152,7 @@ class ApiService : Service() { edziennikInterface = when (loginStore.type) { LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback) + LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback) LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback) else -> null } @@ -159,8 +161,7 @@ class ApiService : Service() { } when (task) { - is SyncProfileRequest -> edziennikInterface?.sync(task.featureIds ?: Features.getAllIds()) - is SyncViewRequest -> edziennikInterface?.sync(Features.getIdsByView(task.targetId), task.targetId) + is SyncProfileRequest -> edziennikInterface?.sync(task.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } ?: Features.getAllIds()) is MessageGetRequest -> edziennikInterface?.getMessage(task.messageId) } } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt index fa133eda..b74e9b77 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Constants.kt @@ -7,7 +7,9 @@ package pl.szczodrzynski.edziennik.api.v2 const val GET = 0 const val POST = 1 -const val LIBRUS_USER_AGENT = "Dalvik/2.1.0 Android LibrusMobileApp" +val SYSTEM_USER_AGENT = System.getProperty("http.agent") ?: "Dalvik/2.1.0 Android" + +val LIBRUS_USER_AGENT = "$SYSTEM_USER_AGENT LibrusMobileApp" const val SYNERGIA_USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Gecko/20100101 Firefox/62.0" const val LIBRUS_CLIENT_ID = "wmSyUMo8llDAs4y9tJVYY92oyZ6h4lAt7KCuy0Gv" const val LIBRUS_REDIRECT_URL = "http://localhost/bar" @@ -36,4 +38,8 @@ const val LIBRUS_JST_DEMO_PIN = "1290" const val LIBRUS_SYNERGIA_TOKEN_LOGIN_URL = "https://synergia.librus.pl/loguj/token/TOKEN/przenies" const val LIBRUS_MESSAGES_URL = "https://wiadomosci.librus.pl/module/" -const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action=" \ No newline at end of file +const val LIBRUS_SANDBOX_URL = "https://sandbox.librus.pl/index.php?action=" + + + +val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Endpoints.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Endpoints.kt index f43db6bb..c04e1343 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Endpoints.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Endpoints.kt @@ -4,7 +4,7 @@ package pl.szczodrzynski.edziennik.api.v2 -import pl.szczodrzynski.edziennik.api.v2.models.Endpoint +import pl.szczodrzynski.edziennik.api.v2.models.Feature const val ENDPOINT_LIBRUS_API_ME = 1001 const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002 @@ -55,11 +55,11 @@ const val ENDPOINT_TEMPLATE_API_SAMPLE = 9993 val endpoints = listOf( // LIBRUS: API - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf( ENDPOINT_LIBRUS_API_TIMETABLES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_SUBSTITUTIONS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf( ENDPOINT_LIBRUS_API_EVENTS to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_EVENT_TYPES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_PT_MEETINGS to LOGIN_METHOD_LIBRUS_API, @@ -67,7 +67,7 @@ val endpoints = listOf( ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( ENDPOINT_LIBRUS_API_NORMAL_GC to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_POINT_GC to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC to LOGIN_METHOD_LIBRUS_API, @@ -81,49 +81,49 @@ val endpoints = listOf( ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf( ENDPOINT_LIBRUS_API_HOMEWORK to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_NOTICES, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_BEHAVIOUR, listOf( ENDPOINT_LIBRUS_API_NOTICES to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCES, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCE, listOf( ENDPOINT_LIBRUS_API_ATTENDANCE to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf( ENDPOINT_LIBRUS_API_ANNOUNCEMENTS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( ENDPOINT_LIBRUS_API_ME to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf( ENDPOINT_LIBRUS_API_SCHOOLS to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_UNITS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf( ENDPOINT_LIBRUS_API_CLASSES to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf( ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf( ENDPOINT_LIBRUS_API_LUCKY_NUMBER to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf( ENDPOINT_LIBRUS_API_USERS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf( ENDPOINT_LIBRUS_API_SUBJECTS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf( ENDPOINT_LIBRUS_API_CLASSROOMS to LOGIN_METHOD_LIBRUS_API ), listOf(LOGIN_METHOD_LIBRUS_API)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf( ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)), /*Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( @@ -131,28 +131,28 @@ val endpoints = listOf( ), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),*/ - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( ENDPOINT_LIBRUS_API_NORMAL_GC to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API, ENDPOINT_LIBRUS_SYNERGIA_GRADES to LOGIN_METHOD_LIBRUS_SYNERGIA ), listOf(LOGIN_METHOD_LIBRUS_API, LOGIN_METHOD_LIBRUS_SYNERGIA)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf( ENDPOINT_LIBRUS_MESSAGES_RECEIVED to LOGIN_METHOD_LIBRUS_MESSAGES ), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_OUTBOX, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_SENT, listOf( ENDPOINT_LIBRUS_MESSAGES_SENT to LOGIN_METHOD_LIBRUS_MESSAGES ), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)) ) val templateEndpoints = listOf( - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf( ENDPOINT_TEMPLATE_WEB_SAMPLE to LOGIN_METHOD_TEMPLATE_WEB ), listOf(LOGIN_METHOD_TEMPLATE_WEB)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf( ENDPOINT_TEMPLATE_WEB_SAMPLE_2 to LOGIN_METHOD_TEMPLATE_WEB ), listOf(LOGIN_METHOD_TEMPLATE_WEB)), - Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( + Feature(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf( ENDPOINT_TEMPLATE_API_SAMPLE to LOGIN_METHOD_TEMPLATE_API ), listOf(LOGIN_METHOD_TEMPLATE_API)) ) \ No newline at end of file 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 561f8906..7780cb92 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 @@ -54,7 +54,7 @@ const val ERROR_LOGIN_LIBRUS_API_INVALID_CLIENT = 126 const val ERROR_LOGIN_LIBRUS_API_REG_ACCEPT_NEEDED = 127 const val ERROR_LOGIN_LIBRUS_API_CHANGE_PASSWORD_ERROR = 128 const val ERROR_LOGIN_LIBRUS_API_PASSWORD_CHANGE_REQUIRED = 129 -const val ERROR_LOGIN_LIBRUS_API_INVALID_GRANT = 130 +const val ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN = 130 const val ERROR_LOGIN_LIBRUS_API_OTHER = 131 const val ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING = 132 const val ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED = 133 @@ -63,7 +63,7 @@ const val ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING = 139 const val ERROR_LIBRUS_API_TOKEN_EXPIRED = 140 const val ERROR_LIBRUS_API_INSUFFICIENT_SCOPES = 141 const val ERROR_LIBRUS_API_OTHER = 142 -const val ERROR_LIBRUS_API_REQUEST_DENIED = 143 +const val ERROR_LIBRUS_API_ACCESS_DENIED = 143 const val ERROR_LIBRUS_API_RESOURCE_NOT_FOUND = 144 const val ERROR_LIBRUS_API_DATA_NOT_FOUND = 145 const val ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC = 146 @@ -93,6 +93,18 @@ const val ERROR_LOGIN_LIBRUS_PORTAL_NO_REDIRECT = 169 const val ERROR_LOGIN_LIBRUS_PORTAL_UNSUPPORTED_GRANT = 170 const val ERROR_LOGIN_LIBRUS_PORTAL_INVALID_CLIENT_ID = 171 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN = 201 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD = 202 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_DEVICE = 203 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_ARCHIVED = 204 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_MAINTENANCE = 205 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS = 206 +const val ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER = 210 +const val ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED = 211 +const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY = 212 +const val ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE = 212 +const val ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID = 213 + const val ERROR_TEMPLATE_WEB_OTHER = 301 const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901 diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Features.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Features.kt index b9b5cd59..33bbe2f9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Features.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Features.kt @@ -15,19 +15,19 @@ import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT -import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment const val FEATURE_ALL = 0 const val FEATURE_TIMETABLE = 1 const val FEATURE_AGENDA = 2 const val FEATURE_GRADES = 3 const val FEATURE_HOMEWORK = 4 -const val FEATURE_NOTICES = 5 -const val FEATURE_ATTENDANCES = 6 +const val FEATURE_BEHAVIOUR = 5 +const val FEATURE_ATTENDANCE = 6 const val FEATURE_MESSAGES_INBOX = 7 -const val FEATURE_MESSAGES_OUTBOX = 8 +const val FEATURE_MESSAGES_SENT = 8 const val FEATURE_ANNOUNCEMENTS = 9 +const val FEATURE_ALWAYS_NEEDED = 100 const val FEATURE_STUDENT_INFO = 101 const val FEATURE_STUDENT_NUMBER = 109 const val FEATURE_SCHOOL_INFO = 102 @@ -42,6 +42,7 @@ const val FEATURE_MESSAGE_GET = 201 object Features { private fun getAllNecessary(): List = listOf( + FEATURE_ALWAYS_NEEDED, FEATURE_STUDENT_INFO, FEATURE_STUDENT_NUMBER, FEATURE_SCHOOL_INFO, @@ -57,30 +58,30 @@ object Features { FEATURE_AGENDA, FEATURE_GRADES, FEATURE_HOMEWORK, - FEATURE_NOTICES, - FEATURE_ATTENDANCES, + FEATURE_BEHAVIOUR, + FEATURE_ATTENDANCE, FEATURE_MESSAGES_INBOX, - FEATURE_MESSAGES_OUTBOX, + FEATURE_MESSAGES_SENT, FEATURE_ANNOUNCEMENTS) fun getAllIds(): List = getAllFeatures() + getAllNecessary() - fun getIdsByView(targetId: Int): List { - return when (targetId) { + fun getIdsByView(targetId: Int, targetType: Int): List { + return (when (targetId) { DRAWER_ITEM_HOME -> getAllFeatures() DRAWER_ITEM_TIMETABLE -> listOf(FEATURE_TIMETABLE) DRAWER_ITEM_AGENDA -> listOf(FEATURE_AGENDA) DRAWER_ITEM_GRADES -> listOf(FEATURE_GRADES) - DRAWER_ITEM_MESSAGES -> when (MessagesFragment.pageSelection) { + DRAWER_ITEM_MESSAGES -> when (targetType) { TYPE_RECEIVED -> listOf(FEATURE_MESSAGES_INBOX) - TYPE_SENT -> listOf(FEATURE_MESSAGES_OUTBOX) - else -> listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_OUTBOX) + TYPE_SENT -> listOf(FEATURE_MESSAGES_SENT) + else -> listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_SENT) } DRAWER_ITEM_HOMEWORK -> listOf(FEATURE_HOMEWORK) - DRAWER_ITEM_BEHAVIOUR -> listOf(FEATURE_NOTICES) - DRAWER_ITEM_ATTENDANCE -> listOf(FEATURE_ATTENDANCES) + DRAWER_ITEM_BEHAVIOUR -> listOf(FEATURE_BEHAVIOUR) + DRAWER_ITEM_ATTENDANCE -> listOf(FEATURE_ATTENDANCE) DRAWER_ITEM_ANNOUNCEMENTS -> listOf(FEATURE_ANNOUNCEMENTS) else -> getAllFeatures() - } + getAllNecessary() + } + getAllNecessary()).sorted() } } \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/LoginMethods.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/LoginMethods.kt index 96f65e71..8d94e388 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/LoginMethods.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/LoginMethods.kt @@ -8,17 +8,23 @@ import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginPortal 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.mobidziennik.login.MobidziennikLoginWeb import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLoginApi import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLoginWeb +// librus +// mobidziennik +// idziennik +// vulcan +// mobireg + const val SYNERGIA_API_ENABLED = true -const val LOGIN_TYPE_MOBIDZIENNIK = 1 const val LOGIN_TYPE_LIBRUS = 2 -const val LOGIN_TYPE_IUCZNIOWIE = 3 +const val LOGIN_TYPE_MOBIDZIENNIK = 1 +const val LOGIN_TYPE_IDZIENNIK = 3 const val LOGIN_TYPE_VULCAN = 4 -const val LOGIN_TYPE_DEMO = 20 const val LOGIN_TYPE_TEMPLATE = 21 // LOGIN MODES @@ -36,7 +42,8 @@ const val LOGIN_METHOD_LIBRUS_PORTAL = 100 const val LOGIN_METHOD_LIBRUS_API = 200 const val LOGIN_METHOD_LIBRUS_SYNERGIA = 300 const val LOGIN_METHOD_LIBRUS_MESSAGES = 400 -const val LOGIN_METHOD_MOBIDZIENNIK_API = 100 +const val LOGIN_METHOD_MOBIDZIENNIK_WEB = 100 +const val LOGIN_METHOD_MOBIDZIENNIK_API2 = 300 const val LOGIN_METHOD_IDZIENNIK_WEB = 100 const val LOGIN_METHOD_IDZIENNIK_API = 200 const val LOGIN_METHOD_VULCAN_WEB = 100 @@ -72,6 +79,12 @@ val librusLoginMethods = listOf( } ) +val mobidziennikLoginMethods = listOf( + LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_WEB, MobidziennikLoginWeb::class.java) + .withIsPossible { _, _ -> true } + .withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED } +) + val templateLoginMethods = listOf( LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java) .withIsPossible { _, _ -> true } diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncProfileRequest.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncProfileRequest.kt index 902e5069..34247a6a 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncProfileRequest.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncProfileRequest.kt @@ -6,8 +6,8 @@ package pl.szczodrzynski.edziennik.api.v2.events.requests import pl.szczodrzynski.edziennik.api.v2.models.ApiTask -data class SyncProfileRequest(override val profileId: Int, val featureIds: List? = null) : ApiTask(profileId) { +data class SyncProfileRequest(override val profileId: Int, val viewIds: List>? = null) : ApiTask(profileId) { override fun toString(): String { - return "SyncProfileRequest(profileId=$profileId, featureIds=$featureIds)" + return "SyncProfileRequest(profileId=$profileId, viewIds=$viewIds)" } } \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncViewRequest.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncViewRequest.kt index 316850fa..fe494236 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncViewRequest.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/events/requests/SyncViewRequest.kt @@ -6,8 +6,8 @@ package pl.szczodrzynski.edziennik.api.v2.events.requests import pl.szczodrzynski.edziennik.api.v2.models.ApiTask -class SyncViewRequest(override val profileId: Int, val targetId: Int) : ApiTask(profileId) { +class SyncViewRequest(override val profileId: Int, val targetId: Int, val targetType: Int) : ApiTask(profileId) { override fun toString(): String { - return "SyncViewRequest(profileId=$profileId, targetId=$targetId)" + return "SyncViewRequest(profileId=$profileId, targetId=$targetId, targetType=$targetType)" } } \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EdziennikCallback.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EdziennikCallback.kt index 4e172a9b..5ce22d96 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EdziennikCallback.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EdziennikCallback.kt @@ -4,12 +4,12 @@ package pl.szczodrzynski.edziennik.api.v2.interfaces -import pl.szczodrzynski.edziennik.api.v2.models.Endpoint +import pl.szczodrzynski.edziennik.api.v2.models.Feature import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod /** * A callback passed only to an e-register class. - * All [Endpoint]s and [LoginMethod]s receive this callback, + * All [Feature]s and [LoginMethod]s receive this callback, * but may only use [EndpointCallback]'s methods. */ interface EdziennikCallback : EndpointCallback { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EndpointCallback.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EndpointCallback.kt index 5c2717d2..a4449fde 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EndpointCallback.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/interfaces/EndpointCallback.kt @@ -5,11 +5,11 @@ package pl.szczodrzynski.edziennik.api.v2.interfaces import pl.szczodrzynski.edziennik.api.v2.models.ApiError -import pl.szczodrzynski.edziennik.api.v2.models.Endpoint +import pl.szczodrzynski.edziennik.api.v2.models.Feature import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod /** - * A callback passed to all [Endpoint]s and [LoginMethod]s + * A callback passed to all [Feature]s and [LoginMethod]s */ interface EndpointCallback { fun onError(apiError: ApiError) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt index 012b4bac..7ad98803 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/Librus.kt @@ -16,7 +16,7 @@ import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusData import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLogin import pl.szczodrzynski.edziennik.api.v2.librusLoginMethods import pl.szczodrzynski.edziennik.api.v2.models.ApiError -import pl.szczodrzynski.edziennik.api.v2.models.Endpoint +import pl.szczodrzynski.edziennik.api.v2.models.Feature import pl.szczodrzynski.edziennik.data.db.modules.api.* import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile @@ -60,7 +60,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va } //var highestLoginMethod = 0 - var endpointList = mutableListOf() + var endpointList = mutableListOf() val requiredLoginMethods = mutableListOf() data.targetEndpointIds.clear() @@ -80,7 +80,7 @@ class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, va endpointList = endpointList // sort the endpoint list by feature ID and priority - .sortedWith(compareBy(Endpoint::featureId, Endpoint::priority)) + .sortedWith(compareBy(Feature::featureId, Feature::priority)) // select only the most important endpoint for each feature .distinctBy { it.featureId } .toMutableList() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/DataLibrus.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/DataLibrus.kt index dec33957..950ca815 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/DataLibrus.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/DataLibrus.kt @@ -5,7 +5,6 @@ package pl.szczodrzynski.edziennik.api.v2.librus.data import okhttp3.Cookie -import okhttp3.HttpUrl 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 @@ -90,7 +89,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app * A Synergia login, like 1234567u. * Used: for login (API Login Method) in Synergia mode. * Used: for login (Synergia Login Method) in Synergia mode. - * And also in various places in [pl.szczodrzynski.edziennik.api.v2.models.Endpoint]s + * And also in various places in [pl.szczodrzynski.edziennik.api.v2.models.Feature]s */ private var mApiLogin: String? = null var apiLogin: String? diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/LibrusApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/LibrusApi.kt index 5484b6fa..eabb3263 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/LibrusApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/data/LibrusApi.kt @@ -41,7 +41,7 @@ open class LibrusApi(open val data: DataLibrus) { when (code) { "TokenIsExpired" -> ERROR_LIBRUS_API_TOKEN_EXPIRED "Insufficient scopes" -> ERROR_LIBRUS_API_INSUFFICIENT_SCOPES - "Request is denied" -> ERROR_LIBRUS_API_REQUEST_DENIED + "Request is denied" -> ERROR_LIBRUS_API_ACCESS_DENIED "Resource not found" -> ERROR_LIBRUS_API_RESOURCE_NOT_FOUND "NotFound" -> ERROR_LIBRUS_API_DATA_NOT_FOUND "AccessDeny" -> when (json.getString("Message")) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginApi.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginApi.kt index cd528e9c..102db2d1 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginApi.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginApi.kt @@ -126,7 +126,7 @@ class LibrusLoginApi { "librus_reg_accept_needed" -> ERROR_LOGIN_LIBRUS_API_REG_ACCEPT_NEEDED "librus_change_password_error" -> ERROR_LOGIN_LIBRUS_API_CHANGE_PASSWORD_ERROR "librus_password_change_required" -> ERROR_LOGIN_LIBRUS_API_PASSWORD_CHANGE_REQUIRED - "invalid_grant" -> ERROR_LOGIN_LIBRUS_API_INVALID_GRANT + "invalid_grant" -> ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN else -> ERROR_LOGIN_LIBRUS_API_OTHER }.let { errorCode -> data.error(ApiError(TAG, errorCode) diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginSynergia.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginSynergia.kt index d64808df..23a0b361 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginSynergia.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/librus/login/LibrusLoginSynergia.kt @@ -82,7 +82,7 @@ class LibrusLoginSynergia(val data: DataLibrus, val onSuccess: () -> Unit) { when (code) { "TokenIsExpired" -> ERROR_LIBRUS_API_TOKEN_EXPIRED "Insufficient scopes" -> ERROR_LIBRUS_API_INSUFFICIENT_SCOPES - "Request is denied" -> ERROR_LIBRUS_API_REQUEST_DENIED + "Request is denied" -> ERROR_LIBRUS_API_ACCESS_DENIED "Resource not found" -> ERROR_LIBRUS_API_RESOURCE_NOT_FOUND "NotFound" -> ERROR_LIBRUS_API_DATA_NOT_FOUND "AccessDeny" -> when (json.getString("Message")) { diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt new file mode 100644 index 00000000..938ed410 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/Mobidziennik.kt @@ -0,0 +1,173 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik + +import android.util.Log +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.mobidziennik.data.DataMobidziennik +import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.MobidziennikData +import pl.szczodrzynski.edziennik.api.v2.mobidziennik.login.MobidziennikLogin +import pl.szczodrzynski.edziennik.api.v2.models.ApiError +import pl.szczodrzynski.edziennik.api.v2.models.Feature +import pl.szczodrzynski.edziennik.api.v2.template.data.DataTemplate +import pl.szczodrzynski.edziennik.api.v2.template.data.TemplateData +import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLogin +import pl.szczodrzynski.edziennik.data.db.modules.api.EndpointTimer +import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS +import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_NEVER +import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore +import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile +import pl.szczodrzynski.edziennik.utils.Utils + +class Mobidziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface { + companion object { + private const val TAG = "Mobidziennik" + } + + val internalErrorList = mutableListOf() + val data: DataMobidziennik + private var cancelled = false + + init { + data = DataMobidziennik(app, profile, loginStore).apply { + callback = wrapCallback(this@Mobidziennik.callback) + } + data.satisfyLoginMethods() + } + + private fun completed() { + data.saveData() + callback.onCompleted() + } + + /* _______ _ _ _ _ _ + |__ __| | /\ | | (_) | | | + | | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___ + | | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \ + | | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | | + |_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_| + __/ | + |__*/ + override fun sync(featureIds: List, viewId: Int?) { + val possibleLoginMethods = data.loginMethods.toMutableList() + + for (loginMethod in mobidziennikLoginMethods) { + if (loginMethod.isPossible(profile, loginStore)) + possibleLoginMethods += loginMethod.loginMethodId + } + + //var highestLoginMethod = 0 + var endpointList = mutableListOf() + val requiredLoginMethods = mutableListOf() + + data.targetEndpointIds.clear() + data.targetLoginMethodIds.clear() + + // get all endpoints for every feature, only if possible to login + for (featureId in featureIds) { + MobidziennikFeatures.filter { + it.featureId == featureId && possibleLoginMethods.containsAll(it.requiredLoginMethods) + } + .let { + endpointList.addAll(it) + } + } + + val timestamp = System.currentTimeMillis() + + endpointList = endpointList + // sort the endpoint list by feature ID and priority + .sortedWith(compareBy(Feature::featureId, Feature::priority)) + // select only the most important endpoint for each feature + .distinctBy { it.featureId } + .toMutableList() + // add all endpoint IDs and required login methods, filtering using timers + .onEach { feature -> + feature.endpointIds.forEach { endpoint -> + (data.endpointTimers + .singleOrNull { it.endpointId == endpoint.first } ?: EndpointTimer(data.profile?.id ?: -1, endpoint.first)) + .let { timer -> + if (timer.nextSync == SYNC_ALWAYS || + (timer.viewId == viewId) || + (timer.nextSync != SYNC_NEVER && timer.nextSync < timestamp)) { + data.targetEndpointIds.add(endpoint.first) + requiredLoginMethods.add(endpoint.second) + } + } + } + } + + // check every login method for any dependencies + for (loginMethodId in requiredLoginMethods) { + var requiredLoginMethod: Int? = loginMethodId + while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) { + mobidziennikLoginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { loginMethod -> + if (requiredLoginMethod != null) + data.targetLoginMethodIds.add(requiredLoginMethod!!) + requiredLoginMethod = loginMethod.requiredLoginMethod(data.profile, data.loginStore) + } + } + } + + // sort and distinct every login method and endpoint + data.targetLoginMethodIds = data.targetLoginMethodIds.toHashSet().toMutableList() + data.targetLoginMethodIds.sort() + + data.targetEndpointIds = data.targetEndpointIds.toHashSet().toMutableList() + data.targetEndpointIds.sort() + + Log.d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}") + Log.d(TAG, "Endpoint IDs: ${data.targetEndpointIds}") + + MobidziennikLogin(data) { + MobidziennikData(data) { + completed() + } + } + } + + override fun getMessage(messageId: Int) { + + } + + override fun cancel() { + Utils.d(TAG, "Cancelled") + cancelled = true + } + + private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback { + return object : EdziennikCallback { + override fun onCompleted() { + callback.onCompleted() + } + + override fun onProgress(step: Int) { + callback.onProgress(step) + } + + override fun onStartProgress(stringRes: Int) { + callback.onStartProgress(stringRes) + } + + override fun onError(apiError: ApiError) { + when (apiError.errorCode) { + in internalErrorList -> { + // finish immediately if the same error occurs twice during the same sync + callback.onError(apiError) + } + CODE_INTERNAL_LIBRUS_ACCOUNT_410 -> { + internalErrorList.add(apiError.errorCode) + loginStore.removeLoginData("refreshToken") // force a clean login + //loginLibrus() + } + else -> callback.onError(apiError) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/MobidziennikFeatures.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/MobidziennikFeatures.kt new file mode 100644 index 00000000..29e8a135 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/MobidziennikFeatures.kt @@ -0,0 +1,107 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik + +import pl.szczodrzynski.edziennik.api.v2.* +import pl.szczodrzynski.edziennik.api.v2.models.Feature + +const val ENDPOINT_MOBIDZIENNIK_API = 1000 +const val ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX = 2011 +const val ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_SENT = 2012 +const val ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL = 2019 +const val ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR = 2020 +const val ENDPOINT_MOBIDZIENNIK_WEB_GRADES = 2030 +const val ENDPOINT_MOBIDZIENNIK_WEB_NOTICES = 2040 +const val ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE = 2050 +const val ENDPOINT_MOBIDZIENNIK_WEB_MANUALS = 2100 +const val ENDPOINT_MOBIDZIENNIK_API2 = 3000 + +val MobidziennikFeatures = listOf( + // timetable + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_TIMETABLE, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + // agenda + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_AGENDA, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + // grades + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_GRADES, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_GRADES to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + // homework + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_HOMEWORK, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + // behaviour + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_BEHAVIOUR, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB, + ENDPOINT_MOBIDZIENNIK_WEB_NOTICES to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB, LOGIN_METHOD_MOBIDZIENNIK_WEB)), + // attendance + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_ATTENDANCE, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + // messages + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_MESSAGES_INBOX, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_MESSAGES_SENT, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_ALWAYS_NEEDED, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + /*Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_STUDENT_INFO, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_STUDENT_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_SCHOOL_INFO, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_CLASS_INFO, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_TEAM_INFO, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_TEACHERS, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_SUBJECTS, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)), + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_CLASSROOMS, listOf( + ENDPOINT_MOBIDZIENNIK_API to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)),*/ + + // lucky number possibilities + // all endpoints that may supply the lucky number + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_MANUALS to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 10 }, + + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 3 }, + + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_GRADES to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 2 }, + + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_NOTICES to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 1 }, + + Feature(LOGIN_TYPE_MOBIDZIENNIK, FEATURE_LUCKY_NUMBER, listOf( + ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_MOBIDZIENNIK_WEB + ), listOf(LOGIN_METHOD_MOBIDZIENNIK_WEB)).apply { priority = 4 } + +) \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/DataMobidziennik.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/DataMobidziennik.kt new file mode 100644 index 00000000..c0c6c49c --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/DataMobidziennik.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data + +import pl.szczodrzynski.edziennik.App +import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_MOBIDZIENNIK_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 + +class DataMobidziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) { + + fun isWebLoginValid() = webSessionIdExpiryTime-30 > currentTimeUnix() + && webSessionValue.isNotNullNorEmpty() + && webSessionKey.isNotNullNorEmpty() + && webServerId.isNotNullNorEmpty() + + override fun satisfyLoginMethods() { + loginMethods.clear() + if (isWebLoginValid()) { + loginMethods += LOGIN_METHOD_MOBIDZIENNIK_WEB + } + } + + private var mLoginServerName: String? = null + var loginServerName: String? + get() { mLoginServerName = mLoginServerName ?: loginStore.getLoginData("serverName", null); return mLoginServerName } + set(value) { loginStore.putLoginData("serverName", value); mLoginServerName = value } + + private var mLoginUsername: String? = null + var loginUsername: String? + get() { mLoginUsername = mLoginUsername ?: loginStore.getLoginData("username", null); return mLoginUsername } + set(value) { loginStore.putLoginData("username", value); mLoginUsername = 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 mWebSessionKey: String? = null + var webSessionKey: String? + get() { mWebSessionKey = mWebSessionKey ?: loginStore.getLoginData("sessionCookie", null); return mWebSessionKey } + set(value) { loginStore.putLoginData("sessionCookie", value); mWebSessionKey = value } + + private var mWebSessionValue: String? = null + var webSessionValue: String? + get() { mWebSessionValue = mWebSessionValue ?: loginStore.getLoginData("sessionID", null); return mWebSessionValue } + set(value) { loginStore.putLoginData("sessionID", value); mWebSessionValue = value } + + private var mWebServerId: String? = null + var webServerId: String? + get() { mWebServerId = mWebServerId ?: loginStore.getLoginData("sessionServer", null); return mWebServerId } + set(value) { loginStore.putLoginData("sessionServer", value); mWebServerId = value } + + private var mWebSessionIdExpiryTime: Long? = null + var webSessionIdExpiryTime: Long + get() { mWebSessionIdExpiryTime = mWebSessionIdExpiryTime ?: loginStore.getLoginData("sessionIDTime", 0L); return mWebSessionIdExpiryTime ?: 0L } + set(value) { loginStore.putLoginData("sessionIDTime", value); mWebSessionIdExpiryTime = value } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikData.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikData.kt new file mode 100644 index 00000000..46efbd00 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikData.kt @@ -0,0 +1,81 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data + +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.api.v2.ENDPOINT_TEMPLATE_API_SAMPLE +import pl.szczodrzynski.edziennik.api.v2.ENDPOINT_TEMPLATE_WEB_SAMPLE +import pl.szczodrzynski.edziennik.api.v2.ENDPOINT_TEMPLATE_WEB_SAMPLE_2 +import pl.szczodrzynski.edziennik.api.v2.mobidziennik.* +import pl.szczodrzynski.edziennik.api.v2.template.data.DataTemplate +import pl.szczodrzynski.edziennik.api.v2.template.data.api.TemplateApiSample +import pl.szczodrzynski.edziennik.api.v2.template.data.web.TemplateWebSample +import pl.szczodrzynski.edziennik.api.v2.template.data.web.TemplateWebSample2 +import pl.szczodrzynski.edziennik.utils.Utils + +class MobidziennikData(val data: DataMobidziennik, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "MobidziennikData" + } + + private var cancelled = false + + init { + nextEndpoint(onSuccess) + } + + private fun nextEndpoint(onSuccess: () -> Unit) { + if (data.targetEndpointIds.isEmpty()) { + onSuccess() + return + } + useEndpoint(data.targetEndpointIds.removeAt(0)) { + if (cancelled) { + onSuccess() + return@useEndpoint + } + nextEndpoint(onSuccess) + } + } + + private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) { + Utils.d(TAG, "Using endpoint $endpointId") + when (endpointId) { + /*ENDPOINT_MOBIDZIENNIK_API -> { + data.startProgress(R.string.edziennik_progress_endpoint_data) + MobidziennikApi(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_INBOX -> { + data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox) + MobidziennikWebMessagesInbox(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_MESSAGES_ALL -> { + data.startProgress(R.string.edziennik_progress_endpoint_messages) + MobidziennikWebMessagesAll(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_CALENDAR -> { + data.startProgress(R.string.edziennik_progress_endpoint_calendar) + MobidziennikWebCalendar(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_GRADES -> { + data.startProgress(R.string.edziennik_progress_endpoint_grades) + MobidziennikWebGrades(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_NOTICES -> { + data.startProgress(R.string.edziennik_progress_endpoint_behaviour) + MobidziennikWebNotices(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_ATTENDANCE -> { + data.startProgress(R.string.edziennik_progress_endpoint_attendance) + MobidziennikWebAttendance(data) { onSuccess() } + } + ENDPOINT_MOBIDZIENNIK_WEB_MANUALS -> { + data.startProgress(R.string.edziennik_progress_endpoint_lucky_number) + MobidziennikWebManuals(data) { onSuccess() } + }*/ + else -> onSuccess() + } + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikWeb.kt new file mode 100644 index 00000000..a5c14df7 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/data/MobidziennikWeb.kt @@ -0,0 +1,93 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik.data + +import com.google.gson.JsonObject +import im.wangchao.mhttp.Request +import im.wangchao.mhttp.Response +import im.wangchao.mhttp.callback.TextCallbackHandler +import okhttp3.Cookie +import pl.szczodrzynski.edziennik.api.v2.* +import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia +import pl.szczodrzynski.edziennik.api.v2.models.ApiError +import pl.szczodrzynski.edziennik.api.v2.template.data.DataTemplate +import pl.szczodrzynski.edziennik.currentTimeUnix +import pl.szczodrzynski.edziennik.data.api.AppError +import pl.szczodrzynski.edziennik.data.api.AppError.* +import pl.szczodrzynski.edziennik.utils.Utils.d + +open class MobidziennikWeb(open val data: DataMobidziennik) { + companion object { + private const val TAG = "MobidziennikWeb" + } + + val profileId + get() = data.profile?.id ?: -1 + + val profile + get() = data.profile + + fun webGet(tag: String, endpoint: String, method: Int = GET, payload: List>? = null, onSuccess: (text: String) -> Unit) { + val url = "https://${data.loginServerName}.mobidziennik.pl$endpoint" + + d(tag, "Requesting $url") + + if (data.webSessionKey == null) { + data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_KEY) + return + } + if (data.webSessionValue == null) { + data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SESSION_VALUE) + return + } + if (data.webServerId == null) { + data.error(TAG, ERROR_MOBIDZIENNIK_WEB_NO_SERVER_ID) + return + } + + val callback = object : TextCallbackHandler() { + override fun onSuccess(text: String?, response: Response?) { + if (text.isNullOrEmpty()) { + data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY) + .withResponse(response)) + return + } + if (text == "Nie jestes zalogowany") { + data.error(ApiError(TAG, ERROR_MOBIDZIENNIK_WEB_ACCESS_DENIED) + .withResponse(response)) + return + } + + onSuccess(text) + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + data.error(ApiError(TAG, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable)) + } + } + + data.app.cookieJar.saveFromResponse(null, listOf( + Cookie.Builder() + .name(data.webSessionKey!!) + .value(data.webSessionValue!!) + .domain("${data.loginServerName}.mobidziennik.pl") + .secure().httpOnly().build(), + Cookie.Builder() + .name("SERVERID") + .value(data.webServerId!!) + .domain("${data.loginServerName}.mobidziennik.pl") + .secure().httpOnly().build() + )) + + Request.builder() + .url(url) + .userAgent(MOBIDZIENNIK_USER_AGENT) + .callback(callback) + .build() + .enqueue() + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLogin.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLogin.kt new file mode 100644 index 00000000..efbcd6c8 --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLogin.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik.login + +import pl.szczodrzynski.edziennik.R +import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_MOBIDZIENNIK_WEB +import pl.szczodrzynski.edziennik.api.v2.mobidziennik.data.DataMobidziennik +import pl.szczodrzynski.edziennik.utils.Utils + +class MobidziennikLogin(val data: DataMobidziennik, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "MobidziennikLogin" + } + + private var cancelled = false + + init { + nextLoginMethod(onSuccess) + } + + private fun nextLoginMethod(onSuccess: () -> Unit) { + if (data.targetLoginMethodIds.isEmpty()) { + onSuccess() + return + } + useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId -> + if (usedMethodId != -1) + data.loginMethods.add(usedMethodId) + if (cancelled) { + onSuccess() + return@useLoginMethod + } + 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_MOBIDZIENNIK_WEB -> { + data.startProgress(R.string.edziennik_progress_login_mobidziennik_web) + MobidziennikLoginWeb(data) { onSuccess(loginMethodId) } + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLoginWeb.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLoginWeb.kt new file mode 100644 index 00000000..0cf3bd7c --- /dev/null +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/mobidziennik/login/MobidziennikLoginWeb.kt @@ -0,0 +1,102 @@ +/* + * Copyright (c) Kuba Szczodrzyński 2019-10-5. + */ + +package pl.szczodrzynski.edziennik.api.v2.mobidziennik.login + +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.mobidziennik.data.DataMobidziennik +import pl.szczodrzynski.edziennik.api.v2.models.ApiError +import pl.szczodrzynski.edziennik.getUnixDate +import pl.szczodrzynski.edziennik.isNotNullNorEmpty + +class MobidziennikLoginWeb(val data: DataMobidziennik, val onSuccess: () -> Unit) { + companion object { + private const val TAG = "MobidziennikLoginWeb" + } + + init { run { + if (data.profile == null) { + data.error(ApiError(TAG, ERROR_PROFILE_MISSING)) + return@run + } + + if (data.isWebLoginValid()) { + onSuccess() + } + else { + if (data.loginServerName.isNotNullNorEmpty() && data.loginUsername.isNotNullNorEmpty() && data.loginPassword.isNotNullNorEmpty()) { + data.app.cookieJar.clearForDomain(data.loginServerName + ".mobidziennik.pl") + loginWithCredentials() + } + else { + data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING)) + } + } + }} + + private fun loginWithCredentials() { + val callback = object : TextCallbackHandler() { + override fun onSuccess(text: String?, response: Response?) { + if (text != "ok") { + when { + text == "Nie jestes zalogowany" -> ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_LOGIN + text == "ifun" -> ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_DEVICE + text == "stare haslo" -> ERROR_LOGIN_MOBIDZIENNIK_WEB_OLD_PASSWORD + text == "Archiwum" -> ERROR_LOGIN_MOBIDZIENNIK_WEB_ARCHIVED + text == "Trwają prace techniczne lub pojawił się jakiś problem" -> ERROR_LOGIN_MOBIDZIENNIK_WEB_MAINTENANCE + text?.contains("Uuuups... nieprawidłowy adres") == true -> ERROR_LOGIN_MOBIDZIENNIK_WEB_INVALID_ADDRESS + text?.contains("przerwa techniczna") == true -> ERROR_LOGIN_MOBIDZIENNIK_WEB_MAINTENANCE + else -> ERROR_LOGIN_MOBIDZIENNIK_WEB_OTHER + }.let { errorCode -> + data.error(ApiError(TAG, errorCode) + .withApiResponse(text) + .withResponse(response)) + return + } + } + + val cookies = data.app.cookieJar.getForDomain("${data.loginServerName}.mobidziennik.pl") + val cookie = cookies.singleOrNull { it.name().length > 32 } + val sessionKey = cookie?.name() + val sessionId = cookie?.value() + if (sessionId == null) { + data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID) + .withResponse(response) + .withApiResponse(text)) + return + } + + data.webSessionKey = sessionKey + data.webSessionValue = sessionId + data.webServerId = data.app.cookieJar.getCookie("${data.loginServerName}.mobidziennik.pl", "SERVERID") + data.webSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */ + onSuccess() + } + + override fun onFailure(response: Response?, throwable: Throwable?) { + data.error(ApiError(TAG, ERROR_REQUEST_FAILURE) + .withResponse(response) + .withThrowable(throwable)) + } + } + + + Request.builder() + .url("https://${data.loginServerName}.mobidziennik.pl/api/") + .userAgent(System.getProperty("http.agent")) + .contentType("application/x-www-form-urlencoded; charset=UTF-8") + .addParameter("wersja", "20") + .addParameter("ip", data.app.deviceId) + .addParameter("login", data.loginUsername) + .addParameter("haslo", data.loginPassword) + .addParameter("token", data.app.appConfig.fcmTokens[LOGIN_TYPE_MOBIDZIENNIK]?.first) + .post() + .callback(callback) + .build() + .enqueue() + } +} \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt index 098375a4..a6b5bbe9 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Data.kt @@ -38,7 +38,7 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) var fakeLogin = false /** - * A callback passed to all [Endpoint]s and [LoginMethod]s + * A callback passed to all [Feature]s and [LoginMethod]s */ lateinit var callback: EndpointCallback diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Endpoint.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Feature.kt similarity index 82% rename from app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Endpoint.kt rename to app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Feature.kt index 2dba888b..b8d9b8a7 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Endpoint.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/Feature.kt @@ -10,15 +10,14 @@ package pl.szczodrzynski.edziennik.api.v2.models * * @param loginType type of the e-register this endpoint handles * @param featureId a feature ID - * @param endpointIds a [List] of [Endpoint]s that satisfy this feature ID + * @param endpointIds a [List] of [Feature]s that satisfy this feature ID * @param requiredLoginMethod a required login method, which will have to be executed before this endpoint. */ -data class Endpoint( +data class Feature( val loginType: Int, val featureId: Int, val endpointIds: List>, val requiredLoginMethods: List ) { - val priority - get() = endpointIds.size + var priority = endpointIds.size } \ No newline at end of file diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/LoginMethod.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/LoginMethod.kt index e61d1142..95559feb 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/LoginMethod.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/models/LoginMethod.kt @@ -11,7 +11,7 @@ import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile /** * A Login Method descriptor class. * - * This is used by the API to satisfy all [Endpoint]s' dependencies. + * This is used by the API to satisfy all [Feature]s' dependencies. * A login method may have its own dependencies which need to be * satisfied before the [loginMethodClass]'s constructor is invoked. * diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt index 93a808e7..f12ce12e 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/api/v2/template/Template.kt @@ -11,7 +11,7 @@ import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_NOT_NEEDED import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface import pl.szczodrzynski.edziennik.api.v2.models.ApiError -import pl.szczodrzynski.edziennik.api.v2.models.Endpoint +import pl.szczodrzynski.edziennik.api.v2.models.Feature import pl.szczodrzynski.edziennik.api.v2.template.data.DataTemplate import pl.szczodrzynski.edziennik.api.v2.template.data.TemplateData import pl.szczodrzynski.edziennik.api.v2.template.login.TemplateLogin @@ -62,7 +62,7 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, } //var highestLoginMethod = 0 - var endpointList = mutableListOf() + var endpointList = mutableListOf() val requiredLoginMethods = mutableListOf() data.targetEndpointIds.clear() @@ -82,7 +82,7 @@ class Template(val app: App, val profile: Profile?, val loginStore: LoginStore, endpointList = endpointList // sort the endpoint list by feature ID and priority - .sortedWith(compareBy(Endpoint::featureId, Endpoint::priority)) + .sortedWith(compareBy(Feature::featureId, Feature::priority)) // select only the most important endpoint for each feature .distinctBy { it.featureId } .toMutableList() diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/login/LoginStore.java b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/login/LoginStore.java index 5545c5f5..e32dc143 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/login/LoginStore.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/login/LoginStore.java @@ -157,7 +157,7 @@ public class LoginStore { case LOGIN_TYPE_LIBRUS: return "LOGIN_TYPE_LIBRUS"; case LOGIN_TYPE_IUCZNIOWIE: - return "LOGIN_TYPE_IUCZNIOWIE"; + return "LOGIN_TYPE_IDZIENNIK"; case LOGIN_TYPE_VULCAN: return "LOGIN_TYPE_VULCAN"; case LOGIN_TYPE_DEMO: diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/ProfileFull.kt b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/ProfileFull.kt index ae41a733..ceb88413 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/ProfileFull.kt +++ b/app/src/main/java/pl/szczodrzynski/edziennik/data/db/modules/profiles/ProfileFull.kt @@ -223,7 +223,7 @@ class ProfileFull : Profile { when (loginStoreType) { LOGIN_TYPE_MOBIDZIENNIK -> return "LOGIN_TYPE_MOBIDZIENNIK" LOGIN_TYPE_LIBRUS -> return "LOGIN_TYPE_LIBRUS" - LOGIN_TYPE_IUCZNIOWIE -> return "LOGIN_TYPE_IUCZNIOWIE" + LOGIN_TYPE_IUCZNIOWIE -> return "LOGIN_TYPE_IDZIENNIK" LOGIN_TYPE_VULCAN -> return "LOGIN_TYPE_VULCAN" LOGIN_TYPE_DEMO -> return "LOGIN_TYPE_DEMO" else -> return "LOGIN_TYPE_UNKNOWN" diff --git a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.java b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.java index 69fb2ac2..e18a3877 100644 --- a/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.java +++ b/app/src/main/java/pl/szczodrzynski/edziennik/ui/modules/home/HomeFragment.java @@ -39,6 +39,7 @@ import org.greenrobot.eventbus.EventBus; import java.util.ArrayList; import java.util.List; +import kotlin.Pair; import pl.szczodrzynski.edziennik.App; import pl.szczodrzynski.edziennik.BuildConfig; import pl.szczodrzynski.edziennik.R; @@ -66,6 +67,8 @@ import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem; import static pl.szczodrzynski.edziennik.App.UPDATES_ON_PLAY_STORE; import static pl.szczodrzynski.edziennik.MainActivity.DRAWER_ITEM_GRADES; +import static pl.szczodrzynski.edziennik.MainActivity.DRAWER_ITEM_HOME; +import static pl.szczodrzynski.edziennik.MainActivity.DRAWER_ITEM_MESSAGES; import static pl.szczodrzynski.edziennik.api.v2.FeaturesKt.FEATURE_STUDENT_INFO; import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_FINAL; import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_PROPOSED; @@ -74,6 +77,7 @@ import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMES import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_FINAL; import static pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_PROPOSED; import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK; +import static pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT; public class HomeFragment extends Fragment { private static final String TAG = "HomeFragment"; @@ -129,19 +133,23 @@ public class HomeFragment extends Fragment { b.test2.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE); b.test2.setOnClickListener((v -> { - List list = new ArrayList<>(); - list.add(FEATURE_STUDENT_INFO); - EventBus.getDefault().post(new SyncProfileRequest(16, list)); + List> list = new ArrayList<>(); + list.add(new Pair<>(DRAWER_ITEM_HOME, 0)); + EventBus.getDefault().post(new SyncProfileRequest(10, list)); })); b.test3.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE); b.test3.setOnClickListener((v -> { - EventBus.getDefault().post(new SyncProfileRequest(16, null)); + List> list = new ArrayList<>(); + list.add(new Pair<>(DRAWER_ITEM_MESSAGES, TYPE_SENT)); + EventBus.getDefault().post(new SyncProfileRequest(10, list)); })); b.test4.setVisibility(BuildConfig.DEBUG ? View.VISIBLE : View.GONE); b.test4.setOnClickListener((v -> { - EventBus.getDefault().post(new SyncViewRequest(16, DRAWER_ITEM_GRADES)); + List> list = new ArrayList<>(); + list.add(new Pair<>(DRAWER_ITEM_GRADES, 0)); + EventBus.getDefault().post(new SyncProfileRequest(10, list)); })); //((TextView)v.findViewById(R.id.nextSync)).setText(getString(R.string.next_sync_format,Time.fromMillis(app.appJobs.syncJobTime).getStringHMS())); diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 03c894ac..aeb2b074 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -64,7 +64,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="8dp" - android:text="Sync profile 16 - feature me" + android:text="Sync profile 16 - view home" android:visibility="gone"/> Pobieranie ocen ucznia... Logowanie do Template WEB... Logowanie do Template API... + Logowanie do MobiDziennika... + Logowanie do API MobiDziennika... + Pobieram dane... + Pobieram wiadomości odebrane... + Pobieram wiadomości... + Pobieram szczęśliwy numerek... + Pobieram kalendarz... + Pobieram uwagi ucznia... + Pobieram frekwencję ucznia... diff --git a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java index 7f096d54..3a6b5a8c 100644 --- a/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java +++ b/mhttp/src/main/java/im/wangchao/mhttp/internal/cookie/PersistentCookieJar.java @@ -74,6 +74,27 @@ public class PersistentCookieJar implements ClearableCookieJar { return validCookies; } + @NonNull + synchronized public List getForDomain(String domain) { + List removedCookies = new ArrayList<>(); + List validCookies = new ArrayList<>(); + + for (Iterator it = cache.iterator(); it.hasNext(); ) { + Cookie currentCookie = it.next(); + if (isCookieExpired(currentCookie)) { + removedCookies.add(currentCookie); + it.remove(); + + } else if (domain.equals(currentCookie.domain())) { + validCookies.add(currentCookie); + } + } + + persistor.removeAll(removedCookies); + + return validCookies; + } + @Nullable synchronized public String getCookie(String domain, String name) { String cookieValue = null;