aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Ng <chrng8@gmail.com>2023-11-07 18:20:49 -0800
committerChristopher Ng <chrng8@gmail.com>2023-11-15 17:13:14 -0800
commite1a934d90ccfb464db2aa0c2d0fc8b026e36a680 (patch)
tree5b98ef2c3a1c53f5e288b3ea15275f3fe36d40ae
parentf4d86818b287d265b402f5b2cb53a89689fbeffd (diff)
downloadnextcloud-server-e1a934d90ccfb464db2aa0c2d0fc8b026e36a680.tar.gz
nextcloud-server-e1a934d90ccfb464db2aa0c2d0fc8b026e36a680.zip
chore(systemtags): Add services for global tags and files-specific tags
Signed-off-by: Christopher Ng <chrng8@gmail.com>
-rw-r--r--apps/systemtags/src/services/api.ts69
-rw-r--r--apps/systemtags/src/services/files.ts82
-rw-r--r--apps/systemtags/src/types.ts2
3 files changed, 114 insertions, 39 deletions
diff --git a/apps/systemtags/src/services/api.ts b/apps/systemtags/src/services/api.ts
index 91393e0afe4..0e3b7e09c6e 100644
--- a/apps/systemtags/src/services/api.ts
+++ b/apps/systemtags/src/services/api.ts
@@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
+
import type { FileStat, ResponseDataDetailed } from 'webdav'
import type { ServerTag, Tag, TagWithId } from '../types.js'
@@ -30,7 +31,7 @@ import { davClient } from './davClient.js'
import { formatTag, parseIdFromLocation, parseTags } from '../utils'
import { logger } from '../logger.js'
-const fetchTagsBody = `<?xml version="1.0"?>
+export const fetchTagsBody = `<?xml version="1.0"?>
<d:propfind xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
<d:prop>
<oc:id />
@@ -67,39 +68,10 @@ export const fetchLastUsedTagIds = async (): Promise<number[]> => {
}
}
-export const fetchSelectedTags = async (fileId: number): Promise<TagWithId[]> => {
- const path = '/systemtags-relations/files/' + fileId
- try {
- const { data: tags } = await davClient.getDirectoryContents(path, {
- data: fetchTagsBody,
- details: true,
- glob: '/systemtags-relations/files/*/*', // Filter out first empty tag
- }) as ResponseDataDetailed<Required<FileStat>[]>
- return parseTags(tags)
- } catch (error) {
- logger.error(t('systemtags', 'Failed to load selected tags'), { error })
- throw new Error(t('systemtags', 'Failed to load selected tags'))
- }
-}
-
-export const selectTag = async (fileId: number, tag: Tag | ServerTag): Promise<void> => {
- const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
- const tagToPut = formatTag(tag)
- try {
- await davClient.customRequest(path, {
- method: 'PUT',
- data: tagToPut,
- })
- } catch (error) {
- logger.error(t('systemtags', 'Failed to select tag'), { error })
- throw new Error(t('systemtags', 'Failed to select tag'))
- }
-}
-
/**
* @return created tag id
*/
-export const createTag = async (fileId: number, tag: Tag): Promise<number> => {
+export const createTag = async (tag: Tag | ServerTag): Promise<number> => {
const path = '/systemtags'
const tagToPost = formatTag(tag)
try {
@@ -109,12 +81,7 @@ export const createTag = async (fileId: number, tag: Tag): Promise<number> => {
})
const contentLocation = headers.get('content-location')
if (contentLocation) {
- const tagToPut = {
- ...tagToPost,
- id: parseIdFromLocation(contentLocation),
- }
- await selectTag(fileId, tagToPut)
- return tagToPut.id
+ return parseIdFromLocation(contentLocation)
}
logger.error(t('systemtags', 'Missing "Content-Location" header'))
throw new Error(t('systemtags', 'Missing "Content-Location" header'))
@@ -124,8 +91,32 @@ export const createTag = async (fileId: number, tag: Tag): Promise<number> => {
}
}
-export const deleteTag = async (fileId: number, tag: Tag): Promise<void> => {
- const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
+export const updateTag = async (tag: TagWithId): Promise<void> => {
+ const path = '/systemtags/' + tag.id
+ const data = `<?xml version="1.0"?>
+ <d:propertyupdate xmlns:d="DAV:" xmlns:oc="http://owncloud.org/ns">
+ <d:set>
+ <d:prop>
+ <oc:display-name>${tag.displayName}</oc:display-name>
+ <oc:user-visible>${tag.userVisible}</oc:user-visible>
+ <oc:user-assignable>${tag.userAssignable}</oc:user-assignable>
+ </d:prop>
+ </d:set>
+ </d:propertyupdate>`
+
+ try {
+ await davClient.customRequest(path, {
+ method: 'PROPPATCH',
+ data,
+ })
+ } catch (error) {
+ logger.error(t('systemtags', 'Failed to update tag'), { error })
+ throw new Error(t('systemtags', 'Failed to update tag'))
+ }
+}
+
+export const deleteTag = async (tag: TagWithId): Promise<void> => {
+ const path = '/systemtags/' + tag.id
try {
await davClient.deleteFile(path)
} catch (error) {
diff --git a/apps/systemtags/src/services/files.ts b/apps/systemtags/src/services/files.ts
new file mode 100644
index 00000000000..7dbd04c5350
--- /dev/null
+++ b/apps/systemtags/src/services/files.ts
@@ -0,0 +1,82 @@
+/**
+ * @copyright 2023 Christopher Ng <chrng8@gmail.com>
+ *
+ * @author Christopher Ng <chrng8@gmail.com>
+ *
+ * @license AGPL-3.0-or-later
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero 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 Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+import type { FileStat, ResponseDataDetailed } from 'webdav'
+import type { ServerTagWithId, Tag, TagWithId } from '../types.js'
+
+import { davClient } from './davClient.js'
+import { createTag, fetchTagsBody } from './api.js'
+import { formatTag, parseTags } from '../utils.js'
+import { logger } from '../logger.js'
+
+export const fetchTagsForFile = async (fileId: number): Promise<TagWithId[]> => {
+ const path = '/systemtags-relations/files/' + fileId
+ try {
+ const { data: tags } = await davClient.getDirectoryContents(path, {
+ data: fetchTagsBody,
+ details: true,
+ glob: '/systemtags-relations/files/*/*', // Filter out first empty tag
+ }) as ResponseDataDetailed<Required<FileStat>[]>
+ return parseTags(tags)
+ } catch (error) {
+ logger.error(t('systemtags', 'Failed to load tags for file'), { error })
+ throw new Error(t('systemtags', 'Failed to load tags for file'))
+ }
+}
+
+/**
+ * @return created tag id
+ */
+export const createTagForFile = async (tag: Tag, fileId: number): Promise<number> => {
+ const tagToCreate = formatTag(tag)
+ const tagId = await createTag(tagToCreate)
+ const tagToSet: ServerTagWithId = {
+ ...tagToCreate,
+ id: tagId,
+ }
+ await setTagForFile(tagToSet, fileId)
+ return tagToSet.id
+}
+
+export const setTagForFile = async (tag: TagWithId | ServerTagWithId, fileId: number): Promise<void> => {
+ const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
+ const tagToPut = formatTag(tag)
+ try {
+ await davClient.customRequest(path, {
+ method: 'PUT',
+ data: tagToPut,
+ })
+ } catch (error) {
+ logger.error(t('systemtags', 'Failed to set tag for file'), { error })
+ throw new Error(t('systemtags', 'Failed to set tag for file'))
+ }
+}
+
+export const deleteTagForFile = async (tag: TagWithId, fileId: number): Promise<void> => {
+ const path = '/systemtags-relations/files/' + fileId + '/' + tag.id
+ try {
+ await davClient.deleteFile(path)
+ } catch (error) {
+ logger.error(t('systemtags', 'Failed to delete tag for file'), { error })
+ throw new Error(t('systemtags', 'Failed to delete tag for file'))
+ }
+}
diff --git a/apps/systemtags/src/types.ts b/apps/systemtags/src/types.ts
index c38a360c1fe..f2cff9b06c2 100644
--- a/apps/systemtags/src/types.ts
+++ b/apps/systemtags/src/types.ts
@@ -36,3 +36,5 @@ export type TagWithId = Required<Tag>
export type ServerTag = BaseTag & {
name: string
}
+
+export type ServerTagWithId = Required<ServerTag>