Skip to content

Commit

Permalink
Merge pull request #1622 from nextcloud/tagColor
Browse files Browse the repository at this point in the history
Feature - Add Tag Color
  • Loading branch information
tobiasKaminsky authored Jan 21, 2025
2 parents e399f10 + 0b31cc6 commit 40fea7d
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 24 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,8 @@ class ReadFolderRemoteOperationIT : AbstractIT() {
assertEquals(remotePath + "1.txt", remoteFile.remotePath)
assertEquals(2, remoteFile.tags?.size)

remoteFile.tags?.sort()
assertEquals(tag1, remoteFile.tags?.get(0))
assertEquals(tag2, remoteFile.tags?.get(1))
remoteFile.tags?.sortBy { it?.name }
assertEquals(tag1, remoteFile.tags?.get(0)?.name)
assertEquals(tag2, remoteFile.tags?.get(1)?.name)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,20 @@ package com.owncloud.android.lib.resources.tags

import com.nextcloud.test.RandomStringGenerator
import com.owncloud.android.AbstractIT
import com.owncloud.android.lib.common.network.WebdavEntry
import com.owncloud.android.lib.resources.files.CreateFolderRemoteOperation
import com.owncloud.android.lib.resources.files.ReadFileRemoteOperation
import com.owncloud.android.lib.resources.files.ReadFolderRemoteOperation
import com.owncloud.android.lib.resources.files.model.RemoteFile
import com.owncloud.android.lib.resources.status.NextcloudVersion
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertTrue
import org.apache.commons.httpclient.HttpStatus
import org.apache.jackrabbit.webdav.client.methods.PropPatchMethod
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet
import org.apache.jackrabbit.webdav.property.DavPropertySet
import org.apache.jackrabbit.webdav.property.DefaultDavProperty
import org.apache.jackrabbit.webdav.xml.Namespace
import org.junit.Test

class GetTagsRemoteOperationIT : AbstractIT() {
Expand All @@ -19,7 +31,10 @@ class GetTagsRemoteOperationIT : AbstractIT() {
}

@Test
@Suppress("LongMethod")
fun list() {
testOnlyOnServer(NextcloudVersion.nextcloud_31)

var sut = GetTagsRemoteOperation().execute(client)
assertTrue(sut.isSuccess)

Expand All @@ -31,8 +46,66 @@ class GetTagsRemoteOperationIT : AbstractIT() {
.isSuccess
)

assertTrue(
CreateTagRemoteOperation(RandomStringGenerator.make(TAG_LENGTH))
.execute(nextcloudClient)
.isSuccess
)

sut = GetTagsRemoteOperation().execute(client)
assertTrue(sut.isSuccess)
assertEquals(count + 1, sut.resultData.size)
assertEquals(count + 2, sut.resultData.size)

// add color to one tag
val plainColor = "ff00ff"
val colorWithHex = "#$plainColor"
val tag1 = sut.resultData.first()
val tag2 = sut.resultData[1]
val newProps = DavPropertySet()
newProps.add(
DefaultDavProperty(
"nc:color",
plainColor,
Namespace.getNamespace(WebdavEntry.NAMESPACE_NC)
)
)
val propPatchMethod =
PropPatchMethod(
client.baseUri.toString() + "/remote.php/dav/systemtags/" + tag1.id,
newProps,
DavPropertyNameSet()
)
assertTrue(client.executeMethod(propPatchMethod) == HttpStatus.SC_MULTI_STATUS)

sut = GetTagsRemoteOperation().execute(client)

assertEquals(colorWithHex, sut.resultData.find { it.id == tag1.id }?.color)

// add colored tag to file
val tagFolder = "/coloredFolder/"
assertTrue(CreateFolderRemoteOperation(tagFolder, true).execute(client).isSuccess)
val folderMetadata = ReadFileRemoteOperation(tagFolder).execute(client)
assertTrue(
PutTagRemoteOperation(
tag1.id,
(folderMetadata.data[0] as RemoteFile).localId
).execute(nextcloudClient).isSuccess
)
assertTrue(
PutTagRemoteOperation(
tag2.id,
(folderMetadata.data[0] as RemoteFile).localId
).execute(nextcloudClient).isSuccess
)

// read metadata
val rootMetadata = ReadFolderRemoteOperation("/").execute(client)
val tags =
(rootMetadata.data as ArrayList<RemoteFile>)
.find { it.remotePath == tagFolder }
?.tags
assertEquals(2, tags?.size)
assertEquals(colorWithHex, tags?.first()?.color)
assertEquals(null, tags?.get(1)?.color)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import com.owncloud.android.lib.resources.files.model.GeoLocation
import com.owncloud.android.lib.resources.files.model.ImageDimension
import com.owncloud.android.lib.resources.shares.ShareType
import com.owncloud.android.lib.resources.shares.ShareeUser
import com.owncloud.android.lib.resources.tags.Tag
import org.apache.jackrabbit.webdav.MultiStatusResponse
import org.apache.jackrabbit.webdav.property.DavProperty
import org.apache.jackrabbit.webdav.property.DavPropertyName
Expand Down Expand Up @@ -90,7 +91,7 @@ class WebdavEntry constructor(
private set
var lockToken: String? = null
private set
var tags = arrayOfNulls<String>(0)
var tags = emptyArray<Tag?>()
var imageDimension: ImageDimension? = null
var geoLocation: GeoLocation? = null
var hidden = false
Expand Down Expand Up @@ -393,24 +394,23 @@ class WebdavEntry constructor(
}

prop = propSet[EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace]
if (prop != null && prop.value != null) {
if (prop.value is ArrayList<*>) {
val list = prop.value as ArrayList<*>
val tempList: MutableList<String> = ArrayList(list.size)
for (i in list.indices) {
val element = list[i] as Element
tempList.add(element.firstChild.textContent)
}
tags = tempList.toTypedArray()
} else {
// single item or empty
val element = prop.value as Element
val value = element.firstChild.textContent
if (prop?.value != null) {
tags =
when (prop.value) {
is ArrayList<*> ->
(prop.value as ArrayList<*>)
.filterIsInstance<Element>()
.map { parseTag(it) }
.toTypedArray()

is Element -> {
val element = (prop.value as Element)
val tag = parseTag(element)
arrayOf(tag)
}

if (value != null) {
tags = arrayOf(value)
else -> emptyArray()
}
}
}

// NC metadata size property <nc:file-metadata-size>
Expand Down Expand Up @@ -485,6 +485,18 @@ class WebdavEntry constructor(
}
}

private fun parseTag(element: Element): Tag {
val name = element.firstChild.textContent

val color =
if (element.getAttribute("nc:color").isNotEmpty()) {
"#" + element.getAttribute("nc:color")
} else {
null
}
return Tag(remoteId ?: "", name, color)
}

private fun parseLockProperties(
ncNamespace: Namespace,
propSet: DavPropertySet
Expand Down Expand Up @@ -659,6 +671,7 @@ class WebdavEntry constructor(
const val EXTENDED_PROPERTY_LOCK_TIMEOUT = "lock-timeout"
const val EXTENDED_PROPERTY_LOCK_TOKEN = "lock-token"
const val EXTENDED_PROPERTY_SYSTEM_TAGS = "system-tags"
const val EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR = "color"

// v27
const val EXTENDED_PROPERTY_METADATA_SIZE = "file-metadata-size"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public static DavPropertyNameSet getAllPropSet() {
propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TIMEOUT, ncNamespace);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_LOCK_TOKEN, ncNamespace);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_SYSTEM_TAGS, ncNamespace);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR, ncNamespace);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_SIZE, ncNamespace);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_GPS, ncNamespace);
propSet.add(WebdavEntry.EXTENDED_PROPERTY_METADATA_PHOTOS_SIZE, ncNamespace);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.owncloud.android.lib.common.network.WebdavEntry.MountType
import com.owncloud.android.lib.resources.files.FileUtils
import com.owncloud.android.lib.resources.files.model.FileLockType.Companion.fromValue
import com.owncloud.android.lib.resources.shares.ShareeUser
import com.owncloud.android.lib.resources.tags.Tag
import java.io.Serializable

/**
Expand Down Expand Up @@ -53,7 +54,7 @@ class RemoteFile :
var lockOwnerEditor: String? = null
var lockTimeout: Long = 0
var lockToken: String? = null
var tags: Array<String?>? = null
var tags: Array<Tag?>? = null
var imageDimension: ImageDimension? = null
var geoLocation: GeoLocation? = null
var hidden = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ package com.owncloud.android.lib.resources.tags

import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.EXTENDED_PROPERTY_NAME_REMOTE_ID
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.NAMESPACE_NC
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.NAMESPACE_OC
import com.owncloud.android.lib.common.network.WebdavEntry.Companion.SHAREES_DISPLAY_NAME
import com.owncloud.android.lib.common.operations.RemoteOperation
Expand All @@ -18,15 +20,18 @@ import org.apache.jackrabbit.webdav.client.methods.PropFindMethod
import org.apache.jackrabbit.webdav.property.DavPropertyNameSet
import org.apache.jackrabbit.webdav.xml.Namespace

@Suppress("NestedBlockDepth")
class GetTagsRemoteOperation : RemoteOperation<List<Tag>>() {
@Deprecated("Deprecated in Java")
override fun run(client: OwnCloudClient): RemoteOperationResult<List<Tag>> {
val ocNamespace = Namespace.getNamespace(NAMESPACE_OC)
val ncNamespace = Namespace.getNamespace(NAMESPACE_NC)

val propSet =
DavPropertyNameSet().apply {
add(EXTENDED_PROPERTY_NAME_REMOTE_ID, ocNamespace)
add(SHAREES_DISPLAY_NAME, ocNamespace)
add(EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR, ncNamespace)
}

val propFindMethod =
Expand Down Expand Up @@ -55,7 +60,17 @@ class GetTagsRemoteOperation : RemoteOperation<List<Tag>>() {
.get(SHAREES_DISPLAY_NAME, ocNamespace)
.value as String

result.add(Tag(id, name))
var color =
it
.getProperties(HttpStatus.SC_OK)
.get(EXTENDED_PROPERTY_SYSTEM_TAGS_COLOR, ncNamespace)
?.value as String?

if (color != null) {
color = "#$color"
}

result.add(Tag(id, name, color))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ package com.owncloud.android.lib.resources.tags

data class Tag(
val id: String,
val name: String
val name: String,
val color: String?
)

0 comments on commit 40fea7d

Please sign in to comment.