diff --git a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt index 573269baf..709e44473 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/UploadAndShareFilesWorker.kt @@ -151,7 +151,7 @@ class UploadAndShareFilesWorker(val context: Context, workerParameters: WorkerPa } else { Log.d(TAG, "starting normal upload (not chunked) of $fileName") - FileUploader(context, currentUser, roomToken, ncApi) + FileUploader(okHttpClient, context, currentUser, roomToken, ncApi, file!!) .upload(sourceFileUri, fileName, remotePath, metaData) .blockingFirst() } diff --git a/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt b/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt index 2c796df63..a62c8e9f4 100644 --- a/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt +++ b/app/src/main/java/com/nextcloud/talk/upload/normal/FileUploader.kt @@ -10,7 +10,10 @@ package com.nextcloud.talk.upload.normal import android.content.Context import android.net.Uri import android.util.Log +import at.bitfire.dav4jvm.DavResource +import at.bitfire.dav4jvm.exception.HttpException import com.nextcloud.talk.api.NcApi +import com.nextcloud.talk.dagger.modules.RestModule import com.nextcloud.talk.data.user.model.User import com.nextcloud.talk.jobs.ShareOperationWorker import com.nextcloud.talk.utils.ApiUtils @@ -18,24 +21,48 @@ import com.nextcloud.talk.utils.FileUtils import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers import io.reactivex.schedulers.Schedulers +import okhttp3.HttpUrl.Companion.toHttpUrlOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull +import okhttp3.OkHttpClient +import okhttp3.Protocol import okhttp3.RequestBody +import okhttp3.Response +import java.io.File +import java.io.IOException import java.io.InputStream class FileUploader( + okHttpClient: OkHttpClient, val context: Context, val currentUser: User, val roomToken: String, - val ncApi: NcApi + val ncApi: NcApi, + val file: File ) { + + private var okHttpClientNoRedirects: OkHttpClient? = null + private var okhttpClient: OkHttpClient = okHttpClient + + init { + initHttpClient(okHttpClient, currentUser) + } + fun upload(sourceFileUri: Uri, fileName: String, remotePath: String, metaData: String?): Observable { return ncApi.uploadFile( - ApiUtils.getCredentials(currentUser.username, currentUser.token), - ApiUtils.getUrlForFileUpload(currentUser.baseUrl!!, currentUser.userId!!, remotePath), + ApiUtils.getCredentials( + currentUser.username, + currentUser.token + ), + ApiUtils.getUrlForFileUpload( + currentUser.baseUrl!!, + currentUser.userId!!, + remotePath + ), createRequestBody(sourceFileUri) ) .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()).map { response -> + .observeOn(AndroidSchedulers.mainThread()) + .flatMap { response -> if (response.isSuccessful) { ShareOperationWorker.shareFile( roomToken, @@ -44,13 +71,52 @@ class FileUploader( metaData ) FileUtils.copyFileToCache(context, sourceFileUri, fileName) - true + Observable.just(true) } else { - false + if (response.code() == HTTP_CODE_NOT_FOUND || + response.code() == HTTP_CODE_CONFLICT + ) { + createDavResource(sourceFileUri, fileName, remotePath, metaData) + } else { + Observable.just(false) + } } } } + private fun createDavResource( + sourceFileUri: Uri, + fileName: String, + remotePath: String, + metaData: String? + ): Observable { + return Observable.fromCallable { + val userFileUploadPath = ApiUtils.userFileUploadPath( + currentUser.baseUrl!!, + currentUser.userId!! + ) + val userTalkAttachmentsUploadPath = ApiUtils.userTalkAttachmentsUploadPath( + currentUser.baseUrl!!, + currentUser.userId!! + ) + + var davResource = DavResource( + okHttpClientNoRedirects!!, + userFileUploadPath.toHttpUrlOrNull()!! + ) + createFolder(davResource) + initHttpClient(okHttpClient = okhttpClient, currentUser) + davResource = DavResource( + okHttpClientNoRedirects!!, + userTalkAttachmentsUploadPath.toHttpUrlOrNull()!! + ) + createFolder(davResource) + true + } + .subscribeOn(Schedulers.io()) + .flatMap { upload(sourceFileUri, fileName, remotePath, metaData) } + } + @Suppress("Detekt.TooGenericExceptionCaught") private fun createRequestBody(sourceFileUri: Uri): RequestBody? { var requestBody: RequestBody? = null @@ -68,7 +134,49 @@ class FileUploader( return requestBody } + private fun initHttpClient(okHttpClient: OkHttpClient, currentUser: User) { + val okHttpClientBuilder: OkHttpClient.Builder = okHttpClient.newBuilder() + okHttpClientBuilder.followRedirects(false) + okHttpClientBuilder.followSslRedirects(false) + okHttpClientBuilder.protocols(listOf(Protocol.HTTP_1_1)) + okHttpClientBuilder.authenticator( + RestModule.HttpAuthenticator( + ApiUtils.getCredentials( + currentUser.username, + currentUser.token + )!!, + "Authorization" + ) + ) + this.okHttpClientNoRedirects = okHttpClientBuilder.build() + } + + @Suppress("Detekt.ThrowsCount") + private fun createFolder(davResource: DavResource) { + try { + davResource.mkCol( + xmlBody = null + ) { response: Response -> + + if (!response.isSuccessful) { + throw IOException("failed to create folder. response code: " + response.code) + } + } + } catch (e: IOException) { + throw IOException("failed to create folder", e) + } catch (e: HttpException) { + if (e.code == METHOD_NOT_ALLOWED_CODE) { + Log.d(TAG, "Folder most probably already exists, that's okay, just continue..") + } else { + throw IOException("failed to create folder", e) + } + } + } + companion object { private val TAG = FileUploader::class.simpleName + private const val METHOD_NOT_ALLOWED_CODE: Int = 405 + private const val HTTP_CODE_NOT_FOUND: Int = 404 + private const val HTTP_CODE_CONFLICT: Int = 409 } } diff --git a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt index 755e8959b..66cb5b2cb 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/ApiUtils.kt @@ -459,6 +459,14 @@ object ApiUtils { return "$baseUrl/remote.php/dav/files/$user/$remotePath" } + fun userFileUploadPath(baseUrl: String, user: String): String { + return "$baseUrl/remote.php/dav/files/$user" + } + + fun userTalkAttachmentsUploadPath(baseUrl: String, user: String): String { + return "$baseUrl/remote.php/dav/files/$user/Talk" + } + fun getUrlForTempAvatar(baseUrl: String): String { return "$baseUrl$OCS_API_VERSION/apps/spreed/temp-user-avatar" } diff --git a/app/src/main/res/layout/activity_conversation_info.xml b/app/src/main/res/layout/activity_conversation_info.xml index 9da666b8b..f67dac31e 100644 --- a/app/src/main/res/layout/activity_conversation_info.xml +++ b/app/src/main/res/layout/activity_conversation_info.xml @@ -90,6 +90,35 @@ + + + + + + + + + + - - - - - - - - - -