Added Blackboard Courses to List
This commit is contained in:
@@ -45,7 +45,7 @@ import de.sebse.fuplanner.services.fulogin.AccountGeneral;
|
||||
import de.sebse.fuplanner.services.kvv.KVV;
|
||||
import de.sebse.fuplanner.services.kvv.KVVListener;
|
||||
import de.sebse.fuplanner.services.kvv.sync.KVVContentProvider;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginToken;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV;
|
||||
import de.sebse.fuplanner.services.kvv.types.Modules;
|
||||
import de.sebse.fuplanner.services.news.NewsManager;
|
||||
import de.sebse.fuplanner.tools.CustomAccountManager;
|
||||
@@ -658,7 +658,7 @@ public class MainActivity extends AppCompatActivity
|
||||
|
||||
|
||||
@Override
|
||||
public void onLogin(LoginToken token, boolean isOnlyRefresh) {
|
||||
public void onLogin(LoginTokenKVV token, boolean isOnlyRefresh) {
|
||||
toLoginState(token.getFullName(), token.getEmail(), getDefaultFragmentAfterLogin());
|
||||
if (!isOnlyRefresh) {
|
||||
registerSync();
|
||||
|
||||
@@ -4,5 +4,4 @@ public class AccountGeneral {
|
||||
public static final String ACCOUNT_TYPE = "de.sebse.fuplanner.fuauth";
|
||||
public static final String AUTHTOKEN_TYPE_KVV = "KVV";
|
||||
public static final String AUTHTOKEN_TYPE_BLACKBOARD = "Blackboard";
|
||||
public static final long SYNC_INTERVAL = 6 * 60 * 60; // defined in seconds
|
||||
}
|
||||
|
||||
@@ -14,9 +14,10 @@ import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import de.sebse.fuplanner.R;
|
||||
import de.sebse.fuplanner.services.kvv.sync.Login;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginToken;
|
||||
import de.sebse.fuplanner.services.kvv.sync.BBLogin;
|
||||
import de.sebse.fuplanner.services.kvv.sync.KVVLogin;
|
||||
import de.sebse.fuplanner.tools.logging.Logger;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
|
||||
/**
|
||||
@@ -34,20 +35,22 @@ public class UserLoginTask extends AsyncTask<Void, Void, String> {
|
||||
};*/
|
||||
static final String PARAM_USER_PASS = "PARAM_USER_PASS";
|
||||
|
||||
private final String mEmail;
|
||||
private final String mUsername;
|
||||
private final String mPassword;
|
||||
private final Login mVolleyLogin;
|
||||
private final KVVLogin mKVVLogin;
|
||||
private final BBLogin mBBLogin;
|
||||
private String mTokenType;
|
||||
private Logger log = new Logger(this);
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
@Nullable
|
||||
private FUAuthenticatorActivity mActivity;
|
||||
|
||||
UserLoginTask(String email, String password, String tokenType, @NotNull Context context) {
|
||||
mEmail = email;
|
||||
UserLoginTask(String username, String password, String tokenType, @NotNull Context context) {
|
||||
mUsername = username;
|
||||
mPassword = password;
|
||||
mTokenType = tokenType;
|
||||
mVolleyLogin = new Login(context);
|
||||
mKVVLogin = new KVVLogin(context);
|
||||
mBBLogin = new BBLogin(context);
|
||||
if (context instanceof FUAuthenticatorActivity)
|
||||
mActivity = (FUAuthenticatorActivity) context;
|
||||
}
|
||||
@@ -57,30 +60,38 @@ public class UserLoginTask extends AsyncTask<Void, Void, String> {
|
||||
// TODO: attempt authentication against a network service.
|
||||
|
||||
CountDownLatch latch = new CountDownLatch(1);
|
||||
AtomicReference<LoginToken> login = new AtomicReference<>();
|
||||
mVolleyLogin.doLogin(mEmail, mPassword, success -> {
|
||||
mVolleyLogin.testLoginToken(success, success1 -> {
|
||||
login.set(success);
|
||||
latch.countDown();
|
||||
}, error -> {
|
||||
log.e(error);
|
||||
latch.countDown();
|
||||
});
|
||||
}, error -> {
|
||||
AtomicReference<String> login = new AtomicReference<>();
|
||||
NetworkErrorCallback errorFunc = error -> {
|
||||
log.e(error);
|
||||
latch.countDown();
|
||||
});
|
||||
};
|
||||
switch (mTokenType) {
|
||||
case AccountGeneral.AUTHTOKEN_TYPE_KVV:
|
||||
mKVVLogin.doLogin(mUsername, mPassword, success -> {
|
||||
mKVVLogin.testLoginToken(success, success1 -> {
|
||||
login.set(success1.toJsonString());
|
||||
latch.countDown();
|
||||
}, errorFunc);
|
||||
}, errorFunc);
|
||||
break;
|
||||
case AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD:
|
||||
mBBLogin.doLogin(mUsername, mPassword, success -> {
|
||||
mBBLogin.testLoginToken(success, success1 -> {
|
||||
login.set(success1.toJsonString());
|
||||
latch.countDown();
|
||||
}, errorFunc);
|
||||
}, errorFunc);
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
latch.await();
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (login.get() == null) {
|
||||
return null;
|
||||
} else {
|
||||
return login.get().toJsonString();
|
||||
}
|
||||
return login.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,7 +105,7 @@ public class UserLoginTask extends AsyncTask<Void, Void, String> {
|
||||
|
||||
if (success != null) {
|
||||
final Intent res = new Intent();
|
||||
res.putExtra(AccountManager.KEY_ACCOUNT_NAME, mEmail);
|
||||
res.putExtra(AccountManager.KEY_ACCOUNT_NAME, mUsername);
|
||||
res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE);
|
||||
res.putExtra(AccountManager.KEY_AUTHTOKEN, success);
|
||||
res.putExtra(PARAM_USER_PASS, mPassword);
|
||||
|
||||
@@ -2,11 +2,11 @@ package de.sebse.fuplanner.services.kvv;
|
||||
|
||||
import com.android.volley.NetworkResponse;
|
||||
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginToken;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV;
|
||||
import de.sebse.fuplanner.tools.CustomAccountManager;
|
||||
|
||||
public interface KVVListener {
|
||||
default void onLogin(LoginToken token, boolean isOnlyRefresh) {}
|
||||
default void onLogin(LoginTokenKVV token, boolean isOnlyRefresh) {}
|
||||
|
||||
default void onLogout() {}
|
||||
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
package de.sebse.fuplanner.services.kvv;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Pair;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import de.sebse.fuplanner.services.fulogin.AccountGeneral;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginToken;
|
||||
import de.sebse.fuplanner.services.kvv.sync.BBLogin;
|
||||
import de.sebse.fuplanner.services.kvv.sync.KVVLogin;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginTokenBB;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV;
|
||||
import de.sebse.fuplanner.tools.CustomAccountManager;
|
||||
import de.sebse.fuplanner.tools.NetworkCallbackCollector;
|
||||
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||
@@ -16,9 +20,10 @@ import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
public class Login extends HTTPService {
|
||||
private final KVVListener mListener;
|
||||
@Nullable private LoginToken mToken;
|
||||
@Nullable private LoginTokenKVV mTokenKVV;
|
||||
@Nullable private LoginTokenBB mTokenBB;
|
||||
private boolean mLoginPending = false;
|
||||
private final NetworkCallbackCollector<LoginToken> mRefreshCallbacks = new NetworkCallbackCollector<>();
|
||||
private final NetworkCallbackCollector<Pair<LoginTokenKVV, LoginTokenBB>> mRefreshCallbacks = new NetworkCallbackCollector<>();
|
||||
|
||||
Login(KVVListener listener, Context context) {
|
||||
super(context);
|
||||
@@ -31,27 +36,33 @@ public class Login extends HTTPService {
|
||||
return;
|
||||
}
|
||||
mLoginPending = true;
|
||||
LoginToken.load(mListener.getAccountManager(), token -> {
|
||||
boolean result = setToken(token);
|
||||
mLoginPending = false;
|
||||
callback.run(result);
|
||||
LoginTokenKVV.load(mListener.getAccountManager(), tokenKVV -> {
|
||||
LoginTokenBB.load(mListener.getAccountManager(), tokenBB -> {
|
||||
boolean result = setToken(tokenKVV, tokenBB);
|
||||
mLoginPending = false;
|
||||
callback.run(result);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public void isOfflineStoredAvailable(BooleanInterface callback) {
|
||||
LoginToken.load(mListener.getAccountManager(), token -> {
|
||||
callback.run(token != null);
|
||||
LoginTokenKVV.load(mListener.getAccountManager(), tokenKVV -> {
|
||||
LoginTokenBB.load(mListener.getAccountManager(), tokenBB -> {
|
||||
callback.run(tokenKVV != null && tokenBB != null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public boolean logout(boolean delete) {
|
||||
if (mLoginPending)
|
||||
return false;
|
||||
if (mToken == null)
|
||||
if (mTokenKVV == null || mTokenBB == null)
|
||||
return true;
|
||||
if (delete)
|
||||
mToken.delete(mListener.getAccountManager());
|
||||
mToken = null;
|
||||
if (delete) {
|
||||
mTokenKVV.delete(mListener.getAccountManager());
|
||||
mTokenBB.delete(mListener.getAccountManager());
|
||||
}
|
||||
mTokenKVV = null;
|
||||
return handleCallbacks(false);
|
||||
}
|
||||
|
||||
@@ -60,43 +71,57 @@ public class Login extends HTTPService {
|
||||
}
|
||||
|
||||
public boolean isLoggedIn() {
|
||||
return mToken != null;
|
||||
return mTokenKVV != null && mTokenBB != null;
|
||||
}
|
||||
|
||||
public boolean isInOnlineMode() {
|
||||
return isLoggedIn();
|
||||
}
|
||||
|
||||
void testLoginToken(@NotNull NetworkCallback<LoginToken> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
if (mToken == null) {
|
||||
void testLoginToken(@NotNull NetworkCallback<Pair<LoginTokenKVV, LoginTokenBB>> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
if (mTokenKVV == null) {
|
||||
errorCallback.onError(new NetworkError(100173, -1, "Not logged in!"));
|
||||
return;
|
||||
}
|
||||
testLoginToken(mToken, callback, errorCallback);
|
||||
if (mTokenBB == null) {
|
||||
errorCallback.onError(new NetworkError(100174, -1, "Not logged in!"));
|
||||
return;
|
||||
}
|
||||
testLoginToken(mTokenKVV, mTokenBB, callback, errorCallback);
|
||||
}
|
||||
|
||||
private void testLoginToken(@NotNull LoginToken token, @NotNull NetworkCallback<LoginToken> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
new de.sebse.fuplanner.services.kvv.sync.Login(getContext()).testLoginToken(token, callback, errorCallback);
|
||||
private void testLoginToken(@NotNull LoginTokenKVV tokenKVV, @NotNull LoginTokenBB tokenBB, @NotNull NetworkCallback<Pair<LoginTokenKVV, LoginTokenBB>> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
new KVVLogin(getContext()).testLoginToken(tokenKVV, tokenKVV1 -> {
|
||||
new BBLogin(getContext()).testLoginToken(tokenBB, tokenBB1 -> {
|
||||
callback.onResponse(new Pair<>(tokenKVV1, tokenBB1));
|
||||
}, errorCallback);
|
||||
}, errorCallback);
|
||||
}
|
||||
|
||||
@Nullable public LoginToken getLoginToken() {
|
||||
return mToken;
|
||||
@Nullable public LoginTokenKVV getLoginTokenKVV() {
|
||||
return mTokenKVV;
|
||||
}
|
||||
|
||||
void refreshLogin(NetworkCallback<LoginToken> success, NetworkErrorCallback error) {
|
||||
@Nullable public LoginTokenBB getLoginTokenBB() {
|
||||
return mTokenBB;
|
||||
}
|
||||
|
||||
void refreshLogin(NetworkCallback<Pair<LoginTokenKVV, LoginTokenBB>> success, NetworkErrorCallback error) {
|
||||
boolean isFirst = mRefreshCallbacks.isEmpty();
|
||||
mRefreshCallbacks.add(success, error);
|
||||
if (!isFirst)
|
||||
return;
|
||||
CustomAccountManager manager = mListener.getAccountManager();
|
||||
manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, ignored -> {
|
||||
restoreOnlineLogin(isRestored -> {
|
||||
if (isRestored)
|
||||
testLoginToken(mRefreshCallbacks::responseResponse, mRefreshCallbacks::responseError);
|
||||
else {
|
||||
logout(true);
|
||||
mRefreshCallbacks.responseError(new NetworkError(100180, 403, "Re-login failed!"));
|
||||
}
|
||||
manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD, ignored2 -> {
|
||||
restoreOnlineLogin(isRestored -> {
|
||||
if (isRestored)
|
||||
testLoginToken(mRefreshCallbacks::responseResponse, mRefreshCallbacks::responseError);
|
||||
else {
|
||||
logout(true);
|
||||
mRefreshCallbacks.responseError(new NetworkError(100180, 403, "Re-login failed!"));
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -104,8 +129,8 @@ public class Login extends HTTPService {
|
||||
|
||||
|
||||
private boolean handleCallbacks(boolean isOnlyRefresh) {
|
||||
if (mToken != null) {
|
||||
mListener.onLogin(mToken, isOnlyRefresh);
|
||||
if (mTokenKVV != null) {
|
||||
mListener.onLogin(mTokenKVV, isOnlyRefresh);
|
||||
return true;
|
||||
} else {
|
||||
mListener.onLogout();
|
||||
@@ -113,11 +138,12 @@ public class Login extends HTTPService {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setToken(@Nullable LoginToken token) {
|
||||
if (token == null)
|
||||
private boolean setToken(@Nullable LoginTokenKVV tokenKVV, @Nullable LoginTokenBB tokenBB) {
|
||||
if (tokenKVV == null || tokenBB == null)
|
||||
return false;
|
||||
boolean isOnlyRefresh = mToken != null;
|
||||
mToken = token;
|
||||
boolean isOnlyRefresh = mTokenKVV != null && tokenBB != null;
|
||||
mTokenKVV = tokenKVV;
|
||||
mTokenBB = tokenBB;
|
||||
return isOnlyRefresh || handleCallbacks(isOnlyRefresh);
|
||||
}
|
||||
|
||||
|
||||
@@ -33,12 +33,12 @@ public class ModulesAnnouncements extends PartModules<ArrayList<Announcement>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(final String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
protected void upgradeKVV(final String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginToken().getCookies(), response -> {
|
||||
super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!"));
|
||||
@@ -88,4 +88,9 @@ public class ModulesAnnouncements extends PartModules<ArrayList<Announcement>> {
|
||||
callback.onResponse(announcements);
|
||||
}, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgradeBB(String ID, NetworkCallback<ArrayList<Announcement>> callback, NetworkErrorCallback errorCallback) {
|
||||
callback.onResponse(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,12 +34,12 @@ public class ModulesAssignments extends PartModules<AssignmentList> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(final String ID, final NetworkCallback<AssignmentList> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
protected void upgradeKVV(final String ID, final NetworkCallback<AssignmentList> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101304, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> {
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101301, 403, "No assignments retrieved!"));
|
||||
@@ -87,4 +87,9 @@ public class ModulesAssignments extends PartModules<AssignmentList> {
|
||||
callback.onResponse(assignments);
|
||||
}, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get assignments!")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgradeBB(String ID, NetworkCallback<AssignmentList> callback, NetworkErrorCallback errorCallback) {
|
||||
callback.onResponse(new AssignmentList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,12 +32,12 @@ public class ModulesEvents extends PartModules<EventList> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(final String ID, final NetworkCallback<EventList> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
protected void upgradeKVV(final String ID, final NetworkCallback<EventList> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101404, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true", ID), mLogin.getLoginToken().getCookies(), response -> {
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101401, 403, "No events retrieved!"));
|
||||
@@ -80,4 +80,9 @@ public class ModulesEvents extends PartModules<EventList> {
|
||||
callback.onResponse(events);
|
||||
}, error -> errorCallback.onError(new NetworkError(101403, error.networkResponse.statusCode, "Cannot get events!")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgradeBB(String ID, NetworkCallback<EventList> callback, NetworkErrorCallback errorCallback) {
|
||||
callback.onResponse(new EventList());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(final String ID, final NetworkCallback<ArrayList<Grade>> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
protected void upgradeKVV(final String ID, final NetworkCallback<ArrayList<Grade>> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101504, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
super.get(String.format("https://kvv.imp.fu-berlin.de/direct/gradebook/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> {
|
||||
super.get(String.format("https://kvv.imp.fu-berlin.de/direct/gradebook/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101501, 403, "No gradebook retrieved!"));
|
||||
@@ -73,4 +73,9 @@ public class ModulesGradebook extends PartModules<ArrayList<Grade>> {
|
||||
callback.onResponse(gradebook);
|
||||
}, error -> errorCallback.onError(new NetworkError(101503, error.networkResponse.statusCode, "Cannot get gradebook!")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgradeBB(String ID, NetworkCallback<ArrayList<Grade>> callback, NetworkErrorCallback errorCallback) {
|
||||
callback.onResponse(new ArrayList<>());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import org.json.JSONObject;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.regex.MatchResult;
|
||||
|
||||
import de.sebse.fuplanner.services.kvv.types.Lecturer;
|
||||
@@ -61,7 +63,10 @@ public class ModulesList extends HTTPService {
|
||||
}
|
||||
|
||||
private void find(String moduleID, NetworkCallback<Modules.Module> moduleNetworkCallback, NetworkErrorCallback errorCallback, int retries) {
|
||||
if (mModules != null && mLogin.getLoginToken() != null && mLogin.getLoginToken().isOtherUser(mModules.getUsername()))
|
||||
if (mModules != null &&
|
||||
mLogin.getLoginTokenKVV() != null && mLogin.getLoginTokenKVV().isOtherUser(mModules.getUsername()) &&
|
||||
mLogin.getLoginTokenBB() != null && mLogin.getLoginTokenBB().isOtherUser(mModules.getUsername())
|
||||
)
|
||||
delete();
|
||||
if (retries < 0) {
|
||||
errorCallback.onError(new NetworkError(101107, -1, "Too many retries!"));
|
||||
@@ -114,7 +119,10 @@ public class ModulesList extends HTTPService {
|
||||
}
|
||||
|
||||
private void recv(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback, boolean forceRefresh, final int retries) {
|
||||
if (mModules != null && mLogin.getLoginToken() != null && mLogin.getLoginToken().isOtherUser(mModules.getUsername()))
|
||||
if (mModules != null &&
|
||||
mLogin.getLoginTokenKVV() != null && mLogin.getLoginTokenKVV().isOtherUser(mModules.getUsername()) &&
|
||||
mLogin.getLoginTokenBB() != null && mLogin.getLoginTokenBB().isOtherUser(mModules.getUsername())
|
||||
)
|
||||
delete();
|
||||
mQueue.add(() -> {
|
||||
if (this.mModules != null && !forceRefresh) {
|
||||
@@ -122,19 +130,10 @@ public class ModulesList extends HTTPService {
|
||||
mQueue.next();
|
||||
return;
|
||||
}
|
||||
this.upgrade(success -> {
|
||||
if (this.mModules == null)
|
||||
this.mModules = success;
|
||||
else if(this.mModules.updateList(success)) {
|
||||
mListener.onModuleListChange();
|
||||
store();
|
||||
}
|
||||
callback.onResponse(this.mModules);
|
||||
mQueue.next();
|
||||
}, error -> {
|
||||
NetworkErrorCallback errorFunc = (error -> {
|
||||
if (retries > 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) {
|
||||
mLogin.refreshLogin(success -> {
|
||||
recv(callback, errorCallback, forceRefresh, retries-1);
|
||||
recv(callback, errorCallback, forceRefresh, retries - 1);
|
||||
mQueue.next();
|
||||
}, error1 -> {
|
||||
errorCallback.onError(error1);
|
||||
@@ -145,28 +144,40 @@ public class ModulesList extends HTTPService {
|
||||
errorCallback.onError(error);
|
||||
mQueue.next();
|
||||
});
|
||||
this.upgradeKVV(successKVV -> {
|
||||
this.upgradeBlackboard(successKVV, success -> {
|
||||
if (this.mModules == null)
|
||||
this.mModules = success;
|
||||
else if (this.mModules.updateList(success)) {
|
||||
mListener.onModuleListChange();
|
||||
store();
|
||||
}
|
||||
callback.onResponse(this.mModules);
|
||||
mQueue.next();
|
||||
}, errorFunc);
|
||||
}, errorFunc);
|
||||
});
|
||||
}
|
||||
|
||||
private void upgrade(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
errorCallback.onError(new NetworkError(101105, 500, "Currently running in offline mode!"));
|
||||
private void upgradeKVV(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101110, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
get("https://kvv.imp.fu-berlin.de/direct/site.json", mLogin.getLoginToken().getCookies(), response -> {
|
||||
get("https://kvv.imp.fu-berlin.de/direct/site.json", mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101101, 403, "No module list retrieved!"));
|
||||
errorCallback.onError(new NetworkError(101111, 403, "No module list retrieved!"));
|
||||
return;
|
||||
}
|
||||
Modules modules = new Modules(mLogin.getLoginToken().getUsername());
|
||||
Modules modules = new Modules(mLogin.getLoginTokenKVV().getUsername());
|
||||
JSONArray sites;
|
||||
try {
|
||||
JSONObject json = new JSONObject(body);
|
||||
sites = json.getJSONArray("site_collection");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!"));
|
||||
errorCallback.onError(new NetworkError(101112, 403, "Cannot parse module list!"));
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < sites.length(); i++) {
|
||||
@@ -192,13 +203,13 @@ public class ModulesList extends HTTPService {
|
||||
String description = site.optString("description", "");
|
||||
description = String.valueOf(PartModules.fromHtml(description));
|
||||
String id = site.getString("id");
|
||||
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id);
|
||||
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id, Modules.TYPE_KVV);
|
||||
} catch (JSONException e) {
|
||||
log.e(new NetworkError(101103, 403, "Cannot parse module list!"));
|
||||
log.e(new NetworkError(101113, 403, "Cannot parse module list!"));
|
||||
log.e("ID:", i, "JSON:", sites);
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchFieldException e) {
|
||||
log.e(new NetworkError(101106, 403, "Cannot parse module list!"));
|
||||
log.e(new NetworkError(101114, 403, "Cannot parse module list!"));
|
||||
log.e("ID:", i, "JSON:", sites);
|
||||
e.printStackTrace();
|
||||
}
|
||||
@@ -208,6 +219,76 @@ public class ModulesList extends HTTPService {
|
||||
mLogin.testLoginToken(token -> callback.onResponse(modules), errorCallback);
|
||||
else
|
||||
callback.onResponse(modules);
|
||||
}, error -> errorCallback.onError(new NetworkError(101104, error.networkResponse.statusCode, "Cannot get module list!")));
|
||||
}, error -> errorCallback.onError(new NetworkError(101115, error.networkResponse.statusCode, "Cannot get module list!")));
|
||||
}
|
||||
|
||||
private void upgradeBlackboard(final Modules modulesKVV, final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null) {
|
||||
errorCallback.onError(new NetworkError(101120, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/%s/courses", mLogin.getLoginTokenBB().getId()), mLogin.getLoginTokenBB().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101121, 403, "No module list retrieved!"));
|
||||
return;
|
||||
}
|
||||
final JSONArray[] sites = new JSONArray[1];
|
||||
try {
|
||||
JSONObject json = new JSONObject(body);
|
||||
sites[0] = json.getJSONArray("results");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
errorCallback.onError(new NetworkError(101122, 403, "Cannot parse module list!"));
|
||||
return;
|
||||
}
|
||||
final int[] latch = {sites[0].length()};
|
||||
for (int i = 0; i < sites[0].length(); i++) {
|
||||
try {
|
||||
JSONObject site = sites[0].getJSONObject(i);
|
||||
String courseId = site.getString("courseId");
|
||||
get(String.format("https://lms.fu-berlin.de/learn/api/v1/courses/%s", courseId), mLogin.getLoginTokenBB().getCookies(), response1 -> {
|
||||
String body1 = response1.getParsed();
|
||||
if (body1 == null) {
|
||||
errorCallback.onError(new NetworkError(101124, 403, "No module list retrieved!"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSONObject json = new JSONObject(body1);
|
||||
String name = json.getString("name");
|
||||
String type = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 1);
|
||||
String lvNumber = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 2);
|
||||
String semYear = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 3);
|
||||
String semType = Regex.regex("[A-Za-z0-9]*_([A-Za-z0-9]*)_([A-Za-z0-9]*)_([0-9]*)([A-Z]*)", json.getString("courseId"), 4);
|
||||
boolean found = false;
|
||||
for (Modules.Module module: modulesKVV) {
|
||||
if (module.lvNumber.contains(lvNumber)) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
modulesKVV.addModule(new Semester(semType.equals("W") ? Semester.SEM_WS : Semester.SEM_SS, Integer.valueOf(semYear)), new HashSet<>(), name, new LinkedHashSet<>(), type, "", courseId, Modules.TYPE_BB);
|
||||
latch[0]--;
|
||||
if (latch[0] == 0)
|
||||
callback.onResponse(modulesKVV);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
errorCallback.onError(new NetworkError(101125, 403, "Cannot parse module list!"));
|
||||
return;
|
||||
} catch (NoSuchFieldException e) {
|
||||
e.printStackTrace();
|
||||
errorCallback.onError(new NetworkError(101127, 403, "Cannot parse module list!"));
|
||||
return;
|
||||
}
|
||||
}, error -> errorCallback.onError(new NetworkError(101126, error.networkResponse.statusCode, "Cannot get module list!")));
|
||||
} catch (JSONException e) {
|
||||
log.e(new NetworkError(101123, 403, "Cannot parse module list!"));
|
||||
log.e("ID:", i, "JSON:", sites[0]);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}, error -> errorCallback.onError(new NetworkError(101125, error.networkResponse.statusCode, "Cannot get module list!")));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,12 +42,12 @@ public class ModulesResources extends PartModules<ArrayList<Resource>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgrade(final String ID, final NetworkCallback<ArrayList<Resource>> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
protected void upgradeKVV(final String ID, final NetworkCallback<ArrayList<Resource>> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json", ID), mLogin.getLoginToken().getCookies(), response -> {
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(101601, 403, "No resources retrieved!"));
|
||||
@@ -124,6 +124,10 @@ public class ModulesResources extends PartModules<ArrayList<Resource>> {
|
||||
}, error -> errorCallback.onError(new NetworkError(101603, error.networkResponse.statusCode, "Cannot get resources!")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void upgradeBB(String ID, NetworkCallback<ArrayList<Resource>> callback, NetworkErrorCallback errorCallback) {
|
||||
callback.onResponse(new ArrayList<>());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -160,11 +164,11 @@ public class ModulesResources extends PartModules<ArrayList<Resource>> {
|
||||
}
|
||||
|
||||
private void fileUpgrade(String filename, String url, String modulename, final NetworkCallback<String> callback, final NetworkErrorCallback errorCallback) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
|
||||
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
|
||||
errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!"));
|
||||
return;
|
||||
}
|
||||
get(url, mLogin.getLoginToken().getCookies(), response -> {
|
||||
get(url, mLogin.getLoginTokenKVV().getCookies(), response -> {
|
||||
if (Regex.has("\\.[Uu][Rr][Ll]$", url)){
|
||||
// Return redirected URL
|
||||
String path = response.getHeaders().get("Location");
|
||||
|
||||
@@ -25,7 +25,7 @@ abstract class PartModules<T> extends Part<Modules.Module> {
|
||||
mQueue.next();
|
||||
return;
|
||||
}
|
||||
upgrade(module.getID(), success -> {
|
||||
upgrade(module.getModuleType(), module.getID(), success -> {
|
||||
if (setPart(module, success)) {
|
||||
this.mList.store();
|
||||
}
|
||||
@@ -61,5 +61,18 @@ abstract class PartModules<T> extends Part<Modules.Module> {
|
||||
|
||||
protected abstract boolean setPart(Modules.Module module, T part);
|
||||
|
||||
protected abstract void upgrade(final String ID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback);
|
||||
protected void upgrade(final int moduleType, final String ID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback) {
|
||||
switch (moduleType) {
|
||||
case Modules.TYPE_KVV:
|
||||
upgradeKVV(ID, callback, errorCallback);
|
||||
break;
|
||||
case Modules.TYPE_BB:
|
||||
upgradeBB(ID, callback, errorCallback);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void upgradeKVV(final String ID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback);
|
||||
|
||||
protected abstract void upgradeBB(final String ID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,266 @@
|
||||
package de.sebse.fuplanner.services.kvv.sync;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginTokenBB;
|
||||
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
public class BBLogin extends HTTPService {
|
||||
public BBLogin(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public void testLoginToken(@NotNull LoginTokenBB token, @NotNull NetworkCallback<LoginTokenBB> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/?userName=%s", token.getUsername()), token.getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
errorCallback.onError(new NetworkError(100272, 403, "Testing login failed!"));
|
||||
return;
|
||||
}
|
||||
try {
|
||||
JSONObject json = new JSONObject(body);
|
||||
json = json.getJSONArray("results").getJSONObject(0);
|
||||
String id = json.getString("id");
|
||||
String studentId = json.getString("studentId");
|
||||
token.setAdditionals(id, studentId);
|
||||
callback.onResponse(token);
|
||||
} catch (JSONException e) {
|
||||
errorCallback.onError(new NetworkError(100271, 403, "Cannot parse profile!"));
|
||||
}
|
||||
}, error -> errorCallback.onError(new NetworkError(100270, error.networkResponse.statusCode, "Testing login failed!")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public void doLogin(String username, String password, NetworkCallback<LoginTokenBB> callback, NetworkErrorCallback error) {
|
||||
step1(success1 -> {
|
||||
String samlLocation = success1.get("Location");
|
||||
step2(samlLocation, success2 -> {
|
||||
String fuJSESSIONID = success2.get("JSESSIONID");
|
||||
step3(fuJSESSIONID, success3 -> {
|
||||
step4(username, password, fuJSESSIONID, success4 -> {
|
||||
String samlResponse = success4.get("SAMLResponse");
|
||||
step5(samlResponse, success5 -> {
|
||||
String shibsessionKey = success5.get("shibsessionKey");
|
||||
String shibsessionName = success5.get("shibsessionName");
|
||||
step6(shibsessionKey, shibsessionName, success6 -> {
|
||||
String s_session_id = success6.get("s_session_id");
|
||||
String session_id = success6.get("session_id");
|
||||
LoginTokenBB token = new LoginTokenBB(username, s_session_id, session_id);
|
||||
callback.onResponse(token);
|
||||
}, error);
|
||||
}, error);
|
||||
}, error);
|
||||
}, error);
|
||||
}, error);
|
||||
}, error);
|
||||
}
|
||||
|
||||
/*
|
||||
1= GET https://lms.fu-berlin.de/lms-apps/login/sso/index.php
|
||||
-> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState]
|
||||
*/
|
||||
private void step1(final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get("https://lms.fu-berlin.de/lms-apps/login/sso/index.php", null, response -> {
|
||||
String location = response.getHeaders().get("Location");
|
||||
if (location==null) {
|
||||
errorCallback.onError(new NetworkError(100211, -1, "Error on getting SAML request!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object = new HashMap<>();
|
||||
object.put("Location", location);
|
||||
callback.onResponse(object);
|
||||
}, error -> errorCallback.onError(new NetworkError(100210, error.networkResponse.statusCode, "Error on getting SAML request!")));
|
||||
}
|
||||
|
||||
/*
|
||||
2= GET [Location-Header 1]
|
||||
-> Set-Cookie: JSESSIONID=[JSESSION-FU]
|
||||
-> Location: /idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1
|
||||
*/
|
||||
private void step2(String url, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get(url, null, response -> {
|
||||
String cookies = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies==null) {
|
||||
errorCallback.onError(new NetworkError(100221, -1, "Error on starting FU session!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object;
|
||||
try {
|
||||
object = getCookie(cookies, new String[]{"JSESSIONID"});
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(100222, -1, "Error on starting FU session!"));
|
||||
return;
|
||||
}
|
||||
callback.onResponse(object);
|
||||
}, error -> errorCallback.onError(new NetworkError(100220, error.networkResponse.statusCode, "Error on starting FU session!")));
|
||||
}
|
||||
|
||||
/*
|
||||
3= GET [Location-Header 2]
|
||||
+ Cookie: JSESSIONID=[JSESSION-FU]
|
||||
*/
|
||||
private void step3(String JSESSIONID_FU, final NetworkCallback<Boolean> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID_FU);
|
||||
head("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> {
|
||||
callback.onResponse(true);
|
||||
}, error -> errorCallback.onError(new NetworkError(100230, error.networkResponse.statusCode, "Error starting login page!")));
|
||||
}
|
||||
|
||||
/*
|
||||
4= POST [Location-Header 2]
|
||||
+ Body: j_username=[USERNAME]&j_password=[PASSWORD]&_eventId_proceed=
|
||||
+ Header: Content-Type: application/x-www-form-urlencoded
|
||||
+ Header: Referer: [Location-Header 2]
|
||||
+ Cookie: JSESSIONID=[JSESSION-FU]
|
||||
-> Set-Cookie: shib_idp_session=[SHIB-IDP-SESSION]
|
||||
-> Body SAMLResponse-Input-value
|
||||
*/
|
||||
private void step4(String username, String password, String JSESSIONID_FU, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID_FU);
|
||||
HashMap<String, String> body = new HashMap<>();
|
||||
body.put("j_username", username);
|
||||
body.put("j_password", password);
|
||||
body.put("_eventId_proceed", "");
|
||||
post("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, body, response -> {
|
||||
String cookies1 = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies1 ==null) {
|
||||
errorCallback.onError(new NetworkError(100241, -1, "Error on logging in to FU Identity Server!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object;
|
||||
try {
|
||||
object = getCookie(cookies1, new String[]{"shib_idp_session"});
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(100242, -1, "Error on logging in to FU Identity Server!"));
|
||||
return;
|
||||
}
|
||||
|
||||
String content = response.getParsed();
|
||||
if (content == null) {
|
||||
errorCallback.onError(new NetworkError(100243, -1, "Error on getting SAML response!"));
|
||||
return;
|
||||
}
|
||||
Pattern pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)");
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
if (!matcher.find()) {
|
||||
errorCallback.onError(new NetworkError(100244, -1, "Error on getting SAML response!"));
|
||||
return;
|
||||
}
|
||||
object.put("SAMLResponse", matcher.group(1));
|
||||
callback.onResponse(object);
|
||||
}, error -> errorCallback.onError(new NetworkError(100245, error.networkResponse.statusCode, "Error on logging in to FU Identity Server!")));
|
||||
}
|
||||
|
||||
/*
|
||||
5= POST https://lms.fu-berlin.de/Shibboleth.sso/SAML2/POST
|
||||
+ Body: SAMLResponse=[SAML-RESPONSE]
|
||||
+ Header: Content-Type: application/x-www-form-urlencoded
|
||||
-> Set-Cookie: _shibsession_[SESS-NR]: [SESS-VALUE]
|
||||
*/
|
||||
private void step5(String SAMLResponse, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> body = new HashMap<>();
|
||||
body.put("SAMLResponse", SAMLResponse);
|
||||
post("https://lms.fu-berlin.de/Shibboleth.sso/SAML2/POST", null, body, response -> {
|
||||
String cookies = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies ==null) {
|
||||
errorCallback.onError(new NetworkError(100251, -1, "Error on starting KVV session!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object = new HashMap<>();
|
||||
|
||||
|
||||
Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);");
|
||||
Matcher matcher = pattern.matcher(cookies);
|
||||
if (!matcher.find()) {
|
||||
errorCallback.onError(new NetworkError(100252, -1, "Error on starting KVV session!"));
|
||||
}
|
||||
object.put("shibsessionKey", matcher.group(1));
|
||||
object.put("shibsessionName", matcher.group(2));
|
||||
|
||||
callback.onResponse(object);
|
||||
}, error -> errorCallback.onError(new NetworkError(100250, error.networkResponse.statusCode, "Error on starting KVV session!")));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
6= https://lms.fu-berlin.de/webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1
|
||||
+ Cookie: _shibsession_[SESS-NR]: [SESS-VALUE]
|
||||
-> Set-Cookie: JSESSIONID: [JSESSION-KVV]
|
||||
*/
|
||||
private void step6(String shibsessionKey, String shibsessionName, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put(shibsessionKey, shibsessionName);
|
||||
log.d(shibsessionKey, shibsessionName);
|
||||
get("https://lms.fu-berlin.de/webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1", cookies, response -> {
|
||||
String cookies1 = response.getHeaders().get("Set-Cookie");
|
||||
if (cookies1 ==null) {
|
||||
errorCallback.onError(new NetworkError(100261, -1, "Cannot finish login process!"));
|
||||
return;
|
||||
}
|
||||
HashMap<String, String> object;
|
||||
try {
|
||||
object = getCookie(cookies1, new String[]{"session_id", "s_session_id"});
|
||||
} catch (NoSuchFieldException e) {
|
||||
errorCallback.onError(new NetworkError(100262, -1, "Cannot finish login process!"));
|
||||
return;
|
||||
}
|
||||
callback.onResponse(object);
|
||||
}, error -> errorCallback.onError(new NetworkError(100260, error.networkResponse.statusCode, "Cannot finish login process!")));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private String getCookie(String cookies, String name) throws NoSuchFieldException {
|
||||
Pattern pattern = Pattern.compile(name+"=([^;]+);");
|
||||
Matcher matcher = pattern.matcher(cookies);
|
||||
if (!matcher.find()) {
|
||||
log.e("GETcookie failed", name);
|
||||
log.e("GETcookie failed", cookies);
|
||||
throw new NoSuchFieldException();
|
||||
}
|
||||
return matcher.group(1);
|
||||
}
|
||||
|
||||
private HashMap<String, String> getCookie(String cookies, String[] names) throws NoSuchFieldException {
|
||||
HashMap<String, String> result = new HashMap<>();
|
||||
for (String name: names) {
|
||||
result.put(name,this.getCookie(cookies, name));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -10,19 +10,19 @@ import java.util.HashMap;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginToken;
|
||||
import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV;
|
||||
import de.sebse.fuplanner.tools.network.HTTPService;
|
||||
import de.sebse.fuplanner.tools.network.NetworkCallback;
|
||||
import de.sebse.fuplanner.tools.network.NetworkError;
|
||||
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
|
||||
|
||||
public class Login extends HTTPService {
|
||||
public Login(Context context) {
|
||||
public class KVVLogin extends HTTPService {
|
||||
public KVVLogin(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
public void testLoginToken(@NotNull LoginToken token, @NotNull NetworkCallback<LoginToken> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
public void testLoginToken(@NotNull LoginTokenKVV token, @NotNull NetworkCallback<LoginTokenKVV> callback, @NotNull NetworkErrorCallback errorCallback) {
|
||||
get(String.format("https://kvv.imp.fu-berlin.de/direct/profile/%s.json", token.getUsername()), token.getCookies(), response -> {
|
||||
String body = response.getParsed();
|
||||
if (body == null) {
|
||||
@@ -55,7 +55,7 @@ public class Login extends HTTPService {
|
||||
|
||||
|
||||
|
||||
public void doLogin(String username, String password, NetworkCallback<LoginToken> callback, NetworkErrorCallback error) {
|
||||
public void doLogin(String username, String password, NetworkCallback<LoginTokenKVV> callback, NetworkErrorCallback error) {
|
||||
step1(success1 -> {
|
||||
String samlLocation = success1.get("Location");
|
||||
step2(samlLocation, success2 -> {
|
||||
@@ -68,7 +68,7 @@ public class Login extends HTTPService {
|
||||
String shibsessionName = success5.get("shibsessionName");
|
||||
step6(shibsessionKey, shibsessionName, success6 -> {
|
||||
String kvvJSESSIONID = success6.get("JSESSIONID");
|
||||
LoginToken token = new LoginToken(username, kvvJSESSIONID);
|
||||
LoginTokenKVV token = new LoginTokenKVV(username, kvvJSESSIONID);
|
||||
callback.onResponse(token);
|
||||
}, error);
|
||||
}, error);
|
||||
@@ -80,7 +80,7 @@ public class Login extends HTTPService {
|
||||
|
||||
/*
|
||||
1= GET https://kvv.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub
|
||||
-> Location-Header: https://identity.fu-berlin.de:9443/idp-fub-qa/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState]
|
||||
-> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState]
|
||||
*/
|
||||
private void step1(final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get("https://kvv.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub", null, response -> {
|
||||
@@ -98,7 +98,7 @@ public class Login extends HTTPService {
|
||||
/*
|
||||
2= GET [Location-Header 1]
|
||||
-> Set-Cookie: JSESSIONID=[JSESSION-FU]
|
||||
-> Location: /idp-fub-qa/profile/SAML2/Redirect/SSO?execution=e1s1
|
||||
-> Location: /idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1
|
||||
*/
|
||||
private void step2(String url, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
|
||||
get(url, null, response -> {
|
||||
@@ -125,7 +125,7 @@ public class Login extends HTTPService {
|
||||
private void step3(String JSESSIONID_FU, final NetworkCallback<Boolean> callback, final NetworkErrorCallback errorCallback) {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("JSESSIONID", JSESSIONID_FU);
|
||||
get("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> {
|
||||
head("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> {
|
||||
callback.onResponse(true);
|
||||
}, error -> errorCallback.onError(new NetworkError(100130, error.networkResponse.statusCode, "Error starting login page!")));
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package de.sebse.fuplanner.services.kvv.types;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.sebse.fuplanner.services.fulogin.AccountGeneral;
|
||||
import de.sebse.fuplanner.tools.CustomAccountManager;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class LoginTokenBB {
|
||||
private final String s_session_id;
|
||||
private final String session_id;
|
||||
private final String username;
|
||||
@Nullable private String id;
|
||||
@Nullable private String studentId;
|
||||
|
||||
public LoginTokenBB(String username, String s_session_id, String session_id) {
|
||||
this.username = username;
|
||||
this.s_session_id = s_session_id;
|
||||
this.session_id = session_id;
|
||||
}
|
||||
|
||||
public static void load(CustomAccountManager manager, LoginTokenInterface callback) {
|
||||
if (!manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) {
|
||||
callback.run(null);
|
||||
return;
|
||||
}
|
||||
manager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD, tokenString -> {
|
||||
if (tokenString == null) {
|
||||
callback.run(null);
|
||||
return;
|
||||
}
|
||||
callback.run(LoginTokenBB.fromJsonString(tokenString));
|
||||
});
|
||||
}
|
||||
|
||||
public void delete(CustomAccountManager manager) {
|
||||
manager.deleteAccount(AccountGeneral.ACCOUNT_TYPE);
|
||||
}
|
||||
|
||||
public void setAdditionals(String id, String studentId) {
|
||||
this.id = id;
|
||||
this.studentId = studentId;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
private String getSessionId() {
|
||||
return session_id;
|
||||
}
|
||||
|
||||
public String getSSessionId() {
|
||||
return s_session_id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getStudentId() {
|
||||
return studentId;
|
||||
}
|
||||
|
||||
public HashMap<String, String> getCookies() {
|
||||
HashMap<String, String> cookies = new HashMap<>();
|
||||
cookies.put("session_id", getSessionId());
|
||||
cookies.put("s_session_id", getSSessionId());
|
||||
return cookies;
|
||||
}
|
||||
|
||||
public boolean isOtherUser(String username) {
|
||||
return !this.getUsername().equals(username);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder result = new StringBuilder();
|
||||
HashMap<String, String> cookies = this.getCookies();
|
||||
for (String header: cookies.keySet()) {
|
||||
result.append(header).append("=").append(cookies.get(header)).append(";");
|
||||
}
|
||||
return result.substring(0, result.length()-1);
|
||||
}
|
||||
|
||||
public String toJsonString() {
|
||||
JSONObject json = new JSONObject();
|
||||
try {
|
||||
json.put("s_session_id", s_session_id);
|
||||
json.put("session_id", session_id);
|
||||
json.put("username", username);
|
||||
json.put("id", id);
|
||||
json.put("studentId", studentId);
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
private static LoginTokenBB fromJsonString(String tokenString) {
|
||||
try {
|
||||
JSONObject json = new JSONObject(tokenString);
|
||||
LoginTokenBB token = new LoginTokenBB(
|
||||
json.getString("username"),
|
||||
json.getString("s_session_id"),
|
||||
json.getString("session_id"));
|
||||
if (!json.isNull("id"))
|
||||
token.setAdditionals(
|
||||
json.getString("id"),
|
||||
json.getString("studentId")
|
||||
);
|
||||
return token;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public interface LoginTokenInterface {
|
||||
void run(LoginTokenBB token);
|
||||
}
|
||||
}
|
||||
@@ -3,26 +3,24 @@ package de.sebse.fuplanner.services.kvv.types;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.HashMap;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import de.sebse.fuplanner.services.fulogin.AccountGeneral;
|
||||
import de.sebse.fuplanner.tools.CustomAccountManager;
|
||||
import de.sebse.fuplanner.tools.logging.Logger;
|
||||
|
||||
/**
|
||||
* Created by sebastian on 29.10.17.
|
||||
*/
|
||||
|
||||
public class LoginToken implements Serializable {
|
||||
public class LoginTokenKVV {
|
||||
private final String username;
|
||||
private final String JSESSIONID;
|
||||
@Nullable private String fullName;
|
||||
@Nullable private String email;
|
||||
|
||||
public LoginToken(String username, String JSESSIONID) {
|
||||
public LoginTokenKVV(String username, String JSESSIONID) {
|
||||
this.username = username;
|
||||
this.JSESSIONID = JSESSIONID;
|
||||
}
|
||||
@@ -37,7 +35,7 @@ public class LoginToken implements Serializable {
|
||||
callback.run(null);
|
||||
return;
|
||||
}
|
||||
callback.run(LoginToken.fromJsonString(tokenString));
|
||||
callback.run(LoginTokenKVV.fromJsonString(tokenString));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -103,10 +101,10 @@ public class LoginToken implements Serializable {
|
||||
return json.toString();
|
||||
}
|
||||
|
||||
private static LoginToken fromJsonString(String tokenString) {
|
||||
private static LoginTokenKVV fromJsonString(String tokenString) {
|
||||
try {
|
||||
JSONObject json = new JSONObject(tokenString);
|
||||
LoginToken token = new LoginToken(
|
||||
LoginTokenKVV token = new LoginTokenKVV(
|
||||
json.getString("username"),
|
||||
json.getString("JSESSIONID"));
|
||||
if (!json.isNull("fullName"))
|
||||
@@ -122,6 +120,6 @@ public class LoginToken implements Serializable {
|
||||
}
|
||||
|
||||
public interface LoginTokenInterface {
|
||||
void run(LoginToken token);
|
||||
void run(LoginTokenKVV token);
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,9 @@ import androidx.annotation.Nullable;
|
||||
*/
|
||||
|
||||
public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||
public static final int TYPE_KVV = 1;
|
||||
public static final int TYPE_BB = 2;
|
||||
|
||||
private SortedListModule list;
|
||||
private final String mUsername;
|
||||
private transient long mLastTimestamp = 0;
|
||||
@@ -37,8 +40,8 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||
this.list = new SortedListModule();
|
||||
}
|
||||
|
||||
public void addModule(@Nullable Semester semester, HashSet<String> lvNumber, String title, LinkedHashSet<Lecturer> lecturer, String type, String description, String ID) {
|
||||
Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID);
|
||||
public void addModule(@Nullable Semester semester, HashSet<String> lvNumber, String title, LinkedHashSet<Lecturer> lecturer, String type, String description, String ID, int moduleType) {
|
||||
Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID, moduleType);
|
||||
this.list.add(m);
|
||||
}
|
||||
|
||||
@@ -154,14 +157,16 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||
}
|
||||
|
||||
public class Module implements Serializable {
|
||||
|
||||
@Nullable public final Semester semester;
|
||||
@NotNull final HashSet<String> lvNumber;
|
||||
@NotNull public final HashSet<String> lvNumber;
|
||||
@NotNull public final String title;
|
||||
@NotNull
|
||||
public final ArrayList<Lecturer> lecturer;
|
||||
@Nullable public final String type;
|
||||
@Nullable public final String description;
|
||||
@NotNull private final String ID;
|
||||
@NotNull private final int moduleType;
|
||||
@Nullable public ArrayList<Announcement> announcements;
|
||||
@Nullable public AssignmentList assignments;
|
||||
@Nullable public EventList events;
|
||||
@@ -182,7 +187,7 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||
return userPoint/maxPoint;
|
||||
}
|
||||
|
||||
private Module(@Nullable Semester semester, @NotNull HashSet<String> lvNumber, @NotNull String title, @NotNull LinkedHashSet<Lecturer> lecturer, @Nullable String type, @Nullable String description, @NotNull String ID) {
|
||||
private Module(@Nullable Semester semester, @NotNull HashSet<String> lvNumber, @NotNull String title, @NotNull LinkedHashSet<Lecturer> lecturer, @Nullable String type, @Nullable String description, @NotNull String ID, @NotNull int moduleType) {
|
||||
|
||||
title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1");
|
||||
|
||||
@@ -193,6 +198,7 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||
this.type = type;
|
||||
this.description = description;
|
||||
this.ID = ID;
|
||||
this.moduleType = moduleType;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@@ -213,7 +219,11 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hashCode(semester, lvNumber, title, lecturer, type, description, ID);
|
||||
return Objects.hashCode(semester, lvNumber, title, lecturer, type, description, ID, moduleType);
|
||||
}
|
||||
|
||||
public int getModuleType() {
|
||||
return moduleType;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,8 +52,17 @@ public class HTTPService {
|
||||
successResponseListener.remove(id);
|
||||
}
|
||||
|
||||
protected void head(String url, @Nullable final HashMap<String, String> cookies, Response.Listener<Result> response, Response.ErrorListener error) {
|
||||
get(url, cookies, response, error, true);
|
||||
}
|
||||
|
||||
protected void get(String url, @Nullable final HashMap<String, String> cookies, Response.Listener<Result> response, Response.ErrorListener error) {
|
||||
HttpRequest request = new HttpRequest(Request.Method.GET, url, response, error) {
|
||||
get(url, cookies, response, error, false);
|
||||
}
|
||||
|
||||
protected void get(String url, @Nullable final HashMap<String, String> cookies, Response.Listener<Result> response, Response.ErrorListener error, boolean noBody) {
|
||||
int requestMethod = noBody ? Request.Method.HEAD : Request.Method.GET;
|
||||
HttpRequest request = new HttpRequest(requestMethod, url, response, error) {
|
||||
@Override
|
||||
public void deliverError(VolleyError error) {
|
||||
if (error == null) {
|
||||
|
||||
Reference in New Issue
Block a user