Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 Alper Ozturk <alper.ozturk@nextcloud.com>

* SPDX-License-Identifier: MIT
*/

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025-2026 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2023 Álvaro Brey <alvaro.brey@nextcloud.com>
Expand Down Expand Up @@ -682,6 +683,12 @@ class WebdavEntry constructor(
const val SHAREES_SHARE_TYPE = "type"
const val PROPERTY_QUOTA_USED_BYTES = "quota-used-bytes"
const val PROPERTY_QUOTA_AVAILABLE_BYTES = "quota-available-bytes"
const val PROPERTY_LAST_PHOTO = "last-photo"
const val PROPERTY_NB_ITEMS = "nbItems"
const val PROPERTY_LOCATION = "location"
const val PROPERTY_DATE_RANGE = "dateRange"
const val PROPERTY_COLLABORATORS = "collaborators"
const val COLLABORATORS_SHARE_LABEL = "label"
private const val IS_ENCRYPTED = "1"
private const val CODE_PROP_NOT_FOUND = 404
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2018-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2023 Alper Ozturk <alper.ozturk@nextcloud.com>
* SPDX-FileCopyrightText: 2022 Álvaro Brey <alvaro.brey@nextcloud.com>
Expand Down Expand Up @@ -222,6 +223,20 @@ public static DavPropertyNameSet getChunksPropSet() {
return propSet;
}

public static DavPropertyNameSet getAlbumPropSet() {
DavPropertyNameSet propertySet = new DavPropertyNameSet();
Namespace ncNamespace = Namespace.getNamespace("nc",WebdavEntry.NAMESPACE_NC);

propertySet.add(DavPropertyName.create(WebdavEntry.PROPERTY_LAST_PHOTO,ncNamespace));
propertySet.add(DavPropertyName.create(WebdavEntry.PROPERTY_NB_ITEMS, ncNamespace));
propertySet.add(DavPropertyName.create(WebdavEntry.PROPERTY_LOCATION, ncNamespace));
propertySet.add(DavPropertyName.create(WebdavEntry.PROPERTY_DATE_RANGE, ncNamespace));
propertySet.add(DavPropertyName.create(WebdavEntry.PROPERTY_COLLABORATORS, ncNamespace));

return propertySet;
}


/**
*
* @param rawEtag
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2026 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-FileCopyrightText: 2017-2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2017 Mario Danic <mario@lovelyhq.com>
* SPDX-License-Identifier: MIT
*/
package com.owncloud.android.lib.common.utils;

import android.net.Uri;

import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.network.WebdavEntry;
import com.owncloud.android.lib.resources.files.model.RemoteFile;
Expand All @@ -15,6 +18,8 @@
import org.apache.jackrabbit.webdav.MultiStatusResponse;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* WebDav helper.
Expand Down Expand Up @@ -59,4 +64,38 @@ public ArrayList<RemoteFile> readData(MultiStatus remoteData,

return mFolderAndFiles;
}

/**
* Read the data retrieved from the server about the contents of the target folder
*
* @param remoteData Full response got from the server with the data of the target
* folder and its direct children.
* @param client Client instance to the remote server where the data were
* retrieved.
* @return list of remote file
*/
public List<RemoteFile> readAlbumData(MultiStatus remoteData, OwnCloudClient client) {
String baseUrl = client.getBaseUri() + "/remote.php/dav/photos/" + client.getUserId();
Uri uri = Uri.parse(baseUrl);
if (uri == null) {
return Collections.emptyList();
}

String encodedPath = uri.getEncodedPath();
if (encodedPath == null) {
return Collections.emptyList();
}

final var responses = remoteData.getResponses();
List<RemoteFile> files = new ArrayList<>(Math.max(0, responses.length - 1));

// reading from 1 as 0th item will be just the root album path
for (int i = 1; i < responses.length; i++) {
WebdavEntry entry = new WebdavEntry(responses[i], encodedPath);
RemoteFile remoteFile = new RemoteFile(entry);
files.add(remoteFile);
}

return files;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2026 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: MIT
*/
package com.owncloud.android.lib.resources.albums

import android.util.Log
import com.nextcloud.common.SessionTimeOut
import com.nextcloud.common.defaultSessionTimeOut
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.network.WebdavUtils
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
import org.apache.commons.httpclient.HttpStatus
import org.apache.jackrabbit.webdav.DavException
import org.apache.jackrabbit.webdav.Status
import org.apache.jackrabbit.webdav.client.methods.CopyMethod
import java.io.IOException

/**
* Remote operation moving a remote file or folder in the ownCloud server to a different folder
* in the same account.
*
*
* Allows renaming the moving file/folder at the same time.
*/
class CopyFileToAlbumRemoteOperation @JvmOverloads constructor(
private val mSrcRemotePath: String,
private val mTargetRemotePath: String,
private val sessionTimeOut: SessionTimeOut = defaultSessionTimeOut
) :
RemoteOperation<Any>() {
/**
* Performs the operation.
*
* @param client Client object to communicate with the remote ownCloud server.
*/
@Deprecated("Deprecated in Java")
@Suppress("TooGenericExceptionCaught")
override fun run(client: OwnCloudClient): RemoteOperationResult<Any> {
/** check parameters */

var result: RemoteOperationResult<Any>
if (mTargetRemotePath == mSrcRemotePath) {
// nothing to do!
result = RemoteOperationResult(ResultCode.OK)
} else {
/** perform remote operation */
var copyMethod: CopyMethod? = null
try {
copyMethod = CopyMethod(
client.getFilesDavUri(this.mSrcRemotePath),
"${client.baseUri}/remote.php/dav/photos/${client.userId}/albums${
WebdavUtils.encodePath(
mTargetRemotePath
)
}",
false
)
val status = client.executeMethod(
copyMethod,
sessionTimeOut.readTimeOut,
sessionTimeOut.connectionTimeOut
)

/** process response */
result = when (status) {
HttpStatus.SC_MULTI_STATUS -> processPartialError(copyMethod)
HttpStatus.SC_PRECONDITION_FAILED -> {
client.exhaustResponse(copyMethod.responseBodyAsStream)
RemoteOperationResult<Any>(ResultCode.INVALID_OVERWRITE)
}

else -> {
client.exhaustResponse(copyMethod.responseBodyAsStream)
RemoteOperationResult<Any>(isSuccess(status), copyMethod)
}
}

Log.i(
TAG,
"Copy $mSrcRemotePath to $mTargetRemotePath : ${result.logMessage}"
)
} catch (e: Exception) {
result = RemoteOperationResult<Any>(e)
Log.e(
TAG,
"Copy $mSrcRemotePath to $mTargetRemotePath : ${result.logMessage}", e
)
} finally {
copyMethod?.releaseConnection()
}
}

return result
}

/**
* Analyzes a multistatus response from the OC server to generate an appropriate result.
*
*
* In WebDAV, a COPY request on collections (folders) can be PARTIALLY successful: some
* children are copied, some other aren't.
*
*
* According to the WebDAV specification, a multistatus response SHOULD NOT include partial
* successes (201, 204) nor for descendants of already failed children (424) in the response
* entity. But SHOULD NOT != MUST NOT, so take carefully.
*
* @param copyMethod Copy operation just finished with a multistatus response
* @return A result for the [CopyFileToAlbumRemoteOperation] caller
* @throws java.io.IOException If the response body could not be parsed
* @throws org.apache.jackrabbit.webdav.DavException If the status code is other than MultiStatus or if obtaining
* the response XML document fails
*/
@Throws(IOException::class, DavException::class)
private fun processPartialError(copyMethod: CopyMethod): RemoteOperationResult<Any> {
// Adding a list of failed descendants to the result could be interesting; or maybe not.
// For the moment, let's take the easy way.
/** check that some error really occurred */

val responses = copyMethod.responseBodyAsMultiStatus.responses
var status: Array<Status>?
var failFound = false
var i = 0
while (i < responses.size && !failFound) {
status = responses[i].status
failFound = (!status.isNullOrEmpty() && status[0].statusCode > FAILED_STATUS_CODE
)
i++
}
val result: RemoteOperationResult<Any> = if (failFound) {
RemoteOperationResult<Any>(ResultCode.PARTIAL_COPY_DONE)
} else {
RemoteOperationResult<Any>(true, copyMethod)
}

return result
}

private fun isSuccess(status: Int): Boolean {
return status == HttpStatus.SC_CREATED || status == HttpStatus.SC_NO_CONTENT
}

companion object {
private val TAG: String = CopyFileToAlbumRemoteOperation::class.java.simpleName
private const val FAILED_STATUS_CODE = 299
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2025 TSI-mc <surinder.kumar@t-systems.com>
* SPDX-License-Identifier: MIT
*/
package com.owncloud.android.lib.resources.albums

import com.nextcloud.common.SessionTimeOut
import com.nextcloud.common.defaultSessionTimeOut
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.network.WebdavUtils
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import org.apache.commons.httpclient.HttpStatus
import org.apache.jackrabbit.webdav.client.methods.MkColMethod

class CreateNewAlbumRemoteOperation
@JvmOverloads
constructor(
val newAlbumName: String,
private val sessionTimeOut: SessionTimeOut = defaultSessionTimeOut
) : RemoteOperation<Void>() {
/**
* Performs the operation.
*
* @param client Client object to communicate with the remote ownCloud server.
*/
@Deprecated("Deprecated in Java")
@Suppress("TooGenericExceptionCaught")
override fun run(client: OwnCloudClient): RemoteOperationResult<Void> {
var mkCol: MkColMethod? = null
var result: RemoteOperationResult<Void>
try {
mkCol =
MkColMethod(
"${client.baseUri}/remote.php/dav/photos/${client.userId}/albums${
WebdavUtils.encodePath(
newAlbumName
)
}"
)
client.executeMethod(
mkCol,
sessionTimeOut.readTimeOut,
sessionTimeOut.connectionTimeOut
)
if (HttpStatus.SC_METHOD_NOT_ALLOWED == mkCol.statusCode) {
result =
RemoteOperationResult(RemoteOperationResult.ResultCode.FOLDER_ALREADY_EXISTS)
} else {
result = RemoteOperationResult(mkCol.succeeded(), mkCol)
result.resultData = null
}

Log_OC.d(TAG, "Create album $newAlbumName : ${result.logMessage}")
client.exhaustResponse(mkCol.responseBodyAsStream)
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(TAG, "Create album $newAlbumName : ${result.logMessage}", e)
} finally {
mkCol?.releaseConnection()
}

return result
}

companion object {
private val TAG: String = CreateNewAlbumRemoteOperation::class.java.simpleName
}
}
Loading