diff options
author | Stefan Niedermann <info@niedermann.it> | 2021-04-28 20:36:58 +0300 |
---|---|---|
committer | Stefan Niedermann <info@niedermann.it> | 2021-04-28 20:36:58 +0300 |
commit | 4b416116d5017d8e571135bedc0409a75a87e9f5 (patch) | |
tree | a092196f723695c07326e4a730bdfe3b29a849b7 | |
parent | 1c3b9a0d629901d2d1c47000dae11347b06c57c9 (diff) |
#1167 Use retrofit also for capabilities endpoint
10 files changed, 286 insertions, 126 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 b053227e..ecf9dfcf 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,19 +1,24 @@ package it.niedermann.owncloud.notes.persistence; import android.content.Context; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.WorkerThread; import com.google.gson.JsonParseException; +import com.nextcloud.android.sso.api.NextcloudAPI; +import com.nextcloud.android.sso.api.ParsedResponse; import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; import com.nextcloud.android.sso.model.SingleSignOnAccount; import java.io.IOException; +import java.util.Map; -import it.niedermann.owncloud.notes.persistence.sync.ApiProvider; +import it.niedermann.owncloud.notes.persistence.sync.OcsAPI; import it.niedermann.owncloud.notes.shared.model.Capabilities; +import retrofit2.NextcloudRetrofitApiBuilder; import retrofit2.Response; import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; @@ -21,14 +26,23 @@ import static java.net.HttpURLConnection.HTTP_UNAVAILABLE; @WorkerThread public class CapabilitiesClient { - protected static final String HEADER_KEY_ETAG = "ETag"; + private static final String TAG = CapabilitiesClient.class.getSimpleName(); + + private static final String API_ENDPOINT_OCS = "/ocs/v2.php/cloud/"; + private static final String HEADER_KEY_ETAG = "ETag"; 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(); + final NextcloudAPI nextcloudAPI = SSOClient.getNextcloudAPI(context.getApplicationContext(), ssoAccount); + final OcsAPI ocsAPI = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_OCS).create(OcsAPI.class); + final Response<ParsedResponse<Capabilities>> response = ocsAPI.getCapabilities(lastETag).execute(); try { - final Capabilities capabilities = response.body(); - capabilities.setETag(response.headers().get(HEADER_KEY_ETAG)); + final Capabilities capabilities = response.body().getResponse(); + final Map<String, String> headers = response.body().getHeaders(); + if (headers != null) { + capabilities.setETag(headers.get(HEADER_KEY_ETAG)); + } else { + Log.w(TAG, "Response headers of capabilities are null"); + } return capabilities; } catch (JsonParseException e) { if (e.getCause() instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) e.getCause()).getStatusCode() == HTTP_UNAVAILABLE) { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java index b3af4ab7..79e844ae 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/NotesServerSyncTask.java @@ -6,6 +6,8 @@ import android.util.Log; import androidx.annotation.NonNull; import com.nextcloud.android.sso.AccountImporter; +import com.nextcloud.android.sso.api.NextcloudAPI; +import com.nextcloud.android.sso.api.ParsedResponse; import com.nextcloud.android.sso.exceptions.NextcloudFilesAppAccountNotFoundException; import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException; import com.nextcloud.android.sso.exceptions.TokenMismatchException; @@ -23,7 +25,7 @@ import java.util.Set; import it.niedermann.owncloud.notes.persistence.entity.Account; import it.niedermann.owncloud.notes.persistence.entity.Note; -import it.niedermann.owncloud.notes.persistence.sync.ApiProvider; +import it.niedermann.owncloud.notes.persistence.sync.NotesAPI; import it.niedermann.owncloud.notes.shared.model.DBStatus; import it.niedermann.owncloud.notes.shared.model.ISyncCallback; import it.niedermann.owncloud.notes.shared.model.SyncResultStatus; @@ -49,7 +51,7 @@ abstract class NotesServerSyncTask extends Thread { @NonNull private final Context context; @NonNull - private ApiProvider notesClient; + private NotesAPI notesAPI; @NonNull private final NotesRepository repo; @NonNull @@ -78,18 +80,21 @@ abstract class NotesServerSyncTask extends Thread { @Override public void run() { onPreExecute(); - notesClient = new ApiProvider(context, ssoAccount); - new Thread(() -> { - Log.i(TAG, "STARTING SYNCHRONIZATION"); - final SyncResultStatus status = new SyncResultStatus(); - status.pushSuccessful = pushLocalChanges(); - if (!onlyLocalChanges) { - status.pullSuccessful = pullRemoteChanges(); - } - Log.i(TAG, "SYNCHRONIZATION FINISHED"); - onPostExecute(status); - }).start(); + final NextcloudAPI nextcloudAPI = SSOClient.getNextcloudAPI(context.getApplicationContext(), ssoAccount); + notesAPI = new NotesAPI(nextcloudAPI, localAccount.getPreferredApiVersion()); + + Log.i(TAG, "STARTING SYNCHRONIZATION"); + + final SyncResultStatus status = new SyncResultStatus(); + status.pushSuccessful = pushLocalChanges(); + if (!onlyLocalChanges) { + status.pullSuccessful = pullRemoteChanges(); + } + + Log.i(TAG, "SYNCHRONIZATION FINISHED"); + + onPostExecute(status); } abstract void onPreExecute(); @@ -113,13 +118,13 @@ abstract class NotesServerSyncTask extends Thread { Log.v(TAG, " ...create/edit"); if (note.getRemoteId() != null) { Log.v(TAG, " ...Note has remoteId → try to edit"); - final Response<Note> editResponse = notesClient.getNotesAPI().editNote(note, note.getRemoteId()).execute(); + final Response<Note> editResponse = notesAPI.editNote(note, note.getRemoteId()).execute(); if (editResponse.isSuccessful()) { remoteNote = editResponse.body(); } else { if (editResponse.code() == HTTP_NOT_FOUND) { Log.v(TAG, " ...Note does no longer exist on server → recreate"); - final Response<Note> createResponse = notesClient.getNotesAPI().createNote(note).execute(); + final Response<Note> createResponse = notesAPI.createNote(note).execute(); if (createResponse.isSuccessful()) { remoteNote = createResponse.body(); } else { @@ -131,7 +136,7 @@ abstract class NotesServerSyncTask extends Thread { } } else { Log.v(TAG, " ...Note does not have a remoteId yet → create"); - final Response<Note> createResponse = notesClient.getNotesAPI().createNote(note).execute(); + final Response<Note> createResponse = notesAPI.createNote(note).execute(); if (createResponse.isSuccessful()) { remoteNote = createResponse.body(); repo.updateRemoteId(note.getId(), remoteNote.getRemoteId()); @@ -147,7 +152,7 @@ abstract class NotesServerSyncTask extends Thread { Log.v(TAG, " ...delete (only local, since it has never been synchronized)"); } else { Log.v(TAG, " ...delete (from server and local)"); - final Response<Note> deleteResponse = notesClient.getNotesAPI().deleteNote(note.getRemoteId()).execute(); + final Response<Note> deleteResponse = notesAPI.deleteNote(note.getRemoteId()).execute(); if (!deleteResponse.isSuccessful()) { if (deleteResponse.code() == HTTP_NOT_FOUND) { Log.v(TAG, " ...delete (note has already been deleted remotely)"); @@ -197,9 +202,9 @@ abstract class NotesServerSyncTask extends Thread { localAccount.setModified(accountFromDatabase.getModified()); localAccount.setETag(accountFromDatabase.getETag()); - final Response<List<Note>> fetchResponse = notesClient.getNotesAPI().getNotes(localAccount.getModified().getTimeInMillis() / 1_000, localAccount.getETag()).execute(); + final Response<ParsedResponse<List<Note>>> fetchResponse = notesAPI.getNotes(localAccount.getModified().getTimeInMillis() / 1_000, localAccount.getETag()).execute(); if (fetchResponse.isSuccessful()) { - final List<Note> remoteNotes = fetchResponse.body(); + final List<Note> remoteNotes = fetchResponse.body().getResponse(); final Set<Long> remoteIDs = new HashSet<>(); // pull remote changes: update or create each remote note for (Note remoteNote : remoteNotes) { @@ -231,14 +236,14 @@ abstract class NotesServerSyncTask extends Thread { } // update ETag and Last-Modified in order to reduce size of next response - localAccount.setETag(fetchResponse.headers().get(HEADER_KEY_ETAG)); + localAccount.setETag(fetchResponse.body().getHeaders().get(HEADER_KEY_ETAG)); final Calendar lastModified = Calendar.getInstance(); lastModified.setTimeInMillis(0); - final String lastModifiedHeader = fetchResponse.headers().get(HEADER_KEY_LAST_MODIFIED); + final String lastModifiedHeader = fetchResponse.body().getHeaders().get(HEADER_KEY_LAST_MODIFIED); if (lastModifiedHeader != null) lastModified.setTimeInMillis(Date.parse(lastModifiedHeader)); - Log.d(TAG, "ETag: " + fetchResponse.headers().get(HEADER_KEY_ETAG) + "; Last-Modified: " + lastModified + " (" + lastModified + ")"); + Log.d(TAG, "ETag: " + fetchResponse.body().getHeaders().get(HEADER_KEY_ETAG) + "; Last-Modified: " + lastModified + " (" + lastModified + ")"); localAccount.setModified(lastModified); @@ -247,7 +252,7 @@ abstract class NotesServerSyncTask extends Thread { String supportedApiVersions = null; - final String supportedApiVersionsHeader = fetchResponse.headers().get(HEADER_KEY_X_NOTES_API_VERSIONS); + final String supportedApiVersionsHeader = fetchResponse.body().getHeaders().get(HEADER_KEY_X_NOTES_API_VERSIONS); if (supportedApiVersionsHeader != null) { supportedApiVersions = "[" + Objects.requireNonNull(supportedApiVersionsHeader) + "]"; } @@ -260,16 +265,17 @@ abstract class NotesServerSyncTask extends Thread { } return true; } else { - throw new Exception(fetchResponse.errorBody().string()); - } - } catch (NextcloudHttpRequestFailedException e) { - Log.d(TAG, "Server returned HTTP Status Code " + e.getStatusCode() + " - " + e.getMessage()); - if (e.getStatusCode() == HTTP_NOT_MODIFIED) { - return true; - } else { - exceptions.add(e); + exceptions.add(new Exception(fetchResponse.errorBody().string())); return false; } +// } catch (NextcloudHttpRequestFailedException e) { +// Log.d(TAG, "Server returned HTTP Status Code " + e.getStatusCode() + " - " + e.getMessage()); +// if (e.getStatusCode() == HTTP_NOT_MODIFIED) { +// return true; +// } else { +// exceptions.add(e); +// return false; +// } } catch (Exception e) { if (e instanceof TokenMismatchException) { SSOClient.invalidateAPICache(ssoAccount); 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 9f28cfff..d110c8a0 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,40 +1,25 @@ 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 { @@ -43,7 +28,7 @@ public class SSOClient { private static final Map<String, NextcloudAPI> mNextcloudAPIs = new HashMap<>(); - public static NextcloudAPI getNextcloudAPI(Context appContext, SingleSignOnAccount ssoAccount) { + public static synchronized NextcloudAPI getNextcloudAPI(@NonNull Context appContext, @NonNull SingleSignOnAccount ssoAccount) { if (mNextcloudAPIs.containsKey(ssoAccount.name)) { return mNextcloudAPIs.get(ssoAccount.name); } else { @@ -58,18 +43,18 @@ public class SSOClient { return calendar; }) .registerTypeAdapter(Capabilities.class, new CapabilitiesDeserializer()) - .create(), - new NextcloudAPI.ApiConnectedListener() { - @Override - public void onConnected() { - Log.i(TAG, "SSO API connected for " + ssoAccount); - } + .create(), new NextcloudAPI.ApiConnectedListener() { + @Override + public void onConnected() { + Log.i(TAG, "SSO API connected for " + ssoAccount); + } - @Override - public void onError(Exception ex) { - ex.printStackTrace(); - } - }); + @Override + public void onError(Exception ex) { + ex.printStackTrace(); + SSOClient.invalidateAPICache(ssoAccount); + } + }); mNextcloudAPIs.put(ssoAccount.name, nextcloudAPI); return nextcloudAPI; } 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 deleted file mode 100644 index 538afd89..00000000 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/ApiProvider.java +++ /dev/null @@ -1,38 +0,0 @@ -package it.niedermann.owncloud.notes.persistence.sync; - -import android.content.Context; - -import androidx.annotation.NonNull; - -import com.google.gson.GsonBuilder; -import com.nextcloud.android.sso.api.NextcloudAPI; -import com.nextcloud.android.sso.model.SingleSignOnAccount; - -import it.niedermann.owncloud.notes.persistence.SSOClient; -import retrofit2.NextcloudRetrofitApiBuilder; - -/** - * Created by david on 26.05.17. - */ -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/NotesAPI.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java index 92130664..29f3119c 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI.java @@ -1,34 +1,97 @@ package it.niedermann.owncloud.notes.persistence.sync; -import java.util.Calendar; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.nextcloud.android.sso.api.NextcloudAPI; +import com.nextcloud.android.sso.api.ParsedResponse; + import java.util.List; import it.niedermann.owncloud.notes.persistence.entity.Note; +import it.niedermann.owncloud.notes.shared.model.ApiVersion; 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; +import retrofit2.NextcloudRetrofitApiBuilder; /** - * @link <a href="https://deck.readthedocs.io/en/latest/API/">Deck REST API</a> + * Compatibility layer to support multiple API versions */ -public interface NotesAPI { +public class NotesAPI { + + private static final String TAG = NotesAPI.class.getSimpleName(); + + private static final String API_ENDPOINT_NOTES_1_0 = "/index.php/apps/notes/api/v1/"; + private static final String API_ENDPOINT_NOTES_0_2 = "/index.php/apps/notes/api/v0.2/"; + + @NonNull + private final ApiVersion usedApiVersion; + private final NotesAPI_0_2 notesAPI_0_2; + private final NotesAPI_1_0 notesAPI_1_0; - @GET("notes") - Call<List<Note>> getNotes(@Query(value = "pruneBefore") long lastModified, @Query("If-None-Match") String lastETag); + public NotesAPI(@NonNull NextcloudAPI nextcloudAPI, @Nullable ApiVersion preferredApiVersion) { + if (preferredApiVersion == null) { + Log.i(TAG, "Using " + ApiVersion.API_VERSION_0_2 + ", preferredApiVersion is null"); + usedApiVersion = ApiVersion.API_VERSION_0_2; + notesAPI_0_2 = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_NOTES_0_2).create(NotesAPI_0_2.class); + notesAPI_1_0 = null; + } else if (ApiVersion.API_VERSION_1_0.equals(preferredApiVersion)) { + Log.i(TAG, "Using " + ApiVersion.API_VERSION_1_0); + usedApiVersion = ApiVersion.API_VERSION_1_0; + notesAPI_0_2 = null; + notesAPI_1_0 = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_NOTES_1_0).create(NotesAPI_1_0.class); + } else if (ApiVersion.API_VERSION_0_2.equals(preferredApiVersion)) { + Log.i(TAG, "Using " + ApiVersion.API_VERSION_0_2); + usedApiVersion = ApiVersion.API_VERSION_0_2; + notesAPI_0_2 = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_NOTES_0_2).create(NotesAPI_0_2.class); + notesAPI_1_0 = null; + } else { + Log.w(TAG, "Unsupported API version " + preferredApiVersion + " - try using " + ApiVersion.API_VERSION_0_2); + usedApiVersion = ApiVersion.API_VERSION_0_2; + notesAPI_0_2 = new NextcloudRetrofitApiBuilder(nextcloudAPI, API_ENDPOINT_NOTES_0_2).create(NotesAPI_0_2.class); + notesAPI_1_0 = null; + } + } - @POST("notes") - Call<Note> createNote(@Body Note note); + public Call<ParsedResponse<List<Note>>> getNotes(long lastModified, String lastETag) { + if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) { + return notesAPI_1_0.getNotes(lastModified, lastETag); + } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) { + return notesAPI_0_2.getNotes(lastModified, lastETag); + } else { + throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support getNotes()."); + } + } - @PUT("notes/{remoteId}") - Call<Note> editNote(@Body Note note, @Path("remoteId") long remoteId); + public Call<Note> createNote(Note note) { + if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) { + return notesAPI_1_0.createNote(note); + } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) { + return notesAPI_0_2.createNote(note); + } else { + throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support createNote()."); + } + } - @DELETE("notes/{remoteId}") - Call<Note> deleteNote(@Path("remoteId") long noteId); + public Call<Note> editNote(Note note, long remoteId) { + if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) { + return notesAPI_1_0.editNote(note, remoteId); + } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) { + return notesAPI_0_2.editNote(note, remoteId); + } else { + throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support editNote()."); + } + } + public Call<Note> deleteNote(long noteId) { + if (ApiVersion.API_VERSION_1_0.equals(usedApiVersion)) { + return notesAPI_1_0.deleteNote(noteId); + } else if (ApiVersion.API_VERSION_0_2.equals(usedApiVersion)) { + return notesAPI_0_2.deleteNote(noteId); + } else { + throw new UnsupportedOperationException("Used API version " + usedApiVersion + " does not support createNote()."); + } + } } diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java new file mode 100644 index 00000000..9a77f8c4 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_0_2.java @@ -0,0 +1,70 @@ +package it.niedermann.owncloud.notes.persistence.sync; + + +import com.google.gson.annotations.Expose; +import com.nextcloud.android.sso.api.ParsedResponse; + +import java.util.Calendar; +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://github.com/nextcloud/notes/wiki/API-0.2">Notes API v0.2</a> + */ +public interface NotesAPI_0_2 { + + @GET("notes") + Call<ParsedResponse<List<Note>>> getNotes(@Query(value = "pruneBefore") long lastModified, @Query("If-None-Match") String lastETag); + + default Call<Note> createNote(@Body Note note) { + return createNote(new Note_0_2(note)); + } + + @POST("notes") + Call<Note> createNote(@Body Note_0_2 note); + + @PUT("notes/{remoteId}") + Call<Note> editNote(@Body Note note, @Path("remoteId") long remoteId); + + @DELETE("notes/{remoteId}") + Call<Note> deleteNote(@Path("remoteId") long noteId); + + class Note_0_2 { + @Expose + public final long id; + @Expose + public final String title; + @Expose + public final String category; + @Expose + public final Calendar modified; + @Expose + public final String content; + @Expose + public final boolean favorite; + @Expose + public final String eTag; + + private Note_0_2(Note note) { + if (note == null) { + throw new IllegalArgumentException(Note.class.getSimpleName() + " can not be converted to " + Note_0_2.class.getSimpleName() + " because it is null."); + } + this.id = note.getRemoteId(); + this.title = note.getTitle(); + this.category = note.getCategory(); + this.modified = note.getModified(); + this.content = note.getContent(); + this.favorite = note.getFavorite(); + this.eTag = note.getETag(); + } + } +} diff --git a/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java new file mode 100644 index 00000000..1c738ca7 --- /dev/null +++ b/app/src/main/java/it/niedermann/owncloud/notes/persistence/sync/NotesAPI_1_0.java @@ -0,0 +1,34 @@ +package it.niedermann.owncloud.notes.persistence.sync; + + +import com.nextcloud.android.sso.api.ParsedResponse; + +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://github.com/nextcloud/notes/blob/master/docs/api/README.md">Notes API v1</a> + */ +public interface NotesAPI_1_0 { + + @GET("notes") + Call<ParsedResponse<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 index 17bc3c4f..8923d50f 100644 --- 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 @@ -1,6 +1,8 @@ package it.niedermann.owncloud.notes.persistence.sync; +import com.nextcloud.android.sso.api.ParsedResponse; + import it.niedermann.owncloud.notes.shared.model.Capabilities; import retrofit2.Call; import retrofit2.http.GET; @@ -12,5 +14,5 @@ import retrofit2.http.Query; public interface OcsAPI { @GET("capabilities?format=json") - Call<Capabilities> getCapabilities(@Query("If-None-Match") String eTag); + Call<ParsedResponse<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 761d0dc3..94c5408d 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 @@ -3,6 +3,7 @@ package it.niedermann.owncloud.notes.shared.model; import androidx.annotation.NonNull; +import java.util.Objects; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -10,14 +11,17 @@ 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 API_VERSION_0_2 = new ApiVersion(0, 2); + public static final ApiVersion API_VERSION_1_0 = new ApiVersion(1, 0); + public static final ApiVersion[] SUPPORTED_API_VERSIONS = new ApiVersion[]{ - new ApiVersion(1, 0), - new ApiVersion(0, 2) + API_VERSION_1_0, + API_VERSION_0_2 }; private String originalVersion = "?"; - private int major; - private int minor; + private final int major; + private final int minor; public ApiVersion(String originalVersion, int major, int minor) { this(major, minor); @@ -70,7 +74,7 @@ public class ApiVersion implements Comparable<ApiVersion> { * 1 if the compared major version is <strong>lower</strong> than the current major version */ @Override - public int compareTo(ApiVersion compare) { + public int compareTo(@NonNull ApiVersion compare) { if (compare.getMajor() > getMajor()) { return -1; } else if (compare.getMajor() < getMajor()) { @@ -79,6 +83,19 @@ public class ApiVersion implements Comparable<ApiVersion> { return 0; } + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ApiVersion that = (ApiVersion) o; + return compareTo(that) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(major, minor); + } + @NonNull @Override public String toString() { diff --git a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/SyncResultStatus.java b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/SyncResultStatus.java index 2031568b..41ba850a 100644 --- a/app/src/main/java/it/niedermann/owncloud/notes/shared/model/SyncResultStatus.java +++ b/app/src/main/java/it/niedermann/owncloud/notes/shared/model/SyncResultStatus.java @@ -3,4 +3,11 @@ package it.niedermann.owncloud.notes.shared.model; public class SyncResultStatus { public boolean pullSuccessful = true; public boolean pushSuccessful = true; + + public static final SyncResultStatus FAILED = new SyncResultStatus(); + + static { + FAILED.pullSuccessful = false; + FAILED.pushSuccessful = false; + } } |