mirror of
https://github.com/simstudioai/sim.git
synced 2026-09-24 15:45:35 +08:00
feat(file): include public share status in File read output (#5191)
* feat(file): include public share status in File read output
The read operation now attaches each workspace file's public share status as a
"share" field (the share record, or null when not shared), batch-fetched via
getSharesForResources to avoid N+1. Picker/upload input files have no canonical
id and carry share: null.
* refactor(file): read share status uses visibility vocabulary, no row internals
Read's per-file "share" is now { visibility, url, allowedEmails } using the
same visibility vocabulary as Manage Sharing: 'private' when not shared (url
null, no config) instead of null, otherwise public/password/email/sso with the
link. Drops row internals (id, token, resourceType, resourceId, isActive,
hasPassword).
* fix(file): mark picker files private without a share lookup
Input (picker/upload) files only have a synthetic id (storage key/URL), so
looking them up in the shares map could collide with a canonical file id and
attach the wrong share. Give them an explicit private share instead.
* docs(file): terser share-status output descriptions
* chore(file): drop verbose comment in read share enrichment
This commit is contained in:
@@ -17,6 +17,7 @@ import { withRouteHandler } from '@/lib/core/utils/with-route-handler'
|
||||
import { isSupportedFileType, parseBuffer } from '@/lib/file-parsers'
|
||||
import {
|
||||
getShareForResource,
|
||||
getSharesForResources,
|
||||
ShareValidationError,
|
||||
upsertFileShare,
|
||||
} from '@/lib/public-shares/share-manager'
|
||||
@@ -417,12 +418,30 @@ export const POST = withRouteHandler(async (request: NextRequest) => {
|
||||
)
|
||||
}
|
||||
|
||||
const shares = await getSharesForResources('file', selectedFileIds)
|
||||
const privateReadShare = () => ({
|
||||
visibility: 'private' as const,
|
||||
url: null,
|
||||
allowedEmails: [] as string[],
|
||||
})
|
||||
const toReadShare = (fileId: string) => {
|
||||
const share = shares.get(fileId)
|
||||
if (!share || !share.isActive) return privateReadShare()
|
||||
return {
|
||||
visibility: share.authType,
|
||||
url: share.url,
|
||||
allowedEmails: share.allowedEmails,
|
||||
}
|
||||
}
|
||||
const userFiles = files
|
||||
.map((file) => workspaceFileToUserFile(file))
|
||||
.filter((file): file is NonNullable<ReturnType<typeof workspaceFileToUserFile>> =>
|
||||
Boolean(file)
|
||||
)
|
||||
.concat(selectedInputFiles)
|
||||
.map((file) => ({ ...file, share: toReadShare(file.id) }))
|
||||
// Picker/upload entries have only a synthetic id (storage key/URL), so they
|
||||
// never carry a canonical share — mark them private without a lookup.
|
||||
.concat(selectedInputFiles.map((file) => ({ ...file, share: privateReadShare() })))
|
||||
|
||||
logger.info('Files retrieved', {
|
||||
count: userFiles.length,
|
||||
|
||||
@@ -1361,7 +1361,7 @@ export const FileV5Block: BlockConfig<FileParserV3Output> = {
|
||||
files: {
|
||||
type: 'file[]',
|
||||
description:
|
||||
'Workspace file objects (read), fetched file objects (fetch), the compressed archive (compress), or extracted files (decompress)',
|
||||
'Workspace file objects with share status (read), fetched file objects (fetch), the compressed archive (compress), or extracted files (decompress)',
|
||||
},
|
||||
contents: {
|
||||
type: 'array',
|
||||
|
||||
Reference in New Issue
Block a user