Skip to content

Conversation

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented Dec 8, 2025

This is an automated pull request to merge tofik/update-organization-owner into dev.
It was created by the [Auto Pull Request] action.

…le the section del organization only for owner
@vercel
Copy link

vercel bot commented Dec 8, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
app Ready Ready Preview Comment Dec 8, 2025 7:12pm
1 Skipped Deployment
Project Deployment Preview Comments Updated (UTC)
portal Skipped Skipped Dec 8, 2025 7:12pm

@cursor
Copy link

cursor bot commented Dec 8, 2025

PR Summary

Adds POST /v1/organization/transfer-ownership with role-transfer logic and a Settings UI to transfer ownership; restricts delete to owners and updates OpenAPI docs.

  • Backend (API):
    • New Endpoint: POST /v1/organization/transfer-ownership in organization.controller.ts with request/response schemas and error responses.
    • Service Logic: organization.service.ts validates actors, prevents self-transfer, updates roles transactionally (owner -> current user loses owner, becomes admin; new owner gains owner).
    • DTO/Schemas: Added TransferOwnershipDto/ResponseDto, TRANSFER_OWNERSHIP_BODY, TRANSFER_OWNERSHIP_RESPONSES, and operation metadata.
  • Frontend (App):
    • Settings Page: Loads by orgId, fetches ownership context, renders TransferOwnership form, and shows DeleteOrganization only for owners.
    • New Component: TransferOwnership client form to pick member, confirm, and call API.
  • Docs:
    • OpenAPI: Documents the new transfer ownership endpoint and schemas.

Written by Cursor Bugbot for commit 5342d90. This will update automatically on new commits. Configure here.

@graphite-app graphite-app bot requested a review from Marfuen December 8, 2025 17:37
@graphite-app
Copy link

graphite-app bot commented Dec 8, 2025

Graphite Automations

"Auto-assign PRs to Author" took an action on this PR • (12/08/25)

1 reviewer was added to this PR based on Mariano Fuentes's automation.

// Get current user's member record
const currentUserMember = await db.member.findFirst({
where: { organizationId: orgId, userId: currentUserId },
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing deactivated check allows deactivated owner transfer

The currentUserMember query does not filter by deactivated: false, unlike similar patterns elsewhere in the codebase (e.g., add-comment.ts, change-organization.ts). This inconsistency means a deactivated member who still has the owner role could potentially execute the ownership transfer action. The new owner lookup correctly includes the deactivated: false check, but the current user's permission check does not.

Fix in Cursor Fix in Web

params: Promise<{ orgId: string }>;
}) {
const { orgId } = await params;
console.log('[OrganizationSettings Debug] orgId:', orgId);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Debug console.log statement left in production code

A console.log statement with a debug label [OrganizationSettings Debug] was left in the code. This appears to be debugging code that was accidentally committed and will output to logs in production, potentially leaking organization IDs in server logs.

Fix in Cursor Fix in Web

Comment on lines 104 to 120
const allMembers = await db.member.findMany({
where: {
organizationId: orgId,
},
select: {
id: true,
userId: true,
deactivated: true,
role: true,
user: {
select: {
name: true,
email: true,
},
},
},
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The allMembers query is executed but never used. This performs an unnecessary database query on every page load, fetching all members including deactivated ones. This wastes database resources and adds latency.

// Remove this unused query:
// const allMembers = await db.member.findMany({
//   where: {
//     organizationId: orgId,
//   },
//   ...
// });

If this was intended for debugging, it should be removed before merging to production.

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

Comment on lines 118 to 123
if (!authContext.userId) {
return {
success: false,
message: 'User ID is required for this operation',
};
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returns HTTP 200 with success: false when userId is missing, but the endpoint is already protected by @UseGuards(HybridAuthGuard). If authentication passes but userId is somehow missing, this indicates a critical auth system issue that should throw an exception, not return a 200 response.

This creates inconsistent error handling - other validation errors throw exceptions (400, 403, 404) but this returns 200. API consumers cannot reliably check HTTP status codes.

if (!authContext.userId) {
  throw new UnauthorizedException('User ID is required for this operation');
}
Suggested change
if (!authContext.userId) {
return {
success: false,
message: 'User ID is required for this operation',
};
}
if (!authContext.userId) {
throw new UnauthorizedException('User ID is required for this operation');
}

Spotted by Graphite Agent

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.


return organization;
});
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Missing authorization check allows cross-organization data access

The organizationDetails function fetches organization data using the orgId directly from URL params without validating that it matches the user's activeOrganizationId from their session. Previously this function used session?.session.activeOrganizationId from the cached session. Other similar functions in the codebase (like getContextEntries) properly verify session.session.activeOrganizationId === orgId before returning data. This could allow users to view organization details for any organization by manipulating the URL.

Fix in Cursor Fix in Web

// Get current user's member record
const currentUserMember = await db.member.findFirst({
where: { organizationId, userId: currentUserId },
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Deactivated owner can still transfer ownership

The currentUserMember query in transferOwnership doesn't filter by deactivated: false, unlike the query for newOwnerMember and other similar member queries elsewhere in the codebase (e.g., in hybrid-auth.guard.ts and comments.service.ts). This inconsistency could allow a deactivated member who still has the owner role to transfer ownership.

Fix in Cursor Fix in Web

@Marfuen Marfuen merged commit c432067 into main Dec 8, 2025
15 checks passed
@Marfuen Marfuen deleted the tofik/update-organization-owner branch December 8, 2025 19:14
@claudfuen
Copy link
Contributor

🎉 This PR is included in version 1.70.0 🎉

The release is available on GitHub release

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants