-
Notifications
You must be signed in to change notification settings - Fork 54
feat: shared ledger access for invited users #1467
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
base: main
Are you sure you want to change the base?
Changes from all commits
badbaed
f60369e
ae60716
ad39b11
448e6cf
282e47d
f725f5b
48165a8
ad0e56e
d2555e6
4b64c28
dd3d430
274d08e
8970ac8
abc0e81
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -63,23 +63,46 @@ export async function addUserToLedger(ctx: FPApiSQLCtx, req: AddUserToLedger): P | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(and(eq(sqlLedgerUsers.userId, req.userId), ne(sqlLedgerUsers.default, 0))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .run(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ret = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| await ctx.db | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .insert(sqlLedgerUsers) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .values({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerId: ledger.Ledgers.ledgerId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: req.userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: req.userName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| role: req.role, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: req.right, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: req.default ? 1 : 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: now, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| updatedAt: now, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .returning() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| )[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const inserted = await ctx.db | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .insert(sqlLedgerUsers) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .values({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerId: ledger.Ledgers.ledgerId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: req.userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name: req.userName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| role: req.role, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: req.right, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: req.default ? 1 : 0, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| createdAt: now, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| updatedAt: now, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .onConflictDoNothing() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .returning(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (inserted.length === 0) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // User already exists in ledger, fetch existing record | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const existing = await ctx.db | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .select() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .from(sqlLedgerUsers) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .where(and(eq(sqlLedgerUsers.ledgerId, ledger.Ledgers.ledgerId), eq(sqlLedgerUsers.userId, req.userId))) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .get(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!existing) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.Err("failed to insert or find ledger user"); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.Ok({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerName: toUndef(ledger.Ledgers.name), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userName: toUndef(existing.name), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerId: ledger.Ledgers.ledgerId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tenantId: ledger.Ledgers.tenantId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| status: existing.status as UserStatus, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| statusReason: existing.statusReason, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userId: req.userId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| default: !!existing.default, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| role: toRole(existing.role), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| right: toReadWrite(existing.right), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+80
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix: Query must filter by role and status to match primary key. The conflict case query filters only by Apply this diff to filter by the correct role and status: const existing = await ctx.db
.select()
.from(sqlLedgerUsers)
- .where(and(eq(sqlLedgerUsers.ledgerId, ledger.Ledgers.ledgerId), eq(sqlLedgerUsers.userId, req.userId)))
+ .where(
+ and(
+ eq(sqlLedgerUsers.ledgerId, ledger.Ledgers.ledgerId),
+ eq(sqlLedgerUsers.userId, req.userId),
+ eq(sqlLedgerUsers.role, req.role),
+ eq(sqlLedgerUsers.status, "active")
+ )
+ )
.get();📝 Committable suggestion
Suggested change
🤖 Prompt for AI AgentsFix: Respect When Consider updating the existing record to set the default flag when if (!existing) {
return Result.Err("failed to insert or find ledger user");
}
+ // Update default flag if requested
+ if (req.default && !existing.default) {
+ await ctx.db
+ .update(sqlLedgerUsers)
+ .set({ default: 1, updatedAt: now })
+ .where(
+ and(
+ eq(sqlLedgerUsers.ledgerId, ledger.Ledgers.ledgerId),
+ eq(sqlLedgerUsers.userId, req.userId),
+ eq(sqlLedgerUsers.role, req.role)
+ )
+ )
+ .run();
+ }
return Result.Ok({
ledgerName: toUndef(ledger.Ledgers.name),
userName: toUndef(existing.name),
ledgerId: ledger.Ledgers.ledgerId,
tenantId: ledger.Ledgers.tenantId,
status: existing.status as UserStatus,
statusReason: existing.statusReason,
userId: req.userId,
- default: !!existing.default,
+ default: req.default ?? !!existing.default,
role: toRole(existing.role),
right: toReadWrite(existing.right),
});📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const ret = inserted[0]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return Result.Ok({ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerName: ledger.Ledgers.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerName: toUndef(ledger.Ledgers.name), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| userName: req.userName, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ledgerId: ledger.Ledgers.ledgerId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| tenantId: ledger.Ledgers.tenantId, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -88,39 +88,86 @@ export async function ensureCloudToken( | |
| return Result.Err(`no tenant found for binding of appId:${req.appId} userId:${req.auth.user.userId}`); | ||
| } | ||
| if (!ledgerId) { | ||
| // create ledger | ||
| const rCreateLedger = await createLedger(ctx, { | ||
| type: "reqCreateLedger", | ||
| auth: req.auth, | ||
| ledger: { | ||
| tenantId, | ||
| name: `${req.appId}-${req.auth.user.userId}`, | ||
| }, | ||
| }); | ||
| if (rCreateLedger.isErr()) { | ||
| return Result.Err(rCreateLedger.Err()); | ||
| } | ||
| ledgerId = rCreateLedger.Ok().ledger.ledgerId; | ||
| const maxBindings = await ctx.db | ||
| .select({ | ||
| total: count(sqlAppIdBinding.appId), | ||
| }) | ||
| // Check if there's already an AppIdBinding for this appId (without user join) | ||
| // This handles the case where an invited user visits before being added to the ledger | ||
| const existingBinding = await ctx.db | ||
| .select() | ||
| .from(sqlAppIdBinding) | ||
| .where(eq(sqlAppIdBinding.appId, req.appId)) | ||
| .innerJoin(sqlLedgers, eq(sqlLedgers.ledgerId, sqlAppIdBinding.ledgerId)) | ||
| .where(and(eq(sqlAppIdBinding.appId, req.appId), eq(sqlAppIdBinding.env, req.env ?? "prod"))) | ||
| .get(); | ||
|
Comment on lines
+91
to
98
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Implementation uses exact matching, not prefix matching as described The PR title and description emphasize "prefix matching" to find ledgers whose names start with the appId (e.g., matching .where(and(eq(sqlAppIdBinding.appId, req.appId), eq(sqlAppIdBinding.env, req.env ?? "prod")))There's no
Please clarify which approach is correct. Note that exact matching on 🤖 Prompt for AI Agents |
||
| if (maxBindings && maxBindings.total >= ctx.params.maxAppIdBindings) { | ||
| return Result.Err(`max appId bindings reached for appId:${req.appId}`); | ||
| if (existingBinding) { | ||
| console.log( | ||
| "[ensureCloudToken p0.49] existingBinding found for appId:", | ||
| req.appId, | ||
| "ledgerId:", | ||
| existingBinding.Ledgers.ledgerId, | ||
| ); | ||
| // Auto-redeem any pending invites for this user (ensureUser calls redeemInvite) | ||
| await ensureUser(ctx, { | ||
| type: "reqEnsureUser", | ||
| auth: req.auth.verifiedAuth, | ||
| }); | ||
| // Verify the user is actually in LedgerUsers before granting access (strict policy) | ||
| const userInLedger = await ctx.db | ||
| .select() | ||
| .from(sqlLedgerUsers) | ||
| .where( | ||
| and( | ||
| eq(sqlLedgerUsers.ledgerId, existingBinding.Ledgers.ledgerId), | ||
| eq(sqlLedgerUsers.userId, req.auth.user.userId), | ||
| eq(sqlLedgerUsers.status, "active"), | ||
| ), | ||
| ) | ||
| .get(); | ||
| console.log( | ||
| "[ensureCloudToken p0.49] userInLedger check for ledgerId:", | ||
| existingBinding.Ledgers.ledgerId, | ||
| "userId:", | ||
| req.auth.user.userId, | ||
| "found:", | ||
| !!userInLedger, | ||
| ); | ||
| if (!userInLedger) { | ||
| return Result.Err(`user not authorized for ledger - please accept the invite first`); | ||
| } | ||
| ledgerId = existingBinding.Ledgers.ledgerId; | ||
| tenantId = existingBinding.Ledgers.tenantId; | ||
| } else { | ||
| // create ledger | ||
| const rCreateLedger = await createLedger(ctx, { | ||
| type: "reqCreateLedger", | ||
| auth: req.auth, | ||
| ledger: { | ||
| tenantId, | ||
| name: req.appId, | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, let's examine the file context around line 129
cd dashboard/backend && cat -n public/ensure-cloud-token.ts | sed -n '115,140p'Repository: fireproof-storage/fireproof Length of output: 1084 🏁 Script executed: # Search for PR description or objectives in common locations
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "*.yml" -o -name "*.yaml" \) | head -20Repository: fireproof-storage/fireproof Length of output: 661 🏁 Script executed: # Search for other ledger creation patterns in the codebase
rg "name:\s*req\.appId|name:\s*\`.*appId.*userId" --type ts --type tsxRepository: fireproof-storage/fireproof Length of output: 98 🏁 Script executed: # Search for Ledgers table schema definition
rg "Ledgers.*table|CREATE.*TABLE.*Ledgers" --type ts --type tsx --type sql -A 10Repository: fireproof-storage/fireproof Length of output: 98 🏁 Script executed: # Search for how ledger naming is handled elsewhere in the codebase
rg "appId.*ownerUserId|ownerUserId.*appId" --type ts --type tsx -B 2 -A 2Repository: fireproof-storage/fireproof Length of output: 98 🏁 Script executed: # Let me adjust the search - remove tsx type and search more broadly
rg "name.*appId" --type ts -B 2 -A 2Repository: fireproof-storage/fireproof Length of output: 1609 🏁 Script executed: # Search for other createLedger calls to see naming patterns
rg "createLedger" --type ts -B 3 -A 3Repository: fireproof-storage/fireproof Length of output: 22537 🏁 Script executed: # Search for ownerUserId or userId in ledger context
rg "ownerUserId|userId.*ledger|ledger.*userId" --type ts -B 1 -A 1Repository: fireproof-storage/fireproof Length of output: 9109 🏁 Script executed: # Look for PR description in the repository (check git logs or PR-related files)
git log --oneline --all | head -20Repository: fireproof-storage/fireproof Length of output: 228 🏁 Script executed: # Check if there's a specific PR or branch with objectives
git branch -a | grep -E "801|enhance|ledger" || echo "No matching branches found"Repository: fireproof-storage/fireproof Length of output: 97 🏁 Script executed: # Look at the test section about ledger naming
sed -n '1,150p' dashboard/backend/tests/db-api.test.ts | grep -A 40 "appId.*ownerUserId"Repository: fireproof-storage/fireproof Length of output: 53 🏁 Script executed: # Look for the actual test implementation that uses appId-ownerUserId format
rg "appId.*userId|userId.*appId" dashboard/backend/tests/db-api.test.ts -B 5 -A 5Repository: fireproof-storage/fireproof Length of output: 53 🏁 Script executed: # Check if there are any TODOs or comments about ledger naming in ensure-cloud-token.ts
cat -n dashboard/backend/public/ensure-cloud-token.ts | sed -n '100,160p'Repository: fireproof-storage/fireproof Length of output: 2579 🏁 Script executed: # Look for all places where ledger names are created with appId
rg "name:\s*\`?\$?\{?req\.appId" dashboard/backend -B 3 -A 3Repository: fireproof-storage/fireproof Length of output: 558 🏁 Script executed: # Read the test section that mentions appId-ownerUserId more carefully
sed -n '1200,1350p' dashboard/backend/tests/db-api.test.tsRepository: fireproof-storage/fireproof Length of output: 4960 🏁 Script executed: # Check the git history of the ensure-cloud-token.ts file to see if there were recent changes
git log --oneline -20 -- dashboard/backend/public/ensure-cloud-token.tsRepository: fireproof-storage/fireproof Length of output: 143 🏁 Script executed: # Look for comments or TODOs about ledger naming in the codebase
rg "TODO|FIXME|XXX|HACK" dashboard/backend/public/ensure-cloud-token.ts dashboard/backend/tests/db-api.test.tsRepository: fireproof-storage/fireproof Length of output: 53 🏁 Script executed: # Search for any documentation on the intended ledger naming scheme
rg "ledger.*name|name.*format" --type md --type ts -B 2 -A 2Repository: fireproof-storage/fireproof Length of output: 23497 Ledger naming doesn't match documented format The test documentation describes ledger names as name: req.appId,This works for the current binding model (one appId per ledger per tenant), but deviates from the documented design. Either the code should be updated to use 🤖 Prompt for AI Agents |
||
| }, | ||
| }); | ||
| if (rCreateLedger.isErr()) { | ||
| return Result.Err(rCreateLedger.Err()); | ||
| } | ||
| ledgerId = rCreateLedger.Ok().ledger.ledgerId; | ||
| const maxBindings = await ctx.db | ||
| .select({ | ||
| total: count(sqlAppIdBinding.appId), | ||
| }) | ||
| .from(sqlAppIdBinding) | ||
| .where(eq(sqlAppIdBinding.appId, req.appId)) | ||
| .get(); | ||
| if (maxBindings && maxBindings.total >= ctx.params.maxAppIdBindings) { | ||
| return Result.Err(`max appId bindings reached for appId:${req.appId}`); | ||
| } | ||
|
Comment on lines
+150
to
+159
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check The Move the max-bindings check before ledger creation: } else {
+ // Validate binding quota before creating resources
+ const maxBindings = await ctx.db
+ .select({
+ total: count(sqlAppIdBinding.appId),
+ })
+ .from(sqlAppIdBinding)
+ .where(eq(sqlAppIdBinding.appId, req.appId))
+ .get();
+ if (maxBindings && maxBindings.total >= ctx.params.maxAppIdBindings) {
+ return Result.Err(`max appId bindings reached for appId:${req.appId}`);
+ }
+
// create ledger
const rCreateLedger = await createLedger(ctx, {
type: "reqCreateLedger",
auth: req.auth,
ledger: {
tenantId,
name: req.appId,
},
});
if (rCreateLedger.isErr()) {
return Result.Err(rCreateLedger.Err());
}
ledgerId = rCreateLedger.Ok().ledger.ledgerId;
- const maxBindings = await ctx.db
- .select({
- total: count(sqlAppIdBinding.appId),
- })
- .from(sqlAppIdBinding)
- .where(eq(sqlAppIdBinding.appId, req.appId))
- .get();
- if (maxBindings && maxBindings.total >= ctx.params.maxAppIdBindings) {
- return Result.Err(`max appId bindings reached for appId:${req.appId}`);
- }
🤖 Prompt for AI Agents |
||
| await ctx.db | ||
| .insert(sqlAppIdBinding) | ||
| .values({ | ||
| appId: req.appId, | ||
| env: req.env ?? "prod", | ||
| ledgerId, | ||
| tenantId, | ||
| createdAt: new Date().toISOString(), | ||
| }) | ||
| .run(); | ||
| } | ||
| await ctx.db | ||
| .insert(sqlAppIdBinding) | ||
| .values({ | ||
| appId: req.appId, | ||
| env: req.env ?? "prod", | ||
| ledgerId, | ||
| tenantId, | ||
| createdAt: new Date().toISOString(), | ||
| }) | ||
| .run(); | ||
| } | ||
| } else { | ||
| ledgerId = binding.Ledgers.ledgerId; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -121,10 +121,12 @@ export async function ensureUser(ctx: FPApiSQLCtx, req: ReqEnsureUser): Promise< | |
| } | ||
| } | ||
| // Auto-redeem any pending invites for this user | ||
| await redeemInvite(ctx, { | ||
| console.log("[ensureUser p0.47] calling redeemInvite for email:", auth.verifiedAuth.params.email); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove PII logging before production deployment. Email addresses and potentially other user identifiers in the redeemInvite result are being logged to console. This violates privacy regulations (GDPR, CCPA) and best practices. Remove or redact PII from these logs: - console.log("[ensureUser p0.47] calling redeemInvite for email:", auth.verifiedAuth.params.email);
+ console.log("[ensureUser p0.47] calling redeemInvite for user");
const redeemResult = await redeemInvite(ctx, {
type: "reqRedeemInvite",
auth,
});
- console.log("[ensureUser p0.47] redeemInvite result:", JSON.stringify(redeemResult));
+ console.log("[ensureUser p0.47] redeemInvite completed, found invites:", redeemResult.isOk() ? redeemResult.Ok().invites.length : 0);Also applies to: 129-129 🤖 Prompt for AI Agents |
||
| const redeemResult = await redeemInvite(ctx, { | ||
| type: "reqRedeemInvite", | ||
| auth, | ||
| }); | ||
| console.log("[ensureUser p0.47] redeemInvite result:", JSON.stringify(redeemResult)); | ||
| return Result.Ok({ | ||
| type: "resEnsureUser", | ||
| user: user, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,21 +13,37 @@ export async function redeemInvite( | |
| ctx: FPApiSQLCtx, | ||
| req: ReqWithVerifiedAuthUser<ReqRedeemInvite>, | ||
| ): Promise<Result<ResRedeemInvite>> { | ||
| const query = { | ||
| byString: req.auth.verifiedAuth.params.email, | ||
| byNick: req.auth.verifiedAuth.params.nick, | ||
| existingUserId: req.auth.user.userId, | ||
| }; | ||
| console.log("[redeemInvite p0.47] searching with query:", JSON.stringify(query)); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove PII logging and fix formatting issues. Two issues to address:
Fix PII logging and run - console.log("[redeemInvite p0.47] searching with query:", JSON.stringify(query));
+ console.log("[redeemInvite p0.47] searching for invites");
const foundInvites = await findInvite(ctx, { query });
- console.log("[redeemInvite p0.47] found invites:", foundInvites.length, "pending:", foundInvites.filter((i) => i.status === "pending").length);
- if (foundInvites.length > 0) {
- console.log("[redeemInvite p0.47] invite details:", JSON.stringify(foundInvites.map((i) => ({ id: i.inviteId, status: i.status, queryEmail: i.query.byEmail, ledger: i.invitedParams.ledger?.id }))));
- }
+ console.log("[redeemInvite p0.47] found invites:", foundInvites.length, "pending:", foundInvites.filter((i) => i.status === "pending").length);Also applies to: 24-26 🤖 Prompt for AI Agents |
||
| const foundInvites = await findInvite(ctx, { query }); | ||
| console.log( | ||
| "[redeemInvite p0.47] found invites:", | ||
| foundInvites.length, | ||
| "pending:", | ||
| foundInvites.filter((i) => i.status === "pending").length, | ||
| ); | ||
| if (foundInvites.length > 0) { | ||
| console.log( | ||
| "[redeemInvite p0.47] invite details:", | ||
| JSON.stringify( | ||
| foundInvites.map((i) => ({ | ||
| id: i.inviteId, | ||
| status: i.status, | ||
| queryEmail: i.query.byEmail, | ||
| ledger: i.invitedParams.ledger?.id, | ||
| })), | ||
| ), | ||
| ); | ||
| } | ||
| return Result.Ok({ | ||
| type: "resRedeemInvite", | ||
| invites: sqlToInviteTickets( | ||
| await Promise.all( | ||
| ( | ||
| await findInvite(ctx, { | ||
| query: { | ||
| byString: req.auth.verifiedAuth.params.email, | ||
| byNick: req.auth.verifiedAuth.params.nick, | ||
| existingUserId: req.auth.user.userId, | ||
| // TODO | ||
| // andProvider: req.auth.verifiedAuth.provider, | ||
| }, | ||
| }) | ||
| ) | ||
| foundInvites | ||
| .filter((i) => i.status === "pending") | ||
| .map(async (invite) => { | ||
| if (invite.invitedParams.tenant) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove PII logging before production deployment.
User IDs are logged to console (lines 163, 166), which may violate privacy regulations depending on how user IDs are classified in your system. Consider removing or redacting this PII.
Apply this diff:
Also applies to: 163-163, 166-166
🤖 Prompt for AI Agents