Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/stefan-niedermann/nextcloud-notes.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2021-04-28 12:25:24 +0300
committerStefan Niedermann <info@niedermann.it>2021-04-28 12:25:24 +0300
commit1c3b9a0d629901d2d1c47000dae11347b06c57c9 (patch)
treec88848039af050cf423c00e1af13ef95f85c7a95
parent403cdecc8650af44ddec8b627826588e9c229142 (diff)
#1167 Use retrofit also for capabilities endpoint
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java81
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClient.java217
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV02.java63
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV1.java64
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/SSOClient.java21
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/Account.java4
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ApiProvider.java7
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/CapabilitiesDeserializer.java81
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NextcloudAPI.java33
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/OcsAPI.java16
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java5
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/shared/model/Capabilities.java32
-rw-r--r--app/src/main/java/it/niedermann/owncloud/notes/shared/model/ServerResponse.java103
-rw-r--r--app/src/test/java/it/niedermann/owncloud/notes/shared/model/CapabilitiesTest.java8
14 files changed, 174 insertions, 561 deletions
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java
index 9a08bc1e..b053227e 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/CapabilitiesClient.java
@@ -1,87 +1,38 @@
package it.niedermann.owncloud.notes.persistence;
import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
-import com.nextcloud.android.sso.aidl.NextcloudRequest;
-import com.nextcloud.android.sso.api.AidlNetworkRequest;
-import com.nextcloud.android.sso.api.Response;
-import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException;
+import com.google.gson.JsonParseException;
+import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.io.IOException;
+import it.niedermann.owncloud.notes.persistence.sync.ApiProvider;
import it.niedermann.owncloud.notes.shared.model.Capabilities;
+import retrofit2.Response;
+
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
@WorkerThread
public class CapabilitiesClient {
- private static final String TAG = CapabilitiesClient.class.getSimpleName();
-
- private static final int MIN_NEXTCLOUD_FILES_APP_VERSION_CODE = 30090000;
-
- protected static final String HEADER_KEY_IF_NONE_MATCH = "If-None-Match";
protected static final String HEADER_KEY_ETAG = "ETag";
- private static final String API_PATH = "/ocs/v2.php/cloud/capabilities";
- private static final String METHOD_GET = "GET";
- private static final String PARAM_KEY_FORMAT = "format";
- private static final String PARAM_VALUE_JSON = "json";
-
- private static final Map<String, String> parameters = new HashMap<>();
-
- static {
- parameters.put(PARAM_KEY_FORMAT, PARAM_VALUE_JSON);
- }
-
- public static Capabilities getCapabilities(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable String lastETag) throws Exception {
- final NextcloudRequest.Builder requestBuilder = new NextcloudRequest.Builder()
- .setMethod(METHOD_GET)
- .setUrl(API_PATH)
- .setParameter(parameters);
-
- final Map<String, List<String>> header = new HashMap<>();
- if (lastETag != null && !lastETag.isEmpty()) {
- header.put(HEADER_KEY_IF_NONE_MATCH, Collections.singletonList('"' + lastETag + '"'));
- requestBuilder.setHeader(header);
- }
-
- final NextcloudRequest nextcloudRequest = requestBuilder.build();
- final StringBuilder result = new StringBuilder();
-
+ public static Capabilities getCapabilities(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @Nullable String lastETag) throws NextcloudHttpRequestFailedException, IOException {
+ final ApiProvider provider = new ApiProvider(context, ssoAccount);
+ final Response<Capabilities> response = provider.getOcsAPI().getCapabilities(lastETag).execute();
try {
- Log.v(TAG, ssoAccount.name + " → " + nextcloudRequest.getMethod() + " " + nextcloudRequest.getUrl() + " ");
- final Response response = SSOClient.requestFilesApp(context.getApplicationContext(), ssoAccount, nextcloudRequest);
- Log.v(TAG, "NextcloudRequest: " + nextcloudRequest.toString());
-
- final BufferedReader rd = new BufferedReader(new InputStreamReader(response.getBody()));
- String line;
- while ((line = rd.readLine()) != null) {
- result.append(line);
- }
- response.getBody().close();
-
- String etag = null;
- final AidlNetworkRequest.PlainHeader eTagHeader = response.getPlainHeader(HEADER_KEY_ETAG);
- if (eTagHeader != null) {
- etag = eTagHeader.getValue().replace("\"", "");
- }
-
- return new Capabilities(result.toString(), etag);
- } catch (NullPointerException e) {
- final PackageInfo pInfo = context.getApplicationContext().getPackageManager().getPackageInfo("com.nextcloud.client", 0);
- if (pInfo.versionCode < MIN_NEXTCLOUD_FILES_APP_VERSION_CODE) {
- throw new NextcloudFilesAppNotSupportedException();
+ final Capabilities capabilities = response.body();
+ capabilities.setETag(response.headers().get(HEADER_KEY_ETAG));
+ return capabilities;
+ } catch (JsonParseException e) {
+ if (e.getCause() instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) e.getCause()).getStatusCode() == HTTP_UNAVAILABLE) {
+ throw (NextcloudHttpRequestFailedException) e.getCause();
} else {
throw e;
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClient.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClient.java
deleted file mode 100644
index f5a8f189..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClient.java
+++ /dev/null
@@ -1,217 +0,0 @@
-package it.niedermann.owncloud.notes.persistence;
-
-import android.content.Context;
-import android.content.pm.PackageInfo;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.WorkerThread;
-
-import com.nextcloud.android.sso.aidl.NextcloudRequest;
-import com.nextcloud.android.sso.api.AidlNetworkRequest;
-import com.nextcloud.android.sso.api.Response;
-import com.nextcloud.android.sso.exceptions.NextcloudFilesAppNotSupportedException;
-import com.nextcloud.android.sso.model.SingleSignOnAccount;
-
-import org.json.JSONObject;
-
-import java.io.BufferedReader;
-import java.io.InputStreamReader;
-import java.util.Calendar;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-
-import it.niedermann.owncloud.notes.persistence.entity.Note;
-import it.niedermann.owncloud.notes.shared.model.ApiVersion;
-import it.niedermann.owncloud.notes.shared.model.ServerResponse.NoteResponse;
-import it.niedermann.owncloud.notes.shared.model.ServerResponse.NotesResponse;
-
-@SuppressWarnings("WeakerAccess")
-@WorkerThread
-public abstract class NotesClient {
-
- final static int MIN_NEXTCLOUD_FILES_APP_VERSION_CODE = 30090000;
- private static final String TAG = NotesClient.class.getSimpleName();
-
- protected final Context appContext;
-
- protected static final String GET_PARAM_KEY_PRUNE_BEFORE = "pruneBefore";
-
- protected static final String HEADER_KEY_ETAG = "ETag";
- protected static final String HEADER_KEY_LAST_MODIFIED = "Last-Modified";
- protected static final String HEADER_KEY_CONTENT_TYPE = "Content-Type";
- protected static final String HEADER_KEY_IF_NONE_MATCH = "If-None-Match";
- protected static final String HEADER_KEY_X_NOTES_API_VERSIONS = "X-Notes-API-Versions";
-
- protected static final String HEADER_VALUE_APPLICATION_JSON = "application/json";
-
- protected static final String METHOD_GET = "GET";
- protected static final String METHOD_PUT = "PUT";
- protected static final String METHOD_POST = "POST";
- protected static final String METHOD_DELETE = "DELETE";
-
- public static final String JSON_ID = "id";
- public static final String JSON_TITLE = "title";
- public static final String JSON_CONTENT = "content";
- public static final String JSON_FAVORITE = "favorite";
- public static final String JSON_CATEGORY = "category";
- public static final String JSON_ETAG = "etag";
- public static final String JSON_MODIFIED = "modified";
-
- public static final ApiVersion[] SUPPORTED_API_VERSIONS = new ApiVersion[]{
- new ApiVersion(1, 0),
- new ApiVersion(0, 2)
- };
-
- public static NotesClient newInstance(@Nullable ApiVersion preferredApiVersion,
- @NonNull Context appContext) {
- if (preferredApiVersion == null) {
- Log.i(TAG, "apiVersion is null, using " + NotesClientV02.class.getSimpleName());
- return new NotesClientV02(appContext);
- } else if (preferredApiVersion.compareTo(SUPPORTED_API_VERSIONS[0]) == 0) {
- Log.i(TAG, "Using " + NotesClientV1.class.getSimpleName());
- return new NotesClientV1(appContext);
- } else if (preferredApiVersion.compareTo(SUPPORTED_API_VERSIONS[1]) == 0) {
- Log.i(TAG, "Using " + NotesClientV02.class.getSimpleName());
- return new NotesClientV02(appContext);
- }
- Log.w(TAG, "Unsupported API version " + preferredApiVersion + " - try using " + NotesClientV02.class.getSimpleName());
- return new NotesClientV02(appContext);
- }
-
- @SuppressWarnings("WeakerAccess")
- protected NotesClient(@NonNull Context appContext) {
- this.appContext = appContext;
- }
-
- /**
- * Gets the list of notes from the server.
- *
- * @param ssoAccount Account to be used
- * @param lastModified Last modified time of a former response (Unix timestamp in seconds!). All notes older than this time will be skipped.
- * @param lastETag ETag of a former response. If nothing changed, the response will be 304 NOT MODIFIED.
- * @return list of notes
- * @throws Exception
- */
- abstract NotesResponse getNotes(SingleSignOnAccount ssoAccount, Calendar lastModified, String lastETag) throws Exception;
-
- abstract NoteResponse createNote(SingleSignOnAccount ssoAccount, Note note) throws Exception;
-
- abstract NoteResponse editNote(SingleSignOnAccount ssoAccount, Note note) throws Exception;
-
- abstract void deleteNote(SingleSignOnAccount ssoAccount, long noteId) throws Exception;
-
- /**
- * This entity class is used to return relevant data of the HTTP reponse.
- */
- public static class ResponseData {
- private final String content;
- private final String etag;
- private final String supportedApiVersions;
- private final Calendar lastModified;
-
- ResponseData(@NonNull String content, String etag, @NonNull Calendar lastModified, @Nullable String supportedApiVersions) {
- this.content = content;
- this.etag = etag;
- this.lastModified = lastModified;
- this.supportedApiVersions = supportedApiVersions;
- }
-
- public String getContent() {
- return content;
- }
-
- public String getETag() {
- return etag;
- }
-
- public Calendar getLastModified() {
- return lastModified;
- }
-
- public String getSupportedApiVersions() {
- return this.supportedApiVersions;
- }
- }
-
- abstract protected String getApiPath();
-
- /**
- * Request-Method for POST, PUT with or without JSON-Object-Parameter
- *
- * @param target Filepath to the wanted function
- * @param method GET, POST, DELETE or PUT
- * @param parameter optional headers to be sent
- * @param requestBody JSON Object which shall be transferred to the server.
- * @param lastETag optional ETag of last response
- * @return Body of answer
- */
- protected ResponseData requestServer(SingleSignOnAccount ssoAccount, String target, String method, Map<String, String> parameter, JSONObject requestBody, String lastETag) throws Exception {
- final NextcloudRequest.Builder requestBuilder = new NextcloudRequest.Builder()
- .setMethod(method)
- .setUrl(getApiPath() + target);
- if (parameter != null) {
- requestBuilder.setParameter(parameter);
- }
-
- final Map<String, List<String>> header = new HashMap<>();
- if (requestBody != null) {
- header.put(HEADER_KEY_CONTENT_TYPE, Collections.singletonList(HEADER_VALUE_APPLICATION_JSON));
- requestBuilder.setRequestBody(requestBody.toString());
- }
- if (lastETag != null && !lastETag.isEmpty() && METHOD_GET.equals(method)) {
- header.put(HEADER_KEY_IF_NONE_MATCH, Collections.singletonList('"' + lastETag + '"'));
- requestBuilder.setHeader(header);
- }
-
- final NextcloudRequest nextcloudRequest = requestBuilder.build();
- final StringBuilder result = new StringBuilder();
-
- try {
- Log.v(TAG, ssoAccount.name + " → " + nextcloudRequest.getMethod() + " " + nextcloudRequest.getUrl() + " ");
- Log.d(TAG, "NextcloudRequest: " + nextcloudRequest.toString());
- final Response response = SSOClient.requestFilesApp(appContext, ssoAccount, nextcloudRequest);
-
- final BufferedReader rd = new BufferedReader(new InputStreamReader(response.getBody()));
- String line;
- while ((line = rd.readLine()) != null) {
- result.append(line);
- }
- response.getBody().close();
-
- String etag = "";
- final AidlNetworkRequest.PlainHeader eTagHeader = response.getPlainHeader(HEADER_KEY_ETAG);
- if (eTagHeader != null) {
- etag = Objects.requireNonNull(eTagHeader.getValue()).replace("\"", "");
- }
-
- final Calendar lastModified = Calendar.getInstance();
- lastModified.setTimeInMillis(0);
- final AidlNetworkRequest.PlainHeader lastModifiedHeader = response.getPlainHeader(HEADER_KEY_LAST_MODIFIED);
- if (lastModifiedHeader != null)
- lastModified.setTimeInMillis(Date.parse(lastModifiedHeader.getValue()));
- Log.d(TAG, "ETag: " + etag + "; Last-Modified: " + lastModified + " (" + lastModified + ")");
-
- String supportedApiVersions = null;
- final AidlNetworkRequest.PlainHeader supportedApiVersionsHeader = response.getPlainHeader(HEADER_KEY_X_NOTES_API_VERSIONS);
- if (supportedApiVersionsHeader != null) {
- supportedApiVersions = "[" + Objects.requireNonNull(supportedApiVersionsHeader.getValue()) + "]";
- }
-
- // return these header fields since they should only be saved after successful processing the result!
- return new ResponseData(result.toString(), etag, lastModified, supportedApiVersions);
- } catch (NullPointerException e) {
- final PackageInfo pInfo = appContext.getPackageManager().getPackageInfo("com.nextcloud.client", 0);
- if (pInfo.versionCode < MIN_NEXTCLOUD_FILES_APP_VERSION_CODE) {
- throw new NextcloudFilesAppNotSupportedException();
- } else {
- throw e;
- }
- }
- }
-}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV02.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV02.java
deleted file mode 100644
index 31a4de39..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV02.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package it.niedermann.owncloud.notes.persistence;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.WorkerThread;
-
-import com.nextcloud.android.sso.model.SingleSignOnAccount;
-
-import org.json.JSONObject;
-
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Map;
-
-import it.niedermann.owncloud.notes.persistence.entity.Note;
-import it.niedermann.owncloud.notes.shared.model.ServerResponse.NoteResponse;
-import it.niedermann.owncloud.notes.shared.model.ServerResponse.NotesResponse;
-
-@WorkerThread
-public class NotesClientV02 extends NotesClient {
-
- private static final String API_PATH = "/index.php/apps/notes/api/v0.2/";
-
- NotesClientV02(@NonNull Context appContext) {
- super(appContext);
- }
-
- NotesResponse getNotes(SingleSignOnAccount ssoAccount, Calendar lastModified, String lastETag) throws Exception {
- final Map<String, String> parameter = new HashMap<>();
- parameter.put(GET_PARAM_KEY_PRUNE_BEFORE, Long.toString(lastModified == null ? 0 : lastModified.getTimeInMillis() / 1_000));
- return new NotesResponse(requestServer(ssoAccount, "notes", METHOD_GET, parameter, null, lastETag));
- }
-
- private NoteResponse putNote(SingleSignOnAccount ssoAccount, Note note, String path, String method) throws Exception {
- JSONObject paramObject = new JSONObject();
- paramObject.accumulate(JSON_CONTENT, note.getContent());
- paramObject.accumulate(JSON_MODIFIED, note.getModified().getTimeInMillis() / 1_000);
- paramObject.accumulate(JSON_FAVORITE, note.getFavorite());
- paramObject.accumulate(JSON_CATEGORY, note.getCategory());
- return new NoteResponse(requestServer(ssoAccount, path, method, null, paramObject, null));
- }
-
- @Override
- NoteResponse createNote(SingleSignOnAccount ssoAccount, Note note) throws Exception {
- return putNote(ssoAccount, note, "notes", METHOD_POST);
- }
-
- @Override
- NoteResponse editNote(SingleSignOnAccount ssoAccount, Note note) throws Exception {
- return putNote(ssoAccount, note, "notes/" + note.getRemoteId(), METHOD_PUT);
- }
-
- @Override
- void deleteNote(SingleSignOnAccount ssoAccount, long noteId) throws Exception {
- this.requestServer(ssoAccount, "notes/" + noteId, METHOD_DELETE, null, null, null);
- }
-
- @Override
- protected String getApiPath() {
- return API_PATH;
- }
-}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV1.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV1.java
deleted file mode 100644
index 56661543..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesClientV1.java
+++ /dev/null
@@ -1,64 +0,0 @@
-package it.niedermann.owncloud.notes.persistence;
-
-import android.content.Context;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.WorkerThread;
-
-import com.nextcloud.android.sso.model.SingleSignOnAccount;
-
-import org.json.JSONObject;
-
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.Map;
-
-import it.niedermann.owncloud.notes.persistence.entity.Note;
-import it.niedermann.owncloud.notes.shared.model.ServerResponse.NoteResponse;
-import it.niedermann.owncloud.notes.shared.model.ServerResponse.NotesResponse;
-
-@WorkerThread
-public class NotesClientV1 extends NotesClient {
-
- private static final String API_PATH = "/index.php/apps/notes/api/v1/";
-
- NotesClientV1(@NonNull Context appContext) {
- super(appContext);
- }
-
- NotesResponse getNotes(SingleSignOnAccount ssoAccount, Calendar lastModified, String lastETag) throws Exception {
- final Map<String, String> parameter = new HashMap<>();
- parameter.put(GET_PARAM_KEY_PRUNE_BEFORE, Long.toString(lastModified == null ? 0 : lastModified.getTimeInMillis() / 1_000));
- return new NotesResponse(requestServer(ssoAccount, "notes", METHOD_GET, parameter, null, lastETag));
- }
-
- private NoteResponse putNote(SingleSignOnAccount ssoAccount, Note note, String path, String method) throws Exception {
- JSONObject paramObject = new JSONObject();
- paramObject.accumulate(JSON_TITLE, note.getTitle());
- paramObject.accumulate(JSON_CONTENT, note.getContent());
- paramObject.accumulate(JSON_MODIFIED, note.getModified().getTimeInMillis() / 1_000);
- paramObject.accumulate(JSON_FAVORITE, note.getFavorite());
- paramObject.accumulate(JSON_CATEGORY, note.getCategory());
- return new NoteResponse(requestServer(ssoAccount, path, method, null, paramObject, null));
- }
-
- @Override
- NoteResponse createNote(SingleSignOnAccount ssoAccount, Note note) throws Exception {
- return putNote(ssoAccount, note, "notes", METHOD_POST);
- }
-
- @Override
- NoteResponse editNote(SingleSignOnAccount ssoAccount, Note note) throws Exception {
- return putNote(ssoAccount, note, "notes/" + note.getRemoteId(), METHOD_PUT);
- }
-
- @Override
- void deleteNote(SingleSignOnAccount ssoAccount, long noteId) throws Exception {
- this.requestServer(ssoAccount, "notes/" + noteId, METHOD_DELETE, null, null, null);
- }
-
- @Override
- protected String getApiPath() {
- return API_PATH;
- }
-}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/SSOClient.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/SSOClient.java
index d5901496..9f28cfff 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/SSOClient.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/SSOClient.java
@@ -1,24 +1,40 @@
package it.niedermann.owncloud.notes.persistence;
import android.content.Context;
+import android.graphics.Color;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
+import com.bumptech.glide.load.HttpException;
import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializer;
import com.nextcloud.android.sso.aidl.NextcloudRequest;
import com.nextcloud.android.sso.api.NextcloudAPI;
import com.nextcloud.android.sso.api.Response;
+import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import com.nextcloud.android.sso.model.SingleSignOnAccount;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Type;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
+import it.niedermann.android.util.ColorUtil;
+import it.niedermann.owncloud.notes.persistence.sync.CapabilitiesDeserializer;
+import it.niedermann.owncloud.notes.shared.model.Capabilities;
+
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+
@SuppressWarnings("WeakerAccess")
@WorkerThread
public class SSOClient {
@@ -27,10 +43,6 @@ public class SSOClient {
private static final Map<String, NextcloudAPI> mNextcloudAPIs = new HashMap<>();
- public static Response requestFilesApp(@NonNull Context context, @NonNull SingleSignOnAccount ssoAccount, @NonNull NextcloudRequest nextcloudRequest) throws Exception {
- return getNextcloudAPI(context.getApplicationContext(), ssoAccount).performNetworkRequestV2(nextcloudRequest);
- }
-
public static NextcloudAPI getNextcloudAPI(Context appContext, SingleSignOnAccount ssoAccount) {
if (mNextcloudAPIs.containsKey(ssoAccount.name)) {
return mNextcloudAPIs.get(ssoAccount.name);
@@ -45,6 +57,7 @@ public class SSOClient {
calendar.setTimeInMillis(src.getAsLong() * 1_000);
return calendar;
})
+ .registerTypeAdapter(Capabilities.class, new CapabilitiesDeserializer())
.create(),
new NextcloudAPI.ApiConnectedListener() {
@Override
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/Account.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/Account.java
index ed6dcd6c..5317ed33 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/Account.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/entity/Account.java
@@ -7,7 +7,6 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
-import androidx.room.Ignore;
import androidx.room.Index;
import androidx.room.PrimaryKey;
@@ -21,7 +20,6 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.NoSuchElementException;
-import it.niedermann.owncloud.notes.persistence.NotesClient;
import it.niedermann.owncloud.notes.shared.model.ApiVersion;
import it.niedermann.owncloud.notes.shared.model.Capabilities;
@@ -83,7 +81,7 @@ public class Account implements Serializable {
final Collection<ApiVersion> supportedApiVersions = new HashSet<>(versionsArray.length());
for (int i = 0; i < versionsArray.length(); i++) {
final ApiVersion parsedApiVersion = ApiVersion.of(versionsArray.getString(i));
- for (ApiVersion temp : NotesClient.SUPPORTED_API_VERSIONS) {
+ for (ApiVersion temp : ApiVersion.SUPPORTED_API_VERSIONS) {
if (temp.compareTo(parsedApiVersion) == 0) {
supportedApiVersions.add(parsedApiVersion);
break;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ApiProvider.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ApiProvider.java
index cbb0687b..538afd89 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ApiProvider.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ApiProvider.java
@@ -16,16 +16,23 @@ import retrofit2.NextcloudRetrofitApiBuilder;
*/
public class ApiProvider {
+ private static final String API_ENDPOINT_OCS = "/ocs/v2.php/cloud/";
private static final String API_ENDPOINT_NOTES = "/index.php/apps/notes/api/v1/";
+ private final OcsAPI ocsAPI;
private final NotesAPI notesAPI;
public ApiProvider(@NonNull Context appContext, @NonNull SingleSignOnAccount ssoAccount) {
final NextcloudAPI nextcloudAPI = SSOClient.getNextcloudAPI(appContext, ssoAccount);
+ ocsAPI = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_OCS).create(OcsAPI.class);
notesAPI = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_NOTES).create(NotesAPI.class);
}
public NotesAPI getNotesAPI() {
return notesAPI;
}
+
+ public OcsAPI getOcsAPI() {
+ return ocsAPI;
+ }
}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/CapabilitiesDeserializer.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/CapabilitiesDeserializer.java
new file mode 100644
index 00000000..c9bf78da
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/CapabilitiesDeserializer.java
@@ -0,0 +1,81 @@
+package it.niedermann.owncloud.notes.persistence.sync;
+
+import android.graphics.Color;
+import android.util.Log;
+
+import com.bumptech.glide.load.HttpException;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParseException;
+import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
+
+import java.lang.reflect.Type;
+
+import it.niedermann.android.util.ColorUtil;
+import it.niedermann.owncloud.notes.shared.model.Capabilities;
+
+import static java.net.HttpURLConnection.HTTP_UNAVAILABLE;
+
+public class CapabilitiesDeserializer implements JsonDeserializer<Capabilities> {
+
+ private static final String TAG = CapabilitiesDeserializer.class.getSimpleName();
+
+ private static final String JSON_OCS = "ocs";
+ private static final String JSON_OCS_META = "meta";
+ private static final String JSON_OCS_META_STATUSCODE = "statuscode";
+ private static final String JSON_OCS_DATA = "data";
+ private static final String JSON_OCS_DATA_CAPABILITIES = "capabilities";
+ private static final String JSON_OCS_DATA_CAPABILITIES_NOTES = "notes";
+ private static final String JSON_OCS_DATA_CAPABILITIES_NOTES_API_VERSION = "api_version";
+ private static final String JSON_OCS_DATA_CAPABILITIES_THEMING = "theming";
+ private static final String JSON_OCS_DATA_CAPABILITIES_THEMING_COLOR = "color";
+ private static final String JSON_OCS_DATA_CAPABILITIES_THEMING_COLOR_TEXT = "color-text";
+
+ @Override
+ public Capabilities deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
+ final Capabilities response = new Capabilities();
+ final JsonObject ocs = json.getAsJsonObject().getAsJsonObject(JSON_OCS);
+ if (ocs.has(JSON_OCS_META)) {
+ final JsonObject meta = ocs.getAsJsonObject(JSON_OCS_META);
+ if (meta.has(JSON_OCS_META_STATUSCODE)) {
+ if (meta.get(JSON_OCS_META_STATUSCODE).getAsInt() == HTTP_UNAVAILABLE) {
+ Log.i(TAG, "Capabilities Endpoint: This instance is currently in maintenance mode.");
+ throw new JsonParseException(new NextcloudHttpRequestFailedException(HTTP_UNAVAILABLE, new HttpException(HTTP_UNAVAILABLE)));
+ }
+ }
+ }
+ if (ocs.has(JSON_OCS_DATA)) {
+ final JsonObject data = ocs.getAsJsonObject(JSON_OCS_DATA);
+ if (data.has(JSON_OCS_DATA_CAPABILITIES)) {
+ final JsonObject capabilities = data.getAsJsonObject(JSON_OCS_DATA_CAPABILITIES);
+ if (capabilities.has(JSON_OCS_DATA_CAPABILITIES_NOTES)) {
+ final JsonObject notes = capabilities.getAsJsonObject(JSON_OCS_DATA_CAPABILITIES_NOTES);
+ if (notes.has(JSON_OCS_DATA_CAPABILITIES_NOTES_API_VERSION)) {
+ final JsonElement apiVersion = notes.get(JSON_OCS_DATA_CAPABILITIES_NOTES_API_VERSION);
+ response.setApiVersion(apiVersion.isJsonArray() ? apiVersion.toString() : null);
+ }
+ }
+ if (capabilities.has(JSON_OCS_DATA_CAPABILITIES_THEMING)) {
+ final JsonObject theming = capabilities.getAsJsonObject(JSON_OCS_DATA_CAPABILITIES_THEMING);
+ if (theming.has(JSON_OCS_DATA_CAPABILITIES_THEMING_COLOR)) {
+ try {
+ response.setColor(Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(theming.get(JSON_OCS_DATA_CAPABILITIES_THEMING_COLOR).getAsString())));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ if (theming.has(JSON_OCS_DATA_CAPABILITIES_THEMING_COLOR_TEXT)) {
+ try {
+ response.setTextColor(Color.parseColor(ColorUtil.INSTANCE.formatColorToParsableHexString(theming.get(JSON_OCS_DATA_CAPABILITIES_THEMING_COLOR_TEXT).getAsString())));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+ }
+ return response;
+ }
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NextcloudAPI.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NextcloudAPI.java
deleted file mode 100644
index 9ddb5941..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NextcloudAPI.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package it.niedermann.owncloud.notes.persistence.sync;
-
-
-import java.util.List;
-
-import it.niedermann.owncloud.notes.persistence.entity.Note;
-import retrofit2.Call;
-import retrofit2.http.Body;
-import retrofit2.http.DELETE;
-import retrofit2.http.GET;
-import retrofit2.http.POST;
-import retrofit2.http.PUT;
-import retrofit2.http.Path;
-import retrofit2.http.Query;
-
-/**
- * @link <a href="https://deck.readthedocs.io/en/latest/API/">Deck REST API</a>
- */
-public interface NextcloudAPI {
-
- @GET("notes")
- Call<List<Note>> getNotes(@Query(value = "pruneBefore") long lastModified, @Query("If-None-Match") String lastETag);
-
- @POST("notes")
- Call<Note> createNote(@Body Note note);
-
- @PUT("notes/{remoteId}")
- Call<Note> editNote(@Body Note note, @Path("remoteId") long remoteId);
-
- @DELETE("notes/{remoteId}")
- Call<Note> deleteNote(@Path("remoteId") long noteId);
-
-}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/OcsAPI.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/OcsAPI.java
new file mode 100644
index 00000000..17bc3c4f
--- /dev/null
+++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/OcsAPI.java
@@ -0,0 +1,16 @@
+package it.niedermann.owncloud.notes.persistence.sync;
+
+
+import it.niedermann.owncloud.notes.shared.model.Capabilities;
+import retrofit2.Call;
+import retrofit2.http.GET;
+import retrofit2.http.Query;
+
+/**
+ * @link <a href="https://deck.readthedocs.io/en/latest/API/">Deck REST API</a>
+ */
+public interface OcsAPI {
+
+ @GET("capabilities?format=json")
+ Call<Capabilities> getCapabilities(@Query("If-None-Match") String eTag);
+}
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java
index b27afd7a..761d0dc3 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ApiVersion.java
@@ -10,6 +10,11 @@ import java.util.regex.Pattern;
public class ApiVersion implements Comparable<ApiVersion> {
private static final Pattern NUMBER_EXTRACTION_PATTERN = Pattern.compile("[0-9]+");
+ public static final ApiVersion[] SUPPORTED_API_VERSIONS = new ApiVersion[]{
+ new ApiVersion(1, 0),
+ new ApiVersion(0, 2)
+ };
+
private String originalVersion = "?";
private int major;
private int minor;
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/Capabilities.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/Capabilities.java
index 1c1bed3d..5514a91b 100644
--- a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/Capabilities.java
+++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/Capabilities.java
@@ -6,6 +6,7 @@ import android.util.Log;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.bumptech.glide.load.HttpException;
import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
@@ -38,12 +39,17 @@ public class Capabilities {
private String apiVersion = null;
@ColorInt
- private Integer color = -16743735;
+ private int color = -16743735;
@ColorInt
- private Integer textColor = -16777216;
+ private int textColor = -16777216;
@Nullable
- private final String eTag;
+ private String eTag;
+ public Capabilities() {
+
+ }
+
+ @VisibleForTesting
public Capabilities(@NonNull String response, @Nullable String eTag) throws NextcloudHttpRequestFailedException {
this.eTag = eTag;
final JSONObject ocs;
@@ -92,6 +98,10 @@ public class Capabilities {
}
}
+ public void setApiVersion(String apiVersion) {
+ this.apiVersion = apiVersion;
+ }
+
public String getApiVersion() {
return apiVersion;
}
@@ -101,14 +111,26 @@ public class Capabilities {
return eTag;
}
- public Integer getColor() {
+ public void setETag(@Nullable String eTag) {
+ this.eTag = eTag;
+ }
+
+ public int getColor() {
return color;
}
- public Integer getTextColor() {
+ public void setColor(@ColorInt int color) {
+ this.color = color;
+ }
+
+ public int getTextColor() {
return textColor;
}
+ public void setTextColor(@ColorInt int textColor) {
+ this.textColor = textColor;
+ }
+
@NonNull
@Override
public String toString() {
diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ServerResponse.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ServerResponse.java
deleted file mode 100644
index dca53fb9..00000000
--- a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/ServerResponse.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package it.niedermann.owncloud.notes.shared.model;
-
-import androidx.annotation.Nullable;
-
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.List;
-
-import it.niedermann.owncloud.notes.persistence.NotesClient;
-import it.niedermann.owncloud.notes.persistence.entity.Note;
-
-/**
- * Provides entity classes for handling server responses with a single note ({@link NoteResponse}) or a list of notes ({@link NotesResponse}).
- */
-public class ServerResponse {
-
- public static class NoteResponse extends ServerResponse {
- public NoteResponse(NotesClient.ResponseData response) {
- super(response);
- }
-
- public Note getNote() throws JSONException {
- return getNoteFromJSON(new JSONObject(getContent()));
- }
- }
-
- public static class NotesResponse extends ServerResponse {
- public NotesResponse(NotesClient.ResponseData response) {
- super(response);
- }
-
- public List<Note> getNotes() throws JSONException {
- List<Note> notesList = new ArrayList<>();
- JSONArray notes = new JSONArray(getContent());
- for (int i = 0; i < notes.length(); i++) {
- JSONObject json = notes.getJSONObject(i);
- notesList.add(getNoteFromJSON(json));
- }
- return notesList;
- }
- }
-
-
- private final NotesClient.ResponseData response;
-
- ServerResponse(NotesClient.ResponseData response) {
- this.response = response;
- }
-
- protected String getContent() {
- return response == null ? null : response.getContent();
- }
-
- public String getETag() {
- return response.getETag();
- }
-
- public Calendar getLastModified() {
- return response.getLastModified();
- }
-
- @Nullable
- public String getSupportedApiVersions() {
- return response.getSupportedApiVersions();
- }
-
- Note getNoteFromJSON(JSONObject json) throws JSONException {
- long remoteId = 0;
- String title = "";
- String content = "";
- Calendar modified = null;
- boolean favorite = false;
- String category = "";
- String etag = null;
- if (!json.isNull(NotesClient.JSON_ID)) {
- remoteId = json.getLong(NotesClient.JSON_ID);
- }
- if (!json.isNull(NotesClient.JSON_TITLE)) {
- title = json.getString(NotesClient.JSON_TITLE);
- }
- if (!json.isNull(NotesClient.JSON_CONTENT)) {
- content = json.getString(NotesClient.JSON_CONTENT);
- }
- if (!json.isNull(NotesClient.JSON_MODIFIED)) {
- modified = Calendar.getInstance();
- modified.setTimeInMillis(json.getLong(NotesClient.JSON_MODIFIED) * 1_000);
- }
- if (!json.isNull(NotesClient.JSON_FAVORITE)) {
- favorite = json.getBoolean(NotesClient.JSON_FAVORITE);
- }
- if (!json.isNull(NotesClient.JSON_CATEGORY)) {
- category = json.getString(NotesClient.JSON_CATEGORY);
- }
- if (!json.isNull(NotesClient.JSON_ETAG)) {
- etag = json.getString(NotesClient.JSON_ETAG);
- }
- return new Note(remoteId, modified, title, content, category, favorite, etag);
- }
-}
diff --git a/app/src/test/java/it/niedermann/owncloud/notes/shared/model/CapabilitiesTest.java b/app/src/test/java/it/niedermann/owncloud/notes/shared/model/CapabilitiesTest.java
index 6415bb39..5a30bd2a 100644
--- a/app/src/test/java/it/niedermann/owncloud/notes/shared/model/CapabilitiesTest.java
+++ b/app/src/test/java/it/niedermann/owncloud/notes/shared/model/CapabilitiesTest.java
@@ -48,8 +48,8 @@ public class CapabilitiesTest {
final Capabilities capabilities = new Capabilities(response, null);
assertNull(capabilities.getETag());
assertNull(capabilities.getApiVersion());
- assertEquals(Integer.valueOf(Color.parseColor("#1E4164")), capabilities.getColor());
- assertEquals(Integer.valueOf(Color.parseColor("#ffffff")), capabilities.getTextColor());
+ assertEquals(Color.parseColor("#1E4164"), capabilities.getColor());
+ assertEquals(Color.parseColor("#ffffff"), capabilities.getTextColor());
}
@Test
@@ -86,8 +86,8 @@ public class CapabilitiesTest {
final Capabilities capabilities = new Capabilities(response, null);
assertNull(capabilities.getETag());
assertEquals("1.0", capabilities.getApiVersion());
- assertEquals(Integer.valueOf(Color.parseColor("#1E4164")), capabilities.getColor());
- assertEquals(Integer.valueOf(Color.parseColor("#ffffff")), capabilities.getTextColor());
+ assertEquals(Color.parseColor("#1E4164"), capabilities.getColor());
+ assertEquals(Color.parseColor("#ffffff"), capabilities.getTextColor());
}
@Test