forked from github/szkolny
[APIv2] Add API Service. Update other APIv2 components. Update Profile DAO
This commit is contained in:
parent
5edd4d5922
commit
0bf2026a64
@ -218,6 +218,8 @@
|
||||
android:name=".sync.SyncService"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/sync_service" />
|
||||
|
||||
<service android:name=".api.v2.ApiService" />
|
||||
</application>
|
||||
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
@ -19,7 +19,6 @@ import android.provider.Settings;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector;
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor;
|
||||
@ -81,7 +80,6 @@ import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.models.AppConfig;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.receivers.JobsCreator;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.utils.PermissionChecker;
|
||||
@ -617,7 +615,7 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
}
|
||||
|
||||
public ProfileFull profileGetOrNull(int id) {
|
||||
return db.profileDao().getByIdNow(id);
|
||||
return db.profileDao().getFullByIdNow(id);
|
||||
}
|
||||
|
||||
public void profileLoadById(int id) {
|
||||
@ -632,7 +630,7 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
return;
|
||||
}*/
|
||||
if (profile == null || profile.getId() != id) {
|
||||
profile = db.profileDao().getByIdNow(id);
|
||||
profile = db.profileDao().getFullByIdNow(id);
|
||||
/*if (profile == null) {
|
||||
profileLoadById(id);
|
||||
return;
|
||||
@ -659,7 +657,7 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
|
||||
/*public void profileRemove(int id)
|
||||
{
|
||||
Profile profile = db.profileDao().getByIdNow(id);
|
||||
Profile profile = db.profileDao().getFullByIdNow(id);
|
||||
|
||||
if (profile.id == profile.loginStoreId) {
|
||||
// this profile is the owner of the login store
|
||||
|
@ -10,10 +10,13 @@ import androidx.core.app.ActivityCompat
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Response
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.datamodels.Teacher
|
||||
import pl.szczodrzynski.navlib.crc16
|
||||
import pl.szczodrzynski.navlib.getColorFromRes
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
|
||||
fun List<Teacher>.byId(id: Long) = firstOrNull { it.id == id }
|
||||
@ -118,3 +121,10 @@ fun Activity.isStoragePermissionGranted(): Boolean {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
fun Response?.getUnixDate(): Long {
|
||||
val rfcDate = this?.headers()?.get("date") ?: return currentTimeUnix()
|
||||
val pattern = "EEE, dd MMM yyyy HH:mm:ss Z"
|
||||
val format = SimpleDateFormat(pattern, Locale.ENGLISH)
|
||||
return format.parse(rfcDate).time / 1000
|
||||
}
|
@ -41,7 +41,7 @@ import com.mikepenz.materialdrawer.model.interfaces.IProfile
|
||||
import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.*
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.*
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
|
@ -244,7 +244,7 @@ public class WidgetTimetable extends AppWidgetProvider {
|
||||
filterOutArchived(profileList);
|
||||
}
|
||||
else {
|
||||
Profile profile = app.db.profileDao().getByIdNow(widgetConfig.profileId);
|
||||
Profile profile = app.db.profileDao().getFullByIdNow(widgetConfig.profileId);
|
||||
if (profile != null) {
|
||||
profileList.add(profile);
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.MainActivity;
|
||||
import pl.szczodrzynski.edziennik.WidgetTimetable;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback;
|
||||
import pl.szczodrzynski.edziennik.datamodels.AnnouncementFull;
|
||||
import pl.szczodrzynski.edziennik.datamodels.Attendance;
|
||||
@ -81,16 +81,16 @@ import static pl.szczodrzynski.edziennik.api.AppError.CODE_PROFILE_ARCHIVED;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.CODE_PROFILE_NOT_FOUND;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.stringErrorCode;
|
||||
import static pl.szczodrzynski.edziennik.api.AppError.stringErrorType;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_AGENDA;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_ALL;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_ANNOUNCEMENTS;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_ATTENDANCES;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_GRADES;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_HOMEWORKS;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_MESSAGES_INBOX;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_MESSAGES_OUTBOX;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_NOTICES;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface.FEATURE_TIMETABLE;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_AGENDA;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_ALL;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_ANNOUNCEMENTS;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_ATTENDANCES;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_GRADES;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_HOMEWORKS;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_MESSAGES_INBOX;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_MESSAGES_OUTBOX;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_NOTICES;
|
||||
import static pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface.FEATURE_TIMETABLE;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Event.TYPE_HOMEWORK;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_SEMESTER1_FINAL;
|
||||
import static pl.szczodrzynski.edziennik.datamodels.Grade.TYPE_SEMESTER1_PROPOSED;
|
||||
@ -115,7 +115,7 @@ public class Edziennik {
|
||||
private static boolean registerEmpty;
|
||||
public static int oldLuckyNumber;
|
||||
|
||||
public static EdziennikInterface getApi(App app, int loginType) {
|
||||
public static OldEdziennikInterface getApi(App app, int loginType) {
|
||||
switch (loginType) {
|
||||
default:
|
||||
case LOGIN_TYPE_MOBIDZIENNIK:
|
||||
@ -625,7 +625,7 @@ public class Edziennik {
|
||||
* Used in services, login form and {@code guiSync}
|
||||
* <p>
|
||||
* May be ran on worker thread.
|
||||
* {@link EdziennikInterface}.sync is ran always on worker thread.
|
||||
* {@link OldEdziennikInterface}.sync is ran always on worker thread.
|
||||
* Every callback is ran on the UI thread.
|
||||
*
|
||||
* @param app
|
||||
@ -676,7 +676,7 @@ public class Edziennik {
|
||||
}
|
||||
};
|
||||
AsyncTask.execute(() -> {
|
||||
ProfileFull profile = app.db.profileDao().getByIdNow(profileId);
|
||||
ProfileFull profile = app.db.profileDao().getFullByIdNow(profileId);
|
||||
if (profile != null) {
|
||||
|
||||
if (profile.getArchived()) {
|
||||
@ -1130,7 +1130,7 @@ public class Edziennik {
|
||||
.show();
|
||||
}
|
||||
public void removeProfile(int profileId) {
|
||||
Profile profileObject = app.db.profileDao().getByIdNow(profileId);
|
||||
Profile profileObject = app.db.profileDao().getFullByIdNow(profileId);
|
||||
if (profileObject == null)
|
||||
return;
|
||||
app.db.announcementDao().clear(profileId);
|
||||
|
@ -35,7 +35,7 @@ import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.AttachmentGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.LoginCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.MessageGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
||||
@ -91,7 +91,7 @@ import static pl.szczodrzynski.edziennik.utils.Utils.crc32;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getWordGradeValue;
|
||||
|
||||
public class Iuczniowie implements EdziennikInterface {
|
||||
public class Iuczniowie implements OldEdziennikInterface {
|
||||
public Iuczniowie(App app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.AttachmentGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.LoginCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.MessageGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
||||
@ -131,7 +131,7 @@ import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getGradeValue;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.strToInt;
|
||||
|
||||
public class Librus implements EdziennikInterface {
|
||||
public class Librus implements OldEdziennikInterface {
|
||||
public Librus(App app) {
|
||||
this.app = app;
|
||||
}
|
||||
@ -2537,7 +2537,7 @@ public class Librus implements EdziennikInterface {
|
||||
&& (el = obj.get("Id")) != null) {
|
||||
type = el.getAsInt();
|
||||
}
|
||||
/*EventType typeObject = app.db.eventTypeDao().getByIdNow(profileId, type);
|
||||
/*EventType typeObject = app.db.eventTypeDao().getFullByIdNow(profileId, type);
|
||||
if (typeObject == null) {
|
||||
getCustomTypes = true;
|
||||
}*/
|
||||
|
@ -41,7 +41,7 @@ import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.BuildConfig;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.AttachmentGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.LoginCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.MessageGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
||||
@ -99,7 +99,7 @@ import static pl.szczodrzynski.edziennik.utils.Utils.d;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.monthFromName;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.strToInt;
|
||||
|
||||
public class Mobidziennik implements EdziennikInterface {
|
||||
public class Mobidziennik implements OldEdziennikInterface {
|
||||
public Mobidziennik(App app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ import okio.Buffer;
|
||||
import pl.szczodrzynski.edziennik.App;
|
||||
import pl.szczodrzynski.edziennik.R;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.AttachmentGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.EdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.OldEdziennikInterface;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.LoginCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.MessageGetCallback;
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.RecipientListGetCallback;
|
||||
@ -93,7 +93,7 @@ import static pl.szczodrzynski.edziennik.utils.Utils.getGradeValue;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.getVulcanGradeColor;
|
||||
import static pl.szczodrzynski.edziennik.utils.Utils.intToStr;
|
||||
|
||||
public class Vulcan implements EdziennikInterface {
|
||||
public class Vulcan implements OldEdziennikInterface {
|
||||
public Vulcan(App app) {
|
||||
this.app = app;
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ import pl.szczodrzynski.edziennik.datamodels.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.messages.MessagesComposeInfo;
|
||||
import pl.szczodrzynski.edziennik.models.Endpoint;
|
||||
|
||||
public interface EdziennikInterface {
|
||||
public interface OldEdziennikInterface {
|
||||
|
||||
/**
|
||||
* Sync all Edziennik data.
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.core.app.NotificationCompat
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.MessageGetRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.SyncProgressEvent
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncProfileRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.SyncViewRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.Librus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiTask
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import kotlin.math.min
|
||||
|
||||
class ApiService : Service() {
|
||||
companion object {
|
||||
const val TAG = "ApiService"
|
||||
const val NOTIFICATION_API_CHANNEL_ID = "pl.szczodrzynski.edziennik.GET_DATA"
|
||||
}
|
||||
|
||||
private val app by lazy { applicationContext as App }
|
||||
|
||||
private val taskQueue = mutableListOf<ApiTask>()
|
||||
private val errorList = mutableListOf<ApiError>()
|
||||
|
||||
private var taskRunning = false
|
||||
private var taskRunningId = -1
|
||||
private var taskMaximumId = 0
|
||||
|
||||
private var taskProfileId = -1
|
||||
private var taskProfileName: String? = null
|
||||
private var taskProgress = 0
|
||||
private var taskProgressRes: Int? = null
|
||||
|
||||
private val taskCallback = object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
override fun onProgress(step: Int) {
|
||||
taskProgress += step
|
||||
taskProgress = min(100, taskProgress)
|
||||
EventBus.getDefault().post(SyncProgressEvent(taskProfileId, taskProfileName, taskProgress, taskProgressRes))
|
||||
}
|
||||
|
||||
override fun onStartProgress(stringRes: Int) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun sync() {
|
||||
if (taskRunning)
|
||||
return
|
||||
if (taskQueue.size <= 0)
|
||||
return // TODO stopSelf() or sth
|
||||
|
||||
val task = taskQueue.removeAt(0)
|
||||
taskRunning = true
|
||||
taskRunningId = task.taskId
|
||||
|
||||
// get the requested profile and login store
|
||||
val profile: Profile? = app.db.profileDao().getByIdNow(task.profileId)
|
||||
if (profile == null || !profile.syncEnabled) {
|
||||
return
|
||||
}
|
||||
val loginStore: LoginStore? = app.db.loginStoreDao().getByIdNow(profile.loginStoreId)
|
||||
if (loginStore == null) {
|
||||
return
|
||||
}
|
||||
// save the profile ID and name as the current task's
|
||||
taskProfileId = profile.id
|
||||
taskProfileName = profile.name
|
||||
taskProgress = 0
|
||||
taskProgressRes = null
|
||||
|
||||
|
||||
val edziennikInterface = when (loginStore.type) {
|
||||
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||
else -> null
|
||||
}
|
||||
if (edziennikInterface == null) {
|
||||
return
|
||||
}
|
||||
|
||||
when (task) {
|
||||
is SyncProfileRequest -> edziennikInterface.sync(task.featureIds ?: Features.getAllIds())
|
||||
is SyncViewRequest -> edziennikInterface.sync(Features.getIdsByView(task.targetId))
|
||||
is MessageGetRequest -> edziennikInterface.getMessage(task.messageId)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.ASYNC)
|
||||
fun onSyncRequest(syncRequest: SyncRequest) {
|
||||
app.db.profileDao().idsForSyncNow.forEach { id ->
|
||||
taskQueue += SyncProfileRequest(id, null)
|
||||
}
|
||||
sync()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.ASYNC)
|
||||
fun onSyncProfileRequest(syncProfileRequest: SyncProfileRequest) {
|
||||
Log.d(TAG, syncProfileRequest.toString())
|
||||
taskQueue += syncProfileRequest
|
||||
sync()
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.ASYNC)
|
||||
fun onMessageGetRequest(messageGetRequest: MessageGetRequest) {
|
||||
Log.d(TAG, messageGetRequest.toString())
|
||||
taskQueue += messageGetRequest
|
||||
sync()
|
||||
}
|
||||
|
||||
private val notification by lazy {
|
||||
NotificationCompat.Builder(this, NOTIFICATION_API_CHANNEL_ID)
|
||||
.setContentTitle("API")
|
||||
.setContentText("API is running")
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun onCreate() {
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
startForeground(1, notification)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
}
|
@ -4,18 +4,6 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
internal const val FEATURE_ANY = -1
|
||||
const val FEATURE_ALL = 0
|
||||
const val FEATURE_TIMETABLE = 1
|
||||
const val FEATURE_AGENDA = 2
|
||||
const val FEATURE_GRADES = 3
|
||||
const val FEATURE_HOMEWORKS = 4
|
||||
const val FEATURE_NOTICES = 5
|
||||
const val FEATURE_ATTENDANCES = 6
|
||||
const val FEATURE_MESSAGES_INBOX = 7
|
||||
const val FEATURE_MESSAGES_OUTBOX = 8
|
||||
const val FEATURE_ANNOUNCEMENTS = 9
|
||||
|
||||
const val LIBRUS_USER_AGENT = "Dalvik/2.1.0 Android 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"
|
||||
@ -42,7 +30,7 @@ const val LIBRUS_JST_DEMO_CODE = "68656A21"
|
||||
const val LIBRUS_JST_DEMO_PIN = "1290"
|
||||
|
||||
/** https://synergia.librus.pl/loguj/token/TOKEN/przenies */
|
||||
const val LIBRUS_SYNERGIA_TOKEN_LOGIN_URL = "https://synergia.librus.pl/loguj/token/TOKEN/przenies/"
|
||||
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="
|
@ -4,20 +4,130 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import android.util.Log
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApiGrades
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApiMe
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergiaGrades
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Endpoint
|
||||
|
||||
const val ENDPOINT_LIBRUS_API_ME = 0
|
||||
const val ENDPOINT_LIBRUS_API_GRADES = 0
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 0
|
||||
const val ENDPOINT_LIBRUS_API_ME = 101
|
||||
const val ENDPOINT_LIBRUS_API_SCHOOLS = 102
|
||||
const val ENDPOINT_LIBRUS_API_CLASSES = 103
|
||||
const val ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES = 104
|
||||
const val ENDPOINT_LIBRUS_API_UNITS = 105
|
||||
const val ENDPOINT_LIBRUS_API_USERS = 106
|
||||
const val ENDPOINT_LIBRUS_API_SUBJECTS = 107
|
||||
const val ENDPOINT_LIBRUS_API_CLASSROOMS = 108
|
||||
const val ENDPOINT_LIBRUS_API_TIMETABLES = 109
|
||||
const val ENDPOINT_LIBRUS_API_SUBSTITUTIONS = 110
|
||||
const val ENDPOINT_LIBRUS_API_NORMAL_GC = 111
|
||||
const val ENDPOINT_LIBRUS_API_POINT_GC = 112
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC = 113
|
||||
const val ENDPOINT_LIBRUS_API_TEXT_GC = 114
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 115
|
||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 116
|
||||
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 117
|
||||
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 118
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 119
|
||||
const val ENDPOINT_LIBRUS_API_TEXT_GRADES = 120
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES = 121
|
||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES = 122
|
||||
const val ENDPOINT_LIBRUS_API_EVENTS = 123
|
||||
const val ENDPOINT_LIBRUS_API_EVENT_TYPES = 124
|
||||
const val ENDPOINT_LIBRUS_API_HOMEWORK = 125
|
||||
const val ENDPOINT_LIBRUS_API_LUCKY_NUMBER = 126
|
||||
const val ENDPOINT_LIBRUS_API_NOTICES = 127
|
||||
const val ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES = 128
|
||||
const val ENDPOINT_LIBRUS_API_ATTENDANCE = 129
|
||||
const val ENDPOINT_LIBRUS_API_ANNOUNCEMENTS = 130
|
||||
const val ENDPOINT_LIBRUS_API_PT_MEETINGS = 131
|
||||
const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS = 132
|
||||
const val ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS = 133
|
||||
const val ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS = 134
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 201
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 202
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 301
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 302
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 303
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVERS = 304
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_GET = 304
|
||||
|
||||
val endpoints = listOf(
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, ENDPOINT_LIBRUS_API_ME, null, LibrusApiMe::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_API},
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, 1, listOf(), LibrusSynergiaGrades::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_SYNERGIA },
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, 1, listOf(), LibrusApiGrades::class.java) { _, _ -> LOGIN_METHOD_LIBRUS_API }
|
||||
|
||||
// LIBRUS: API
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TIMETABLE, listOf(
|
||||
ENDPOINT_LIBRUS_API_TIMETABLES,
|
||||
ENDPOINT_LIBRUS_API_SUBSTITUTIONS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_AGENDA, listOf(
|
||||
ENDPOINT_LIBRUS_API_EVENTS,
|
||||
ENDPOINT_LIBRUS_API_EVENT_TYPES,
|
||||
ENDPOINT_LIBRUS_API_PT_MEETINGS,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS,
|
||||
ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS,
|
||||
ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GC,
|
||||
ENDPOINT_LIBRUS_API_POINT_GC,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC,
|
||||
ENDPOINT_LIBRUS_API_TEXT_GC,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES,
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADES,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_API_HOMEWORK
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_NOTICES, listOf(
|
||||
ENDPOINT_LIBRUS_API_NOTICES
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCES, listOf(
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE,
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_ME
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SCHOOL_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_SCHOOLS,
|
||||
ENDPOINT_LIBRUS_API_UNITS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSES
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf(
|
||||
ENDPOINT_LIBRUS_API_USERS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_SUBJECTS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSROOMS
|
||||
), LOGIN_METHOD_LIBRUS_API),
|
||||
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO
|
||||
), LOGIN_METHOD_LIBRUS_SYNERGIA),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO
|
||||
), LOGIN_METHOD_LIBRUS_SYNERGIA),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_GRADES
|
||||
), LOGIN_METHOD_LIBRUS_SYNERGIA),
|
||||
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf(ENDPOINT_LIBRUS_MESSAGES_RECEIVED), LOGIN_METHOD_LIBRUS_MESSAGES),
|
||||
Endpoint(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_OUTBOX, listOf(ENDPOINT_LIBRUS_MESSAGES_SENT), LOGIN_METHOD_LIBRUS_MESSAGES)
|
||||
)
|
||||
|
||||
/*
|
||||
|
@ -59,11 +59,6 @@ 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
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR = 134
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_TOKEN_ERROR = 135
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_DISCONNECTED = 136
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_410 = 137
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND = 138
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_OTHER = 139
|
||||
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
|
||||
@ -83,8 +78,22 @@ const val ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID = 154
|
||||
const val ERROR_LIBRUS_MESSAGES_ACCESS_DENIED = 155
|
||||
const val ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED = 156
|
||||
const val ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID = 157
|
||||
const val ERROR_LIBRUS_PORTAL_TOKEN_EXPIRED = 158
|
||||
const val ERROR_LIBRUS_PORTAL_API_DISABLED = 159
|
||||
const val ERROR_LIBRUS_PORTAL_SYNERGIA_DISCONNECTED = 160
|
||||
const val ERROR_LIBRUS_PORTAL_OTHER = 161
|
||||
const val ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND = 162
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_OTHER = 163
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_CODE_EXPIRED = 164
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_CODE_REVOKED = 165
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_NO_CLIENT_ID = 166
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_NO_CODE = 167
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_NO_REFRESH = 168
|
||||
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 EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901
|
||||
const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902
|
||||
const val EXCEPTION_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903
|
||||
const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903
|
||||
const val EXCEPTION_LIBRUS_API_REQUEST = 904
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_ATTENDANCES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_GRADES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOME
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORKS
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_NOTICES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.datamodels.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.datamodels.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.messages.MessagesListFragment
|
||||
|
||||
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_MESSAGES_INBOX = 7
|
||||
const val FEATURE_MESSAGES_OUTBOX = 8
|
||||
const val FEATURE_ANNOUNCEMENTS = 9
|
||||
|
||||
const val FEATURE_STUDENT_INFO = 101
|
||||
const val FEATURE_STUDENT_NUMBER = 109
|
||||
const val FEATURE_SCHOOL_INFO = 102
|
||||
const val FEATURE_CLASS_INFO = 103
|
||||
const val FEATURE_TEAM_INFO = 104
|
||||
const val FEATURE_LUCKY_NUMBER = 105
|
||||
const val FEATURE_TEACHERS = 106
|
||||
const val FEATURE_SUBJECTS = 107
|
||||
const val FEATURE_CLASSROOMS = 108
|
||||
|
||||
const val FEATURE_MESSAGE_GET = 201
|
||||
|
||||
object Features {
|
||||
private fun getAllNecessary(): List<Int> = listOf(
|
||||
FEATURE_STUDENT_INFO,
|
||||
FEATURE_STUDENT_NUMBER,
|
||||
FEATURE_SCHOOL_INFO,
|
||||
FEATURE_CLASS_INFO,
|
||||
FEATURE_TEAM_INFO,
|
||||
FEATURE_LUCKY_NUMBER,
|
||||
FEATURE_TEACHERS,
|
||||
FEATURE_SUBJECTS,
|
||||
FEATURE_CLASSROOMS)
|
||||
|
||||
private fun getAllFeatures(): List<Int> = listOf(
|
||||
FEATURE_TIMETABLE,
|
||||
FEATURE_AGENDA,
|
||||
FEATURE_GRADES,
|
||||
FEATURE_HOMEWORK,
|
||||
FEATURE_NOTICES,
|
||||
FEATURE_ATTENDANCES,
|
||||
FEATURE_MESSAGES_INBOX,
|
||||
FEATURE_MESSAGES_OUTBOX,
|
||||
FEATURE_ANNOUNCEMENTS)
|
||||
|
||||
fun getAllIds(): List<Int> = getAllFeatures() + getAllNecessary()
|
||||
|
||||
fun getIdsByView(targetId: Int): List<Int> {
|
||||
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) {
|
||||
TYPE_RECEIVED -> listOf(FEATURE_MESSAGES_INBOX)
|
||||
TYPE_SENT -> listOf(FEATURE_MESSAGES_OUTBOX)
|
||||
else -> listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_OUTBOX)
|
||||
}
|
||||
DRAWER_ITEM_HOMEWORKS -> listOf(FEATURE_HOMEWORK)
|
||||
DRAWER_ITEM_NOTICES -> listOf(FEATURE_NOTICES)
|
||||
DRAWER_ITEM_ATTENDANCES -> listOf(FEATURE_ATTENDANCES)
|
||||
DRAWER_ITEM_ANNOUNCEMENTS -> listOf(FEATURE_ANNOUNCEMENTS)
|
||||
else -> getAllFeatures()
|
||||
} + getAllNecessary()
|
||||
}
|
||||
}
|
@ -10,6 +10,8 @@ import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusMessages
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LoginLibrusSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||
|
||||
val SYNERGIA_API_ENABLED = "true".toBoolean()
|
||||
|
||||
const val LOGIN_TYPE_MOBIDZIENNIK = 1
|
||||
const val LOGIN_TYPE_LIBRUS = 2
|
||||
const val LOGIN_TYPE_IUCZNIOWIE = 3
|
||||
@ -37,14 +39,29 @@ const val LOGIN_METHOD_VULCAN_WEB = 100
|
||||
const val LOGIN_METHOD_VULCAN_API = 200
|
||||
|
||||
val librusLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_PORTAL, null, LoginLibrusPortal::class.java) { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_API, null, LoginLibrusApi::class.java) { _, loginStore ->
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_PORTAL, LoginLibrusPortal::class.java)
|
||||
.withIsPossible { _, loginStore ->
|
||||
loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL
|
||||
}
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_API, LoginLibrusApi::class.java)
|
||||
.withIsPossible { _, loginStore ->
|
||||
loginStore.mode != LOGIN_MODE_LIBRUS_SYNERGIA || SYNERGIA_API_ENABLED
|
||||
}
|
||||
.withRequiredLoginMethod { _, loginStore ->
|
||||
if (loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) LOGIN_METHOD_LIBRUS_PORTAL else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, listOf(FEATURE_GRADES, FEATURE_HOMEWORKS, FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_OUTBOX), LoginLibrusSynergia::class.java) { profile, _ ->
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_SYNERGIA, LoginLibrusSynergia::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_API else LOGIN_METHOD_NOT_NEEDED
|
||||
},
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, listOf(FEATURE_MESSAGES_INBOX, FEATURE_MESSAGES_OUTBOX), LoginLibrusMessages::class.java) { profile, _ ->
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_MESSAGES, LoginLibrusMessages::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
|
||||
class SyncErrorEvent(val error: ApiError)
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class SyncFinishedEvent
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class SyncProfileFinishedEvent(val profileId: Int)
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class SyncProgressEvent(val profileId: Int, val profileName: String?, val progress: Int, val progressRes: Int?)
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class SyncStartedEvent(val profileId: Int)
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.requests
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiTask
|
||||
|
||||
data class MessageGetRequest(override val profileId: Int, val messageId: Int) : ApiTask(profileId) {
|
||||
override fun toString(): String {
|
||||
return "MessageGetRequest(profileId=$profileId, messageId=$messageId)"
|
||||
}
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
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<Int>?) : ApiTask(profileId) {
|
||||
override fun toString(): String {
|
||||
return "SyncProfileRequest(profileId=$profileId, featureIds=$featureIds)"
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.requests
|
||||
|
||||
class SyncRequest()
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
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) {
|
||||
override fun toString(): String {
|
||||
return "SyncViewRequest(profileId=$profileId, targetId=$targetId)"
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Endpoint
|
||||
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,
|
||||
* but may only use [EndpointCallback]'s methods.
|
||||
*/
|
||||
interface EdziennikCallback : EndpointCallback {
|
||||
fun onCompleted()
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
||||
|
||||
interface EdziennikInterface {
|
||||
fun sync(featureIds: List<Int>)
|
||||
fun getMessage(messageId: Int)
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
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.LoginMethod
|
||||
|
||||
/**
|
||||
* A callback passed to all [Endpoint]s and [LoginMethod]s
|
||||
*/
|
||||
interface EndpointCallback {
|
||||
fun onError(apiError: ApiError)
|
||||
fun onProgress(step: Int)
|
||||
fun onStartProgress(stringRes: Int)
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
abstract class ILoginMethod(
|
||||
val app: App,
|
||||
val profile: Profile?,
|
||||
val loginStore: LoginStore,
|
||||
val callback: ProgressCallback,
|
||||
val onSuccess: () -> Unit
|
||||
) {
|
||||
|
||||
}
|
@ -9,22 +9,30 @@ import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.SyncCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikInterface
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull
|
||||
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: SyncCallback) {
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
lateinit var data: DataLibrus
|
||||
val data: DataLibrus
|
||||
|
||||
init {
|
||||
data = DataLibrus(app, profile, loginStore).apply {
|
||||
callback = wrapCallback(this@Librus.callback)
|
||||
}
|
||||
data.satisfyLoginMethods()
|
||||
}
|
||||
|
||||
override fun sync(featureIds: List<Int>) {
|
||||
|
||||
}
|
||||
|
||||
override fun getMessage(messageId: Int) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,6 @@ import pl.szczodrzynski.edziennik.api.interfaces.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.FirstLoginLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.FirstLoginSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.SynergiaTokenExtractor
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.MessageFull
|
||||
@ -15,10 +14,9 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
import pl.szczodrzynski.edziennik.datamodels.ProfileFull
|
||||
import pl.szczodrzynski.edziennik.messages.MessagesComposeInfo
|
||||
import pl.szczodrzynski.edziennik.models.Endpoint
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.lang.Exception
|
||||
|
||||
class LibrusOld(val app: App, val profile: Profile?, val loginStore: LoginStore) : EdziennikInterface {
|
||||
class LibrusOld(val app: App, val profile: Profile?, val loginStore: LoginStore) : OldEdziennikInterface {
|
||||
private val TAG = "librus.Librus"
|
||||
|
||||
lateinit var syncCallback: SyncCallback
|
||||
|
@ -5,6 +5,7 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
@ -30,21 +31,24 @@ class LibrusTest(val app: App) {
|
||||
|
||||
putStudentData("accountLogin", "1234567")
|
||||
|
||||
putStudentData("accountToken", "token")
|
||||
putStudentData("accountTokenTime", 1569523077)
|
||||
//putStudentData("accountToken", "token")
|
||||
//putStudentData("accountTokenTime", 1569458277)
|
||||
}
|
||||
val loginStore = LoginStore(1, LOGIN_TYPE_LIBRUS, JsonObject().apply {
|
||||
addProperty("email", "test@example.com")
|
||||
addProperty("password", "zaq1@WSX")
|
||||
|
||||
addProperty("accessToken", "token")
|
||||
addProperty("refreshToken", "refresh")
|
||||
addProperty("tokenExpiryTime", 1569523077)
|
||||
//addProperty("accessToken", "token")
|
||||
//addProperty("refreshToken", "refresh")
|
||||
//addProperty("tokenExpiryTime", 1569523077)
|
||||
}).also {
|
||||
it.mode = LOGIN_MODE_LIBRUS_EMAIL
|
||||
}
|
||||
|
||||
fun go() {
|
||||
|
||||
app.startService(Intent(app, ApiService::class.java))
|
||||
|
||||
val data = DataLibrus(app, profile, loginStore).apply {
|
||||
callback = object : ProgressCallback {
|
||||
override fun onProgress(progressStep: Int) {
|
||||
|
@ -19,10 +19,11 @@ class LoginLibrus(val data: DataLibrus, vararg loginMethodIds: Int, val onSucces
|
||||
|
||||
init {
|
||||
for (loginMethodId in loginMethodIds) {
|
||||
var requiredLoginMethod = loginMethodId
|
||||
var requiredLoginMethod: Int? = loginMethodId
|
||||
while (requiredLoginMethod != LOGIN_METHOD_NOT_NEEDED) {
|
||||
librusLoginMethods.singleOrNull { it.loginMethodId == requiredLoginMethod }?.let { loginMethod ->
|
||||
loginMethodList.add(requiredLoginMethod)
|
||||
if (requiredLoginMethod != null)
|
||||
loginMethodList.add(requiredLoginMethod!!)
|
||||
requiredLoginMethod = loginMethod.requiredLoginMethod(data.profile, data.loginStore)
|
||||
}
|
||||
}
|
||||
|
@ -9,14 +9,9 @@ import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
class LoginLibrusApi {
|
||||
@ -121,7 +116,7 @@ class LoginLibrusApi {
|
||||
data.error(TAG, ERROR_RESPONSE_EMPTY, response)
|
||||
return
|
||||
}
|
||||
json.getString("error")?.let { error ->
|
||||
if (response?.code() != 200) json.getString("error")?.let { error ->
|
||||
when (error) {
|
||||
"librus_captcha_needed" -> ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED
|
||||
"connection_problems" -> ERROR_LOGIN_LIBRUS_API_CONNECTION_PROBLEMS
|
||||
@ -140,7 +135,7 @@ class LoginLibrusApi {
|
||||
try {
|
||||
data.apiAccessToken = json.getString("access_token")
|
||||
data.apiRefreshToken = json.getString("refresh_token")
|
||||
data.apiTokenExpiryTime = currentTimeUnix() + json.getInt("expires_in", 86400)
|
||||
data.apiTokenExpiryTime = response.getUnixDate() + json.getInt("expires_in", 86400)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
data.error(TAG, EXCEPTION_LOGIN_LIBRUS_API_TOKEN, response, e, json)
|
||||
|
@ -13,6 +13,7 @@ import okhttp3.internal.http.HttpDate
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
|
||||
class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
@ -73,7 +74,7 @@ class LoginLibrusMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
return
|
||||
}
|
||||
data.messagesSessionId = sessionId
|
||||
data.messagesSessionIdExpiryTime = currentTimeUnix() + 3600 /* 1h */
|
||||
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,52 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
|
||||
private var refreshTokenFailed = false
|
||||
private fun accessToken(code: String?, refreshToken: String?) {
|
||||
data.callback.onActionStarted(R.string.sync_action_getting_token)
|
||||
val onSuccess = { json: JsonObject, response: Response? ->
|
||||
data.portalAccessToken = json.getString("access_token")
|
||||
data.portalRefreshToken = json.getString("refresh_token")
|
||||
data.portalTokenExpiryTime = response.getUnixDate() + json.getInt("expires_in", 86400)
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null) {
|
||||
data.error(TAG, ERROR_RESPONSE_EMPTY, response)
|
||||
return
|
||||
}
|
||||
val error = if (response?.code() == 200) null else
|
||||
json.getString("hint")
|
||||
error?.let { code ->
|
||||
when (code) {
|
||||
"Authorization code has expired" -> ERROR_LOGIN_LIBRUS_PORTAL_CODE_EXPIRED
|
||||
"Authorization code has been revoked" -> ERROR_LOGIN_LIBRUS_PORTAL_CODE_REVOKED
|
||||
"Check the `client_id` parameter" -> ERROR_LOGIN_LIBRUS_PORTAL_NO_CLIENT_ID
|
||||
"Check the `code` parameter" -> ERROR_LOGIN_LIBRUS_PORTAL_NO_CODE
|
||||
"Check the `refresh_token` parameter" -> ERROR_LOGIN_LIBRUS_PORTAL_NO_REFRESH
|
||||
"Check the `redirect_uri` parameter" -> ERROR_LOGIN_LIBRUS_PORTAL_NO_REDIRECT
|
||||
else -> when (json.getString("error")) {
|
||||
"unsupported_grant_type" -> ERROR_LOGIN_LIBRUS_PORTAL_UNSUPPORTED_GRANT
|
||||
"invalid_client" -> ERROR_LOGIN_LIBRUS_PORTAL_INVALID_CLIENT_ID
|
||||
else -> ERROR_LOGIN_LIBRUS_PORTAL_OTHER
|
||||
}
|
||||
}.let { errorCode ->
|
||||
data.error(TAG, errorCode, apiResponse = json, response = response)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(json, response)
|
||||
} catch (e: NullPointerException) {
|
||||
data.error(TAG, EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN, response, e, json)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
val params = ArrayList<Pair<String, Any>>()
|
||||
params.add(Pair("client_id", LIBRUS_CLIENT_ID))
|
||||
if (code != null) {
|
||||
@ -132,46 +177,14 @@ class LoginLibrusPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
params.add(Pair("grant_type", "refresh_token"))
|
||||
params.add(Pair("refresh_token", refreshToken))
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParams(params)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
if (json == null) {
|
||||
data.error(TAG, ERROR_RESPONSE_EMPTY, response)
|
||||
return
|
||||
}
|
||||
json.getString("error")?.let { error ->
|
||||
val hint = json.getString("hint", "")
|
||||
//val message = json.getString("message", "")
|
||||
if (!refreshTokenFailed && refreshToken != null && (hint == "Token has been revoked" || hint == "Token has expired")) {
|
||||
c(TAG, "refreshing the token failed. Trying to log in again.")
|
||||
refreshTokenFailed = true
|
||||
authorize(LIBRUS_AUTHORIZE_URL)
|
||||
return
|
||||
}
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_TOKEN_ERROR, response, apiResponse = json)
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
data.portalAccessToken = json.getString("access_token")
|
||||
data.portalRefreshToken = json.getString("refresh_token")
|
||||
data.portalTokenExpiryTime = currentTimeUnix() + json.getInt("expires_in", 86400)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
data.error(TAG, EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN, response, e, json)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable)
|
||||
}
|
||||
})
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
import java.lang.Exception
|
||||
import java.net.HttpURLConnection
|
||||
@ -75,7 +76,10 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
data.error(TAG, ERROR_RESPONSE_EMPTY, response)
|
||||
return
|
||||
}
|
||||
val error = json.getString("Code") ?: json.getString("Message") ?: response?.parserErrorBody
|
||||
val error = if (response?.code() == 200) null else
|
||||
json.getString("Code") ?:
|
||||
json.getString("Message") ?:
|
||||
response?.parserErrorBody
|
||||
error?.let { code ->
|
||||
when (code) {
|
||||
"TokenIsExpired" -> ERROR_LIBRUS_API_TOKEN_EXPIRED
|
||||
@ -145,7 +149,7 @@ class LoginLibrusSynergia(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
return
|
||||
}
|
||||
data.synergiaSessionId = sessionId
|
||||
data.synergiaSessionIdExpiryTime = currentTimeUnix() + 3600 /* 1h */
|
||||
data.synergiaSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
|
@ -33,16 +33,80 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
}
|
||||
else {
|
||||
if (!synergiaAccount()) {
|
||||
|
||||
data.error(TAG, ERROR_LOGIN_DATA_MISSING)
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
/**
|
||||
* Get an Api token from the Portal account, using Portal API.
|
||||
* If necessary, refreshes the token.
|
||||
*/
|
||||
private fun synergiaAccount(): Boolean {
|
||||
val accountLogin = data.apiLogin ?: return false
|
||||
val accessToken = data.portalAccessToken ?: return false
|
||||
data.callback.onActionStarted(R.string.sync_action_getting_account)
|
||||
d(TAG, "Requesting " + (LIBRUS_ACCOUNT_URL + accountLogin))
|
||||
|
||||
val onSuccess = { json: JsonObject, response: Response? ->
|
||||
// synergiaAccount is executed when a synergia token needs a refresh
|
||||
val accountId = json.getInt("id")
|
||||
val accountToken = json.getString("accessToken")
|
||||
if (accountId == null || accountToken == null) {
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING, response, apiResponse = json)
|
||||
}
|
||||
else {
|
||||
data.apiAccessToken = accountToken
|
||||
data.apiTokenExpiryTime = response.getUnixDate() + 6 * 60 * 60
|
||||
|
||||
// TODO remove this
|
||||
data.profile?.studentNameLong = json.getString("studentName")
|
||||
val nameParts = json.getString("studentName")?.split(" ")?.toTypedArray()
|
||||
data.profile?.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null) {
|
||||
data.error(TAG, ERROR_RESPONSE_EMPTY, response)
|
||||
return
|
||||
}
|
||||
val error = if (response?.code() == 200) null else
|
||||
json.getString("reason") ?:
|
||||
json.getString("message") ?:
|
||||
json.getString("hint") ?:
|
||||
json.getString("Code")
|
||||
error?.let { code ->
|
||||
when (code) {
|
||||
"requires_an_action" -> ERROR_LIBRUS_PORTAL_SYNERGIA_DISCONNECTED
|
||||
"Access token is invalid" -> ERROR_LIBRUS_PORTAL_TOKEN_EXPIRED
|
||||
"ApiDisabled" -> ERROR_LIBRUS_PORTAL_API_DISABLED
|
||||
"Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND
|
||||
else -> ERROR_LIBRUS_PORTAL_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(TAG, errorCode, apiResponse = json, response = response)
|
||||
return
|
||||
}
|
||||
}
|
||||
if (response?.code() == HTTP_OK) {
|
||||
try {
|
||||
onSuccess(json, response)
|
||||
} catch (e: NullPointerException) {
|
||||
e.printStackTrace()
|
||||
data.error(TAG, EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN, response, e, json)
|
||||
}
|
||||
|
||||
} else {
|
||||
data.error(TAG, ERROR_REQUEST_FAILURE, response, apiResponse = json)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable)
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_ACCOUNT_URL + accountLogin)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
@ -53,59 +117,7 @@ class SynergiaTokenExtractor(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_GONE)
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
if (json == null) {
|
||||
data.error(TAG, ERROR_RESPONSE_EMPTY, response)
|
||||
return
|
||||
}
|
||||
if (response.code() == 410) {
|
||||
val reason = json.get("reason")
|
||||
if (reason != null && reason !is JsonNull && reason.asString == "requires_an_action") {
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_DISCONNECTED, response, apiResponse = json)
|
||||
return
|
||||
}
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_410, response, apiResponse = json)
|
||||
return
|
||||
}
|
||||
if (json.get("message") != null) {
|
||||
val message = json.get("message").asString
|
||||
if (message == "Account not found") {
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND, response, apiResponse = json)
|
||||
return
|
||||
}
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_OTHER, response, apiResponse = json)
|
||||
return
|
||||
}
|
||||
if (response.code() == HTTP_OK) {
|
||||
try {
|
||||
// synergiaAccount is executed when a synergia token needs a refresh
|
||||
val accountId = json.getInt("id")
|
||||
val accountToken = json.getString("accessToken")
|
||||
if (accountId == null || accountToken == null) {
|
||||
data.error(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING, response, apiResponse = json)
|
||||
return
|
||||
}
|
||||
data.apiAccessToken = accountToken
|
||||
data.apiTokenExpiryTime = currentTimeUnix() + 6*60*60
|
||||
data.profile?.studentNameLong = json.getString("studentName")
|
||||
val nameParts = json.getString("studentName")?.split(" ")?.toTypedArray()
|
||||
data.profile?.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
e.printStackTrace()
|
||||
data.error(TAG, EXCEPTION_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN, response, e, json)
|
||||
}
|
||||
|
||||
} else {
|
||||
data.error(TAG, ERROR_REQUEST_FAILURE, response, apiResponse = json)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
data.error(TAG, ERROR_REQUEST_FAILURE, response, throwable)
|
||||
}
|
||||
})
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
return true
|
||||
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
|
||||
class ApiError(val profileId: Int, val tag: String, val errorCode: Int) {
|
||||
private var throwable: Throwable? = null
|
||||
private var apiResponse: String? = null
|
||||
private var request: Request? = null
|
||||
private var response: Response? = null
|
||||
|
||||
fun withThrowable(throwable: Throwable?): ApiError {
|
||||
this.throwable = throwable
|
||||
return this
|
||||
}
|
||||
fun withApiResponse(apiResponse: String?): ApiError {
|
||||
this.apiResponse = apiResponse
|
||||
return this
|
||||
}
|
||||
fun withApiResponse(apiResponse: JsonObject?): ApiError {
|
||||
this.apiResponse = apiResponse?.toString()
|
||||
return this
|
||||
}
|
||||
fun withRequest(request: Request?): ApiError {
|
||||
this.request = request
|
||||
return this
|
||||
}
|
||||
fun withResponse(response: Response?): ApiError {
|
||||
this.response = response
|
||||
this.request = response?.request()
|
||||
return this
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
|
||||
data class ApiLoginResult(val loginStore: LoginStore, val error: AppError?)
|
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
open class ApiTask(open val profileId: Int) {
|
||||
var taskId: Int = 0
|
||||
}
|
@ -7,15 +7,24 @@ import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Response
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.AppError.*
|
||||
import pl.szczodrzynski.edziennik.api.interfaces.ProgressCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EndpointCallback
|
||||
import pl.szczodrzynski.edziennik.datamodels.*
|
||||
import pl.szczodrzynski.edziennik.models.Date
|
||||
import java.io.InterruptedIOException
|
||||
import java.net.SocketTimeoutException
|
||||
import java.net.UnknownHostException
|
||||
import javax.net.ssl.SSLException
|
||||
|
||||
open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore) {
|
||||
|
||||
var fakeLogin = false
|
||||
|
||||
lateinit var callback: ProgressCallback
|
||||
/**
|
||||
* A callback passed to all [Endpoint]s and [LoginMethod]s
|
||||
*/
|
||||
lateinit var callback: EndpointCallback
|
||||
|
||||
/**
|
||||
* A list of [LoginMethod]s *already fulfilled* during this sync.
|
||||
@ -152,9 +161,25 @@ open class Data(val app: App, val profile: Profile?, val loginStore: LoginStore)
|
||||
}
|
||||
|
||||
fun error(tag: String, errorCode: Int, response: Response? = null, throwable: Throwable? = null, apiResponse: JsonObject? = null) {
|
||||
callback.onError(null, AppError(tag, 999, errorCode, response, throwable, apiResponse))
|
||||
var code = when (throwable) {
|
||||
is UnknownHostException, is SSLException, is InterruptedIOException -> CODE_NO_INTERNET
|
||||
is SocketTimeoutException -> CODE_TIMEOUT
|
||||
else -> when (response?.code()) {
|
||||
400, 401, 424, 500, 503, 404 -> CODE_MAINTENANCE
|
||||
else -> errorCode
|
||||
}
|
||||
}
|
||||
callback.onError(ApiError(profile?.id ?: -1, tag, code).withResponse(response).withThrowable(throwable).withApiResponse(apiResponse))
|
||||
}
|
||||
fun error(tag: String, errorCode: Int, response: Response? = null, apiResponse: String? = null) {
|
||||
callback.onError(null, AppError(tag, 999, errorCode, response, null, apiResponse))
|
||||
var code = when (null) {
|
||||
is UnknownHostException, is SSLException, is InterruptedIOException -> CODE_NO_INTERNET
|
||||
is SocketTimeoutException -> CODE_TIMEOUT
|
||||
else -> when (response?.code()) {
|
||||
400, 401, 424, 500, 503, 404 -> CODE_MAINTENANCE
|
||||
else -> errorCode
|
||||
}
|
||||
}
|
||||
callback.onError(ApiError(profile?.id ?: -1, tag, code).withResponse(response).withApiResponse(apiResponse))
|
||||
}
|
||||
}
|
@ -7,21 +7,18 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
* A Endpoint descriptor class.
|
||||
*
|
||||
* The API runs appropriate endpoints in order to fulfill its
|
||||
* [Feature] list.
|
||||
* feature list.
|
||||
* An endpoint may have its [LoginMethod] dependencies which will be
|
||||
* satisfied by the API before the [endpointClass]'s constructor is invoked.
|
||||
*
|
||||
* @param loginType type of the e-register this endpoint handles
|
||||
* @param endpointId a unique ID of this endpoint
|
||||
* @param featureIds a [List] of [Feature]s (their IDs) this endpoint can download
|
||||
* May be null if no strict feature set is associated with this method.
|
||||
* @param endpointClass a [Class] which constructor will be invoked when a data download is needed
|
||||
* @param requiredLoginMethod a lambda returning a required login method (which will be called before this). May differ depending on the [Profile] and/or [LoginStore].
|
||||
* @param featureId a feature ID
|
||||
* @param endpointIds a [List] of [Endpoint]s that satisfy this feature ID
|
||||
* @param requiredLoginMethod a required login method, which will have to be executed before this endpoint.
|
||||
*/
|
||||
class Endpoint(
|
||||
val loginType: Int,
|
||||
val endpointId: Int,
|
||||
val featureIds: List<Int>?,
|
||||
val endpointClass: Class<*>,
|
||||
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
||||
val featureId: Int,
|
||||
val endpointIds: List<Int>,
|
||||
val requiredLoginMethod: Int
|
||||
)
|
@ -1,11 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
|
||||
|
||||
data class Feature(val featureId: Int, val loginOptions: Map<Int, List<Int>>) {
|
||||
|
||||
init {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
|
||||
val Features = listOf(
|
||||
Feature(FEATURE_TIMETABLE, mapOf(
|
||||
LOGIN_TYPE_LIBRUS to listOf(
|
||||
LOGIN_MODE_LIBRUS_EMAIL,
|
||||
LOGIN_MODE_LIBRUS_SYNERGIA,
|
||||
LOGIN_MODE_LIBRUS_JST
|
||||
)
|
||||
))
|
||||
)
|
@ -1,6 +0,0 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.AppError
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
data class FirstLoginResult(val profileList: ArrayList<Profile>, val error: AppError?)
|
@ -4,6 +4,7 @@
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.models
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_NOT_NEEDED
|
||||
import pl.szczodrzynski.edziennik.datamodels.LoginStore
|
||||
import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
|
||||
@ -16,15 +17,30 @@ import pl.szczodrzynski.edziennik.datamodels.Profile
|
||||
*
|
||||
* @param loginType type of the e-register this login method handles
|
||||
* @param loginMethodId a unique ID of this login method
|
||||
* @param featureIds a [List] of [Feature]s (their IDs) this login method can provide access to
|
||||
* May be null if no strict feature set is associated with this method.
|
||||
* @param loginMethodClass a [Class] which constructor will be invoked when a log in is needed
|
||||
* @param requiredLoginMethod a lambda returning a required login method (which will be called before this). May differ depending on the [Profile] and/or [LoginStore].
|
||||
* @param requiredLoginMethod a required login method (which will be called before this). May differ depending on the [Profile] and/or [LoginStore].
|
||||
*/
|
||||
class LoginMethod(
|
||||
val loginType: Int,
|
||||
val loginMethodId: Int,
|
||||
val featureIds: List<Int>?,
|
||||
val loginMethodClass: Class<*>,
|
||||
val requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int
|
||||
)
|
||||
private var mIsPossible: ((profile: Profile?, loginStore: LoginStore) -> Boolean)? = null,
|
||||
private var mRequiredLoginMethod: ((profile: Profile?, loginStore: LoginStore) -> Int)? = null
|
||||
) {
|
||||
|
||||
fun withIsPossible(isPossible: (profile: Profile?, loginStore: LoginStore) -> Boolean): LoginMethod {
|
||||
this.mIsPossible = isPossible
|
||||
return this
|
||||
}
|
||||
fun withRequiredLoginMethod(requiredLoginMethod: (profile: Profile?, loginStore: LoginStore) -> Int): LoginMethod {
|
||||
this.mRequiredLoginMethod = requiredLoginMethod
|
||||
return this
|
||||
}
|
||||
|
||||
fun isPossible(profile: Profile?, loginStore: LoginStore): Boolean {
|
||||
return mIsPossible?.invoke(profile, loginStore) ?: false
|
||||
}
|
||||
fun requiredLoginMethod(profile: Profile?, loginStore: LoginStore): Int {
|
||||
return mRequiredLoginMethod?.invoke(profile, loginStore) ?: LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
}
|
@ -25,7 +25,10 @@ public interface ProfileDao {
|
||||
LiveData<ProfileFull> getById(int profileId);
|
||||
|
||||
@Query("SELECT profiles.*, loginStores.loginStoreType, loginStores.loginStoreData FROM profiles LEFT JOIN loginStores ON profiles.loginStoreId = loginStores.loginStoreId WHERE profileId = :profileId")
|
||||
ProfileFull getByIdNow(int profileId);
|
||||
ProfileFull getFullByIdNow(int profileId);
|
||||
|
||||
@Query("SELECT* FROM profiles WHERE profileId = :profileId")
|
||||
Profile getByIdNow(int profileId);
|
||||
|
||||
@Query("SELECT * FROM profiles WHERE profileId >= 0 ORDER BY profileId")
|
||||
LiveData<List<Profile>> getAll();
|
||||
@ -45,6 +48,9 @@ public interface ProfileDao {
|
||||
@Query("SELECT * FROM profiles WHERE syncEnabled = 1 AND archived = 0 AND profileId >= 0 ORDER BY profileId")
|
||||
List<Profile> getProfilesForSyncNow();
|
||||
|
||||
@Query("SELECT profileId FROM profiles WHERE syncEnabled = 1 AND archived = 0 AND profileId >= 0 ORDER BY profileId")
|
||||
List<Integer> getIdsForSyncNow();
|
||||
|
||||
@Query("SELECT profileId FROM profiles WHERE profileId >= 0 ORDER BY profileId")
|
||||
List<Integer> getIdsNow();
|
||||
|
||||
|
@ -425,7 +425,7 @@ public class EventManualDialog {
|
||||
return;
|
||||
this.app = _app;
|
||||
AsyncTask.execute(() -> {
|
||||
this.profile = app.db.profileDao().getByIdNow(profileId);
|
||||
this.profile = app.db.profileDao().getFullByIdNow(profileId);
|
||||
if (profile != null) {
|
||||
((Activity) context).runOnUiThread(() -> {
|
||||
actualShow(editingEvent, defaultDate, defaultTime, dialogType);
|
||||
|
@ -159,7 +159,7 @@ public class WidgetLuckyNumber extends AppWidgetProvider {
|
||||
}
|
||||
}
|
||||
|
||||
Profile profile = app.db.profileDao().getByIdNow(widgetConfig.profileId);
|
||||
Profile profile = app.db.profileDao().getFullByIdNow(widgetConfig.profileId);
|
||||
IIcon icon = CommunityMaterial.Icon.cmd_emoticon_dead_outline;
|
||||
boolean noNumberText = false;
|
||||
if (profile == null) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user