({
workspaceId,
fileId,
userId,
isActive,
authType,
password,
allowedEmails,
token,
}: UpsertFileShareInput)
| 109 | * later re-enable restores it. Validation failures throw {@link ShareValidationError}. |
| 110 | */ |
| 111 | export async function upsertFileShare({ |
| 112 | workspaceId, |
| 113 | fileId, |
| 114 | userId, |
| 115 | isActive, |
| 116 | authType, |
| 117 | password, |
| 118 | allowedEmails, |
| 119 | token, |
| 120 | }: UpsertFileShareInput): Promise<ShareRecord> { |
| 121 | const [existing] = await db |
| 122 | .select() |
| 123 | .from(publicShare) |
| 124 | .where(and(eq(publicShare.resourceType, 'file'), eq(publicShare.resourceId, fileId))) |
| 125 | .limit(1) |
| 126 | |
| 127 | const finalAuthType: ShareAuthType = |
| 128 | authType ?? (existing?.authType as ShareAuthType | undefined) ?? 'public' |
| 129 | const existingAllowedEmails = Array.isArray(existing?.allowedEmails) |
| 130 | ? (existing.allowedEmails as string[]) |
| 131 | : [] |
| 132 | |
| 133 | // Disabling preserves the stored config (and skips validation) so turning |
| 134 | // sharing off always succeeds; only enabling validates the chosen auth mode. |
| 135 | let finalPassword: string | null = existing?.password ?? null |
| 136 | let finalAllowedEmails: string[] = existingAllowedEmails |
| 137 | if (isActive) { |
| 138 | if (finalAuthType === 'password') { |
| 139 | if (password) { |
| 140 | finalPassword = (await encryptSecret(password)).encrypted |
| 141 | } else if (existing?.password) { |
| 142 | finalPassword = existing.password |
| 143 | } else { |
| 144 | throw new ShareValidationError('Password is required for password-protected shares') |
| 145 | } |
| 146 | finalAllowedEmails = [] |
| 147 | } else if (finalAuthType === 'email' || finalAuthType === 'sso') { |
| 148 | finalAllowedEmails = allowedEmails ?? existingAllowedEmails |
| 149 | if (finalAllowedEmails.length === 0) { |
| 150 | throw new ShareValidationError( |
| 151 | 'At least one allowed email is required for email/SSO shares' |
| 152 | ) |
| 153 | } |
| 154 | finalPassword = null |
| 155 | } else { |
| 156 | finalPassword = null |
| 157 | finalAllowedEmails = [] |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | const [row] = await db |
| 162 | .insert(publicShare) |
| 163 | .values({ |
| 164 | id: generateId(), |
| 165 | resourceType: 'file', |
| 166 | resourceId: fileId, |
| 167 | workspaceId, |
| 168 | createdBy: userId, |
no test coverage detected