From d5d867f4b5f9e29f072800251b323c45ab3a687f Mon Sep 17 00:00:00 2001 From: Sebastian Seedorf Date: Mon, 4 Feb 2019 17:40:25 +0100 Subject: [PATCH] BB Lecturers (not tested) --- .../services/kvv/ModulesAnnouncements.java | 6 +- .../fuplanner/services/kvv/ModulesList.java | 28 +++- .../services/kvv/ModulesListLecturer.java | 141 ++++++++++++++++++ .../services/kvv/types/Lecturer.java | 7 + .../services/kvv/types/LecturerStorage.java | 95 ++++++++++++ build.gradle | 10 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 7 files changed, 272 insertions(+), 17 deletions(-) create mode 100644 app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesListLecturer.java create mode 100644 app/src/main/java/de/sebse/fuplanner/services/kvv/types/LecturerStorage.java diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java index 0c00d14..5304195 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java @@ -133,11 +133,7 @@ public class ModulesAnnouncements extends PartModules> { } } - // Empty announcements *may be* because token is invalid -> check - if (announcements.size() == 0) - mLogin.testLoginToken(token -> callback.onResponse(announcements), errorCallback); - else - callback.onResponse(announcements); + callback.onResponse(announcements); }, error -> errorCallback.onError(new NetworkError(101213, error.networkResponse.statusCode, "Cannot get announcements!"))); } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java index 15681f4..d46347a 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java @@ -31,6 +31,7 @@ public class ModulesList extends HTTPService { private final Login mLogin; private final KVVListener mListener; @Nullable private Modules mModules; + private ModulesListLecturer mLecturer; private final NewAsyncQueue mQueue = new NewAsyncQueue(); ModulesList(Login login, KVVListener listener, Context context) { @@ -206,7 +207,7 @@ public class ModulesList extends HTTPService { if (lecturer.length() > 2) lecturers.add(new Lecturer(lecturer)); } - String type = site.getJSONObject("props").optString("kvv_coursetype", null); + 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"); @@ -286,13 +287,19 @@ public class ModulesList extends HTTPService { } } } catch (NoSuchFieldException e) { - type = "Project"; + type = "Projekt"; } - if (!found) - modulesKVV.addModule(semester, lvNumberSet, name, new LinkedHashSet<>(), type, "", courseId, Modules.TYPE_BB); - latch[0]--; - if (latch[0] == 0) - callback.onResponse(modulesKVV); + if (!found) { + Semester finalSemester = semester; + String finalType = type; + lecturer().getBBLecturers(courseId, success -> { + modulesKVV.addModule(finalSemester, lvNumberSet, name, success, finalType, "", courseId, Modules.TYPE_BB); + if (--latch[0] == 0) callback.onResponse(modulesKVV); + }, error -> { + log.e(error); + if (--latch[0] == 0) callback.onResponse(modulesKVV); + }); + } else if (--latch[0] == 0) callback.onResponse(modulesKVV); } catch (JSONException e) { e.printStackTrace(); errorCallback.onError(new NetworkError(101125, 403, "Cannot parse module list!")); @@ -305,6 +312,13 @@ public class ModulesList extends HTTPService { } } }, error -> errorCallback.onError(new NetworkError(101125, error.networkResponse.statusCode, "Cannot get module list!"))); + } + + + private ModulesListLecturer lecturer() { + if (mLecturer == null) + mLecturer = new ModulesListLecturer(getContext(), mLogin); + return mLecturer; } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesListLecturer.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesListLecturer.java new file mode 100644 index 0000000..7882532 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesListLecturer.java @@ -0,0 +1,141 @@ +package de.sebse.fuplanner.services.kvv; + +import android.content.Context; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashSet; + +import de.sebse.fuplanner.services.kvv.types.Lecturer; +import de.sebse.fuplanner.services.kvv.types.LecturerStorage; +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; + +class ModulesListLecturer extends HTTPService { + private final Login mLogin; + private final LecturerStorage mStorage; + + public ModulesListLecturer(Context context, Login login) { + super(context); + this.mLogin = login; + LecturerStorage storage = null; + try { + storage = LecturerStorage.load(context); + } catch (IOException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + if (storage == null) { + mStorage = new LecturerStorage(); + } else { + mStorage = storage; + } + } + + public void getBBLecturers(String moduleID, NetworkCallback> callback, NetworkErrorCallback errorCallback) { + ArrayList lecturerString = mStorage.getLecturersPerCourse(moduleID); + if (lecturerString != null) { + final int[] latch = {lecturerString.size()}; + LinkedHashSet lecturers = new LinkedHashSet<>(); + for (String userId : lecturerString) { + getBBLecturer(userId, success -> { + lecturers.add(success); + if (--latch[0] == 0) callback.onResponse(lecturers); + }, error -> { + log.e(error); + if (--latch[0] == 0) callback.onResponse(lecturers); + }); + } + return; + } + + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) { + errorCallback.onError(new NetworkError(102100, 500, "Currently running in offline mode!")); + return; + } + + get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/courses/%s/users?fields=userId,courseRoleId", moduleID), mLogin.getLoginTokenBB().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(102101, 403, "No lecturers retrieved!")); + return; + } + LinkedHashSet lecturers = new LinkedHashSet<>(); + JSONArray sites; + try { + JSONObject json = new JSONObject(body); + sites = json.getJSONArray("results"); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(102102, 403, "Cannot parse lecturers!")); + return; + } + + final int[] latch = {sites.length()}; + for (int i = 0; i < sites.length(); i++) { + try { + JSONObject lecturerJson = sites.getJSONObject(i); + String userId = lecturerJson.getString("userId"); + String role = lecturerJson.getString("courseRoleId"); + ArrayList lecturerString2 = new ArrayList<>(); + if (!"Student".equals(role)) { + lecturerString2.add(userId); + getBBLecturer(userId, success -> { + lecturers.add(success); + if (--latch[0] == 0) callback.onResponse(lecturers); + }, error -> { + log.e(error); + if (--latch[0] == 0) callback.onResponse(lecturers); + }); + } else { + if (--latch[0] == 0) callback.onResponse(lecturers); + } + mStorage.setLecturersPerCourse(moduleID, lecturerString2); + mStorage.save(getContext()); + } catch (JSONException e) { + log.e(new NetworkError(102103, 403, "Cannot parse lecturers!")); + log.e("ID:", i, "JSON:", sites); + e.printStackTrace(); + if (--latch[0] == 0) callback.onResponse(lecturers); + } catch (IOException e) { + log.e("Saving LecturerStorage failed!"); + e.printStackTrace(); + } + } + callback.onResponse(lecturers); + }, error -> errorCallback.onError(new NetworkError(102104, error.networkResponse.statusCode, "Error retrieving lecturers!"))); + } + + public void getBBLecturer(String lecturerID, NetworkCallback callback, NetworkErrorCallback errorCallback) { + if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) { + errorCallback.onError(new NetworkError(102110, 500, "Currently running in offline mode!")); + return; + } + get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/%s?fields=userName,name", lecturerID), mLogin.getLoginTokenBB().getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + errorCallback.onError(new NetworkError(102111, 403, "No lecturer retrieved!")); + return; + } + try { + JSONObject json = new JSONObject(body); + String userName = json.getString("userName"); + String givenName = json.getJSONObject("name").getString("given"); + String familyName = json.getJSONObject("name").getString("family"); + Lecturer lecturer = new Lecturer(givenName, familyName, userName + "@zedat.fu-berlin.de", true); + callback.onResponse(lecturer); + } catch (JSONException e) { + e.printStackTrace(); + errorCallback.onError(new NetworkError(102112, 403, "Cannot parse lecturer!")); + return; + } + }, error -> errorCallback.onError(new NetworkError(102113, error.networkResponse.statusCode, "Error retrieving lecturer!"))); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Lecturer.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Lecturer.java index 48842c5..9e8bb42 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Lecturer.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/Lecturer.java @@ -12,6 +12,13 @@ public class Lecturer implements Serializable { private final String mail; private final boolean isResponsible; + public Lecturer(String firstName, String surname, String mail, boolean isResponsible) { + this.firstName = firstName; + this.surname = surname; + this.mail = mail; + this.isResponsible = isResponsible; + } + public Lecturer(String parsableString) throws NoSuchFieldException { Pattern pattern = Pattern.compile("([^|]*)\\|([^|]*)\\|([^|]*)\\|\\|([^|]*)", Pattern.DOTALL); Matcher matcher = pattern.matcher(parsableString); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LecturerStorage.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LecturerStorage.java new file mode 100644 index 0000000..08e9be3 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LecturerStorage.java @@ -0,0 +1,95 @@ +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.ArrayList; +import java.util.HashMap; + +public class LecturerStorage implements Serializable { + private static final long RESAVE_TIMER = 1000L * 60 * 60 * 24 * 30; + private static final String FILE_NAME = "LecturerStorageSaving"; + private static final String FILE_NAME_TIMESTAMP = "LecturerStorageSavingTimestamp"; + private transient long mLastTimestamp = 0; + + private HashMap> mLecturersPerCourse = new HashMap<>(); + private HashMap mLecturersPerCourseRefresh = new HashMap<>(); + private HashMap mLecturers = new HashMap<>(); + private HashMap mLecturersRefresh = new HashMap<>(); + + public static LecturerStorage load(Context context) throws IOException, ClassNotFoundException { + FileInputStream fis = context.openFileInput(FILE_NAME); + ObjectInputStream is = new ObjectInputStream(fis); + Object readObject = is.readObject(); + if (!(readObject instanceof LecturerStorage)) + return null; + LecturerStorage storage = (LecturerStorage) 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 setLecturersPerCourse(String courseID, ArrayList lecturers) { + mLecturersPerCourse.put(courseID, lecturers); + mLecturersPerCourseRefresh.put(courseID, System.currentTimeMillis()); + } + + public void setLecturer(String lecturerID, Lecturer lecturer) { + mLecturers.put(lecturerID, lecturer); + mLecturersRefresh.put(lecturerID, System.currentTimeMillis()); + } + + public ArrayList getLecturersPerCourse(String courseID) { + if (!mLecturersPerCourseRefresh.containsKey(courseID)) + return null; + //noinspection ConstantConditions + if (mLecturersPerCourseRefresh.get(courseID) + RESAVE_TIMER < System.currentTimeMillis()) + return null; + return mLecturersPerCourse.get(courseID); + } + + public Lecturer getLecturer(String lecturerID) { + if (!mLecturersRefresh.containsKey(lecturerID)) + return null; + //noinspection ConstantConditions + if (mLecturersRefresh.get(lecturerID) + RESAVE_TIMER < System.currentTimeMillis()) + return null; + return mLecturers.get(lecturerID); + } +} diff --git a/build.gradle b/build.gradle index 72a43de..ecec744 100644 --- a/build.gradle +++ b/build.gradle @@ -2,11 +2,12 @@ buildscript { repositories { - google() + /*google() jcenter() maven { url "https://jitpack.io" - } + }*/ + mavenLocal() } dependencies { classpath 'com.android.tools.build:gradle:3.3.0' @@ -18,11 +19,12 @@ buildscript { allprojects { repositories { - google() + /*google() jcenter() maven { url "https://jitpack.io" - } + }*/ + mavenLocal() } gradle.projectsEvaluated { diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f13d1ff..68c34b2 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,4 +1,4 @@ -#Wed Jan 16 22:29:38 CET 2019 +#Tue Oct 16 18:11:34 CEST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME