forked from github/szkolny
Compare commits
139 Commits
v3.2.2
...
code-refor
Author | SHA1 | Date | |
---|---|---|---|
8f80bc70ed | |||
e1d902ceb5 | |||
eb1984c6b5 | |||
399ae7e3dc | |||
22726f8566 | |||
d789d08f31 | |||
07863fed6f | |||
dcd355851d | |||
aa161b5b0e | |||
99ab9d586f | |||
33c009befe | |||
64019dccf7 | |||
e3bb607303 | |||
0b211c4f12 | |||
38d0a173af | |||
bf73c75872 | |||
dd99771c0b | |||
01657ca002 | |||
f2b3603531 | |||
d6d73b19ec | |||
2ad8a308b3 | |||
81c6275255 | |||
cfc5db2fe8 | |||
5e90e9aa71 | |||
debb0b1507 | |||
f452a1b81c | |||
42f70da162 | |||
4e8b80822b | |||
7ce7859a5f | |||
13b970f4e8 | |||
054426c9cc | |||
10c439afad | |||
46dd543b48 | |||
28e0f3487c | |||
ca10ee2fe5 | |||
3e99c111bd | |||
843a8e4298 | |||
454e8caa0d | |||
e38dc011bd | |||
9aef3d56df | |||
8c099bc137 | |||
de82bc7e4d | |||
5166228915 | |||
35ed31f6b9 | |||
05ce790587 | |||
ff7f015146 | |||
e2150e3018 | |||
bbf8f05d3c | |||
36c810fdbe | |||
7822810b91 | |||
9fefae3da3 | |||
74ce9cd38d | |||
bfcbeb7140 | |||
5d3bebfdce | |||
b8f58328cb | |||
3540b09623 | |||
25744037f5 | |||
0395598efb | |||
f44b64fcc5 | |||
2a7535920e | |||
9e6741d542 | |||
0e5a32b253 | |||
929287a553 | |||
a0fe24ada0 | |||
dd34e7d008 | |||
92fb83ccf9 | |||
b32ebe4479 | |||
e138ca6eab | |||
cf8afc03bc | |||
8dc358b075 | |||
24ab2e7795 | |||
c03eca3804 | |||
f79263e628 | |||
e91b4fcf8b | |||
0b7f9a08ef | |||
440b76d302 | |||
c433a615db | |||
7b5269a1fe | |||
33cfaef454 | |||
fe62c93602 | |||
bdc0ceb11d | |||
b35df5ef11 | |||
b59887d4e0 | |||
da9ccf6d29 | |||
6b80d7cbd0 | |||
0e17a70193 | |||
6ff439b20d | |||
70d35e12e5 | |||
7561087c78 | |||
42b56fa4a2 | |||
fb945470c0 | |||
4f9b9c5f7b | |||
3b273440cc | |||
b0fb87acdb | |||
0875d13737 | |||
39050cdee5 | |||
7594fdd578 | |||
93d5596942 | |||
93fcc0deb7 | |||
f6b50fbb58 | |||
cf0aa2788d | |||
67fbb96cd9 | |||
ed8ca00a85 | |||
7b3e2a9ea0 | |||
2730c73413 | |||
bbaa405c59 | |||
6127e574db | |||
1b53c35ec5 | |||
359fd4efed | |||
f7412fea7f | |||
f0bf6b8b81 | |||
7a06593821 | |||
ddf4fb0b46 | |||
535d608829 | |||
18e469af71 | |||
ce921b9b85 | |||
bb0a366ef1 | |||
fabacfdcca | |||
648699547e | |||
c8c933fb20 | |||
870a429f3d | |||
23a9f24d52 | |||
48a2ae3599 | |||
4c6b467847 | |||
92880d40cf | |||
d2f06a256f | |||
7da3101678 | |||
2ae6d2a4a0 | |||
0bf2026a64 | |||
5edd4d5922 | |||
2870931481 | |||
4cbb573d17 | |||
e95d9ee514 | |||
a785db4d47 | |||
76d39ac623 | |||
1bdee7857c | |||
3827aeb9b4 | |||
4b5c14cbd5 | |||
003ffa2251 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -47,6 +47,7 @@ captures/
|
||||
.idea/modules.xml
|
||||
# Comment next line if keeping position of elements in Navigation Editor is relevant for you
|
||||
.idea/navEditor.xml
|
||||
.idea/copyright/profiles_settings.xml
|
||||
|
||||
# Keystore files
|
||||
# Uncomment the following lines if you do not want to check your keystore files in.
|
||||
|
3
.idea/copyright/profiles_settings.xml
generated
3
.idea/copyright/profiles_settings.xml
generated
@ -1,3 +0,0 @@
|
||||
<component name="CopyrightManager">
|
||||
<settings default="kubasz" />
|
||||
</component>
|
5
.idea/misc.xml
generated
5
.idea/misc.xml
generated
@ -5,6 +5,11 @@
|
||||
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
|
||||
</configurations>
|
||||
</component>
|
||||
<component name="EntryPointsManager">
|
||||
<list size="1">
|
||||
<item index="0" class="java.lang.String" itemvalue="org.greenrobot.eventbus.Subscribe" />
|
||||
</list>
|
||||
</component>
|
||||
<component name="NullableNotNullManager">
|
||||
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
|
||||
<option name="myDefaultNotNull" value="androidx.annotation.RecentlyNonNull" />
|
||||
|
@ -49,6 +49,6 @@ dependencies {
|
||||
|
||||
// other libraries
|
||||
//implementation 'se.emilsjolander:stickylistheaders:2.7.0'
|
||||
implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT'
|
||||
implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar'
|
||||
implementation 'io.reactivex:rxjava:1.1.1'
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android-extensions'
|
||||
apply plugin: 'kotlin-android'
|
||||
apply plugin: 'kotlin-kapt'
|
||||
apply plugin: 'com.google.gms.google-services'
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
@ -91,7 +92,7 @@ tasks.whenTaskAdded { task ->
|
||||
dependencies {
|
||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||
|
||||
annotationProcessor "androidx.room:room-compiler:${versions.room}"
|
||||
kapt "androidx.room:room-compiler:${versions.room}"
|
||||
debugImplementation "com.amitshekhar.android:debug-db:1.0.5"
|
||||
|
||||
implementation "android.arch.navigation:navigation-fragment-ktx:${versions.navigationFragment}"
|
||||
@ -142,7 +143,7 @@ dependencies {
|
||||
implementation "org.jsoup:jsoup:1.10.1"
|
||||
implementation "pl.droidsonroids.gif:android-gif-drawable:1.2.15"
|
||||
//implementation "se.emilsjolander:stickylistheaders:2.7.0"
|
||||
implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT'
|
||||
implementation 'com.github.edisonw:StickyListHeaders:master-SNAPSHOT@aar'
|
||||
implementation "uk.co.samuelwall:material-tap-target-prompt:2.14.0"
|
||||
|
||||
implementation project(":agendacalendarview")
|
||||
@ -152,6 +153,23 @@ dependencies {
|
||||
implementation project(":nachos")
|
||||
//implementation project(":Navigation")
|
||||
implementation project(":szkolny-font")
|
||||
|
||||
debugImplementation "com.github.ChuckerTeam.Chucker:library:3.0.1"
|
||||
releaseImplementation "com.github.ChuckerTeam.Chucker:library-no-op:3.0.1"
|
||||
|
||||
//implementation 'com.github.wulkanowy:uonet-request-signer:master-SNAPSHOT'
|
||||
//implementation 'com.github.kuba2k2.uonet-request-signer:android:master-63f094b14a-1'
|
||||
|
||||
implementation "org.redundent:kotlin-xml-builder:1.5.3"
|
||||
|
||||
implementation "io.github.wulkanowy:signer-android:0.1.1"
|
||||
|
||||
implementation "androidx.work:work-runtime-ktx:${versions.work}"
|
||||
|
||||
api "com.google.dagger:dagger:${versions.dagger}"
|
||||
api "com.google.dagger:dagger-android-support:${versions.dagger}"
|
||||
kapt "com.google.dagger:dagger-compiler:${versions.dagger}"
|
||||
kapt "com.google.dagger:dagger-android-processor:${versions.dagger}"
|
||||
}
|
||||
repositories {
|
||||
mavenCentral()
|
||||
|
@ -204,6 +204,14 @@
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
<receiver
|
||||
android:name=".sync.FirebaseBroadcastReceiver"
|
||||
android:exported="true"
|
||||
android:permission="com.google.android.c2dm.permission.SEND">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<service
|
||||
android:name=".widgets.timetable.WidgetTimetableService"
|
||||
android:permission="android.permission.BIND_REMOTEVIEWS" />
|
||||
@ -214,10 +222,15 @@
|
||||
|
||||
<service android:name=".Notifier$GetDataRetryService" />
|
||||
|
||||
<service
|
||||
android:name=".sync.SyncService"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:label="@string/sync_service" />
|
||||
<receiver
|
||||
android:name=".receivers.SzkolnyReceiver"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="pl.szczodrzynski.edziennik.SZKOLNY_MAIN" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<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" />
|
||||
|
@ -20,7 +20,14 @@ import android.util.Base64;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
|
||||
import com.evernote.android.job.JobManager;
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import androidx.multidex.MultiDex;
|
||||
import androidx.work.Configuration;
|
||||
|
||||
import com.chuckerteam.chucker.api.ChuckerCollector;
|
||||
import com.chuckerteam.chucker.api.ChuckerInterceptor;
|
||||
import com.chuckerteam.chucker.api.RetentionManager;
|
||||
import com.google.android.gms.security.ProviderInstaller;
|
||||
import com.google.firebase.FirebaseApp;
|
||||
import com.google.firebase.FirebaseOptions;
|
||||
@ -52,9 +59,9 @@ import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
import androidx.appcompat.app.AppCompatDelegate;
|
||||
import cat.ereza.customactivityoncrash.config.CaocConfig;
|
||||
import dagger.android.AndroidInjector;
|
||||
import dagger.android.support.DaggerApplication;
|
||||
import im.wangchao.mhttp.MHttp;
|
||||
import im.wangchao.mhttp.internal.cookie.PersistentCookieJar;
|
||||
import im.wangchao.mhttp.internal.cookie.cache.SetCookieCache;
|
||||
@ -63,7 +70,6 @@ import me.leolin.shortcutbadger.ShortcutBadger;
|
||||
import okhttp3.ConnectionSpec;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.TlsVersion;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
||||
import pl.szczodrzynski.edziennik.data.api.Edziennik;
|
||||
import pl.szczodrzynski.edziennik.data.api.Iuczniowie;
|
||||
import pl.szczodrzynski.edziennik.data.api.Librus;
|
||||
@ -74,23 +80,33 @@ import pl.szczodrzynski.edziennik.data.db.modules.debuglog.DebugLog;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.utils.models.AppConfig;
|
||||
import pl.szczodrzynski.edziennik.di.DaggerAppComponent;
|
||||
import pl.szczodrzynski.edziennik.network.NetworkUtils;
|
||||
import pl.szczodrzynski.edziennik.network.TLSSocketFactory;
|
||||
import pl.szczodrzynski.edziennik.receivers.JobsCreator;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker;
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.CrashActivity;
|
||||
import pl.szczodrzynski.edziennik.utils.PermissionChecker;
|
||||
import pl.szczodrzynski.edziennik.utils.Themes;
|
||||
import pl.szczodrzynski.edziennik.utils.Utils;
|
||||
import pl.szczodrzynski.edziennik.utils.models.AppConfig;
|
||||
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_MOBIDZIENNIK;
|
||||
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_VULCAN;
|
||||
|
||||
public class App extends androidx.multidex.MultiDexApplication {
|
||||
public class App extends DaggerApplication implements Configuration.Provider {
|
||||
private static final String TAG = "App";
|
||||
public static int profileId = -1;
|
||||
private Context mContext;
|
||||
|
||||
@Override
|
||||
public Configuration getWorkManagerConfiguration() {
|
||||
return new Configuration.Builder()
|
||||
.setMinimumLoggingLevel(Log.VERBOSE)
|
||||
.build();
|
||||
}
|
||||
|
||||
|
||||
public static final int REQUEST_TIMEOUT = 10 * 1000;
|
||||
|
||||
// notifications
|
||||
@ -169,6 +185,17 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
return Icon.createWithBitmap(bitmap);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void attachBaseContext(Context base) {
|
||||
super.attachBaseContext(base);
|
||||
MultiDex.install(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
|
||||
return DaggerAppComponent.factory().create(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
@ -207,6 +234,33 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
|
||||
cookieJar = new PersistentCookieJar(new SetCookieCache(), new SharedPrefsCookiePersistor(this));
|
||||
|
||||
appSharedPrefs = getSharedPreferences(getString(R.string.preference_file_global), Context.MODE_PRIVATE);
|
||||
|
||||
loadConfig();
|
||||
|
||||
Themes.INSTANCE.setThemeInt(appConfig.appTheme);
|
||||
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
for (Signature signature: packageInfo.signatures) {
|
||||
byte[] signatureBytes = signature.toByteArray();
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
md.update(signatureBytes);
|
||||
this.signature = Base64.encodeToString(md.digest(), Base64.DEFAULT);
|
||||
//Log.d(TAG, "Signature is "+this.signature);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ("f054761fbdb6a238".equals(deviceId) || BuildConfig.DEBUG) {
|
||||
devMode = true;
|
||||
}
|
||||
else if (appConfig.devModePassword != null) {
|
||||
checkDevModePassword();
|
||||
}
|
||||
|
||||
OkHttpClient.Builder httpBuilder = new OkHttpClient.Builder()
|
||||
.cache(null)
|
||||
.followRedirects(true)
|
||||
@ -254,6 +308,12 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
}
|
||||
}
|
||||
|
||||
if (App.devMode || BuildConfig.DEBUG) {
|
||||
ChuckerCollector chuckerCollector = new ChuckerCollector(this, true, RetentionManager.Period.ONE_HOUR);
|
||||
ChuckerInterceptor chuckerInterceptor = new ChuckerInterceptor(this, chuckerCollector);
|
||||
httpBuilder.addInterceptor(chuckerInterceptor);
|
||||
}
|
||||
|
||||
http = httpBuilder.build();
|
||||
httpLazy = http.newBuilder().followRedirects(false).followSslRedirects(false).build();
|
||||
|
||||
@ -262,41 +322,13 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
|
||||
//register = new Register(mContext);
|
||||
|
||||
appSharedPrefs = getSharedPreferences(getString(R.string.preference_file_global), Context.MODE_PRIVATE);
|
||||
|
||||
loadConfig();
|
||||
|
||||
Themes.INSTANCE.setThemeInt(appConfig.appTheme);
|
||||
|
||||
//profileLoadById(appSharedPrefs.getInt("current_profile_id", 1));
|
||||
|
||||
try {
|
||||
PackageInfo packageInfo = getPackageManager().getPackageInfo(getPackageName(), PackageManager.GET_SIGNATURES);
|
||||
for (Signature signature: packageInfo.signatures) {
|
||||
byte[] signatureBytes = signature.toByteArray();
|
||||
MessageDigest md = MessageDigest.getInstance("SHA");
|
||||
md.update(signatureBytes);
|
||||
this.signature = Base64.encodeToString(md.digest(), Base64.DEFAULT);
|
||||
//Log.d(TAG, "Signature is "+this.signature);
|
||||
}
|
||||
}
|
||||
catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if ("f054761fbdb6a238".equals(deviceId)) {
|
||||
devMode = true;
|
||||
}
|
||||
else if (appConfig.devModePassword != null) {
|
||||
checkDevModePassword();
|
||||
}
|
||||
|
||||
JobManager.create(this).addJobCreator(new JobsCreator());
|
||||
if (appConfig.registerSyncEnabled) {
|
||||
SyncJob.schedule(this);
|
||||
SyncWorker.Companion.scheduleNext(this, false);
|
||||
}
|
||||
else {
|
||||
SyncJob.clear();
|
||||
SyncWorker.Companion.cancelNext(this);
|
||||
}
|
||||
|
||||
db.metadataDao().countUnseen().observeForever(count -> {
|
||||
@ -400,20 +432,20 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
FirebaseApp pushMobidziennikApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
new FirebaseOptions.Builder()
|
||||
.setApplicationId("1:1029629079999:android:58bb378dab031f42")
|
||||
.setGcmSenderId("1029629079999")
|
||||
.setApiKey("AIzaSyCi5LmsZ5BBCQnGtrdvWnp1bWLCNP8OWQE")
|
||||
.setApplicationId("1:747285019373:android:f6341bf7b158621d")
|
||||
.build(),
|
||||
"Mobidziennik"
|
||||
"Mobidziennik2"
|
||||
);
|
||||
|
||||
/*FirebaseApp pushLibrusApp = FirebaseApp.initializeApp(
|
||||
FirebaseApp pushLibrusApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
new FirebaseOptions.Builder()
|
||||
.setApiKey("AIzaSyDfTuEoYPKdv4aceEws1CO3n0-HvTndz-o")
|
||||
.setApplicationId("1:513056078587:android:1e29083b760af544")
|
||||
.build(),
|
||||
"Librus"
|
||||
);*/
|
||||
);
|
||||
|
||||
FirebaseApp pushVulcanApp = FirebaseApp.initializeApp(
|
||||
this,
|
||||
@ -434,10 +466,10 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
Log.d(TAG, "Token for Mobidziennik is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_MOBIDZIENNIK, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
});
|
||||
/*FirebaseInstanceId.getInstance(pushLibrusApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
FirebaseInstanceId.getInstance(pushLibrusApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for Librus is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
appConfig.fcmTokens.put(LOGIN_TYPE_LIBRUS, new Pair<>(instanceIdResult.getToken(), new ArrayList<>()));
|
||||
});*/
|
||||
});
|
||||
FirebaseInstanceId.getInstance(pushVulcanApp).getInstanceId().addOnSuccessListener(instanceIdResult -> {
|
||||
Log.d(TAG, "Token for Vulcan is " + instanceIdResult.getToken() + ", ID is " + instanceIdResult.getId());
|
||||
Pair<String, List<Integer>> pair = appConfig.fcmTokens.get(LOGIN_TYPE_VULCAN);
|
||||
@ -526,6 +558,7 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
appConfig = new AppConfig(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void saveConfig()
|
||||
{
|
||||
try {
|
||||
@ -606,7 +639,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) {
|
||||
@ -621,7 +654,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;
|
||||
@ -648,7 +681,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
|
||||
@ -700,16 +733,11 @@ public class App extends androidx.multidex.MultiDexApplication {
|
||||
|
||||
public void checkDevModePassword() {
|
||||
try {
|
||||
if (Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", appConfig.devModePassword).equals("ok here you go it's enabled now")) {
|
||||
devMode = true;
|
||||
}
|
||||
else {
|
||||
devMode = false;
|
||||
}
|
||||
devMode = Utils.AESCrypt.decrypt("nWFVxY65Pa8/aRrT7EylNAencmOD+IxUY2Gg/beiIWY=", appConfig.devModePassword).equals("ok here you go it's enabled now")
|
||||
|| BuildConfig.DEBUG;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
devMode = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -6,14 +6,23 @@ import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.util.LongSparseArray
|
||||
import android.util.SparseArray
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.util.forEach
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Response
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.navlib.R
|
||||
import pl.szczodrzynski.navlib.crc16
|
||||
import pl.szczodrzynski.navlib.getColorFromRes
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.zip.CRC32
|
||||
|
||||
|
||||
fun List<Teacher>.byId(id: Long) = firstOrNull { it.id == id }
|
||||
fun List<Teacher>.byNameFirstLast(nameFirstLast: String) = firstOrNull { it.name + " " + it.surname == nameFirstLast }
|
||||
@ -21,11 +30,25 @@ fun List<Teacher>.byNameLastFirst(nameLastFirst: String) = firstOrNull { it.surn
|
||||
fun List<Teacher>.byNameFDotLast(nameFDotLast: String) = firstOrNull { it.name + "." + it.surname == nameFDotLast }
|
||||
fun List<Teacher>.byNameFDotSpaceLast(nameFDotSpaceLast: String) = firstOrNull { it.name + ". " + it.surname == nameFDotSpaceLast }
|
||||
|
||||
fun JsonObject.getString(key: String): String? = get(key).let { if (it.isJsonNull) null else it.asString }
|
||||
fun JsonObject.getInt(key: String): Int? = get(key).let { if (it.isJsonNull) null else it.asInt }
|
||||
fun JsonObject.getLong(key: String): Long? = get(key).let { if (it.isJsonNull) null else it.asLong }
|
||||
fun JsonObject.getJsonObject(key: String): JsonObject? = get(key).let { if (it.isJsonNull) null else it.asJsonObject }
|
||||
fun JsonObject.getJsonArray(key: String): JsonArray? = get(key).let { if (it.isJsonNull) null else it.asJsonArray }
|
||||
fun JsonObject?.get(key: String): JsonElement? = this?.get(key)
|
||||
|
||||
fun JsonObject?.getBoolean(key: String): Boolean? = get(key)?.let { if (it.isJsonNull) null else it.asBoolean }
|
||||
fun JsonObject?.getString(key: String): String? = get(key)?.let { if (it.isJsonNull) null else it.asString }
|
||||
fun JsonObject?.getInt(key: String): Int? = get(key)?.let { if (it.isJsonNull) null else it.asInt }
|
||||
fun JsonObject?.getLong(key: String): Long? = get(key)?.let { if (it.isJsonNull) null else it.asLong }
|
||||
fun JsonObject?.getFloat(key: String): Float? = get(key)?.let { if(it.isJsonNull) null else it.asFloat }
|
||||
fun JsonObject?.getJsonObject(key: String): JsonObject? = get(key)?.let { if (it.isJsonNull) null else it.asJsonObject }
|
||||
fun JsonObject?.getJsonArray(key: String): JsonArray? = get(key)?.let { if (it.isJsonNull) null else it.asJsonArray }
|
||||
|
||||
fun JsonObject?.getBoolean(key: String, defaultValue: Boolean): Boolean = get(key)?.let { if (it.isJsonNull) defaultValue else it.asBoolean } ?: defaultValue
|
||||
fun JsonObject?.getString(key: String, defaultValue: String): String = get(key)?.let { if (it.isJsonNull) defaultValue else it.asString } ?: defaultValue
|
||||
fun JsonObject?.getInt(key: String, defaultValue: Int): Int = get(key)?.let { if (it.isJsonNull) defaultValue else it.asInt } ?: defaultValue
|
||||
fun JsonObject?.getLong(key: String, defaultValue: Long): Long = get(key)?.let { if (it.isJsonNull) defaultValue else it.asLong } ?: defaultValue
|
||||
fun JsonObject?.getFloat(key: String, defaultValue: Float): Float = get(key)?.let { if(it.isJsonNull) defaultValue else it.asFloat } ?: defaultValue
|
||||
fun JsonObject?.getJsonObject(key: String, defaultValue: JsonObject): JsonObject = get(key)?.let { if (it.isJsonNull) defaultValue else it.asJsonObject } ?: defaultValue
|
||||
fun JsonObject?.getJsonArray(key: String, defaultValue: JsonArray): JsonArray = get(key)?.let { if (it.isJsonNull) defaultValue else it.asJsonArray } ?: defaultValue
|
||||
|
||||
fun JsonArray?.asJsonObjectList() = this?.map { it.asJsonObject }
|
||||
|
||||
fun CharSequence?.isNotNullNorEmpty(): Boolean {
|
||||
return this != null && this.isNotEmpty()
|
||||
@ -46,8 +69,56 @@ fun Bundle?.getString(key: String, defaultValue: String): String {
|
||||
return this?.getString(key, defaultValue) ?: defaultValue
|
||||
}
|
||||
|
||||
fun String.fixName(): String {
|
||||
return this.fixWhiteSpaces().toProperCase()
|
||||
}
|
||||
|
||||
fun String.toProperCase(): String = changeStringCase(this)
|
||||
|
||||
fun String.swapFirstLastName(): String {
|
||||
return this.split(" ").let {
|
||||
if (it.size > 1)
|
||||
it[1]+" "+it[0]
|
||||
else
|
||||
it[0]
|
||||
}
|
||||
}
|
||||
|
||||
fun changeStringCase(s: String): String {
|
||||
val delimiters = " '-/"
|
||||
val sb = StringBuilder()
|
||||
var capNext = true
|
||||
for (ch in s.toCharArray()) {
|
||||
var c = ch
|
||||
c = if (capNext)
|
||||
Character.toUpperCase(c)
|
||||
else
|
||||
Character.toLowerCase(c)
|
||||
sb.append(c)
|
||||
capNext = delimiters.indexOf(c) >= 0
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
fun buildFullName(firstName: String?, lastName: String?): String {
|
||||
return "$firstName $lastName".fixName()
|
||||
}
|
||||
|
||||
fun String.getShortName(): String {
|
||||
return split(" ").let {
|
||||
if (it.size > 1)
|
||||
"${it[0]} ${it[1][0]}."
|
||||
else
|
||||
it[0]
|
||||
}
|
||||
}
|
||||
|
||||
fun List<String>.join(delimiter: String): String {
|
||||
return this.joinToString(delimiter)
|
||||
}
|
||||
|
||||
fun colorFromName(context: Context, name: String?): Int {
|
||||
var crc = crc16(name ?: "")
|
||||
var crc = (name ?: "").crc16()
|
||||
crc = (crc and 0xff) or (crc shr 8)
|
||||
crc %= 16
|
||||
val color = when (crc) {
|
||||
@ -87,3 +158,172 @@ 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
|
||||
}
|
||||
|
||||
const val MINUTE = 60L
|
||||
const val HOUR = 60L*MINUTE
|
||||
const val DAY = 24L*HOUR
|
||||
const val WEEK = 7L*DAY
|
||||
const val MONTH = 30L*DAY
|
||||
const val YEAR = 365L*DAY
|
||||
|
||||
fun <T> LongSparseArray<T>.values(): List<T> {
|
||||
val result = mutableListOf<T>()
|
||||
forEach { _, value ->
|
||||
result += value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T> SparseArray<T>.values(): List<T> {
|
||||
val result = mutableListOf<T>()
|
||||
forEach { _, value ->
|
||||
result += value
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T> List<T>.toSparseArray(destination: SparseArray<T>, key: (T) -> Int) {
|
||||
forEach {
|
||||
destination.put(key(it), it)
|
||||
}
|
||||
}
|
||||
fun <T> List<T>.toSparseArray(destination: LongSparseArray<T>, key: (T) -> Long) {
|
||||
forEach {
|
||||
destination.put(key(it), it)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> List<T>.toSparseArray(key: (T) -> Int): SparseArray<T> {
|
||||
val result = SparseArray<T>()
|
||||
toSparseArray(result, key)
|
||||
return result
|
||||
}
|
||||
fun <T> List<T>.toSparseArray(key: (T) -> Long): LongSparseArray<T> {
|
||||
val result = LongSparseArray<T>()
|
||||
toSparseArray(result, key)
|
||||
return result
|
||||
}
|
||||
|
||||
fun <T> SparseArray<T>.singleOrNull(predicate: (T) -> Boolean): T? {
|
||||
forEach { _, value ->
|
||||
if (predicate(value))
|
||||
return value
|
||||
}
|
||||
return null
|
||||
}
|
||||
fun <T> LongSparseArray<T>.singleOrNull(predicate: (T) -> Boolean): T? {
|
||||
forEach { _, value ->
|
||||
if (predicate(value))
|
||||
return value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun String.fixWhiteSpaces() = buildString(length) {
|
||||
var wasWhiteSpace = true
|
||||
for (c in this@fixWhiteSpaces) {
|
||||
if (c.isWhitespace()) {
|
||||
if (!wasWhiteSpace) {
|
||||
append(c)
|
||||
wasWhiteSpace = true
|
||||
}
|
||||
} else {
|
||||
append(c)
|
||||
wasWhiteSpace = false
|
||||
}
|
||||
}
|
||||
}.trimEnd()
|
||||
|
||||
fun List<Team>.getById(id: Long): Team? {
|
||||
return singleOrNull { it.id == id }
|
||||
}
|
||||
fun LongSparseArray<Team>.getById(id: Long): Team? {
|
||||
forEach { _, value ->
|
||||
if (value.id == id)
|
||||
return value
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
operator fun MatchResult.get(group: Int): String {
|
||||
if (group >= groupValues.size)
|
||||
return ""
|
||||
return groupValues[group]
|
||||
}
|
||||
|
||||
fun Activity.setLanguage(language: String) {
|
||||
val locale = Locale(language.toLowerCase(Locale.ROOT))
|
||||
val configuration = resources.configuration
|
||||
Locale.setDefault(locale)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
configuration.setLocale(locale)
|
||||
}
|
||||
configuration.locale = locale
|
||||
resources.updateConfiguration(configuration, resources.displayMetrics)
|
||||
baseContext.resources.updateConfiguration(configuration, baseContext.resources.displayMetrics)
|
||||
}
|
||||
|
||||
/*
|
||||
Code copied from android-28/java.util.Locale.initDefault()
|
||||
*/
|
||||
fun initDefaultLocale() {
|
||||
run {
|
||||
// user.locale gets priority
|
||||
/*val languageTag: String? = System.getProperty("user.locale", "")
|
||||
if (languageTag.isNotNullNorEmpty()) {
|
||||
return@run Locale(languageTag)
|
||||
}*/
|
||||
|
||||
// user.locale is empty
|
||||
val language: String? = System.getProperty("user.language", "pl")
|
||||
val region: String? = System.getProperty("user.region")
|
||||
val country: String?
|
||||
val variant: String?
|
||||
// for compatibility, check for old user.region property
|
||||
if (region != null) {
|
||||
// region can be of form country, country_variant, or _variant
|
||||
val i = region.indexOf('_')
|
||||
if (i >= 0) {
|
||||
country = region.substring(0, i)
|
||||
variant = region.substring(i + 1)
|
||||
} else {
|
||||
country = region
|
||||
variant = ""
|
||||
}
|
||||
} else {
|
||||
country = System.getProperty("user.country", "")
|
||||
variant = System.getProperty("user.variant", "")
|
||||
}
|
||||
return@run Locale(language)
|
||||
}.let {
|
||||
Locale.setDefault(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun String.crc16(): Int {
|
||||
var crc = 0xFFFF
|
||||
for (aBuffer in this) {
|
||||
crc = crc.ushr(8) or (crc shl 8) and 0xffff
|
||||
crc = crc xor (aBuffer.toInt() and 0xff) // byte to int, trunc sign
|
||||
crc = crc xor (crc and 0xff shr 4)
|
||||
crc = crc xor (crc shl 12 and 0xffff)
|
||||
crc = crc xor (crc and 0xFF shl 5 and 0xffff)
|
||||
}
|
||||
crc = crc and 0xffff
|
||||
return crc + 32768
|
||||
}
|
||||
|
||||
fun String.crc32(): Long {
|
||||
val crc = CRC32()
|
||||
crc.update(toByteArray())
|
||||
return crc.value
|
||||
}
|
||||
|
||||
fun Long.formatDate(format: String = "yyyy-MM-dd HH:mm:ss"): String = SimpleDateFormat(format).format(this)
|
@ -2,84 +2,83 @@ package pl.szczodrzynski.edziennik
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.content.*
|
||||
import android.graphics.BitmapFactory
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.os.*
|
||||
import android.util.Log
|
||||
import android.view.Gravity
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.lifecycle.Observer
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
|
||||
import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet
|
||||
import pl.szczodrzynski.navlib.drawer.NavDrawer
|
||||
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
|
||||
import pl.szczodrzynski.navlib.drawer.items.withAppTitle
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.graphics.ColorUtils
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.navigation.NavOptions
|
||||
import com.danimahardhika.cafebar.CafeBar
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||
import com.mikepenz.iconics.IconicsColor
|
||||
import com.mikepenz.iconics.IconicsDrawable
|
||||
import com.mikepenz.iconics.IconicsSize
|
||||
import com.mikepenz.iconics.typeface.library.community.material.CommunityMaterial
|
||||
import com.mikepenz.iconics.typeface.library.szkolny.font.SzkolnyFont
|
||||
import com.mikepenz.materialdrawer.model.DividerDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.ProfileDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.ProfileSettingDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.interfaces.IDrawerItem
|
||||
import com.mikepenz.materialdrawer.model.interfaces.IProfile
|
||||
import me.zhanghai.android.materialprogressbar.internal.ThemeUtils
|
||||
import dagger.android.support.DaggerAppCompatActivity
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.droidsonroids.gif.GifDrawable
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.EdziennikInterface.*
|
||||
import pl.szczodrzynski.edziennik.data.api.interfaces.SyncCallback
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata.*
|
||||
import pl.szczodrzynski.edziennik.databinding.ActivitySzkolnyBinding
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesDetailsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob
|
||||
import pl.szczodrzynski.edziennik.sync.AppManagerDetectedEvent
|
||||
import pl.szczodrzynski.edziennik.sync.SyncWorker
|
||||
import pl.szczodrzynski.edziennik.ui.dialogs.changelog.ChangelogDialog
|
||||
import pl.szczodrzynski.edziennik.ui.modules.agenda.AgendaFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.announcements.AnnouncementsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.attendance.AttendanceFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.base.DebugFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.FeedbackFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.feedback.HelpFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.GradesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.grades.editor.GradesEditorFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.home.HomeFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.behaviour.BehaviourFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.homework.HomeworkFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.login.LoginActivity
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesDetailsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.messages.MessagesFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.notifications.NotificationsFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.ProfileManagerFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.settings.SettingsNewFragment
|
||||
import pl.szczodrzynski.edziennik.ui.modules.timetable.TimetableFragment
|
||||
import pl.szczodrzynski.edziennik.utils.SwipeRefreshLayoutNoTouch
|
||||
import pl.szczodrzynski.edziennik.utils.Themes
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.dpToPx
|
||||
import pl.szczodrzynski.edziennik.utils.models.NavTarget
|
||||
import pl.szczodrzynski.navlib.*
|
||||
import pl.szczodrzynski.navlib.SystemBarsUtil.Companion.COLOR_HALF_TRANSPARENT
|
||||
import pl.szczodrzynski.navlib.bottomsheet.NavBottomSheet
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetPrimaryItem
|
||||
import pl.szczodrzynski.navlib.bottomsheet.items.BottomSheetSeparatorItem
|
||||
import pl.szczodrzynski.navlib.drawer.NavDrawer
|
||||
import pl.szczodrzynski.navlib.drawer.items.DrawerPrimaryItem
|
||||
import pl.szczodrzynski.navlib.drawer.items.withAppTitle
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class MainActivity : AppCompatActivity() {
|
||||
class MainActivity : DaggerAppCompatActivity() {
|
||||
companion object {
|
||||
|
||||
var useOldMessages = false
|
||||
@ -236,6 +235,10 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
setTheme(Themes.appTheme)
|
||||
|
||||
app.appConfig.language?.let {
|
||||
setLanguage(it)
|
||||
}
|
||||
|
||||
setContentView(b.root)
|
||||
|
||||
navLoading = true
|
||||
@ -337,7 +340,7 @@ class MainActivity : AppCompatActivity() {
|
||||
if (!profileListEmpty) {
|
||||
handleIntent(intent?.extras)
|
||||
}
|
||||
app.db.profileDao().getAllFull().observe(this, Observer { profiles ->
|
||||
app.db.profileDao().allFull.observe(this, Observer { profiles ->
|
||||
// TODO fix weird -1 profiles ???
|
||||
profiles.removeAll { it.id < 0 }
|
||||
drawer.setProfileList(profiles)
|
||||
@ -354,7 +357,7 @@ class MainActivity : AppCompatActivity() {
|
||||
if (app.profile != null)
|
||||
setDrawerItems()
|
||||
|
||||
app.db.metadataDao().getUnreadCounts().observe(this, Observer { unreadCounters ->
|
||||
app.db.metadataDao().unreadCounts.observe(this, Observer { unreadCounters ->
|
||||
unreadCounters.map {
|
||||
it.type = it.thingType
|
||||
}
|
||||
@ -366,7 +369,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
isStoragePermissionGranted()
|
||||
|
||||
SyncJob.schedule(app)
|
||||
SyncWorker.scheduleNext(app)
|
||||
|
||||
// APP BACKGROUND
|
||||
if (app.appConfig.appBackground != null) {
|
||||
@ -474,6 +477,13 @@ class MainActivity : AppCompatActivity() {
|
||||
.withIcon(CommunityMaterial.Icon.cmd_android_debug_bridge)
|
||||
.withOnClickListener(View.OnClickListener { loadTarget(DRAWER_ITEM_DEBUG) })
|
||||
}
|
||||
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
var profileListEmptyListener = {
|
||||
@ -488,7 +498,7 @@ class MainActivity : AppCompatActivity() {
|
||||
profileListEmptyListener()
|
||||
}
|
||||
DRAWER_PROFILE_SYNC_ALL -> {
|
||||
SyncJob.run(app)
|
||||
EdziennikTask.sync().enqueue(this)
|
||||
}
|
||||
else -> {
|
||||
loadTarget(id)
|
||||
@ -508,36 +518,102 @@ class MainActivity : AppCompatActivity() {
|
||||
fun syncCurrentFeature() {
|
||||
swipeRefreshLayout.isRefreshing = true
|
||||
Toast.makeText(this, fragmentToSyncName(navTargetId), Toast.LENGTH_SHORT).show()
|
||||
val callback = object : SyncCallback {
|
||||
override fun onLoginFirst(profileList: List<Profile>, loginStore: LoginStore) {
|
||||
|
||||
ApiService.start(this)
|
||||
val fragmentParam = when (navTargetId) {
|
||||
DRAWER_ITEM_MESSAGES -> MessagesFragment.pageSelection
|
||||
else -> 0
|
||||
}
|
||||
EventBus.getDefault().postSticky(
|
||||
EdziennikTask.syncProfile(
|
||||
App.profileId,
|
||||
listOf(navTargetId to fragmentParam)
|
||||
)
|
||||
)
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncStartedEvent(event: ApiTaskStartedEvent) {
|
||||
swipeRefreshLayout.isRefreshing = true
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = null
|
||||
subtitleFormatWithUnread = null
|
||||
subtitle = getString(R.string.toolbar_subtitle_syncing)
|
||||
}
|
||||
|
||||
override fun onSuccess(activityContext: Context, profileFull: ProfileFull) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
|
||||
override fun onError(activityContext: Context, error: AppError) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
app.apiEdziennik.guiShowErrorSnackbar(this@MainActivity, error)
|
||||
}
|
||||
|
||||
override fun onProgress(progressStep: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun onActionStarted(stringResId: Int) {
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncProgressEvent(event: ApiTaskProgressEvent) {
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = null
|
||||
subtitleFormatWithUnread = null
|
||||
subtitle = if (event.progress < 0f)
|
||||
event.progressText ?: ""
|
||||
else
|
||||
getString(R.string.toolbar_subtitle_syncing_format, event.progress.roundToInt(), event.progressText ?: "")
|
||||
|
||||
}
|
||||
}
|
||||
val feature = fragmentToFeature(navTargetId)
|
||||
if (feature == FEATURE_ALL) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
app.apiEdziennik.guiSync(app, this, App.profileId, R.string.sync_dialog_title, R.string.sync_dialog_text, R.string.sync_done)
|
||||
} else {
|
||||
app.apiEdziennik.guiSyncSilent(app, this, App.profileId, callback, feature)
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncProfileFinishedEvent(event: ApiTaskFinishedEvent) {
|
||||
if (event.profileId == App.profileId) {
|
||||
navView.toolbar.apply {
|
||||
subtitleFormat = R.string.toolbar_subtitle
|
||||
subtitleFormatWithUnread = R.plurals.toolbar_subtitle_with_unread
|
||||
subtitle = "Gotowe"
|
||||
}
|
||||
}
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncFinishedEvent(event: ApiTaskAllFinishedEvent) {
|
||||
swipeRefreshLayout.isRefreshing = false
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
fun onSyncErrorEvent(event: ApiTaskErrorEvent) {
|
||||
|
||||
}
|
||||
@Subscribe(threadMode = ThreadMode.MAIN, sticky = true)
|
||||
fun onAppManagerDetectedEvent(event: AppManagerDetectedEvent) {
|
||||
if (app.appConfig.dontShowAppManagerDialog)
|
||||
return
|
||||
MaterialAlertDialogBuilder(this)
|
||||
.setTitle(R.string.app_manager_dialog_title)
|
||||
.setMessage(R.string.app_manager_dialog_text)
|
||||
.setPositiveButton(R.string.ok) { dialog, which ->
|
||||
try {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
"com.huawei.systemmanager",
|
||||
"com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity"
|
||||
)
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
try {
|
||||
val intent = Intent()
|
||||
intent.component = ComponentName(
|
||||
"com.asus.mobilemanager",
|
||||
"com.asus.mobilemanager.MainActivity"
|
||||
)
|
||||
startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
startActivity(Intent(android.provider.Settings.ACTION_SETTINGS))
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
Toast.makeText(this, R.string.app_manager_open_failed, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.setNeutralButton(R.string.dont_ask_again) { dialog, which ->
|
||||
app.appConfig.dontShowAppManagerDialog = true
|
||||
app.saveConfig("dontShowAppManagerDialog")
|
||||
}
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
}
|
||||
private fun fragmentToFeature(currentFragment: Int): Int {
|
||||
return when (currentFragment) {
|
||||
DRAWER_ITEM_TIMETABLE -> FEATURE_TIMETABLE
|
||||
@ -584,11 +660,11 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
private fun handleIntent(extras: Bundle?) {
|
||||
|
||||
Log.d(TAG, "handleIntent() {")
|
||||
d(TAG, "handleIntent() {")
|
||||
extras?.keySet()?.forEach { key ->
|
||||
Log.d(TAG, " \"$key\": "+extras.get(key))
|
||||
d(TAG, " \"$key\": "+extras.get(key))
|
||||
}
|
||||
Log.d(TAG, "}")
|
||||
d(TAG, "}")
|
||||
|
||||
if (extras?.containsKey("reloadProfileId") == true) {
|
||||
val reloadProfileId = extras.getInt("reloadProfileId", -1)
|
||||
@ -712,7 +788,7 @@ class MainActivity : AppCompatActivity() {
|
||||
fun loadProfile(id: Int) = loadProfile(id, navTargetId)
|
||||
fun loadProfile(id: Int, arguments: Bundle?) = loadProfile(id, navTargetId, arguments)
|
||||
fun loadProfile(id: Int, drawerSelection: Int, arguments: Bundle? = null) {
|
||||
Log.d("NavDebug", "loadProfile(id = $id, drawerSelection = $drawerSelection)")
|
||||
d("NavDebug", "loadProfile(id = $id, drawerSelection = $drawerSelection)")
|
||||
if (app.profile != null && App.profileId == id) {
|
||||
drawer.currentProfile = app.profile.id
|
||||
loadTarget(drawerSelection, arguments)
|
||||
@ -752,7 +828,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
private fun loadTarget(target: NavTarget, arguments: Bundle? = null) {
|
||||
Log.d("NavDebug", "loadItem(id = ${target.id})")
|
||||
d("NavDebug", "loadItem(id = ${target.id})")
|
||||
|
||||
bottomSheet.close()
|
||||
bottomSheet.removeAllContextual()
|
||||
@ -765,7 +841,7 @@ class MainActivity : AppCompatActivity() {
|
||||
navView.bottomBar.fabExtended = false
|
||||
navView.bottomBar.setFabOnClickListener(null)
|
||||
|
||||
Log.d("NavDebug", "Navigating from ${navTarget.fragmentClass?.java?.simpleName} to ${target.fragmentClass?.java?.simpleName}")
|
||||
d("NavDebug", "Navigating from ${navTarget.fragmentClass?.java?.simpleName} to ${target.fragmentClass?.java?.simpleName}")
|
||||
|
||||
val fragment = target.fragmentClass?.java?.newInstance() ?: return
|
||||
fragment.arguments = arguments
|
||||
@ -824,9 +900,9 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
Log.d("NavDebug", "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:")
|
||||
d("NavDebug", "Current fragment ${navTarget.fragmentClass?.java?.simpleName}, pop to home ${navTarget.popToHome}, back stack:")
|
||||
navBackStack.forEachIndexed { index, target2 ->
|
||||
Log.d("NavDebug", " - $index: ${target2.fragmentClass?.java?.simpleName}")
|
||||
d("NavDebug", " - $index: ${target2.fragmentClass?.java?.simpleName}")
|
||||
}
|
||||
|
||||
transaction.replace(R.id.fragment, fragment)
|
||||
@ -917,7 +993,7 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
fun setDrawerItems() {
|
||||
Log.d("NavDebug", "setDrawerItems() app.profile = ${app.profile ?: "null"}")
|
||||
d("NavDebug", "setDrawerItems() app.profile = ${app.profile ?: "null"}")
|
||||
val drawerItems = arrayListOf<IDrawerItem<*>>()
|
||||
val drawerProfiles = arrayListOf<ProfileSettingDrawerItem>()
|
||||
|
||||
|
@ -8,24 +8,22 @@ import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.ProfileFull;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.receivers.BootReceiver;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncService;
|
||||
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_DEFAULT;
|
||||
import static androidx.core.app.NotificationCompat.PRIORITY_MAX;
|
||||
import static pl.szczodrzynski.edziennik.sync.SyncService.ACTION_CANCEL;
|
||||
|
||||
public class Notifier {
|
||||
|
||||
@ -36,14 +34,14 @@ public class Notifier {
|
||||
private static String CHANNEL_GET_DATA_DESC;
|
||||
private static final String GROUP_KEY_GET_DATA = "pl.szczodrzynski.edziennik.GET_DATA";
|
||||
|
||||
private static final int ID_NOTIFICATIONS = 1337002;
|
||||
private static String CHANNEL_NOTIFICATIONS_NAME;
|
||||
private static String CHANNEL_NOTIFICATIONS_DESC;
|
||||
public static final int ID_NOTIFICATIONS = 1337002;
|
||||
public static String CHANNEL_NOTIFICATIONS_NAME;
|
||||
public static String CHANNEL_NOTIFICATIONS_DESC;
|
||||
public static final String GROUP_KEY_NOTIFICATIONS = "pl.szczodrzynski.edziennik.NOTIFICATIONS";
|
||||
|
||||
private static final int ID_NOTIFICATIONS_QUIET = 1337002;
|
||||
private static String CHANNEL_NOTIFICATIONS_QUIET_NAME;
|
||||
private static String CHANNEL_NOTIFICATIONS_QUIET_DESC;
|
||||
public static final int ID_NOTIFICATIONS_QUIET = 1337002;
|
||||
public static String CHANNEL_NOTIFICATIONS_QUIET_NAME;
|
||||
public static String CHANNEL_NOTIFICATIONS_QUIET_DESC;
|
||||
public static final String GROUP_KEY_NOTIFICATIONS_QUIET = "pl.szczodrzynski.edziennik.NOTIFICATIONS_QUIET";
|
||||
|
||||
private static final int ID_UPDATES = 1337003;
|
||||
@ -52,9 +50,9 @@ public class Notifier {
|
||||
private static final String GROUP_KEY_UPDATES = "pl.szczodrzynski.edziennik.UPDATES";
|
||||
|
||||
private App app;
|
||||
private NotificationManager notificationManager;
|
||||
public NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder getDataNotificationBuilder;
|
||||
private int notificationColor;
|
||||
public int notificationColor;
|
||||
|
||||
Notifier(App _app) {
|
||||
this.app = _app;
|
||||
@ -71,7 +69,7 @@ public class Notifier {
|
||||
notificationColor = ContextCompat.getColor(app.getContext(), R.color.colorPrimary);
|
||||
notificationManager = (NotificationManager) app.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
NotificationChannel channelGetData = new NotificationChannel(GROUP_KEY_GET_DATA, CHANNEL_GET_DATA_NAME, NotificationManager.IMPORTANCE_LOW);
|
||||
NotificationChannel channelGetData = new NotificationChannel(GROUP_KEY_GET_DATA, CHANNEL_GET_DATA_NAME, NotificationManager.IMPORTANCE_MIN);
|
||||
channelGetData.setDescription(CHANNEL_GET_DATA_DESC);
|
||||
notificationManager.createNotificationChannel(channelGetData);
|
||||
|
||||
@ -109,13 +107,13 @@ public class Notifier {
|
||||
return app.appConfig.quietHoursStart > 0 && now >= start && now <= end;
|
||||
}
|
||||
|
||||
private int getNotificationDefaults() {
|
||||
public int getNotificationDefaults() {
|
||||
return (shouldBeQuiet() ? 0 : Notification.DEFAULT_ALL);
|
||||
}
|
||||
private String getNotificationGroup() {
|
||||
public String getNotificationGroup() {
|
||||
return shouldBeQuiet() ? GROUP_KEY_NOTIFICATIONS_QUIET : GROUP_KEY_NOTIFICATIONS;
|
||||
}
|
||||
private int getNotificationPriority() {
|
||||
public int getNotificationPriority() {
|
||||
return shouldBeQuiet() ? PRIORITY_DEFAULT : PRIORITY_MAX;
|
||||
}
|
||||
|
||||
@ -126,17 +124,17 @@ public class Notifier {
|
||||
| |__| | (_| | || (_| | | |__| | __/ |_
|
||||
|_____/ \__,_|\__\__,_| \_____|\___|\_*/
|
||||
public Notification notificationGetDataShow(int maxProgress) {
|
||||
Intent notificationIntent = new Intent(app.getContext(), SyncService.class);
|
||||
/*Intent notificationIntent = new Intent(app.getContext(), SyncService.class);
|
||||
notificationIntent.setAction(ACTION_CANCEL);
|
||||
PendingIntent pendingIntent = PendingIntent.getService(app.getContext(), 0,
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
|
||||
notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);*/
|
||||
|
||||
getDataNotificationBuilder = new NotificationCompat.Builder(app, GROUP_KEY_GET_DATA)
|
||||
.setSmallIcon(android.R.drawable.stat_sys_download)
|
||||
.setColor(notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_get_data_title))
|
||||
.setContentText(app.getString(R.string.notification_get_data_text))
|
||||
.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_cancel), pendingIntent)
|
||||
//.addAction(R.drawable.ic_notification, app.getString(R.string.notification_get_data_cancel), pendingIntent)
|
||||
//.setGroup(GROUP_KEY_GET_DATA)
|
||||
.setOngoing(true)
|
||||
.setProgress(maxProgress, 0, false)
|
||||
@ -208,10 +206,8 @@ public class Notifier {
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
SyncJob.run((App) getApplication(), intent.getExtras().getInt("failedProfileId", -1), -1);
|
||||
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
assert notificationManager != null;
|
||||
notificationManager.cancel(ID_GET_DATA_ERROR);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventFull;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange;
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonFull;
|
||||
@ -38,7 +39,6 @@ import pl.szczodrzynski.edziennik.utils.models.ItemWidgetTimetableModel;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time;
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week;
|
||||
import pl.szczodrzynski.edziennik.widgets.WidgetConfig;
|
||||
import pl.szczodrzynski.edziennik.sync.SyncJob;
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.LessonDetailsActivity;
|
||||
import pl.szczodrzynski.edziennik.widgets.timetable.WidgetTimetableService;
|
||||
|
||||
@ -65,8 +65,8 @@ public class WidgetTimetable extends AppWidgetProvider {
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())){
|
||||
SyncJob.run((App) context.getApplicationContext());
|
||||
if (ACTION_SYNC_DATA.equals(intent.getAction())) {
|
||||
EdziennikTask.Companion.sync().enqueue(context);
|
||||
}
|
||||
super.onReceive(context, intent);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
@ -0,0 +1,246 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import android.app.Service
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.IBinder
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.ServiceCloseRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.requests.TaskCancelRequest
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.EdziennikTask
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.ErrorReportTask
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.IApiTask
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.task.NotifyTask
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import kotlin.math.min
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
class ApiService : Service() {
|
||||
companion object {
|
||||
const val TAG = "ApiService"
|
||||
const val NOTIFICATION_API_CHANNEL_ID = "pl.szczodrzynski.edziennik.GET_DATA"
|
||||
fun start(context: Context) {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
}
|
||||
fun startAndRequest(context: Context, request: Any) {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
EventBus.getDefault().postSticky(request)
|
||||
}
|
||||
}
|
||||
|
||||
private val app by lazy { applicationContext as App }
|
||||
|
||||
private val finishingTaskQueue = mutableListOf(
|
||||
NotifyTask(),
|
||||
ErrorReportTask()
|
||||
)
|
||||
private val taskQueue = mutableListOf<IApiTask>()
|
||||
private val errorList = mutableListOf<ApiError>()
|
||||
|
||||
private var serviceClosed = false
|
||||
private var taskCancelled = false
|
||||
private var taskIsRunning = false
|
||||
private var taskRunning: IApiTask? = null // for debug purposes
|
||||
private var taskRunningId = -1
|
||||
private var taskMaximumId = 0
|
||||
|
||||
private var taskProfileId = -1
|
||||
private var taskProgress = -1f
|
||||
private var taskProgressText: String? = null
|
||||
|
||||
private val notification by lazy { EdziennikNotification(this) }
|
||||
|
||||
/* ______ _ _ _ _ _____ _ _ _ _
|
||||
| ____| | | (_) (_) | / ____| | | | | | |
|
||||
| |__ __| |_____ ___ _ __ _ __ _| | __ | | __ _| | | |__ __ _ ___| | __
|
||||
| __| / _` |_ / |/ _ \ '_ \| '_ \| | |/ / | | / _` | | | '_ \ / _` |/ __| |/ /
|
||||
| |___| (_| |/ /| | __/ | | | | | | | < | |___| (_| | | | |_) | (_| | (__| <
|
||||
|______\__,_/___|_|\___|_| |_|_| |_|_|_|\_\ \_____\__,_|_|_|_.__/ \__,_|\___|_|\*/
|
||||
private val taskCallback = object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
d(TAG, "Task $taskRunningId (profile $taskProfileId) - $taskProgressText - finished")
|
||||
//if (!taskCancelled) {
|
||||
EventBus.getDefault().post(ApiTaskFinishedEvent(taskProfileId))
|
||||
//}
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
taskRunning = null
|
||||
taskProfileId = -1
|
||||
taskProgress = -1f
|
||||
taskProgressText = null
|
||||
|
||||
notification.setIdle().post()
|
||||
runTask()
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
d(TAG, "Task $taskRunningId threw an error - $apiError")
|
||||
apiError.profileId = taskProfileId
|
||||
EventBus.getDefault().post(ApiTaskErrorEvent(apiError))
|
||||
errorList.add(apiError)
|
||||
apiError.throwable?.printStackTrace()
|
||||
if (apiError.isCritical) {
|
||||
notification.setCriticalError().post()
|
||||
taskRunning = null
|
||||
taskIsRunning = false
|
||||
taskRunningId = -1
|
||||
runTask()
|
||||
}
|
||||
else {
|
||||
notification.addError().post()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onProgress(step: Float) {
|
||||
if (step <= 0)
|
||||
return
|
||||
if (taskProgress < 0)
|
||||
taskProgress = 0f
|
||||
taskProgress += step
|
||||
taskProgress = min(100f, taskProgress)
|
||||
d(TAG, "Task $taskRunningId progress: ${taskProgress.roundToInt()}%")
|
||||
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
||||
notification.setProgress(taskProgress).post()
|
||||
}
|
||||
|
||||
override fun onStartProgress(stringRes: Int) {
|
||||
taskProgressText = getString(stringRes)
|
||||
d(TAG, "Task $taskRunningId progress: $taskProgressText")
|
||||
EventBus.getDefault().post(ApiTaskProgressEvent(taskProfileId, taskProgress, taskProgressText))
|
||||
notification.setProgressText(taskProgressText).post()
|
||||
}
|
||||
}
|
||||
|
||||
/* _______ _ _ _
|
||||
|__ __| | | | | (_)
|
||||
| | __ _ ___| | __ _____ _____ ___ _ _| |_ _ ___ _ __
|
||||
| |/ _` / __| |/ / / _ \ \/ / _ \/ __| | | | __| |/ _ \| '_ \
|
||||
| | (_| \__ \ < | __/> < __/ (__| |_| | |_| | (_) | | | |
|
||||
|_|\__,_|___/_|\_\ \___/_/\_\___|\___|\__,_|\__|_|\___/|_| |*/
|
||||
private fun runTask() {
|
||||
if (taskIsRunning)
|
||||
return
|
||||
if (taskCancelled || serviceClosed || (taskQueue.isEmpty() && finishingTaskQueue.isEmpty())) {
|
||||
serviceClosed = false
|
||||
allCompleted()
|
||||
return
|
||||
}
|
||||
|
||||
val task = if (taskQueue.isEmpty()) finishingTaskQueue.removeAt(0) else taskQueue.removeAt(0)
|
||||
task.taskId = ++taskMaximumId
|
||||
task.prepare(app)
|
||||
taskIsRunning = true
|
||||
taskRunningId = task.taskId
|
||||
taskRunning = task
|
||||
taskProfileId = task.profileId
|
||||
taskProgress = -1f
|
||||
taskProgressText = task.taskName
|
||||
|
||||
d(TAG, "Executing task $taskRunningId ($taskProgressText) - $task")
|
||||
|
||||
// update the notification
|
||||
notification.setCurrentTask(taskRunningId, taskProgressText).post()
|
||||
|
||||
// post an event
|
||||
EventBus.getDefault().post(ApiTaskStartedEvent(taskProfileId, task.profile))
|
||||
|
||||
when (task) {
|
||||
is EdziennikTask -> task.run(app, taskCallback)
|
||||
is NotifyTask -> task.run(app, taskCallback)
|
||||
is ErrorReportTask -> task.run(app, taskCallback, notification, errorList)
|
||||
}
|
||||
}
|
||||
|
||||
private fun allCompleted() {
|
||||
EventBus.getDefault().post(ApiTaskAllFinishedEvent())
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
/* ______ _ ____
|
||||
| ____| | | | _ \
|
||||
| |____ _____ _ __ | |_| |_) |_ _ ___
|
||||
| __\ \ / / _ \ '_ \| __| _ <| | | / __|
|
||||
| |___\ V / __/ | | | |_| |_) | |_| \__ \
|
||||
|______\_/ \___|_| |_|\__|____/ \__,_|__*/
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||
fun onApiTask(task: IApiTask) {
|
||||
EventBus.getDefault().removeStickyEvent(task)
|
||||
d(TAG, task.toString())
|
||||
|
||||
if (task is EdziennikTask) {
|
||||
when (task.request) {
|
||||
is EdziennikTask.SyncRequest -> app.db.profileDao().idsForSyncNow.forEach {
|
||||
taskQueue += EdziennikTask.syncProfile(it)
|
||||
}
|
||||
is EdziennikTask.SyncProfileListRequest -> task.request.profileList.forEach {
|
||||
taskQueue += EdziennikTask.syncProfile(it)
|
||||
}
|
||||
else -> {
|
||||
taskQueue += task
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
taskQueue += task
|
||||
}
|
||||
d(TAG, "EventBus received an IApiTask: $task")
|
||||
d(TAG, "Current queue:")
|
||||
taskQueue.forEach {
|
||||
d(TAG, " - $it")
|
||||
}
|
||||
runTask()
|
||||
}
|
||||
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||
fun onTaskCancelRequest(request: TaskCancelRequest) {
|
||||
EventBus.getDefault().removeStickyEvent(request)
|
||||
d(TAG, request.toString())
|
||||
|
||||
taskCancelled = true
|
||||
taskRunning?.cancel()
|
||||
}
|
||||
@Subscribe(sticky = true, threadMode = ThreadMode.ASYNC)
|
||||
fun onServiceCloseRequest(request: ServiceCloseRequest) {
|
||||
EventBus.getDefault().removeStickyEvent(request)
|
||||
d(TAG, request.toString())
|
||||
|
||||
serviceClosed = true
|
||||
taskCancelled = true
|
||||
taskRunning?.cancel()
|
||||
stopSelf()
|
||||
}
|
||||
|
||||
/* _____ _ _ _
|
||||
/ ____| (_) (_) | |
|
||||
| (___ ___ _ ____ ___ ___ ___ _____ _____ _ __ _ __ _ __| | ___ ___
|
||||
\___ \ / _ \ '__\ \ / / |/ __/ _ \ / _ \ \ / / _ \ '__| '__| |/ _` |/ _ \/ __|
|
||||
____) | __/ | \ V /| | (_| __/ | (_) \ V / __/ | | | | | (_| | __/\__ \
|
||||
|_____/ \___|_| \_/ |_|\___\___| \___/ \_/ \___|_| |_| |_|\__,_|\___||__*/
|
||||
override fun onCreate() {
|
||||
EventBus.getDefault().register(this)
|
||||
notification.setIdle().setCloseAction()
|
||||
}
|
||||
|
||||
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
|
||||
startForeground(EdziennikNotification.NOTIFICATION_ID, notification.notification)
|
||||
return START_NOT_STICKY
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
override fun onBind(intent: Intent?): IBinder? {
|
||||
return null
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-19.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import android.os.Build
|
||||
import pl.szczodrzynski.edziennik.BuildConfig
|
||||
|
||||
const val GET = 0
|
||||
const val POST = 1
|
||||
|
||||
val SYSTEM_USER_AGENT = System.getProperty("http.agent") ?: "Dalvik/2.1.0 Android"
|
||||
|
||||
val SERVER_USER_AGENT = "Szkolny.eu/${BuildConfig.VERSION_NAME} $SYSTEM_USER_AGENT"
|
||||
|
||||
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"
|
||||
const val LIBRUS_AUTHORIZE_URL = "https://portal.librus.pl/oauth2/authorize?client_id=$LIBRUS_CLIENT_ID&redirect_uri=$LIBRUS_REDIRECT_URL&response_type=code"
|
||||
const val LIBRUS_LOGIN_URL = "https://portal.librus.pl/rodzina/login/action"
|
||||
const val LIBRUS_TOKEN_URL = "https://portal.librus.pl/oauth2/access_token"
|
||||
|
||||
const val LIBRUS_ACCOUNT_URL = "/v2/SynergiaAccounts/fresh/" // + login
|
||||
const val LIBRUS_ACCOUNTS_URL = "/v2/SynergiaAccounts"
|
||||
|
||||
/** https://api.librus.pl/2.0 */
|
||||
const val LIBRUS_API_URL = "https://api.librus.pl/2.0"
|
||||
/** https://portal.librus.pl/api */
|
||||
const val LIBRUS_PORTAL_URL = "https://portal.librus.pl/api"
|
||||
/** https://api.librus.pl/OAuth/Token */
|
||||
const val LIBRUS_API_TOKEN_URL = "https://api.librus.pl/OAuth/Token"
|
||||
/** https://api.librus.pl/OAuth/TokenJST */
|
||||
const val LIBRUS_API_TOKEN_JST_URL = "https://api.librus.pl/OAuth/TokenJST"
|
||||
const val LIBRUS_API_AUTHORIZATION = "Mjg6ODRmZGQzYTg3YjAzZDNlYTZmZmU3NzdiNThiMzMyYjE="
|
||||
const val LIBRUS_API_SECRET_JST = "18b7c1ee08216f636a1b1a2440e68398"
|
||||
const val LIBRUS_API_CLIENT_ID_JST = "49"
|
||||
//const val LIBRUS_API_CLIENT_ID_JST_REFRESH = "42"
|
||||
|
||||
const val LIBRUS_JST_DEMO_CODE = "68656A21"
|
||||
const val LIBRUS_JST_DEMO_PIN = "1290"
|
||||
|
||||
const val LIBRUS_SYNERGIA_URL = "https://synergia.librus.pl"
|
||||
/** 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="
|
||||
|
||||
const val IDZIENNIK_USER_AGENT = SYNERGIA_USER_AGENT
|
||||
const val IDZIENNIK_WEB_URL = "https://iuczniowie.progman.pl/idziennik"
|
||||
const val IDZIENNIK_WEB_LOGIN = "login.aspx"
|
||||
const val IDZIENNIK_WEB_SETTINGS = "mod_panelRodzica/Ustawienia.aspx"
|
||||
const val IDZIENNIK_WEB_TIMETABLE = "mod_panelRodzica/plan/WS_Plan.asmx/pobierzPlanZajec"
|
||||
const val IDZIENNIK_WEB_GRADES = "mod_panelRodzica/oceny/WS_ocenyUcznia.asmx/pobierzOcenyUcznia"
|
||||
const val IDZIENNIK_WEB_MISSING_GRADES = "mod_panelRodzica/brak_ocen/WS_BrakOcenUcznia.asmx/pobierzBrakujaceOcenyUcznia"
|
||||
const val IDZIENNIK_WEB_EXAMS = "mod_panelRodzica/sprawdziany/mod_sprawdzianyPanel.asmx/pobierzListe"
|
||||
const val IDZIENNIK_WEB_NOTICES = "mod_panelRodzica/uwagi/WS_uwagiUcznia.asmx/pobierzUwagiUcznia"
|
||||
const val IDZIENNIK_WEB_ATTENDANCE = "mod_panelRodzica/obecnosci/WS_obecnosciUcznia.asmx/pobierzObecnosciUcznia"
|
||||
const val IDZIENNIK_WEB_ANNOUNCEMENTS = "mod_panelRodzica/tabOgl/WS_tablicaOgloszen.asmx/GetOgloszenia"
|
||||
const val IDZIENNIK_WEB_MESSAGES_LIST = "mod_komunikator/WS_wiadomosci.asmx/PobierzListeWiadomosci"
|
||||
|
||||
val IDZIENNIK_API_USER_AGENT = SYSTEM_USER_AGENT
|
||||
const val IDZIENNIK_API_URL = "https://iuczniowie.progman.pl/idziennik/api"
|
||||
const val IDZIENNIK_API_CURRENT_REGISTER = "Uczniowie/\$STUDENT_ID/AktualnyDziennik"
|
||||
const val IDZIENNIK_API_GRADES = "Uczniowie/\$STUDENT_ID/Oceny/" /* + semester */
|
||||
const val IDZIENNIK_API_MESSAGES_INBOX = "Wiadomosci/Odebrane"
|
||||
const val IDZIENNIK_API_MESSAGES_SENT = "Wiadomosci/Wyslane"
|
||||
|
||||
|
||||
val MOBIDZIENNIK_USER_AGENT = SYSTEM_USER_AGENT
|
||||
|
||||
const val VULCAN_API_USER_AGENT = "MobileUserAgent"
|
||||
const val VULCAN_API_APP_NAME = "VULCAN-Android-ModulUcznia"
|
||||
const val VULCAN_API_APP_VERSION = "19.4.1.436"
|
||||
const val VULCAN_API_PASSWORD = "CE75EA598C7743AD9B0B7328DED85B06"
|
||||
const val VULCAN_API_PASSWORD_FAKELOG = "012345678901234567890123456789AB"
|
||||
val VULCAN_API_DEVICE_NAME = "Szkolny.eu ${Build.MODEL}"
|
||||
|
||||
const val VULCAN_API_ENDPOINT_CERTIFICATE = "mobile-api/Uczen.v3.UczenStart/Certyfikat"
|
||||
const val VULCAN_API_ENDPOINT_STUDENT_LIST = "mobile-api/Uczen.v3.UczenStart/ListaUczniow"
|
||||
const val VULCAN_API_ENDPOINT_DICTIONARIES = "mobile-api/Uczen.v3.Uczen/Slowniki"
|
||||
const val VULCAN_API_ENDPOINT_TIMETABLE = "mobile-api/Uczen.v3.Uczen/PlanLekcjiZeZmianami"
|
||||
const val VULCAN_API_ENDPOINT_GRADES = "mobile-api/Uczen.v3.Uczen/Oceny"
|
||||
const val VULCAN_API_ENDPOINT_GRADES_PROPOSITIONS = "mobile-api/Uczen.v3.Uczen/OcenyPodsumowanie"
|
||||
const val VULCAN_API_ENDPOINT_EVENTS = "mobile-api/Uczen.v3.Uczen/Sprawdziany"
|
||||
const val VULCAN_API_ENDPOINT_HOMEWORK = "mobile-api/Uczen.v3.Uczen/ZadaniaDomowe"
|
||||
const val VULCAN_API_ENDPOINT_NOTICES = "mobile-api/Uczen.v3.Uczen/UwagiUcznia"
|
||||
const val VULCAN_API_ENDPOINT_ATTENDANCE = "mobile-api/Uczen.v3.Uczen/Frekwencje"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_RECEIVED = "mobile-api/Uczen.v3.Uczen/WiadomosciOdebrane"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_SENT = "mobile-api/Uczen.v3.Uczen/WiadomosciWyslane"
|
||||
const val VULCAN_API_ENDPOINT_MESSAGES_CHANGE_STATUS = "mobile-api/Uczen.v3.Uczen/ZmienStatusWiadomosci"
|
||||
const val VULCAN_API_ENDPOINT_PUSH = "mobile-api/Uczen.v3.Uczen/UstawPushToken"
|
@ -0,0 +1,210 @@
|
||||
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_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_BEHAVIOUR
|
||||
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_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_ANNOUNCEMENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_GRADE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_NOTICE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_TIMETABLE_LESSON_CHANGE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class DataNotifications(val data: Data) {
|
||||
companion object {
|
||||
private const val TAG = "DataNotifications"
|
||||
}
|
||||
|
||||
val app = data.app
|
||||
val profileId = data.profile?.id ?: -1
|
||||
val profileName = data.profile?.name ?: ""
|
||||
val profile = data.profile
|
||||
val loginStore = data.loginStore
|
||||
|
||||
init { run {
|
||||
if (profile == null) {
|
||||
return@run
|
||||
}
|
||||
|
||||
for (change in app.db.lessonChangeDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.getString(R.string.notification_lesson_change_format, change.changeTypeStr(app), if (change.lessonDate == null) "" else change.lessonDate!!.formattedString, change.subjectLongName)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_TIMETABLE_LESSON_CHANGE),
|
||||
text = text,
|
||||
type = TYPE_TIMETABLE_LESSON_CHANGE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_TIMETABLE,
|
||||
addedDate = change.addedDate
|
||||
).addExtra("timetableDate", change.lessonDate?.value?.toLong())
|
||||
}
|
||||
|
||||
for (event in app.db.eventDao().getNotNotifiedNow(profileId)) {
|
||||
val text = if (event.type == Event.TYPE_HOMEWORK)
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_homework_no_subject_format
|
||||
else
|
||||
R.string.notification_homework_format,
|
||||
event.subjectLongName,
|
||||
event.eventDate.formattedString
|
||||
)
|
||||
else
|
||||
app.getString(
|
||||
if (event.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_event_no_subject_format
|
||||
else
|
||||
R.string.notification_event_format,
|
||||
event.typeName,
|
||||
event.eventDate.formattedString,
|
||||
event.subjectLongName
|
||||
)
|
||||
val type = if (event.type == Event.TYPE_HOMEWORK) TYPE_NEW_HOMEWORK else TYPE_NEW_EVENT
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(type),
|
||||
text = text,
|
||||
type = type,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = if (event.type == Event.TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA,
|
||||
addedDate = event.addedDate
|
||||
).addExtra("eventId", event.id).addExtra("eventDate", event.eventDate.value.toLong())
|
||||
}
|
||||
|
||||
val today = Date.getToday()
|
||||
val todayValue = today.value
|
||||
profile.currentSemester = profile.dateToSemester(today)
|
||||
|
||||
for (grade in app.db.gradeDao().getNotNotifiedNow(profileId)) {
|
||||
val gradeName = when (grade.type) {
|
||||
TYPE_SEMESTER1_PROPOSED, TYPE_SEMESTER2_PROPOSED -> app.getString(R.string.grade_semester_proposed_format_2, grade.name)
|
||||
TYPE_SEMESTER1_FINAL, TYPE_SEMESTER2_FINAL -> app.getString(R.string.grade_semester_final_format_2, grade.name)
|
||||
TYPE_YEAR_PROPOSED -> app.getString(R.string.grade_year_proposed_format_2, grade.name)
|
||||
TYPE_YEAR_FINAL -> app.getString(R.string.grade_year_final_format_2, grade.name)
|
||||
else -> grade.name
|
||||
}
|
||||
val text = app.getString(R.string.notification_grade_format, gradeName, grade.subjectLongName)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_GRADE),
|
||||
text = text,
|
||||
type = TYPE_NEW_GRADE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_GRADES,
|
||||
addedDate = grade.addedDate
|
||||
).addExtra("gradeId", grade.id).addExtra("gradesSubjectId", grade.subjectId)
|
||||
}
|
||||
|
||||
for (notice in app.db.noticeDao().getNotNotifiedNow(profileId)) {
|
||||
val noticeTypeStr = if (notice.type == Notice.TYPE_POSITIVE) app.getString(R.string.notification_notice_praise) else if (notice.type == Notice.TYPE_NEGATIVE) app.getString(R.string.notification_notice_warning) else app.getString(R.string.notification_notice_new)
|
||||
val text = app.getString(R.string.notification_notice_format, noticeTypeStr, notice.teacherFullName, Date.fromMillis(notice.addedDate).formattedString)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_NOTICE),
|
||||
text = text,
|
||||
type = TYPE_NEW_NOTICE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_BEHAVIOUR,
|
||||
addedDate = notice.addedDate
|
||||
).addExtra("noticeId", notice.id)
|
||||
}
|
||||
|
||||
for (attendance in app.db.attendanceDao().getNotNotifiedNow(profileId)) {
|
||||
var attendanceTypeStr = app.getString(R.string.notification_type_attendance)
|
||||
when (attendance.type) {
|
||||
Attendance.TYPE_ABSENT -> attendanceTypeStr = app.getString(R.string.notification_absence)
|
||||
Attendance.TYPE_ABSENT_EXCUSED -> attendanceTypeStr = app.getString(R.string.notification_absence_excused)
|
||||
Attendance.TYPE_BELATED -> attendanceTypeStr = app.getString(R.string.notification_belated)
|
||||
Attendance.TYPE_BELATED_EXCUSED -> attendanceTypeStr = app.getString(R.string.notification_belated_excused)
|
||||
Attendance.TYPE_RELEASED -> attendanceTypeStr = app.getString(R.string.notification_release)
|
||||
}
|
||||
val text = app.getString(
|
||||
if (attendance.subjectLongName.isNullOrEmpty())
|
||||
R.string.notification_attendance_no_lesson_format
|
||||
else
|
||||
R.string.notification_attendance_format,
|
||||
attendanceTypeStr,
|
||||
attendance.subjectLongName,
|
||||
attendance.lessonDate.formattedString
|
||||
)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_ATTENDANCE),
|
||||
text = text,
|
||||
type = TYPE_NEW_ATTENDANCE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_ATTENDANCE,
|
||||
addedDate = attendance.addedDate
|
||||
).addExtra("attendanceId", attendance.id).addExtra("attendanceSubjectId", attendance.subjectId)
|
||||
}
|
||||
|
||||
for (announcement in app.db.announcementDao().getNotNotifiedNow(profileId)) {
|
||||
val text = app.context.getString(R.string.notification_announcement_format, announcement.subject)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_ANNOUNCEMENT),
|
||||
text = text,
|
||||
type = TYPE_NEW_ANNOUNCEMENT,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_ANNOUNCEMENTS,
|
||||
addedDate = announcement.addedDate
|
||||
).addExtra("announcementId", announcement.id)
|
||||
}
|
||||
|
||||
for (message in app.db.messageDao().getReceivedNotNotifiedNow(profileId)) {
|
||||
val text = app.context.getString(R.string.notification_message_format, message.senderFullName, message.subject)
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_NEW_MESSAGE),
|
||||
text = text,
|
||||
type = TYPE_NEW_MESSAGE,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_MESSAGES,
|
||||
addedDate = message.addedDate
|
||||
).addExtra("messageType", Message.TYPE_RECEIVED.toLong()).addExtra("messageId", message.id)
|
||||
}
|
||||
|
||||
val luckyNumbers = app.db.luckyNumberDao().getNotNotifiedNow(profileId)
|
||||
luckyNumbers?.removeAll { it.date < today }
|
||||
luckyNumbers?.forEach { luckyNumber ->
|
||||
val text = when {
|
||||
luckyNumber.date.value == todayValue -> // LN for today
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_format else R.string.notification_lucky_number_format, luckyNumber.number)
|
||||
luckyNumber.date.value == todayValue + 1 -> // LN for tomorrow
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_tomorrow_format else R.string.notification_lucky_number_tomorrow_format, luckyNumber.number)
|
||||
else -> // LN for later
|
||||
app.getString(if (profile.studentNumber != -1 && profile.studentNumber == luckyNumber.number) R.string.notification_lucky_number_yours_later_format else R.string.notification_lucky_number_later_format, luckyNumber.date.formattedString, luckyNumber.number)
|
||||
}
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(TYPE_LUCKY_NUMBER),
|
||||
text = text,
|
||||
type = TYPE_LUCKY_NUMBER,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = DRAWER_ITEM_HOME,
|
||||
addedDate = luckyNumber.addedDate
|
||||
)
|
||||
}
|
||||
|
||||
data.db.metadataDao().setAllNotified(profileId, true)
|
||||
}}
|
||||
}
|
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import android.app.Notification
|
||||
import android.app.NotificationManager
|
||||
import android.app.PendingIntent
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationCompat.PRIORITY_MIN
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
|
||||
class EdziennikNotification(val context: Context) {
|
||||
companion object {
|
||||
const val NOTIFICATION_ID = 20191001
|
||||
}
|
||||
|
||||
private val notificationManager by lazy { context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager }
|
||||
|
||||
private val notificationBuilder: NotificationCompat.Builder by lazy {
|
||||
NotificationCompat.Builder(context, ApiService.NOTIFICATION_API_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setPriority(PRIORITY_MIN)
|
||||
.setOngoing(true)
|
||||
.setLocalOnly(true)
|
||||
}
|
||||
|
||||
val notification: Notification
|
||||
get() = notificationBuilder.build()
|
||||
|
||||
private var errorCount = 0
|
||||
private var criticalErrorCount = 0
|
||||
|
||||
private fun cancelPendingIntent(taskId: Int): PendingIntent {
|
||||
val intent = Intent("pl.szczodrzynski.edziennik.SZKOLNY_MAIN")
|
||||
intent.putExtra("task", "TaskCancelRequest")
|
||||
intent.putExtra("taskId", taskId)
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT) as PendingIntent
|
||||
}
|
||||
private val closePendingIntent: PendingIntent
|
||||
get() {
|
||||
val intent = Intent("pl.szczodrzynski.edziennik.SZKOLNY_MAIN")
|
||||
intent.putExtra("task", "ServiceCloseRequest")
|
||||
return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT) as PendingIntent
|
||||
}
|
||||
|
||||
private fun errorCountText(): String? {
|
||||
var result = ""
|
||||
if (criticalErrorCount > 0) {
|
||||
result += context.resources.getQuantityString(R.plurals.critical_errors_format, criticalErrorCount, criticalErrorCount)
|
||||
}
|
||||
if (criticalErrorCount > 0 && errorCount > 0) {
|
||||
result += ", "
|
||||
}
|
||||
if (errorCount > 0) {
|
||||
result += context.resources.getQuantityString(R.plurals.normal_errors_format, errorCount, errorCount)
|
||||
}
|
||||
return if (result.isEmpty()) null else result
|
||||
}
|
||||
|
||||
fun setIdle(): EdziennikNotification {
|
||||
notificationBuilder.setContentTitle(context.getString(R.string.edziennik_notification_api_title))
|
||||
notificationBuilder.setProgress(0, 0, false)
|
||||
notificationBuilder.apply {
|
||||
val str = context.getString(R.string.edziennik_notification_api_text)
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(str))
|
||||
setContentText(str)
|
||||
}
|
||||
setCloseAction()
|
||||
return this
|
||||
}
|
||||
|
||||
fun addError(): EdziennikNotification {
|
||||
errorCount++
|
||||
return this
|
||||
}
|
||||
fun setCriticalError(): EdziennikNotification {
|
||||
criticalErrorCount++
|
||||
notificationBuilder.setContentTitle(context.getString(R.string.edziennik_notification_api_error_title))
|
||||
notificationBuilder.setProgress(0, 0, false)
|
||||
notificationBuilder.apply {
|
||||
val str = errorCountText()
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(str))
|
||||
setContentText(str)
|
||||
}
|
||||
setCloseAction()
|
||||
return this
|
||||
}
|
||||
|
||||
fun setProgress(progress: Float): EdziennikNotification {
|
||||
notificationBuilder.setProgress(100, progress.roundToInt(), progress < 0f)
|
||||
return this
|
||||
}
|
||||
fun setProgressText(progressText: String?): EdziennikNotification {
|
||||
notificationBuilder.setContentTitle(progressText)
|
||||
return this
|
||||
}
|
||||
|
||||
fun setCurrentTask(taskId: Int, progressText: String?): EdziennikNotification {
|
||||
notificationBuilder.setProgress(100, 0, true)
|
||||
notificationBuilder.setContentTitle(progressText)
|
||||
notificationBuilder.apply {
|
||||
val str = errorCountText()
|
||||
setStyle(NotificationCompat.BigTextStyle().bigText(str))
|
||||
setContentText(str)
|
||||
}
|
||||
setCancelAction(taskId)
|
||||
return this
|
||||
}
|
||||
|
||||
fun setCloseAction(): EdziennikNotification {
|
||||
notificationBuilder.mActions.clear()
|
||||
notificationBuilder.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_notification,
|
||||
context.getString(R.string.edziennik_notification_api_close),
|
||||
closePendingIntent
|
||||
))
|
||||
return this
|
||||
}
|
||||
private fun setCancelAction(taskId: Int) {
|
||||
notificationBuilder.mActions.clear()
|
||||
notificationBuilder.addAction(
|
||||
NotificationCompat.Action(
|
||||
R.drawable.ic_notification,
|
||||
context.getString(R.string.edziennik_notification_api_cancel),
|
||||
cancelPendingIntent(taskId)
|
||||
))
|
||||
}
|
||||
|
||||
fun post() {
|
||||
notificationManager.notify(NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Feature
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||
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
|
||||
|
||||
fun Data.prepare(loginMethods: List<LoginMethod>, features: List<Feature>, featureIds: List<Int>, viewId: Int?) {
|
||||
val data = this
|
||||
|
||||
val possibleLoginMethods = data.loginMethods.toMutableList()
|
||||
|
||||
for (loginMethod in loginMethods) {
|
||||
if (loginMethod.isPossible(profile, loginStore))
|
||||
possibleLoginMethods += loginMethod.loginMethodId
|
||||
}
|
||||
|
||||
//var highestLoginMethod = 0
|
||||
var endpointList = mutableListOf<Feature>()
|
||||
val requiredLoginMethods = mutableListOf<Int>()
|
||||
|
||||
data.targetEndpointIds.clear()
|
||||
data.targetLoginMethodIds.clear()
|
||||
|
||||
// get all endpoints for every feature, only if possible to login and possible/necessary to sync
|
||||
for (featureId in featureIds) {
|
||||
features.filter {
|
||||
it.featureId == featureId // feature ID matches
|
||||
&& possibleLoginMethods.containsAll(it.requiredLoginMethods) // is possible to login
|
||||
&& it.shouldSync?.invoke(data) ?: true // is necessary/possible to sync
|
||||
}.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 ||
|
||||
(viewId != null && 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) {
|
||||
loginMethods.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()
|
||||
|
||||
progressCount = targetLoginMethodIds.size + targetEndpointIds.size
|
||||
progressStep = if (progressCount <= 0) 0f else 100f / progressCount.toFloat()
|
||||
}
|
164
app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt
Normal file
164
app/src/main/java/pl/szczodrzynski/edziennik/api/v2/Errors.kt
Normal file
@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
/*const val CODE_OTHER = 0
|
||||
const val CODE_OK = 1
|
||||
const val CODE_NO_INTERNET = 10
|
||||
const val CODE_SSL_ERROR = 13
|
||||
const val CODE_ARCHIVED = 5
|
||||
const val CODE_MAINTENANCE = 6
|
||||
const val CODE_LOGIN_ERROR = 7
|
||||
const val CODE_ACCOUNT_MISMATCH = 8
|
||||
const val CODE_APP_SERVER_ERROR = 9
|
||||
const val CODE_MULTIACCOUNT_SETUP = 12
|
||||
const val CODE_TIMEOUT = 11
|
||||
const val CODE_PROFILE_NOT_FOUND = 14
|
||||
const val CODE_ATTACHMENT_NOT_AVAILABLE = 28
|
||||
const val CODE_INVALID_LOGIN = 2
|
||||
const val CODE_INVALID_SERVER_ADDRESS = 21
|
||||
const val CODE_INVALID_SCHOOL_NAME = 22
|
||||
const val CODE_INVALID_DEVICE = 23
|
||||
const val CODE_OLD_PASSWORD = 4
|
||||
const val CODE_INVALID_TOKEN = 24
|
||||
const val CODE_EXPIRED_TOKEN = 27
|
||||
const val CODE_INVALID_SYMBOL = 25
|
||||
const val CODE_INVALID_PIN = 26
|
||||
const val CODE_LIBRUS_NOT_ACTIVATED = 29
|
||||
const val CODE_SYNERGIA_NOT_ACTIVATED = 32
|
||||
const val CODE_LIBRUS_DISCONNECTED = 31
|
||||
const val CODE_PROFILE_ARCHIVED = 30*/
|
||||
|
||||
const val ERROR_REQUEST_FAILURE = 50
|
||||
const val ERROR_REQUEST_HTTP_400 = 51
|
||||
const val ERROR_REQUEST_HTTP_401 = 52
|
||||
const val ERROR_REQUEST_HTTP_403 = 53
|
||||
const val ERROR_REQUEST_HTTP_404 = 54
|
||||
const val ERROR_REQUEST_HTTP_405 = 55
|
||||
const val ERROR_REQUEST_HTTP_410 = 56
|
||||
const val ERROR_REQUEST_HTTP_500 = 57
|
||||
const val ERROR_RESPONSE_EMPTY = 100
|
||||
const val ERROR_LOGIN_DATA_MISSING = 101
|
||||
const val ERROR_LOGIN_DATA_INVALID = 102
|
||||
const val ERROR_PROFILE_MISSING = 105
|
||||
const val ERROR_INVALID_LOGIN_MODE = 110
|
||||
const val ERROR_LOGIN_METHOD_NOT_SATISFIED = 111
|
||||
const val ERROR_NOT_IMPLEMENTED = 112
|
||||
|
||||
const val ERROR_NO_STUDENTS_IN_ACCOUNT = 115
|
||||
|
||||
const val CODE_INTERNAL_LIBRUS_ACCOUNT_410 = 120
|
||||
const val CODE_INTERNAL_LIBRUS_SYNERGIA_EXPIRED = 121
|
||||
const val ERROR_LOGIN_LIBRUS_API_CAPTCHA_NEEDED = 124
|
||||
const val ERROR_LOGIN_LIBRUS_API_CONNECTION_PROBLEMS = 125
|
||||
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_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
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR = 134
|
||||
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_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
|
||||
const val ERROR_LIBRUS_API_RESOURCE_ACCESS_DENIED = 147
|
||||
const val ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS = 148
|
||||
const val ERROR_LIBRUS_API_INCORRECT_ENDPOINT = 149
|
||||
const val ERROR_LIBRUS_API_LUCKY_NUMBER_NOT_ACTIVE = 150
|
||||
const val ERROR_LIBRUS_API_NOTES_NOT_ACTIVE = 151
|
||||
const val ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN = 152
|
||||
const val ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID = 153
|
||||
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_ACCESS_DENIED = 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 ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID = 172
|
||||
const val ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_REVOKED = 173
|
||||
const val ERROR_LIBRUS_SYNERGIA_OTHER = 174
|
||||
const val ERROR_LIBRUS_SYNERGIA_MAINTENANCE = 175
|
||||
|
||||
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_MOBIDZIENNIK_WEB_INVALID_RESPONSE = 214
|
||||
const val ERROR_LOGIN_MOBIDZIENNIK_WEB_NO_SESSION_ID = 215
|
||||
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_SYMBOL = 301
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_TOKEN = 302
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN = 309
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN_0_REMAINING = 310
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN_1_REMAINING = 311
|
||||
const val ERROR_LOGIN_VULCAN_INVALID_PIN_2_REMAINING = 312
|
||||
const val ERROR_LOGIN_VULCAN_EXPIRED_TOKEN = 321
|
||||
const val ERROR_LOGIN_VULCAN_OTHER = 322
|
||||
const val ERROR_LOGIN_VULCAN_ONLY_KINDERGARTEN = 330
|
||||
const val ERROR_LOGIN_VULCAN_NO_PUPILS = 331
|
||||
const val ERROR_VULCAN_API_MAINTENANCE = 340
|
||||
const val ERROR_VULCAN_API_BAD_REQUEST = 341
|
||||
const val ERROR_VULCAN_API_OTHER = 342
|
||||
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN = 401
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME = 402
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 403
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE = 404
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR = 405
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_OTHER = 410
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_API_NO_ACCESS = 411 /* {"d":{"__type":"mds.Web.mod_komunikator.WS_mod_wiadomosci+detailWiadomosci","Wiadomosc":{"_recordId":0,"DataNadania":null,"DataOdczytania":null,"Nadawca":null,"ListaOdbiorcow":[],"Tytul":null,"Text":null,"ListaZal":[]},"Bledy":{"__type":"mds.Module.Globalne+sBledy","CzyJestBlad":true,"ListaBledow":["Nie masz dostępu do tych zasobów!"],"ListaKodowBledow":[]},"czyJestWiecej":false}} */
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION = 420
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH = 421
|
||||
const val ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER = 422
|
||||
const val ERROR_IDZIENNIK_WEB_ACCESS_DENIED = 430
|
||||
const val ERROR_IDZIENNIK_WEB_OTHER = 431
|
||||
const val ERROR_IDZIENNIK_WEB_MAINTENANCE = 432
|
||||
const val ERROR_IDZIENNIK_WEB_SERVER_ERROR = 433
|
||||
const val ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED = 434
|
||||
const val ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR = 440
|
||||
const val ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA = 441
|
||||
const val ERROR_IDZIENNIK_API_ACCESS_DENIED = 450
|
||||
const val ERROR_IDZIENNIK_API_OTHER = 451
|
||||
|
||||
const val ERROR_TEMPLATE_WEB_OTHER = 801
|
||||
|
||||
const val EXCEPTION_LOGIN_LIBRUS_API_TOKEN = 901
|
||||
const val EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN = 902
|
||||
const val EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN = 903
|
||||
const val EXCEPTION_LIBRUS_API_REQUEST = 904
|
||||
const val EXCEPTION_LIBRUS_SYNERGIA_REQUEST = 905
|
||||
const val EXCEPTION_MOBIDZIENNIK_WEB_REQUEST = 906
|
||||
const val EXCEPTION_VULCAN_API_REQUEST = 907
|
||||
const val EXCEPTION_NOTIFY_AND_SYNC = 910
|
||||
const val EXCEPTION_LIBRUS_MESSAGES_REQUEST = 911
|
||||
const val EXCEPTION_IDZIENNIK_WEB_REQUEST = 912
|
||||
const val EXCEPTION_IDZIENNIK_WEB_API_REQUEST = 913
|
||||
const val EXCEPTION_IDZIENNIK_API_REQUEST = 914
|
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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_ATTENDANCE
|
||||
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_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
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
|
||||
|
||||
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_BEHAVIOUR = 5
|
||||
const val FEATURE_ATTENDANCE = 6
|
||||
const val FEATURE_MESSAGES_INBOX = 7
|
||||
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
|
||||
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_PUSH_CONFIG = 120
|
||||
|
||||
const val FEATURE_MESSAGE_GET = 201
|
||||
|
||||
object Features {
|
||||
private fun getAllNecessary(): List<Int> = listOf(
|
||||
FEATURE_ALWAYS_NEEDED,
|
||||
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_BEHAVIOUR,
|
||||
FEATURE_ATTENDANCE,
|
||||
FEATURE_MESSAGES_INBOX,
|
||||
FEATURE_MESSAGES_SENT,
|
||||
FEATURE_ANNOUNCEMENTS)
|
||||
|
||||
fun getAllIds(): List<Int> = getAllFeatures() + getAllNecessary()
|
||||
|
||||
fun getIdsByView(targetId: Int, targetType: 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 (targetType) {
|
||||
TYPE_RECEIVED -> listOf(FEATURE_MESSAGES_INBOX)
|
||||
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_BEHAVIOUR)
|
||||
DRAWER_ITEM_ATTENDANCE -> listOf(FEATURE_ATTENDANCE)
|
||||
DRAWER_ITEM_ANNOUNCEMENTS -> listOf(FEATURE_ANNOUNCEMENTS)
|
||||
else -> getAllFeatures()
|
||||
} + getAllNecessary()).sorted()
|
||||
}
|
||||
}
|
@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLoginWeb
|
||||
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.LibrusLoginPortal
|
||||
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
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.login.VulcanLoginApi
|
||||
|
||||
// librus
|
||||
// mobidziennik
|
||||
// idziennik
|
||||
// vulcan
|
||||
// mobireg
|
||||
|
||||
const val SYNERGIA_API_ENABLED = true
|
||||
|
||||
|
||||
|
||||
const val LOGIN_TYPE_IDZIENNIK = 3
|
||||
|
||||
const val LOGIN_TYPE_TEMPLATE = 21
|
||||
|
||||
// LOGIN MODES
|
||||
const val LOGIN_MODE_IDZIENNIK_WEB = 0
|
||||
|
||||
const val LOGIN_MODE_TEMPLATE_WEB = 0
|
||||
|
||||
// LOGIN METHODS
|
||||
const val LOGIN_METHOD_NOT_NEEDED = -1
|
||||
const val LOGIN_METHOD_IDZIENNIK_WEB = 100
|
||||
const val LOGIN_METHOD_IDZIENNIK_API = 200
|
||||
const val LOGIN_METHOD_TEMPLATE_WEB = 100
|
||||
const val LOGIN_METHOD_TEMPLATE_API = 200
|
||||
|
||||
const val LOGIN_TYPE_LIBRUS = 2
|
||||
const val LOGIN_MODE_LIBRUS_EMAIL = 0
|
||||
const val LOGIN_MODE_LIBRUS_SYNERGIA = 1
|
||||
const val LOGIN_MODE_LIBRUS_JST = 2
|
||||
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
|
||||
val librusLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_PORTAL, LibrusLoginPortal::class.java)
|
||||
.withIsPossible { _, loginStore ->
|
||||
loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL
|
||||
}
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_LIBRUS, LOGIN_METHOD_LIBRUS_API, LibrusLoginApi::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, LibrusLoginSynergia::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, LibrusLoginMessages::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { profile, _ ->
|
||||
if (profile?.hasStudentData("accountPassword") == false) LOGIN_METHOD_LIBRUS_SYNERGIA else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_MOBIDZIENNIK = 1
|
||||
const val LOGIN_MODE_MOBIDZIENNIK_WEB = 0
|
||||
const val LOGIN_METHOD_MOBIDZIENNIK_WEB = 100
|
||||
const val LOGIN_METHOD_MOBIDZIENNIK_API2 = 300
|
||||
val mobidziennikLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_WEB, MobidziennikLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }/*,
|
||||
|
||||
LoginMethod(LOGIN_TYPE_MOBIDZIENNIK, LOGIN_METHOD_MOBIDZIENNIK_API2, MobidziennikLoginApi2::class.java)
|
||||
.withIsPossible { _, loginStore -> loginStore.hasLoginData("email") }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED }*/
|
||||
)
|
||||
|
||||
const val LOGIN_TYPE_VULCAN = 4
|
||||
const val LOGIN_MODE_VULCAN_API = 0
|
||||
const val LOGIN_MODE_VULCAN_WEB = 1
|
||||
const val LOGIN_METHOD_VULCAN_WEB_MAIN = 100
|
||||
const val LOGIN_METHOD_VULCAN_WEB_NEW = 200
|
||||
const val LOGIN_METHOD_VULCAN_WEB_OLD = 300
|
||||
const val LOGIN_METHOD_VULCAN_WEB_MESSAGES = 400
|
||||
const val LOGIN_METHOD_VULCAN_API = 500
|
||||
val vulcanLoginMethods = listOf(
|
||||
/*LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_MAIN, VulcanLoginWebMain::class.java)
|
||||
.withIsPossible { _, _ -> false }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_NEW, VulcanLoginWebNew::class.java)
|
||||
.withIsPossible { _, _ -> false }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_WEB_OLD, VulcanLoginWebOld::class.java)
|
||||
.withIsPossible { _, _ -> false }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_VULCAN_WEB_MAIN },*/
|
||||
|
||||
LoginMethod(LOGIN_TYPE_VULCAN, LOGIN_METHOD_VULCAN_API, VulcanLoginApi::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, loginStore ->
|
||||
if (loginStore.mode == LOGIN_MODE_VULCAN_WEB) LOGIN_METHOD_VULCAN_WEB_NEW else LOGIN_METHOD_NOT_NEEDED
|
||||
}
|
||||
)
|
||||
|
||||
val idziennikLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_IDZIENNIK, LOGIN_METHOD_IDZIENNIK_WEB, IdziennikLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_IDZIENNIK, LOGIN_METHOD_IDZIENNIK_API, IdziennikLoginApi::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_IDZIENNIK_WEB }
|
||||
)
|
||||
|
||||
val templateLoginMethods = listOf(
|
||||
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_WEB, TemplateLoginWeb::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_NOT_NEEDED },
|
||||
|
||||
LoginMethod(LOGIN_TYPE_TEMPLATE, LOGIN_METHOD_TEMPLATE_API, TemplateLoginApi::class.java)
|
||||
.withIsPossible { _, _ -> true }
|
||||
.withRequiredLoginMethod { _, _ -> LOGIN_METHOD_TEMPLATE_WEB }
|
||||
)
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-6.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
object Regexes {
|
||||
val MOBIDZIENNIK_GRADES_SUBJECT_NAME by lazy {
|
||||
"""<div.*?>\n*\s*(.+?)\s*\n*(?:<.*?)??</div>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_COLOR by lazy {
|
||||
"""background-color:([#A-Fa-f0-9]+);""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_CATEGORY by lazy {
|
||||
"""> (.+?):</span>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_CLASS_AVERAGE by lazy {
|
||||
"""Średnia ocen:.*<strong>([0-9]*\.?[0-9]*)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_ADDED_DATE by lazy {
|
||||
"""Wpisano:.*<strong>.+?,\s([0-9]+)\s(.+?)\s([0-9]{4}),\sgodzina\s([0-9:]+)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_COUNT_TO_AVG by lazy {
|
||||
"""Liczona do średniej:.*?<strong>nie<br/?></strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_GRADES_DETAILS by lazy {
|
||||
"""<strong.*?>(.+?)</strong>.*?<sup>.+?</sup>.*?<small>\((.+?)\)</small>.*?<span>.*?Wartość oceny:.*?<strong>([0-9.]+)</strong>.*?Wpisał\(a\):.*?<strong>(.+?)</strong>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
|
||||
val MOBIDZIENNIK_EVENT_TYPE by lazy {
|
||||
"""\(([0-9A-ząęóżźńśłć]*?)\)$""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_LUCKY_NUMBER by lazy {
|
||||
"""class="szczesliwy_numerek".*>0*([0-9]+)(?:/0*[0-9]+)*</a>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val MOBIDZIENNIK_CLASS_CALENDAR by lazy {
|
||||
"""events: (.+),$""".toRegex(RegexOption.MULTILINE)
|
||||
}
|
||||
|
||||
|
||||
|
||||
val IDZIENNIK_LOGIN_HIDDEN_FIELDS by lazy {
|
||||
"""<input type="hidden".+?name="([A-z0-9_]+)?".+?value="([A-z0-9_+-/=]+)?".+?>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_ERROR by lazy {
|
||||
"""id="spanErrorMessage">(.*?)</""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME by lazy {
|
||||
"""Imię i nazwisko:.+?">(.+?)</div>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_IS_PARENT by lazy {
|
||||
"""id="ctl00_CzyRodzic" value="([01])" />""".toRegex()
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR by lazy {
|
||||
"""name="ctl00\${"$"}dxComboRokSzkolny".+?selected="selected".*?value="([0-9]+)">([0-9/]+)<""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT_SELECT by lazy {
|
||||
"""<select.*?name="ctl00\${"$"}dxComboUczniowie".*?</select>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
val IDZIENNIK_LOGIN_FIRST_STUDENT by lazy {
|
||||
"""<option.*?value="([0-9]+)"\sdata-id-ucznia="([A-z0-9]+?)".*?>(.+?)\s(.+?)\s*\((.+?),\s*(.+?)\)</option>""".toRegex(RegexOption.DOT_MATCHES_ALL)
|
||||
}
|
||||
}
|
@ -0,0 +1,179 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2
|
||||
|
||||
import pl.szczodrzynski.edziennik.App.APP_URL
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_APP_SERVER_ERROR
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event.TYPE_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_EVENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_NEW_SHARED_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.Notification.Companion.TYPE_SERVER_MESSAGE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notification.getNotificationTitle
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.getJsonArray
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.network.ServerRequest
|
||||
|
||||
class ServerSync(val data: Data, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "ServerSync"
|
||||
}
|
||||
|
||||
val app = data.app
|
||||
val profileId = data.profile?.id ?: -1
|
||||
val profileName = data.profile?.name ?: ""
|
||||
val profile = data.profile
|
||||
val loginStore = data.loginStore
|
||||
|
||||
private fun getUsernameId(): String {
|
||||
if (loginStore.data == null) {
|
||||
return "NO_LOGIN_STORE"
|
||||
}
|
||||
if (profile?.studentData == null) {
|
||||
return "NO_STUDENT_STORE"
|
||||
}
|
||||
return when (data.loginStore.type) {
|
||||
LoginStore.LOGIN_TYPE_MOBIDZIENNIK -> loginStore.getLoginData("serverName", "MOBI_UN") + ":" + loginStore.getLoginData("username", "MOBI_UN") + ":" + profile.getStudentData("studentId", -1)
|
||||
LoginStore.LOGIN_TYPE_LIBRUS -> profile.getStudentData("schoolName", "LIBRUS_UN") + ":" + profile.getStudentData("accountLogin", "LIBRUS_LOGIN_UN")
|
||||
LoginStore.LOGIN_TYPE_IUCZNIOWIE -> loginStore.getLoginData("schoolName", "IUCZNIOWIE_UN") + ":" + loginStore.getLoginData("username", "IUCZNIOWIE_UN") + ":" + profile.getStudentData("registerId", -1)
|
||||
LoginStore.LOGIN_TYPE_VULCAN -> profile.getStudentData("schoolName", "VULCAN_UN") + ":" + profile.getStudentData("studentId", -1)
|
||||
LoginStore.LOGIN_TYPE_DEMO -> loginStore.getLoginData("serverName", "DEMO_UN") + ":" + loginStore.getLoginData("username", "DEMO_UN") + ":" + profile.getStudentData("studentId", -1)
|
||||
else -> "TYPE_UNKNOWN"
|
||||
}
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (profile?.registration != Profile.REGISTRATION_ENABLED) {
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
|
||||
val request = ServerRequest(
|
||||
app,
|
||||
app.requestScheme+APP_URL+"main.php?sync",
|
||||
"Edziennik2/REG",
|
||||
profile,
|
||||
data.loginStore.type,
|
||||
getUsernameId()
|
||||
)
|
||||
|
||||
if (profile.empty) {
|
||||
request.setBodyParameter("first_run", "true")
|
||||
}
|
||||
|
||||
var hasNotifications = true
|
||||
if (app.appConfig.webPushEnabled) {
|
||||
data.notifications
|
||||
.filterNot { it.posted }
|
||||
.let {
|
||||
if (it.isEmpty()) {
|
||||
hasNotifications = false
|
||||
null
|
||||
}
|
||||
else
|
||||
it
|
||||
}?.forEachIndexed { index, notification ->
|
||||
if (notification.type != TYPE_NEW_SHARED_EVENT
|
||||
&& notification.type != TYPE_SERVER_MESSAGE
|
||||
&& notification.type != TYPE_NEW_SHARED_HOMEWORK) {
|
||||
request.setBodyParameter("notify[$index][type]", notification.type.toString())
|
||||
request.setBodyParameter("notify[$index][title]", notification.title)
|
||||
request.setBodyParameter("notify[$index][text]", notification.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((!app.appConfig.webPushEnabled || !hasNotifications) && !profile.enableSharedEvents) {
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
|
||||
val result = request.runSync()
|
||||
|
||||
if (result == null) {
|
||||
data.error(ApiError(TAG, CODE_APP_SERVER_ERROR)
|
||||
.setCritical(false))
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
var apiResponse = result.toString()
|
||||
if (result.getString("success") != "true") {
|
||||
data.error(ApiError(TAG, CODE_APP_SERVER_ERROR)
|
||||
.setCritical(false))
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
// HERE PROCESS ALL THE RECEIVED EVENTS
|
||||
// add them to the profile and create appropriate notifications
|
||||
result.getJsonArray("events")?.forEach { jEventEl ->
|
||||
val event = jEventEl.asJsonObject
|
||||
val teamCode = event.getString("team")
|
||||
|
||||
// get the target Team from teamCode
|
||||
val team = app.db.teamDao().getByCodeNow(profile.id, teamCode)
|
||||
if (team != null) {
|
||||
|
||||
// create the event from Json. Add the missing teamId and !!profileId!!
|
||||
val eventObject = app.gson.fromJson(event.toString(), Event::class.java)
|
||||
// proguard. disable for Event.class
|
||||
if (eventObject.eventDate == null) {
|
||||
apiResponse += "\n\nEventDate == null\n$event"
|
||||
}
|
||||
eventObject.profileId = profileId
|
||||
eventObject.teamId = team.id
|
||||
eventObject.addedManually = true
|
||||
|
||||
if (eventObject.sharedBy == getUsernameId()) {
|
||||
eventObject.sharedBy = "self"
|
||||
eventObject.sharedByName = profile.studentNameLong
|
||||
}
|
||||
|
||||
val typeObject = app.db.eventTypeDao().getByIdNow(profileId, eventObject.type)
|
||||
|
||||
app.db.eventDao().add(eventObject)
|
||||
|
||||
val metadata = Metadata(
|
||||
profileId,
|
||||
if (eventObject.type == TYPE_HOMEWORK) Metadata.TYPE_HOMEWORK else Metadata.TYPE_EVENT,
|
||||
eventObject.id,
|
||||
profile.empty,
|
||||
true,
|
||||
event.getLong("addedDate") ?: 0
|
||||
)
|
||||
|
||||
val metadataId = app.db.metadataDao().add(metadata)
|
||||
|
||||
// notify if the event is new and not first sync
|
||||
if (metadataId != -1L && !profile.empty) {
|
||||
val text = app.getString(
|
||||
R.string.notification_shared_event_format,
|
||||
eventObject.sharedByName,
|
||||
if (typeObject != null) typeObject.name else "wydarzenie",
|
||||
if (eventObject.eventDate == null) "???" else eventObject.eventDate.formattedString,
|
||||
eventObject.topic
|
||||
)
|
||||
val type = if (eventObject.type == TYPE_HOMEWORK) TYPE_NEW_SHARED_HOMEWORK else TYPE_NEW_SHARED_EVENT
|
||||
data.notifications += Notification(
|
||||
title = app.getNotificationTitle(type),
|
||||
text = text,
|
||||
type = type,
|
||||
profileId = profileId,
|
||||
profileName = profileName,
|
||||
viewId = if (eventObject.type == TYPE_HOMEWORK) DRAWER_ITEM_HOMEWORK else DRAWER_ITEM_AGENDA,
|
||||
addedDate = metadata.addedDate
|
||||
).addExtra("eventId", eventObject.id).addExtra("eventDate", eventObject.eventDate.value.toLong())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onSuccess()
|
||||
}}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class ApiTaskAllFinishedEvent
|
@ -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 ApiTaskErrorEvent(val error: ApiError)
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class ApiTaskFinishedEvent(val profileId: Int)
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
class ApiTaskProgressEvent(val profileId: Int, val progress: Float, val progressText: String?)
|
@ -0,0 +1,9 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class ApiTaskStartedEvent(val profileId: Int, val profile: Profile? = null)
|
@ -0,0 +1,6 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.events
|
||||
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
data class FirstLoginFinishedEvent(val profileList: List<Profile>, val loginStore: LoginStore)
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.requests
|
||||
|
||||
class ServiceCloseRequest
|
@ -0,0 +1,7 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.requests
|
||||
|
||||
class TaskCancelRequest(val taskId: Int)
|
@ -0,0 +1,90 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.task
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.Idziennik
|
||||
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.template.Template
|
||||
import pl.szczodrzynski.edziennik.api.v2.vulcan.Vulcan
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
|
||||
open class EdziennikTask(override val profileId: Int, val request: Any) : IApiTask(profileId) {
|
||||
companion object {
|
||||
private const val TAG = "EdziennikTask"
|
||||
|
||||
fun firstLogin(loginStore: LoginStore) = EdziennikTask(-1, FirstLoginRequest(loginStore))
|
||||
fun sync() = EdziennikTask(-1, SyncRequest())
|
||||
fun syncProfile(profileId: Int, viewIds: List<Pair<Int, Int>>? = null) = EdziennikTask(profileId, SyncProfileRequest(viewIds))
|
||||
fun syncProfileList(profileList: List<Int>) = EdziennikTask(-1, SyncProfileListRequest(profileList))
|
||||
fun messageGet(profileId: Int, messageId: Int) = EdziennikTask(profileId, MessageGetRequest(messageId))
|
||||
fun announcementsRead(profileId: Int) = EdziennikTask(profileId, AnnouncementsReadRequest())
|
||||
}
|
||||
|
||||
private lateinit var loginStore: LoginStore
|
||||
|
||||
override fun prepare(app: App) {
|
||||
if (request is FirstLoginRequest) {
|
||||
// get the requested profile and login store
|
||||
this.profile = null
|
||||
loginStore = request.loginStore
|
||||
// save the profile ID and name as the current task's
|
||||
taskName = app.getString(R.string.edziennik_notification_api_first_login_title)
|
||||
}
|
||||
else {
|
||||
// get the requested profile and login store
|
||||
val profile = app.db.profileDao().getByIdNow(profileId)
|
||||
this.profile = profile
|
||||
if (profile == null || !profile.syncEnabled) {
|
||||
return
|
||||
}
|
||||
val loginStore = app.db.loginStoreDao().getByIdNow(profile.loginStoreId) ?: return
|
||||
this.loginStore = loginStore
|
||||
// save the profile ID and name as the current task's
|
||||
taskName = app.getString(R.string.edziennik_notification_api_sync_title_format, profile.name)
|
||||
}
|
||||
}
|
||||
|
||||
private var edziennikInterface: EdziennikInterface? = null
|
||||
|
||||
fun run(app: App, taskCallback: EdziennikCallback) {
|
||||
edziennikInterface = when (loginStore.type) {
|
||||
LOGIN_TYPE_LIBRUS -> Librus(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_MOBIDZIENNIK -> Mobidziennik(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_VULCAN -> Vulcan(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_IDZIENNIK -> Idziennik(app, profile, loginStore, taskCallback)
|
||||
LOGIN_TYPE_TEMPLATE -> Template(app, profile, loginStore, taskCallback)
|
||||
else -> null
|
||||
}
|
||||
if (edziennikInterface == null) {
|
||||
return
|
||||
}
|
||||
|
||||
when (request) {
|
||||
is SyncProfileRequest -> edziennikInterface?.sync(
|
||||
featureIds = request.viewIds?.flatMap { Features.getIdsByView(it.first, it.second) } ?: Features.getAllIds(),
|
||||
viewId = request.viewIds?.get(0)?.first)
|
||||
is MessageGetRequest -> edziennikInterface?.getMessage(request.messageId)
|
||||
is FirstLoginRequest -> edziennikInterface?.firstLogin()
|
||||
is AnnouncementsReadRequest -> edziennikInterface?.markAllAnnouncementsAsRead()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
edziennikInterface?.cancel()
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "EdziennikTask(profileId=$profileId, request=$request, edziennikInterface=$edziennikInterface)"
|
||||
}
|
||||
|
||||
data class FirstLoginRequest(val loginStore: LoginStore)
|
||||
class SyncRequest
|
||||
data class SyncProfileRequest(val viewIds: List<Pair<Int, Int>>? = null)
|
||||
data class SyncProfileListRequest(val profileList: List<Int>)
|
||||
data class MessageGetRequest(val messageId: Int)
|
||||
class AnnouncementsReadRequest
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-1.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.task
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||
import pl.szczodrzynski.edziennik.api.v2.EdziennikNotification
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class ErrorReportTask : IApiTask(-1) {
|
||||
override fun prepare(app: App) {
|
||||
taskName = app.getString(R.string.edziennik_notification_api_error_report_title)
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
|
||||
}
|
||||
|
||||
fun run(app: App, taskCallback: EdziennikCallback, notification: EdziennikNotification, errorList: MutableList<ApiError>) {
|
||||
errorList.forEach { error ->
|
||||
Utils.d(ApiService.TAG, "Error ${error.tag} profile ${error.profileId}: code ${error.errorCode}")
|
||||
}
|
||||
errorList.clear()
|
||||
|
||||
taskCallback.onCompleted()
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.task
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.v2.ApiService
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
abstract class IApiTask(open val profileId: Int) {
|
||||
var taskId: Int = 0
|
||||
var profile: Profile? = null
|
||||
var taskName: String? = null
|
||||
|
||||
/**
|
||||
* A method called before running the task.
|
||||
* It is synchronous and its main task is
|
||||
* to prepare the correct task name.
|
||||
*/
|
||||
abstract fun prepare(app: App)
|
||||
abstract fun cancel()
|
||||
|
||||
fun enqueue(context: Context) {
|
||||
context.startService(Intent(context, ApiService::class.java))
|
||||
EventBus.getDefault().postSticky(this)
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return "IApiTask(profileId=$profileId, taskId=$taskId, profile=$profile, taskName=$taskName)"
|
||||
}
|
||||
}
|
@ -0,0 +1,89 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.events.task
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.content.Intent
|
||||
import android.os.Build
|
||||
import androidx.core.app.NotificationCompat
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.MainActivity
|
||||
import pl.szczodrzynski.edziennik.Notifier.ID_NOTIFICATIONS
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.interfaces.EdziennikCallback
|
||||
import pl.szczodrzynski.edziennik.utils.models.Notification
|
||||
import kotlin.math.min
|
||||
|
||||
class NotifyTask : IApiTask(-1) {
|
||||
override fun prepare(app: App) {
|
||||
taskName = app.getString(R.string.edziennik_notification_api_notify_title)
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
|
||||
}
|
||||
|
||||
fun run(app: App, taskCallback: EdziennikCallback) {
|
||||
val list = app.db.notificationDao().getNotPostedNow()
|
||||
val notificationList = list.subList(0, min(15, list.size))
|
||||
|
||||
var unreadCount = list.size
|
||||
|
||||
for (notification in notificationList) {
|
||||
val intent = Intent(app, MainActivity::class.java)
|
||||
notification.fillIntent(intent)
|
||||
val pendingIntent = PendingIntent.getActivity(app, notification.id, intent, 0)
|
||||
val notificationBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||
// title, text, type, date
|
||||
.setContentTitle(notification.title)
|
||||
.setContentText(notification.text)
|
||||
.setSubText(Notification.stringType(app, notification.type))
|
||||
.setWhen(notification.addedDate)
|
||||
.setTicker(app.getString(R.string.notification_ticker_format, Notification.stringType(app, notification.type)))
|
||||
// icon, color, lights, priority
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(app.notifier.notificationColor)
|
||||
.setLights(-0xff0001, 2000, 2000)
|
||||
.setPriority(app.notifier.notificationPriority)
|
||||
// channel, group, style
|
||||
.setChannelId(app.notifier.notificationGroup)
|
||||
.setGroup(app.notifier.notificationGroup)
|
||||
.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY)
|
||||
.setStyle(NotificationCompat.BigTextStyle().bigText(notification.text))
|
||||
// intent, auto cancel
|
||||
.setContentIntent(pendingIntent)
|
||||
.setAutoCancel(true)
|
||||
if (!app.notifier.shouldBeQuiet()) {
|
||||
notificationBuilder.setDefaults(app.notifier.notificationDefaults)
|
||||
}
|
||||
app.notifier.notificationManager.notify(notification.id, notificationBuilder.build())
|
||||
}
|
||||
|
||||
if (notificationList.isNotEmpty() && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
val intent = Intent(app, MainActivity::class.java)
|
||||
intent.action = "android.intent.action.MAIN"
|
||||
intent.putExtra("fragmentId", MainActivity.DRAWER_ITEM_NOTIFICATIONS)
|
||||
val pendingIntent = PendingIntent.getActivity(app, ID_NOTIFICATIONS,
|
||||
intent, 0)
|
||||
|
||||
val groupBuilder = NotificationCompat.Builder(app, app.notifier.notificationGroup)
|
||||
.setSmallIcon(R.drawable.ic_notification)
|
||||
.setColor(app.notifier.notificationColor)
|
||||
.setContentTitle(app.getString(R.string.notification_new_notification_title_format, unreadCount))
|
||||
.setGroupSummary(true)
|
||||
.setAutoCancel(true)
|
||||
.setChannelId(app.notifier.notificationGroup)
|
||||
.setGroup(app.notifier.notificationGroup)
|
||||
.setLights(-0xff0001, 2000, 2000)
|
||||
.setPriority(app.notifier.notificationPriority)
|
||||
.setContentIntent(pendingIntent)
|
||||
.setStyle(NotificationCompat.BigTextStyle())
|
||||
if (!app.notifier.shouldBeQuiet()) {
|
||||
groupBuilder.setDefaults(app.notifier.notificationDefaults)
|
||||
}
|
||||
app.notifier.notificationManager.notify(ID_NOTIFICATIONS, groupBuilder.build())
|
||||
}
|
||||
|
||||
app.db.notificationDao().setAllPosted()
|
||||
|
||||
taskCallback.onCompleted()
|
||||
}
|
||||
}
|
@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik
|
||||
|
||||
import androidx.core.util.set
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_API
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
class DataIdziennik(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
fun isWebLoginValid() = loginExpiryTime-30 > currentTimeUnix() && webSessionId.isNotNullNorEmpty() && webAuth.isNotNullNorEmpty()
|
||||
fun isApiLoginValid() = apiExpiryTime-30 > currentTimeUnix() && apiBearer.isNotNullNorEmpty()
|
||||
|
||||
override fun satisfyLoginMethods() {
|
||||
loginMethods.clear()
|
||||
if (isWebLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_IDZIENNIK_WEB
|
||||
app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("ASP.NET_SessionId_iDziennik")
|
||||
.value(webSessionId!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name(".ASPXAUTH")
|
||||
.value(webAuth!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
}
|
||||
if (isApiLoginValid())
|
||||
loginMethods += LOGIN_METHOD_IDZIENNIK_API
|
||||
}
|
||||
|
||||
private var mLoginExpiryTime: Long? = null
|
||||
var loginExpiryTime: Long
|
||||
get() { mLoginExpiryTime = mLoginExpiryTime ?: loginStore.getLoginData("loginExpiryTime", 0L); return mLoginExpiryTime ?: 0L }
|
||||
set(value) { loginStore.putLoginData("loginExpiryTime", value); mLoginExpiryTime = value }
|
||||
|
||||
private var mApiExpiryTime: Long? = null
|
||||
var apiExpiryTime: Long
|
||||
get() { mApiExpiryTime = mApiExpiryTime ?: loginStore.getLoginData("apiExpiryTime", 0L); return mApiExpiryTime ?: 0L }
|
||||
set(value) { loginStore.putLoginData("apiExpiryTime", value); mApiExpiryTime = value }
|
||||
|
||||
/* __ __ _
|
||||
\ \ / / | |
|
||||
\ \ /\ / /__| |__
|
||||
\ \/ \/ / _ \ '_ \
|
||||
\ /\ / __/ |_) |
|
||||
\/ \/ \___|_._*/
|
||||
private var mWebSchoolName: String? = null
|
||||
var webSchoolName: String?
|
||||
get() { mWebSchoolName = mWebSchoolName ?: loginStore.getLoginData("schoolName", null); return mWebSchoolName }
|
||||
set(value) { loginStore.putLoginData("schoolName", value); mWebSchoolName = value }
|
||||
private var mWebUsername: String? = null
|
||||
var webUsername: String?
|
||||
get() { mWebUsername = mWebUsername ?: loginStore.getLoginData("username", null); return mWebUsername }
|
||||
set(value) { loginStore.putLoginData("username", value); mWebUsername = value }
|
||||
private var mWebPassword: String? = null
|
||||
var webPassword: String?
|
||||
get() { mWebPassword = mWebPassword ?: loginStore.getLoginData("password", null); return mWebPassword }
|
||||
set(value) { loginStore.putLoginData("password", value); mWebPassword = value }
|
||||
|
||||
private var mWebSessionId: String? = null
|
||||
var webSessionId: String?
|
||||
get() { mWebSessionId = mWebSessionId ?: loginStore.getLoginData("webSessionId", null); return mWebSessionId }
|
||||
set(value) { loginStore.putLoginData("webSessionId", value); mWebSessionId = value }
|
||||
private var mWebAuth: String? = null
|
||||
var webAuth: String?
|
||||
get() { mWebAuth = mWebAuth ?: loginStore.getLoginData("webAuth", null); return mWebAuth }
|
||||
set(value) { loginStore.putLoginData("webAuth", value); mWebAuth = value }
|
||||
|
||||
/* _
|
||||
/\ (_)
|
||||
/ \ _ __ _
|
||||
/ /\ \ | '_ \| |
|
||||
/ ____ \| |_) | |
|
||||
/_/ \_\ .__/|_|
|
||||
| |
|
||||
|*/
|
||||
private var mApiBearer: String? = null
|
||||
var apiBearer: String?
|
||||
get() { mApiBearer = mApiBearer ?: loginStore.getLoginData("apiBearer", null); return mApiBearer }
|
||||
set(value) { loginStore.putLoginData("apiBearer", value); mApiBearer = value }
|
||||
|
||||
/* ____ _ _
|
||||
/ __ \| | | |
|
||||
| | | | |_| |__ ___ _ __
|
||||
| | | | __| '_ \ / _ \ '__|
|
||||
| |__| | |_| | | | __/ |
|
||||
\____/ \__|_| |_|\___|*/
|
||||
private var mStudentId: String? = null
|
||||
var studentId: String?
|
||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", null); return mStudentId }
|
||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = value }
|
||||
|
||||
private var mRegisterId: Int? = null
|
||||
var registerId: Int
|
||||
get() { mRegisterId = mRegisterId ?: profile?.getStudentData("registerId", 0); return mRegisterId ?: 0 }
|
||||
set(value) { profile?.putStudentData("registerId", value) ?: return; mRegisterId = value }
|
||||
|
||||
private var mSchoolYearId: Int? = null
|
||||
var schoolYearId: Int
|
||||
get() { mSchoolYearId = mSchoolYearId ?: profile?.getStudentData("schoolYearId", 0); return mSchoolYearId ?: 0 }
|
||||
set(value) { profile?.putStudentData("schoolYearId", value) ?: return; mSchoolYearId = value }
|
||||
|
||||
|
||||
|
||||
/* _ _ _ _ _
|
||||
| | | | | (_) |
|
||||
| | | | |_ _| |___
|
||||
| | | | __| | / __|
|
||||
| |__| | |_| | \__ \
|
||||
\____/ \__|_|_|__*/
|
||||
fun getSubject(name: String, id: Long?, shortName: String): Subject {
|
||||
var subject = if (id == null)
|
||||
subjectList.singleOrNull { it.longName == name }
|
||||
else
|
||||
subjectList.singleOrNull { it.id == id }
|
||||
|
||||
if (subject == null) {
|
||||
subject = Subject(profileId, id ?: name.crc16().toLong(), name, shortName)
|
||||
subjectList[subject.id] = subject
|
||||
}
|
||||
return subject
|
||||
}
|
||||
|
||||
fun getTeacher(firstName: String, lastName: String): Teacher {
|
||||
val teacher = teacherList.singleOrNull { it.fullName == "$firstName $lastName" }
|
||||
return validateTeacher(teacher, firstName, lastName)
|
||||
}
|
||||
fun getTeacher(firstNameChar: Char, lastName: String): Teacher {
|
||||
val teacher = teacherList.singleOrNull { it.shortName == "$firstNameChar.$lastName" }
|
||||
return validateTeacher(teacher, firstNameChar.toString(), lastName)
|
||||
}
|
||||
fun getTeacherByLastFirst(nameLastFirst: String): Teacher {
|
||||
val nameParts = nameLastFirst.split(" ")
|
||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[1], nameParts[0])
|
||||
}
|
||||
|
||||
fun getTeacherByFirstLast(nameFirstLast: String): Teacher {
|
||||
val nameParts = nameFirstLast.split(" ")
|
||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0], nameParts[1])
|
||||
}
|
||||
|
||||
fun getTeacherByFDotLast(nameFDotLast: String): Teacher {
|
||||
val nameParts = nameFDotLast.split(".")
|
||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0][0], nameParts[1])
|
||||
}
|
||||
|
||||
fun getTeacherByFDotSpaceLast(nameFDotSpaceLast: String): Teacher {
|
||||
val nameParts = nameFDotSpaceLast.split(".")
|
||||
return if (nameParts.size == 1) getTeacher(nameParts[0], "") else getTeacher(nameParts[0][0], nameParts[1])
|
||||
}
|
||||
|
||||
private fun validateTeacher(teacher: Teacher?, firstName: String, lastName: String): Teacher {
|
||||
(teacher ?: Teacher(profileId, -1, firstName, lastName).apply {
|
||||
id = shortName.crc16().toLong()
|
||||
teacherList[id] = this
|
||||
}).apply {
|
||||
if (firstName.length > 1)
|
||||
name = firstName
|
||||
surname = lastName
|
||||
return this
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.v2.CODE_INTERNAL_LIBRUS_ACCOUNT_410
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikData
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.firstlogin.IdziennikFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennikLoginMethods
|
||||
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.prepare
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Idziennik(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
companion object {
|
||||
private const val TAG = "Idziennik"
|
||||
}
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataIdziennik
|
||||
|
||||
init {
|
||||
data = DataIdziennik(app, profile, loginStore).apply {
|
||||
callback = wrapCallback(this@Idziennik.callback)
|
||||
satisfyLoginMethods()
|
||||
}
|
||||
}
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notifyAndSyncEvents {
|
||||
callback.onCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|__ __| | /\ | | (_) | | |
|
||||
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
|
||||
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
|
||||
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
||||
data.prepare(idziennikLoginMethods, IdziennikFeatures, featureIds, viewId)
|
||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
IdziennikLogin(data) {
|
||||
IdziennikData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(messageId: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
IdziennikFirstLogin(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
return object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
override fun onProgress(step: Float) {
|
||||
callback.onProgress(step)
|
||||
}
|
||||
|
||||
override fun onStartProgress(stringRes: Int) {
|
||||
callback.onStartProgress(stringRes)
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Feature
|
||||
|
||||
const val ENDPOINT_IDZIENNIK_WEB_TIMETABLE = 1030
|
||||
const val ENDPOINT_IDZIENNIK_WEB_GRADES = 1040
|
||||
const val ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES = 1050
|
||||
const val ENDPOINT_IDZIENNIK_WEB_EXAMS = 1060
|
||||
const val ENDPOINT_IDZIENNIK_WEB_NOTICES = 1070
|
||||
const val ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS = 1080
|
||||
const val ENDPOINT_IDZIENNIK_WEB_ATTENDANCE = 1090
|
||||
const val ENDPOINT_IDZIENNIK_WEB_MESSAGES_INBOX = 1110
|
||||
const val ENDPOINT_IDZIENNIK_WEB_MESSAGES_SENT = 1120
|
||||
const val ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER = 2010
|
||||
const val ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX = 2110
|
||||
const val ENDPOINT_IDZIENNIK_API_MESSAGES_SENT = 2120
|
||||
|
||||
val IdziennikFeatures = listOf(
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_TIMETABLE, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_TIMETABLE to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_GRADES, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_GRADES to LOGIN_METHOD_IDZIENNIK_WEB,
|
||||
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_AGENDA, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_EXAMS to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_BEHAVIOUR, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_NOTICES to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_ATTENDANCE, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)),
|
||||
|
||||
/*Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_INBOX, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_MESSAGES_INBOX to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)).withPriority(2),
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_SENT, listOf(
|
||||
ENDPOINT_IDZIENNIK_WEB_MESSAGES_SENT to LOGIN_METHOD_IDZIENNIK_WEB
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_WEB)).withPriority(2),*/
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_INBOX, listOf(
|
||||
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX to LOGIN_METHOD_IDZIENNIK_API
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_API)),
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_MESSAGES_SENT, listOf(
|
||||
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT to LOGIN_METHOD_IDZIENNIK_API
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_API)),
|
||||
|
||||
Feature(LOGIN_TYPE_IDZIENNIK, FEATURE_LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER to LOGIN_METHOD_IDZIENNIK_API
|
||||
), listOf(LOGIN_METHOD_IDZIENNIK_API))
|
||||
)
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
open class IdziennikApi(open val data: DataIdziennik) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikApi"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun apiGet(tag: String, endpointTemplate: String, method: Int = GET, parameters: Map<String, Any> = emptyMap(), onSuccess: (json: JsonElement) -> Unit) {
|
||||
val endpoint = endpointTemplate.replace("\$STUDENT_ID", data.studentId ?: "")
|
||||
Utils.d(tag, "Request: Idziennik/API - $IDZIENNIK_API_URL/$endpoint")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
val json = try {
|
||||
JsonParser().parse(text)
|
||||
} catch (_: Exception) { null }
|
||||
|
||||
var error: String? = null
|
||||
if (json == null) {
|
||||
error = text
|
||||
}
|
||||
else if (json is JsonObject) {
|
||||
error = if (response?.code() == 200) null else
|
||||
json.getString("message") ?: json.toString()
|
||||
}
|
||||
error?.let { code ->
|
||||
when (code) {
|
||||
"Authorization has been denied for this request." -> ERROR_IDZIENNIK_API_ACCESS_DENIED
|
||||
else -> ERROR_IDZIENNIK_API_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(tag, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(json!!)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_IDZIENNIK_API_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$IDZIENNIK_API_URL/$endpoint")
|
||||
.userAgent(IDZIENNIK_API_USER_AGENT)
|
||||
.addHeader("Authorization", "Bearer ${data.apiBearer}")
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> {
|
||||
postJson()
|
||||
val json = JsonObject()
|
||||
parameters.map { (name, value) ->
|
||||
when (value) {
|
||||
is JsonObject -> json.add(name, value)
|
||||
is JsonArray -> json.add(name, value)
|
||||
is String -> json.addProperty(name, value)
|
||||
is Int -> json.addProperty(name, value)
|
||||
is Long -> json.addProperty(name, value)
|
||||
is Float -> json.addProperty(name, value)
|
||||
is Char -> json.addProperty(name, value)
|
||||
}
|
||||
}
|
||||
setJsonBody(json)
|
||||
}
|
||||
}
|
||||
}
|
||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_INTERNAL_ERROR)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiCurrentRegister
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiMessagesInbox
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.api.IdziennikApiMessagesSent
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.web.*
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class IdziennikData(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikData"
|
||||
}
|
||||
|
||||
init {
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||
if (data.targetEndpointIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (data.cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useEndpoint(data.targetEndpointIds.removeAt(0)) {
|
||||
data.progress(data.progressStep)
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId")
|
||||
when (endpointId) {
|
||||
ENDPOINT_IDZIENNIK_WEB_TIMETABLE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_timetable)
|
||||
IdziennikWebTimetable(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
IdziennikWebGrades(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_proposed_grades)
|
||||
IdziennikWebProposedGrades(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_EXAMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_exams)
|
||||
IdziennikWebExams(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_NOTICES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
IdziennikWebNotices(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
IdziennikWebAnnouncements(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_WEB_ATTENDANCE -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
IdziennikWebAttendance(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
IdziennikApiCurrentRegister(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||
IdziennikApiMessagesInbox(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_IDZIENNIK_API_MESSAGES_SENT -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||
IdziennikApiMessagesSent(data) { onSuccess() }
|
||||
}
|
||||
else -> onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.HTTP_INTERNAL_ERROR
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
|
||||
open class IdziennikWeb(open val data: DataIdziennik) {
|
||||
companion object {
|
||||
const val TAG = "IdziennikWeb"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun webApiGet(tag: String, endpoint: String, parameters: Map<String, Any> = emptyMap(), onSuccess: (json: JsonObject) -> Unit) {
|
||||
d(tag, "Request: Idziennik/Web/API - $IDZIENNIK_WEB_URL/$endpoint")
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null && response?.parserErrorBody == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
when {
|
||||
response?.code() == HTTP_UNAUTHORIZED -> ERROR_IDZIENNIK_WEB_ACCESS_DENIED
|
||||
response?.code() == HTTP_INTERNAL_ERROR -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
||||
response?.parserErrorBody != null -> when {
|
||||
response.parserErrorBody.contains("Identyfikator zgłoszenia") -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
||||
response.parserErrorBody.contains("Hasło dostępu do systemu wygasło") -> ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED
|
||||
response.parserErrorBody.contains("Trwają prace konserwacyjne") -> ERROR_IDZIENNIK_WEB_MAINTENANCE
|
||||
else -> ERROR_IDZIENNIK_WEB_OTHER
|
||||
}
|
||||
else -> null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(json?.toString() ?: response?.parserErrorBody)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (json == null) {
|
||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(json)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_IDZIENNIK_WEB_API_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$IDZIENNIK_WEB_URL/$endpoint")
|
||||
.userAgent(IDZIENNIK_USER_AGENT)
|
||||
.postJson()
|
||||
.apply {
|
||||
val json = JsonObject()
|
||||
parameters.map { (name, value) ->
|
||||
when (value) {
|
||||
is JsonObject -> json.add(name, value)
|
||||
is JsonArray -> json.add(name, value)
|
||||
is String -> json.addProperty(name, value)
|
||||
is Int -> json.addProperty(name, value)
|
||||
is Long -> json.addProperty(name, value)
|
||||
is Float -> json.addProperty(name, value)
|
||||
is Char -> json.addProperty(name, value)
|
||||
}
|
||||
}
|
||||
setJsonBody(json)
|
||||
}
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HTTP_INTERNAL_ERROR)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
fun webGet(tag: String, endpoint: String, onSuccess: (text: String) -> Unit) {
|
||||
d(tag, "Request: Idziennik/Web - $IDZIENNIK_WEB_URL/$endpoint")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
if (!text.contains("czyWyswietlicDostepMobilny")) {
|
||||
when {
|
||||
text.contains("Identyfikator zgłoszenia") -> ERROR_IDZIENNIK_WEB_SERVER_ERROR
|
||||
text.contains("Hasło dostępu do systemu wygasło") -> ERROR_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED
|
||||
text.contains("Trwają prace konserwacyjne") -> ERROR_IDZIENNIK_WEB_MAINTENANCE
|
||||
else -> ERROR_IDZIENNIK_WEB_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(text)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_IDZIENNIK_WEB_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$IDZIENNIK_WEB_URL/$endpoint")
|
||||
.userAgent(IDZIENNIK_USER_AGENT)
|
||||
.get()
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_CURRENT_REGISTER
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class IdziennikApiCurrentRegister(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikApi(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikApiCurrentRegister"
|
||||
}
|
||||
|
||||
init {
|
||||
data.profile?.luckyNumber = -1
|
||||
data.profile?.luckyNumberDate = null
|
||||
|
||||
apiGet(TAG, IDZIENNIK_API_CURRENT_REGISTER) { json ->
|
||||
if (json !is JsonObject) {
|
||||
onSuccess()
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
var nextSync = System.currentTimeMillis() + 14*DAY*1000
|
||||
|
||||
val settings = json.getJsonObject("ustawienia")?.apply {
|
||||
profile?.dateSemester1Start = getString("poczatekSemestru1")?.let { Date.fromY_m_d(it) }
|
||||
profile?.dateSemester2Start = getString("koniecSemestru1")?.let { Date.fromY_m_d(it).stepForward(0, 0, 1) }
|
||||
profile?.dateYearEnd = getString("koniecSemestru2")?.let { Date.fromY_m_d(it) }
|
||||
}
|
||||
|
||||
json.getInt("szczesliwyNumerek")?.let { luckyNumber ->
|
||||
val luckyNumberDate = Date.getToday()
|
||||
settings.getString("godzinaPublikacjiSzczesliwegoLosu")
|
||||
?.let { Time.fromH_m(it) }
|
||||
?.let { publishTime ->
|
||||
val now = Time.getNow()
|
||||
if (publishTime.value < 150000 && now.value < publishTime.value) {
|
||||
nextSync = luckyNumberDate.combineWith(publishTime)
|
||||
luckyNumberDate.stepForward(0, 0, -1) // the lucky number is still for yesterday
|
||||
}
|
||||
else if (publishTime.value >= 150000 && now.value > publishTime.value) {
|
||||
luckyNumberDate.stepForward(0, 0, 1) // the lucky number is already for tomorrow
|
||||
nextSync = luckyNumberDate.combineWith(publishTime)
|
||||
}
|
||||
else if (publishTime.value < 150000) {
|
||||
nextSync = luckyNumberDate
|
||||
.clone()
|
||||
.stepForward(0, 0, 1)
|
||||
.combineWith(publishTime)
|
||||
}
|
||||
else {
|
||||
nextSync = luckyNumberDate.combineWith(publishTime)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val luckyNumberObject = LuckyNumber(
|
||||
data.profileId,
|
||||
Date.getToday(),
|
||||
luckyNumber
|
||||
)
|
||||
|
||||
data.luckyNumberList.add(luckyNumberObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LUCKY_NUMBER,
|
||||
luckyNumberObject.date.value.toLong(),
|
||||
data.profile?.empty ?: false,
|
||||
data.profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_CURRENT_REGISTER, syncAt = nextSync)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_INBOX
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
|
||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_DELETED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getBoolean
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc32
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikApiMessagesInbox(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikApi(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikApiMessagesInbox"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, IDZIENNIK_API_MESSAGES_INBOX) { json ->
|
||||
if (json !is JsonArray) {
|
||||
onSuccess()
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
json.asJsonObjectList()?.forEach { jMessage ->
|
||||
val subject = jMessage.getString("tytul")
|
||||
if (subject?.contains("(") == true && subject.startsWith("iDziennik - "))
|
||||
return@forEach
|
||||
if (subject?.startsWith("Uwaga dla ucznia (klasa:") == true)
|
||||
return@forEach
|
||||
|
||||
val messageIdStr = jMessage.getString("id")
|
||||
val messageId = crc32((messageIdStr + "0").toByteArray())
|
||||
|
||||
var body = "[META:$messageIdStr;-1]"
|
||||
body += jMessage.getString("tresc")?.replace("\n".toRegex(), "<br>")
|
||||
|
||||
val readDate = if (jMessage.getBoolean("odczytana") == true) Date.fromIso(jMessage.getString("wersjaRekordu")) else 0
|
||||
val sentDate = Date.fromIso(jMessage.getString("dataWyslania"))
|
||||
|
||||
val sender = jMessage.getAsJsonObject("nadawca")
|
||||
val rTeacher = data.getTeacher(
|
||||
sender.getString("imie") ?: "",
|
||||
sender.getString("nazwisko") ?: ""
|
||||
)
|
||||
rTeacher.loginId = sender.getString("id") + ":" + sender.getString("usr")
|
||||
|
||||
val message = Message(
|
||||
profileId,
|
||||
messageId,
|
||||
subject,
|
||||
body,
|
||||
if (jMessage.getBoolean("rekordUsuniety") == true) TYPE_DELETED else TYPE_RECEIVED,
|
||||
rTeacher.id,
|
||||
-1
|
||||
)
|
||||
|
||||
val messageRecipient = MessageRecipient(
|
||||
profileId,
|
||||
-1 /* me */,
|
||||
-1,
|
||||
readDate,
|
||||
/*messageId*/ messageId
|
||||
)
|
||||
|
||||
data.messageList.add(message)
|
||||
data.messageRecipientList.add(messageRecipient)
|
||||
data.messageMetadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
message.id,
|
||||
readDate > 0,
|
||||
readDate > 0 || profile?.empty ?: false,
|
||||
sentDate
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_INBOX, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-30.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.api
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_API_MESSAGES_SENT
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_API_MESSAGES_SENT
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikApi
|
||||
import pl.szczodrzynski.edziennik.asJsonObjectList
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message.TYPE_SENT
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.crc32
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikApiMessagesSent(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikApi(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikApiMessagesSent"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, IDZIENNIK_API_MESSAGES_SENT) { json ->
|
||||
if (json !is JsonArray) {
|
||||
onSuccess()
|
||||
return@apiGet
|
||||
}
|
||||
|
||||
json.asJsonObjectList()?.forEach { jMessage ->
|
||||
val messageIdStr = jMessage.get("id").asString
|
||||
val messageId = crc32((messageIdStr + "1").toByteArray())
|
||||
|
||||
val subject = jMessage.get("tytul").asString
|
||||
|
||||
var body = "[META:$messageIdStr;-1]"
|
||||
body += jMessage.get("tresc").asString.replace("\n".toRegex(), "<br>")
|
||||
|
||||
val sentDate = Date.fromIso(jMessage.get("dataWyslania").asString)
|
||||
|
||||
val message = Message(
|
||||
profileId,
|
||||
messageId,
|
||||
subject,
|
||||
body,
|
||||
TYPE_SENT,
|
||||
-1,
|
||||
-1
|
||||
)
|
||||
|
||||
for (recipientEl in jMessage.getAsJsonArray("odbiorcy")) {
|
||||
val recipient = recipientEl.asJsonObject
|
||||
var firstName = recipient.get("imie").asString
|
||||
var lastName = recipient.get("nazwisko").asString
|
||||
if (firstName.isEmpty() || lastName.isEmpty()) {
|
||||
firstName = "usunięty"
|
||||
lastName = "użytkownik"
|
||||
}
|
||||
val rTeacher = data.getTeacher(firstName, lastName)
|
||||
rTeacher.loginId = recipient.get("id").asString + ":" + recipient.get("usr").asString
|
||||
|
||||
val messageRecipient = MessageRecipient(
|
||||
profileId,
|
||||
rTeacher.id,
|
||||
-1,
|
||||
-1,
|
||||
/*messageId*/ messageId
|
||||
)
|
||||
data.messageRecipientIgnoreList.add(messageRecipient)
|
||||
}
|
||||
|
||||
data.messageList.add(message)
|
||||
data.metadataList.add(Metadata(profileId, Metadata.TYPE_MESSAGE, message.id, true, true, sentDate))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_API_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import com.google.gson.JsonArray
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebAnnouncements(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebAnnouncements"
|
||||
}
|
||||
|
||||
init {
|
||||
val param = JsonObject()
|
||||
param.add("parametryFiltrow", JsonArray())
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_ANNOUNCEMENTS, mapOf(
|
||||
"uczenId" to (data.studentId ?: ""),
|
||||
"param" to param
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
for (jAnnouncementEl in json.getAsJsonArray("ListK")) {
|
||||
val jAnnouncement = jAnnouncementEl.asJsonObject
|
||||
// jAnnouncement
|
||||
val announcementId = jAnnouncement.get("Id").asLong
|
||||
|
||||
val rTeacher = data.getTeacherByFirstLast(jAnnouncement.get("Autor").asString)
|
||||
val addedDate = java.lang.Long.parseLong(jAnnouncement.get("DataDodania").asString.replace("[^\\d]".toRegex(), ""))
|
||||
val startDate = Date.fromMillis(java.lang.Long.parseLong(jAnnouncement.get("DataWydarzenia").asString.replace("[^\\d]".toRegex(), "")))
|
||||
|
||||
val announcementObject = Announcement(
|
||||
profileId,
|
||||
announcementId,
|
||||
jAnnouncement.get("Temat").asString,
|
||||
jAnnouncement.get("Tresc").asString,
|
||||
startDate,
|
||||
null,
|
||||
rTeacher.id
|
||||
)
|
||||
data.announcementList.add(announcementObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
announcementObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_ATTENDANCE
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.crc16
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance.*
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class IdziennikWebAttendance(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebAttendance"
|
||||
}
|
||||
|
||||
private var attendanceYear = Date.getToday().year
|
||||
private var attendanceMonth = Date.getToday().month
|
||||
private var attendancePrevMonthChecked = false
|
||||
|
||||
init {
|
||||
getAttendance()
|
||||
}
|
||||
|
||||
private fun getAttendance() {
|
||||
webApiGet(TAG, IDZIENNIK_WEB_ATTENDANCE, mapOf(
|
||||
"idPozDziennika" to data.registerId,
|
||||
"mc" to attendanceMonth,
|
||||
"rok" to attendanceYear,
|
||||
"dataTygodnia" to ""
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
for (jAttendanceEl in json.getAsJsonArray("Obecnosci")) {
|
||||
val jAttendance = jAttendanceEl.asJsonObject
|
||||
// jAttendance
|
||||
val attendanceTypeIdziennik = jAttendance.get("TypObecnosci").asInt
|
||||
if (attendanceTypeIdziennik == 5 || attendanceTypeIdziennik == 7)
|
||||
continue
|
||||
val attendanceDate = Date.fromY_m_d(jAttendance.get("Data").asString)
|
||||
val attendanceTime = Time.fromH_m(jAttendance.get("OdDoGodziny").asString)
|
||||
if (attendanceDate.combineWith(attendanceTime) > System.currentTimeMillis())
|
||||
continue
|
||||
|
||||
val attendanceId = jAttendance.get("IdLesson").asString.crc16().toLong()
|
||||
val rSubject = data.getSubject(jAttendance.get("Przedmiot").asString, jAttendance.get("IdPrzedmiot").asLong, "")
|
||||
val rTeacher = data.getTeacherByFDotSpaceLast(jAttendance.get("PrzedmiotNauczyciel").asString)
|
||||
|
||||
var attendanceName = "obecność"
|
||||
var attendanceType = Attendance.TYPE_CUSTOM
|
||||
|
||||
when (attendanceTypeIdziennik) {
|
||||
1 /* nieobecność usprawiedliwiona */ -> {
|
||||
attendanceName = "nieobecność usprawiedliwiona"
|
||||
attendanceType = TYPE_ABSENT_EXCUSED
|
||||
}
|
||||
2 /* spóźnienie */ -> {
|
||||
attendanceName = "spóźnienie"
|
||||
attendanceType = TYPE_BELATED
|
||||
}
|
||||
3 /* nieobecność nieusprawiedliwiona */ -> {
|
||||
attendanceName = "nieobecność nieusprawiedliwiona"
|
||||
attendanceType = TYPE_ABSENT
|
||||
}
|
||||
4 /* zwolnienie */, 9 /* zwolniony / obecny */ -> {
|
||||
attendanceType = TYPE_RELEASED
|
||||
if (attendanceTypeIdziennik == 4)
|
||||
attendanceName = "zwolnienie"
|
||||
if (attendanceTypeIdziennik == 9)
|
||||
attendanceName = "zwolnienie / obecność"
|
||||
}
|
||||
0 /* obecny */, 8 /* Wycieczka */ -> {
|
||||
attendanceType = TYPE_PRESENT
|
||||
if (attendanceTypeIdziennik == 8)
|
||||
attendanceName = "wycieczka"
|
||||
}
|
||||
}
|
||||
|
||||
val semester = profile?.dateToSemester(attendanceDate) ?: 1
|
||||
|
||||
val attendanceObject = Attendance(
|
||||
profileId,
|
||||
attendanceId,
|
||||
rTeacher.id,
|
||||
rSubject.id,
|
||||
semester,
|
||||
attendanceName,
|
||||
attendanceDate,
|
||||
attendanceTime,
|
||||
attendanceType
|
||||
)
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
if (attendanceObject.type != TYPE_PRESENT) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
attendanceObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
val attendanceDateValue = attendanceYear * 10000 + attendanceMonth * 100
|
||||
if (profile?.empty == true && attendanceDateValue > profile?.getSemesterStart(1)?.value ?: 99999999) {
|
||||
attendancePrevMonthChecked = true // do not need to check prev month later
|
||||
attendanceMonth--
|
||||
if (attendanceMonth < 1) {
|
||||
attendanceMonth = 12
|
||||
attendanceYear--
|
||||
}
|
||||
getAttendance()
|
||||
} else if (!attendancePrevMonthChecked /* get also the previous month */) {
|
||||
attendanceMonth--
|
||||
if (attendanceMonth < 1) {
|
||||
attendanceMonth = 12
|
||||
attendanceYear--
|
||||
}
|
||||
attendancePrevMonthChecked = true
|
||||
getAttendance()
|
||||
} else {
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_ATTENDANCE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_EXAMS
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebExams(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebExams"
|
||||
}
|
||||
|
||||
private var examsYear = Date.getToday().year
|
||||
private var examsMonth = Date.getToday().month
|
||||
private var examsMonthsChecked = 0
|
||||
private var examsNextMonthChecked = false // TO DO temporary // no more // idk
|
||||
|
||||
init {
|
||||
getExams()
|
||||
}
|
||||
|
||||
private fun getExams() {
|
||||
val param = JsonObject()
|
||||
param.addProperty("strona", 1)
|
||||
param.addProperty("iloscNaStrone", "99")
|
||||
param.addProperty("iloscRekordow", -1)
|
||||
param.addProperty("kolumnaSort", "ss.Nazwa,sp.Data_sprawdzianu")
|
||||
param.addProperty("kierunekSort", 0)
|
||||
param.addProperty("maxIloscZaznaczonych", 0)
|
||||
param.addProperty("panelFiltrow", 0)
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_EXAMS, mapOf(
|
||||
"idP" to data.registerId,
|
||||
"rok" to examsYear,
|
||||
"miesiac" to examsMonth,
|
||||
"param" to param
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
for (jExamEl in json.getAsJsonArray("ListK")) {
|
||||
val jExam = jExamEl.asJsonObject
|
||||
// jExam
|
||||
val eventId = jExam.get("_recordId").asLong
|
||||
val rSubject = data.getSubject(jExam.get("przedmiot").asString, -1, "")
|
||||
val rTeacher = data.getTeacherByLastFirst(jExam.get("wpisal").asString)
|
||||
val examDate = Date.fromY_m_d(jExam.get("data").asString)
|
||||
val lessonObject = Lesson.getByWeekDayAndSubject(data.lessonList, examDate.weekDay, rSubject.id)
|
||||
val examTime = lessonObject?.startTime
|
||||
|
||||
val eventType = if (jExam.get("rodzaj").asString == "sprawdzian/praca klasowa") Event.TYPE_EXAM else Event.TYPE_SHORT_QUIZ
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
eventId,
|
||||
examDate,
|
||||
examTime,
|
||||
jExam.get("zakres").asString,
|
||||
-1,
|
||||
eventType,
|
||||
false,
|
||||
rTeacher.id,
|
||||
rSubject.id,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
eventObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
if (profile?.empty == true && examsMonthsChecked < 3 /* how many months backwards to check? */) {
|
||||
examsMonthsChecked++
|
||||
examsMonth--
|
||||
if (examsMonth < 1) {
|
||||
examsMonth = 12
|
||||
examsYear--
|
||||
}
|
||||
getExams()
|
||||
} else if (!examsNextMonthChecked /* get also one month forward */) {
|
||||
val showDate = Date.getToday().stepForward(0, 1, 0)
|
||||
examsYear = showDate.year
|
||||
examsMonth = showDate.month
|
||||
examsNextMonthChecked = true
|
||||
getExams()
|
||||
} else {
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_EXAMS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,155 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import android.graphics.Color
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_GRADES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_GRADES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebGrades(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
webApiGet(TAG, IDZIENNIK_WEB_GRADES, mapOf(
|
||||
"idPozDziennika" to data.registerId
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.onEach { subjectJson ->
|
||||
val subject = data.getSubject(
|
||||
subjectJson.getString("Przedmiot") ?: return@onEach,
|
||||
subjectJson.getLong("IdPrzedmiotu") ?: return@onEach,
|
||||
subjectJson.getString("Przedmiot") ?: return@onEach
|
||||
)
|
||||
subjectJson.getJsonArray("Oceny")?.asJsonObjectList()?.forEach { grade ->
|
||||
val id = grade.getLong("idK") ?: return@forEach
|
||||
val category = grade.getString("Kategoria") ?: ""
|
||||
val name = grade.getString("Ocena") ?: "?"
|
||||
val semester = grade.getInt("Semestr") ?: 1
|
||||
val teacher = data.getTeacherByLastFirst(grade.getString("Wystawil") ?: return@forEach)
|
||||
|
||||
val countToAverage = grade.getBoolean("DoSredniej") ?: true
|
||||
var value = grade.getFloat("WartoscDoSred") ?: 0.0f
|
||||
val weight = if (countToAverage)
|
||||
grade.getFloat("Waga") ?: 0.0f
|
||||
else
|
||||
0.0f
|
||||
|
||||
val gradeColor = grade.getString("Kolor") ?: ""
|
||||
var colorInt = 0xff2196f3.toInt()
|
||||
if (gradeColor.isNotEmpty()) {
|
||||
colorInt = Color.parseColor("#$gradeColor")
|
||||
}
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
category,
|
||||
colorInt,
|
||||
"",
|
||||
name,
|
||||
value,
|
||||
weight,
|
||||
semester,
|
||||
teacher.id,
|
||||
subject.id)
|
||||
|
||||
when (grade.getInt("Typ")) {
|
||||
0 -> {
|
||||
val history = grade.getJsonArray("Historia")?.asJsonObjectList()
|
||||
if (history?.isNotEmpty() == true) {
|
||||
var sum = gradeObject.value * gradeObject.weight
|
||||
var count = gradeObject.weight
|
||||
for (historyItem in history) {
|
||||
val countToTheAverage = historyItem.getBoolean("DoSredniej") ?: false
|
||||
value = historyItem.get("WartoscDoSred").asFloat
|
||||
val weight = historyItem.get("Waga").asFloat
|
||||
|
||||
if (value > 0 && countToTheAverage) {
|
||||
sum += value * weight
|
||||
count += weight
|
||||
}
|
||||
|
||||
val historyObject = Grade(
|
||||
profileId,
|
||||
gradeObject.id * -1,
|
||||
historyItem.get("Kategoria").asString,
|
||||
Color.parseColor("#" + historyItem.get("Kolor").asString),
|
||||
historyItem.get("Uzasadnienie").asString,
|
||||
historyItem.get("Ocena").asString,
|
||||
value,
|
||||
if (value > 0f && countToTheAverage) weight * -1f else 0f,
|
||||
historyItem.get("Semestr").asInt,
|
||||
teacher.id,
|
||||
subject.id)
|
||||
historyObject.parentId = gradeObject.id
|
||||
|
||||
val addedDate = historyItem.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
|
||||
|
||||
data.gradeList.add(historyObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
historyObject.id,
|
||||
true,
|
||||
true,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
// update the current grade's value with an average of all historical grades and itself
|
||||
if (sum > 0 && count > 0) {
|
||||
gradeObject.value = sum / count
|
||||
}
|
||||
gradeObject.isImprovement = true // gradeObject is the improved grade. Originals are historyObjects
|
||||
}
|
||||
}
|
||||
1 -> {
|
||||
gradeObject.type = Grade.TYPE_SEMESTER1_FINAL
|
||||
gradeObject.name = name
|
||||
gradeObject.weight = 0f
|
||||
}
|
||||
2 -> {
|
||||
gradeObject.type = Grade.TYPE_YEAR_FINAL
|
||||
gradeObject.name = name
|
||||
gradeObject.weight = 0f
|
||||
}
|
||||
}
|
||||
|
||||
val addedDate = grade.getString("Data_wystaw")?.let { Date.fromY_m_d(it).inMillis } ?: System.currentTimeMillis()
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
data.profile?.empty ?: false,
|
||||
data.profile?.empty ?: false,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_NOTICES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_NOTICES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.crc16
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice.*
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class IdziennikWebNotices(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebNotices"
|
||||
}
|
||||
|
||||
init {
|
||||
webApiGet(TAG, IDZIENNIK_WEB_NOTICES, mapOf(
|
||||
"idPozDziennika" to data.registerId
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
for (jNoticeEl in json.getAsJsonArray("SUwaga")) {
|
||||
val jNotice = jNoticeEl.asJsonObject
|
||||
// jNotice
|
||||
val noticeId = jNotice.get("id").asString.crc16().toLong()
|
||||
|
||||
val rTeacher = data.getTeacherByLastFirst(jNotice.get("Nauczyciel").asString)
|
||||
val addedDate = Date.fromY_m_d(jNotice.get("Data").asString)
|
||||
|
||||
var nType = TYPE_NEUTRAL
|
||||
val jType = jNotice.get("Typ").asString
|
||||
if (jType == "n") {
|
||||
nType = TYPE_NEGATIVE
|
||||
} else if (jType == "p") {
|
||||
nType = TYPE_POSITIVE
|
||||
}
|
||||
|
||||
val noticeObject = Notice(
|
||||
profileId,
|
||||
noticeId,
|
||||
jNotice.get("Tresc").asString,
|
||||
jNotice.get("Semestr").asInt,
|
||||
nType,
|
||||
rTeacher.id)
|
||||
data.noticeList.add(noticeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_NOTICE,
|
||||
noticeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate.inMillis
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_NOTICES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-28.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_MISSING_GRADES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_SEMESTER1_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade.TYPE_YEAR_PROPOSED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.getWordGradeValue
|
||||
|
||||
class IdziennikWebProposedGrades(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebProposedGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
webApiGet(TAG, IDZIENNIK_WEB_MISSING_GRADES, mapOf(
|
||||
"idPozDziennika" to data.registerId
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
val jSubjects = json.getAsJsonArray("Przedmioty")
|
||||
for (jSubjectEl in jSubjects) {
|
||||
val jSubject = jSubjectEl.getAsJsonObject()
|
||||
// jSubject
|
||||
val rSubject = data.getSubject(jSubject.get("Przedmiot").getAsString(), -1, jSubject.get("Przedmiot").getAsString())
|
||||
val semester1Proposed = jSubject.get("OcenaSem1").getAsString()
|
||||
val semester2Proposed = jSubject.get("OcenaSem2").getAsString()
|
||||
val semester1Value = getWordGradeValue(semester1Proposed)
|
||||
val semester2Value = getWordGradeValue(semester2Proposed)
|
||||
val semester1Id = rSubject.id * -100 - 1
|
||||
val semester2Id = rSubject.id * -100 - 2
|
||||
|
||||
if (semester1Proposed != "") {
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
semester1Id,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
semester1Value.toString(),
|
||||
semester1Value.toFloat(),
|
||||
0f,
|
||||
1,
|
||||
-1,
|
||||
rSubject.id)
|
||||
|
||||
gradeObject.type = TYPE_SEMESTER1_PROPOSED
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
gradeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
if (semester2Proposed != "") {
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
semester2Id,
|
||||
"",
|
||||
-1,
|
||||
"",
|
||||
semester2Value.toString(),
|
||||
semester2Value.toFloat(),
|
||||
0f,
|
||||
2,
|
||||
-1,
|
||||
rSubject.id)
|
||||
|
||||
gradeObject.type = TYPE_YEAR_PROPOSED
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
gradeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_PROPOSED_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.data.web
|
||||
|
||||
import androidx.core.util.set
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.ENDPOINT_IDZIENNIK_WEB_TIMETABLE
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.Lesson
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CANCELLED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonChange.TYPE_CHANGE
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import pl.szczodrzynski.edziennik.utils.models.Week
|
||||
|
||||
class IdziennikWebTimetable(override val data: DataIdziennik,
|
||||
val onSuccess: () -> Unit) : IdziennikWeb(data) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikWebTimetable"
|
||||
}
|
||||
|
||||
init {
|
||||
val weekStart = Week.getWeekStart()
|
||||
if (Date.getToday().weekDay > 4) {
|
||||
weekStart.stepForward(0, 0, 7)
|
||||
}
|
||||
|
||||
webApiGet(TAG, IDZIENNIK_WEB_TIMETABLE, mapOf(
|
||||
"idPozDziennika" to data.registerId,
|
||||
"pidRokSzkolny" to data.schoolYearId,
|
||||
"data" to weekStart.stringY_m_d+"T10:00:00.000Z"
|
||||
)) { result ->
|
||||
val json = result.getJsonObject("d") ?: run {
|
||||
data.error(ApiError(TAG, ERROR_IDZIENNIK_WEB_REQUEST_NO_DATA)
|
||||
.withApiResponse(result))
|
||||
return@webApiGet
|
||||
}
|
||||
|
||||
json.getJsonArray("GodzinyLekcyjne")?.asJsonObjectList()?.forEach { range ->
|
||||
val lessonRange = LessonRange(
|
||||
profileId,
|
||||
range.getInt("LiczbaP") ?: return@forEach,
|
||||
range.getString("Poczatek")?.let { Time.fromH_m(it) } ?: return@forEach,
|
||||
range.getString("Koniec")?.let { Time.fromH_m(it) } ?: return@forEach
|
||||
)
|
||||
data.lessonRanges[lessonRange.lessonNumber] = lessonRange
|
||||
}
|
||||
|
||||
json.getJsonArray("Przedmioty")?.asJsonObjectList()?.forEach { lesson ->
|
||||
val subject = data.getSubject(
|
||||
lesson.getString("Nazwa") ?: return@forEach,
|
||||
lesson.getLong("Id"),
|
||||
lesson.getString("Skrot") ?: ""
|
||||
)
|
||||
val teacher = data.getTeacherByFDotLast(lesson.getString("Nauczyciel") ?: return@forEach)
|
||||
val weekDay = lesson.getInt("DzienTygodnia")?.minus(1) ?: return@forEach
|
||||
val lessonRange = data.lessonRanges[lesson.getInt("Godzina")?.plus(1) ?: return@forEach]
|
||||
|
||||
val lessonObject = Lesson(
|
||||
profileId,
|
||||
weekDay,
|
||||
lessonRange.startTime,
|
||||
lessonRange.endTime
|
||||
).apply {
|
||||
subjectId = subject.id
|
||||
teacherId = teacher.id
|
||||
teamId = data.teamClass?.id ?: -1
|
||||
classroomName = lesson.getString("NazwaSali") ?: ""
|
||||
}
|
||||
|
||||
data.lessonList.add(lessonObject)
|
||||
|
||||
val type = lesson.getInt("TypZastepstwa") ?: -1
|
||||
if (type != -1) {
|
||||
// we have a lesson change to process
|
||||
val lessonChangeObject = LessonChange(
|
||||
profileId,
|
||||
weekStart.clone().stepForward(0, 0, weekDay),
|
||||
lessonObject.startTime,
|
||||
lessonObject.endTime
|
||||
)
|
||||
|
||||
lessonChangeObject.teamId = lessonObject.teamId
|
||||
lessonChangeObject.teacherId = lessonObject.teacherId
|
||||
lessonChangeObject.subjectId = lessonObject.subjectId
|
||||
lessonChangeObject.classroomName = lessonObject.classroomName
|
||||
when (type) {
|
||||
0 -> lessonChangeObject.type = TYPE_CANCELLED
|
||||
1, 2, 3, 4, 5 -> {
|
||||
lessonChangeObject.type = TYPE_CHANGE
|
||||
val newTeacher = lesson.getString("NauZastepujacy")
|
||||
val newSubject = lesson.getString("PrzedmiotZastepujacy")
|
||||
if (newTeacher != null) {
|
||||
lessonChangeObject.teacherId = data.getTeacherByFDotLast(newTeacher).id
|
||||
}
|
||||
if (newSubject != null) {
|
||||
lessonChangeObject.subjectId = data.getSubject(newSubject, null, "").id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data.lessonChangeList.add(lessonChangeObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LESSON_CHANGE,
|
||||
lessonChangeObject.id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_IDZIENNIK_WEB_TIMETABLE, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.firstlogin
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR
|
||||
import pl.szczodrzynski.edziennik.api.v2.IDZIENNIK_WEB_SETTINGS
|
||||
import pl.szczodrzynski.edziennik.api.v2.Regexes
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.data.IdziennikWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.login.IdziennikLoginWeb
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.fixName
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.swapFirstLastName
|
||||
|
||||
class IdziennikFirstLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikFirstLogin"
|
||||
}
|
||||
|
||||
private val web = IdziennikWeb(data)
|
||||
private val profileList = mutableListOf<Profile>()
|
||||
|
||||
init {
|
||||
IdziennikLoginWeb(data) {
|
||||
web.webGet(TAG, IDZIENNIK_WEB_SETTINGS) { text ->
|
||||
//val accounts = json.getJsonArray("accounts")
|
||||
|
||||
val isParent = Regexes.IDZIENNIK_LOGIN_FIRST_IS_PARENT.find(text)?.get(1) != "0"
|
||||
val accountNameLong = if (isParent)
|
||||
Regexes.IDZIENNIK_LOGIN_FIRST_ACCOUNT_NAME.find(text)?.get(1)?.swapFirstLastName()?.fixName()
|
||||
else
|
||||
null
|
||||
|
||||
var schoolYearName: String? = null
|
||||
val schoolYear = Regexes.IDZIENNIK_LOGIN_FIRST_SCHOOL_YEAR.find(text)?.let {
|
||||
schoolYearName = it[2]
|
||||
it[1].toIntOrNull()
|
||||
} ?: run {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_IDZIENNIK_FIRST_NO_SCHOOL_YEAR)
|
||||
.withApiResponse(text))
|
||||
return@webGet
|
||||
}
|
||||
|
||||
Regexes.IDZIENNIK_LOGIN_FIRST_STUDENT.findAll(text)
|
||||
.toMutableList()
|
||||
.reversed()
|
||||
.forEach { match ->
|
||||
val registerId = match[1].toIntOrNull() ?: return@forEach
|
||||
val studentId = match[2]
|
||||
val firstName = match[3]
|
||||
val lastName = match[4]
|
||||
val className = match[5] + " " + match[6]
|
||||
|
||||
val profile = Profile()
|
||||
profile.studentNameLong = "$firstName $lastName".fixName()
|
||||
profile.studentNameShort = "$firstName ${lastName[0]}.".fixName()
|
||||
profile.accountNameLong = accountNameLong
|
||||
profile.studentClassName = className
|
||||
profile.studentSchoolYear = schoolYearName
|
||||
profile.name = profile.studentNameLong
|
||||
profile.subname = data.webUsername
|
||||
profile.empty = true
|
||||
profile.putStudentData("studentId", studentId)
|
||||
profile.putStudentData("registerId", registerId)
|
||||
profile.putStudentData("schoolYearId", schoolYear)
|
||||
profileList.add(profile)
|
||||
}
|
||||
|
||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-25.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_API
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_IDZIENNIK_WEB
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class IdziennikLogin(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikLogin"
|
||||
}
|
||||
|
||||
private var cancelled = false
|
||||
|
||||
init {
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextLoginMethod(onSuccess: () -> Unit) {
|
||||
if (data.targetLoginMethodIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId ->
|
||||
data.progress(data.progressStep)
|
||||
if (usedMethodId != -1)
|
||||
data.loginMethods.add(usedMethodId)
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) {
|
||||
// this should never be true
|
||||
if (data.loginMethods.contains(loginMethodId)) {
|
||||
onSuccess(-1)
|
||||
return
|
||||
}
|
||||
Utils.d(TAG, "Using login method $loginMethodId")
|
||||
when (loginMethodId) {
|
||||
LOGIN_METHOD_IDZIENNIK_WEB -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_idziennik_web)
|
||||
IdziennikLoginWeb(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
LOGIN_METHOD_IDZIENNIK_API -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_idziennik_api)
|
||||
IdziennikLoginApi(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-27.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
|
||||
class IdziennikLoginApi(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikLoginApi"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.isApiLoginValid()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
onSuccess()
|
||||
}
|
||||
}}
|
||||
}
|
@ -0,0 +1,148 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-26.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.idziennik.login
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.HOUR
|
||||
import pl.szczodrzynski.edziennik.MINUTE
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.idziennik.DataIdziennik
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class IdziennikLoginWeb(val data: DataIdziennik, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "IdziennikLoginWeb"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.isWebLoginValid()) {
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("ASP.NET_SessionId_iDziennik")
|
||||
.value(data.webSessionId!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build(),
|
||||
Cookie.Builder()
|
||||
.name(".ASPXAUTH")
|
||||
.value(data.webAuth!!)
|
||||
.domain("iuczniowie.progman.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("iuczniowie.progman.pl")
|
||||
if (data.webSchoolName != null && data.webUsername != null && data.webPassword != null) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
private fun loginWithCredentials() {
|
||||
Utils.d(TAG, "Request: Idziennik/Login/Web - $IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
||||
|
||||
val loginCallback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text.isNullOrEmpty()) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
// login succeeded: there is a start page
|
||||
if (text.contains("czyWyswietlicDostepMobilny")) {
|
||||
val cookies = data.app.cookieJar.getForDomain("iuczniowie.progman.pl")
|
||||
run {
|
||||
data.webSessionId = cookies.singleOrNull { it.name() == "ASP.NET_SessionId_iDziennik" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_SESSION
|
||||
data.webAuth = cookies.singleOrNull { it.name() == ".ASPXAUTH" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_AUTH
|
||||
data.apiBearer = cookies.singleOrNull { it.name() == "Bearer" }?.value() ?: return@run ERROR_LOGIN_IDZIENNIK_WEB_NO_BEARER
|
||||
data.loginExpiryTime = response.getUnixDate() + 30 * MINUTE /* after about 40 minutes the login didn't work already */
|
||||
data.apiExpiryTime = response.getUnixDate() + 12 * HOUR /* actually it expires after 24 hours but I'm not sure when does the token refresh. */
|
||||
return@run null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
|
||||
val errorText = Regexes.IDZIENNIK_LOGIN_ERROR.find(text)?.get(1)
|
||||
when {
|
||||
errorText?.contains("nieprawidłową nazwę szkoły") == true -> ERROR_LOGIN_IDZIENNIK_WEB_INVALID_SCHOOL_NAME
|
||||
errorText?.contains("nieprawidłowy login lub hasło") == true -> ERROR_LOGIN_IDZIENNIK_WEB_INVALID_LOGIN
|
||||
text.contains("Identyfikator zgłoszenia") -> ERROR_LOGIN_IDZIENNIK_WEB_SERVER_ERROR
|
||||
text.contains("Hasło dostępu do systemu wygasło") -> ERROR_LOGIN_IDZIENNIK_WEB_PASSWORD_CHANGE_NEEDED
|
||||
text.contains("Trwają prace konserwacyjne") -> ERROR_LOGIN_IDZIENNIK_WEB_MAINTENANCE
|
||||
else -> ERROR_LOGIN_IDZIENNIK_WEB_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(text)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
val getCallback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
Request.builder()
|
||||
.url("$IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
||||
.userAgent(IDZIENNIK_USER_AGENT)
|
||||
.addHeader("Origin", "https://iuczniowie.progman.pl")
|
||||
.addHeader("Referer", "$IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
||||
.apply {
|
||||
Regexes.IDZIENNIK_LOGIN_HIDDEN_FIELDS.findAll(text ?: return@apply).forEach {
|
||||
addParameter(it[1], it[2])
|
||||
}
|
||||
}
|
||||
.addParameter("ctl00\$ContentPlaceHolder\$nazwaPrzegladarki", IDZIENNIK_USER_AGENT)
|
||||
.addParameter("ctl00\$ContentPlaceHolder\$NazwaSzkoly", data.webSchoolName)
|
||||
.addParameter("ctl00\$ContentPlaceHolder\$UserName", data.webUsername)
|
||||
.addParameter("ctl00\$ContentPlaceHolder\$Password", data.webPassword)
|
||||
.addParameter("ctl00\$ContentPlaceHolder\$captcha", "")
|
||||
.addParameter("ctl00\$ContentPlaceHolder\$Logowanie", "Zaloguj")
|
||||
.post()
|
||||
.allowErrorCode(502)
|
||||
.callback(loginCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$IDZIENNIK_WEB_URL/$IDZIENNIK_WEB_LOGIN")
|
||||
.userAgent(IDZIENNIK_USER_AGENT)
|
||||
.get()
|
||||
.allowErrorCode(502)
|
||||
.callback(getCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -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.Feature
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||
|
||||
/**
|
||||
* A callback passed only to an e-register class.
|
||||
* All [Feature]s and [LoginMethod]s receive this callback,
|
||||
* but may only use [EndpointCallback]'s methods.
|
||||
*/
|
||||
interface EdziennikCallback : EndpointCallback {
|
||||
fun onCompleted()
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-29.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.interfaces
|
||||
|
||||
interface EdziennikInterface {
|
||||
fun sync(featureIds: List<Int>, viewId: Int? = null)
|
||||
fun getMessage(messageId: Int)
|
||||
fun markAllAnnouncementsAsRead()
|
||||
fun firstLogin()
|
||||
fun cancel()
|
||||
}
|
@ -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.Feature
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.LoginMethod
|
||||
|
||||
/**
|
||||
* A callback passed to all [Feature]s and [LoginMethod]s
|
||||
*/
|
||||
interface EndpointCallback {
|
||||
fun onError(apiError: ApiError)
|
||||
fun onProgress(step: Float)
|
||||
fun onStartProgress(stringRes: Int)
|
||||
}
|
@ -0,0 +1,272 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_API
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_PORTAL
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Data
|
||||
import pl.szczodrzynski.edziennik.currentTimeUnix
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.isNotNullNorEmpty
|
||||
|
||||
class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app, profile, loginStore) {
|
||||
|
||||
fun isPortalLoginValid() = portalTokenExpiryTime-30 > currentTimeUnix() && portalRefreshToken.isNotNullNorEmpty() && portalAccessToken.isNotNullNorEmpty()
|
||||
fun isApiLoginValid() = apiTokenExpiryTime-30 > currentTimeUnix() && apiAccessToken.isNotNullNorEmpty()
|
||||
fun isSynergiaLoginValid() = synergiaSessionIdExpiryTime-30 > currentTimeUnix() && synergiaSessionId.isNotNullNorEmpty()
|
||||
fun isMessagesLoginValid() = messagesSessionIdExpiryTime-30 > currentTimeUnix() && messagesSessionId.isNotNullNorEmpty()
|
||||
|
||||
override fun satisfyLoginMethods() {
|
||||
loginMethods.clear()
|
||||
if (isPortalLoginValid())
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_PORTAL
|
||||
if (isApiLoginValid())
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_API
|
||||
if (isSynergiaLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(synergiaSessionId!!)
|
||||
.domain("synergia.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
}
|
||||
if (isMessagesLoginValid()) {
|
||||
loginMethods += LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fun getColor(id: Int?): Int {
|
||||
return when (id) {
|
||||
1 -> 0xFFF0E68C
|
||||
2 -> 0xFF87CEFA
|
||||
3 -> 0xFFB0C4DE
|
||||
4 -> 0xFFF0F8FF
|
||||
5 -> 0xFFF0FFFF
|
||||
6 -> 0xFFF5F5DC
|
||||
7 -> 0xFFFFEBCD
|
||||
8 -> 0xFFFFF8DC
|
||||
9 -> 0xFFA9A9A9
|
||||
10 -> 0xFFBDB76B
|
||||
11 -> 0xFF8FBC8F
|
||||
12 -> 0xFFDCDCDC
|
||||
13 -> 0xFFDAA520
|
||||
14 -> 0xFFE6E6FA
|
||||
15 -> 0xFFFFA07A
|
||||
16 -> 0xFF32CD32
|
||||
17 -> 0xFF66CDAA
|
||||
18 -> 0xFF66CDAA
|
||||
19 -> 0xFFC0C0C0
|
||||
20 -> 0xFFD2B48C
|
||||
21 -> 0xFF3333FF
|
||||
22 -> 0xFF7B68EE
|
||||
23 -> 0xFFBA55D3
|
||||
24 -> 0xFFFFB6C1
|
||||
25 -> 0xFFFF1493
|
||||
26 -> 0xFFDC143C
|
||||
27 -> 0xFFFF0000
|
||||
28 -> 0xFFFF8C00
|
||||
29 -> 0xFFFFD700
|
||||
30 -> 0xFFADFF2F
|
||||
31 -> 0xFF7CFC00
|
||||
else -> 0xff2196f3
|
||||
}.toInt()
|
||||
}
|
||||
|
||||
/* _____ _ _
|
||||
| __ \ | | | |
|
||||
| |__) |__ _ __| |_ __ _| |
|
||||
| ___/ _ \| '__| __/ _` | |
|
||||
| | | (_) | | | || (_| | |
|
||||
|_| \___/|_| \__\__,_|*/
|
||||
private var mPortalEmail: String? = null
|
||||
var portalEmail: String?
|
||||
get() { mPortalEmail = mPortalEmail ?: loginStore.getLoginData("email", null); return mPortalEmail }
|
||||
set(value) { loginStore.putLoginData("email", value); mPortalEmail = value }
|
||||
private var mPortalPassword: String? = null
|
||||
var portalPassword: String?
|
||||
get() { mPortalPassword = mPortalPassword ?: loginStore.getLoginData("password", null); return mPortalPassword }
|
||||
set(value) { loginStore.putLoginData("password", value); mPortalPassword = value }
|
||||
|
||||
private var mPortalAccessToken: String? = null
|
||||
var portalAccessToken: String?
|
||||
get() { mPortalAccessToken = mPortalAccessToken ?: loginStore.getLoginData("accessToken", null); return mPortalAccessToken }
|
||||
set(value) { loginStore.putLoginData("accessToken", value); mPortalAccessToken = value }
|
||||
private var mPortalRefreshToken: String? = null
|
||||
var portalRefreshToken: String?
|
||||
get() { mPortalRefreshToken = mPortalRefreshToken ?: loginStore.getLoginData("refreshToken", null); return mPortalRefreshToken }
|
||||
set(value) { loginStore.putLoginData("refreshToken", value); mPortalRefreshToken = value }
|
||||
private var mPortalTokenExpiryTime: Long? = null
|
||||
var portalTokenExpiryTime: Long
|
||||
get() { mPortalTokenExpiryTime = mPortalTokenExpiryTime ?: loginStore.getLoginData("tokenExpiryTime", 0L); return mPortalTokenExpiryTime ?: 0L }
|
||||
set(value) { loginStore.putLoginData("tokenExpiryTime", value); mPortalTokenExpiryTime = value }
|
||||
|
||||
/* _____ _____
|
||||
/\ | __ \_ _|
|
||||
/ \ | |__) || |
|
||||
/ /\ \ | ___/ | |
|
||||
/ ____ \| | _| |_
|
||||
/_/ \_\_| |____*/
|
||||
/**
|
||||
* 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.Feature]s
|
||||
*/
|
||||
private var mApiLogin: String? = null
|
||||
var apiLogin: String?
|
||||
get() { mApiLogin = mApiLogin ?: profile?.getStudentData("accountLogin", null); return mApiLogin }
|
||||
set(value) { profile?.putStudentData("accountLogin", value) ?: return; mApiLogin = value }
|
||||
/**
|
||||
* A Synergia password.
|
||||
* Used: for login (API Login Method) in Synergia mode.
|
||||
* Used: for login (Synergia Login Method) in Synergia mode.
|
||||
*/
|
||||
private var mApiPassword: String? = null
|
||||
var apiPassword: String?
|
||||
get() { mApiPassword = mApiPassword ?: profile?.getStudentData("accountPassword", null); return mApiPassword }
|
||||
set(value) { profile?.putStudentData("accountPassword", value) ?: return; mApiPassword = value }
|
||||
|
||||
/**
|
||||
* A JST login Code.
|
||||
* Used only during first login in JST mode.
|
||||
*/
|
||||
private var mApiCode: String? = null
|
||||
var apiCode: String?
|
||||
get() { mApiCode = mApiCode ?: profile?.getStudentData("accountCode", null); return mApiCode }
|
||||
set(value) { profile?.putStudentData("accountCode", value) ?: return; mApiCode = value }
|
||||
/**
|
||||
* A JST login PIN.
|
||||
* Used only during first login in JST mode.
|
||||
*/
|
||||
private var mApiPin: String? = null
|
||||
var apiPin: String?
|
||||
get() { mApiPin = mApiPin ?: profile?.getStudentData("accountPin", null); return mApiPin }
|
||||
set(value) { profile?.putStudentData("accountPin", value) ?: return; mApiPin = value }
|
||||
|
||||
/**
|
||||
* A Synergia API access token.
|
||||
* Used in all Api Endpoints.
|
||||
* Created in Login Method Api.
|
||||
* Applicable for all login modes.
|
||||
*/
|
||||
private var mApiAccessToken: String? = null
|
||||
var apiAccessToken: String?
|
||||
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
|
||||
set(value) { profile?.putStudentData("accountToken", value) ?: return; mApiAccessToken = value }
|
||||
/**
|
||||
* A Synergia API refresh token.
|
||||
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
|
||||
*/
|
||||
private var mApiRefreshToken: String? = null
|
||||
var apiRefreshToken: String?
|
||||
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
|
||||
set(value) { profile?.putStudentData("accountRefreshToken", value) ?: return; mApiRefreshToken = value }
|
||||
/**
|
||||
* The expiry time for [apiAccessToken], as a UNIX timestamp.
|
||||
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
|
||||
* Used when refreshing the [apiAccessToken] in Portal mode ([pl.szczodrzynski.edziennik.api.v2.librus.login.SynergiaTokenExtractor])
|
||||
*/
|
||||
private var mApiTokenExpiryTime: Long? = null
|
||||
var apiTokenExpiryTime: Long
|
||||
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
|
||||
set(value) { profile?.putStudentData("accountTokenTime", value) ?: return; mApiTokenExpiryTime = value }
|
||||
|
||||
/* _____ _
|
||||
/ ____| (_)
|
||||
| (___ _ _ _ __ ___ _ __ __ _ _ __ _
|
||||
\___ \| | | | '_ \ / _ \ '__/ _` | |/ _` |
|
||||
____) | |_| | | | | __/ | | (_| | | (_| |
|
||||
|_____/ \__, |_| |_|\___|_| \__, |_|\__,_|
|
||||
__/ | __/ |
|
||||
|___/ |__*/
|
||||
/**
|
||||
* A Synergia web Session ID (DZIENNIKSID).
|
||||
* Used in endpoints with Synergia login method.
|
||||
*/
|
||||
private var mSynergiaSessionId: String? = null
|
||||
var synergiaSessionId: String?
|
||||
get() { mSynergiaSessionId = mSynergiaSessionId ?: profile?.getStudentData("accountSID", null); return mSynergiaSessionId }
|
||||
set(value) { profile?.putStudentData("accountSID", value) ?: return; mSynergiaSessionId = value }
|
||||
/**
|
||||
* The expiry time for [synergiaSessionId], as a UNIX timestamp.
|
||||
* Used in endpoints with Synergia login method.
|
||||
* TODO verify how long is the session ID valid.
|
||||
*/
|
||||
private var mSynergiaSessionIdExpiryTime: Long? = null
|
||||
var synergiaSessionIdExpiryTime: Long
|
||||
get() { mSynergiaSessionIdExpiryTime = mSynergiaSessionIdExpiryTime ?: profile?.getStudentData("accountSIDTime", 0L); return mSynergiaSessionIdExpiryTime ?: 0L }
|
||||
set(value) { profile?.putStudentData("accountSIDTime", value) ?: return; mSynergiaSessionIdExpiryTime = value }
|
||||
|
||||
|
||||
/**
|
||||
* A Messages web Session ID (DZIENNIKSID).
|
||||
* Used in endpoints with Messages login method.
|
||||
*/
|
||||
private var mMessagesSessionId: String? = null
|
||||
var messagesSessionId: String?
|
||||
get() { mMessagesSessionId = mMessagesSessionId ?: profile?.getStudentData("messagesSID", null); return mMessagesSessionId }
|
||||
set(value) { profile?.putStudentData("messagesSID", value) ?: return; mMessagesSessionId = value }
|
||||
/**
|
||||
* The expiry time for [messagesSessionId], as a UNIX timestamp.
|
||||
* Used in endpoints with Messages login method.
|
||||
* TODO verify how long is the session ID valid.
|
||||
*/
|
||||
private var mMessagesSessionIdExpiryTime: Long? = null
|
||||
var messagesSessionIdExpiryTime: Long
|
||||
get() { mMessagesSessionIdExpiryTime = mMessagesSessionIdExpiryTime ?: profile?.getStudentData("messagesSIDTime", 0L); return mMessagesSessionIdExpiryTime ?: 0L }
|
||||
set(value) { profile?.putStudentData("messagesSIDTime", value) ?: return; mMessagesSessionIdExpiryTime = value }
|
||||
|
||||
/* ____ _ _
|
||||
/ __ \| | | |
|
||||
| | | | |_| |__ ___ _ __
|
||||
| | | | __| '_ \ / _ \ '__|
|
||||
| |__| | |_| | | | __/ |
|
||||
\____/ \__|_| |_|\___|*/
|
||||
var isPremium
|
||||
get() = profile?.getStudentData("isPremium", false) ?: false
|
||||
set(value) { profile?.putStudentData("isPremium", value) }
|
||||
|
||||
private var mSchoolName: String? = null
|
||||
var schoolName: String?
|
||||
get() { mSchoolName = mSchoolName ?: profile?.getStudentData("schoolName", null); return mSchoolName }
|
||||
set(value) { profile?.putStudentData("schoolName", value) ?: return; mSchoolName = value }
|
||||
|
||||
private var mUnitId: Long? = null
|
||||
var unitId: Long
|
||||
get() { mUnitId = mUnitId ?: profile?.getStudentData("unitId", 0L); return mUnitId ?: 0L }
|
||||
set(value) { profile?.putStudentData("unitId", value) ?: return; mUnitId = value }
|
||||
|
||||
private var mStartPointsSemester1: Int? = null
|
||||
var startPointsSemester1: Int
|
||||
get() { mStartPointsSemester1 = mStartPointsSemester1 ?: profile?.getStudentData("startPointsSemester1", 0); return mStartPointsSemester1 ?: 0 }
|
||||
set(value) { profile?.putStudentData("startPointsSemester1", value) ?: return; mStartPointsSemester1 = value }
|
||||
private var mStartPointsSemester2: Int? = null
|
||||
var startPointsSemester2: Int
|
||||
get() { mStartPointsSemester2 = mStartPointsSemester2 ?: profile?.getStudentData("startPointsSemester2", 0); return mStartPointsSemester2 ?: 0 }
|
||||
set(value) { profile?.putStudentData("startPointsSemester2", value) ?: return; mStartPointsSemester2 = value }
|
||||
|
||||
private var mEnablePointGrades: Boolean? = null
|
||||
var enablePointGrades: Boolean
|
||||
get() { mEnablePointGrades = mEnablePointGrades ?: profile?.getStudentData("enablePointGrades", true); return mEnablePointGrades ?: true }
|
||||
set(value) { profile?.putStudentData("enablePointGrades", value) ?: return; mEnablePointGrades = value }
|
||||
private var mEnableDescriptiveGrades: Boolean? = null
|
||||
var enableDescriptiveGrades: Boolean
|
||||
get() { mEnableDescriptiveGrades = mEnableDescriptiveGrades ?: profile?.getStudentData("enableDescriptiveGrades", true); return mEnableDescriptiveGrades ?: true }
|
||||
set(value) { profile?.putStudentData("enableDescriptiveGrades", value) ?: return; mEnableDescriptiveGrades = value }
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import pl.szczodrzynski.edziennik.App
|
||||
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.LibrusData
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaMarkAllAnnouncementsAsRead
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.firstlogin.LibrusFirstLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLogin
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginSynergia
|
||||
import pl.szczodrzynski.edziennik.api.v2.librusLoginMethods
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.api.v2.prepare
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class Librus(val app: App, val profile: Profile?, val loginStore: LoginStore, val callback: EdziennikCallback) : EdziennikInterface {
|
||||
companion object {
|
||||
private const val TAG = "Librus"
|
||||
}
|
||||
|
||||
val internalErrorList = mutableListOf<Int>()
|
||||
val data: DataLibrus
|
||||
|
||||
init {
|
||||
data = DataLibrus(app, profile, loginStore).apply {
|
||||
callback = wrapCallback(this@Librus.callback)
|
||||
satisfyLoginMethods()
|
||||
}
|
||||
}
|
||||
|
||||
private fun completed() {
|
||||
data.saveData()
|
||||
data.notifyAndSyncEvents {
|
||||
callback.onCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
/* _______ _ _ _ _ _
|
||||
|__ __| | /\ | | (_) | | |
|
||||
| | | |__ ___ / \ | | __ _ ___ _ __ _| |_| |__ _ __ ___
|
||||
| | | '_ \ / _ \ / /\ \ | |/ _` |/ _ \| '__| | __| '_ \| '_ ` _ \
|
||||
| | | | | | __/ / ____ \| | (_| | (_) | | | | |_| | | | | | | | |
|
||||
|_| |_| |_|\___| /_/ \_\_|\__, |\___/|_| |_|\__|_| |_|_| |_| |_|
|
||||
__/ |
|
||||
|__*/
|
||||
override fun sync(featureIds: List<Int>, viewId: Int?) {
|
||||
data.prepare(librusLoginMethods, LibrusFeatures, featureIds, viewId)
|
||||
d(TAG, "LoginMethod IDs: ${data.targetLoginMethodIds}")
|
||||
d(TAG, "Endpoint IDs: ${data.targetEndpointIds}")
|
||||
LibrusLogin(data) {
|
||||
LibrusData(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMessage(messageId: Int) {
|
||||
|
||||
}
|
||||
|
||||
override fun markAllAnnouncementsAsRead() {
|
||||
LibrusLoginApi(data) {
|
||||
LibrusLoginSynergia(data) {
|
||||
LibrusSynergiaMarkAllAnnouncementsAsRead(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun firstLogin() {
|
||||
LibrusFirstLogin(data) {
|
||||
completed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun cancel() {
|
||||
d(TAG, "Cancelled")
|
||||
data.cancel()
|
||||
}
|
||||
|
||||
private fun wrapCallback(callback: EdziennikCallback): EdziennikCallback {
|
||||
return object : EdziennikCallback {
|
||||
override fun onCompleted() {
|
||||
callback.onCompleted()
|
||||
}
|
||||
|
||||
override fun onProgress(step: Float) {
|
||||
callback.onProgress(step)
|
||||
}
|
||||
|
||||
override fun onStartProgress(stringRes: Int) {
|
||||
callback.onStartProgress(stringRes)
|
||||
}
|
||||
|
||||
override fun onError(apiError: ApiError) {
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-11.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.Feature
|
||||
|
||||
const val ENDPOINT_LIBRUS_API_ME = 1001
|
||||
const val ENDPOINT_LIBRUS_API_SCHOOLS = 1002
|
||||
const val ENDPOINT_LIBRUS_API_CLASSES = 1003
|
||||
const val ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES = 1004
|
||||
const val ENDPOINT_LIBRUS_API_UNITS = 1005
|
||||
const val ENDPOINT_LIBRUS_API_USERS = 1006
|
||||
const val ENDPOINT_LIBRUS_API_SUBJECTS = 1007
|
||||
const val ENDPOINT_LIBRUS_API_CLASSROOMS = 1008
|
||||
const val ENDPOINT_LIBRUS_API_PUSH_CONFIG = 1010
|
||||
const val ENDPOINT_LIBRUS_API_TIMETABLES = 1015
|
||||
const val ENDPOINT_LIBRUS_API_SUBSTITUTIONS = 1016
|
||||
const val ENDPOINT_LIBRUS_API_NORMAL_GC = 1021
|
||||
const val ENDPOINT_LIBRUS_API_POINT_GC = 1022
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GC = 1023
|
||||
const val ENDPOINT_LIBRUS_API_TEXT_GC = 1024
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC = 1025
|
||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GC = 1026
|
||||
const val ENDPOINT_LIBRUS_API_NORMAL_GRADES = 1031
|
||||
const val ENDPOINT_LIBRUS_API_POINT_GRADES = 1032
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES = 1033
|
||||
const val ENDPOINT_LIBRUS_API_TEXT_GRADES = 1034
|
||||
const val ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GRADES = 1035
|
||||
const val ENDPOINT_LIBRUS_API_BEHAVIOUR_GRADES = 1036
|
||||
const val ENDPOINT_LIBRUS_API_EVENT_TYPES = 1040
|
||||
const val ENDPOINT_LIBRUS_API_EVENTS = 1041
|
||||
const val ENDPOINT_LIBRUS_API_HOMEWORK = 1050
|
||||
const val ENDPOINT_LIBRUS_API_LUCKY_NUMBER = 1060
|
||||
const val ENDPOINT_LIBRUS_API_NOTICE_TYPES = 1070
|
||||
const val ENDPOINT_LIBRUS_API_NOTICES = 1071
|
||||
const val ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES = 1080
|
||||
const val ENDPOINT_LIBRUS_API_ATTENDANCES = 1081
|
||||
const val ENDPOINT_LIBRUS_API_ANNOUNCEMENTS = 1090
|
||||
const val ENDPOINT_LIBRUS_API_PT_MEETINGS = 1100
|
||||
const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES = 1109
|
||||
const val ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS = 1110
|
||||
const val ENDPOINT_LIBRUS_API_SCHOOL_FREE_DAYS = 1120
|
||||
const val ENDPOINT_LIBRUS_API_CLASS_FREE_DAYS = 1130
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_INFO = 2010
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_GRADES = 2020
|
||||
const val ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK = 2030
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVED = 3010
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_SENT = 3020
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_TRASH = 3030
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_RECEIVERS = 3040
|
||||
const val ENDPOINT_LIBRUS_MESSAGES_GET = 3040
|
||||
|
||||
val LibrusFeatures = listOf(
|
||||
|
||||
// push config
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_PUSH_CONFIG, listOf(
|
||||
ENDPOINT_LIBRUS_API_PUSH_CONFIG to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data ->
|
||||
data.app.appConfig.fcmTokens[LOGIN_TYPE_LIBRUS]?.second?.contains(data.profileId) == false
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Timetable - using API.
|
||||
*/
|
||||
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)),
|
||||
/**
|
||||
* Agenda - using API.
|
||||
* Events, Parent-teacher meetings, free days (teacher/school/class).
|
||||
*/
|
||||
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,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS to LOGIN_METHOD_LIBRUS_API,
|
||||
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)),
|
||||
/**
|
||||
* Grades - using API.
|
||||
* All grades + categories.
|
||||
*/
|
||||
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,
|
||||
ENDPOINT_LIBRUS_API_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_TEXT_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_BEHAVIOUR_GC to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_POINT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_DESCRIPTIVE_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_TEXT_GRADES to LOGIN_METHOD_LIBRUS_API,
|
||||
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)),
|
||||
/**
|
||||
* Homework - using API.
|
||||
* Sync only if account has premium access.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_API_HOMEWORK to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data ->
|
||||
(data as DataLibrus).isPremium
|
||||
},
|
||||
/**
|
||||
* Behaviour - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_BEHAVIOUR, listOf(
|
||||
ENDPOINT_LIBRUS_API_NOTICES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Attendance - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_ATTENDANCE, listOf(
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES to LOGIN_METHOD_LIBRUS_API,
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Announcements - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_ANNOUNCEMENTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Student info - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_ME to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* School info - using API.
|
||||
*/
|
||||
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)),
|
||||
/**
|
||||
* Class info - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASS_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Team info - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEAM_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Lucky number - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_LUCKY_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)).withShouldSync { data -> data.shouldSyncLuckyNumber() },
|
||||
/**
|
||||
* Teacher list - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_TEACHERS, listOf(
|
||||
ENDPOINT_LIBRUS_API_USERS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Subject list - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_SUBJECTS, listOf(
|
||||
ENDPOINT_LIBRUS_API_SUBJECTS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
/**
|
||||
* Classroom list - using API.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_CLASSROOMS, listOf(
|
||||
ENDPOINT_LIBRUS_API_CLASSROOMS to LOGIN_METHOD_LIBRUS_API
|
||||
), listOf(LOGIN_METHOD_LIBRUS_API)),
|
||||
|
||||
/**
|
||||
* Student info - using synergia scrapper.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_INFO, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),
|
||||
/**
|
||||
* Student number - using synergia scrapper.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_STUDENT_NUMBER, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),
|
||||
|
||||
|
||||
/**
|
||||
* Grades - using API + synergia scrapper.
|
||||
*/
|
||||
/*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_GRADES, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_GRADES to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)),*/
|
||||
|
||||
/**
|
||||
* Homework - using scrapper.
|
||||
* Sync only if account has not premium access.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_HOMEWORK, listOf(
|
||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK to LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
), listOf(LOGIN_METHOD_LIBRUS_SYNERGIA)).withShouldSync { data ->
|
||||
!(data as DataLibrus).isPremium
|
||||
},
|
||||
|
||||
/**
|
||||
* Messages inbox - using messages website.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_INBOX, listOf(
|
||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED to LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
), listOf(LOGIN_METHOD_LIBRUS_MESSAGES)),
|
||||
/**
|
||||
* Messages sent - using messages website.
|
||||
*/
|
||||
Feature(LOGIN_TYPE_LIBRUS, FEATURE_MESSAGES_SENT, listOf(
|
||||
ENDPOINT_LIBRUS_MESSAGES_SENT to LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
), listOf(LOGIN_METHOD_LIBRUS_MESSAGES))
|
||||
)
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.*
|
||||
|
||||
open class LibrusApi(open val data: DataLibrus) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusApi"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun apiGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Api - $LIBRUS_API_URL/$endpoint")
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null && response?.parserErrorBody == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
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
|
||||
"Insufficient scopes" -> ERROR_LIBRUS_API_INSUFFICIENT_SCOPES
|
||||
"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")) {
|
||||
"Student timetable is not public" -> ERROR_LIBRUS_API_TIMETABLE_NOT_PUBLIC
|
||||
else -> ERROR_LIBRUS_API_RESOURCE_ACCESS_DENIED
|
||||
}
|
||||
"LuckyNumberIsNotActive" -> ERROR_LIBRUS_API_LUCKY_NUMBER_NOT_ACTIVE
|
||||
"NotesIsNotActive" -> ERROR_LIBRUS_API_NOTES_NOT_ACTIVE
|
||||
"InvalidRequest" -> ERROR_LIBRUS_API_INVALID_REQUEST_PARAMS
|
||||
"Nieprawidłowy węzeł." -> ERROR_LIBRUS_API_INCORRECT_ENDPOINT
|
||||
else -> ERROR_LIBRUS_API_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(tag, errorCode)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (json == null) {
|
||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(json)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_API_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
// TODO add hotfix for Classrooms 500
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_API_URL/$endpoint")
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addHeader("Authorization", "Bearer ${data.apiAccessToken}")
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> post()
|
||||
}
|
||||
if (payload != null)
|
||||
setJsonBody(payload)
|
||||
}
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-5.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.api.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.messages.LibrusMessagesGetList
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaHomework
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.synergia.LibrusSynergiaInfo
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class LibrusData(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusEndpoints"
|
||||
}
|
||||
|
||||
init {
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextEndpoint(onSuccess: () -> Unit) {
|
||||
if (data.targetEndpointIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (data.cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useEndpoint(data.targetEndpointIds.removeAt(0)) {
|
||||
data.progress(data.progressStep)
|
||||
nextEndpoint(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useEndpoint(endpointId: Int, onSuccess: () -> Unit) {
|
||||
Utils.d(TAG, "Using endpoint $endpointId")
|
||||
when (endpointId) {
|
||||
/**
|
||||
* API
|
||||
*/
|
||||
ENDPOINT_LIBRUS_API_ME -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||
LibrusApiMe(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_SCHOOLS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_school_info)
|
||||
LibrusApiSchools(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_CLASSES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_classes)
|
||||
LibrusApiClasses(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teams)
|
||||
LibrusApiVirtualClasses(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_UNITS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_units)
|
||||
LibrusApiUnits(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_USERS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teachers)
|
||||
LibrusApiUsers(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_SUBJECTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_subjects)
|
||||
LibrusApiSubjects(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_CLASSROOMS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_classrooms)
|
||||
LibrusApiClassrooms(data) { onSuccess() }
|
||||
}
|
||||
// TODO push config
|
||||
// TODO timetable
|
||||
|
||||
ENDPOINT_LIBRUS_API_NORMAL_GRADES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_grades)
|
||||
LibrusApiGrades(data) { onSuccess() }
|
||||
}
|
||||
// TODO grades
|
||||
|
||||
ENDPOINT_LIBRUS_API_EVENT_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_event_types)
|
||||
LibrusApiEventTypes(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_EVENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_events)
|
||||
LibrusApiEvents(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
LibrusApiHomework(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_LUCKY_NUMBER -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_lucky_number)
|
||||
LibrusApiLuckyNumber(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_NOTICE_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notice_types)
|
||||
LibrusApiNoticeTypes(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_NOTICES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_notices)
|
||||
LibrusApiNotices(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance_types)
|
||||
LibrusApiAttendanceTypes(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_ATTENDANCES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_attendance)
|
||||
LibrusApiAttendances(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_ANNOUNCEMENTS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_announcements)
|
||||
LibrusApiAnnouncements(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_PT_MEETINGS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_pt_meetings)
|
||||
LibrusApiPtMeetings(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_day_types)
|
||||
LibrusApiTeacherFreeDayTypes(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_teacher_free_days)
|
||||
LibrusApiTeacherFreeDays(data) { onSuccess() }
|
||||
}
|
||||
|
||||
/**
|
||||
* SYNERGIA
|
||||
*/
|
||||
ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_homework)
|
||||
LibrusSynergiaHomework(data) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_SYNERGIA_INFO -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_student_info)
|
||||
LibrusSynergiaInfo(data) { onSuccess() }
|
||||
}
|
||||
|
||||
/**
|
||||
* MESSAGES
|
||||
*/
|
||||
ENDPOINT_LIBRUS_MESSAGES_RECEIVED -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_inbox)
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_RECEIVED) { onSuccess() }
|
||||
}
|
||||
ENDPOINT_LIBRUS_MESSAGES_SENT -> {
|
||||
data.startProgress(R.string.edziennik_progress_endpoint_messages_outbox)
|
||||
LibrusMessagesGetList(data, type = Message.TYPE_SENT) { onSuccess() }
|
||||
}
|
||||
|
||||
else -> onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.parser.Parser
|
||||
import org.redundent.kotlin.xml.PrintOptions
|
||||
import org.redundent.kotlin.xml.xml
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
open class LibrusMessages(open val data: DataLibrus) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusMessages"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun messagesGet(tag: String, endpoint: String, method: Int = POST,
|
||||
parameters: Map<String, Any>? = null, onSuccess: (doc: Document) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Messages - $LIBRUS_MESSAGES_URL/$endpoint")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
if (text.isNullOrEmpty()) {
|
||||
data.error(ApiError(LibrusSynergia.TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: Finish error handling
|
||||
|
||||
if ("error" in text) {
|
||||
when ("<type>(.*)</type>".toRegex().find(text)?.get(1)) {
|
||||
"eAccessDeny" -> data.error(ApiError(tag, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
val doc = Jsoup.parse(text, "", Parser.xmlParser())
|
||||
onSuccess(doc)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_MESSAGES_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(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("DZIENNIKSID")
|
||||
.value(data.messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
|
||||
val requestXml = xml("service") {
|
||||
"header" { }
|
||||
"data" {
|
||||
for ((key, value) in parameters.orEmpty()) {
|
||||
key {
|
||||
-value.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}.toString(PrintOptions(
|
||||
singleLineTextElements = true,
|
||||
useSelfClosingTags = true
|
||||
))
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_MESSAGES_URL/$endpoint")
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.setTextBody(requestXml, MediaTypeUtils.APPLICATION_XML)
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> post()
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,101 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
open class LibrusPortal(open val data: DataLibrus) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusPortal"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun portalGet(tag: String, endpoint: String, method: Int = GET, payload: JsonObject? = null, onSuccess: (json: JsonObject, response: Response?) -> Unit) {
|
||||
|
||||
d(tag, "Request: Librus/Portal - $LIBRUS_PORTAL_URL$endpoint")
|
||||
|
||||
val callback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null) {
|
||||
data.error(ApiError(tag, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(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_ACCESS_DENIED
|
||||
"ApiDisabled" -> ERROR_LIBRUS_PORTAL_API_DISABLED
|
||||
"Account not found" -> ERROR_LIBRUS_PORTAL_SYNERGIA_NOT_FOUND
|
||||
else -> ERROR_LIBRUS_PORTAL_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(tag, errorCode)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
if (response?.code() == HttpURLConnection.HTTP_OK) {
|
||||
try {
|
||||
onSuccess(json, response)
|
||||
} catch (e: NullPointerException) {
|
||||
e.printStackTrace()
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_PORTAL_SYNERGIA_TOKEN)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
|
||||
} else {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(tag, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_PORTAL_URL + endpoint)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addHeader("Authorization", "Bearer ${data.portalAccessToken}")
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> post()
|
||||
}
|
||||
if (payload != null)
|
||||
setJsonBody(payload)
|
||||
}
|
||||
.allowErrorCode(HttpURLConnection.HTTP_NOT_FOUND)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_GONE)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-21.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data
|
||||
|
||||
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.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
open class LibrusSynergia(open val data: DataLibrus) {
|
||||
companion object {
|
||||
const val TAG = "LibrusSynergia"
|
||||
}
|
||||
|
||||
val profileId
|
||||
get() = data.profile?.id ?: -1
|
||||
|
||||
val profile
|
||||
get() = data.profile
|
||||
|
||||
fun synergiaGet(tag: String, endpoint: String, method: Int = GET,
|
||||
parameters: Map<String, Any> = emptyMap(), onSuccess: (text: String) -> Unit) {
|
||||
d(tag, "Request: Librus/Synergia - $LIBRUS_SYNERGIA_URL/$endpoint")
|
||||
|
||||
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.contains("jesteś zalogowany")) {
|
||||
when {
|
||||
text.contains("stop.png") -> ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED
|
||||
text.contains("Przerwa techniczna") -> ERROR_LIBRUS_SYNERGIA_MAINTENANCE
|
||||
else -> ERROR_LIBRUS_SYNERGIA_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(tag, errorCode)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
onSuccess(text)
|
||||
} catch (e: Exception) {
|
||||
data.error(ApiError(tag, EXCEPTION_LIBRUS_SYNERGIA_REQUEST)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(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("DZIENNIKSID")
|
||||
.value(data.synergiaSessionId!!)
|
||||
.domain("synergia.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))*/
|
||||
|
||||
Request.builder()
|
||||
.url("$LIBRUS_SYNERGIA_URL/$endpoint")
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.apply {
|
||||
when (method) {
|
||||
GET -> get()
|
||||
POST -> post()
|
||||
}
|
||||
parameters.map { (name, value) ->
|
||||
addParameter(name, value)
|
||||
}
|
||||
}
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-13
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ANNOUNCEMENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.announcements.Announcement
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiAnnouncements(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAnnouncements"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "SchoolNotices") { json ->
|
||||
val announcements = json.getJsonArray("SchoolNotices").asJsonObjectList()
|
||||
|
||||
announcements?.forEach { announcement ->
|
||||
val id = Utils.crc16(announcement.getString("Id")?.toByteArray()
|
||||
?: return@forEach).toLong()
|
||||
val subject = announcement.getString("Subject") ?: ""
|
||||
val text = announcement.getString("Content") ?: ""
|
||||
val startDate = Date.fromY_m_d(announcement.getString("StartDate"))
|
||||
val endDate = Date.fromY_m_d(announcement.getString("EndDate"))
|
||||
val teacherId = announcement.getJsonObject("AddedBy")?.getLong("Id") ?: -1
|
||||
val addedDate = Date.fromIso(announcement.getString("CreationDate"))
|
||||
val read = announcement.getBoolean("WasRead") ?: false
|
||||
|
||||
val announcementObject = Announcement(
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
text,
|
||||
startDate,
|
||||
endDate,
|
||||
teacherId
|
||||
)
|
||||
|
||||
data.announcementList.add(announcementObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ANNOUNCEMENT,
|
||||
id,
|
||||
read,
|
||||
read,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ANNOUNCEMENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-13
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import android.graphics.Color
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.AttendanceType
|
||||
|
||||
class LibrusApiAttendanceTypes(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAttendanceTypes"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Attendances/Types") { json ->
|
||||
val attendanceTypes = json.getJsonArray("Types").asJsonObjectList()
|
||||
|
||||
attendanceTypes?.forEach { attendanceType ->
|
||||
val id = attendanceType.getLong("Id") ?: return@forEach
|
||||
val name = attendanceType.getString("Name") ?: ""
|
||||
val color = attendanceType.getString("ColorRGB")?.let { Color.parseColor("#$it") } ?: -1
|
||||
|
||||
val standardId = when (attendanceType.getBoolean("Standard") ?: false) {
|
||||
true -> id
|
||||
false -> attendanceType.getJsonObject("StandardType")?.getLong("Id") ?: id
|
||||
}
|
||||
val type = when (standardId) {
|
||||
1L -> Attendance.TYPE_ABSENT
|
||||
2L -> Attendance.TYPE_BELATED
|
||||
3L -> Attendance.TYPE_ABSENT_EXCUSED
|
||||
4L -> Attendance.TYPE_RELEASED
|
||||
/*100*/else -> Attendance.TYPE_PRESENT
|
||||
}
|
||||
|
||||
data.attendanceTypes.put(id, AttendanceType(profileId, id, name, type, color))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCE_TYPES, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-13
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import androidx.core.util.isEmpty
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ATTENDANCES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.attendance.Attendance
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiAttendances(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiAttendances"
|
||||
}
|
||||
|
||||
init {
|
||||
if (data.attendanceTypes.isEmpty()) {
|
||||
data.db.attendanceTypeDao().getAllNow(profileId).toSparseArray(data.attendanceTypes) { it.id }
|
||||
}
|
||||
|
||||
apiGet(TAG, "Attendances") { json ->
|
||||
val attendances = json.getJsonArray("Attendances").asJsonObjectList()
|
||||
|
||||
attendances?.forEach { attendance ->
|
||||
val id = Utils.strToInt((attendance.getString("Id") ?: return@forEach)
|
||||
.replace("[^\\d.]".toRegex(), "")).toLong()
|
||||
val teacherId = attendance.getJsonObject("AddedBy")?.getLong("Id") ?: -1
|
||||
val lessonNo = attendance.getInt("LessonNo") ?: return@forEach
|
||||
val startTime = data.lessonRanges.get(lessonNo).startTime
|
||||
val lessonDate = Date.fromY_m_d(attendance.getString("Date"))
|
||||
val subjectId = data.lessonList.singleOrNull {
|
||||
it.weekDay == lessonDate.weekDay && it.startTime.value == startTime.value
|
||||
}?.subjectId ?: -1
|
||||
val semester = attendance.getInt("Semester") ?: return@forEach
|
||||
val type = attendance.getJsonObject("Type")?.getLong("Id") ?: return@forEach
|
||||
val typeObject = data.attendanceTypes.get(type)
|
||||
val topic = typeObject?.name ?: ""
|
||||
|
||||
val attendanceObject = Attendance(
|
||||
profileId,
|
||||
id,
|
||||
teacherId,
|
||||
subjectId,
|
||||
semester,
|
||||
topic,
|
||||
lessonDate,
|
||||
startTime,
|
||||
typeObject.type
|
||||
)
|
||||
|
||||
val addedDate = Date.fromIso(attendance.getString("AddDate") ?: return@forEach)
|
||||
|
||||
data.attendanceList.add(attendanceObject)
|
||||
if(typeObject.type != Attendance.TYPE_PRESENT) {
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_ATTENDANCE,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ATTENDANCES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-14
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_CLASSES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getLong
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiClasses(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiClasses"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Classes") { json ->
|
||||
json.getJsonObject("Class")?.also { studentClass ->
|
||||
val id = studentClass.getLong("Id") ?: return@also
|
||||
val name = studentClass.getString("Number") +
|
||||
studentClass.getString("Symbol")
|
||||
val code = data.schoolName + ":" + name
|
||||
val teacherId = studentClass.getJsonObject("ClassTutor")?.getLong("Id") ?: -1
|
||||
|
||||
val teamObject = Team(
|
||||
profileId,
|
||||
id,
|
||||
name,
|
||||
1,
|
||||
code,
|
||||
teacherId
|
||||
)
|
||||
|
||||
data.teamList.put(id, teamObject)
|
||||
|
||||
data.unitId = studentClass.getJsonObject("Unit").getLong("Id") ?: 0L
|
||||
|
||||
profile?.apply {
|
||||
dateSemester1Start = Date.fromY_m_d(studentClass.getString("BeginSchoolYear")
|
||||
?: return@apply)
|
||||
dateSemester2Start = Date.fromY_m_d(studentClass.getString("EndFirstSemester")
|
||||
?: return@apply)
|
||||
dateYearEnd = Date.fromY_m_d(studentClass.getString("EndSchoolYear")
|
||||
?: return@apply)
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_CLASSES, 4 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-24.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_CLASSROOMS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.classrooms.Classroom
|
||||
import java.util.*
|
||||
|
||||
class LibrusApiClassrooms(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiClassrooms"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Classrooms") { json ->
|
||||
val classrooms = json.getJsonArray("Classrooms").asJsonObjectList()
|
||||
|
||||
classrooms?.forEach { classroom ->
|
||||
val id = classroom.getLong("Id") ?: return@forEach
|
||||
val name = classroom.getString("Name")?.toLowerCase(Locale.getDefault()) ?: ""
|
||||
val symbol = classroom.getString("Symbol")?.toLowerCase(Locale.getDefault()) ?: ""
|
||||
val nameShort = name.split(" ").onEach { it[0] }.joinToString()
|
||||
|
||||
val friendlyName = if (name != symbol && !name.contains(symbol) && !nameShort.contains(symbol)) {
|
||||
classroom.getString("Symbol") + " " + classroom.getString("Name")
|
||||
}
|
||||
else {
|
||||
classroom.getString("Name") ?: ""
|
||||
}
|
||||
|
||||
data.classrooms.put(id, Classroom(profileId, id, friendlyName))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_CLASSROOMS, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-24.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENT_TYPES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.EventType
|
||||
|
||||
class LibrusApiEventTypes(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiEventTypes"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "HomeWorks/Categories") { json ->
|
||||
val eventTypes = json.getJsonArray("Categories").asJsonObjectList()
|
||||
|
||||
eventTypes?.forEach { eventType ->
|
||||
val id = eventType.getLong("Id") ?: return@forEach
|
||||
val name = eventType.getString("Name") ?: ""
|
||||
val color = data.getColor(eventType.getJsonObject("Color")?.getInt("Id"))
|
||||
|
||||
data.eventTypes.put(id, EventType(profileId, id, name, color))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENT_TYPES, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-4.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import androidx.core.util.isEmpty
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_EVENTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class LibrusApiEvents(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiEvents"
|
||||
}
|
||||
|
||||
init {
|
||||
if (data.eventTypes.isEmpty()) {
|
||||
data.db.eventTypeDao().getAllNow(profileId).toSparseArray(data.eventTypes) { it.id }
|
||||
}
|
||||
|
||||
apiGet(TAG, "HomeWorks") { json ->
|
||||
val events = json.getJsonArray("HomeWorks").asJsonObjectList()
|
||||
|
||||
events?.forEach { event ->
|
||||
val id = event.getLong("Id") ?: return@forEach
|
||||
val eventDate = Date.fromY_m_d(event.getString("Date"))
|
||||
val topic = event.getString("Content") ?: ""
|
||||
val type = event.getJsonObject("Category")?.getInt("Id") ?: -1
|
||||
val teacherId = event.getJsonObject("CreatedBy")?.getLong("Id") ?: -1
|
||||
val subjectId = event.getJsonObject("Subject")?.getLong("Id") ?: -1
|
||||
val teamId = event.getJsonObject("Class")?.getLong("Id") ?: -1
|
||||
|
||||
val lessonNo = event.getInt("LessonNo")
|
||||
val lessonRange = data.lessonRanges.singleOrNull { it.lessonNumber == lessonNo }
|
||||
val startTime = lessonRange?.startTime ?: Time.fromH_m(event.getString("TimeFrom"))
|
||||
val addedDate = Date.fromIso(event.getString("AddDate"))
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
type,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
teamId
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_EVENTS, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,97 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NORMAL_GRADES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.grades.Grade
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiGrades(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiGrades"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Grades") { json ->
|
||||
val grades = json.getJsonArray("Grades").asJsonObjectList()
|
||||
|
||||
grades?.forEach { grade ->
|
||||
val id = grade.getLong("Id") ?: return@forEach
|
||||
val categoryId = grade.getJsonObject("Category")?.getLong("Id") ?: -1
|
||||
val name = grade.getString("Grade") ?: ""
|
||||
val semester = grade.getInt("Semester") ?: return@forEach
|
||||
val teacherId = grade.getJsonObject("AddedBy")?.getLong("Id") ?: -1
|
||||
val subjectId = grade.getJsonObject("Subject")?.getLong("Id") ?: -1
|
||||
val addedDate = Date.fromIso(grade.getString("AddDate"))
|
||||
|
||||
val category = data.gradeCategories.singleOrNull { it.categoryId == categoryId }
|
||||
val categoryName = category?.text ?: ""
|
||||
val color = category?.color ?: -1
|
||||
var weight = category?.weight ?: 0f
|
||||
val value = Utils.getGradeValue(name)
|
||||
|
||||
|
||||
if (name == "-" || name == "+"
|
||||
|| name.equals("np", ignoreCase = true)
|
||||
|| name.equals("bz", ignoreCase = true)) {
|
||||
weight = 0f
|
||||
}
|
||||
|
||||
val gradeObject = Grade(
|
||||
profileId,
|
||||
id,
|
||||
categoryName,
|
||||
color,
|
||||
"",
|
||||
name,
|
||||
value,
|
||||
weight,
|
||||
semester,
|
||||
teacherId,
|
||||
subjectId
|
||||
)
|
||||
|
||||
when {
|
||||
grade.getBoolean("IsConstituent") ?: false ->
|
||||
gradeObject.type = Grade.TYPE_NORMAL
|
||||
grade.getBoolean("IsSemester") ?: false -> // semester final
|
||||
gradeObject.type = if (gradeObject.semester == 1) Grade.TYPE_SEMESTER1_FINAL else Grade.TYPE_SEMESTER2_FINAL
|
||||
grade.getBoolean("IsSemesterProposition") ?: false -> // semester proposed
|
||||
gradeObject.type = if (gradeObject.semester == 1) Grade.TYPE_SEMESTER1_PROPOSED else Grade.TYPE_SEMESTER2_PROPOSED
|
||||
grade.getBoolean("IsFinal") ?: false -> // year final
|
||||
gradeObject.type = Grade.TYPE_YEAR_FINAL
|
||||
grade.getBoolean("IsFinalProposition") ?: false -> // year final
|
||||
gradeObject.type = Grade.TYPE_YEAR_PROPOSED
|
||||
}
|
||||
|
||||
grade.getJsonObject("Improvement")?.also {
|
||||
val historicalId = it.getLong("Id")
|
||||
data.gradeList.firstOrNull { grade -> grade.id == historicalId }?.also { grade ->
|
||||
grade.parentId = gradeObject.id
|
||||
if (grade.name == "nb") grade.weight = 0f
|
||||
}
|
||||
gradeObject.isImprovement = true
|
||||
}
|
||||
|
||||
data.gradeList.add(gradeObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_GRADE,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_NORMAL_GRADES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-12.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiHomework(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiHomework"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "HomeWorkAssignments") { json ->
|
||||
val homeworkList = json.getJsonArray("HomeWorkAssignments").asJsonObjectList()
|
||||
|
||||
homeworkList?.forEach { homework ->
|
||||
val id = homework.getLong("Id") ?: return@forEach
|
||||
val eventDate = Date.fromY_m_d(homework.getString("DueDate"))
|
||||
val topic = homework.getString("Topic") + "\n" + homework.getString("Text")
|
||||
val teacherId = homework.getJsonObject("Teacher")?.getLong("Id") ?: -1
|
||||
val addedDate = Date.fromY_m_d(homework.getString("Date"))
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
null,
|
||||
topic,
|
||||
-1,
|
||||
-1,
|
||||
false,
|
||||
teacherId,
|
||||
-1,
|
||||
-1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate.inMillis
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_HOMEWORK, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-14
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_LUCKY_NUMBER
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.luckynumber.LuckyNumber
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getJsonObject
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class LibrusApiLuckyNumber(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiLuckyNumber"
|
||||
}
|
||||
|
||||
init {
|
||||
data.profile?.luckyNumber = -1
|
||||
data.profile?.luckyNumberDate = null
|
||||
|
||||
var nextSync = System.currentTimeMillis() + 2*DAY*1000
|
||||
|
||||
apiGet(TAG, "LuckyNumbers") { json ->
|
||||
if (json.isJsonNull) {
|
||||
//profile?.luckyNumberEnabled = false
|
||||
} else {
|
||||
json.getJsonObject("LuckyNumber")?.also { luckyNumberEl ->
|
||||
|
||||
val luckyNumberDate = Date.fromY_m_d(luckyNumberEl.getString("LuckyNumberDay")) ?: Date.getToday()
|
||||
val luckyNumber = luckyNumberEl.getInt("LuckyNumber") ?: -1
|
||||
val luckyNumberObject = LuckyNumber(
|
||||
profileId,
|
||||
luckyNumberDate,
|
||||
luckyNumber
|
||||
)
|
||||
|
||||
//if (luckyNumberDate > Date.getToday()) {
|
||||
nextSync = luckyNumberDate.combineWith(Time(15, 0, 0))
|
||||
//}
|
||||
|
||||
data.luckyNumberList.add(luckyNumberObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_LUCKY_NUMBER,
|
||||
luckyNumberObject.date.value.toLong(),
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_LUCKY_NUMBER, syncAt = nextSync)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-3.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_ME
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
|
||||
class LibrusApiMe(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiMe"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Me") { json ->
|
||||
val me = json.getJsonObject("Me")
|
||||
val account = me?.getJsonObject("Account")
|
||||
val user = me?.getJsonObject("User")
|
||||
|
||||
data.isPremium = account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true
|
||||
|
||||
val isParent = account?.getInt("GroupId") == 5
|
||||
data.profile?.accountNameLong =
|
||||
if (isParent)
|
||||
buildFullName(account?.getString("FirstName"), account?.getString("LastName"))
|
||||
else null
|
||||
|
||||
data.profile?.studentNameLong =
|
||||
buildFullName(user?.getString("FirstName"), user?.getString("LastName"))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_ME, 2*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-24.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NOTICE_TYPES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.NoticeType
|
||||
|
||||
class LibrusApiNoticeTypes(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiNoticeTypes"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Notes/Categories") { json ->
|
||||
val noticeTypes = json.getJsonArray("Categories").asJsonObjectList()
|
||||
|
||||
noticeTypes?.forEach { noticeType ->
|
||||
val id = noticeType.getLong("Id") ?: return@forEach
|
||||
val name = noticeType.getString("CategoryName") ?: ""
|
||||
|
||||
data.noticeTypes.put(id, NoticeType(profileId, id, name))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_NOTICE_TYPES, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-24.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import androidx.core.util.isEmpty
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_NOTICES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.notices.Notice
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusApiNotices(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiNotices"
|
||||
}
|
||||
|
||||
init {
|
||||
if (data.noticeTypes.isEmpty()) {
|
||||
data.db.noticeTypeDao().getAllNow(profileId).toSparseArray(data.noticeTypes) { it.id }
|
||||
}
|
||||
|
||||
apiGet(TAG, "Notes") { json ->
|
||||
val notes = json.getJsonArray("Notes").asJsonObjectList()
|
||||
|
||||
notes?.forEach { note ->
|
||||
val id = note.getLong("Id") ?: return@forEach
|
||||
val text = note.getString("Text") ?: ""
|
||||
val categoryId = note.getJsonObject("Category")?.getLong("Id") ?: -1
|
||||
val teacherId = note.getJsonObject("AddedBy")?.getLong("Id") ?: -1
|
||||
val addedDate = note.getString("Date")?.let { Date.fromY_m_d(it) } ?: return@forEach
|
||||
|
||||
val type = when (note.getInt("Positive")) {
|
||||
0 -> Notice.TYPE_NEGATIVE
|
||||
1 -> Notice.TYPE_POSITIVE
|
||||
/*2*/else -> Notice.TYPE_NEUTRAL
|
||||
}
|
||||
val categoryText = data.noticeTypes[categoryId]?.name ?: ""
|
||||
val semester = profile?.dateToSemester(addedDate) ?: 1
|
||||
|
||||
val noticeObject = Notice(
|
||||
profileId,
|
||||
id,
|
||||
categoryText+"\n"+text,
|
||||
semester,
|
||||
type,
|
||||
teacherId
|
||||
)
|
||||
|
||||
data.noticeList.add(noticeObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_NOTICE,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
addedDate.inMillis
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_NOTICES, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-24.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_PT_MEETINGS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class LibrusApiPtMeetings(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiPtMeetings"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "ParentTeacherConferences") { json ->
|
||||
val ptMeetings = json.getJsonArray("ParentTeacherConferences").asJsonObjectList()
|
||||
|
||||
ptMeetings?.forEach { meeting ->
|
||||
val id = meeting.getLong("Id") ?: return@forEach
|
||||
val topic = meeting.getString("Topic") ?: ""
|
||||
val teacherId = meeting.getJsonObject("Teacher")?.getLong("Id") ?: -1
|
||||
val eventDate = meeting.getString("Date")?.let { Date.fromY_m_d(it) } ?: return@forEach
|
||||
val startTime = meeting.getString("Time")?.let {
|
||||
if (it == "00:00:00")
|
||||
null
|
||||
else
|
||||
Time.fromH_m_s(it)
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
topic,
|
||||
-1,
|
||||
Event.TYPE_PT_MEETING,
|
||||
false,
|
||||
teacherId,
|
||||
-1,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(
|
||||
Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_EVENT,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_PT_MEETINGS, 12*HOUR)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-4.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_SCHOOLS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.lessons.LessonRange
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
import java.util.*
|
||||
|
||||
class LibrusApiSchools(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiSchools"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Schools") { json ->
|
||||
val school = json.getJsonObject("School")
|
||||
val schoolId = school?.getInt("Id")
|
||||
val schoolNameLong = school?.getString("Name")
|
||||
|
||||
// create the school's short name using first letters of each long name's word
|
||||
// append the town name and save to student data
|
||||
var schoolNameShort = ""
|
||||
schoolNameLong?.split(" ")?.forEach {
|
||||
if (it.isBlank())
|
||||
return@forEach
|
||||
schoolNameShort += it[0].toLowerCase()
|
||||
}
|
||||
val schoolTown = school?.getString("Town")?.toLowerCase(Locale.getDefault())
|
||||
data.schoolName = schoolId.toString() + schoolNameShort + "_" + schoolTown
|
||||
|
||||
school?.getJsonArray("LessonsRange")?.let { ranges ->
|
||||
data.lessonRanges.clear()
|
||||
ranges.forEachIndexed { index, rangeEl ->
|
||||
val range = rangeEl.asJsonObject
|
||||
val from = range.getString("From") ?: return@forEachIndexed
|
||||
val to = range.getString("To") ?: return@forEachIndexed
|
||||
data.lessonRanges.put(
|
||||
index,
|
||||
LessonRange(
|
||||
profileId,
|
||||
index,
|
||||
Time.fromH_m(from),
|
||||
Time.fromH_m(to)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_SCHOOLS, 4 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-23.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_SUBJECTS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.subjects.Subject
|
||||
|
||||
class LibrusApiSubjects(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiSubjects"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Subjects") { json ->
|
||||
val subjects = json.getJsonArray("Subjects").asJsonObjectList()
|
||||
|
||||
subjects?.forEach { subject ->
|
||||
val id = subject.getLong("Id") ?: return@forEach
|
||||
val longName = subject.getString("Name") ?: ""
|
||||
val shortName = subject.getString("Short") ?: ""
|
||||
|
||||
data.subjectList.put(id, Subject(profileId, id, longName, shortName))
|
||||
}
|
||||
|
||||
data.subjectList.put(1, Subject(profileId, 1, "Zachowanie", "zach"))
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_SUBJECTS, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-19
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsenceType
|
||||
|
||||
class LibrusApiTeacherFreeDayTypes(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiTeacherFreeDayTypes"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "TeacherFreeDays/Types") { json ->
|
||||
val teacherAbsenceTypes = json.getJsonArray("Types").asJsonObjectList()
|
||||
|
||||
teacherAbsenceTypes?.forEach { teacherAbsenceType ->
|
||||
val id = teacherAbsenceType.getLong("Id") ?: return@forEach
|
||||
val name = teacherAbsenceType.getString("Name") ?: return@forEach
|
||||
|
||||
val teacherAbsenceTypeObject = TeacherAbsenceType(
|
||||
profileId,
|
||||
id,
|
||||
name
|
||||
)
|
||||
|
||||
data.teacherAbsenceTypes.put(id, teacherAbsenceTypeObject)
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAY_TYPES, 7 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-4.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import androidx.core.util.isEmpty
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_AGENDA
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.TeacherAbsence
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
class LibrusApiTeacherFreeDays(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiTeacherFreeDays"
|
||||
}
|
||||
|
||||
init {
|
||||
if (data.teacherAbsenceTypes.isEmpty()) {
|
||||
data.db.teacherAbsenceTypeDao().getAllNow(profileId).toSparseArray(data.teacherAbsenceTypes) { it.id }
|
||||
}
|
||||
|
||||
apiGet(TAG, "TeacherFreeDays") { json ->
|
||||
val teacherAbsences = json.getJsonArray("TeacherFreeDays").asJsonObjectList()
|
||||
|
||||
teacherAbsences?.forEach { teacherAbsence ->
|
||||
val id = teacherAbsence.getLong("Id") ?: return@forEach
|
||||
val teacherId = teacherAbsence.getJsonObject("Teacher")?.getLong("Id")
|
||||
?: return@forEach
|
||||
val type = teacherAbsence.getJsonObject("Type").getLong("Id") ?: return@forEach
|
||||
val name = data.teacherAbsenceTypes.singleOrNull { it.id == type }?.name
|
||||
val dateFrom = Date.fromY_m_d(teacherAbsence.getString("DateFrom"))
|
||||
val dateTo = Date.fromY_m_d(teacherAbsence.getString("DateTo"))
|
||||
val timeFrom = teacherAbsence.getString("TimeFrom")?.let { Time.fromH_m_s(it) }
|
||||
val timeTo = teacherAbsence.getString("TimeTo")?.let { Time.fromH_m_s(it) }
|
||||
|
||||
val teacherAbsenceObject = TeacherAbsence(
|
||||
profileId,
|
||||
id,
|
||||
teacherId,
|
||||
type,
|
||||
name,
|
||||
dateFrom,
|
||||
dateTo,
|
||||
timeFrom,
|
||||
timeTo
|
||||
)
|
||||
|
||||
data.teacherAbsenceList.add(teacherAbsenceObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_TEACHER_ABSENCE,
|
||||
id,
|
||||
profile?.empty ?: false,
|
||||
profile?.empty ?: false,
|
||||
System.currentTimeMillis()
|
||||
))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_TEACHER_FREE_DAYS, 6*HOUR, DRAWER_ITEM_AGENDA)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-4.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
|
||||
class LibrusApiTemplate(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApi"
|
||||
}
|
||||
|
||||
init {
|
||||
/*apiGet(TAG, "") { json ->
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
}*/
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-23.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_UNITS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
|
||||
class LibrusApiUnits(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiUnits"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.unitId == 0L) {
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_UNITS, 12 * DAY)
|
||||
onSuccess()
|
||||
return@run
|
||||
}
|
||||
|
||||
apiGet(TAG, "Units") { json ->
|
||||
val units = json.getJsonArray("Units").asJsonObjectList()
|
||||
|
||||
units?.singleOrNull { it.getLong("Id") == data.unitId }?.also { unit ->
|
||||
val startPoints = unit.getJsonObject("BehaviourGradesSettings")?.getJsonObject("StartPoints")
|
||||
startPoints?.apply {
|
||||
data.startPointsSemester1 = getInt("Semester1", defaultValue = 0)
|
||||
data.startPointsSemester2 = getInt("Semester2", defaultValue = data.startPointsSemester1)
|
||||
}
|
||||
unit.getJsonObject("GradesSettings")?.apply {
|
||||
data.enablePointGrades = getBoolean("PointGradesEnabled", true)
|
||||
data.enableDescriptiveGrades = getBoolean("DescriptiveGradesEnabled", true)
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_UNITS, 7 * DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-23.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_USERS
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
|
||||
class LibrusApiUsers(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiUsers"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "Users") { json ->
|
||||
val users = json.getJsonArray("Users").asJsonObjectList()
|
||||
|
||||
users?.forEach { user ->
|
||||
val id = user.getLong("Id") ?: return@forEach
|
||||
val firstName = user.getString("FirstName")?.fixWhiteSpaces() ?: ""
|
||||
val lastName = user.getString("LastName")?.fixWhiteSpaces() ?: ""
|
||||
|
||||
data.teacherList.put(id, Teacher(profileId, id, firstName, lastName))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_USERS, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-23.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.api
|
||||
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teams.Team
|
||||
|
||||
class LibrusApiVirtualClasses(override val data: DataLibrus,
|
||||
val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusApiVirtualClasses"
|
||||
}
|
||||
|
||||
init {
|
||||
apiGet(TAG, "VirtualClasses") { json ->
|
||||
val virtualClasses = json.getJsonArray("VirtualClasses").asJsonObjectList()
|
||||
|
||||
virtualClasses?.forEach { virtualClass ->
|
||||
val id = virtualClass.getLong("Id") ?: return@forEach
|
||||
val name = virtualClass.getString("Name") ?: ""
|
||||
val teacherId = virtualClass.getJsonObject("Teacher")?.getLong("Id") ?: -1
|
||||
val code = "${data.schoolName}:$name"
|
||||
|
||||
data.teamList.put(id, Team(profileId, id, name, 2, code, teacherId))
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_API_VIRTUAL_CLASSES, 4*DAY)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-24
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.messages
|
||||
|
||||
import pl.szczodrzynski.edziennik.DAY
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_NOT_IMPLEMENTED
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_MESSAGES_RECEIVED
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_MESSAGES_SENT
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.Message
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.messages.MessageRecipient
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.teachers.Teacher
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusMessagesGetList(override val data: DataLibrus, private val type: Int = Message.TYPE_RECEIVED,
|
||||
archived: Boolean = false, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusMessagesGetList"
|
||||
}
|
||||
|
||||
init {
|
||||
val endpoint = when (type) {
|
||||
Message.TYPE_RECEIVED -> "Inbox/action/GetList"
|
||||
Message.TYPE_SENT -> "Outbox/action/GetList"
|
||||
else -> null
|
||||
}
|
||||
|
||||
if (endpoint != null) {
|
||||
messagesGet(TAG, endpoint, parameters = mapOf(
|
||||
"archive" to if (archived) 1 else 0
|
||||
)) { doc ->
|
||||
doc.select("GetList data").firstOrNull()?.children()?.forEach { element ->
|
||||
val id = element.select("messageId").text().toLong()
|
||||
val subject = element.select("topic").text().trim()
|
||||
val readDateText = element.select("readDate").text().trim()
|
||||
val readDate = when (readDateText.isNotBlank()) {
|
||||
true -> Date.fromIso(readDateText)
|
||||
else -> 0
|
||||
}
|
||||
val sentDate = Date.fromIso(element.select("sendDate").text().trim())
|
||||
var senderId: Long = -1
|
||||
var receiverId: Long = -1
|
||||
|
||||
when (type) {
|
||||
Message.TYPE_RECEIVED -> {
|
||||
val senderFirstName = element.select("senderFirstName").text().trim()
|
||||
val senderLastName = element.select("senderLastName").text().trim()
|
||||
senderId = data.teacherList.singleOrNull {
|
||||
it.name == senderFirstName && it.surname == senderLastName
|
||||
}?.id ?: -1
|
||||
}
|
||||
|
||||
Message.TYPE_SENT -> {
|
||||
val receiverFirstName = element.select("receiverFirstName").text().trim()
|
||||
val receiverLastName = element.select("receiverLastName").text().trim()
|
||||
receiverId = data.teacherList.singleOrNull {
|
||||
it.name == receiverFirstName && it.surname == receiverLastName
|
||||
}?.id ?: {
|
||||
val teacherObject = Teacher(
|
||||
profileId,
|
||||
-1 * Utils.crc16("$receiverFirstName $receiverLastName".toByteArray()).toLong(),
|
||||
receiverFirstName,
|
||||
receiverLastName
|
||||
)
|
||||
data.teacherList.put(teacherObject.id, teacherObject)
|
||||
teacherObject.id
|
||||
}.invoke()
|
||||
}
|
||||
}
|
||||
|
||||
val notified = when (type) {
|
||||
Message.TYPE_SENT -> true
|
||||
else -> readDate > 0 || profile?.empty ?: false
|
||||
}
|
||||
|
||||
val messageObject = Message(
|
||||
profileId,
|
||||
id,
|
||||
subject,
|
||||
null,
|
||||
type,
|
||||
senderId,
|
||||
-1
|
||||
)
|
||||
|
||||
val messageRecipientObject = MessageRecipient(
|
||||
profileId,
|
||||
receiverId,
|
||||
-1,
|
||||
readDate,
|
||||
id
|
||||
)
|
||||
|
||||
data.messageList.add(messageObject)
|
||||
data.messageRecipientList.add(messageRecipientObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_MESSAGE,
|
||||
id,
|
||||
notified,
|
||||
notified,
|
||||
sentDate
|
||||
))
|
||||
}
|
||||
|
||||
when (type) {
|
||||
Message.TYPE_RECEIVED -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_RECEIVED, SYNC_ALWAYS)
|
||||
Message.TYPE_SENT -> data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_SENT, DAY, DRAWER_ITEM_MESSAGES)
|
||||
}
|
||||
onSuccess()
|
||||
}
|
||||
} else {
|
||||
data.error(TAG, ERROR_NOT_IMPLEMENTED)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-25
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.messages
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusMessages
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
|
||||
class LibrusMessagesTemplate(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusMessages(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusMessages"
|
||||
}
|
||||
|
||||
init {
|
||||
/* messagesGet(TAG, "") { doc ->
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_MESSAGES_, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
} */
|
||||
}
|
||||
}
|
@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-22.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.synergia
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.HOUR
|
||||
import pl.szczodrzynski.edziennik.MainActivity.Companion.DRAWER_ITEM_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.POST
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.events.Event
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.metadata.Metadata
|
||||
import pl.szczodrzynski.edziennik.get
|
||||
import pl.szczodrzynski.edziennik.singleOrNull
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
|
||||
class LibrusSynergiaHomework(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusSynergia(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusSynergiaHomework"
|
||||
}
|
||||
|
||||
init {
|
||||
synergiaGet(TAG, "moje_zadania", method = POST, parameters = mapOf(
|
||||
"dataOd" to
|
||||
if (data.profile?.empty != false)
|
||||
profile!!.getSemesterStart(1).stringY_m_d
|
||||
else
|
||||
Date.getToday().stringY_m_d,
|
||||
"dataDo" to profile!!.getSemesterEnd(profile?.currentSemester ?: 2).stringY_m_d,
|
||||
"przedmiot" to -1
|
||||
|
||||
)) { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
doc.select("table.myHomeworkTable > tbody").firstOrNull()?.also { homeworkTable ->
|
||||
val homeworkElements = homeworkTable.children()
|
||||
|
||||
val graphElements = doc.select("table[border].center td[align=left] tbody").first().children()
|
||||
|
||||
homeworkElements.forEachIndexed { i, el ->
|
||||
val elements = el.children()
|
||||
|
||||
val subjectName = elements[0].text().trim()
|
||||
val subjectId = data.subjectList.singleOrNull { it.longName == subjectName }?.id
|
||||
?: -1
|
||||
val teacherName = elements[1].text().trim()
|
||||
val teacherId = data.teacherList.singleOrNull { teacherName == it.fullName }?.id
|
||||
?: -1
|
||||
val topic = elements[2].text().trim()
|
||||
val addedDate = Date.fromY_m_d(elements[4].text().trim()).inMillis
|
||||
val eventDate = Date.fromY_m_d(elements[6].text().trim())
|
||||
val id = "/podglad/([0-9]+)'".toRegex().find(
|
||||
elements[9].select("input").attr("onclick")
|
||||
)?.get(1)?.toLong() ?: return@forEachIndexed
|
||||
val startTime = data.lessonList.singleOrNull {
|
||||
it.weekDay == eventDate.weekDay && it.subjectId == subjectId
|
||||
}?.startTime
|
||||
|
||||
val moreInfo = graphElements[2 * i + 1].select("td[title]")
|
||||
.attr("title").trim()
|
||||
val description = "Treść: (.*)".toRegex(RegexOption.DOT_MATCHES_ALL).find(moreInfo)
|
||||
?.get(1)?.replace("<br.*/>".toRegex(), "\n")?.trim()
|
||||
|
||||
val notified = when (profile?.empty) {
|
||||
true -> true
|
||||
false -> Date.getToday() < eventDate
|
||||
else -> false
|
||||
}
|
||||
|
||||
val eventObject = Event(
|
||||
profileId,
|
||||
id,
|
||||
eventDate,
|
||||
startTime,
|
||||
"$topic\n$description",
|
||||
-1,
|
||||
Event.TYPE_HOMEWORK,
|
||||
false,
|
||||
teacherId,
|
||||
subjectId,
|
||||
data.teamClass?.id ?: -1
|
||||
)
|
||||
|
||||
data.eventList.add(eventObject)
|
||||
data.metadataList.add(Metadata(
|
||||
profileId,
|
||||
Metadata.TYPE_HOMEWORK,
|
||||
id,
|
||||
notified,
|
||||
notified,
|
||||
addedDate
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
// because this requires a synergia login (2 more requests) sync this every two hours or if explicit :D
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_HOMEWORK, 2 * HOUR, DRAWER_ITEM_HOMEWORK)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.synergia
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.MONTH
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.ENDPOINT_LIBRUS_SYNERGIA_INFO
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||
|
||||
class LibrusSynergiaInfo(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusSynergia(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusSynergiaInfo"
|
||||
}
|
||||
|
||||
init {
|
||||
synergiaGet(TAG, "informacja") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
doc.select("table.form tbody").firstOrNull()?.children()?.also { info ->
|
||||
val studentNumber = info[2].select("td").text().trim().toIntOrNull()
|
||||
|
||||
studentNumber?.also {
|
||||
data.profile?.studentNumber = it
|
||||
}
|
||||
}
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_INFO, MONTH)
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-26
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.synergia
|
||||
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||
|
||||
class LibrusSynergiaMarkAllAnnouncementsAsRead(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusSynergia(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusSynergiaMarkAllAnnouncementsAsRead"
|
||||
}
|
||||
|
||||
init {
|
||||
synergiaGet(TAG, "ogloszenia") {
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) Kacper Ziubryniewicz 2019-10-23
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.data.synergia
|
||||
|
||||
import org.jsoup.Jsoup
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusSynergia
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.api.SYNC_ALWAYS
|
||||
|
||||
class LibrusSynergiaTemplate(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusSynergia(data) {
|
||||
companion object {
|
||||
const val TAG = "LibrusSynergia"
|
||||
}
|
||||
|
||||
init {
|
||||
/* synergiaGet(TAG, "") { text ->
|
||||
val doc = Jsoup.parse(text)
|
||||
|
||||
data.setSyncNext(ENDPOINT_LIBRUS_SYNERGIA_, SYNC_ALWAYS)
|
||||
onSuccess()
|
||||
} */
|
||||
}
|
||||
}
|
@ -0,0 +1,91 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.firstlogin
|
||||
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.ERROR_NO_STUDENTS_IN_ACCOUNT
|
||||
import pl.szczodrzynski.edziennik.api.v2.LIBRUS_ACCOUNTS_URL
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_MODE_LIBRUS_EMAIL
|
||||
import pl.szczodrzynski.edziennik.api.v2.events.FirstLoginFinishedEvent
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusPortal
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.login.LibrusLoginPortal
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_LIBRUS_DISCONNECTED
|
||||
import pl.szczodrzynski.edziennik.data.api.AppError.CODE_SYNERGIA_NOT_ACTIVATED
|
||||
import pl.szczodrzynski.edziennik.data.db.modules.profiles.Profile
|
||||
|
||||
class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusFirstLogin"
|
||||
}
|
||||
|
||||
private val portal = LibrusPortal(data)
|
||||
private val api = LibrusApi(data)
|
||||
private val profileList = mutableListOf<Profile>()
|
||||
|
||||
init {
|
||||
if (data.loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL) {
|
||||
// email login: use Portal for account list
|
||||
LibrusLoginPortal(data) {
|
||||
portal.portalGet(TAG, LIBRUS_ACCOUNTS_URL) { json, response ->
|
||||
val accounts = json.getJsonArray("accounts")
|
||||
|
||||
if (accounts == null || accounts.size() < 1) {
|
||||
data.error(ApiError(TAG, ERROR_NO_STUDENTS_IN_ACCOUNT)
|
||||
.withResponse(response)
|
||||
.withApiResponse(json))
|
||||
return@portalGet
|
||||
}
|
||||
val accountDataTime = json.getLong("lastModification")
|
||||
|
||||
for (accountEl in accounts) {
|
||||
val account = accountEl.asJsonObject
|
||||
|
||||
val state = account.getString("state")
|
||||
when (state) {
|
||||
"requiring_an_action" -> CODE_LIBRUS_DISCONNECTED
|
||||
"need-activation" -> CODE_SYNERGIA_NOT_ACTIVATED
|
||||
else -> null
|
||||
}?.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return@portalGet
|
||||
}
|
||||
|
||||
val id = account.getInt("id") ?: continue
|
||||
val login = account.getString("login") ?: continue
|
||||
val token = account.getString("accessToken") ?: continue
|
||||
val tokenTime = (accountDataTime ?: 0) + DAY
|
||||
val name = account.getString("studentName")?.fixName() ?: ""
|
||||
|
||||
val profile = Profile()
|
||||
profile.studentNameLong = name
|
||||
profile.studentNameShort = name.getShortName()
|
||||
profile.name = profile.studentNameLong
|
||||
profile.subname = data.portalEmail
|
||||
profile.empty = true
|
||||
profile.putStudentData("accountId", id)
|
||||
profile.putStudentData("accountLogin", login)
|
||||
profile.putStudentData("accountToken", token)
|
||||
profile.putStudentData("accountTokenTime", tokenTime)
|
||||
profileList.add(profile)
|
||||
}
|
||||
|
||||
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// synergia or JST login: use Api for account info
|
||||
LibrusLoginApi(data) {
|
||||
api.apiGet(TAG, "Me") { json ->
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-5.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import pl.szczodrzynski.edziennik.R
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_API
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_MESSAGES
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_PORTAL
|
||||
import pl.szczodrzynski.edziennik.api.v2.LOGIN_METHOD_LIBRUS_SYNERGIA
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
|
||||
class LibrusLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LibrusLogin"
|
||||
}
|
||||
|
||||
private var cancelled = false
|
||||
|
||||
init {
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
|
||||
private fun nextLoginMethod(onSuccess: () -> Unit) {
|
||||
if (data.targetLoginMethodIds.isEmpty()) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
if (cancelled) {
|
||||
onSuccess()
|
||||
return
|
||||
}
|
||||
useLoginMethod(data.targetLoginMethodIds.removeAt(0)) { usedMethodId ->
|
||||
data.progress(data.progressStep)
|
||||
if (usedMethodId != -1)
|
||||
data.loginMethods.add(usedMethodId)
|
||||
nextLoginMethod(onSuccess)
|
||||
}
|
||||
}
|
||||
|
||||
private fun useLoginMethod(loginMethodId: Int, onSuccess: (usedMethodId: Int) -> Unit) {
|
||||
// this should never be true
|
||||
if (data.loginMethods.contains(loginMethodId)) {
|
||||
onSuccess(-1)
|
||||
return
|
||||
}
|
||||
Utils.d(TAG, "Using login method $loginMethodId")
|
||||
when (loginMethodId) {
|
||||
LOGIN_METHOD_LIBRUS_PORTAL -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_librus_portal)
|
||||
LibrusLoginPortal(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
LOGIN_METHOD_LIBRUS_API -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_librus_api)
|
||||
LibrusLoginApi(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
LOGIN_METHOD_LIBRUS_SYNERGIA -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_librus_synergia)
|
||||
LibrusLoginSynergia(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
LOGIN_METHOD_LIBRUS_MESSAGES -> {
|
||||
data.startProgress(R.string.edziennik_progress_login_librus_messages)
|
||||
LibrusLoginMessages(data) { onSuccess(loginMethodId) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
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.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getInt
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.HTTP_BAD_REQUEST
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
|
||||
class LibrusLoginApi {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusApi"
|
||||
}
|
||||
|
||||
private lateinit var data: DataLibrus
|
||||
private lateinit var onSuccess: () -> Unit
|
||||
|
||||
/* do NOT move this to primary constructor */
|
||||
constructor(data: DataLibrus, onSuccess: () -> Unit) {
|
||||
this.data = data
|
||||
this.onSuccess = onSuccess
|
||||
|
||||
if (data.loginStore.mode == LOGIN_MODE_LIBRUS_EMAIL && data.profile == null) {
|
||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||
return
|
||||
}
|
||||
|
||||
if (data.isApiLoginValid()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
when (data.loginStore.mode) {
|
||||
LOGIN_MODE_LIBRUS_EMAIL -> loginWithPortal()
|
||||
LOGIN_MODE_LIBRUS_SYNERGIA -> loginWithSynergia()
|
||||
LOGIN_MODE_LIBRUS_JST -> loginWithJst()
|
||||
else -> {
|
||||
data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loginWithPortal() {
|
||||
if (!data.loginMethods.contains(LOGIN_METHOD_LIBRUS_PORTAL)) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_METHOD_NOT_SATISFIED))
|
||||
return
|
||||
}
|
||||
SynergiaTokenExtractor(data) {
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
private fun copyFromLoginStore() {
|
||||
data.loginStore.data?.apply {
|
||||
if (has("accountLogin")) {
|
||||
data.apiLogin = getString("accountLogin")
|
||||
remove("accountLogin")
|
||||
}
|
||||
if (has("accountPassword")) {
|
||||
data.apiPassword = getString("accountPassword")
|
||||
remove("accountPassword")
|
||||
}
|
||||
if (has("accountCode")) {
|
||||
data.apiCode = getString("accountCode")
|
||||
remove("accountCode")
|
||||
}
|
||||
if (has("accountPin")) {
|
||||
data.apiPin = getString("accountPin")
|
||||
remove("accountPin")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun loginWithSynergia() {
|
||||
copyFromLoginStore()
|
||||
if (data.apiRefreshToken != null) {
|
||||
// refresh a Synergia token
|
||||
synergiaRefreshToken()
|
||||
}
|
||||
else if (data.apiLogin != null && data.apiPassword != null) {
|
||||
synergiaGetToken()
|
||||
}
|
||||
else {
|
||||
// cannot log in: token expired, no login data present
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
|
||||
private fun loginWithJst() {
|
||||
copyFromLoginStore()
|
||||
|
||||
if (data.apiRefreshToken != null) {
|
||||
// refresh a JST token
|
||||
jstRefreshToken()
|
||||
}
|
||||
else if (data.apiCode != null && data.apiPin != null) {
|
||||
// get a JST token from Code and PIN
|
||||
jstGetToken()
|
||||
}
|
||||
else {
|
||||
// cannot log in: token expired, no login data present
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
|
||||
private val tokenCallback = object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response?) {
|
||||
if (json == null) {
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
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
|
||||
"invalid_client" -> ERROR_LOGIN_LIBRUS_API_INVALID_CLIENT
|
||||
"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_LOGIN
|
||||
else -> ERROR_LOGIN_LIBRUS_API_OTHER
|
||||
}.let { errorCode ->
|
||||
data.error(ApiError(TAG, errorCode)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
data.apiAccessToken = json.getString("access_token")
|
||||
data.apiRefreshToken = json.getString("refresh_token")
|
||||
data.apiTokenExpiryTime = response.getUnixDate() + json.getInt("expires_in", 86400)
|
||||
onSuccess()
|
||||
} catch (e: NullPointerException) {
|
||||
data.error(ApiError(TAG, EXCEPTION_LOGIN_LIBRUS_API_TOKEN)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
private fun synergiaGetToken() {
|
||||
d(TAG, "Request: Librus/Login/Api - $LIBRUS_API_TOKEN_URL")
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "password")
|
||||
.addParameter("username", data.apiLogin)
|
||||
.addParameter("password", data.apiPassword)
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.addParameter("librus_rules_accepted", "1")
|
||||
.addHeader("Authorization", "Basic $LIBRUS_API_AUTHORIZATION")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
private fun synergiaRefreshToken() {
|
||||
d(TAG, "Request: Librus/Login/Api - $LIBRUS_API_TOKEN_URL")
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "refresh_token")
|
||||
.addParameter("refresh_token", data.apiRefreshToken)
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.addParameter("librus_rules_accepted", "1")
|
||||
.addHeader("Authorization", "Basic $LIBRUS_API_AUTHORIZATION")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
private fun jstGetToken() {
|
||||
d(TAG, "Request: Librus/Login/Api - $LIBRUS_API_TOKEN_JST_URL")
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_JST_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "implicit_grant")
|
||||
.addParameter("client_id", LIBRUS_API_CLIENT_ID_JST)
|
||||
.addParameter("secret", LIBRUS_API_SECRET_JST)
|
||||
.addParameter("code", data.apiCode)
|
||||
.addParameter("pin", data.apiPin)
|
||||
.addParameter("librus_rules_accepted", "1")
|
||||
.addParameter("librus_mobile_rules_accepted", "1")
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
private fun jstRefreshToken() {
|
||||
d(TAG, "Request: Librus/Login/Api - $LIBRUS_API_TOKEN_JST_URL")
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_API_TOKEN_JST_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("grant_type", "refresh_token")
|
||||
.addParameter("client_id", LIBRUS_API_CLIENT_ID_JST)
|
||||
.addParameter("refresh_token", data.apiRefreshToken)
|
||||
.addParameter("librus_long_term_token", "1")
|
||||
.addParameter("mobile_app_accept_rules", "1")
|
||||
.addParameter("synergy_accept_rules", "1")
|
||||
.contentType(MediaTypeUtils.APPLICATION_FORM)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(tokenCallback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
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.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class LibrusLoginMessages(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusMessages"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.profile == null) {
|
||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||
return@run
|
||||
}
|
||||
|
||||
if (data.isMessagesLoginValid()) {
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(data.messagesSessionId!!)
|
||||
.domain("wiadomosci.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("wiadomosci.librus.pl")
|
||||
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_SYNERGIA)) {
|
||||
loginWithSynergia()
|
||||
}
|
||||
else if (data.apiLogin != null && data.apiPassword != null && false) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
/**
|
||||
* XML (Flash messages website) login method. Uses a Synergia login and password.
|
||||
*/
|
||||
private fun loginWithCredentials() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A login method using the Synergia website (/wiadomosci2 Auto Login).
|
||||
*/
|
||||
private fun loginWithSynergia(url: String = "https://synergia.librus.pl/wiadomosci2") {
|
||||
d(TAG, "Request: Librus/Login/Messages - $url")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(text: String?, response: Response?) {
|
||||
val location = response?.headers()?.get("Location")
|
||||
when {
|
||||
location?.contains("MultiDomainLogon") == true -> loginWithSynergia(location)
|
||||
location?.contains("AutoLogon") == true -> {
|
||||
var sessionId = data.app.cookieJar.getCookie("wiadomosci.librus.pl", "DZIENNIKSID")
|
||||
sessionId = sessionId?.replace("-MAINT", "")
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_MESSAGES_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(text))
|
||||
return
|
||||
}
|
||||
data.messagesSessionId = sessionId
|
||||
data.messagesSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||
onSuccess()
|
||||
}
|
||||
|
||||
text?.contains("eAccessDeny") == true -> data.error(TAG, ERROR_LIBRUS_MESSAGES_ACCESS_DENIED, response, text)
|
||||
text?.contains("stop.png") == true -> data.error(TAG, ERROR_LIBRUS_SYNERGIA_ACCESS_DENIED, response, text)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(SYNERGIA_USER_AGENT)
|
||||
.get()
|
||||
.callback(callback)
|
||||
.withClient(data.app.httpLazy)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,216 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import android.util.Pair
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.body.MediaTypeUtils
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection.HTTP_UNAUTHORIZED
|
||||
import java.util.ArrayList
|
||||
import java.util.regex.Pattern
|
||||
|
||||
class LibrusLoginPortal(val data: DataLibrus, val onSuccess: () -> Unit) {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusPortal"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
|
||||
data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE))
|
||||
return@run
|
||||
}
|
||||
if (data.portalEmail == null || data.portalPassword == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
return@run
|
||||
}
|
||||
|
||||
// succeed having a non-expired access token and a refresh token
|
||||
if (data.isPortalLoginValid()) {
|
||||
onSuccess()
|
||||
}
|
||||
else if (data.portalRefreshToken != null) {
|
||||
data.app.cookieJar.clearForDomain("portal.librus.pl")
|
||||
accessToken(null, data.portalRefreshToken)
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("portal.librus.pl")
|
||||
authorize(LIBRUS_AUTHORIZE_URL)
|
||||
}
|
||||
}}
|
||||
|
||||
private fun authorize(url: String?) {
|
||||
d(TAG, "Request: Librus/Login/Portal - $url")
|
||||
|
||||
Request.builder()
|
||||
.url(url)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.withClient(data.app.httpLazy)
|
||||
.callback(object : TextCallbackHandler() {
|
||||
override fun onSuccess(json: String, response: Response) {
|
||||
val location = response.headers().get("Location")
|
||||
if (location != null) {
|
||||
val authMatcher = Pattern.compile("http://localhost/bar\\?code=([A-z0-9]+?)$", Pattern.DOTALL or Pattern.MULTILINE).matcher(location)
|
||||
if (authMatcher.find()) {
|
||||
accessToken(authMatcher.group(1), null)
|
||||
} else {
|
||||
authorize(location)
|
||||
}
|
||||
} else {
|
||||
val csrfMatcher = Pattern.compile("name=\"csrf-token\" content=\"([A-z0-9=+/\\-_]+?)\"", Pattern.DOTALL).matcher(json)
|
||||
if (csrfMatcher.find()) {
|
||||
login(csrfMatcher.group(1))
|
||||
} else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_CSRF_MISSING)
|
||||
.withResponse(response)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private fun login(csrfToken: String) {
|
||||
d(TAG, "Request: Librus/Login/Portal - $LIBRUS_LOGIN_URL")
|
||||
|
||||
Request.builder()
|
||||
.url(LIBRUS_LOGIN_URL)
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.addParameter("email", data.portalEmail)
|
||||
.addParameter("password", data.portalPassword)
|
||||
.addHeader("X-CSRF-TOKEN", csrfToken)
|
||||
.contentType(MediaTypeUtils.APPLICATION_JSON)
|
||||
.post()
|
||||
.callback(object : JsonCallbackHandler() {
|
||||
override fun onSuccess(json: JsonObject?, response: Response) {
|
||||
if (json == null) {
|
||||
if (response.parserErrorBody?.contains("wciąż nieaktywne") == true) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_NOT_ACTIVATED)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
data.error(ApiError(TAG, ERROR_RESPONSE_EMPTY)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
if (json.get("errors") != null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_ACTION_ERROR)
|
||||
.withResponse(response)
|
||||
.withApiResponse(json))
|
||||
return
|
||||
}
|
||||
authorize(json.getString("redirect", LIBRUS_AUTHORIZE_URL))
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response, throwable: Throwable) {
|
||||
if (response.code() == 403 || response.code() == 401) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_INVALID)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
return
|
||||
}
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
})
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
|
||||
private var refreshTokenFailed = false
|
||||
private fun accessToken(code: String?, refreshToken: String?) {
|
||||
d(TAG, "Request: Librus/Login/Portal - $LIBRUS_TOKEN_URL")
|
||||
|
||||
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
|
||||
"Cannot decrypt the refresh token" -> ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_INVALID
|
||||
"Token has been revoked" -> ERROR_LOGIN_LIBRUS_PORTAL_REFRESH_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(ApiError(TAG, errorCode)
|
||||
.withApiResponse(json)
|
||||
.withResponse(response))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
onSuccess(json, response)
|
||||
} catch (e: NullPointerException) {
|
||||
data.error(ApiError(TAG, EXCEPTION_LOGIN_LIBRUS_PORTAL_TOKEN)
|
||||
.withResponse(response)
|
||||
.withThrowable(e)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
val params = ArrayList<Pair<String, Any>>()
|
||||
params.add(Pair("client_id", LIBRUS_CLIENT_ID))
|
||||
if (code != null) {
|
||||
params.add(Pair("grant_type", "authorization_code"))
|
||||
params.add(Pair("code", code))
|
||||
params.add(Pair("redirect_uri", LIBRUS_REDIRECT_URL))
|
||||
} else if (refreshToken != null) {
|
||||
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)
|
||||
.post()
|
||||
.allowErrorCode(HTTP_UNAUTHORIZED)
|
||||
.callback(callback)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-9-20.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Request
|
||||
import im.wangchao.mhttp.Response
|
||||
import im.wangchao.mhttp.callback.JsonCallbackHandler
|
||||
import im.wangchao.mhttp.callback.TextCallbackHandler
|
||||
import okhttp3.Cookie
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusApi
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.getString
|
||||
import pl.szczodrzynski.edziennik.getUnixDate
|
||||
import pl.szczodrzynski.edziennik.utils.Utils
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
import java.net.HttpURLConnection
|
||||
|
||||
class LibrusLoginSynergia(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusApi(data) {
|
||||
companion object {
|
||||
private const val TAG = "LoginLibrusSynergia"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.profile == null) {
|
||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||
return@run
|
||||
}
|
||||
|
||||
if (data.isSynergiaLoginValid()) {
|
||||
data.app.cookieJar.saveFromResponse(null, listOf(
|
||||
Cookie.Builder()
|
||||
.name("DZIENNIKSID")
|
||||
.value(data.synergiaSessionId!!)
|
||||
.domain("synergia.librus.pl")
|
||||
.secure().httpOnly().build()
|
||||
))
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.app.cookieJar.clearForDomain("synergia.librus.pl")
|
||||
if (data.loginMethods.contains(LOGIN_METHOD_LIBRUS_API)) {
|
||||
loginWithApi()
|
||||
}
|
||||
else if (data.apiLogin != null && data.apiPassword != null && false) {
|
||||
loginWithCredentials()
|
||||
}
|
||||
else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_DATA_MISSING))
|
||||
}
|
||||
}
|
||||
}}
|
||||
|
||||
/**
|
||||
* HTML form-based login method. Uses a Synergia login and password.
|
||||
*/
|
||||
private fun loginWithCredentials() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A login method using the Synergia API (AutoLoginToken endpoint).
|
||||
*/
|
||||
private fun loginWithApi() {
|
||||
d(TAG, "Request: Librus/Login/Synergia - $LIBRUS_API_URL/AutoLoginToken")
|
||||
|
||||
val onSuccess = { json: JsonObject ->
|
||||
loginWithToken(json.getString("Token"))
|
||||
}
|
||||
|
||||
apiGet(TAG, "AutoLoginToken", POST, null, onSuccess)
|
||||
}
|
||||
|
||||
private fun loginWithToken(token: String?) {
|
||||
if (token == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_TOKEN))
|
||||
return
|
||||
}
|
||||
|
||||
d(TAG, "Request: Librus/Login/Synergia - " + LIBRUS_SYNERGIA_TOKEN_LOGIN_URL.replace("TOKEN", token) + "/uczen/widok/centrum_powiadomien")
|
||||
|
||||
val callback = object : TextCallbackHandler() {
|
||||
override fun onSuccess(json: String?, response: Response?) {
|
||||
val location = response?.headers()?.get("Location")
|
||||
if (location?.endsWith("centrum_powiadomien") == true) {
|
||||
val sessionId = data.app.cookieJar.getCookie("synergia.librus.pl", "DZIENNIKSID")
|
||||
if (sessionId == null) {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_NO_SESSION_ID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(json))
|
||||
return
|
||||
}
|
||||
data.synergiaSessionId = sessionId
|
||||
data.synergiaSessionIdExpiryTime = response.getUnixDate() + 45 * 60 /* 45min */
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
data.error(ApiError(TAG, ERROR_LOGIN_LIBRUS_SYNERGIA_TOKEN_INVALID)
|
||||
.withResponse(response)
|
||||
.withApiResponse(json))
|
||||
}
|
||||
}
|
||||
|
||||
override fun onFailure(response: Response?, throwable: Throwable?) {
|
||||
data.error(ApiError(TAG, ERROR_REQUEST_FAILURE)
|
||||
.withResponse(response)
|
||||
.withThrowable(throwable))
|
||||
}
|
||||
}
|
||||
|
||||
data.app.cookieJar.clearForDomain("synergia.librus.pl")
|
||||
Request.builder()
|
||||
.url(LIBRUS_SYNERGIA_TOKEN_LOGIN_URL.replace("TOKEN", token) + "/uczen/widok/centrum_powiadomien")
|
||||
.userAgent(LIBRUS_USER_AGENT)
|
||||
.get()
|
||||
.allowErrorCode(HttpURLConnection.HTTP_BAD_REQUEST)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_FORBIDDEN)
|
||||
.allowErrorCode(HttpURLConnection.HTTP_UNAUTHORIZED)
|
||||
.callback(callback)
|
||||
.withClient(data.app.httpLazy)
|
||||
.build()
|
||||
.enqueue()
|
||||
}
|
||||
}
|
@ -0,0 +1,73 @@
|
||||
package pl.szczodrzynski.edziennik.api.v2.librus.login
|
||||
|
||||
import com.google.gson.JsonObject
|
||||
import im.wangchao.mhttp.Response
|
||||
import pl.szczodrzynski.edziennik.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.*
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.DataLibrus
|
||||
import pl.szczodrzynski.edziennik.api.v2.librus.data.LibrusPortal
|
||||
import pl.szczodrzynski.edziennik.api.v2.models.ApiError
|
||||
import pl.szczodrzynski.edziennik.utils.Utils.d
|
||||
|
||||
class SynergiaTokenExtractor(override val data: DataLibrus, val onSuccess: () -> Unit) : LibrusPortal(data) {
|
||||
companion object {
|
||||
private const val TAG = "SynergiaTokenExtractor"
|
||||
}
|
||||
|
||||
init { run {
|
||||
if (data.loginStore.mode != LOGIN_MODE_LIBRUS_EMAIL) {
|
||||
data.error(ApiError(TAG, ERROR_INVALID_LOGIN_MODE))
|
||||
return@run
|
||||
}
|
||||
if (data.profile == null) {
|
||||
data.error(ApiError(TAG, ERROR_PROFILE_MISSING))
|
||||
return@run
|
||||
}
|
||||
|
||||
if (data.apiTokenExpiryTime-30 > currentTimeUnix() && data.apiAccessToken.isNotNullNorEmpty()) {
|
||||
onSuccess()
|
||||
}
|
||||
else {
|
||||
if (!synergiaAccount()) {
|
||||
data.error(ApiError(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
|
||||
data.portalAccessToken ?: return false
|
||||
|
||||
d(TAG, "Request: Librus/SynergiaTokenExtractor - $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(ApiError(TAG, ERROR_LOGIN_LIBRUS_PORTAL_SYNERGIA_TOKEN_MISSING)
|
||||
.withResponse(response)
|
||||
.withApiResponse(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(" ")
|
||||
data.profile?.studentNameShort = nameParts?.get(0) + " " + nameParts?.get(1)?.get(0)
|
||||
|
||||
onSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
portalGet(TAG, LIBRUS_ACCOUNT_URL+accountLogin, onSuccess = onSuccess)
|
||||
return true
|
||||
}
|
||||
}
|
@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) Kuba Szczodrzyński 2019-10-6.
|
||||
*/
|
||||
|
||||
package pl.szczodrzynski.edziennik.api.v2.mobidziennik
|
||||
|
||||
import android.util.LongSparseArray
|
||||
import android.util.SparseArray
|
||||
import android.util.SparseIntArray
|
||||
import androidx.core.util.isNotEmpty
|
||||
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
|
||||
import pl.szczodrzynski.edziennik.utils.models.Date
|
||||
import pl.szczodrzynski.edziennik.utils.models.Time
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
val teachersMap = LongSparseArray<String>()
|
||||
val subjectsMap = LongSparseArray<String>()
|
||||
|
||||
val gradeAddedDates = LongSparseArray<Long>()
|
||||
val gradeAverages = LongSparseArray<Float>()
|
||||
val gradeColors = LongSparseArray<Int>()
|
||||
|
||||
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 mLoginEmail: String? = null
|
||||
var loginEmail: String?
|
||||
get() { mLoginEmail = mLoginEmail ?: loginStore.getLoginData("email", null); return mLoginEmail }
|
||||
set(value) { loginStore.putLoginData("email", value); mLoginEmail = value }
|
||||
|
||||
private var 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 mStudentId: Int? = null
|
||||
var studentId: Int
|
||||
get() { mStudentId = mStudentId ?: profile?.getStudentData("studentId", 0); return mStudentId ?: 0 }
|
||||
set(value) { profile?.putStudentData("studentId", value) ?: return; mStudentId = 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 }
|
||||
|
||||
|
||||
override fun saveData() {
|
||||
super.saveData()
|
||||
if (gradeAddedDates.isNotEmpty()) {
|
||||
app.db.gradeDao().updateDetails(profileId, gradeAverages, gradeAddedDates, gradeColors)
|
||||
}
|
||||
}
|
||||
|
||||
val mobiLessons = mutableListOf<MobiLesson>()
|
||||
|
||||
data class MobiLesson(
|
||||
var id: Long,
|
||||
var subjectId: Long,
|
||||
var teacherId: Long,
|
||||
var teamId: Long,
|
||||
var topic: String,
|
||||
var date: Date,
|
||||
var startTime: Time,
|
||||
var endTime: Time,
|
||||
var presentCount: Int,
|
||||
var absentCount: Int,
|
||||
var lessonNumber: Int,
|
||||
var signed: String
|
||||
)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user