diff --git a/packages/core/src/libraries/organization-invitation.ts b/packages/core/src/libraries/organization-invitation.ts index e582ca6d042..1c867a6c751 100644 --- a/packages/core/src/libraries/organization-invitation.ts +++ b/packages/core/src/libraries/organization-invitation.ts @@ -174,7 +174,7 @@ export class OrganizationInvitationLibrary { }); if (entity.organizationRoles.length > 0) { - await organizationQueries.relations.rolesUsers.insert( + await organizationQueries.relations.usersRoles.insert( ...entity.organizationRoles.map((role) => ({ organizationId: entity.organizationId, organizationRoleId: role.id, diff --git a/packages/core/src/libraries/user.ts b/packages/core/src/libraries/user.ts index aaa2d026ca1..43996fbd127 100644 --- a/packages/core/src/libraries/user.ts +++ b/packages/core/src/libraries/user.ts @@ -138,7 +138,7 @@ export const createUserLibrary = (queries: Queries) => { const usersRoles = await findUsersRolesByUserId(userId); const rolesScopes = await findRolesScopesByRoleIds(usersRoles.map(({ roleId }) => roleId)); const organizationScopes = findFromOrganizations - ? await organizations.relations.rolesUsers.getUserResourceScopes( + ? await organizations.relations.usersRoles.getUserResourceScopes( userId, resourceIndicator, organizationId @@ -295,7 +295,7 @@ export const createUserLibrary = (queries: Queries) => { })) ); if (data.length > 0) { - await organizations.relations.rolesUsers.insert(...data); + await organizations.relations.usersRoles.insert(...data); } return jitOrganizations; diff --git a/packages/core/src/oidc/grants/refresh-token.test.ts b/packages/core/src/oidc/grants/refresh-token.test.ts index 9839b4c802f..55110e6b58d 100644 --- a/packages/core/src/oidc/grants/refresh-token.test.ts +++ b/packages/core/src/oidc/grants/refresh-token.test.ts @@ -317,7 +317,7 @@ describe('organization token grant', () => { Sinon.stub(tenant.queries.organizations.relations.users, 'exists').resolves(true); Sinon.stub(tenant.queries.applications, 'findApplicationById').resolves(mockApplication); - Sinon.stub(tenant.queries.organizations.relations.rolesUsers, 'getUserScopes').resolves([ + Sinon.stub(tenant.queries.organizations.relations.usersRoles, 'getUserScopes').resolves([ { tenantId: 'default', id: 'foo', name: 'foo', description: 'foo' }, { tenantId: 'default', id: 'bar', name: 'bar', description: 'bar' }, { tenantId: 'default', id: 'baz', name: 'baz', description: 'baz' }, diff --git a/packages/core/src/oidc/grants/refresh-token.ts b/packages/core/src/oidc/grants/refresh-token.ts index d481cf13ee5..9bb2d232c45 100644 --- a/packages/core/src/oidc/grants/refresh-token.ts +++ b/packages/core/src/oidc/grants/refresh-token.ts @@ -338,7 +338,7 @@ export const buildHandler: ( /* === RFC 0001 === */ const audience = buildOrganizationUrn(organizationId); /** All available scopes for the user in the organization. */ - const availableScopes = await queries.organizations.relations.rolesUsers + const availableScopes = await queries.organizations.relations.usersRoles .getUserScopes(organizationId, account.accountId) .then((scopes) => scopes.map(({ name }) => name)); diff --git a/packages/core/src/queries/organization/role-application-relations.ts b/packages/core/src/queries/organization/application-role-relations.ts similarity index 96% rename from packages/core/src/queries/organization/role-application-relations.ts rename to packages/core/src/queries/organization/application-role-relations.ts index 58eda8fbea8..f576732c1fa 100644 --- a/packages/core/src/queries/organization/role-application-relations.ts +++ b/packages/core/src/queries/organization/application-role-relations.ts @@ -9,7 +9,7 @@ import { type CommonQueryMethods, sql } from '@silverhand/slonik'; import RelationQueries from '#src/utils/RelationQueries.js'; import { convertToIdentifiers } from '#src/utils/sql.js'; -export class RoleApplicationRelationQueries extends RelationQueries< +export class ApplicationRoleRelationQueries extends RelationQueries< [typeof Organizations, typeof OrganizationRoles, typeof Applications] > { constructor(pool: CommonQueryMethods) { diff --git a/packages/core/src/queries/organization/index.ts b/packages/core/src/queries/organization/index.ts index 84a40dbdc74..1d4d161c08e 100644 --- a/packages/core/src/queries/organization/index.ts +++ b/packages/core/src/queries/organization/index.ts @@ -32,11 +32,11 @@ import { TwoRelationsQueries } from '#src/utils/RelationQueries.js'; import SchemaQueries from '#src/utils/SchemaQueries.js'; import { conditionalSql, convertToIdentifiers } from '#src/utils/sql.js'; +import { ApplicationRoleRelationQueries } from './application-role-relations.js'; import { EmailDomainQueries } from './email-domains.js'; -import { RoleApplicationRelationQueries } from './role-application-relations.js'; -import { RoleUserRelationQueries } from './role-user-relations.js'; import { SsoConnectorQueries } from './sso-connectors.js'; import { UserRelationQueries } from './user-relations.js'; +import { UserRoleRelationQueries } from './user-role-relations.js'; /** * The schema field keys that can be used for searching roles. @@ -285,9 +285,8 @@ export default class OrganizationQueries extends SchemaQueries< ), /** Queries for organization - user relations. */ users: new UserRelationQueries(this.pool), - // TODO: Rename to `usersRoles` /** Queries for organization - organization role - user relations. */ - rolesUsers: new RoleUserRelationQueries(this.pool), + usersRoles: new UserRoleRelationQueries(this.pool), /** Queries for organization - application relations. */ apps: new TwoRelationsQueries( this.pool, @@ -295,9 +294,8 @@ export default class OrganizationQueries extends SchemaQueries< Organizations, Applications ), - // TODO: Rename to `appsRoles` /** Queries for organization - organization role - application relations. */ - rolesApps: new RoleApplicationRelationQueries(this.pool), + appsRoles: new ApplicationRoleRelationQueries(this.pool), invitationsRoles: new TwoRelationsQueries( this.pool, OrganizationInvitationRoleRelations.table, diff --git a/packages/core/src/queries/organization/role-user-relations.ts b/packages/core/src/queries/organization/user-role-relations.ts similarity index 98% rename from packages/core/src/queries/organization/role-user-relations.ts rename to packages/core/src/queries/organization/user-role-relations.ts index c3430fae40f..7f3573c3262 100644 --- a/packages/core/src/queries/organization/role-user-relations.ts +++ b/packages/core/src/queries/organization/user-role-relations.ts @@ -16,7 +16,7 @@ import { sql, type CommonQueryMethods } from '@silverhand/slonik'; import RelationQueries from '#src/utils/RelationQueries.js'; import { conditionalSql, convertToIdentifiers } from '#src/utils/sql.js'; -export class RoleUserRelationQueries extends RelationQueries< +export class UserRoleRelationQueries extends RelationQueries< [typeof Organizations, typeof OrganizationRoles, typeof Users] > { constructor(pool: CommonQueryMethods) { diff --git a/packages/core/src/routes/interaction/actions/submit-interaction.ts b/packages/core/src/routes/interaction/actions/submit-interaction.ts index 69576241904..3c37e9e8035 100644 --- a/packages/core/src/routes/interaction/actions/submit-interaction.ts +++ b/packages/core/src/routes/interaction/actions/submit-interaction.ts @@ -178,7 +178,7 @@ async function handleSubmitRegister( // This is only for Cloud integration tests and data alignment, OSS still uses the legacy Management API user role. const organizationId = getTenantOrganizationId(defaultTenantId); await organizations.relations.users.insert({ organizationId, userId: id }); - await organizations.relations.rolesUsers.insert({ + await organizations.relations.usersRoles.insert({ organizationId, organizationRoleId: getTenantRole(TenantRole.Admin).id, userId: id, diff --git a/packages/core/src/routes/organization/index.application-role-relations.ts b/packages/core/src/routes/organization/index.application-role-relations.ts index 6de2a909097..b9e3f6702ae 100644 --- a/packages/core/src/routes/organization/index.application-role-relations.ts +++ b/packages/core/src/routes/organization/index.application-role-relations.ts @@ -44,7 +44,7 @@ export default function applicationRoleRelationRoutes( async (ctx, next) => { const { id, applicationId } = ctx.guard.params; - const [totalCount, entities] = await organizations.relations.rolesApps.getEntities( + const [totalCount, entities] = await organizations.relations.appsRoles.getEntities( OrganizationRoles, { organizationId: id, @@ -71,7 +71,7 @@ export default function applicationRoleRelationRoutes( const { id, applicationId } = ctx.guard.params; const { organizationRoleIds } = ctx.guard.body; - await organizations.relations.rolesApps.insert( + await organizations.relations.appsRoles.insert( ...organizationRoleIds.map((organizationRoleId) => ({ organizationId: id, applicationId, @@ -97,7 +97,7 @@ export default function applicationRoleRelationRoutes( const { id, applicationId } = ctx.guard.params; const { organizationRoleIds } = ctx.guard.body; - await organizations.relations.rolesApps.replace(id, applicationId, organizationRoleIds); + await organizations.relations.appsRoles.replace(id, applicationId, organizationRoleIds); ctx.status = 204; return next(); @@ -113,7 +113,7 @@ export default function applicationRoleRelationRoutes( async (ctx, next) => { const { id, applicationId, organizationRoleId } = ctx.guard.params; - await organizations.relations.rolesApps.delete({ + await organizations.relations.appsRoles.delete({ organizationId: id, applicationId, organizationRoleId, diff --git a/packages/core/src/routes/organization/index.applications.openapi.json b/packages/core/src/routes/organization/index.applications.openapi.json index afa802114f7..23bebb126cf 100644 --- a/packages/core/src/routes/organization/index.applications.openapi.json +++ b/packages/core/src/routes/organization/index.applications.openapi.json @@ -148,7 +148,10 @@ "description": "The role was removed from the application in the organization successfully." }, "422": { - "description": "The role could not be removed. The role may not exist." + "description": "The application is not associated with the organization." + }, + "404": { + "description": "Cannot find the record to delete." } } } diff --git a/packages/core/src/routes/organization/index.jit.email-domains.ts b/packages/core/src/routes/organization/index.jit.email-domains.ts index 37e79f65dc9..fc5a28916e5 100644 --- a/packages/core/src/routes/organization/index.jit.email-domains.ts +++ b/packages/core/src/routes/organization/index.jit.email-domains.ts @@ -72,7 +72,7 @@ export default function emailDomainRoutes( `${pathname}/:emailDomain`, koaGuard({ params: z.object({ ...params, emailDomain: z.string().min(1) }), - status: [204], + status: [204, 404], }), async (ctx, next) => { const { id, emailDomain } = ctx.guard.params; diff --git a/packages/core/src/routes/organization/index.ts b/packages/core/src/routes/organization/index.ts index 9c37345655b..7b68a455f14 100644 --- a/packages/core/src/routes/organization/index.ts +++ b/packages/core/src/routes/organization/index.ts @@ -129,7 +129,7 @@ export default function organizationRoutes( const { id } = ctx.guard.params; const { userIds, organizationRoleIds } = ctx.guard.body; - await organizations.relations.rolesUsers.insert( + await organizations.relations.usersRoles.insert( ...organizationRoleIds.flatMap((roleId) => userIds.map((userId) => ({ organizationId: id, organizationRoleId: roleId, userId })) ) diff --git a/packages/core/src/routes/organization/index.user-role-relations.ts b/packages/core/src/routes/organization/index.user-role-relations.ts index 2afa1989e33..fa6898f9388 100644 --- a/packages/core/src/routes/organization/index.user-role-relations.ts +++ b/packages/core/src/routes/organization/index.user-role-relations.ts @@ -43,7 +43,7 @@ export default function userRoleRelationRoutes( async (ctx, next) => { const { id, userId } = ctx.guard.params; - const [totalCount, entities] = await organizations.relations.rolesUsers.getEntities( + const [totalCount, entities] = await organizations.relations.usersRoles.getEntities( OrganizationRoles, { organizationId: id, @@ -69,7 +69,7 @@ export default function userRoleRelationRoutes( const { id, userId } = ctx.guard.params; const { organizationRoleIds } = ctx.guard.body; - await organizations.relations.rolesUsers.insert( + await organizations.relations.usersRoles.insert( ...organizationRoleIds.map((roleId) => ({ organizationId: id, organizationRoleId: roleId, @@ -93,7 +93,7 @@ export default function userRoleRelationRoutes( const { id, userId } = ctx.guard.params; const { organizationRoleIds } = ctx.guard.body; - await organizations.relations.rolesUsers.replace(id, userId, organizationRoleIds); + await organizations.relations.usersRoles.replace(id, userId, organizationRoleIds); ctx.status = 204; return next(); @@ -109,7 +109,7 @@ export default function userRoleRelationRoutes( async (ctx, next) => { const { id, roleId, userId } = ctx.guard.params; - await organizations.relations.rolesUsers.delete({ + await organizations.relations.usersRoles.delete({ organizationId: id, organizationRoleId: roleId, userId, @@ -130,7 +130,7 @@ export default function userRoleRelationRoutes( async (ctx, next) => { const { id, userId } = ctx.guard.params; - const scopes = await organizations.relations.rolesUsers.getUserScopes(id, userId); + const scopes = await organizations.relations.usersRoles.getUserScopes(id, userId); ctx.body = scopes; return next(); diff --git a/packages/core/src/routes/organization/index.users.openapi.json b/packages/core/src/routes/organization/index.users.openapi.json index 5580e0b450a..174469303b0 100644 --- a/packages/core/src/routes/organization/index.users.openapi.json +++ b/packages/core/src/routes/organization/index.users.openapi.json @@ -190,8 +190,11 @@ "204": { "description": "The role was removed from the user successfully." }, + "422": { + "description": "The user is not a member of the organization." + }, "404": { - "description": "The user is not a member of the organization; or the user does not have the role." + "description": "Cannot find the record to delete." } } } diff --git a/packages/integration-tests/src/tests/api/organization/organization-application.test.ts b/packages/integration-tests/src/tests/api/organization/organization-application.test.ts index c231e1f915c..36ea50566bb 100644 --- a/packages/integration-tests/src/tests/api/organization/organization-application.test.ts +++ b/packages/integration-tests/src/tests/api/organization/organization-application.test.ts @@ -112,7 +112,7 @@ devFeatureTest.describe('organization application APIs', () => { ); const response = await organizationApi - .addApplicationRoles(organization.id, '0', [application.id]) + .addApplicationRoles(organization.id, application.id, ['0']) .catch((error: unknown) => error); assert(response instanceof HTTPError); expect(response.response.status).toBe(422);