Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open internal file share links in chat via files client #3329

Merged
merged 3 commits into from
Sep 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 155 additions & 0 deletions app/src/androidTest/java/com/nextcloud/talk/utils/UriUtilsIT.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/*
* Nextcloud Talk application
*
* @author Samanwith KSN
* Copyright (C) 2023 Samanwith KSN <[email protected]>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.nextcloud.talk.utils

import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import org.junit.Test

class UriUtilsIT {

@Test
fun testHasHttpProtocolPrefixed() {
val uriHttp = "http://www.example.com"
val resultHttp = UriUtils.hasHttpProtocolPrefixed(uriHttp)
assertTrue(resultHttp)

val uriHttps = "https://www.example.com"
val resultHttps = UriUtils.hasHttpProtocolPrefixed(uriHttps)
assertTrue(resultHttps)

val uriWithoutPrefix = "www.example.com"
val resultWithoutPrefix = UriUtils.hasHttpProtocolPrefixed(uriWithoutPrefix)
assertFalse(resultWithoutPrefix)
}

@Test
fun testExtractInstanceInternalFileFileId() {
assertEquals(
"42",
UriUtils.extractInstanceInternalFileFileId(
"https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=42"
)
)
}

@Test
fun testExtractInstanceInternalFileShareFileId() {
assertEquals(
"42",
UriUtils.extractInstanceInternalFileShareFileId("https://cloud.nextcloud.com/f/42")
)
}

@Test
fun testIsInstanceInternalFileShareUrl() {
assertTrue(
UriUtils.isInstanceInternalFileShareUrl(
"https://cloud.nextcloud.com",
"https://cloud.nextcloud.com/f/42"
)
)

assertFalse(
UriUtils.isInstanceInternalFileShareUrl(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/f/42"
)
)

assertFalse(
UriUtils.isInstanceInternalFileShareUrl(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/f/"
)
)

assertFalse(
UriUtils.isInstanceInternalFileShareUrl(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/f/test123"
)
)
}

@Test
fun testIsInstanceInternalFileUrl() {
assertTrue(
UriUtils.isInstanceInternalFileUrl(
"https://cloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41"
)
)

assertFalse(
UriUtils.isInstanceInternalFileUrl(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41"
)
)

assertFalse(
UriUtils.isInstanceInternalFileUrl(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=test123"
)
)

assertFalse(
UriUtils.isInstanceInternalFileUrl(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid="
)
)

assertFalse(
UriUtils.isInstanceInternalFileUrl(
"https://cloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/?dir=/Engineering"
)
)
}

@Test
fun testIsInstanceInternalFileUrlNew() {
assertTrue(
UriUtils.isInstanceInternalFileUrlNew(
"https://cloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/files/41?dir=/"
)
)

assertFalse(
UriUtils.isInstanceInternalFileUrlNew(
"https://nextcloud.nextcloud.com",
"https://cloud.nextcloud.com/apps/files/files/41?dir=/"
)
)
}

@Test
fun testExtractInstanceInternalFileFileIdNew() {
assertEquals(
"42",
UriUtils.extractInstanceInternalFileFileIdNew("https://cloud.nextcloud.com/apps/files/files/42?dir=/")
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ class IncomingLocationMessageViewHolder(incomingView: View, payload: Any) :
binding.webview.webViewClient = object : WebViewClient() {
@Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)")
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && UriUtils.hasHttpProtocollPrefixed(url)
return if (url != null && UriUtils.hasHttpProtocolPrefixed(url)
) {
view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,14 +37,14 @@ import autodagger.AutoInjector
import coil.load
import com.google.android.flexbox.FlexboxLayout
import com.google.android.material.snackbar.Snackbar
import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.talk.R
import com.nextcloud.talk.application.NextcloudTalkApplication
import com.nextcloud.talk.application.NextcloudTalkApplication.Companion.sharedApplication
import com.nextcloud.talk.databinding.ItemCustomOutcomingLocationMessageBinding
import com.nextcloud.talk.models.json.chat.ChatMessage
import com.nextcloud.talk.models.json.chat.ReadStatus
import com.nextcloud.talk.ui.theme.ViewThemeUtils
import com.nextcloud.android.common.ui.theme.utils.ColorRole
import com.nextcloud.talk.utils.ApiUtils
import com.nextcloud.talk.utils.DateUtils
import com.nextcloud.talk.utils.UriUtils
Expand Down Expand Up @@ -164,7 +164,7 @@ class OutcomingLocationMessageViewHolder(incomingView: View) :
binding.webview.webViewClient = object : WebViewClient() {
@Deprecated("Use shouldOverrideUrlLoading(WebView view, WebResourceRequest request)")
override fun shouldOverrideUrlLoading(view: WebView?, url: String?): Boolean {
return if (url != null && UriUtils.hasHttpProtocollPrefixed(url)
return if (url != null && UriUtils.hasHttpProtocolPrefixed(url)
) {
view?.context?.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(url)))
true
Expand Down
29 changes: 29 additions & 0 deletions app/src/main/java/com/nextcloud/talk/chat/ChatActivity.kt
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ import com.nextcloud.talk.utils.MagicCharPolicy
import com.nextcloud.talk.utils.Mimetype
import com.nextcloud.talk.utils.NotificationUtils
import com.nextcloud.talk.utils.ParticipantPermissions
import com.nextcloud.talk.utils.UriUtils
import com.nextcloud.talk.utils.VibrationUtils
import com.nextcloud.talk.utils.bundle.BundleKeys
import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_CALL_VOICE_ONLY
Expand Down Expand Up @@ -2660,6 +2661,34 @@ class ChatActivity :
)
}

override fun startActivity(intent: Intent) {
val user = currentUserProvider.currentUser.blockingGet()
if (intent.data != null && TextUtils.equals(intent.action, Intent.ACTION_VIEW)) {
val uri = intent.data.toString()
if (uri.startsWith(user.baseUrl!!)) {
if (UriUtils.isInstanceInternalFileShareUrl(user.baseUrl!!, uri)) {
// https://cloud.nextcloud.com/f/41
val fileViewerUtils = FileViewerUtils(this, user)
fileViewerUtils.openFileInFilesApp(uri, UriUtils.extractInstanceInternalFileShareFileId(uri))
} else if (UriUtils.isInstanceInternalFileUrl(user.baseUrl!!, uri)) {
// https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41
val fileViewerUtils = FileViewerUtils(this, user)
fileViewerUtils.openFileInFilesApp(uri, UriUtils.extractInstanceInternalFileFileId(uri))
} else if (UriUtils.isInstanceInternalFileUrlNew(user.baseUrl!!, uri)) {
// https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41
val fileViewerUtils = FileViewerUtils(this, user)
fileViewerUtils.openFileInFilesApp(uri, UriUtils.extractInstanceInternalFileFileIdNew(uri))
} else {
super.startActivity(intent)
}
} else {
super.startActivity(intent)
}
} else {
super.startActivity(intent)
}
}

fun sendSelectLocalFileIntent() {
if (!permissionUtil.isFilesPermissionGranted()) {
requestReadFilesPermissions()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class AccountVerificationController(args: Bundle? = null) : BaseController(

if (
isAccountImport &&
!UriUtils.hasHttpProtocollPrefixed(baseUrl!!) ||
!UriUtils.hasHttpProtocolPrefixed(baseUrl!!) ||
isSameProtocol(baseUrl!!, originalProtocol!!)
) {
determineBaseUrlProtocol(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class ServerSelectionController :
url = url.substring(0, url.length - 1)
}

if (UriUtils.hasHttpProtocollPrefixed(url)) {
if (UriUtils.hasHttpProtocolPrefixed(url)) {
checkServer(url, false)
} else {
checkServer("https://$url", true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ class EntryMenuController(args: Bundle) :
}
binding?.textInputLayout?.isErrorEnabled = false
} else if (
UriUtils.hasHttpProtocollPrefixed(binding?.textEdit?.text.toString()) &&
UriUtils.hasHttpProtocolPrefixed(binding?.textEdit?.text.toString()) &&
binding?.textEdit?.text.toString().contains("/call/")
) {
if (!binding?.okButton?.isEnabled!!) {
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/java/com/nextcloud/talk/utils/AccountUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ object AccountUtils {
private fun matchAccounts(importAccount: ImportAccount, user: User): Boolean {
var accountFound = false
if (importAccount.token != null) {
if (UriUtils.hasHttpProtocollPrefixed(importAccount.baseUrl)) {
if (UriUtils.hasHttpProtocolPrefixed(importAccount.baseUrl)) {
if (
user.username == importAccount.username &&
user.baseUrl == importAccount.baseUrl
Expand Down
42 changes: 40 additions & 2 deletions app/src/main/java/com/nextcloud/talk/utils/UriUtils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,49 @@

package com.nextcloud.talk.utils

import android.net.Uri

class UriUtils {
companion object {

fun hasHttpProtocollPrefixed(uri: String): Boolean {
fun hasHttpProtocolPrefixed(uri: String): Boolean {
return uri.startsWith("http://") || uri.startsWith("https://")
}

fun extractInstanceInternalFileFileId(url: String): String {
// https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41
return Uri.parse(url).getQueryParameter("fileid").toString()
}

fun isInstanceInternalFileShareUrl(baseUrl: String, url: String): Boolean {
// https://cloud.nextcloud.com/f/41
return url.startsWith("$baseUrl/f/") || url.startsWith("$baseUrl/index.php/f/") &&
Regex(".*/f/d*").matches(url)
}

fun extractInstanceInternalFileShareFileId(url: String): String {
// https://cloud.nextcloud.com/f/41
return Uri.parse(url).lastPathSegment ?: ""
}

fun isInstanceInternalFileUrl(baseUrl: String, url: String): Boolean {
// https://cloud.nextcloud.com/apps/files/?dir=/Engineering&fileid=41
return (
url.startsWith("$baseUrl/apps/files/") ||
url.startsWith("$baseUrl/index.php/apps/files/")
) &&
Uri.parse(url).queryParameterNames.contains("fileid") &&
Regex(""".*fileid=\d*""").matches(url)
}

fun isInstanceInternalFileUrlNew(baseUrl: String, url: String): Boolean {
// https://cloud.nextcloud.com/apps/files/files/41?dir=/
return url.startsWith("$baseUrl/apps/files/files/") ||
url.startsWith("$baseUrl/index.php/apps/files/files/")
}

fun extractInstanceInternalFileFileIdNew(url: String): String {
// https://cloud.nextcloud.com/apps/files/files/41?dir=/
return Uri.parse(url).lastPathSegment ?: ""
}
}
}
41 changes: 0 additions & 41 deletions app/src/test/java/com/nextcloud/talk/utils/UriUtilsTest.kt

This file was deleted.

2 changes: 1 addition & 1 deletion detekt.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
build:
maxIssues: 117
maxIssues: 116
weights:
# complexity: 2
# LongParameterList: 1
Expand Down