mirror of
https://github.com/owncloud/android-library.git
synced 2025-06-09 17:06:18 +00:00
commit
c36096d08c
@ -1,6 +1,6 @@
|
|||||||
buildscript {
|
buildscript {
|
||||||
ext {
|
ext {
|
||||||
kotlinVersion = '1.3.72'
|
kotlinVersion = '1.4.20'
|
||||||
moshiVersion = "1.9.2"
|
moshiVersion = "1.9.2"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -9,9 +9,8 @@ buildscript {
|
|||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.0.1'
|
classpath 'com.android.tools.build:gradle:4.1.1'
|
||||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||||
classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlinVersion"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
org.gradle.jvmargs=-Xmx1536M
|
org.gradle.jvmargs=-Xmx1536M
|
||||||
|
@ -1,25 +1,20 @@
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
apply plugin: 'kotlin-kapt'
|
apply plugin: 'kotlin-kapt'
|
||||||
apply plugin: 'kotlin-allopen'
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
api 'com.squareup.okhttp3:okhttp:4.6.0'
|
api 'com.squareup.okhttp3:okhttp:4.6.0'
|
||||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
|
||||||
api 'com.gitlab.ownclouders:dav4android:oc_support_2.1.5'
|
api 'com.gitlab.ownclouders:dav4android:oc_support_2.1.5'
|
||||||
api 'com.github.AppDevNext.Logcat:LogcatCore:2.1.1'
|
api 'com.github.AppDevNext.Logcat:LogcatCore:2.2.2'
|
||||||
api 'net.openid:appauth:0.7.1'
|
|
||||||
|
|
||||||
// Moshi
|
// Moshi
|
||||||
implementation ("com.squareup.moshi:moshi-kotlin:$moshiVersion") {
|
implementation ("com.squareup.moshi:moshi-kotlin:$moshiVersion") {
|
||||||
exclude module: "kotlin-reflect"
|
exclude module: "kotlin-reflect"
|
||||||
}
|
}
|
||||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
|
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
|
||||||
}
|
|
||||||
|
|
||||||
allOpen {
|
testImplementation 'junit:junit:4.13.1'
|
||||||
// allows mocking for classes w/o directly opening them for release builds
|
|
||||||
annotation 'com.owncloud.android.lib.testing.OpenClass'
|
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
@ -29,12 +24,8 @@ android {
|
|||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 29
|
targetSdkVersion 29
|
||||||
|
|
||||||
versionCode = 10000800
|
versionCode = 10000900
|
||||||
versionName = "1.0.8"
|
versionName = "1.0.9"
|
||||||
|
|
||||||
// This is pretty ugly but manifest placeholders don't seem to work very well when using different modules
|
|
||||||
// See https://github.com/openid/AppAuth-Android/issues/325
|
|
||||||
manifestPlaceholders = [appAuthRedirectScheme: '']
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lintOptions {
|
lintOptions {
|
||||||
|
@ -57,6 +57,7 @@ public class HttpClient {
|
|||||||
private static OkHttpClient sOkHttpClient;
|
private static OkHttpClient sOkHttpClient;
|
||||||
private static Context sContext;
|
private static Context sContext;
|
||||||
private static HashMap<String, List<Cookie>> sCookieStore = new HashMap<>();
|
private static HashMap<String, List<Cookie>> sCookieStore = new HashMap<>();
|
||||||
|
private static LogInterceptor sLogInterceptor;
|
||||||
|
|
||||||
public static OkHttpClient getOkHttpClient() {
|
public static OkHttpClient getOkHttpClient() {
|
||||||
if (sOkHttpClient == null) {
|
if (sOkHttpClient == null) {
|
||||||
@ -110,6 +111,7 @@ public class HttpClient {
|
|||||||
};
|
};
|
||||||
|
|
||||||
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
|
OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder()
|
||||||
|
.addNetworkInterceptor(getLogInterceptor())
|
||||||
.protocols(Arrays.asList(Protocol.HTTP_1_1))
|
.protocols(Arrays.asList(Protocol.HTTP_1_1))
|
||||||
.readTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
|
.readTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
.writeTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
|
.writeTimeout(HttpConstants.DEFAULT_DATA_TIMEOUT, TimeUnit.MILLISECONDS)
|
||||||
@ -120,6 +122,7 @@ public class HttpClient {
|
|||||||
.cookieJar(cookieJar);
|
.cookieJar(cookieJar);
|
||||||
// TODO: Not verifying the hostname against certificate. ask owncloud security human if this is ok.
|
// TODO: Not verifying the hostname against certificate. ask owncloud security human if this is ok.
|
||||||
//.hostnameVerifier(new BrowserCompatHostnameVerifier());
|
//.hostnameVerifier(new BrowserCompatHostnameVerifier());
|
||||||
|
|
||||||
sOkHttpClient = clientBuilder.build();
|
sOkHttpClient = clientBuilder.build();
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
@ -137,6 +140,13 @@ public class HttpClient {
|
|||||||
sContext = context;
|
sContext = context;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static LogInterceptor getLogInterceptor() {
|
||||||
|
if (sLogInterceptor == null) {
|
||||||
|
sLogInterceptor = new LogInterceptor();
|
||||||
|
}
|
||||||
|
return sLogInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
public List<Cookie> getCookiesFromUrl(HttpUrl httpUrl) {
|
public List<Cookie> getCookiesFromUrl(HttpUrl httpUrl) {
|
||||||
return sCookieStore.get(httpUrl.host());
|
return sCookieStore.get(httpUrl.host());
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,14 @@ public class HttpConstants {
|
|||||||
public static final String ACCEPT_ENCODING_IDENTITY = "identity";
|
public static final String ACCEPT_ENCODING_IDENTITY = "identity";
|
||||||
public static final String OC_FILE_REMOTE_ID = "OC-FileId";
|
public static final String OC_FILE_REMOTE_ID = "OC-FileId";
|
||||||
|
|
||||||
|
/***********************************************************************************************************
|
||||||
|
************************************************ CONTENT TYPES ********************************************
|
||||||
|
***********************************************************************************************************/
|
||||||
|
|
||||||
|
public static final String CONTENT_TYPE_XML = "application/xml";
|
||||||
|
public static final String CONTENT_TYPE_JSON = "application/json";
|
||||||
|
public static final String CONTENT_TYPE_WWW_FORM = "application/x-www-form-urlencoded";
|
||||||
|
|
||||||
/***********************************************************************************************************
|
/***********************************************************************************************************
|
||||||
************************************************ STATUS CODES *********************************************
|
************************************************ STATUS CODES *********************************************
|
||||||
***********************************************************************************************************/
|
***********************************************************************************************************/
|
||||||
|
@ -0,0 +1,65 @@
|
|||||||
|
/* ownCloud Android Library is available under MIT license
|
||||||
|
* Copyright (C) 2020 ownCloud GmbH.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.owncloud.android.lib.common.http
|
||||||
|
|
||||||
|
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_JSON
|
||||||
|
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_WWW_FORM
|
||||||
|
import com.owncloud.android.lib.common.http.HttpConstants.CONTENT_TYPE_XML
|
||||||
|
import okhttp3.MediaType
|
||||||
|
import timber.log.Timber
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
object LogBuilder {
|
||||||
|
fun logHttp(
|
||||||
|
networkPetition: NetworkPetition,
|
||||||
|
networkNode: NetworkNode,
|
||||||
|
requestId: String? = "",
|
||||||
|
description: String
|
||||||
|
) = Timber.d("[Network, $networkPetition] [$networkNode] [$requestId] $description")
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class NetworkPetition {
|
||||||
|
REQUEST, RESPONSE;
|
||||||
|
|
||||||
|
override fun toString(): String = super.toString().toLowerCase(Locale.ROOT)
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class NetworkNode {
|
||||||
|
INFO, HEADER, BODY;
|
||||||
|
|
||||||
|
override fun toString(): String = super.toString().toLowerCase(Locale.ROOT)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether a media type is loggable.
|
||||||
|
*
|
||||||
|
* @return true if its type is text, xml, json, or x-www-form-urlencoded.
|
||||||
|
*/
|
||||||
|
fun MediaType?.isLoggable(): Boolean =
|
||||||
|
this?.let { mediaType ->
|
||||||
|
val mediaTypeString = mediaType.toString()
|
||||||
|
(mediaType.type == "text" ||
|
||||||
|
mediaTypeString.contains(CONTENT_TYPE_XML) ||
|
||||||
|
mediaTypeString.contains(CONTENT_TYPE_JSON) ||
|
||||||
|
mediaTypeString.contains(CONTENT_TYPE_WWW_FORM))
|
||||||
|
} ?: false
|
@ -0,0 +1,179 @@
|
|||||||
|
/* ownCloud Android Library is available under MIT license
|
||||||
|
* Copyright (C) 2020 ownCloud GmbH.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
package com.owncloud.android.lib.common.http
|
||||||
|
|
||||||
|
import com.owncloud.android.lib.common.http.HttpConstants.AUTHORIZATION_HEADER
|
||||||
|
import com.owncloud.android.lib.common.http.HttpConstants.OC_X_REQUEST_ID
|
||||||
|
import com.owncloud.android.lib.common.http.LogBuilder.logHttp
|
||||||
|
import com.owncloud.android.lib.common.http.NetworkNode.BODY
|
||||||
|
import com.owncloud.android.lib.common.http.NetworkNode.HEADER
|
||||||
|
import com.owncloud.android.lib.common.http.NetworkNode.INFO
|
||||||
|
import com.owncloud.android.lib.common.http.NetworkPetition.REQUEST
|
||||||
|
import com.owncloud.android.lib.common.http.NetworkPetition.RESPONSE
|
||||||
|
import okhttp3.Headers
|
||||||
|
import okhttp3.Interceptor
|
||||||
|
import okhttp3.RequestBody
|
||||||
|
import okhttp3.Response
|
||||||
|
import okhttp3.ResponseBody
|
||||||
|
import okio.Buffer
|
||||||
|
import java.nio.charset.Charset
|
||||||
|
import java.nio.charset.StandardCharsets
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
|
class LogInterceptor : Interceptor {
|
||||||
|
|
||||||
|
override fun intercept(chain: Interceptor.Chain): Response {
|
||||||
|
|
||||||
|
if (!httpLogsEnabled) {
|
||||||
|
return chain.proceed(chain.request())
|
||||||
|
}
|
||||||
|
|
||||||
|
val request = chain.request().also {
|
||||||
|
val requestId = it.headers[OC_X_REQUEST_ID]
|
||||||
|
logHttp(REQUEST, INFO, requestId, "Type: ${it.method} URL: ${it.url}")
|
||||||
|
logHeaders(requestId, it.headers, REQUEST)
|
||||||
|
logRequestBody(requestId, it.body)
|
||||||
|
}
|
||||||
|
|
||||||
|
val response = chain.proceed(request)
|
||||||
|
|
||||||
|
return response.also {
|
||||||
|
val requestId = it.request.headers[OC_X_REQUEST_ID]
|
||||||
|
logHttp(
|
||||||
|
RESPONSE,
|
||||||
|
INFO,
|
||||||
|
requestId,
|
||||||
|
"Code: ${it.code} Message: ${it.message} IsSuccessful: ${it.isSuccessful}"
|
||||||
|
)
|
||||||
|
logHeaders(requestId, it.headers, RESPONSE)
|
||||||
|
logResponseBody(requestId, it.body)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logHeaders(requestId: String?, headers: Headers, networkPetition: NetworkPetition) {
|
||||||
|
headers.forEach { header ->
|
||||||
|
val headerValue: String = if (header.first.equals(AUTHORIZATION_HEADER, true)) {
|
||||||
|
"[redacted]"
|
||||||
|
} else {
|
||||||
|
header.second
|
||||||
|
}
|
||||||
|
logHttp(networkPetition, HEADER, requestId, "${header.first}: $headerValue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logRequestBody(requestId: String?, requestBodyParam: RequestBody?) {
|
||||||
|
requestBodyParam?.let { requestBody ->
|
||||||
|
|
||||||
|
if (requestBody.isOneShot()) {
|
||||||
|
logHttp(REQUEST, BODY, requestId, "One shot body -- Omitted")
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
|
||||||
|
if (requestBody.isDuplex()) {
|
||||||
|
logHttp(REQUEST, BODY, requestId, "Duplex body -- Omitted")
|
||||||
|
return@let
|
||||||
|
}
|
||||||
|
|
||||||
|
val buffer = Buffer()
|
||||||
|
requestBody.writeTo(buffer)
|
||||||
|
|
||||||
|
val contentType = requestBody.contentType()
|
||||||
|
val charset: Charset = contentType?.charset(StandardCharsets.UTF_8) ?: StandardCharsets.UTF_8
|
||||||
|
|
||||||
|
logHttp(REQUEST, BODY, requestId, "Length: ${requestBody.contentLength()} byte body")
|
||||||
|
logHttp(REQUEST, BODY, requestId, "Type: ${requestBody.contentType()}")
|
||||||
|
logHttp(REQUEST, BODY, requestId, "--> Body start for request")
|
||||||
|
|
||||||
|
if (contentType.isLoggable()) {
|
||||||
|
if (requestBody.contentLength() < LIMIT_BODY_LOG) {
|
||||||
|
logHttp(REQUEST, BODY, requestId, buffer.readString(charset))
|
||||||
|
} else {
|
||||||
|
logHttp(REQUEST, BODY, requestId, buffer.readString(LIMIT_BODY_LOG, charset))
|
||||||
|
}
|
||||||
|
logHttp(
|
||||||
|
REQUEST,
|
||||||
|
BODY,
|
||||||
|
requestId,
|
||||||
|
"<-- Body end for request -- Omitted: ${max(0, requestBody.contentLength() - LIMIT_BODY_LOG)} bytes"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logHttp(
|
||||||
|
REQUEST,
|
||||||
|
BODY,
|
||||||
|
requestId,
|
||||||
|
"<-- Body end for request -- Binary -- Omitted: ${requestBody.contentLength()} bytes"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
} ?: logHttp(REQUEST, BODY, requestId, "Empty body")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logResponseBody(requestId: String?, responseBodyParam: ResponseBody?) {
|
||||||
|
responseBodyParam?.let { responseBody ->
|
||||||
|
|
||||||
|
val contentType = responseBody.contentType()
|
||||||
|
val charset: Charset = contentType?.charset(StandardCharsets.UTF_8) ?: StandardCharsets.UTF_8
|
||||||
|
|
||||||
|
logHttp(RESPONSE, BODY, requestId, "Length: ${responseBody.contentLength()} byte body")
|
||||||
|
logHttp(RESPONSE, BODY, requestId, "Type: ${responseBody.contentType()}")
|
||||||
|
logHttp(RESPONSE, BODY, requestId, "--> Body start for response")
|
||||||
|
|
||||||
|
val source = responseBody.source()
|
||||||
|
source.request(LIMIT_BODY_LOG)
|
||||||
|
val buffer = source.buffer
|
||||||
|
|
||||||
|
if (contentType.isLoggable()) {
|
||||||
|
|
||||||
|
if (responseBody.contentLength() < LIMIT_BODY_LOG) {
|
||||||
|
logHttp(RESPONSE, BODY, requestId, buffer.clone().readString(charset))
|
||||||
|
} else {
|
||||||
|
logHttp(RESPONSE, BODY, requestId, buffer.clone().readString(LIMIT_BODY_LOG, charset))
|
||||||
|
}
|
||||||
|
logHttp(
|
||||||
|
RESPONSE,
|
||||||
|
BODY,
|
||||||
|
requestId,
|
||||||
|
"<-- Body end for response -- Omitted: ${
|
||||||
|
max(
|
||||||
|
0,
|
||||||
|
responseBody.contentLength() - LIMIT_BODY_LOG
|
||||||
|
)
|
||||||
|
} bytes"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
logHttp(
|
||||||
|
RESPONSE,
|
||||||
|
BODY,
|
||||||
|
requestId,
|
||||||
|
"<-- Body end for response -- Binary -- Omitted: ${responseBody.contentLength()} bytes"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} ?: logHttp(RESPONSE, BODY, requestId, "Empty body")
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
var httpLogsEnabled: Boolean = false
|
||||||
|
private const val LIMIT_BODY_LOG: Long = 1024
|
||||||
|
}
|
||||||
|
}
|
@ -84,18 +84,12 @@ public class ChunkFromFileRequestBody extends FileRequestBody {
|
|||||||
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
|
long maxCount = Math.min(mOffset + mChunkSize, mChannel.size());
|
||||||
while (mChannel.position() < maxCount) {
|
while (mChannel.position() < maxCount) {
|
||||||
|
|
||||||
Timber.v("Sink buffer size: %s", sink.buffer().size());
|
|
||||||
|
|
||||||
readCount = mChannel.read(mBuffer);
|
readCount = mChannel.read(mBuffer);
|
||||||
|
|
||||||
Timber.v("Read " + readCount + " bytes from file channel to " + mBuffer.toString());
|
sink.getBuffer().write(mBuffer.array(), 0, readCount);
|
||||||
|
|
||||||
sink.buffer().write(mBuffer.array(), 0, readCount);
|
|
||||||
|
|
||||||
sink.flush();
|
sink.flush();
|
||||||
|
|
||||||
Timber.v("Write " + readCount + " bytes to sink buffer with size " + sink.buffer().size());
|
|
||||||
|
|
||||||
mBuffer.clear();
|
mBuffer.clear();
|
||||||
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
|
if (mTransferred < maxCount) { // condition to avoid accumulate progress for repeated chunks
|
||||||
mTransferred += readCount;
|
mTransferred += readCount;
|
||||||
|
@ -53,6 +53,11 @@ public class FileRequestBody extends RequestBody implements ProgressiveDataTrans
|
|||||||
mContentType = contentType;
|
mContentType = contentType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOneShot() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MediaType contentType() {
|
public MediaType contentType() {
|
||||||
return mContentType;
|
return mContentType;
|
||||||
|
@ -21,8 +21,9 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.lib.resources.response
|
package com.owncloud.android.lib.resources
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
// Response retrieved by OCS Rest API, used to obtain capabilities, shares and user info among others.
|
// Response retrieved by OCS Rest API, used to obtain capabilities, shares and user info among others.
|
||||||
@ -41,6 +42,11 @@ data class OCSResponse<T>(
|
|||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class MetaData(
|
data class MetaData(
|
||||||
val status: String,
|
val status: String,
|
||||||
val statuscode: Int,
|
@Json(name = "statuscode")
|
||||||
val message: String?
|
val statusCode: Int,
|
||||||
|
val message: String?,
|
||||||
|
@Json(name = "itemsperpage")
|
||||||
|
val itemsPerPage: String?,
|
||||||
|
@Json(name = "totalitems")
|
||||||
|
val totalItems: String?
|
||||||
)
|
)
|
@ -30,6 +30,8 @@ import java.io.File;
|
|||||||
|
|
||||||
public class FileUtils {
|
public class FileUtils {
|
||||||
public static final String FINAL_CHUNKS_FILE = ".file";
|
public static final String FINAL_CHUNKS_FILE = ".file";
|
||||||
|
public static final String MIME_DIR = "DIR";
|
||||||
|
public static final String MIME_DIR_UNIX = "httpd/unix-directory";
|
||||||
|
|
||||||
static String getParentPath(String remotePath) {
|
static String getParentPath(String remotePath) {
|
||||||
String parentPath = new File(remotePath).getParent();
|
String parentPath = new File(remotePath).getParent();
|
||||||
|
@ -29,7 +29,17 @@ import android.os.Parcelable;
|
|||||||
|
|
||||||
import at.bitfire.dav4jvm.Property;
|
import at.bitfire.dav4jvm.Property;
|
||||||
import at.bitfire.dav4jvm.Response;
|
import at.bitfire.dav4jvm.Response;
|
||||||
import at.bitfire.dav4jvm.property.*;
|
import at.bitfire.dav4jvm.property.CreationDate;
|
||||||
|
import at.bitfire.dav4jvm.property.GetContentLength;
|
||||||
|
import at.bitfire.dav4jvm.property.GetContentType;
|
||||||
|
import at.bitfire.dav4jvm.property.GetETag;
|
||||||
|
import at.bitfire.dav4jvm.property.GetLastModified;
|
||||||
|
import at.bitfire.dav4jvm.property.OCId;
|
||||||
|
import at.bitfire.dav4jvm.property.OCPermissions;
|
||||||
|
import at.bitfire.dav4jvm.property.OCPrivatelink;
|
||||||
|
import at.bitfire.dav4jvm.property.OCSize;
|
||||||
|
import at.bitfire.dav4jvm.property.QuotaAvailableBytes;
|
||||||
|
import at.bitfire.dav4jvm.property.QuotaUsedBytes;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
@ -83,7 +93,8 @@ public class RemoteFile implements Parcelable, Serializable {
|
|||||||
/**
|
/**
|
||||||
* Create new {@link RemoteFile} with given path.
|
* Create new {@link RemoteFile} with given path.
|
||||||
* <p>
|
* <p>
|
||||||
* The path received must be URL-decoded. Path separator must be File.separator, and it must be the first character in 'path'.
|
* The path received must be URL-decoded. Path separator must be File.separator, and it must be the first
|
||||||
|
* character in 'path'.
|
||||||
*
|
*
|
||||||
* @param path The remote path of the file.
|
* @param path The remote path of the file.
|
||||||
*/
|
*/
|
||||||
@ -95,7 +106,7 @@ public class RemoteFile implements Parcelable, Serializable {
|
|||||||
mRemotePath = path;
|
mRemotePath = path;
|
||||||
mCreationTimestamp = 0;
|
mCreationTimestamp = 0;
|
||||||
mLength = 0;
|
mLength = 0;
|
||||||
mMimeType = "DIR";
|
mMimeType = FileUtils.MIME_DIR;
|
||||||
mQuotaUsedBytes = BigDecimal.ZERO;
|
mQuotaUsedBytes = BigDecimal.ZERO;
|
||||||
mQuotaAvailableBytes = BigDecimal.ZERO;
|
mQuotaAvailableBytes = BigDecimal.ZERO;
|
||||||
mPrivateLink = null;
|
mPrivateLink = null;
|
||||||
@ -154,6 +165,14 @@ public class RemoteFile implements Parcelable, Serializable {
|
|||||||
readFromParcel(source);
|
readFromParcel(source);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Use this to find out if this file is a folder.
|
||||||
|
*
|
||||||
|
* @return true if it is a folder
|
||||||
|
*/
|
||||||
|
public boolean isFolder() {
|
||||||
|
return mMimeType != null && (mMimeType.equals(FileUtils.MIME_DIR) || mMimeType.equals(FileUtils.MIME_DIR_UNIX));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Getters and Setters
|
* Getters and Setters
|
||||||
|
@ -46,9 +46,9 @@ import java.net.URL;
|
|||||||
|
|
||||||
public class GetRemoteShareOperation extends RemoteOperation<ShareParserResult> {
|
public class GetRemoteShareOperation extends RemoteOperation<ShareParserResult> {
|
||||||
|
|
||||||
private long mRemoteId;
|
private String mRemoteId;
|
||||||
|
|
||||||
public GetRemoteShareOperation(long remoteId) {
|
public GetRemoteShareOperation(String remoteId) {
|
||||||
mRemoteId = remoteId;
|
mRemoteId = remoteId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,7 +60,7 @@ public class GetRemoteShareOperation extends RemoteOperation<ShareParserResult>
|
|||||||
Uri requestUri = client.getBaseUri();
|
Uri requestUri = client.getBaseUri();
|
||||||
Uri.Builder uriBuilder = requestUri.buildUpon();
|
Uri.Builder uriBuilder = requestUri.buildUpon();
|
||||||
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
|
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH);
|
||||||
uriBuilder.appendEncodedPath(Long.toString(mRemoteId));
|
uriBuilder.appendEncodedPath(mRemoteId);
|
||||||
|
|
||||||
GetMethod getMethod = new GetMethod(new URL(uriBuilder.build().toString()));
|
GetMethod getMethod = new GetMethod(new URL(uriBuilder.build().toString()));
|
||||||
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
|
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
/* ownCloud Android Library is available under MIT license
|
/* ownCloud Android Library is available under MIT license
|
||||||
*
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
* @author masensio
|
* @author masensio
|
||||||
* @author David A. Velasco
|
* @author David A. Velasco
|
||||||
* @author David González Verdugo
|
* @author David González Verdugo
|
||||||
@ -28,16 +29,21 @@
|
|||||||
|
|
||||||
package com.owncloud.android.lib.resources.shares
|
package com.owncloud.android.lib.resources.shares
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
import com.owncloud.android.lib.common.OwnCloudClient
|
||||||
import com.owncloud.android.lib.common.http.HttpConstants
|
import com.owncloud.android.lib.common.http.HttpConstants
|
||||||
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
import com.owncloud.android.lib.common.operations.RemoteOperation
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
|
||||||
import org.json.JSONObject
|
import com.owncloud.android.lib.resources.CommonOcsResponse
|
||||||
|
import com.owncloud.android.lib.resources.shares.responses.ShareeOcsResponse
|
||||||
|
import com.squareup.moshi.JsonAdapter
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
import java.lang.reflect.Type
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by masensio on 08/10/2015.
|
* Created by masensio on 08/10/2015.
|
||||||
@ -65,6 +71,7 @@ import java.util.ArrayList
|
|||||||
* Status codes:
|
* Status codes:
|
||||||
* 100 - successful
|
* 100 - successful
|
||||||
*
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
* @author masensio
|
* @author masensio
|
||||||
* @author David A. Velasco
|
* @author David A. Velasco
|
||||||
* @author David González Verdugo
|
* @author David González Verdugo
|
||||||
@ -78,80 +85,66 @@ class GetRemoteShareesOperation
|
|||||||
* @param perPage maximum number of results in a single page
|
* @param perPage maximum number of results in a single page
|
||||||
*/
|
*/
|
||||||
(private val searchString: String, private val page: Int, private val perPage: Int) :
|
(private val searchString: String, private val page: Int, private val perPage: Int) :
|
||||||
RemoteOperation<ArrayList<JSONObject>>() {
|
RemoteOperation<ShareeOcsResponse>() {
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ArrayList<JSONObject>> {
|
private fun buildRequestUri(baseUri: Uri) =
|
||||||
var result: RemoteOperationResult<ArrayList<JSONObject>>
|
baseUri.buildUpon()
|
||||||
|
.appendEncodedPath(OCS_ROUTE)
|
||||||
|
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
||||||
|
.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE)
|
||||||
|
.appendQueryParameter(PARAM_SEARCH, searchString)
|
||||||
|
.appendQueryParameter(PARAM_PAGE, page.toString())
|
||||||
|
.appendQueryParameter(PARAM_PER_PAGE, perPage.toString())
|
||||||
|
.build()
|
||||||
|
|
||||||
try {
|
private fun parseResponse(response: String): ShareeOcsResponse? {
|
||||||
val requestUri = client.baseUri
|
val moshi = Moshi.Builder().build()
|
||||||
val uriBuilder = requestUri.buildUpon()
|
val type: Type = Types.newParameterizedType(CommonOcsResponse::class.java, ShareeOcsResponse::class.java)
|
||||||
.appendEncodedPath(OCS_ROUTE)
|
val adapter: JsonAdapter<CommonOcsResponse<ShareeOcsResponse>> = moshi.adapter(type)
|
||||||
.appendQueryParameter(PARAM_FORMAT, VALUE_FORMAT)
|
return adapter.fromJson(response)!!.ocs.data
|
||||||
.appendQueryParameter(PARAM_ITEM_TYPE, VALUE_ITEM_TYPE)
|
}
|
||||||
.appendQueryParameter(PARAM_SEARCH, searchString)
|
|
||||||
.appendQueryParameter(PARAM_PAGE, page.toString())
|
|
||||||
.appendQueryParameter(PARAM_PER_PAGE, perPage.toString())
|
|
||||||
|
|
||||||
val getMethod = GetMethod(URL(uriBuilder.build().toString()))
|
private fun onResultUnsuccessful(
|
||||||
|
method: GetMethod,
|
||||||
|
response: String?,
|
||||||
|
status: Int
|
||||||
|
): RemoteOperationResult<ShareeOcsResponse> {
|
||||||
|
Timber.e("Failed response while getting users/groups from the server ")
|
||||||
|
if (response != null) {
|
||||||
|
Timber.e("*** status code: $status; response message: $response")
|
||||||
|
} else {
|
||||||
|
Timber.e("*** status code: $status")
|
||||||
|
}
|
||||||
|
return RemoteOperationResult(method)
|
||||||
|
}
|
||||||
|
|
||||||
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
private fun onRequestSuccessful(response: String?): RemoteOperationResult<ShareeOcsResponse> {
|
||||||
|
val result = RemoteOperationResult<ShareeOcsResponse>(OK)
|
||||||
|
Timber.d("Successful response: $response")
|
||||||
|
result.data = parseResponse(response!!)
|
||||||
|
Timber.d("*** Get Users or groups completed ")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareeOcsResponse> {
|
||||||
|
val requestUri = buildRequestUri(client.baseUri)
|
||||||
|
|
||||||
|
val getMethod = GetMethod(URL(requestUri.toString()))
|
||||||
|
getMethod.addRequestHeader(OCS_API_HEADER, OCS_API_HEADER_VALUE)
|
||||||
|
|
||||||
|
return try {
|
||||||
val status = client.executeHttpMethod(getMethod)
|
val status = client.executeHttpMethod(getMethod)
|
||||||
val response = getMethod.getResponseBodyAsString()
|
val response = getMethod.getResponseBodyAsString()
|
||||||
|
|
||||||
if (isSuccess(status)) {
|
if (!isSuccess(status)) {
|
||||||
Timber.d("Successful response: $response")
|
onResultUnsuccessful(getMethod, response, status)
|
||||||
|
|
||||||
// Parse the response
|
|
||||||
val respJSON = JSONObject(response)
|
|
||||||
val respOCS = respJSON.getJSONObject(NODE_OCS)
|
|
||||||
val respData = respOCS.getJSONObject(NODE_DATA)
|
|
||||||
val respExact = respData.getJSONObject(NODE_EXACT)
|
|
||||||
val respExactUsers = respExact.getJSONArray(NODE_USERS)
|
|
||||||
val respExactGroups = respExact.getJSONArray(NODE_GROUPS)
|
|
||||||
val respExactRemotes = respExact.getJSONArray(NODE_REMOTES)
|
|
||||||
val respPartialUsers = respData.getJSONArray(NODE_USERS)
|
|
||||||
val respPartialGroups = respData.getJSONArray(NODE_GROUPS)
|
|
||||||
val respPartialRemotes = respData.getJSONArray(NODE_REMOTES)
|
|
||||||
val jsonResults = arrayOf(
|
|
||||||
respExactUsers,
|
|
||||||
respExactGroups,
|
|
||||||
respExactRemotes,
|
|
||||||
respPartialUsers,
|
|
||||||
respPartialGroups,
|
|
||||||
respPartialRemotes
|
|
||||||
)
|
|
||||||
|
|
||||||
val data = ArrayList<JSONObject>() // For result data
|
|
||||||
for (i in 0..5) {
|
|
||||||
for (j in 0 until jsonResults[i].length()) {
|
|
||||||
val jsonResult = jsonResults[i].getJSONObject(j)
|
|
||||||
data.add(jsonResult)
|
|
||||||
Timber.d("*** Added item: ${jsonResult.getString(PROPERTY_LABEL)}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
result = RemoteOperationResult(OK)
|
|
||||||
result.data = data
|
|
||||||
|
|
||||||
Timber.d("*** Get Users or groups completed ")
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
result = RemoteOperationResult(getMethod)
|
onRequestSuccessful(response)
|
||||||
Timber.e("Failed response while getting users/groups from the server ")
|
|
||||||
if (response != null) {
|
|
||||||
Timber.e("*** status code: $status; response message: $response")
|
|
||||||
} else {
|
|
||||||
Timber.e("*** status code: $status")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
result = RemoteOperationResult(e)
|
|
||||||
Timber.e(e, "Exception while getting users/groups")
|
Timber.e(e, "Exception while getting users/groups")
|
||||||
|
RemoteOperationResult(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
private fun isSuccess(status: Int) = status == HttpConstants.HTTP_OK
|
||||||
@ -171,18 +164,5 @@ class GetRemoteShareesOperation
|
|||||||
// Arguments - constant values
|
// Arguments - constant values
|
||||||
private const val VALUE_FORMAT = "json"
|
private const val VALUE_FORMAT = "json"
|
||||||
private const val VALUE_ITEM_TYPE = "file" // to get the server search for users / groups
|
private const val VALUE_ITEM_TYPE = "file" // to get the server search for users / groups
|
||||||
|
|
||||||
// JSON Node names
|
|
||||||
private const val NODE_OCS = "ocs"
|
|
||||||
private const val NODE_DATA = "data"
|
|
||||||
private const val NODE_EXACT = "exact"
|
|
||||||
private const val NODE_USERS = "users"
|
|
||||||
private const val NODE_GROUPS = "groups"
|
|
||||||
private const val NODE_REMOTES = "remotes"
|
|
||||||
const val NODE_VALUE = "value"
|
|
||||||
const val PROPERTY_LABEL = "label"
|
|
||||||
const val PROPERTY_SHARE_TYPE = "shareType"
|
|
||||||
const val PROPERTY_SHARE_WITH = "shareWith"
|
|
||||||
const val PROPERTY_SHARE_WITH_ADDITIONAL_INFO = "shareWithAdditionalInfo"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
|
|
||||||
package com.owncloud.android.lib.resources.shares
|
package com.owncloud.android.lib.resources.shares
|
||||||
|
|
||||||
import com.owncloud.android.lib.resources.files.FileUtils
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -35,7 +34,7 @@ import java.io.File
|
|||||||
* @author David González Verdugo
|
* @author David González Verdugo
|
||||||
*/
|
*/
|
||||||
data class RemoteShare(
|
data class RemoteShare(
|
||||||
var id: Long = 0,
|
var id: String = "0",
|
||||||
var shareWith: String = "",
|
var shareWith: String = "",
|
||||||
var path: String = "",
|
var path: String = "",
|
||||||
var token: String = "",
|
var token: String = "",
|
||||||
@ -43,15 +42,11 @@ data class RemoteShare(
|
|||||||
var sharedWithAdditionalInfo: String = "",
|
var sharedWithAdditionalInfo: String = "",
|
||||||
var name: String = "",
|
var name: String = "",
|
||||||
var shareLink: String = "",
|
var shareLink: String = "",
|
||||||
var fileSource: String = "0",
|
|
||||||
var itemSource: String = "0",
|
|
||||||
var shareType: ShareType? = ShareType.UNKNOWN,
|
var shareType: ShareType? = ShareType.UNKNOWN,
|
||||||
var permissions: Int = DEFAULT_PERMISSION,
|
var permissions: Int = DEFAULT_PERMISSION,
|
||||||
var sharedDate: Long = INIT_SHARED_DATE,
|
var sharedDate: Long = INIT_SHARED_DATE,
|
||||||
var expirationDate: Long = INIT_EXPIRATION_DATE_IN_MILLIS,
|
var expirationDate: Long = INIT_EXPIRATION_DATE_IN_MILLIS,
|
||||||
var isFolder: Boolean = path.endsWith(File.separator),
|
var isFolder: Boolean = path.endsWith(File.separator)
|
||||||
var userId: Long = 0,
|
|
||||||
val isValid: Boolean = id > -1
|
|
||||||
) {
|
) {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@ -106,17 +101,6 @@ enum class ShareType constructor(val value: Int) {
|
|||||||
FEDERATED(6);
|
FEDERATED(6);
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun fromValue(value: Int): ShareType? {
|
fun fromValue(value: Int) = values().firstOrNull { it.value == value }
|
||||||
return when (value) {
|
|
||||||
-1 -> UNKNOWN
|
|
||||||
0 -> USER
|
|
||||||
1 -> GROUP
|
|
||||||
3 -> PUBLIC_LINK
|
|
||||||
4 -> EMAIL
|
|
||||||
5 -> CONTACT
|
|
||||||
6 -> FEDERATED
|
|
||||||
else -> null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ import java.net.URL
|
|||||||
*
|
*
|
||||||
* @param remoteShareId Share ID
|
* @param remoteShareId Share ID
|
||||||
*/
|
*/
|
||||||
class RemoveRemoteShareOperation(private val remoteShareId: Long) : RemoteOperation<ShareParserResult>() {
|
class RemoveRemoteShareOperation(private val remoteShareId: String) : RemoteOperation<ShareParserResult>() {
|
||||||
|
|
||||||
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareParserResult> {
|
override fun run(client: OwnCloudClient): RemoteOperationResult<ShareParserResult> {
|
||||||
var result: RemoteOperationResult<ShareParserResult>
|
var result: RemoteOperationResult<ShareParserResult>
|
||||||
@ -57,7 +57,7 @@ class RemoveRemoteShareOperation(private val remoteShareId: Long) : RemoteOperat
|
|||||||
val requestUri = client.baseUri
|
val requestUri = client.baseUri
|
||||||
val uriBuilder = requestUri.buildUpon()
|
val uriBuilder = requestUri.buildUpon()
|
||||||
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH)
|
uriBuilder.appendEncodedPath(ShareUtils.SHARING_API_PATH)
|
||||||
uriBuilder.appendEncodedPath(remoteShareId.toString())
|
uriBuilder.appendEncodedPath(remoteShareId)
|
||||||
|
|
||||||
val deleteMethod = DeleteMethod(
|
val deleteMethod = DeleteMethod(
|
||||||
URL(uriBuilder.build().toString())
|
URL(uriBuilder.build().toString())
|
||||||
|
@ -179,7 +179,7 @@ class ShareXMLParser {
|
|||||||
name.equals(NODE_ID, ignoreCase = true) -> {// Parse Create XML Response
|
name.equals(NODE_ID, ignoreCase = true) -> {// Parse Create XML Response
|
||||||
share = RemoteShare()
|
share = RemoteShare()
|
||||||
val value = readNode(parser, NODE_ID)
|
val value = readNode(parser, NODE_ID)
|
||||||
share.id = Integer.parseInt(value).toLong()
|
share.id = value
|
||||||
}
|
}
|
||||||
name.equals(NODE_URL, ignoreCase = true) -> {
|
name.equals(NODE_URL, ignoreCase = true) -> {
|
||||||
// NOTE: this field is received in all the public shares from OC 9.0.0
|
// NOTE: this field is received in all the public shares from OC 9.0.0
|
||||||
@ -236,7 +236,7 @@ class ShareXMLParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
name.equals(NODE_ID, ignoreCase = true) -> {
|
name.equals(NODE_ID, ignoreCase = true) -> {
|
||||||
remoteShare.id = Integer.parseInt(readNode(parser, NODE_ID)).toLong()
|
remoteShare.id = readNode(parser, NODE_ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
name.equals(NODE_ITEM_TYPE, ignoreCase = true) -> {
|
name.equals(NODE_ITEM_TYPE, ignoreCase = true) -> {
|
||||||
@ -244,10 +244,6 @@ class ShareXMLParser {
|
|||||||
fixPathForFolder(remoteShare)
|
fixPathForFolder(remoteShare)
|
||||||
}
|
}
|
||||||
|
|
||||||
name.equals(NODE_ITEM_SOURCE, ignoreCase = true) -> {
|
|
||||||
remoteShare.itemSource = readNode(parser, NODE_ITEM_SOURCE)
|
|
||||||
}
|
|
||||||
|
|
||||||
name.equals(NODE_PARENT, ignoreCase = true) -> {
|
name.equals(NODE_PARENT, ignoreCase = true) -> {
|
||||||
readNode(parser, NODE_PARENT)
|
readNode(parser, NODE_PARENT)
|
||||||
}
|
}
|
||||||
@ -261,10 +257,6 @@ class ShareXMLParser {
|
|||||||
remoteShare.shareWith = readNode(parser, NODE_SHARE_WITH)
|
remoteShare.shareWith = readNode(parser, NODE_SHARE_WITH)
|
||||||
}
|
}
|
||||||
|
|
||||||
name.equals(NODE_FILE_SOURCE, ignoreCase = true) -> {
|
|
||||||
remoteShare.fileSource = readNode(parser, NODE_FILE_SOURCE)
|
|
||||||
}
|
|
||||||
|
|
||||||
name.equals(NODE_PATH, ignoreCase = true) -> {
|
name.equals(NODE_PATH, ignoreCase = true) -> {
|
||||||
remoteShare.path = readNode(parser, NODE_PATH)
|
remoteShare.path = readNode(parser, NODE_PATH)
|
||||||
fixPathForFolder(remoteShare)
|
fixPathForFolder(remoteShare)
|
||||||
@ -320,9 +312,7 @@ class ShareXMLParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (remoteShare.isValid) {
|
shares.add(remoteShare)
|
||||||
shares.add(remoteShare)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun fixPathForFolder(share: RemoteShare) {
|
private fun fixPathForFolder(share: RemoteShare) {
|
||||||
@ -403,11 +393,9 @@ class ShareXMLParser {
|
|||||||
private const val NODE_ELEMENT = "element"
|
private const val NODE_ELEMENT = "element"
|
||||||
private const val NODE_ID = "id"
|
private const val NODE_ID = "id"
|
||||||
private const val NODE_ITEM_TYPE = "item_type"
|
private const val NODE_ITEM_TYPE = "item_type"
|
||||||
private const val NODE_ITEM_SOURCE = "item_source"
|
|
||||||
private const val NODE_PARENT = "parent"
|
private const val NODE_PARENT = "parent"
|
||||||
private const val NODE_SHARE_TYPE = "share_type"
|
private const val NODE_SHARE_TYPE = "share_type"
|
||||||
private const val NODE_SHARE_WITH = "share_with"
|
private const val NODE_SHARE_WITH = "share_with"
|
||||||
private const val NODE_FILE_SOURCE = "file_source"
|
|
||||||
private const val NODE_PATH = "path"
|
private const val NODE_PATH = "path"
|
||||||
private const val NODE_PERMISSIONS = "permissions"
|
private const val NODE_PERMISSIONS = "permissions"
|
||||||
private const val NODE_STIME = "stime"
|
private const val NODE_STIME = "stime"
|
||||||
|
@ -55,7 +55,7 @@ class UpdateRemoteShareOperation
|
|||||||
/**
|
/**
|
||||||
* @param remoteId Identifier of the share to update.
|
* @param remoteId Identifier of the share to update.
|
||||||
*/
|
*/
|
||||||
private val remoteId: Long
|
private val remoteId: String
|
||||||
|
|
||||||
) : RemoteOperation<ShareParserResult>() {
|
) : RemoteOperation<ShareParserResult>() {
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,72 @@
|
|||||||
|
/* ownCloud Android Library is available under MIT license
|
||||||
|
*
|
||||||
|
* Copyright (C) 2020 ownCloud GmbH.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
package com.owncloud.android.lib.resources.shares.responses
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This was modeled according to the documentation:
|
||||||
|
* https://doc.owncloud.com/server/developer_manual/core/apis/ocs-recipient-api.html#get-shares-recipients
|
||||||
|
*/
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class ShareeOcsResponse(
|
||||||
|
val exact: ExactSharees?,
|
||||||
|
val groups: List<ShareeItem>,
|
||||||
|
val remotes: List<ShareeItem>,
|
||||||
|
val users: List<ShareeItem>
|
||||||
|
) {
|
||||||
|
fun getFlatRepresentationWithoutExact() = ArrayList<ShareeItem>().apply {
|
||||||
|
addAll(users)
|
||||||
|
addAll(remotes)
|
||||||
|
addAll(groups)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class ExactSharees(
|
||||||
|
val groups: List<ShareeItem>,
|
||||||
|
val remotes: List<ShareeItem>,
|
||||||
|
val users: List<ShareeItem>
|
||||||
|
) {
|
||||||
|
fun getFlatRepresentation() = ArrayList<ShareeItem>().apply {
|
||||||
|
addAll(users)
|
||||||
|
addAll(remotes)
|
||||||
|
addAll(groups)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class ShareeItem(
|
||||||
|
val label: String,
|
||||||
|
val value: ShareeValue
|
||||||
|
)
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class ShareeValue(
|
||||||
|
val shareType: Int,
|
||||||
|
val shareWith: String,
|
||||||
|
@Json(name = "shareWithAdditionalInfo")
|
||||||
|
val additionalInfo: String?
|
||||||
|
)
|
@ -44,7 +44,7 @@ interface ShareService : Service {
|
|||||||
): RemoteOperationResult<ShareParserResult>
|
): RemoteOperationResult<ShareParserResult>
|
||||||
|
|
||||||
fun updateShare(
|
fun updateShare(
|
||||||
remoteId: Long,
|
remoteId: String,
|
||||||
name: String,
|
name: String,
|
||||||
password: String?,
|
password: String?,
|
||||||
expirationDate: Long,
|
expirationDate: Long,
|
||||||
@ -52,5 +52,5 @@ interface ShareService : Service {
|
|||||||
publicUpload: Boolean
|
publicUpload: Boolean
|
||||||
): RemoteOperationResult<ShareParserResult>
|
): RemoteOperationResult<ShareParserResult>
|
||||||
|
|
||||||
fun deleteShare(remoteId: Long): RemoteOperationResult<ShareParserResult>
|
fun deleteShare(remoteId: String): RemoteOperationResult<ShareParserResult>
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/**
|
/**
|
||||||
* ownCloud Android client application
|
* ownCloud Android client application
|
||||||
*
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
* @author David González Verdugo
|
* @author David González Verdugo
|
||||||
*
|
*
|
||||||
* Copyright (C) 2020 ownCloud GmbH.
|
* Copyright (C) 2020 ownCloud GmbH.
|
||||||
@ -22,13 +23,12 @@ package com.owncloud.android.lib.resources.shares.services
|
|||||||
|
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||||
import com.owncloud.android.lib.resources.Service
|
import com.owncloud.android.lib.resources.Service
|
||||||
import org.json.JSONObject
|
import com.owncloud.android.lib.resources.shares.responses.ShareeOcsResponse
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
interface ShareeService : Service {
|
interface ShareeService : Service {
|
||||||
fun getSharees(
|
fun getSharees(
|
||||||
searchString: String,
|
searchString: String,
|
||||||
page: Int,
|
page: Int,
|
||||||
perPage: Int
|
perPage: Int
|
||||||
): RemoteOperationResult<ArrayList<JSONObject>>
|
): RemoteOperationResult<ShareeOcsResponse>
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ class OCShareService(override val client: OwnCloudClient) :
|
|||||||
}.execute(client)
|
}.execute(client)
|
||||||
|
|
||||||
override fun updateShare(
|
override fun updateShare(
|
||||||
remoteId: Long,
|
remoteId: String,
|
||||||
name: String,
|
name: String,
|
||||||
password: String?,
|
password: String?,
|
||||||
expirationDate: Long,
|
expirationDate: Long,
|
||||||
@ -84,7 +84,7 @@ class OCShareService(override val client: OwnCloudClient) :
|
|||||||
this.retrieveShareDetails = true
|
this.retrieveShareDetails = true
|
||||||
}.execute(client)
|
}.execute(client)
|
||||||
|
|
||||||
override fun deleteShare(remoteId: Long): RemoteOperationResult<ShareParserResult> =
|
override fun deleteShare(remoteId: String): RemoteOperationResult<ShareParserResult> =
|
||||||
RemoveRemoteShareOperation(
|
RemoveRemoteShareOperation(
|
||||||
remoteId
|
remoteId
|
||||||
).execute(client)
|
).execute(client)
|
||||||
|
@ -23,9 +23,8 @@ package com.owncloud.android.lib.resources.shares.services.implementation
|
|||||||
import com.owncloud.android.lib.common.OwnCloudClient
|
import com.owncloud.android.lib.common.OwnCloudClient
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||||
import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation
|
import com.owncloud.android.lib.resources.shares.GetRemoteShareesOperation
|
||||||
|
import com.owncloud.android.lib.resources.shares.responses.ShareeOcsResponse
|
||||||
import com.owncloud.android.lib.resources.shares.services.ShareeService
|
import com.owncloud.android.lib.resources.shares.services.ShareeService
|
||||||
import org.json.JSONObject
|
|
||||||
import java.util.ArrayList
|
|
||||||
|
|
||||||
class OCShareeService(override val client: OwnCloudClient) :
|
class OCShareeService(override val client: OwnCloudClient) :
|
||||||
ShareeService {
|
ShareeService {
|
||||||
@ -33,7 +32,7 @@ class OCShareeService(override val client: OwnCloudClient) :
|
|||||||
searchString: String,
|
searchString: String,
|
||||||
page: Int,
|
page: Int,
|
||||||
perPage: Int
|
perPage: Int
|
||||||
): RemoteOperationResult<ArrayList<JSONObject>> =
|
): RemoteOperationResult<ShareeOcsResponse> =
|
||||||
GetRemoteShareesOperation(
|
GetRemoteShareesOperation(
|
||||||
searchString,
|
searchString,
|
||||||
page,
|
page,
|
||||||
|
@ -34,8 +34,8 @@ import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
|||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
import com.owncloud.android.lib.common.operations.RemoteOperation
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode.OK
|
||||||
import com.owncloud.android.lib.resources.response.CapabilityResponse
|
import com.owncloud.android.lib.resources.status.responses.CapabilityResponse
|
||||||
import com.owncloud.android.lib.resources.response.CommonOcsResponse
|
import com.owncloud.android.lib.resources.CommonOcsResponse
|
||||||
import com.squareup.moshi.JsonAdapter
|
import com.squareup.moshi.JsonAdapter
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.squareup.moshi.Types
|
import com.squareup.moshi.Types
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.lib.resources.response
|
package com.owncloud.android.lib.resources.status.responses
|
||||||
|
|
||||||
import com.owncloud.android.lib.resources.status.RemoteCapability
|
import com.owncloud.android.lib.resources.status.RemoteCapability
|
||||||
import com.owncloud.android.lib.resources.status.RemoteCapability.CapabilityBooleanType
|
import com.owncloud.android.lib.resources.status.RemoteCapability.CapabilityBooleanType
|
@ -29,8 +29,8 @@ import com.owncloud.android.lib.common.http.methods.nonwebdav.GetMethod
|
|||||||
import com.owncloud.android.lib.common.operations.RemoteOperation
|
import com.owncloud.android.lib.common.operations.RemoteOperation
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult
|
||||||
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
|
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode
|
||||||
import com.owncloud.android.lib.resources.response.CommonOcsResponse
|
import com.owncloud.android.lib.resources.CommonOcsResponse
|
||||||
import com.owncloud.android.lib.resources.response.UserInfoResponse
|
import com.owncloud.android.lib.resources.users.responses.UserInfoResponse
|
||||||
import com.squareup.moshi.JsonAdapter
|
import com.squareup.moshi.JsonAdapter
|
||||||
import com.squareup.moshi.Moshi
|
import com.squareup.moshi.Moshi
|
||||||
import com.squareup.moshi.Types
|
import com.squareup.moshi.Types
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
package com.owncloud.android.lib.resources.response
|
package com.owncloud.android.lib.resources.users.responses
|
||||||
|
|
||||||
import com.owncloud.android.lib.resources.users.RemoteUserInfo
|
import com.owncloud.android.lib.resources.users.RemoteUserInfo
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
@ -0,0 +1,93 @@
|
|||||||
|
/* ownCloud Android Library is available under MIT license
|
||||||
|
* Copyright (C) 2020 ownCloud GmbH.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.owncloud.android.lib.resources.shares.responses
|
||||||
|
|
||||||
|
import com.owncloud.android.lib.resources.CommonOcsResponse
|
||||||
|
import com.squareup.moshi.JsonAdapter
|
||||||
|
import com.squareup.moshi.Moshi
|
||||||
|
import com.squareup.moshi.Types
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
import java.io.File
|
||||||
|
import java.lang.reflect.Type
|
||||||
|
|
||||||
|
class ShareeResponseTest {
|
||||||
|
|
||||||
|
lateinit var adapter: JsonAdapter<CommonOcsResponse<ShareeOcsResponse>>
|
||||||
|
|
||||||
|
private fun loadResponses(fileName: String) =
|
||||||
|
adapter.fromJson(File(fileName).readText())
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun prepare() {
|
||||||
|
val moshi = Moshi.Builder().build()
|
||||||
|
val type: Type = Types.newParameterizedType(CommonOcsResponse::class.java, ShareeOcsResponse::class.java)
|
||||||
|
adapter = moshi.adapter(type)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `check structure - ok - contains meta`() {
|
||||||
|
val response = loadResponses(EXAMPLE_RESPONSE_JSON)!!
|
||||||
|
assertEquals("OK", response.ocs.meta.message!!)
|
||||||
|
assertEquals(200, response.ocs.meta.statusCode)
|
||||||
|
assertEquals("ok", response.ocs.meta.status)
|
||||||
|
assertTrue(response.ocs.meta.itemsPerPage?.isEmpty()!!)
|
||||||
|
assertTrue(response.ocs.meta.totalItems?.isEmpty()!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `example response - ok - correct sturcture`() {
|
||||||
|
val response = loadResponses(EXAMPLE_RESPONSE_JSON)!!
|
||||||
|
assertEquals(2, response.ocs.data.groups.size)
|
||||||
|
assertEquals(0, response.ocs.data.remotes.size)
|
||||||
|
assertEquals(2, response.ocs.data.users.size)
|
||||||
|
assertEquals(0, response.ocs.data.exact?.groups?.size)
|
||||||
|
assertEquals(0, response.ocs.data.exact?.remotes?.size)
|
||||||
|
assertEquals(1, response.ocs.data.exact?.users?.size)
|
||||||
|
assertEquals("user1@user1.com", response.ocs.data.users.get(0).value.additionalInfo)
|
||||||
|
assertNull(response.ocs.data.users[1].value.additionalInfo)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `check empty response - ok - parsing ok`() {
|
||||||
|
val response = loadResponses(EMPTY_RESPONSE_JSON)!!
|
||||||
|
assertTrue(response.ocs.data.exact?.groups?.isEmpty()!!)
|
||||||
|
assertTrue(response.ocs.data.exact?.remotes?.isEmpty()!!)
|
||||||
|
assertTrue(response.ocs.data.exact?.users?.isEmpty()!!)
|
||||||
|
assertTrue(response.ocs.data.groups.isEmpty())
|
||||||
|
assertTrue(response.ocs.data.remotes.isEmpty())
|
||||||
|
assertTrue(response.ocs.data.users.isEmpty())
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val RESOURCES_PATH =
|
||||||
|
"src/test/responses/com.owncloud.android.lib.resources.sharees.responses"
|
||||||
|
val EXAMPLE_RESPONSE_JSON = "$RESOURCES_PATH/example_sharee_response.json"
|
||||||
|
val EMPTY_RESPONSE_JSON = "$RESOURCES_PATH/empty_sharee_response.json"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"ocs": {
|
||||||
|
"meta": {
|
||||||
|
"status": "ok",
|
||||||
|
"statuscode": 100,
|
||||||
|
"message": "OK",
|
||||||
|
"totalitems": "",
|
||||||
|
"itemsperpage": ""
|
||||||
|
},
|
||||||
|
"data": {
|
||||||
|
"exact": {
|
||||||
|
"users": [],
|
||||||
|
"groups": [],
|
||||||
|
"remotes": []
|
||||||
|
},
|
||||||
|
"users": [],
|
||||||
|
"groups": [],
|
||||||
|
"remotes": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"ocs": {
|
||||||
|
"data": {
|
||||||
|
"exact": {
|
||||||
|
"groups": [],
|
||||||
|
"remotes": [],
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"label": "admin",
|
||||||
|
"value": {
|
||||||
|
"shareType": 0,
|
||||||
|
"shareWith": "admin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"groups": [
|
||||||
|
{
|
||||||
|
"label": "group1",
|
||||||
|
"value": {
|
||||||
|
"shareType": 1,
|
||||||
|
"shareWith": "group1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "group2",
|
||||||
|
"value": {
|
||||||
|
"shareType": 1,
|
||||||
|
"shareWith": "group2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"remotes": [],
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"label": "user1",
|
||||||
|
"value": {
|
||||||
|
"shareType": 0,
|
||||||
|
"shareWith": "user1",
|
||||||
|
"shareWithAdditionalInfo": "user1@user1.com"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "user2",
|
||||||
|
"value": {
|
||||||
|
"shareType": 0,
|
||||||
|
"shareWith": "user2"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"meta": {
|
||||||
|
"itemsperpage": "",
|
||||||
|
"message": "OK",
|
||||||
|
"status": "ok",
|
||||||
|
"statuscode": 200,
|
||||||
|
"totalitems": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user