Bug fixing, JSON parsing more robust

This commit is contained in:
Caesar2011
2018-11-09 01:17:59 +01:00
parent 518ae756b1
commit 0439c845a5
9 changed files with 103 additions and 84 deletions

View File

@@ -7,8 +7,8 @@ android {
applicationId "de.sebse.fuplanner" applicationId "de.sebse.fuplanner"
minSdkVersion 15 minSdkVersion 15
targetSdkVersion 28 targetSdkVersion 28
versionCode 9 versionCode 10
versionName "1.2.1" versionName "1.2.2"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
@@ -32,7 +32,6 @@ dependencies {
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0-beta02', { androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0-beta02', {
exclude group: 'com.android.support', module: 'support-annotations' exclude group: 'com.android.support', module: 'support-annotations'
}) })
implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'androidx.preference:preference:1.0.0' implementation 'androidx.preference:preference:1.0.0'
implementation 'com.google.android.material:material:1.0.0' implementation 'com.google.android.material:material:1.0.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2' implementation 'androidx.constraintlayout:constraintlayout:2.0.0-alpha2'
@@ -42,7 +41,7 @@ dependencies {
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.0.0' implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2' implementation 'org.jbundle.util.osgi.wrapped:org.jbundle.util.osgi.wrapped.org.apache.http.client:4.1.2'
implementation 'androidx.legacy:legacy-support-v4:1.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'org.jetbrains:annotations-java5:15.0' implementation 'org.jetbrains:annotations-java5:15.0'

View File

@@ -231,6 +231,7 @@ class ModDetailOverviewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHol
mText = view.findViewById(R.id.expand_text_view);//.findViewById(R.id.description); mText = view.findViewById(R.id.expand_text_view);//.findViewById(R.id.description);
} }
@NonNull
@Override @Override
public String toString() { public String toString() {
return super.toString() + " '" + mText.getText() + "'"; return super.toString() + " '" + mText.getText() + "'";

View File

@@ -34,22 +34,29 @@ public class KVVModulesAnnouncements extends ModulesPart<ArrayList<Announcement>
@Override @Override
protected void upgrade(final String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) { protected void upgrade(final String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) {
if (!login.isInOnlineMode() || login.getLoginToken() == null) { if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
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), login.getLoginToken().getCookies(), response -> { super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginToken().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!"));
return; return;
} }
ArrayList<Announcement> announcements = new ArrayList<>(); ArrayList<Announcement> announcements = new ArrayList<>();
JSONArray sites;
try { try {
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
JSONArray sites = json.getJSONArray("announcement_collection"); sites = json.getJSONArray("announcement_collection");
} catch (JSONException e) {
e.printStackTrace();
errorCallback.onError(new NetworkError(101202, 403, "Cannot parse announcements!"));
return;
}
for (int i = 0; i < sites.length(); i++) { for (int i = 0; i < sites.length(); i++) {
try {
JSONObject site = sites.getJSONObject(i); JSONObject site = sites.getJSONObject(i);
String id = site.getString("announcementId"); String id = site.getString("announcementId");
String title = site.getString("title"); String title = site.getString("title");
@@ -61,21 +68,21 @@ public class KVVModulesAnnouncements extends ModulesPart<ArrayList<Announcement>
// Extract attachment links // Extract attachment links
JSONArray attachments = site.getJSONArray("attachments"); JSONArray attachments = site.getJSONArray("attachments");
ArrayList<String> urls = new ArrayList<>(); ArrayList<String> urls = new ArrayList<>();
for (int j =0; j<attachments.length(); j++){ for (int j = 0; j < attachments.length(); j++) {
urls.add(attachments.getJSONObject(j).optString("url",null)); urls.add(attachments.getJSONObject(j).optString("url", null));
} }
announcements.add(new Announcement(id, title, text, createdBy, createdOn, urls)); announcements.add(new Announcement(id, title, text, createdBy, createdOn, urls));
} catch (JSONException e) {
log.e(new NetworkError(101205, 403, "Cannot parse announcements!"));
e.printStackTrace();
return;
} }
} catch (JSONException e) {
e.printStackTrace();
errorCallback.onError(new NetworkError(101202, 403, "Cannot parse announcements!"));
return;
} }
// Empty announcements *may be* because token is invalid -> check // Empty announcements *may be* because token is invalid -> check
if (announcements.size() == 0) if (announcements.size() == 0)
login.testLoginToken(token -> callback.onResponse(announcements), errorCallback); mLogin.testLoginToken(token -> callback.onResponse(announcements), errorCallback);
else else
callback.onResponse(announcements); 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

@@ -35,22 +35,29 @@ public class KVVModulesAssignments extends ModulesPart<AssignmentList> {
@Override @Override
protected void upgrade(final String ID, final NetworkCallback<AssignmentList> callback, final NetworkErrorCallback errorCallback) { protected void upgrade(final String ID, final NetworkCallback<AssignmentList> callback, final NetworkErrorCallback errorCallback) {
if (!login.isInOnlineMode() || login.getLoginToken() == null) { if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
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), login.getLoginToken().getCookies(), response ->{ get(String.format("https://kvv.imp.fu-berlin.de/direct/assignment/site/%s.json", ID), mLogin.getLoginToken().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!"));
return; return;
} }
AssignmentList assignments = new AssignmentList(); AssignmentList assignments = new AssignmentList();
JSONArray sites;
try { try {
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
JSONArray sites = json.getJSONArray("assignment_collection"); sites = json.getJSONArray("assignment_collection");
} catch (JSONException e) {
e.printStackTrace();
errorCallback.onError(new NetworkError(101302, 403, "Cannot parse assignments!"));
return;
}
for (int i = 0; i < sites.length(); i++) { for (int i = 0; i < sites.length(); i++) {
try {
JSONObject site = sites.getJSONObject(i); JSONObject site = sites.getJSONObject(i);
String id = site.getString("id"); String id = site.getString("id");
String title = site.getString("title"); String title = site.getString("title");
@@ -61,19 +68,20 @@ public class KVVModulesAssignments extends ModulesPart<AssignmentList> {
String gradeScale = site.getString("gradeScale"); String gradeScale = site.getString("gradeScale");
JSONArray attachments = site.getJSONArray("attachments"); JSONArray attachments = site.getJSONArray("attachments");
ArrayList<String> urls = new ArrayList<>(); ArrayList<String> urls = new ArrayList<>();
for (int j = 0; j<attachments.length(); j++){ for (int j = 0; j < attachments.length(); j++) {
urls.add(attachments.getJSONObject(j).getString("url")); urls.add(attachments.getJSONObject(j).getString("url"));
} }
assignments.add(0, new Assignment(id, title, dueTime, gradebookItemName, gradeScale, urls, instructions)); assignments.add(0, new Assignment(id, title, dueTime, gradebookItemName, gradeScale, urls, instructions));
} catch (JSONException e) {
log.e(new NetworkError(101305, 403, "Cannot parse assignments!"));
e.printStackTrace();
return;
} }
} catch (JSONException e) {
e.printStackTrace();
errorCallback.onError(new NetworkError(101302, 403, "Cannot parse announcements!"));
return;
} }
// Empty assignments *may be* because token is invalid -> check // Empty assignments *may be* because token is invalid -> check
if (assignments.size() == 0) if (assignments.size() == 0)
login.testLoginToken(token -> callback.onResponse(assignments), errorCallback); mLogin.testLoginToken(token -> callback.onResponse(assignments), errorCallback);
else else
callback.onResponse(assignments); callback.onResponse(assignments);
}, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get announcements!"))); }, error -> errorCallback.onError(new NetworkError(101303, error.networkResponse.statusCode, "Cannot get announcements!")));

View File

@@ -136,11 +136,10 @@ public class KVVModulesList extends HTTPService {
} }
private void upgrade(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) { private void upgrade(final NetworkCallback<Modules> callback, final NetworkErrorCallback errorCallback) {
if (!mLogin.isInOnlineMode()) { if (!mLogin.isInOnlineMode() || mLogin.getLoginToken() == null) {
errorCallback.onError(new NetworkError(101105, 500, "Currently running in offline mode!")); errorCallback.onError(new NetworkError(101105, 500, "Currently running in offline mode!"));
return; return;
} }
// https://file.io/71sa2V
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.getLoginToken().getCookies(), response -> {
String body = response.getParsed(); String body = response.getParsed();
if (body == null) { if (body == null) {
@@ -148,37 +147,43 @@ public class KVVModulesList extends HTTPService {
return; return;
} }
Modules modules = new Modules(mLogin.getLoginToken().getUsername()); Modules modules = new Modules(mLogin.getLoginToken().getUsername());
JSONArray sites;
try { try {
JSONObject json = new JSONObject(body); JSONObject json = new JSONObject(body);
JSONArray sites = json.getJSONArray("site_collection"); sites = json.getJSONArray("site_collection");
for (int i = 0; i < sites.length(); i++) {
JSONObject site = sites.getJSONObject(i);
String semester = site.getJSONObject("props").getString("term_eid");
HashSet<String> lvNumbers = new HashSet<>();
for (MatchResult matchResult : Regex.allMatches("[0-9]+", site.getJSONObject("props").getString("kvv_lvnumbers"))) {
lvNumbers.add(matchResult.group());
}
String title = site.getString("entityTitle");
HashSet<Lecturer> lecturers = new HashSet<>();
for (String lecturer : site.getJSONObject("props").getString("kvv_lecturers").split("#")) {
if (lecturer.length() > 2)
lecturers.add(new Lecturer(lecturer));
}
String type = site.getJSONObject("props").getString("kvv_coursetype");
String description = site.getString("description");
description = String.valueOf(ModulesPart.fromHtml(description));
String id = site.getString("id");
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id);
}
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!")); errorCallback.onError(new NetworkError(101102, 403, "Cannot parse module list!"));
return; return;
} catch (NoSuchFieldException e) { }
e.printStackTrace(); for (int i = 0; i < sites.length(); i++) {
errorCallback.onError(new NetworkError(101103, 403, "Cannot parse module list!")); try {
return; JSONObject site = sites.getJSONObject(i);
String semester = site.getJSONObject("props").optString("term_eid", null);
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");
HashSet<Lecturer> lecturers = new HashSet<>();
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", null);
String description = site.optString("description", "");
description = String.valueOf(ModulesPart.fromHtml(description));
String id = site.getString("id");
modules.addModule(semester, lvNumbers, title, lecturers, type, description, id);
} catch (JSONException e) {
log.e(new NetworkError(101103, 403, "Cannot parse module list!"));
e.printStackTrace();
} catch (NoSuchFieldException e) {
log.e(new NetworkError(101106, 403, "Cannot parse module list!"));
e.printStackTrace();
}
} }
// Empty module *may be* because token is invalid -> check // Empty module *may be* because token is invalid -> check
if (modules.size() == 0) if (modules.size() == 0)

View File

@@ -11,7 +11,7 @@ import de.sebse.fuplanner.tools.network.NetworkCallback;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback; import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
abstract class ModulesPart<T> extends Part<Modules.Module> { abstract class ModulesPart<T> extends Part<Modules.Module> {
private NewAsyncQueue queue = new NewAsyncQueue(); private NewAsyncQueue mQueue = new NewAsyncQueue();
ModulesPart(KVVLogin login, KVVModulesList list, Context context) { ModulesPart(KVVLogin login, KVVModulesList list, Context context) {
super(login, list, context); super(login, list, context);
@@ -19,28 +19,28 @@ abstract class ModulesPart<T> extends Part<Modules.Module> {
@Override @Override
protected void recv(final Modules.Module module, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh, final int retries) { protected void recv(final Modules.Module module, final NetworkCallback<Modules.Module> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh, final int retries) {
queue.add(() -> { mQueue.add(() -> {
if (getPart(module) != null && !forceRefresh) { if (getPart(module) != null && !forceRefresh) {
callback.onResponse(module); callback.onResponse(module);
queue.next(); mQueue.next();
return; return;
} }
upgrade(module.getID(), success -> { upgrade(module.getID(), success -> {
if (setPart(module, success)) { if (setPart(module, success)) {
this.list.store(); this.mList.store();
} }
callback.onResponse(module); callback.onResponse(module);
queue.next(); mQueue.next();
}, error -> { }, error -> {
if (retries >= 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) { if (retries >= 0 && (error.getHttpStatus() == 401 || error.getHttpStatus() == 403)) {
login.refreshLogin(success -> { mLogin.refreshLogin(success -> {
recv(module, callback, errorCallback, forceRefresh, retries-1); recv(module, callback, errorCallback, forceRefresh, retries-1);
queue.next(); mQueue.next();
}, errorCallback); }, errorCallback);
return; return;
} }
errorCallback.onError(error); errorCallback.onError(error);
queue.next(); mQueue.next();
}); });
}); });
} }

View File

@@ -3,20 +3,19 @@ package de.sebse.fuplanner.services.NewKVV;
import android.content.Context; import android.content.Context;
import de.sebse.fuplanner.services.NewKVV.types.Modules; import de.sebse.fuplanner.services.NewKVV.types.Modules;
import de.sebse.fuplanner.tools.NewAsyncQueue;
import de.sebse.fuplanner.tools.network.HTTPService; import de.sebse.fuplanner.tools.network.HTTPService;
import de.sebse.fuplanner.tools.network.NetworkCallback; import de.sebse.fuplanner.tools.network.NetworkCallback;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback; import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
public abstract class Part<T> extends HTTPService { public abstract class Part<T> extends HTTPService {
static final int RETRY_COUNT = 1; static final int RETRY_COUNT = 1;
protected final KVVLogin login; protected final KVVLogin mLogin;
protected final KVVModulesList list; protected final KVVModulesList mList;
Part(KVVLogin login, KVVModulesList list, Context context) { Part(KVVLogin login, KVVModulesList list, Context context) {
super(context); super(context);
this.login = login; this.mLogin = login;
this.list = list; this.mList = list;
} }
public void recv(final String moduleID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback) { public void recv(final String moduleID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback) {
@@ -24,7 +23,7 @@ public abstract class Part<T> extends HTTPService {
} }
public void recv(final String moduleID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh) { public void recv(final String moduleID, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh) {
list.find(moduleID, success -> recv(success, callback, errorCallback, forceRefresh, RETRY_COUNT), errorCallback); mList.find(moduleID, success -> recv(success, callback, errorCallback, forceRefresh, RETRY_COUNT), errorCallback);
} }
abstract protected void recv(final Modules.Module module, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh, final int retries); abstract protected void recv(final Modules.Module module, final NetworkCallback<T> callback, final NetworkErrorCallback errorCallback, final boolean forceRefresh, final int retries);

View File

@@ -2,6 +2,8 @@ package de.sebse.fuplanner.services.NewKVV.types;
import android.content.Context; import android.content.Context;
import org.jetbrains.annotations.NotNull;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
@@ -30,7 +32,7 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
this.list = new SortedListModule(); this.list = new SortedListModule();
} }
public void addModule(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String description, String ID) { public void addModule(@Nullable String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String description, String ID) {
Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID); Module m = new Module(semester, lvNumber, title, lecturer, type, description, ID);
this.list.add(m); this.list.add(m);
} }
@@ -104,24 +106,19 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
} }
public class Module implements Serializable { public class Module implements Serializable {
public final String semester; @Nullable public final String semester;
final HashSet<String> lvNumber; @NotNull final HashSet<String> lvNumber;
public final String title; @NotNull public final String title;
final HashSet<Lecturer> lecturer; @NotNull final HashSet<Lecturer> lecturer;
public final String type; @Nullable public final String type;
public final String description; @Nullable public final String description;
private final String ID; @NotNull private final String ID;
@Nullable public ArrayList<Announcement> announcements; @Nullable public ArrayList<Announcement> announcements;
@Nullable public AssignmentList assignments; @Nullable public AssignmentList assignments;
@Nullable public EventList events; @Nullable public EventList events;
@Nullable public ArrayList<Gradebook> gradebook; @Nullable public ArrayList<Gradebook> gradebook;
@Nullable public ArrayList<Resource> resources; @Nullable public ArrayList<Resource> resources;
/*private Module() {
this(null, null, null, null, null);
throw new AssertionError("Do not use this constructor!");
}*/
public float getGradebookPercent(){ public float getGradebookPercent(){
float maxPoint = 0; float maxPoint = 0;
float userPoint = 0; float userPoint = 0;
@@ -136,9 +133,11 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
return userPoint/maxPoint; return userPoint/maxPoint;
} }
private Module(String semester, HashSet<String> lvNumber, String title, HashSet<Lecturer> lecturer, String type, String description, String ID) { private Module(@Nullable String semester, @NotNull HashSet<String> lvNumber, @NotNull String title, @NotNull HashSet<Lecturer> lecturer, @Nullable String type, @Nullable String description, @NotNull String ID) {
semester = semester.replace("SS", "S"); if (semester != null) {
semester = semester.replaceAll("[0-9]{2}([0-9]{2})", "$1"); semester = semester.replace("SS", "S");
semester = semester.replaceAll("[0-9]{2}([0-9]{2})", "$1");
}
title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1"); title = title.replaceAll("(.*?) (S[0-9]{2}|W[0-9/]{5})", "$1");
this.semester = semester; this.semester = semester;
@@ -150,6 +149,7 @@ public class Modules implements Iterable<Modules.Module>, Serializable {
this.ID = ID; this.ID = ID;
} }
@NonNull
public String getID() { public String getID() {
return ID; return ID;
} }

View File

@@ -63,6 +63,6 @@ public class SortedListModule extends SortedList<Modules.Module, String, String>
@Override @Override
public boolean hasFilter(Modules.Module o1, String filter) { public boolean hasFilter(Modules.Module o1, String filter) {
return o1.semester.equals(filter); return o1.semester != null && o1.semester.equals(filter);
} }
} }