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

Fix resultToNode by adding some documenation how to use #741

Merged
merged 2 commits into from
Aug 23, 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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
51 changes: 51 additions & 0 deletions README.md
Expand Up @@ -2,3 +2,54 @@
[![npm last version](https://img.shields.io/npm/v/@nextcloud/files.svg?style=flat-square)](https://www.npmjs.com/package/@nextcloud/files) [![Code coverage](https://img.shields.io/codecov/c/github/nextcloud-libraries/nextcloud-files?style=flat-square)](https://app.codecov.io/gh/nextcloud-libraries/nextcloud-files) [![Project documentation](https://img.shields.io/badge/documentation-online-blue?style=flat-square)](https://nextcloud.github.io/nextcloud-files/)

Nextcloud Files helpers for Nextcloud apps and libraries

## Usage example

### Using WebDAV to query favorite nodes

```ts
import { davGetClient, davRootPath, getFavoriteNodes } from '@nextcloud/files'

const client = davGetClient()
// query favorites for the root folder (meaning all favorites)
const favorites = await getFavoriteNodes(client)
// which is the same as writing:
const favorites = await getFavoriteNodes(client, '/', davRootPath)
skjnldsv marked this conversation as resolved.
Show resolved Hide resolved
```

### Using WebDAV to list all nodes in directory

```ts
import {
davGetClient,
davGetDefaultPropfind,
davResultToNode,
davRootPath,
davRemoteURL
} from '@nextcloud/files'

// Get the DAV client for the default remote
const client = davGetClient()
// which is the same as writing
const client = davGetClient(davRemoteURL)
// of cause you can also configure another WebDAV remote
const client = davGetClient('https://example.com/dav')

const path = '/my-folder/' // the directory you want to list

// Query the directory content using the webdav library
// `davRootPath` is the files root, for Nextcloud this is '/files/USERID', by default the current user is used
const results = client.getDirectoryContents(`${davRootPath}${path}`, {
details: true,
// Query all required properties for a Node
data: davGetDefaultPropfind()
})

// Convert the result to an array of Node
const nodes = results.data.map((result) => davResultToNode(r))
// If you specified a different root in the `getDirectoryContents` you must add this also on the `davResultToNode` call:
const nodes = results.data.map((result) => davResultToNode(r, myRoot))
// Same if you used a different remote URL:
const nodes = results.data.map((result) => davResultToNode(r, myRoot, myRemoteURL))

```
60 changes: 59 additions & 1 deletion __tests__/dav/dav.spec.ts
@@ -1,7 +1,8 @@
import { afterAll, describe, expect, test, vi } from 'vitest'
import { readFile } from 'node:fs/promises'

import { File, Folder, davRemoteURL, davGetFavoritesReport, davRootPath, getFavoriteNodes } from '../../lib'
import { File, Folder, davRemoteURL, davGetFavoritesReport, davRootPath, getFavoriteNodes, davResultToNode } from '../../lib'
import { FileStat } from 'webdav'

vi.mock('@nextcloud/auth')
vi.mock('@nextcloud/router')
Expand All @@ -20,13 +21,70 @@
})
})

describe('davResultToNode', () => {
/* Result of:
davGetClient().getDirectoryContents(`${davRootPath}${path}`, { details: true })
*/
const result: FileStat = {
filename: '/files/test/New folder/Neue Textdatei.md',
basename: 'Neue Textdatei.md',
lastmod: 'Tue, 25 Jul 2023 12:29:34 GMT',
size: 123,
type: 'file',
etag: '7a27142de0a62ed27a7293dbc16e93bc',
mime: 'text/markdown',
props: {
resourcetype: { collection: false },
displayname: 'New File',
getcontentlength: '123',
getcontenttype: 'text/markdown',
getetag: '"7a27142de0a62ed27a7293dbc16e93bc"',
getlastmodified: 'Tue, 25 Jul 2023 12:29:34 GMT',
},
}

test('path does not contain root', () => {
const node = davResultToNode(result)
expect(node.basename).toBe(result.basename)
expect(node.extension).toBe('.md')
expect(node.source).toBe('https://localhost/dav/files/test/New folder/Neue Textdatei.md')
expect(node.root).toBe(davRootPath)
expect(node.path).toBe('/New folder/Neue Textdatei.md')
expect(node.dirname).toBe('/New folder')
expect(node.size).toBe(123)
expect(node.mtime?.getTime()).toBe(Date.parse(result.lastmod))
expect(node.mime).toBe(result.mime)
})

test('has correct root set', () => {
const remoteResult = { ...result, filename: '/root/New folder/Neue Textdatei.md' }
const node = davResultToNode(remoteResult, '/root')
expect(node.basename).toBe(remoteResult.basename)
expect(node.extension).toBe('.md')
expect(node.root).toBe('/root')
expect(node.source).toBe('https://localhost/dav/root/New folder/Neue Textdatei.md')
expect(node.path).toBe('/New folder/Neue Textdatei.md')
expect(node.dirname).toBe('/New folder')
})

test('has correct remote path set', () => {
const remoteResult = { ...result, filename: '/root/New folder/Neue Textdatei.md' }
const node = davResultToNode(remoteResult, '/root', 'http://example.com/dav')
expect(node.basename).toBe(remoteResult.basename)
expect(node.extension).toBe('.md')
expect(node.source).toBe('http://example.com/dav/root/New folder/Neue Textdatei.md')
expect(node.path).toBe('/New folder/Neue Textdatei.md')
expect(node.dirname).toBe('/New folder')
})
})

describe('DAV requests', () => {
test('request all favorite files', async () => {
const favoritesResponseJSON = JSON.parse((await readFile(new URL('../fixtures/favorites-response.json', import.meta.url))).toString())

// Mock the WebDAV client
const client = {
getDirectoryContents: vi.fn((path: string, options: any) => {

Check warning on line 87 in __tests__/dav/dav.spec.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
if (options?.details) {
return {
data: favoritesResponseJSON,
Expand Down Expand Up @@ -55,7 +113,7 @@

// Mock the WebDAV client
const client = {
getDirectoryContents: vi.fn((path: string, options: any) => {

Check warning on line 116 in __tests__/dav/dav.spec.ts

View workflow job for this annotation

GitHub Actions / eslint

Unexpected any. Specify a different type
if (options?.details) {
return {
data: favoritesResponseJSON,
Expand Down
2 changes: 1 addition & 1 deletion __tests__/fixtures/favorites-response.json
@@ -1 +1 @@
[{"filename":"/Neuer Ordner","basename":"Neuer Ordner","lastmod":"Mon, 24 Jul 2023 16:30:44 GMT","size":0,"type":"directory","etag":"64bea734d3987","props":{"getetag":"\"64bea734d3987\"","getlastmodified":"Mon, 24 Jul 2023 16:30:44 GMT","quota-available-bytes":-3,"resourcetype":{"collection":""},"has-preview":false,"is-encrypted":0,"mount-type":"","share-attributes":"[]","comments-unread":0,"favorite":1,"fileid":74,"owner-display-name":"user1","owner-id":"user1","permissions":"RGDNVCK","share-types":{"share-type":3},"size":0,"share-permissions":31}},{"filename":"/New folder/Neue Textdatei.md","basename":"Neue Textdatei.md","lastmod":"Tue, 25 Jul 2023 12:29:34 GMT","size":0,"type":"file","etag":"7a27142de0a62ed27a7293dbc16e93bc","mime":"text/markdown","props":{"getcontentlength":0,"getcontenttype":"text/markdown","getetag":"\"7a27142de0a62ed27a7293dbc16e93bc\"","getlastmodified":"Tue, 25 Jul 2023 12:29:34 GMT","resourcetype":"","has-preview":false,"mount-type":"shared","share-attributes":"[{\"scope\":\"permissions\",\"key\":\"download\",\"enabled\":false}]","comments-unread":0,"favorite":1,"fileid":80,"owner-display-name":"admin","owner-id":"admin","permissions":"SRGDNVW","share-types":"","size":0,"share-permissions":19}}]
[{"filename":"/files/test/Neuer Ordner","basename":"Neuer Ordner","lastmod":"Mon, 24 Jul 2023 16:30:44 GMT","size":0,"type":"directory","etag":"64bea734d3987","props":{"getetag":"\"64bea734d3987\"","getlastmodified":"Mon, 24 Jul 2023 16:30:44 GMT","quota-available-bytes":-3,"resourcetype":{"collection":""},"has-preview":false,"is-encrypted":0,"mount-type":"","share-attributes":"[]","comments-unread":0,"favorite":1,"fileid":74,"owner-display-name":"user1","owner-id":"user1","permissions":"RGDNVCK","share-types":{"share-type":3},"size":0,"share-permissions":31}},{"filename":"/files/test/New folder/Neue Textdatei.md","basename":"Neue Textdatei.md","lastmod":"Tue, 25 Jul 2023 12:29:34 GMT","size":0,"type":"file","etag":"7a27142de0a62ed27a7293dbc16e93bc","mime":"text/markdown","props":{"getcontentlength":0,"getcontenttype":"text/markdown","getetag":"\"7a27142de0a62ed27a7293dbc16e93bc\"","getlastmodified":"Tue, 25 Jul 2023 12:29:34 GMT","resourcetype":"","has-preview":false,"mount-type":"shared","share-attributes":"[{\"scope\":\"permissions\",\"key\":\"download\",\"enabled\":false}]","comments-unread":0,"favorite":1,"fileid":80,"owner-display-name":"admin","owner-id":"admin","permissions":"SRGDNVW","share-types":"","size":0,"share-permissions":19}}]
15 changes: 8 additions & 7 deletions lib/dav/dav.ts
Expand Up @@ -56,10 +56,10 @@
/**
* Get a WebDAV client configured to include the Nextcloud request token
*
* @param davURL The DAV remote URL
* @param remoteURL The DAV server remote URL
*/
export const davGetClient = function(davURL = davRemoteURL) {
const client = createClient(davURL, {
export const davGetClient = function(remoteURL = davRemoteURL) {
const client = createClient(remoteURL, {

Check warning on line 62 in lib/dav/dav.ts

View check run for this annotation

Codecov / codecov/patch

lib/dav/dav.ts#L62

Added line #L62 was not covered by tests
headers: {
requesttoken: getRequestToken() || '',
},
Expand Down Expand Up @@ -121,22 +121,23 @@
* Covert DAV result `FileStat` to `Node`
*
* @param node The DAV result
* @param davRoot The DAV root path
* @param filesRoot The DAV files root path
* @param remoteURL The DAV server remote URL (same as on `davGetClient`)
*/
export const davResultToNode = function(node: FileStat, davRoot = davRootPath): Node {
export const davResultToNode = function(node: FileStat, filesRoot = davRootPath, remoteURL = davRemoteURL): Node {
const props = node.props as ResponseProps
const permissions = davParsePermissions(props?.permissions)
const owner = getCurrentUser()?.uid as string

const nodeData: NodeData = {
id: (props?.fileid as number) || 0,
source: generateRemoteUrl(`dav${davRoot}${node.filename}`),
source: `${remoteURL}${node.filename}`,
mtime: new Date(Date.parse(node.lastmod)),
mime: node.mime as string,
size: props?.size || Number.parseInt(props.getcontentlength || '0'),
permissions,
owner,
root: davRoot,
root: filesRoot,
attributes: {
...node,
...props,
Expand Down