Merge remote-tracking branch 'origin/master'

This commit is contained in:
Caesar2011
2019-02-08 20:58:09 +01:00
8 changed files with 218 additions and 77 deletions

View File

@@ -17,6 +17,7 @@ import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.kvv.sync.BBLogin; import de.sebse.fuplanner.services.kvv.sync.BBLogin;
import de.sebse.fuplanner.services.kvv.sync.FULogin; import de.sebse.fuplanner.services.kvv.sync.FULogin;
import de.sebse.fuplanner.services.kvv.sync.KVVLogin; import de.sebse.fuplanner.services.kvv.sync.KVVLogin;
import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV;
import de.sebse.fuplanner.tools.logging.Logger; import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.network.NetworkError; import de.sebse.fuplanner.tools.network.NetworkError;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback; import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
@@ -76,7 +77,17 @@ public class UserLoginTask extends AsyncTask<Void, Void, String> {
login.set(success1.toJsonString()); login.set(success1.toJsonString());
latch.countDown(); latch.countDown();
}, errorFunc); }, errorFunc);
}, errorFunc); }, error -> {
if (error.getCode() == 100101) {
// KVV never used
LoginTokenKVV loginTokenKVV = new LoginTokenKVV(mUsername, "");
loginTokenKVV.setNotAvailable();
login.set(loginTokenKVV.toJsonString());
latch.countDown();
} else {
errorFunc.onError(error);
}
});
break; break;
case AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD: case AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD:
mBBLogin.doLogin(mUsername, mPassword, success -> { mBBLogin.doLogin(mUsername, mPassword, success -> {

View File

@@ -39,7 +39,7 @@ public class ModulesAnnouncements extends PartModules<ArrayList<Announcement>> {
errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!"));
return; return;
} }
super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999&_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
String body = response.getParsed(); String body = response.getParsed();
if (body == null) { if (body == null) {
errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!")); errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!"));
@@ -82,11 +82,7 @@ public class ModulesAnnouncements extends PartModules<ArrayList<Announcement>> {
} }
} }
// Empty announcements *may be* because token is invalid -> check callback.onResponse(announcements);
if (announcements.size() == 0)
mLogin.testLoginToken(token -> callback.onResponse(announcements), errorCallback);
else
callback.onResponse(announcements);
}, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!"))); }, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!")));
} }

View File

@@ -39,7 +39,7 @@ public class ModulesAssignments extends PartModules<AssignmentList> {
errorCallback.onError(new NetworkError(101304, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101304, 500, "Currently running in offline mode!"));
return; return;
} }
get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json?_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
String body = response.getParsed(); String body = response.getParsed();
if (body == null) { if (body == null) {
errorCallback.onError(new NetworkError(101301, 403, "No assignments retrieved!")); errorCallback.onError(new NetworkError(101301, 403, "No assignments retrieved!"));
@@ -80,11 +80,7 @@ public class ModulesAssignments extends PartModules<AssignmentList> {
} }
} }
// Empty assignments *may be* because token is invalid -> check callback.onResponse(assignments);
if (assignments.size() == 0)
mLogin.testLoginToken(token -> callback.onResponse(assignments), errorCallback);
else
callback.onResponse(assignments);
}, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get assignments!"))); }, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get assignments!")));
} }

View File

@@ -45,7 +45,7 @@ public class ModulesEvents extends PartModules<EventList> {
errorCallback.onError(new NetworkError(101404, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101404, 500, "Currently running in offline mode!"));
return; return;
} }
get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { get(String.format("https://kvv.imp.fu-berlin.de/direct/calendar/site/%s.json?detailed=true&_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
String body = response.getParsed(); String body = response.getParsed();
if (body == null) { if (body == null) {
errorCallback.onError(new NetworkError(101401, 403, "No events retrieved!")); errorCallback.onError(new NetworkError(101401, 403, "No events retrieved!"));
@@ -81,11 +81,7 @@ public class ModulesEvents extends PartModules<EventList> {
} }
} }
// Empty events *may be* because token is invalid -> check callback.onResponse(events);
if (events.size() == 0)
mLogin.testLoginToken(token -> callback.onResponse(events), errorCallback);
else
callback.onResponse(events);
}, error -> errorCallback.onError(new NetworkError(101403, error.networkResponse.statusCode, "Cannot get events!"))); }, error -> errorCallback.onError(new NetworkError(101403, error.networkResponse.statusCode, "Cannot get events!")));
} }

View File

@@ -16,6 +16,7 @@ import java.util.regex.Matcher;
import androidx.arch.core.util.Function; import androidx.arch.core.util.Function;
import de.sebse.fuplanner.services.kvv.types.CacheBBCourse; import de.sebse.fuplanner.services.kvv.types.CacheBBCourse;
import de.sebse.fuplanner.services.kvv.types.CacheKVVCourse;
import de.sebse.fuplanner.services.kvv.types.Lecturer; import de.sebse.fuplanner.services.kvv.types.Lecturer;
import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.services.kvv.types.Modules;
import de.sebse.fuplanner.services.kvv.types.Semester; import de.sebse.fuplanner.services.kvv.types.Semester;
@@ -35,6 +36,7 @@ public class ModulesList extends HTTPService {
private ModulesListLecturer mLecturer; private ModulesListLecturer mLecturer;
private CacheBBCourse mBBCache; private CacheBBCourse mBBCache;
private final NewAsyncQueue mQueue = new NewAsyncQueue(); private final NewAsyncQueue mQueue = new NewAsyncQueue();
private CacheKVVCourse mKVVCache;
ModulesList(Login login, KVVListener listener, Context context) { ModulesList(Login login, KVVListener listener, Context context) {
super(context); super(context);
@@ -167,73 +169,109 @@ public class ModulesList extends HTTPService {
} }
private void upgradeKVV(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) { private void upgradeKVV(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
NetworkCallback<Modules> successCallback = (modules -> {
try {
cacheKVVCourse().save(getContext());
} catch (IOException e) {
e.printStackTrace();
}
callback.onResponse(modules);
});
if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) { if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null) {
errorCallback.onError(new NetworkError(101110, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101110, 500, "Currently running in offline mode!"));
return; return;
} }
Modules modules = new Modules(mLogin.getLoginTokenKVV().getUsername());
if (!mLogin.getLoginTokenKVV().isAvailable()) { if (!mLogin.getLoginTokenKVV().isAvailable()) {
callback.onResponse(new Modules(mLogin.getLoginTokenKVV().getUsername())); callback.onResponse(modules);
return; return;
} }
get("https://kvv.imp.fu-berlin.de/direct/site.json", mLogin.getLoginTokenKVV().getCookies(), response -> { get("https://kvv.imp.fu-berlin.de/direct/membership.json?_validateSession=", mLogin.getLoginTokenKVV().getCookies(), response -> {
String body = response.getParsed(); String body = response.getParsed();
if (body == null) { if (body == null) {
errorCallback.onError(new NetworkError(101111, 403, "No module list retrieved!")); errorCallback.onError(new NetworkError(101111, 403, "No membership list retrieved!"));
return; return;
} }
Modules modules = new Modules(mLogin.getLoginTokenKVV().getUsername()); JSONArray memberships;
JSONArray sites;
try { try {
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
sites = json.getJSONArray("site_collection"); memberships = json.getJSONArray("membership_collection");
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
errorCallback.onError(new NetworkError(101112, 403, "Cannot parse module list!")); errorCallback.onError(new NetworkError(101112, 403, "Cannot parse membership list!"));
return; return;
} }
for (int i = 0; i < sites.length(); i++) { final int[] latch = {memberships.length()};
for (int i = 0; i < memberships.length(); i++) {
try { try {
JSONObject site = sites.getJSONObject(i); JSONObject membership = memberships.getJSONObject(i);
String semester_string = site.getJSONObject("props").optString("term_eid", null); String locationReference = membership.getString("locationReference");
Semester semester; String courseId = Regex.regex("/site/([0-9a-f-]+)", locationReference);
if (semester_string == null) Modules.Module kvvCourse = cacheKVVCourse().getKVVCourse(courseId);
semester = null; if (kvvCourse != null) {
else kvvCourse = kvvCourse.clone();
semester = new Semester(semester_string); modules.addModule(kvvCourse);
HashSet<String> lvNumbers = new HashSet<>(); if (--latch[0] == 0) successCallback.onResponse(modules);
String kvv_lvnumbers = site.getJSONObject("props").optString("kvv_lvnumbers", null); continue;
if (kvv_lvnumbers != null)
for (MatchResult matchResult : Regex.allMatches("[0-9]+", kvv_lvnumbers)) {
lvNumbers.add(matchResult.group());
}
String title = site.getString("entityTitle");
LinkedHashSet<Lecturer> lecturers = new LinkedHashSet<>();
String kvv_lecturers = site.getJSONObject("props").optString("kvv_lecturers", null);
if (kvv_lecturers != null) for (String lecturer : kvv_lecturers.split("#")) {
if (lecturer.length() > 2)
lecturers.add(new Lecturer(lecturer));
} }
String type = site.getJSONObject("props").optString("kvv_coursetype", "Projekt"); get(String.format("https://kvv.imp.fu-berlin.de/direct/site/%s.json?_validateSession=", courseId), mLogin.getLoginTokenKVV().getCookies(), response1 -> {
String description = site.optString("description", ""); String body1 = response1.getParsed();
description = String.valueOf(PartModules.fromHtml(description)); if (body1 == null) {
String id = site.getString("id"); errorCallback.onError(new NetworkError(101113, 403, "No site retrieved!"));
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id, Modules.TYPE_KVV); return;
}
try {
JSONObject site = new JSONObject(body1);
String semester_string = site.getJSONObject("props").optString("term_eid", null);
Semester semester;
if (semester_string == null)
semester = null;
else
semester = new Semester(semester_string);
HashSet<String> lvNumbers = new HashSet<>();
String kvv_lvnumbers = site.getJSONObject("props").optString("kvv_lvnumbers", null);
if (kvv_lvnumbers != null)
for (MatchResult matchResult : Regex.allMatches("[0-9]+", kvv_lvnumbers)) {
lvNumbers.add(matchResult.group());
}
String title = site.getString("entityTitle");
LinkedHashSet<Lecturer> lecturers = new LinkedHashSet<>();
String kvv_lecturers = site.getJSONObject("props").optString("kvv_lecturers", null);
if (kvv_lecturers != null) for (String lecturer : kvv_lecturers.split("#")) {
if (lecturer.length() > 2)
lecturers.add(new Lecturer(lecturer));
}
String type = site.getJSONObject("props").optString("kvv_coursetype", "Projekt");
String description = site.optString("description", "");
description = String.valueOf(PartModules.fromHtml(description));
String id = site.getString("id");
Modules.Module module = modules.addModule(semester, lvNumbers, title, lecturers, type, description, id, Modules.TYPE_KVV);
cacheKVVCourse().setKVVCourse(courseId, module.clone());
if (--latch[0] == 0) successCallback.onResponse(modules);
} catch (JSONException e) {
log.e(new NetworkError(101114, 403, "Cannot parse site!"));
log.e("JSON:", body1);
e.printStackTrace();
} catch (NoSuchFieldException e) {
log.e(new NetworkError(101115, 403, "Cannot parse site!"));
e.printStackTrace();
}
}, error -> errorCallback.onError(new NetworkError(101116, error.networkResponse.statusCode, "Cannot get membership list!")));
} catch (JSONException e) { } catch (JSONException e) {
log.e(new NetworkError(101113, 403, "Cannot parse module list!")); log.e("ID:", i, "JSON:", memberships);
log.e("ID:", i, "JSON:", sites);
e.printStackTrace(); e.printStackTrace();
errorCallback.onError(new NetworkError(101117, 403, "Cannot parse membership list!"));
return;
} catch (NoSuchFieldException e) { } catch (NoSuchFieldException e) {
log.e(new NetworkError(101114, 403, "Cannot parse module list!")); log.e("ID:", i, "JSON:", memberships);
log.e("ID:", i, "JSON:", sites);
e.printStackTrace(); e.printStackTrace();
errorCallback.onError(new NetworkError(101118, 403, "Cannot parse membership list!"));
return;
} }
} }
// Empty module *may be* because token is invalid -> check }, error -> errorCallback.onError(new NetworkError(101119, error.networkResponse.statusCode, "Cannot get membership list!")));
if (modules.size() == 0)
mLogin.testLoginToken(token -> callback.onResponse(modules), errorCallback);
else
callback.onResponse(modules);
}, error -> errorCallback.onError(new NetworkError(101115, error.networkResponse.statusCode, "Cannot get module list!")));
} }
private void upgradeBB(final Modules modulesKVV, final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) { private void upgradeBB(final Modules modulesKVV, final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
@@ -367,4 +405,19 @@ public class ModulesList extends HTTPService {
mBBCache = new CacheBBCourse(); mBBCache = new CacheBBCourse();
return mBBCache; return mBBCache;
} }
private CacheKVVCourse cacheKVVCourse() {
if (mKVVCache == null) {
try {
mKVVCache = CacheKVVCourse.load(getContext());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
if (mKVVCache == null)
mKVVCache = new CacheKVVCourse();
return mKVVCache;
}
} }

View File

@@ -47,7 +47,7 @@ public class ModulesResources extends PartModules<ArrayList<Resource>> {
errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!"));
return; return;
} }
get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { get(String.format("https://kvv.imp.fu-berlin.de/direct/content/site/%s.json?_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
String body = response.getParsed(); String body = response.getParsed();
if (body == null) { if (body == null) {
errorCallback.onError(new NetworkError(101601, 403, "No resources retrieved!")); errorCallback.onError(new NetworkError(101601, 403, "No resources retrieved!"));
@@ -116,11 +116,7 @@ public class ModulesResources extends PartModules<ArrayList<Resource>> {
} }
} }
// Empty resources *may be* because token is invalid -> check callback.onResponse(root);
if (resources.size() == 0)
mLogin.testLoginToken(token -> callback.onResponse(root), errorCallback);
else
callback.onResponse(root);
}, error -> errorCallback.onError(new NetworkError(101603, error.networkResponse.statusCode, "Cannot get resources!"))); }, error -> errorCallback.onError(new NetworkError(101603, error.networkResponse.statusCode, "Cannot get resources!")));
} }

View File

@@ -68,22 +68,36 @@ public class KVVLogin extends HTTPService {
public void doLogin(String username, String password, NetworkCallback<LoginTokenKVV> callback, NetworkErrorCallback error) { public void doLogin(String username, String password, NetworkCallback<LoginTokenKVV> callback, NetworkErrorCallback error) {
step1(success1 -> { step0(username, success -> {
String samlLocation = success1.get("Location"); step1(success1 -> {
mFULogin.fulogin(samlLocation, username, password, samlResponse -> { String samlLocation = success1.get("Location");
step5(samlResponse, success5 -> { mFULogin.fulogin(samlLocation, username, password, samlResponse -> {
String shibsessionKey = success5.get("shibsessionKey"); step5(samlResponse, success5 -> {
String shibsessionName = success5.get("shibsessionName"); String shibsessionKey = success5.get("shibsessionKey");
step6(shibsessionKey, shibsessionName, success6 -> { String shibsessionName = success5.get("shibsessionName");
String kvvJSESSIONID = success6.get("JSESSIONID"); step6(shibsessionKey, shibsessionName, success6 -> {
LoginTokenKVV token = new LoginTokenKVV(username, kvvJSESSIONID); String kvvJSESSIONID = success6.get("JSESSIONID");
callback.onResponse(token); LoginTokenKVV token = new LoginTokenKVV(username, kvvJSESSIONID);
callback.onResponse(token);
}, error);
}, error); }, error);
}, error); }, error);
}, error); }, error);
}, error); }, error);
} }
private void step0(String username, final NetworkCallback<Boolean> callback, final NetworkErrorCallback errorCallback) {
get(String.format("https://kvv.imp.fu-berlin.de/direct/profile/%s", username), null, result -> {
callback.onResponse(true);
}, error -> {
if (error.networkResponse.statusCode == 500) {
errorCallback.onError(new NetworkError(100101, error.networkResponse.statusCode, "KVV not available!"));
} else {
callback.onResponse(true);
}
});
}
/* /*
1= GET https://kvv.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub 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/idp-fub/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]

View File

@@ -0,0 +1,79 @@
package de.sebse.fuplanner.services.kvv.types;
import android.content.Context;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
public class CacheKVVCourse implements Serializable {
private transient static final long RESAVE_TIMER = 1000L * 60 * 60 * 24 * 30;
private static final String FILE_NAME = "KVVCourseStorageSaving";
private static final String FILE_NAME_TIMESTAMP = "KVVCourseStorageSavingTimestamp";
private transient long mLastTimestamp = 0;
private HashMap<String, Modules.Module> mKVVCourseList = new HashMap<>();
private HashMap<String, Long> mKVVCourseListRefresh = new HashMap<>();
public static CacheKVVCourse load(Context context) throws IOException, ClassNotFoundException {
FileInputStream fis = context.openFileInput(FILE_NAME);
ObjectInputStream is = new ObjectInputStream(fis);
Object readObject = is.readObject();
if (!(readObject instanceof CacheKVVCourse))
return null;
CacheKVVCourse storage = (CacheKVVCourse) readObject;
is.close();
fis.close();
fis = context.openFileInput(FILE_NAME_TIMESTAMP);
is = new ObjectInputStream(fis);
storage.mLastTimestamp = is.readLong();
is.close();
fis.close();
return storage;
}
public boolean isNewerVersionInStorage(Context context) throws IOException {
FileInputStream fis = context.openFileInput(FILE_NAME_TIMESTAMP);
ObjectInputStream is = new ObjectInputStream(fis);
boolean result = this.mLastTimestamp < is.readLong();
is.close();
fis.close();
return result;
}
public void save(Context context) throws IOException {
FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();
fos.close();
fos = context.openFileOutput(FILE_NAME_TIMESTAMP, Context.MODE_PRIVATE);
os = new ObjectOutputStream(fos);
this.mLastTimestamp = System.currentTimeMillis();
os.writeLong(this.mLastTimestamp);
os.close();
fos.close();
}
public void setKVVCourse(String courseID, Modules.Module lecturer) {
mKVVCourseList.put(courseID, lecturer);
mKVVCourseListRefresh.put(courseID, System.currentTimeMillis());
}
public Modules.Module getKVVCourse(String courseID) {
if (!mKVVCourseListRefresh.containsKey(courseID))
return null;
//noinspection ConstantConditions
if (mKVVCourseListRefresh.get(courseID) + RESAVE_TIMER < System.currentTimeMillis())
return null;
return mKVVCourseList.get(courseID);
}
}