mirror of
https://github.com/logto-io/logto.git
synced 2025-02-17 22:04:19 -05:00
feat(core): user-role related api (#2827)
This commit is contained in:
parent
6e8e3003f8
commit
7e507dbc2b
15 changed files with 288 additions and 6 deletions
|
@ -162,11 +162,13 @@ export const findUsers = async (
|
||||||
);
|
);
|
||||||
|
|
||||||
export const findUsersByIds = async (userIds: string[]) =>
|
export const findUsersByIds = async (userIds: string[]) =>
|
||||||
envSet.pool.any<User>(sql`
|
userIds.length > 0
|
||||||
select ${sql.join(Object.values(fields), sql`, `)}
|
? envSet.pool.any<User>(sql`
|
||||||
from ${table}
|
select ${sql.join(Object.values(fields), sql`, `)}
|
||||||
where ${fields.id} in (${sql.join(userIds, sql`, `)})
|
from ${table}
|
||||||
`);
|
where ${fields.id} in (${sql.join(userIds, sql`, `)})
|
||||||
|
`)
|
||||||
|
: [];
|
||||||
|
|
||||||
const updateUser = buildUpdateWhere<CreateUser, User>(Users, true);
|
const updateUser = buildUpdateWhere<CreateUser, User>(Users, true);
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,17 @@ export const findUsersRolesByRoleId = async (roleId: string) =>
|
||||||
where ${fields.roleId}=${roleId}
|
where ${fields.roleId}=${roleId}
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
export const findFirstUsersRolesByRoleIdAndUserIds = async (roleId: string, userIds: string[]) =>
|
||||||
|
userIds.length > 0
|
||||||
|
? envSet.pool.maybeOne<UsersRole>(sql`
|
||||||
|
select ${sql.join(Object.values(fields), sql`,`)}
|
||||||
|
from ${table}
|
||||||
|
where ${fields.roleId}=${roleId}
|
||||||
|
and ${fields.userId} in (${sql.join(userIds, sql`, `)})
|
||||||
|
limit 1
|
||||||
|
`)
|
||||||
|
: null;
|
||||||
|
|
||||||
export const insertUsersRoles = async (usersRoles: UsersRole[]) =>
|
export const insertUsersRoles = async (usersRoles: UsersRole[]) =>
|
||||||
envSet.pool.query(sql`
|
envSet.pool.query(sql`
|
||||||
insert into ${table} (${fields.userId}, ${fields.roleId}) values
|
insert into ${table} (${fields.userId}, ${fields.roleId}) values
|
||||||
|
|
50
packages/core/src/routes/admin-user-role.test.ts
Normal file
50
packages/core/src/routes/admin-user-role.test.ts
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import { pickDefault, createMockUtils } from '@logto/shared/esm';
|
||||||
|
|
||||||
|
import { mockRole, mockUser } from '#src/__mocks__/index.js';
|
||||||
|
import { createRequester } from '#src/utils/test-utils.js';
|
||||||
|
|
||||||
|
const { jest } = import.meta;
|
||||||
|
|
||||||
|
const { mockEsmWithActual } = createMockUtils(jest);
|
||||||
|
|
||||||
|
await mockEsmWithActual('#src/queries/user.js', () => ({
|
||||||
|
findUserById: jest.fn(),
|
||||||
|
}));
|
||||||
|
const { findRolesByRoleIds } = await mockEsmWithActual('#src/queries/roles.js', () => ({
|
||||||
|
findRolesByRoleIds: jest.fn(),
|
||||||
|
findRoleById: jest.fn(),
|
||||||
|
}));
|
||||||
|
const { findUsersRolesByUserId, insertUsersRoles, deleteUsersRolesByUserIdAndRoleId } =
|
||||||
|
await mockEsmWithActual('#src/queries/users-roles.js', () => ({
|
||||||
|
findUsersRolesByUserId: jest.fn(),
|
||||||
|
insertUsersRoles: jest.fn(),
|
||||||
|
deleteUsersRolesByUserIdAndRoleId: jest.fn(),
|
||||||
|
}));
|
||||||
|
const roleRoutes = await pickDefault(import('./admin-user-role.js'));
|
||||||
|
|
||||||
|
describe('user role routes', () => {
|
||||||
|
const roleRequester = createRequester({ authedRoutes: roleRoutes });
|
||||||
|
|
||||||
|
it('GET /users/:id/roles', async () => {
|
||||||
|
findUsersRolesByUserId.mockResolvedValueOnce([]);
|
||||||
|
findRolesByRoleIds.mockResolvedValueOnce([mockRole]);
|
||||||
|
const response = await roleRequester.get(`/users/${mockUser.id}/roles`);
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.body).toEqual([mockRole]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('POST /users/:id/roles', async () => {
|
||||||
|
findUsersRolesByUserId.mockResolvedValueOnce([]);
|
||||||
|
const response = await roleRequester.post(`/users/${mockUser.id}/roles`).send({
|
||||||
|
roleIds: [mockRole.id],
|
||||||
|
});
|
||||||
|
expect(response.status).toEqual(201);
|
||||||
|
expect(insertUsersRoles).toHaveBeenCalledWith([{ userId: mockUser.id, roleId: mockRole.id }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('DELETE /users/:id/roles/:roleId', async () => {
|
||||||
|
const response = await roleRequester.delete(`/users/${mockUser.id}/roles/${mockRole.id}`);
|
||||||
|
expect(response.status).toEqual(204);
|
||||||
|
expect(deleteUsersRolesByUserIdAndRoleId).toHaveBeenCalledWith(mockUser.id, mockRole.id);
|
||||||
|
});
|
||||||
|
});
|
88
packages/core/src/routes/admin-user-role.ts
Normal file
88
packages/core/src/routes/admin-user-role.ts
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
import { object, string } from 'zod';
|
||||||
|
|
||||||
|
import RequestError from '#src/errors/RequestError/index.js';
|
||||||
|
import koaGuard from '#src/middleware/koa-guard.js';
|
||||||
|
import { findRolesByRoleIds, findRoleById } from '#src/queries/roles.js';
|
||||||
|
import { findUserById } from '#src/queries/user.js';
|
||||||
|
import {
|
||||||
|
deleteUsersRolesByUserIdAndRoleId,
|
||||||
|
findUsersRolesByUserId,
|
||||||
|
insertUsersRoles,
|
||||||
|
} from '#src/queries/users-roles.js';
|
||||||
|
import assertThat from '#src/utils/assert-that.js';
|
||||||
|
|
||||||
|
import type { AuthedRouter } from './types.js';
|
||||||
|
|
||||||
|
export default function adminUserRoleRoutes<T extends AuthedRouter>(router: T) {
|
||||||
|
router.get(
|
||||||
|
'/users/:userId/roles',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ userId: string() }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { userId },
|
||||||
|
} = ctx.guard;
|
||||||
|
|
||||||
|
await findUserById(userId);
|
||||||
|
const usersRoles = await findUsersRolesByUserId(userId);
|
||||||
|
const roles = await findRolesByRoleIds(usersRoles.map(({ roleId }) => roleId));
|
||||||
|
|
||||||
|
ctx.body = roles;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/users/:userId/roles',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ userId: string() }),
|
||||||
|
body: object({ roleIds: string().min(1).array() }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { userId },
|
||||||
|
body: { roleIds },
|
||||||
|
} = ctx.guard;
|
||||||
|
|
||||||
|
await findUserById(userId);
|
||||||
|
const usersRoles = await findUsersRolesByUserId(userId);
|
||||||
|
|
||||||
|
for (const roleId of roleIds) {
|
||||||
|
assertThat(
|
||||||
|
!usersRoles.some(({ roleId: _roleId }) => _roleId === roleId),
|
||||||
|
new RequestError({
|
||||||
|
code: 'user.role_exists',
|
||||||
|
status: 422,
|
||||||
|
roleId,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(roleIds.map(async (roleId) => findRoleById(roleId)));
|
||||||
|
await insertUsersRoles(roleIds.map((roleId) => ({ userId, roleId })));
|
||||||
|
ctx.status = 201;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.delete(
|
||||||
|
'/users/:userId/roles/:roleId',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ userId: string(), roleId: string() }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { userId, roleId },
|
||||||
|
} = ctx.guard;
|
||||||
|
|
||||||
|
await deleteUsersRolesByUserIdAndRoleId(userId, roleId);
|
||||||
|
|
||||||
|
ctx.status = 204;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
|
@ -8,6 +8,7 @@ import koaAuditLogLegacy from '#src/middleware/koa-audit-log-legacy.js';
|
||||||
|
|
||||||
import koaAuth from '../middleware/koa-auth.js';
|
import koaAuth from '../middleware/koa-auth.js';
|
||||||
import koaLogSessionLegacy from '../middleware/koa-log-session-legacy.js';
|
import koaLogSessionLegacy from '../middleware/koa-log-session-legacy.js';
|
||||||
|
import adminUserRoleRoutes from './admin-user-role.js';
|
||||||
import adminUserRoutes from './admin-user.js';
|
import adminUserRoutes from './admin-user.js';
|
||||||
import applicationRoutes from './application.js';
|
import applicationRoutes from './application.js';
|
||||||
import authnRoutes from './authn.js';
|
import authnRoutes from './authn.js';
|
||||||
|
@ -45,6 +46,7 @@ const createRouters = (provider: Provider) => {
|
||||||
resourceRoutes(managementRouter);
|
resourceRoutes(managementRouter);
|
||||||
signInExperiencesRoutes(managementRouter);
|
signInExperiencesRoutes(managementRouter);
|
||||||
adminUserRoutes(managementRouter);
|
adminUserRoutes(managementRouter);
|
||||||
|
adminUserRoleRoutes(managementRouter);
|
||||||
logRoutes(managementRouter);
|
logRoutes(managementRouter);
|
||||||
roleRoutes(managementRouter);
|
roleRoutes(managementRouter);
|
||||||
dashboardRoutes(managementRouter);
|
dashboardRoutes(managementRouter);
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { Role } from '@logto/schemas';
|
import type { Role } from '@logto/schemas';
|
||||||
import { pickDefault, createMockUtils } from '@logto/shared/esm';
|
import { pickDefault, createMockUtils } from '@logto/shared/esm';
|
||||||
|
|
||||||
import { mockRole, mockScope } from '#src/__mocks__/index.js';
|
import { mockRole, mockScope, mockUser } from '#src/__mocks__/index.js';
|
||||||
import { createRequester } from '#src/utils/test-utils.js';
|
import { createRequester } from '#src/utils/test-utils.js';
|
||||||
|
|
||||||
const { jest } = import.meta;
|
const { jest } = import.meta;
|
||||||
|
@ -23,6 +23,7 @@ const { findRoleByRoleName, findRoleById, deleteRoleById } = mockEsm(
|
||||||
...mockRole,
|
...mockRole,
|
||||||
...data,
|
...data,
|
||||||
})),
|
})),
|
||||||
|
findRolesByRoleIds: jest.fn(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
const { findScopeById, findScopesByIds } = await mockEsmWithActual('#src/queries/scope.js', () => ({
|
const { findScopeById, findScopesByIds } = await mockEsmWithActual('#src/queries/scope.js', () => ({
|
||||||
|
@ -37,6 +38,21 @@ const { insertRolesScopes, findRolesScopesByRoleId } = await mockEsmWithActual(
|
||||||
deleteRolesScope: jest.fn(),
|
deleteRolesScope: jest.fn(),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
const { findUsersByIds } = await mockEsmWithActual('#src/queries/user.js', () => ({
|
||||||
|
findUsersByIds: jest.fn(),
|
||||||
|
findUserById: jest.fn(),
|
||||||
|
}));
|
||||||
|
const {
|
||||||
|
insertUsersRoles,
|
||||||
|
findUsersRolesByRoleId,
|
||||||
|
deleteUsersRolesByUserIdAndRoleId,
|
||||||
|
findFirstUsersRolesByRoleIdAndUserIds,
|
||||||
|
} = await mockEsmWithActual('#src/queries/users-roles.js', () => ({
|
||||||
|
insertUsersRoles: jest.fn(),
|
||||||
|
findUsersRolesByRoleId: jest.fn(),
|
||||||
|
findFirstUsersRolesByRoleIdAndUserIds: jest.fn(),
|
||||||
|
deleteUsersRolesByUserIdAndRoleId: jest.fn(),
|
||||||
|
}));
|
||||||
const roleRoutes = await pickDefault(import('./role.js'));
|
const roleRoutes = await pickDefault(import('./role.js'));
|
||||||
|
|
||||||
describe('role routes', () => {
|
describe('role routes', () => {
|
||||||
|
@ -133,4 +149,29 @@ describe('role routes', () => {
|
||||||
const response = await roleRequester.delete(`/roles/${mockRole.id}/scopes/${mockScope.id}`);
|
const response = await roleRequester.delete(`/roles/${mockRole.id}/scopes/${mockScope.id}`);
|
||||||
expect(response.status).toEqual(204);
|
expect(response.status).toEqual(204);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('GET /roles/:id/users', async () => {
|
||||||
|
findRoleById.mockResolvedValueOnce(mockRole);
|
||||||
|
findUsersRolesByRoleId.mockResolvedValueOnce([]);
|
||||||
|
findUsersByIds.mockResolvedValueOnce([mockUser]);
|
||||||
|
const response = await roleRequester.get(`/roles/${mockRole.id}/users`);
|
||||||
|
expect(response.status).toEqual(200);
|
||||||
|
expect(response.body).toEqual([mockUser]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('POST /roles/:id/users', async () => {
|
||||||
|
findRoleById.mockResolvedValueOnce(mockRole);
|
||||||
|
findFirstUsersRolesByRoleIdAndUserIds.mockResolvedValueOnce(null);
|
||||||
|
const response = await roleRequester.post(`/roles/${mockRole.id}/users`).send({
|
||||||
|
userIds: [mockUser.id],
|
||||||
|
});
|
||||||
|
expect(response.status).toEqual(201);
|
||||||
|
expect(insertUsersRoles).toHaveBeenCalledWith([{ userId: mockUser.id, roleId: mockRole.id }]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('DELETE /roles/:id/users/:userId', async () => {
|
||||||
|
const response = await roleRequester.delete(`/roles/${mockRole.id}/users/${mockUser.id}`);
|
||||||
|
expect(response.status).toEqual(204);
|
||||||
|
expect(deleteUsersRolesByUserIdAndRoleId).toHaveBeenCalledWith(mockUser.id, mockRole.id);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,6 +18,13 @@ import {
|
||||||
updateRoleById,
|
updateRoleById,
|
||||||
} from '#src/queries/roles.js';
|
} from '#src/queries/roles.js';
|
||||||
import { findScopeById, findScopesByIds } from '#src/queries/scope.js';
|
import { findScopeById, findScopesByIds } from '#src/queries/scope.js';
|
||||||
|
import { findUserById, findUsersByIds } from '#src/queries/user.js';
|
||||||
|
import {
|
||||||
|
deleteUsersRolesByUserIdAndRoleId,
|
||||||
|
findFirstUsersRolesByRoleIdAndUserIds,
|
||||||
|
findUsersRolesByRoleId,
|
||||||
|
insertUsersRoles,
|
||||||
|
} from '#src/queries/users-roles.js';
|
||||||
import assertThat from '#src/utils/assert-that.js';
|
import assertThat from '#src/utils/assert-that.js';
|
||||||
|
|
||||||
import type { AuthedRouter } from './types.js';
|
import type { AuthedRouter } from './types.js';
|
||||||
|
@ -186,4 +193,69 @@ export default function roleRoutes<T extends AuthedRouter>(router: T) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
router.get(
|
||||||
|
'/roles/:id/users',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ id: string().min(1) }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { id },
|
||||||
|
} = ctx.guard;
|
||||||
|
|
||||||
|
await findRoleById(id);
|
||||||
|
const usersRoles = await findUsersRolesByRoleId(id);
|
||||||
|
ctx.body = await findUsersByIds(usersRoles.map(({ userId }) => userId));
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.post(
|
||||||
|
'/roles/:id/users',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ id: string().min(1) }),
|
||||||
|
body: object({ userIds: string().min(1).array() }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { id },
|
||||||
|
body: { userIds },
|
||||||
|
} = ctx.guard;
|
||||||
|
|
||||||
|
await findRoleById(id);
|
||||||
|
const existingRecord = await findFirstUsersRolesByRoleIdAndUserIds(id, userIds);
|
||||||
|
|
||||||
|
if (existingRecord) {
|
||||||
|
throw new RequestError({
|
||||||
|
code: 'role.user_exists',
|
||||||
|
status: 422,
|
||||||
|
userId: existingRecord.userId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(userIds.map(async (userId) => findUserById(userId)));
|
||||||
|
await insertUsersRoles(userIds.map((userId) => ({ roleId: id, userId })));
|
||||||
|
ctx.status = 201;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
router.delete(
|
||||||
|
'/roles/:id/users/:userId',
|
||||||
|
koaGuard({
|
||||||
|
params: object({ id: string().min(1), userId: string().min(1) }),
|
||||||
|
}),
|
||||||
|
async (ctx, next) => {
|
||||||
|
const {
|
||||||
|
params: { id, userId },
|
||||||
|
} = ctx.guard;
|
||||||
|
await deleteUsersRolesByUserIdAndRoleId(userId, id);
|
||||||
|
ctx.status = 204;
|
||||||
|
|
||||||
|
return next();
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ const errors = {
|
||||||
suspended: 'This account is suspended.', // UNTRANSLATED
|
suspended: 'This account is suspended.', // UNTRANSLATED
|
||||||
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
||||||
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: 'Die Verschlüsselungsmethode {{name}} wird nicht unterstützt.',
|
unsupported_encryption_method: 'Die Verschlüsselungsmethode {{name}} wird nicht unterstützt.',
|
||||||
|
@ -178,6 +179,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ const errors = {
|
||||||
suspended: 'This account is suspended.',
|
suspended: 'This account is suspended.',
|
||||||
user_not_exist: 'User with {{ identifier }} does not exist.',
|
user_not_exist: 'User with {{ identifier }} does not exist.',
|
||||||
missing_profile: 'You need to provide additional info before signing-in.',
|
missing_profile: 'You need to provide additional info before signing-in.',
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user',
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: 'The encryption method {{name}} is not supported.',
|
unsupported_encryption_method: 'The encryption method {{name}} is not supported.',
|
||||||
|
@ -177,6 +178,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use',
|
name_in_use: 'This role name {{name}} is already in use',
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role',
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role',
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,7 @@ const errors = {
|
||||||
suspended: 'This account is suspended.', // UNTRANSLATED
|
suspended: 'This account is suspended.', // UNTRANSLATED
|
||||||
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
||||||
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: "La méthode de cryptage {{name}} n'est pas prise en charge.",
|
unsupported_encryption_method: "La méthode de cryptage {{name}} n'est pas prise en charge.",
|
||||||
|
@ -184,6 +185,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,7 @@ const errors = {
|
||||||
suspended: '이 계정은 일시 정시되었어요.',
|
suspended: '이 계정은 일시 정시되었어요.',
|
||||||
user_not_exist: '{{identifier}}의 사용자가 아직 등록되지 않았어요.',
|
user_not_exist: '{{identifier}}의 사용자가 아직 등록되지 않았어요.',
|
||||||
missing_profile: '로그인 전에 추가 정보를 제공해야해요.',
|
missing_profile: '로그인 전에 추가 정보를 제공해야해요.',
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: '{{name}} 암호화 방법을 지원하지 않아요.',
|
unsupported_encryption_method: '{{name}} 암호화 방법을 지원하지 않아요.',
|
||||||
|
@ -171,6 +172,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ const errors = {
|
||||||
suspended: 'Esta conta está suspensa.',
|
suspended: 'Esta conta está suspensa.',
|
||||||
user_not_exist: 'O usuário com {{ identifier }} não existe',
|
user_not_exist: 'O usuário com {{ identifier }} não existe',
|
||||||
missing_profile: 'Você precisa fornecer informações adicionais antes de fazer login.',
|
missing_profile: 'Você precisa fornecer informações adicionais antes de fazer login.',
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: 'O método de criptografia {{name}} não é suportado.',
|
unsupported_encryption_method: 'O método de criptografia {{name}} não é suportado.',
|
||||||
|
@ -185,6 +186,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ const errors = {
|
||||||
suspended: 'This account is suspended.', // UNTRANSLATED
|
suspended: 'This account is suspended.', // UNTRANSLATED
|
||||||
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
||||||
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: 'O método de enncriptação {{name}} não é suportado.',
|
unsupported_encryption_method: 'O método de enncriptação {{name}} não é suportado.',
|
||||||
|
@ -179,6 +180,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ const errors = {
|
||||||
suspended: 'This account is suspended.', // UNTRANSLATED
|
suspended: 'This account is suspended.', // UNTRANSLATED
|
||||||
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
user_not_exist: 'User with {{ identifier }} does not exist.', // UNTRANSLATED,
|
||||||
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
missing_profile: 'You need to provide additional info before signing-in.', // UNTRANSLATED
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: '{{name}} şifreleme metodu desteklenmiyor.',
|
unsupported_encryption_method: '{{name}} şifreleme metodu desteklenmiyor.',
|
||||||
|
@ -179,6 +180,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,6 +61,7 @@ const errors = {
|
||||||
suspended: '账号已被禁用。',
|
suspended: '账号已被禁用。',
|
||||||
user_not_exist: '未找到与 {{ identifier }} 相关联的用户。',
|
user_not_exist: '未找到与 {{ identifier }} 相关联的用户。',
|
||||||
missing_profile: '请于登录时提供必要的用户补充信息。',
|
missing_profile: '请于登录时提供必要的用户补充信息。',
|
||||||
|
role_exists: 'The role id {{roleId}} is already been added to this user', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
password: {
|
password: {
|
||||||
unsupported_encryption_method: '不支持的加密方法 {{name}}',
|
unsupported_encryption_method: '不支持的加密方法 {{name}}',
|
||||||
|
@ -160,6 +161,7 @@ const errors = {
|
||||||
role: {
|
role: {
|
||||||
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
name_in_use: 'This role name {{name}} is already in use', // UNTRANSLATED
|
||||||
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
scope_exists: 'The scope id {{scopeId}} has already been added to this role', // UNTRANSLATED
|
||||||
|
user_exists: 'The user id {{userId}} is already been added to this role', // UNTRANSLATED
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue