mirror of
https://github.com/logto-io/logto.git
synced 2024-12-30 20:33:54 -05:00
feat(core,test,phrases): add application-role related APIs (#4425)
This commit is contained in:
parent
285aa745e7
commit
9251c2bb40
36 changed files with 584 additions and 0 deletions
|
@ -2,6 +2,7 @@ import { VerificationCodeType } from '@logto/connector-kit';
|
|||
import type {
|
||||
AdminConsoleData,
|
||||
Application,
|
||||
ApplicationsRole,
|
||||
Passcode,
|
||||
Resource,
|
||||
Role,
|
||||
|
@ -120,3 +121,10 @@ export const mockUserRole: UsersRole = {
|
|||
userId: 'foo',
|
||||
roleId: 'role_id',
|
||||
};
|
||||
|
||||
export const mockApplicationRole: ApplicationsRole = {
|
||||
tenantId: 'fake_tenant',
|
||||
id: 'application_role_id',
|
||||
applicationId: 'application_id',
|
||||
roleId: 'role_id',
|
||||
};
|
||||
|
|
98
packages/core/src/routes/application-role.test.ts
Normal file
98
packages/core/src/routes/application-role.test.ts
Normal file
|
@ -0,0 +1,98 @@
|
|||
import { ApplicationType } from '@logto/schemas';
|
||||
import { pickDefault } from '@logto/shared/esm';
|
||||
|
||||
import {
|
||||
mockAdminApplicationRole,
|
||||
mockApplication,
|
||||
mockAdminUserRole2,
|
||||
mockApplicationRole,
|
||||
} from '#src/__mocks__/index.js';
|
||||
import { mockId, mockStandardId } from '#src/test-utils/nanoid.js';
|
||||
import { MockTenant } from '#src/test-utils/tenant.js';
|
||||
import { createRequester } from '#src/utils/test-utils.js';
|
||||
|
||||
const { jest } = import.meta;
|
||||
|
||||
await mockStandardId();
|
||||
|
||||
const mockM2mApplication = { ...mockApplication, type: ApplicationType.MachineToMachine };
|
||||
|
||||
const applications = { findApplicationById: jest.fn(async () => mockM2mApplication) };
|
||||
|
||||
const roles = {
|
||||
findRolesByRoleIds: jest.fn(),
|
||||
findRoleById: jest.fn(),
|
||||
countRoles: jest.fn(async () => ({ count: 1 })),
|
||||
findRoles: jest.fn(async () => [mockAdminApplicationRole]),
|
||||
};
|
||||
const { findRolesByRoleIds } = roles;
|
||||
|
||||
const applicationsRoles = {
|
||||
findApplicationsRolesByApplicationId: jest.fn(),
|
||||
insertApplicationsRoles: jest.fn(),
|
||||
deleteApplicationRole: jest.fn(),
|
||||
};
|
||||
const { findApplicationsRolesByApplicationId, insertApplicationsRoles, deleteApplicationRole } =
|
||||
applicationsRoles;
|
||||
|
||||
const tenantContext = new MockTenant(undefined, { applicationsRoles, applications, roles });
|
||||
|
||||
const applicationRoleRoutes = await pickDefault(import('./application-role.js'));
|
||||
|
||||
describe('application role routes', () => {
|
||||
const applicationRoleRequester = createRequester({
|
||||
authedRoutes: applicationRoleRoutes,
|
||||
tenantContext,
|
||||
});
|
||||
|
||||
it('GET /applications/:applicationId/roles', async () => {
|
||||
findApplicationsRolesByApplicationId.mockResolvedValueOnce([]);
|
||||
const response = await applicationRoleRequester.get(
|
||||
`/applications/${mockM2mApplication.id}/roles`
|
||||
);
|
||||
expect(response.status).toEqual(200);
|
||||
expect(response.body).toEqual([mockAdminApplicationRole]);
|
||||
});
|
||||
|
||||
it('POST /applications/:applicationId/roles', async () => {
|
||||
findApplicationsRolesByApplicationId.mockResolvedValueOnce([]);
|
||||
findRolesByRoleIds.mockResolvedValueOnce([]);
|
||||
const response = await applicationRoleRequester
|
||||
.post(`/applications/${mockM2mApplication.id}/roles`)
|
||||
.send({
|
||||
roleIds: [mockAdminApplicationRole.id],
|
||||
});
|
||||
expect(response.status).toEqual(201);
|
||||
expect(insertApplicationsRoles).toHaveBeenCalledWith([
|
||||
{ id: mockId, applicationId: mockM2mApplication.id, roleId: mockAdminApplicationRole.id },
|
||||
]);
|
||||
});
|
||||
|
||||
it('PUT /applications/:applicationId/roles', async () => {
|
||||
findApplicationsRolesByApplicationId.mockResolvedValueOnce([mockApplicationRole]);
|
||||
const response = await applicationRoleRequester
|
||||
.put(`/applications/${mockM2mApplication.id}/roles`)
|
||||
.send({
|
||||
roleIds: [mockAdminUserRole2.id],
|
||||
});
|
||||
expect(response.status).toEqual(200);
|
||||
expect(deleteApplicationRole).toHaveBeenCalledWith(
|
||||
mockM2mApplication.id,
|
||||
mockAdminApplicationRole.id
|
||||
);
|
||||
expect(insertApplicationsRoles).toHaveBeenCalledWith([
|
||||
{ id: mockId, applicationId: mockM2mApplication.id, roleId: mockAdminUserRole2.id },
|
||||
]);
|
||||
});
|
||||
|
||||
it('DELETE /applications/:applicationId/roles/:roleId', async () => {
|
||||
const response = await applicationRoleRequester.delete(
|
||||
`/applications/${mockM2mApplication.id}/roles/${mockAdminApplicationRole.id}`
|
||||
);
|
||||
expect(response.status).toEqual(204);
|
||||
expect(deleteApplicationRole).toHaveBeenCalledWith(
|
||||
mockM2mApplication.id,
|
||||
mockAdminApplicationRole.id
|
||||
);
|
||||
});
|
||||
});
|
206
packages/core/src/routes/application-role.ts
Normal file
206
packages/core/src/routes/application-role.ts
Normal file
|
@ -0,0 +1,206 @@
|
|||
import { ApplicationType, RoleType, Roles } from '@logto/schemas';
|
||||
import { generateStandardId } from '@logto/shared';
|
||||
import { tryThat } from '@silverhand/essentials';
|
||||
import { array, object, string } from 'zod';
|
||||
|
||||
import RequestError from '#src/errors/RequestError/index.js';
|
||||
import koaGuard from '#src/middleware/koa-guard.js';
|
||||
import koaPagination from '#src/middleware/koa-pagination.js';
|
||||
import koaRoleRlsErrorHandler from '#src/middleware/koa-role-rls-error-handler.js';
|
||||
import assertThat from '#src/utils/assert-that.js';
|
||||
import { parseSearchParamsForSearch } from '#src/utils/search.js';
|
||||
|
||||
import type { AuthedRouter, RouterInitArgs } from './types.js';
|
||||
|
||||
export default function applicationRoleRoutes<T extends AuthedRouter>(
|
||||
...[router, { queries }]: RouterInitArgs<T>
|
||||
) {
|
||||
const {
|
||||
roles: { findRoleById, countRoles, findRoles, findRolesByRoleIds },
|
||||
applications: { findApplicationById },
|
||||
applicationsRoles: {
|
||||
findApplicationsRolesByApplicationId,
|
||||
insertApplicationsRoles,
|
||||
deleteApplicationRole,
|
||||
},
|
||||
} = queries;
|
||||
|
||||
router.use('/applications/:applicationId/roles(/.*)?', koaRoleRlsErrorHandler());
|
||||
|
||||
router.get(
|
||||
'/applications/:applicationId/roles',
|
||||
koaPagination(),
|
||||
koaGuard({
|
||||
params: object({ applicationId: string() }),
|
||||
response: array(Roles.guard),
|
||||
status: [200, 400, 404, 422],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { applicationId } = ctx.guard.params;
|
||||
const { limit, offset } = ctx.pagination;
|
||||
const { searchParams } = ctx.request.URL;
|
||||
|
||||
const application = await findApplicationById(applicationId);
|
||||
assertThat(
|
||||
application.type === ApplicationType.MachineToMachine,
|
||||
new RequestError({
|
||||
code: 'application.invalid_type',
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
|
||||
return tryThat(
|
||||
async () => {
|
||||
const search = parseSearchParamsForSearch(searchParams);
|
||||
const applicationRoles = await findApplicationsRolesByApplicationId(applicationId);
|
||||
const roleIds = applicationRoles.map(({ roleId }) => roleId);
|
||||
const [{ count }, roles] = await Promise.all([
|
||||
countRoles(search, { roleIds }),
|
||||
findRoles(search, limit, offset, { roleIds }),
|
||||
]);
|
||||
|
||||
// Return totalCount to pagination middleware
|
||||
ctx.pagination.totalCount = count;
|
||||
ctx.body = roles;
|
||||
|
||||
return next();
|
||||
},
|
||||
(error) => {
|
||||
if (error instanceof TypeError) {
|
||||
throw new RequestError(
|
||||
{ code: 'request.invalid_input', details: error.message },
|
||||
error
|
||||
);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/applications/:applicationId/roles',
|
||||
koaGuard({
|
||||
params: object({ applicationId: string() }),
|
||||
body: object({ roleIds: string().min(1).array() }),
|
||||
status: [201, 404, 422],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
params: { applicationId },
|
||||
body: { roleIds },
|
||||
} = ctx.guard;
|
||||
|
||||
const application = await findApplicationById(applicationId);
|
||||
assertThat(
|
||||
application.type === ApplicationType.MachineToMachine,
|
||||
new RequestError({
|
||||
code: 'application.invalid_type',
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
const applicationRoles = await findApplicationsRolesByApplicationId(applicationId);
|
||||
|
||||
const roles = await findRolesByRoleIds(roleIds);
|
||||
|
||||
for (const role of roles) {
|
||||
assertThat(
|
||||
!applicationRoles.some(({ roleId: _roleId }) => _roleId === role.id),
|
||||
new RequestError({
|
||||
code: 'application.role_exists',
|
||||
status: 422,
|
||||
roleId: role.id,
|
||||
})
|
||||
);
|
||||
assertThat(
|
||||
role.type === RoleType.MachineToMachine,
|
||||
new RequestError({
|
||||
code: 'application.invalid_role_type',
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
await Promise.all(roleIds.map(async (roleId) => findRoleById(roleId)));
|
||||
await insertApplicationsRoles(
|
||||
roleIds.map((roleId) => ({ id: generateStandardId(), applicationId, roleId }))
|
||||
);
|
||||
ctx.status = 201;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.put(
|
||||
'/applications/:applicationId/roles',
|
||||
koaGuard({
|
||||
params: object({ applicationId: string() }),
|
||||
body: object({ roleIds: string().min(1).array() }),
|
||||
status: [200, 404, 422],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
params: { applicationId },
|
||||
body: { roleIds },
|
||||
} = ctx.guard;
|
||||
|
||||
const application = await findApplicationById(applicationId);
|
||||
assertThat(
|
||||
application.type === ApplicationType.MachineToMachine,
|
||||
new RequestError({
|
||||
code: 'application.invalid_type',
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
const applicationRoles = await findApplicationsRolesByApplicationId(applicationId);
|
||||
|
||||
// Only add the ones that doesn't exist
|
||||
const roleIdsToAdd = roleIds.filter(
|
||||
(roleId) => !applicationRoles.some(({ roleId: _roleId }) => _roleId === roleId)
|
||||
);
|
||||
// Remove existing roles that isn't wanted by app anymore
|
||||
const roleIdsToRemove = applicationRoles
|
||||
.filter(({ roleId }) => !roleIds.includes(roleId))
|
||||
.map(({ roleId }) => roleId);
|
||||
|
||||
await Promise.all(roleIdsToAdd.map(async (roleId) => findRoleById(roleId)));
|
||||
await Promise.all(
|
||||
roleIdsToRemove.map(async (roleId) => deleteApplicationRole(applicationId, roleId))
|
||||
);
|
||||
await insertApplicationsRoles(
|
||||
roleIdsToAdd.map((roleId) => ({ id: generateStandardId(), applicationId, roleId }))
|
||||
);
|
||||
|
||||
ctx.status = 200;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/applications/:applicationId/roles/:roleId',
|
||||
koaGuard({
|
||||
params: object({ applicationId: string(), roleId: string() }),
|
||||
status: [204, 404, 422],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
params: { applicationId, roleId },
|
||||
} = ctx.guard;
|
||||
|
||||
const application = await findApplicationById(applicationId);
|
||||
assertThat(
|
||||
application.type === ApplicationType.MachineToMachine,
|
||||
new RequestError({
|
||||
code: 'application.invalid_type',
|
||||
status: 422,
|
||||
})
|
||||
);
|
||||
await deleteApplicationRole(applicationId, roleId);
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
}
|
|
@ -14,6 +14,7 @@ import adminUserRoleRoutes from './admin-user-role.js';
|
|||
import adminUserSearchRoutes from './admin-user-search.js';
|
||||
import adminUserSocialRoutes from './admin-user-social.js';
|
||||
import adminUserRoutes from './admin-user.js';
|
||||
import applicationRoleRoutes from './application-role.js';
|
||||
import applicationRoutes from './application.js';
|
||||
import authnRoutes from './authn.js';
|
||||
import connectorRoutes from './connector/index.js';
|
||||
|
@ -44,6 +45,7 @@ const createRouters = (tenant: TenantContext) => {
|
|||
managementRouter.use(koaTenantGuard(tenant.cloudConnection));
|
||||
|
||||
applicationRoutes(managementRouter, tenant);
|
||||
applicationRoleRoutes(managementRouter, tenant);
|
||||
logtoConfigRoutes(managementRouter, tenant);
|
||||
connectorRoutes(managementRouter, tenant);
|
||||
resourceRoutes(managementRouter, tenant);
|
||||
|
|
|
@ -3,6 +3,7 @@ import type {
|
|||
CreateApplication,
|
||||
ApplicationType,
|
||||
OidcClientMetadata,
|
||||
Role,
|
||||
} from '@logto/schemas';
|
||||
|
||||
import { authedAdminApi } from './api.js';
|
||||
|
@ -45,3 +46,19 @@ export const updateApplication = async (
|
|||
|
||||
export const deleteApplication = async (applicationId: string) =>
|
||||
authedAdminApi.delete(`applications/${applicationId}`);
|
||||
|
||||
export const getApplicationRoles = async (applicationId: string) =>
|
||||
authedAdminApi.get(`applications/${applicationId}/roles`).json<Role[]>();
|
||||
|
||||
export const assignRolesToApplication = async (applicationId: string, roleIds: string[]) =>
|
||||
authedAdminApi.post(`applications/${applicationId}/roles`, {
|
||||
json: { roleIds },
|
||||
});
|
||||
|
||||
export const putRolesToApplication = async (applicationId: string, roleIds: string[]) =>
|
||||
authedAdminApi.put(`applications/${applicationId}/roles`, {
|
||||
json: { roleIds },
|
||||
});
|
||||
|
||||
export const deleteRoleFromApplication = async (applicationId: string, roleId: string) =>
|
||||
authedAdminApi.delete(`applications/${applicationId}/roles/${roleId}`);
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
import { ApplicationType, RoleType } from '@logto/schemas';
|
||||
import { generateStandardId } from '@logto/shared';
|
||||
import { HTTPError } from 'got';
|
||||
|
||||
import {
|
||||
createApplication,
|
||||
getApplicationRoles,
|
||||
assignRolesToApplication,
|
||||
deleteRoleFromApplication,
|
||||
putRolesToApplication,
|
||||
} from '#src/api/index.js';
|
||||
import { createRole } from '#src/api/role.js';
|
||||
import { expectRejects } from '#src/helpers/index.js';
|
||||
|
||||
describe('admin console application management (roles)', () => {
|
||||
it('should get empty list successfully', async () => {
|
||||
const applicationType = ApplicationType.MachineToMachine;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
|
||||
const applicationRoles = await getApplicationRoles(application.id);
|
||||
expect(applicationRoles.length).toBe(0);
|
||||
});
|
||||
|
||||
it('throws when trying to get roles of non-m2m app', async () => {
|
||||
const applicationType = ApplicationType.SPA;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
|
||||
const response = await getApplicationRoles(application.id).catch((error: unknown) => error);
|
||||
expect(response instanceof HTTPError && response.response.statusCode === 422).toBe(true);
|
||||
});
|
||||
|
||||
it('should assign roles to app and get list successfully', async () => {
|
||||
const applicationType = ApplicationType.MachineToMachine;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
const role1 = await createRole({ type: RoleType.MachineToMachine });
|
||||
const role2 = await createRole({ type: RoleType.MachineToMachine });
|
||||
|
||||
await assignRolesToApplication(application.id, [role1.id, role2.id]);
|
||||
const roles = await getApplicationRoles(application.id);
|
||||
expect(roles.length).toBe(2);
|
||||
expect(roles.find(({ id }) => id === role1.id)).toBeDefined();
|
||||
expect(roles.find(({ id }) => id === role2.id)).toBeDefined();
|
||||
});
|
||||
|
||||
it('should fail when assign duplicated role to app', async () => {
|
||||
const applicationType = ApplicationType.MachineToMachine;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
const role = await createRole({ type: RoleType.MachineToMachine });
|
||||
|
||||
await assignRolesToApplication(application.id, [role.id]);
|
||||
await expectRejects(assignRolesToApplication(application.id, [role.id]), {
|
||||
code: 'application.role_exists',
|
||||
statusCode: 422,
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail when assign role to non-m2m app', async () => {
|
||||
const applicationType = ApplicationType.SPA;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
const role = await createRole({ type: RoleType.MachineToMachine });
|
||||
|
||||
await expectRejects(assignRolesToApplication(application.id, [role.id]), {
|
||||
code: 'application.invalid_type',
|
||||
statusCode: 422,
|
||||
});
|
||||
});
|
||||
|
||||
it('should put roles to app successfully', async () => {
|
||||
const applicationType = ApplicationType.MachineToMachine;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
const role1 = await createRole({ type: RoleType.MachineToMachine });
|
||||
const role2 = await createRole({ type: RoleType.MachineToMachine });
|
||||
const role3 = await createRole({ type: RoleType.MachineToMachine });
|
||||
|
||||
await assignRolesToApplication(application.id, [role2.id]);
|
||||
const roles = await getApplicationRoles(application.id);
|
||||
expect(roles.length).toBe(1);
|
||||
expect(roles.find(({ id }) => id === role2.id)).toBeDefined();
|
||||
|
||||
await putRolesToApplication(application.id, [role1.id, role3.id]);
|
||||
const updatedRoles = await getApplicationRoles(application.id);
|
||||
expect(updatedRoles.length).toBe(2);
|
||||
expect(updatedRoles.find(({ id }) => id === role1.id)).toBeDefined();
|
||||
expect(updatedRoles.find(({ id }) => id === role3.id)).toBeDefined();
|
||||
});
|
||||
|
||||
it('should delete role from app successfully', async () => {
|
||||
const applicationType = ApplicationType.MachineToMachine;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
const role1 = await createRole({ type: RoleType.MachineToMachine });
|
||||
const role2 = await createRole({ type: RoleType.MachineToMachine });
|
||||
|
||||
await assignRolesToApplication(application.id, [role1.id, role2.id]);
|
||||
await deleteRoleFromApplication(application.id, role1.id);
|
||||
|
||||
const roles = await getApplicationRoles(application.id);
|
||||
expect(roles.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should failed to delete non-existing-role from app', async () => {
|
||||
const applicationType = ApplicationType.MachineToMachine;
|
||||
const application = await createApplication(generateStandardId(), applicationType);
|
||||
const role = await createRole({ type: RoleType.MachineToMachine });
|
||||
|
||||
const response = await deleteRoleFromApplication(application.id, role.id).catch(
|
||||
(error: unknown) => error
|
||||
);
|
||||
expect(response instanceof HTTPError && response.response.statusCode === 404).toBe(true);
|
||||
});
|
||||
});
|
8
packages/phrases/src/locales/de/errors/application.ts
Normal file
8
packages/phrases/src/locales/de/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Nur Maschinen-zu-Maschinen-Anwendungen können Rollen haben.',
|
||||
role_exists: 'Die Rolle mit der ID {{roleId}} wurde bereits dieser Anwendung hinzugefügt.',
|
||||
invalid_role_type:
|
||||
'Es ist nicht möglich, einer Maschinen-zu-Maschinen-Anwendung eine Benutzertyp-Rolle zuzuweisen.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/en/errors/application.ts
Normal file
7
packages/phrases/src/locales/en/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: 'Only machine to machine applications can have associated roles.',
|
||||
role_exists: 'The role id {{roleId}} is already been added to this application.',
|
||||
invalid_role_type: 'Can not assign user type role to machine to machine application.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/es/errors/application.ts
Normal file
8
packages/phrases/src/locales/es/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Solo las aplicaciones de máquina a máquina pueden tener roles asociados.',
|
||||
role_exists: 'La identificación del rol {{roleId}} ya se ha agregado a esta aplicación.',
|
||||
invalid_role_type:
|
||||
'No se puede asignar un rol de tipo usuario a una aplicación de máquina a máquina.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/fr/errors/application.ts
Normal file
8
packages/phrases/src/locales/fr/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Seules les applications machine à machine peuvent avoir des rôles associés.',
|
||||
role_exists: "Le rôle d'identifiant {{roleId}} a déjà été ajouté à cette application.",
|
||||
invalid_role_type:
|
||||
"Impossible d'assigner un rôle de type utilisateur à une application machine à machine.",
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/it/errors/application.ts
Normal file
8
packages/phrases/src/locales/it/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Solo le applicazioni da macchina a macchina possono avere ruoli associati.',
|
||||
role_exists: "L'ID ruolo {{roleId}} è già stato aggiunto a questa applicazione.",
|
||||
invalid_role_type:
|
||||
"Impossibile assegnare un ruolo di tipo utente all'applicazione da macchina a macchina.",
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/ja/errors/application.ts
Normal file
8
packages/phrases/src/locales/ja/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: '関連するロールを持つことができるのは、マシン間アプリケーションのみです。',
|
||||
role_exists: 'ロールID {{roleId}} は、すでにこのアプリケーションに追加されています。',
|
||||
invalid_role_type:
|
||||
'ユーザータイプのロールをマシン間アプリケーションに割り当てることはできません。',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/ko/errors/application.ts
Normal file
7
packages/phrases/src/locales/ko/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: '관련 역할을 가질 수 있는 것은 기계 대 기계 응용 프로그램만 가능합니다.',
|
||||
role_exists: '역할 ID {{roleId}} 가 이미이 응용 프로그램에 추가되었습니다.',
|
||||
invalid_role_type: '사용자 유형 역할을 기계 대 기계 응용 프로그램에 할당할 수 없습니다.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/pl-pl/errors/application.ts
Normal file
7
packages/phrases/src/locales/pl-pl/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: 'Tylko aplikacje maszyna-do-maszyny mogą mieć przypisane role.',
|
||||
role_exists: 'Rola o identyfikatorze {{roleId}} została już dodana do tej aplikacji.',
|
||||
invalid_role_type: 'Nie można przypisać roli typu użytkownika do aplikacji maszyna-do-maszyny.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/pt-br/errors/application.ts
Normal file
8
packages/phrases/src/locales/pt-br/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Apenas aplicações de máquina para máquina podem ter funções associadas.',
|
||||
role_exists: 'O id da função {{roleId}} já foi adicionado a este aplicativo.',
|
||||
invalid_role_type:
|
||||
'Não é possível atribuir uma função de tipo de usuário a um aplicativo de máquina para máquina.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/pt-pt/errors/application.ts
Normal file
8
packages/phrases/src/locales/pt-pt/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Apenas aplicações máquina a máquina podem ter funções associadas.',
|
||||
role_exists: 'O id da função {{roleId}} já foi adicionado a esta aplicação.',
|
||||
invalid_role_type:
|
||||
'Não é possível atribuir uma função de tipo de utilizador a uma aplicação máquina a máquina.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
8
packages/phrases/src/locales/ru/errors/application.ts
Normal file
8
packages/phrases/src/locales/ru/errors/application.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
const application = {
|
||||
invalid_type: 'Только приложения типа "от машины к машине" могут иметь связанные роли.',
|
||||
role_exists: 'Роль с идентификатором {{roleId}} уже добавлена в это приложение.',
|
||||
invalid_role_type:
|
||||
'Невозможно назначить роль типа "пользователь" для приложения типа "от машины к машине".',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/tr-tr/errors/application.ts
Normal file
7
packages/phrases/src/locales/tr-tr/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: 'Sadece makine ile makine uygulamaları rollerle ilişkilendirilebilir.',
|
||||
role_exists: 'Bu uygulamaya zaten {{roleId}} kimlikli bir rol eklenmiş.',
|
||||
invalid_role_type: 'Kullanıcı tipi rolü makine ile makine uygulamasına atayamaz.',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/zh-cn/errors/application.ts
Normal file
7
packages/phrases/src/locales/zh-cn/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: '只有机器对机器应用程序可以有关联角色。',
|
||||
role_exists: '角色 ID {{roleId}} 已添加到此应用程序。',
|
||||
invalid_role_type: '无法将用户类型角色分配给机器对机器应用程序。',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/zh-hk/errors/application.ts
Normal file
7
packages/phrases/src/locales/zh-hk/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: '只有機器對機器應用程式才能有相關職能。',
|
||||
role_exists: '角色 ID {{roleId}} 已經被添加到此應用程式中。',
|
||||
invalid_role_type: '無法將使用者類型的角色分配給機器對機器應用程式。',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
7
packages/phrases/src/locales/zh-tw/errors/application.ts
Normal file
7
packages/phrases/src/locales/zh-tw/errors/application.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
const application = {
|
||||
invalid_type: '僅允許機器對機器應用程式附加角色。',
|
||||
role_exists: '該角色 ID {{roleId}} 已被添加至此應用程式。',
|
||||
invalid_role_type: '無法將使用者類型的角色指派給機器對機器應用程式。',
|
||||
};
|
||||
|
||||
export default Object.freeze(application);
|
|
@ -1,3 +1,4 @@
|
|||
import application from './application.js';
|
||||
import auth from './auth.js';
|
||||
import connector from './connector.js';
|
||||
import domain from './domain.js';
|
||||
|
@ -42,6 +43,7 @@ const errors = {
|
|||
hook,
|
||||
domain,
|
||||
subscription,
|
||||
application,
|
||||
};
|
||||
|
||||
export default Object.freeze(errors);
|
||||
|
|
Loading…
Reference in a new issue