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

github.com/stefan-niedermann/nextcloud-deck.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Niedermann <info@niedermann.it>2020-06-21 16:04:42 +0300
committerNiedermann IT-Dienstleistungen <stefan-niedermann@users.noreply.github.com>2020-06-21 17:18:46 +0300
commitf7cca3a2699787728b36268c031d90c99074be8f (patch)
tree7c761d3f1baed68671d27d4fb0ec7438fc0e1a71
parent27623eaac7ccaabba7a4653fdb0152be106e8fbe (diff)
Enhanced exception handling for uploading attachments
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/exceptions/UploadAttachmentFailedException.java12
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java23
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java2
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java32
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java48
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java3
-rw-r--r--app/src/main/java/it/niedermann/nextcloud/deck/util/AttachmentUtil.java33
-rw-r--r--app/src/main/res/values/strings.xml9
8 files changed, 78 insertions, 84 deletions
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/UploadAttachmentFailedException.java b/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/UploadAttachmentFailedException.java
new file mode 100644
index 000000000..05374669d
--- /dev/null
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/exceptions/UploadAttachmentFailedException.java
@@ -0,0 +1,12 @@
+package it.niedermann.nextcloud.deck.exceptions;
+
+public class UploadAttachmentFailedException extends Exception {
+
+ public UploadAttachmentFailedException(String message) {
+ super(message);
+ }
+
+ public UploadAttachmentFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java b/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java
index 1020e5cb3..91192f597 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/model/Attachment.java
@@ -1,15 +1,9 @@
package it.niedermann.nextcloud.deck.model;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.net.Uri;
-import android.webkit.MimeTypeMap;
-
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Index;
-import java.io.File;
import java.io.Serializable;
import java.util.Date;
@@ -146,23 +140,6 @@ public class Attachment extends AbstractRemoteEntity implements Comparable<Attac
this.localPath = localPath;
}
- public static String getMimetypeForUri(Context context, Uri uri) {
- String extension;
-
- //Check uri format to avoid null
- if (uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)) {
- //If scheme is a content
- extension = context.getContentResolver().getType(uri);
- } else {
- //If scheme is a File
- //This will replace white spaces with %20 and also other special characters. This will avoid returning null values on file name with spaces and special characters.
- extension = MimeTypeMap.getFileExtensionFromUrl(Uri.fromFile(new File(uri.getPath())).toString());
-
- }
-
- return extension;
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java
index d660b6ecb..452e2d98f 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/persistence/sync/helpers/providers/AttachmentDataProvider.java
@@ -94,7 +94,7 @@ public class AttachmentDataProvider extends AbstractSyncDataProvider<Attachment>
@Override
public void updateOnServer(ServerAdapter serverAdapter, DataBaseAdapter dataBaseAdapter, long accountId, IResponseCallback<Attachment> callback, Attachment entity) {
Uri uri = Uri.fromFile(new File(entity.getLocalPath()));
- String type = Attachment.getMimetypeForUri(dataBaseAdapter.getContext(), uri);
+ String type = dataBaseAdapter.getContext().getContentResolver().getType(uri);
serverAdapter.updateAttachment(board.getId(), stack.getId(), card.getId(), entity.getId(), type, uri, callback);
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java
index cb9d8e28b..2e31d3e14 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/SelectCardActivity.java
@@ -1,7 +1,9 @@
package it.niedermann.nextcloud.deck.ui;
+import android.content.ContentResolver;
import android.content.Intent;
import android.graphics.Typeface;
+import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.view.Menu;
@@ -13,6 +15,8 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
+import java.io.File;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -20,13 +24,14 @@ import java.util.Objects;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
+import it.niedermann.nextcloud.deck.exceptions.UploadAttachmentFailedException;
import it.niedermann.nextcloud.deck.model.Board;
import it.niedermann.nextcloud.deck.model.full.FullCard;
import it.niedermann.nextcloud.deck.ui.branding.BrandedAlertDialogBuilder;
import it.niedermann.nextcloud.deck.ui.card.SelectCardListener;
import it.niedermann.nextcloud.deck.util.ExceptionUtil;
-import static it.niedermann.nextcloud.deck.util.AttachmentUtil.appendAttachment;
+import static it.niedermann.nextcloud.deck.util.AttachmentUtil.copyContentUriToTempFile;
import static it.niedermann.nextcloud.deck.util.ClipboardUtil.copyToClipboard;
public class SelectCardActivity extends MainActivity implements SelectCardListener {
@@ -77,7 +82,30 @@ public class SelectCardActivity extends MainActivity implements SelectCardListen
public void onCardSelected(FullCard fullCard) {
try {
if (isFile) {
- appendAttachment(this, syncManager, mStreamsToUpload, fullCard);
+ for (Parcelable sourceStream : mStreamsToUpload) {
+ new Thread(() -> {
+ if (!(sourceStream instanceof Uri)) {
+ DeckLog.logError(new UploadAttachmentFailedException("stream is not of type " + Uri.class.getSimpleName()));
+ return;
+ }
+ Uri sourceUri = (Uri) sourceStream;
+ if (!ContentResolver.SCHEME_CONTENT.equals(sourceUri.getScheme())) {
+ DeckLog.logError(new UploadAttachmentFailedException("Unhandled URI scheme: " + sourceUri.getScheme()));
+ return;
+ }
+
+ try {
+ File copiedFile = copyContentUriToTempFile(this, sourceUri, fullCard.getAccountId(), fullCard.getCard().getLocalId());
+ String mimeType = getContentResolver().getType(sourceUri);
+ if (mimeType == null) {
+ mimeType = "application/octet-stream";
+ }
+ syncManager.addAttachmentToCard(fullCard.getAccountId(), fullCard.getCard().getLocalId(), mimeType, copiedFile);
+ } catch (IOException e) {
+ DeckLog.logError(new UploadAttachmentFailedException("Error while uploading attachment", e));
+ }
+ }).start();
+ }
} else {
appendText(fullCard, receivedText);
}
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
index b81411ced..2b2db42e7 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/card/attachments/CardAttachmentsFragment.java
@@ -22,6 +22,7 @@ import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.snackbar.Snackbar;
+import com.nextcloud.android.sso.exceptions.NextcloudHttpRequestFailedException;
import java.io.File;
import java.io.IOException;
@@ -32,6 +33,7 @@ import java.util.Map;
import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.FragmentCardEditTabAttachmentsBinding;
+import it.niedermann.nextcloud.deck.exceptions.UploadAttachmentFailedException;
import it.niedermann.nextcloud.deck.model.Attachment;
import it.niedermann.nextcloud.deck.model.enums.DBStatus;
import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
@@ -39,12 +41,14 @@ import it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.WrappedLiv
import it.niedermann.nextcloud.deck.ui.branding.BrandedFragment;
import it.niedermann.nextcloud.deck.ui.branding.BrandedSnackbar;
import it.niedermann.nextcloud.deck.ui.card.EditCardViewModel;
+import it.niedermann.nextcloud.deck.ui.exception.ExceptionDialogFragment;
import static it.niedermann.nextcloud.deck.persistence.sync.adapters.db.util.LiveDataHelper.observeOnce;
import static it.niedermann.nextcloud.deck.ui.branding.BrandedActivity.applyBrandToFAB;
import static it.niedermann.nextcloud.deck.ui.card.attachments.CardAttachmentAdapter.VIEW_TYPE_DEFAULT;
import static it.niedermann.nextcloud.deck.ui.card.attachments.CardAttachmentAdapter.VIEW_TYPE_IMAGE;
import static it.niedermann.nextcloud.deck.util.AttachmentUtil.copyContentUriToTempFile;
+import static java.net.HttpURLConnection.HTTP_CONFLICT;
public class CardAttachmentsFragment extends BrandedFragment implements AttachmentDeletedListener, AttachmentClickedListener {
@@ -158,31 +162,27 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_CODE_ADD_ATTACHMENT && resultCode == Activity.RESULT_OK) {
if (data == null) {
- DeckLog.warn("data is null");
+ ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("Intent data is null"), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
return;
}
final Uri sourceUri = data.getData();
if (sourceUri == null) {
- DeckLog.warn("data.getParcelableExtra(Intent.EXTRA_STREAM() returned null");
+ ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("sourceUri is null"), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ return;
+ }
+ if (!ContentResolver.SCHEME_CONTENT.equals(sourceUri.getScheme())) {
+ ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("Unknown URI scheme: " + sourceUri.getScheme()), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
return;
}
- DeckLog.info("Uri: " + sourceUri.toString());
+ DeckLog.verbose("--- found content URL " + sourceUri.getPath());
File fileToUpload;
- if (ContentResolver.SCHEME_CONTENT.equals(sourceUri.getScheme())) {
- DeckLog.verbose("--- found content URL " + sourceUri.getPath());
- try {
- DeckLog.verbose("---- so, now copy&upload: " + sourceUri.getPath());
- fileToUpload = copyContentUriToTempFile(requireContext(), sourceUri, viewModel.getAccount().getId(), viewModel.getFullCard().getCard().getLocalId());
- } catch (IOException e) {
- // TODO error popup
- e.printStackTrace();
- return;
- }
- } else {
- // TODO error popup
- DeckLog.warn("can not handle file");
+ try {
+ DeckLog.verbose("---- so, now copy & upload: " + sourceUri.getPath());
+ fileToUpload = copyContentUriToTempFile(requireContext(), sourceUri, viewModel.getAccount().getId(), viewModel.getFullCard().getCard().getLocalId());
+ } catch (IOException e) {
+ ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("Could not copy content URI to temporary file", e), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
return;
}
@@ -196,7 +196,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
final Date now = new Date();
final Attachment a = new Attachment();
- a.setMimetype(Attachment.getMimetypeForUri(getContext(), sourceUri));
+ a.setMimetype(requireContext().getContentResolver().getType(sourceUri));
a.setData(fileToUpload.getName());
a.setFilename(fileToUpload.getName());
a.setBasename(fileToUpload.getName());
@@ -208,12 +208,17 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
viewModel.getFullCard().getAttachments().add(a);
adapter.addAttachment(a);
if (!viewModel.isCreateMode()) {
- WrappedLiveData<Attachment> liveData = syncManager.addAttachmentToCard(viewModel.getAccount().getId(), viewModel.getFullCard().getLocalId(), Attachment.getMimetypeForUri(getContext(), sourceUri), fileToUpload);
+ WrappedLiveData<Attachment> liveData = syncManager.addAttachmentToCard(viewModel.getAccount().getId(), viewModel.getFullCard().getLocalId(), a.getMimetype(), fileToUpload);
observeOnce(liveData, getViewLifecycleOwner(), (next) -> {
if (liveData.hasError()) {
- viewModel.getFullCard().getAttachments().remove(a);
- adapter.removeAttachment(a);
- BrandedSnackbar.make(binding.coordinatorLayout, R.string.attachment_already_exists, Snackbar.LENGTH_LONG).show();
+ Throwable t = liveData.getError();
+ if (t instanceof NextcloudHttpRequestFailedException && ((NextcloudHttpRequestFailedException) t).getStatusCode() == HTTP_CONFLICT) {
+ viewModel.getFullCard().getAttachments().remove(a);
+ adapter.removeAttachment(a);
+ BrandedSnackbar.make(binding.coordinatorLayout, R.string.attachment_already_exists, Snackbar.LENGTH_LONG).show();
+ } else {
+ ExceptionDialogFragment.newInstance(new UploadAttachmentFailedException("Unknown URI scheme", t), viewModel.getAccount()).show(getChildFragmentManager(), ExceptionDialogFragment.class.getSimpleName());
+ }
} else {
viewModel.getFullCard().getAttachments().remove(a);
adapter.removeAttachment(a);
@@ -224,6 +229,7 @@ public class CardAttachmentsFragment extends BrandedFragment implements Attachme
}
updateEmptyContentView();
}
+
}
@Override
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java
index 7d2d0c983..9ab9b70c8 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/ui/exception/ExceptionDialogFragment.java
@@ -28,6 +28,7 @@ import it.niedermann.nextcloud.deck.DeckLog;
import it.niedermann.nextcloud.deck.R;
import it.niedermann.nextcloud.deck.databinding.DialogExceptionBinding;
import it.niedermann.nextcloud.deck.exceptions.DeckException;
+import it.niedermann.nextcloud.deck.exceptions.UploadAttachmentFailedException;
import it.niedermann.nextcloud.deck.model.Account;
import it.niedermann.nextcloud.deck.ui.exception.tips.TipsAdapter;
import it.niedermann.nextcloud.deck.util.ExceptionUtil;
@@ -113,6 +114,8 @@ public class ExceptionDialogFragment extends AppCompatDialogFragment {
adapter.add(R.string.error_dialog_insufficient_storage);
break;
}
+ } else if (throwable instanceof UploadAttachmentFailedException) {
+ adapter.add(R.string.error_dialog_attachment_upload_failed);
} else if (throwable instanceof DeckException) {
switch (((DeckException) throwable).getHint()) {
case CAPABILITIES_VERSION_NOT_PARSABLE:
diff --git a/app/src/main/java/it/niedermann/nextcloud/deck/util/AttachmentUtil.java b/app/src/main/java/it/niedermann/nextcloud/deck/util/AttachmentUtil.java
index 5addd0c34..6d8280bec 100644
--- a/app/src/main/java/it/niedermann/nextcloud/deck/util/AttachmentUtil.java
+++ b/app/src/main/java/it/niedermann/nextcloud/deck/util/AttachmentUtil.java
@@ -1,9 +1,7 @@
package it.niedermann.nextcloud.deck.util;
-import android.content.ContentResolver;
import android.content.Context;
import android.net.Uri;
-import android.os.Parcelable;
import androidx.annotation.NonNull;
@@ -12,11 +10,8 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.util.List;
import it.niedermann.nextcloud.deck.DeckLog;
-import it.niedermann.nextcloud.deck.model.full.FullCard;
-import it.niedermann.nextcloud.deck.persistence.sync.SyncManager;
/**
* Created by stefan on 07.03.20.
@@ -31,34 +26,6 @@ public class AttachmentUtil {
return accountUrl + "/index.php/apps/deck/cards/" + cardRemoteId + "/attachment/" + attachmentRemoteId;
}
- public static void appendAttachment(@NonNull Context context, @NonNull SyncManager syncManager, @NonNull List<Parcelable> streamsToUpload, @NonNull FullCard fullCard) {
- for (Parcelable sourceStream : streamsToUpload) {
- new Thread(() -> {
- Uri sourceUri = (Uri) sourceStream;
- if (sourceUri != null) {
- if (ContentResolver.SCHEME_CONTENT.equals(sourceUri.getScheme())) {
- /// content: uris will be copied to temporary files before calling {@link FileUploader}
- try {
- DeckLog.verbose("---- so, now copy & upload: " + sourceUri.getPath());
- File copiedFile = copyContentUriToTempFile(context, sourceUri, fullCard.getAccountId(), fullCard.getCard().getLocalId());
- String mimeType = context.getContentResolver().getType(sourceUri);
- if (mimeType == null) {
- mimeType = "application/octet-stream";
- }
- syncManager.addAttachmentToCard(fullCard.getAccountId(), fullCard.getCard().getLocalId(), mimeType, copiedFile);
- } catch (IOException e) {
- e.printStackTrace();
- }
- DeckLog.verbose("--- found content URL, remember for later: " + sourceUri.getPath());
- } else { //if (ContentResolver.SCHEME_FILE.equals(sourceUri.getScheme())) {
- // TODO can not handle this type
- DeckLog.verbose("--- found file URL, directly upload: " + sourceUri.getPath());
- }
- }
- }).start();
- }
- }
-
public static File copyContentUriToTempFile(@NonNull Context context, @NonNull Uri currentUri, long accountId, Long localId) throws IOException {
String fullTempPath = context.getApplicationContext().getFilesDir().getAbsolutePath() + "/attachments/account-" + accountId + "/card-" + (localId == null ? "pending-creation" : localId) + '/' + UriUtils.getDisplayNameForUri(currentUri, context);
DeckLog.verbose("----- fullTempPath: " + fullTempPath);
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index d0481bc04..c2441fc93 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -117,10 +117,10 @@
<string name="url_license" translatable="false">https://github.com/stefan-niedermann/nextcloud-deck/blob/master/LICENSE</string>
<string name="url_translations" translatable="false">https://www.transifex.com/nextcloud/nextcloud/</string>
<string name="url_about_icons_disclaimer_mdi" translatable="false">https://materialdesignicons.com/</string>
- <string name="url_fragment_update_deck" translatable="false">/index.php/settings/apps/installed/deck</string>
- <string name="url_fragment_install_deck" translatable="false">/index.php/settings/apps/organization/deck</string>
- <string name="url_fragment_server_logs" translatable="false">/index.php/settings/admin/logging</string>
- <string name="url_fragment_share_card_pre_1_0_0" translatable="false">/index.php/apps/deck/#!/board/%1$d/card/%2$d</string>
+ <string name="url_fragment_update_deck" translatable="false">/index.php/settings/apps/installed/deck</string>
+ <string name="url_fragment_install_deck" translatable="false">/index.php/settings/apps/organization/deck</string>
+ <string name="url_fragment_server_logs" translatable="false">/index.php/settings/admin/logging</string>
+ <string name="url_fragment_share_card_pre_1_0_0" translatable="false">/index.php/apps/deck/#!/board/%1$d/card/%2$d</string>
<string name="url_fragment_share_card_since_1_0_0" translatable="false">/index.php/apps/deck/#/board/%1$d/card/%2$d</string>
<string name="card_edit_details">Details</string>
@@ -255,6 +255,7 @@
<string name="error_dialog_redirect">Your server did respond with a HTTP 302 status code, which implies, that you do not have installed the Deck app on your server or something is misconfigured. This can be caused by custom overrides in a .htaccess-file or by Nextcloud apps like OID Client.</string>
<string name="error_dialog_version_not_parsable">We could not determine the version of the server side Deck app. Please make sure it is installed and enabled.</string>
<string name="error_dialog_capabilities_not_parsable">We could not fetch the capabilities of your server. Please make sure your server is running well and other client apps are able to access Nextcloud.</string>
+ <string name="error_dialog_attachment_upload_failed">An attachment could not be uploaded. Please try to share it on another way and let us know about this bug.</string>
<string name="error_action_open_deck_info">Open App info</string>
<string name="error_action_open_network">Network settings</string>
<string name="error_action_server_logs">Server logs</string>