diff --git a/library/src/main/java/com/owncloud/android/lib/resources/notifications/ActivateWebPushRegistrationOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/notifications/ActivateWebPushRegistrationOperation.kt new file mode 100644 index 0000000000..6b2d822f2c --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/notifications/ActivateWebPushRegistrationOperation.kt @@ -0,0 +1,61 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.notifications + +import com.nextcloud.common.JSONRequestBody +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 com.owncloud.android.lib.common.utils.Log_OC +import org.apache.commons.httpclient.util.HttpURLConnection + +class ActivateWebPushRegistrationOperation( + val activationToken: String +): RemoteOperation() { + + override fun run(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult + var post: PostMethod? = null + try { + val body = JSONRequestBody(ACTIVATION_TOKEN, activationToken) + post = PostMethod("${client.baseUri}$OCS_ROUTE", true, body.get()) + + val status = client.execute(post) + val response = post.getResponseBodyAsString() + when (status) { + HttpURLConnection.HTTP_ACCEPTED -> { + Log_OC.d(TAG, "Web push registration activated (status=202)") + result = RemoteOperationResult(true, post) + } + HttpURLConnection.HTTP_OK -> { + Log_OC.d(TAG, "Web push registration already activated (status=200)") + result = RemoteOperationResult(true, post) + } + else -> { + Log_OC.d(TAG, "Cannot activate web push registration (status=$status): $response") + result = RemoteOperationResult(false, post) + } + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while activating web push registration", e) + } finally { + post?.releaseConnection() + } + return result + } + + companion object { + // OCS Route + private const val OCS_ROUTE = "/ocs/v2.php/apps/notifications/api/v2/webpush/activate" + private const val ACTIVATION_TOKEN = "activationToken" + + private val TAG = ActivateWebPushRegistrationOperation::class.java.getSimpleName() + } +} \ No newline at end of file diff --git a/library/src/main/java/com/owncloud/android/lib/resources/notifications/GetVAPIDOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/notifications/GetVAPIDOperation.kt new file mode 100644 index 0000000000..feacf47772 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/notifications/GetVAPIDOperation.kt @@ -0,0 +1,59 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.notifications + +import com.nextcloud.common.NextcloudClient +import com.nextcloud.operations.GetMethod +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 com.owncloud.android.lib.resources.notifications.models.VapidResponse +import org.json.JSONObject + +class GetVAPIDOperation(): RemoteOperation() { + + override fun run(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult + var get: GetMethod? = null + try { + get = GetMethod("${client.baseUri}$OCS_ROUTE", true) + + val status = client.execute(get) + val response = get.getResponseBodyAsString() + + if (get.isSuccess()) { + result = RemoteOperationResult(true, get) + val vapid = JSONObject(response) + .getJSONObject(OCS) + .getJSONObject(DATA) + .getString(VAPID) + result.resultData = VapidResponse(vapid) + Log_OC.d(TAG, "VAPID key found: $vapid") + } else { + Log_OC.e(TAG, "Failed getting VAPID key (status=$status): $response") + result = RemoteOperationResult(false, get) + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while getting VAPID key", e) + } finally { + get?.releaseConnection() + } + return result + } + + companion object { + // OCS Route + private const val OCS_ROUTE = "/ocs/v2.php/apps/notifications/api/v2/webpush/vapid$JSON_FORMAT" + private const val OCS = "ocs" + private const val DATA = "data" + private const val VAPID = "vapid" + + private val TAG = GetVAPIDOperation::class.java.getSimpleName() + } +} \ No newline at end of file diff --git a/library/src/main/java/com/owncloud/android/lib/resources/notifications/RegisterAccountDeviceForWebPushOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/notifications/RegisterAccountDeviceForWebPushOperation.kt new file mode 100644 index 0000000000..1bbe776da7 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/notifications/RegisterAccountDeviceForWebPushOperation.kt @@ -0,0 +1,70 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.notifications + +import com.nextcloud.common.JSONRequestBody +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 com.owncloud.android.lib.common.utils.Log_OC +import org.apache.commons.httpclient.util.HttpURLConnection + +class RegisterAccountDeviceForWebPushOperation( + val endpoint: String, + val auth: String, + val uaPublicKey: String, + val appTypes: List +): RemoteOperation() { + + override fun run(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult + var post: PostMethod? = null + try { + val body = JSONRequestBody(ENDPOINT, endpoint) + body.put(AUTH, auth) + body.put(UA_PUBLIC_KEY, uaPublicKey) + body.put(APPTYPES, appTypes.joinToString(",")) + post = PostMethod("${client.baseUri}$OCS_ROUTE", true, body.get()) + + val status = client.execute(post) + val response = post.getResponseBodyAsString() + when (status) { + HttpURLConnection.HTTP_CREATED -> { + Log_OC.d(TAG, "New web push registration created (status=201)") + result = RemoteOperationResult(true, post) + } + HttpURLConnection.HTTP_OK -> { + Log_OC.d(TAG, "Web push registration already activated (status=200)") + result = RemoteOperationResult(true, post) + } + else -> { + Log_OC.e(TAG, "Web push registration refused (status=$status): $response") + result = RemoteOperationResult(false, post) + } + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while registering web push", e) + } finally { + post?.releaseConnection() + } + return result + } + + companion object { + // OCS Route + private const val OCS_ROUTE = "/ocs/v2.php/apps/notifications/api/v2/webpush" + private const val ENDPOINT = "endpoint" + private const val AUTH = "auth" + private const val UA_PUBLIC_KEY = "uaPublicKey" + private const val APPTYPES = "appTypes" + + private val TAG = RegisterAccountDeviceForWebPushOperation::class.java.getSimpleName() + } +} \ No newline at end of file diff --git a/library/src/main/java/com/owncloud/android/lib/resources/notifications/UnregisterAccountDeviceForWebPushOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/notifications/UnregisterAccountDeviceForWebPushOperation.kt new file mode 100644 index 0000000000..b8ac9387c8 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/notifications/UnregisterAccountDeviceForWebPushOperation.kt @@ -0,0 +1,56 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.notifications + +import com.nextcloud.common.NextcloudClient +import com.nextcloud.operations.DeleteMethod +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.util.HttpURLConnection + +class UnregisterAccountDeviceForWebPushOperation(): RemoteOperation() { + + override fun run(client: NextcloudClient): RemoteOperationResult { + var result: RemoteOperationResult + var delete: DeleteMethod? = null + try { + delete = DeleteMethod("${client.baseUri}$OCS_ROUTE", true) + + val status = client.execute(delete) + val response = delete.getResponseBodyAsString() + when (status) { + HttpURLConnection.HTTP_ACCEPTED -> { + Log_OC.d(TAG, "Web push registration deleted (status=202)") + result = RemoteOperationResult(true, delete) + } + HttpURLConnection.HTTP_OK -> { + Log_OC.d(TAG, "Web push registration already deleted (status=200)") + result = RemoteOperationResult(true, delete) + } + else -> { + Log_OC.e(TAG, "Web push registration refused (status=$status): $response") + result = RemoteOperationResult(false, delete) + } + } + } catch (e: Exception) { + result = RemoteOperationResult(e) + Log_OC.e(TAG, "Exception while registering web push", e) + } finally { + delete?.releaseConnection() + } + return result + } + + companion object { + // OCS Route + private const val OCS_ROUTE = "/ocs/v2.php/apps/notifications/api/v2/webpush" + + private val TAG = UnregisterAccountDeviceForWebPushOperation::class.java.getSimpleName() + } +} \ No newline at end of file diff --git a/library/src/main/java/com/owncloud/android/lib/resources/notifications/models/VapidResponse.kt b/library/src/main/java/com/owncloud/android/lib/resources/notifications/models/VapidResponse.kt new file mode 100644 index 0000000000..afa36b8596 --- /dev/null +++ b/library/src/main/java/com/owncloud/android/lib/resources/notifications/models/VapidResponse.kt @@ -0,0 +1,10 @@ +/* + * Nextcloud - Android Client + * + * SPDX-FileCopyrightText: 2025 Your Name + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package com.owncloud.android.lib.resources.notifications.models + +data class VapidResponse(val vapid: String) \ No newline at end of file diff --git a/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java b/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java index 08cbae4ed3..8876758b43 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java +++ b/library/src/main/java/com/owncloud/android/lib/resources/status/GetCapabilitiesRemoteOperation.java @@ -113,6 +113,8 @@ public class GetCapabilitiesRemoteOperation extends RemoteOperation { // v1 notifications private static final String NODE_NOTIFICATIONS = "notifications"; private static final String PROPERTY_OCSENDPOINT = "ocs-endpoints"; + private static final String PROPERTY_PUSH = "push"; + private static final String PROPERTY_WEBPUSH = "webpush"; // v2 notifications private static final String PROPERTY_ICONS = "icons"; @@ -549,6 +551,7 @@ private OCCapability parseResponse(String response) throws JSONException { JSONObject respNotifications = respCapabilities.getJSONObject(NODE_NOTIFICATIONS); JSONArray respNotificationSupportArray = respNotifications.getJSONArray( PROPERTY_OCSENDPOINT); + JSONArray respNotificationPushArray = respNotifications.getJSONArray(PROPERTY_PUSH); for (int i = 0; i < respNotificationSupportArray.length(); i++) { String propertyString = respNotificationSupportArray.getString(i); if (PROPERTY_RICH_STRINGS.equals(propertyString) @@ -557,6 +560,13 @@ private OCCapability parseResponse(String response) throws JSONException { break; } } + for (int i = 0; i < respNotificationPushArray.length(); i++) { + String propertyString = respNotificationPushArray.getString(i); + if (PROPERTY_WEBPUSH.equals(propertyString)) { + capability.setSupportsWebPush(CapabilityBooleanType.TRUE); + break; + } + } if (capability.getSupportsNotificationsV2() != CapabilityBooleanType.TRUE) { capability.setSupportsNotificationsV1(CapabilityBooleanType.TRUE); } diff --git a/library/src/main/java/com/owncloud/android/lib/resources/status/OCCapability.kt b/library/src/main/java/com/owncloud/android/lib/resources/status/OCCapability.kt index e0d0378f96..1a4d3717af 100644 --- a/library/src/main/java/com/owncloud/android/lib/resources/status/OCCapability.kt +++ b/library/src/main/java/com/owncloud/android/lib/resources/status/OCCapability.kt @@ -63,6 +63,7 @@ class OCCapability { var supportsNotificationsV1 = CapabilityBooleanType.UNKNOWN var supportsNotificationsV2 = CapabilityBooleanType.UNKNOWN + var supportsWebPush = CapabilityBooleanType.UNKNOWN var externalLinks = CapabilityBooleanType.UNKNOWN