[Login/Librus] Implement Librus JST login form.

This commit is contained in:
Kuba Szczodrzyński
2019-12-14 17:21:29 +01:00
parent 13279a915d
commit ad5afac174
13 changed files with 408 additions and 12 deletions

View File

@ -148,16 +148,16 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
*/
private var mApiCode: String? = null
var apiCode: String?
get() { mApiCode = mApiCode ?: profile?.getStudentData("accountCode", null); return mApiCode }
set(value) { profile?.putStudentData("accountCode", value) ?: return; mApiCode = value }
get() { mApiCode = mApiCode ?: loginStore.getLoginData("accountCode", null); return mApiCode }
set(value) { loginStore.putLoginData("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 }
get() { mApiPin = mApiPin ?: loginStore.getLoginData("accountPin", null); return mApiPin }
set(value) { loginStore.putLoginData("accountPin", value) ?: return; mApiPin = value }
/**
* A Synergia API access token.
@ -168,7 +168,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiAccessToken: String? = null
var apiAccessToken: String?
get() { mApiAccessToken = mApiAccessToken ?: profile?.getStudentData("accountToken", null); return mApiAccessToken }
set(value) { profile?.putStudentData("accountToken", value) ?: return; mApiAccessToken = value }
set(value) { mApiAccessToken = value; profile?.putStudentData("accountToken", value) ?: return; }
/**
* A Synergia API refresh token.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@ -176,7 +176,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiRefreshToken: String? = null
var apiRefreshToken: String?
get() { mApiRefreshToken = mApiRefreshToken ?: profile?.getStudentData("accountRefreshToken", null); return mApiRefreshToken }
set(value) { profile?.putStudentData("accountRefreshToken", value) ?: return; mApiRefreshToken = value }
set(value) { mApiRefreshToken = value; profile?.putStudentData("accountRefreshToken", value) ?: return; }
/**
* The expiry time for [apiAccessToken], as a UNIX timestamp.
* Used when refreshing the [apiAccessToken] in JST, Synergia modes.
@ -185,7 +185,7 @@ class DataLibrus(app: App, profile: Profile?, loginStore: LoginStore) : Data(app
private var mApiTokenExpiryTime: Long? = null
var apiTokenExpiryTime: Long
get() { mApiTokenExpiryTime = mApiTokenExpiryTime ?: profile?.getStudentData("accountTokenTime", 0L); return mApiTokenExpiryTime ?: 0L }
set(value) { profile?.putStudentData("accountTokenTime", value) ?: return; mApiTokenExpiryTime = value }
set(value) { mApiTokenExpiryTime = value; profile?.putStudentData("accountTokenTime", value) ?: return; }
/* _____ _
/ ____| (_)

View File

@ -85,6 +85,36 @@ class LibrusFirstLogin(val data: DataLibrus, val onSuccess: () -> Unit) {
LibrusLoginApi(data) {
api.apiGet(TAG, "Me") { json ->
val profile = Profile()
val me = json.getJsonObject("Me")
val account = me?.getJsonObject("Account")
val user = me?.getJsonObject("User")
profile.putStudentData("isPremium", account?.getBoolean("IsPremium") == true || account?.getBoolean("IsPremiumDemo") == true)
val isParent = account?.getInt("GroupId") == 5
profile.accountNameLong =
if (isParent)
buildFullName(account?.getString("FirstName"), account?.getString("LastName"))
else null
profile.studentNameLong =
buildFullName(user?.getString("FirstName"), user?.getString("LastName"))
profile.studentNameShort = profile.studentNameLong?.getShortName()
profile.name = profile.studentNameLong
profile.subname = account.getString("Login")
profile.empty = true
profile.putStudentData("accountId", account.getInt("Id") ?: 0)
profile.putStudentData("accountLogin", profile.subname)
profile.putStudentData("accountToken", data.apiAccessToken)
profile.putStudentData("accountRefreshToken", data.apiRefreshToken)
profile.putStudentData("accountTokenTime", data.apiTokenExpiryTime)
profileList.add(profile)
EventBus.getDefault().post(FirstLoginFinishedEvent(profileList, data.loginStore))
onSuccess()
}
}
}

View File

@ -108,7 +108,7 @@ import pl.szczodrzynski.edziennik.utils.models.Date;
AttendanceType.class,
pl.szczodrzynski.edziennik.data.db.modules.timetable.Lesson.class,
ConfigEntry.class,
Metadata.class}, version = 68)
Metadata.class}, version = 69)
@TypeConverters({
ConverterTime.class,
ConverterDate.class,
@ -823,6 +823,12 @@ public abstract class AppDb extends RoomDatabase {
database.execSQL("DELETE FROM metadata WHERE thingType=7");
}
};
private static final Migration MIGRATION_68_69 = new Migration(68, 69) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE loginStores ADD COLUMN loginStoreMode INTEGER NOT NULL DEFAULT 0");
}
};
public static AppDb getDatabase(final Context context) {
@ -888,7 +894,8 @@ public abstract class AppDb extends RoomDatabase {
MIGRATION_64_65,
MIGRATION_65_66,
MIGRATION_66_67,
MIGRATION_67_68
MIGRATION_67_68,
MIGRATION_68_69
)
.allowMainThreadQueries()
//.fallbackToDestructiveMigration()

View File

@ -5,7 +5,6 @@ import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.Ignore;
import com.google.gson.JsonElement;
import com.google.gson.JsonNull;
@ -28,7 +27,7 @@ public class LoginStore {
@ColumnInfo(name = "loginStoreData")
public JsonObject data;
@Ignore
@ColumnInfo(name = "loginStoreMode")
public int mode = 0;
public static final int LOGIN_MODE_LIBRUS_EMAIL = 0;
public static final int LOGIN_MODE_LIBRUS_SYNERGIA = 1;

View File

@ -51,6 +51,7 @@ public class LoginChooserFragment extends Fragment {
b.loginMobidziennikLogo.setOnClickListener((v) -> nav.navigate(R.id.loginMobidziennikFragment, null, LoginActivity.navOptions));
b.loginLibrusLogo.setOnClickListener((v) -> nav.navigate(R.id.loginLibrusFragment, null, LoginActivity.navOptions));
b.loginLibrusJstLogo.setOnClickListener((v) -> nav.navigate(R.id.loginLibrusJstFragment, null, LoginActivity.navOptions));
b.loginVulcanLogo.setOnClickListener((v) -> nav.navigate(R.id.loginVulcanFragment, null, LoginActivity.navOptions));
b.loginIuczniowieLogo.setOnClickListener((v) -> nav.navigate(R.id.loginIuczniowieFragment, null, LoginActivity.navOptions));

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) Kuba Szczodrzyński 2019-12-13.
*/
package pl.szczodrzynski.edziennik.ui.modules.login;
import android.os.Bundle;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;
import pl.szczodrzynski.edziennik.App;
import pl.szczodrzynski.edziennik.R;
import pl.szczodrzynski.edziennik.api.v2.models.ApiError;
import pl.szczodrzynski.edziennik.databinding.FragmentLoginLibrusJstBinding;
import pl.szczodrzynski.edziennik.ui.modules.error.ErrorSnackbar;
import static pl.szczodrzynski.edziennik.api.v2.ErrorsKt.ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN;
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_MODE_LIBRUS_JST;
import static pl.szczodrzynski.edziennik.data.db.modules.login.LoginStore.LOGIN_TYPE_LIBRUS;
public class LoginLibrusJstFragment extends Fragment {
private App app;
private NavController nav;
private FragmentLoginLibrusJstBinding b;
private static final String TAG = "LoginLibrus";
private ErrorSnackbar errorSnackbar;
public LoginLibrusJstFragment() { }
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
if (getActivity() != null) {
app = (App) getActivity().getApplicationContext();
nav = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
errorSnackbar = ((LoginActivity) getActivity()).errorSnackbar;
}
else {
return null;
}
b = DataBindingUtil.inflate(inflater, R.layout.fragment_login_librus_jst, container, false);
return b.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
assert getContext() != null;
assert getActivity() != null;
view.postDelayed(() -> {
ApiError error = LoginActivity.error;
if (error != null) {
switch (error.getErrorCode()) {
case ERROR_LOGIN_LIBRUS_API_INVALID_LOGIN:
b.loginCodeLayout.setError(getString(R.string.login_error_incorrect_code_or_pin));
break;
}
errorSnackbar.addError(error).show();
LoginActivity.error = null;
}
}, 100);
b.helpButton.setOnClickListener((v) -> nav.navigate(R.id.loginLibrusHelpFragment, null, LoginActivity.navOptions));
b.backButton.setOnClickListener((v) -> nav.navigateUp());
b.loginButton.setOnClickListener((v) -> {
boolean errors = false;
b.loginCodeLayout.setError(null);
b.loginPinLayout.setError(null);
Editable codeEditable = b.loginCode.getText();
Editable pinEditable = b.loginPin.getText();
if (codeEditable == null || codeEditable.length() == 0) {
b.loginCodeLayout.setError(getString(R.string.login_error_no_code));
errors = true;
}
if (pinEditable == null || pinEditable.length() == 0) {
b.loginPinLayout.setError(getString(R.string.login_error_no_pin));
errors = true;
}
if (errors)
return;
errors = false;
String code = codeEditable.toString().toUpperCase();
String pin = pinEditable.toString();
b.loginCode.setText(code);
if (!code.matches("[A-Z0-9_]+")) {
b.loginCodeLayout.setError(getString(R.string.login_error_incorrect_code));
errors = true;
}
if (!pin.matches("[a-z0-9_]+")) {
b.loginPinLayout.setError(getString(R.string.login_error_incorrect_pin));
errors = true;
}
if (errors)
return;
errors = false;
Bundle args = new Bundle();
args.putInt("loginType", LOGIN_TYPE_LIBRUS);
args.putInt("loginMode", LOGIN_MODE_LIBRUS_JST);
args.putString("accountCode", code);
args.putString("accountPin", pin);
nav.navigate(R.id.loginProgressFragment, args, LoginActivity.navOptions);
});
}
}

View File

@ -85,8 +85,10 @@ public class LoginProgressFragment extends Fragment {
}
int loginType = args.getInt("loginType", -1);
int loginMode = args.getInt("loginMode", 0);
LoginStore loginStore = new LoginStore(-1, loginType, new JsonObject());
loginStore.mode = loginMode;
loginStore.copyFrom(args);
if (App.devMode && LoginChooserFragment.fakeLogin) {