Skip to content

Commit 6445333

Browse files
committed
fix(backend:files): ensure locks are visible on anchored and shared files
1 parent 3071709 commit 6445333

File tree

4 files changed

+58
-16
lines changed

4 files changed

+58
-16
lines changed

backend/src/applications/files/interfaces/file-props.interface.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,15 @@ export interface FileProps extends Omit<File, 'ownerId' | 'spaceId' | 'spaceExte
2828
mime: string
2929
inTrash?: boolean
3030
// used with shares
31-
origin?: { ownerLogin: string; spaceAlias: string; spaceRootExternalPath?: string }
31+
origin?: {
32+
ownerId: number
33+
ownerLogin: string
34+
spaceId: number
35+
spaceAlias: string
36+
spaceExternalRootId: number
37+
spaceRootExternalPath: string
38+
shareExternalId: number
39+
}
3240
// root can be a share or a space root
3341
// enabled, and description are only used for shares
3442
root?: Pick<SpaceRoot, 'id' | 'alias' | 'permissions'> &

backend/src/applications/shares/services/shares-queries.service.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,17 +663,22 @@ export class SharesQueries {
663663
ctime: files.ctime,
664664
mtime: files.mtime,
665665
mime: files.mime,
666+
originOwnerId: sql`${originOwner.id}`.as('originOwnerId'),
666667
originOwnerLogin: sql`${originOwner.login}`.as('originOwnerLogin'),
668+
originSpaceId: sql`${spaces.id}`.as('originSpaceId'),
667669
originSpaceAlias: sql`${spaces.alias}`.as('originSpaceAlias'),
670+
originSpaceExternalRootId: sql`${files.spaceExternalRootId}`.as('originSpaceExternalRootId'),
668671
originSpaceRootExternalPath: sql`IF (${spacesRoots.externalPath} IS NULL,
669672
${shareSpaceRoot.externalPath}, ${spacesRoots.externalPath})`.as('originSpaceRootExternalPath'),
673+
originShareExternalId: sql`IF (${shares.externalPath} IS NOT NULL, ${shares.parentId}, NULL)`.as('originShareExternalId'),
670674
rootId: sql`${shares.id}`.as('rootId'),
671675
rootAlias: shares.alias,
672676
rootName: shares.name,
673677
rootDescription: shares.description,
674678
rootEnabled: shares.enabled,
675679
rootExternalPath: shares.externalPath,
676680
rootPermissions: sharesMembers.permissions,
681+
rootOwnerId: sql`${users.id}`.as('rootOwnerId'),
677682
rootOwnerLogin: sql`${users.login}`.as('rootOwnerLogin'),
678683
rootOwnerEmail: sql`${users.email}`.as('rootOwnerEmail'),
679684
rootOwnerFullName: userFullNameSQL(users).as('rootOwnerFullName'),
@@ -743,9 +748,13 @@ export class SharesQueries {
743748
mtime: unionAlias.mtime,
744749
mime: unionAlias.mime,
745750
origin: {
751+
ownerId: unionAlias.originOwnerId,
746752
ownerLogin: unionAlias.originOwnerLogin,
753+
spaceId: unionAlias.originSpaceId,
747754
spaceAlias: unionAlias.originSpaceAlias,
748-
spaceRootExternalPath: unionAlias.originSpaceRootExternalPath
755+
spaceExternalRootId: unionAlias.originSpaceExternalRootId,
756+
spaceRootExternalPath: unionAlias.originSpaceRootExternalPath,
757+
shareExternalId: unionAlias.originShareExternalId
749758
},
750759
root: {
751760
id: unionAlias.rootId,
@@ -755,7 +764,12 @@ export class SharesQueries {
755764
enabled: unionAlias.rootEnabled,
756765
externalPath: unionAlias.rootExternalPath,
757766
permissions: spaceGroupConcatPermissions(unionAlias.rootPermissions),
758-
owner: { login: unionAlias.rootOwnerLogin, email: unionAlias.rootOwnerEmail, fullName: unionAlias.rootOwnerFullName } as Owner
767+
owner: {
768+
id: unionAlias.rootOwnerId,
769+
login: unionAlias.rootOwnerLogin,
770+
email: unionAlias.rootOwnerEmail,
771+
fullName: unionAlias.rootOwnerFullName
772+
} satisfies Owner
759773
},
760774
shares: sql`IF (${sql.placeholder('withShares')}, ${concatDistinctObjectsInArray(unionAlias.childShareId, {
761775
id: unionAlias.childShareId,

backend/src/applications/spaces/services/spaces-browser.service.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { HttpException, Injectable, Logger } from '@nestjs/common'
88
import fs from 'node:fs/promises'
99
import path from 'node:path'
1010
import { configuration } from '../../../configuration/config.environment'
11+
import { FileDBProps } from '../../files/interfaces/file-db-props.interface'
1112
import { FileLock } from '../../files/interfaces/file-lock.interface'
1213
import { FileProps } from '../../files/interfaces/file-props.interface'
1314
import { FilesLockManager } from '../../files/services/files-lock-manager.service'
@@ -17,7 +18,6 @@ import { dirName, fileName, getProps } from '../../files/utils/files'
1718
import { SharesQueries } from '../../shares/services/shares-queries.service'
1819
import { USER_PERMISSION } from '../../users/constants/user'
1920
import { UserModel } from '../../users/models/user.model'
20-
import { LOCK_SCOPE } from '../../webdav/constants/webdav'
2121
import { SpaceFiles } from '../interfaces/space-files.interface'
2222
import { SpaceEnv } from '../models/space-env.model'
2323
import { IsRealPathIsDirAndExists, realPathFromRootFile } from '../utils/paths'
@@ -56,7 +56,8 @@ export class SpacesBrowser {
5656
this.parseRootFiles(user, space, {
5757
withShares: options.withSpacesAndShares,
5858
withHasComments: options.withHasComments,
59-
withSyncs: options.withSyncs
59+
withSyncs: options.withSyncs,
60+
withLocks: options.withLocks
6061
})
6162
])
6263
this.updateDBFiles(user, space, dbFiles, fsFiles, options)
@@ -83,6 +84,7 @@ export class SpacesBrowser {
8384
withShares?: boolean
8485
withHasComments?: boolean
8586
withSyncs?: boolean
87+
withLocks?: boolean
8688
}
8789
): Promise<FileProps[]> {
8890
if (space.inFilesRepository && space.id && !space.root.alias) {
@@ -155,9 +157,12 @@ export class SpacesBrowser {
155157
}
156158
}
157159

158-
private async updateRootFile(f: FileProps, options: { withShares?: boolean; withHasComments?: boolean; withSyncs?: boolean }): Promise<FileProps> {
159-
// get realpath
160+
private async updateRootFile(
161+
f: FileProps,
162+
options: { withShares?: boolean; withHasComments?: boolean; withSyncs?: boolean; withLocks?: boolean }
163+
): Promise<FileProps> {
160164
const realPath = realPathFromRootFile(f)
165+
const originalPath = f.path
161166
f.path = f.root.name
162167
try {
163168
const fileProps: FileProps = await getProps(realPath, f.path)
@@ -170,8 +175,28 @@ export class SpacesBrowser {
170175
if (options.withSyncs) {
171176
fileProps.syncs = f.syncs
172177
}
178+
if (options.withLocks && (f.origin || f.root?.owner)) {
179+
// `f.origin` is used for shares
180+
// `f.root.owner` is used for anchored files in spaces
181+
// all other files are handled in the `enrichWithLocks` function
182+
const dbFile: FileDBProps = {
183+
...(f.origin?.spaceId
184+
? { spaceId: f.origin.spaceId, ...(f.origin.spaceExternalRootId ? { spaceExternalRootId: f.origin.spaceExternalRootId } : {}) }
185+
: f.origin?.shareExternalId
186+
? { shareExternalId: f.origin.shareExternalId }
187+
: { ownerId: f.origin?.ownerId ?? f.root.owner.id }),
188+
path: originalPath,
189+
inTrash: f.inTrash
190+
}
191+
const locks = await this.filesLockManager.getLocksByPath(dbFile)
192+
if (locks.length > 0) {
193+
fileProps.lock = this.filesLockManager.convertLockToFileLockProps(locks[0])
194+
}
195+
}
196+
// `owner.id` is only used in the `withLocks` condition
197+
delete f.root.owner?.id
198+
// check `f.id`; it can be null for external roots
173199
if (f.id) {
174-
// f.id is null for external roots
175200
// todo: check if a db file referenced under external roots have an id and correctly parsed here
176201
this.filesQueries.compareAndUpdateFileProps(f, fileProps).catch((e: Error) => this.logger.error(`${this.updateRootFile.name} - ${e}`))
177202
fileProps.id = f.id
@@ -299,13 +324,8 @@ export class SpacesBrowser {
299324
}
300325
const locks: Record<string, FileLock> = await this.filesLockManager.browseParentChildLocks(space.dbFile, false)
301326
if (!Object.keys(locks).length) return
302-
for (const f of files.filter((f) => (f.root && f.root.alias in locks) || (!f.root && f.name in locks))) {
303-
const lock: FileLock = f.root ? locks[f.root.alias] : locks[f.name]
304-
f.lock = {
305-
owner: lock?.davLock?.owner || `${lock.owner.fullName} (${lock.owner.email})`,
306-
ownerLogin: lock.owner.login,
307-
isExclusive: lock?.davLock?.lockscope ? lock?.davLock?.lockscope === LOCK_SCOPE.EXCLUSIVE : true
308-
}
327+
for (const f of files.filter((f) => !f.root && !f.origin && f.name in locks)) {
328+
f.lock = this.filesLockManager.convertLockToFileLockProps(locks[f.name])
309329
}
310330
}
311331
}

backend/src/applications/spaces/services/spaces-queries.service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ export class SpacesQueries {
269269
name: spacesRoots.name,
270270
externalPath: spacesRoots.externalPath,
271271
permissions: spacesRoots.permissions,
272-
owner: { login: users.login, email: users.email, fullName: userFullNameSQL(users) }
272+
owner: { id: users.id, login: users.login, email: users.email, fullName: userFullNameSQL(users) }
273273
},
274274
shares: sql`IF (${sql.placeholder('withShares')}, ${concatDistinctObjectsInArray(shares.id, {
275275
id: shares.id,

0 commit comments

Comments
 (0)