Skip to content

Commit

Permalink
Merge pull request #1604 from nextcloud/tos
Browse files Browse the repository at this point in the history
ToS
  • Loading branch information
tobiasKaminsky authored Feb 5, 2025
2 parents e3c0611 + f4f71d5 commit fe8b18f
Show file tree
Hide file tree
Showing 8 changed files with 198 additions and 3 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: MIT
*/

package com.nextcloud.android.lib.resources.tos

import com.owncloud.android.AbstractIT
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue

class TermsOfServicesIT : AbstractIT() {
// @Test disabled for now as no good way to test on CI
fun getAndSignTerms() {
// user 3 with ToS
var result = GetTermsRemoteOperation().execute(nextcloudClient)
assertTrue(result.isSuccess)

var terms = result.resultData
assertTrue(terms.terms.isNotEmpty())
assertFalse(terms.hasSigned)

val id = terms.terms[0].id

// sign
assertTrue(SignTermRemoteOperation(id).execute(nextcloudClient).isSuccess)

// signed terms
result = GetTermsRemoteOperation().execute(nextcloudClient)
assertTrue(result.isSuccess)

terms = result.resultData
assertTrue(terms.terms.isNotEmpty())
assertTrue(terms.hasSigned)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: MIT
*/
package com.nextcloud.android.lib.resources.tos

import com.google.gson.reflect.TypeToken
import com.nextcloud.common.NextcloudClient
import com.nextcloud.operations.GetMethod
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.common.utils.Log_OC
import com.owncloud.android.lib.ocs.ServerResponse
import com.owncloud.android.lib.resources.OCSRemoteOperation
import org.apache.commons.httpclient.HttpStatus

/**
* Get terms of service of an user
*/
class GetTermsRemoteOperation : OCSRemoteOperation<Terms>() {
@Suppress("TooGenericExceptionCaught")
override fun run(client: NextcloudClient): RemoteOperationResult<Terms> {
var result: RemoteOperationResult<Terms>
var getMethod: GetMethod? = null
try {
getMethod =
GetMethod(
client.baseUri.toString() + ENDPOINT + JSON_FORMAT,
true
)
val status = client.execute(getMethod)
if (status == HttpStatus.SC_OK) {
val terms =
getServerResponse(
getMethod,
object : TypeToken<ServerResponse<Terms>>() {}
)?.ocs?.data

if (terms != null) {
result = RemoteOperationResult(true, getMethod)
result.setResultData(terms)
} else {
result = RemoteOperationResult(false, getMethod)
}
} else {
result = RemoteOperationResult(false, getMethod)
}
} catch (e: Exception) {
result = RemoteOperationResult(e)
Log_OC.e(
TAG,
"Get terms failed: " + result.logMessage,
result.exception
)
} finally {
getMethod?.releaseConnection()
}
return result
}

companion object {
private val TAG = GetTermsRemoteOperation::class.java.simpleName
private const val ENDPOINT = "/ocs/v2.php/apps/terms_of_service/terms"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: MIT
*/
package com.nextcloud.android.lib.resources.tos

import com.nextcloud.common.NextcloudClient
import com.nextcloud.operations.PostMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.apache.commons.httpclient.HttpStatus

/**
* Sign terms of services
*/
class SignTermRemoteOperation(
val id: Int
) : RemoteOperation<Void>() {
@Suppress("TooGenericExceptionCaught")
override fun run(client: NextcloudClient): RemoteOperationResult<Void> {
val requestBody = hashMapOf("termId" to id)

val json = gson.toJson(requestBody)

val request = json.toRequestBody("application/json".toMediaTypeOrNull())

val postMethod = PostMethod(client.baseUri.toString() + ENDPOINT, true, request)

val status = postMethod.execute(client)

return if (status == HttpStatus.SC_OK) {
RemoteOperationResult<Void>(true, postMethod)
} else {
RemoteOperationResult<Void>(false, postMethod)
}
}

companion object {
private const val ENDPOINT = "/ocs/v2.php/apps/terms_of_service/sign"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: MIT
*/

package com.nextcloud.android.lib.resources.tos

data class Term(
val id: Int,
val countryCode: String,
val languageCode: String,
val body: String,
val renderedBody: String
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/*
* Nextcloud Android Library
*
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-FileCopyrightText: 2024 Tobias Kaminsky <[email protected]>
* SPDX-License-Identifier: MIT
*/

package com.nextcloud.android.lib.resources.tos

data class Terms(
val terms: List<Term>,
val hasSigned: Boolean,
val languages: Map<String, String>
)
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class ExceptionParser {
private static final String INVALID_PATH_EXCEPTION_STRING = "OC\\Connector\\Sabre\\Exception\\InvalidPath";
private static final String INVALID_PATH_EXCEPTION_UPLOAD_STRING = "OCP\\Files\\InvalidPathException";
private static final String VIRUS_EXCEPTION_STRING = "OCA\\DAV\\Connector\\Sabre\\Exception\\UnsupportedMediaType";
private static final String TOS_EXCEPTION_STRING = "OCA\\TermsOfService\\TermsNotSignedException";

// No namespaces
private static final String ns = null;
Expand Down Expand Up @@ -75,6 +76,10 @@ public boolean isInvalidCharacterException() {
public boolean isVirusException() {
return VIRUS_EXCEPTION_STRING.equalsIgnoreCase(exception) && message.startsWith("Virus");
}

public boolean isToSException() {
return TOS_EXCEPTION_STRING.equalsIgnoreCase(exception);
}

/**
* Parse OCS node
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,8 @@ public enum ResultCode {
VIRUS_DETECTED,
FOLDER_ALREADY_EXISTS,
CANNOT_CREATE_FILE,
LOCKED
LOCKED,
SIGNING_TOS_NEEDED
}

private boolean mSuccess = false;
Expand Down Expand Up @@ -329,7 +330,9 @@ public RemoteOperationResult(boolean success, OkHttpMethodBase httpMethod) {
public RemoteOperationResult(boolean success, HttpMethod httpMethod) {
this(success, httpMethod.getStatusCode(), httpMethod.getStatusText(), httpMethod.getResponseHeaders());

if (mHttpCode == HttpStatus.SC_BAD_REQUEST || mHttpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE) {
if (mHttpCode == HttpStatus.SC_BAD_REQUEST ||
mHttpCode == HttpStatus.SC_UNSUPPORTED_MEDIA_TYPE ||
mHttpCode == HttpStatus.SC_FORBIDDEN) {
try {
String bodyResponse = httpMethod.getResponseBodyAsString();

Expand All @@ -343,6 +346,9 @@ public RemoteOperationResult(boolean success, HttpMethod httpMethod) {
if (xmlParser.isVirusException()) {
mCode = ResultCode.VIRUS_DETECTED;
}
if (xmlParser.isToSException()) {
mCode = ResultCode.SIGNING_TOS_NEEDED;
}

mHttpPhrase = xmlParser.getMessage();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ protected RemoteOperationResult run(OwnCloudClient client) {
status = mRedirectionPath.getLastStatus();
}
client.exhaustResponse(head.getResponseBodyAsStream());
boolean success = (status == HttpStatus.SC_OK && !mSuccessIfAbsent) ||
boolean success = ((status == HttpStatus.SC_OK || status == HttpStatus.SC_UNAUTHORIZED || status == HttpStatus.SC_FORBIDDEN) && !mSuccessIfAbsent) ||
(status == HttpStatus.SC_NOT_FOUND && mSuccessIfAbsent);
result = new RemoteOperationResult(
success,
Expand Down

0 comments on commit fe8b18f

Please sign in to comment.