0
Fork 0
mirror of https://github.com/logto-io/logto.git synced 2025-02-17 22:04:19 -05:00

refactor(core,console)!: remove /me apis (#1781)

* refactor(core,console)!: remove `/me` apis

* fix(phrases): add missing fr phrase
This commit is contained in:
Gao Sun 2022-08-15 20:45:29 +08:00 committed by GitHub
parent a6bb2f7ec2
commit 2c6171c2f9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 70 additions and 145 deletions

View file

@ -30,7 +30,7 @@ const useUserPreferences = () => {
const { isAuthenticated, error: authError } = useLogto();
const shouldFetch = isAuthenticated && !authError;
const { data, mutate, error } = useSWR<unknown, RequestError>(
shouldFetch && '/api/me/custom-data'
shouldFetch && '/api/users/me/custom-data'
);
const api = useApi();
@ -50,7 +50,7 @@ const useUserPreferences = () => {
const update = async (data: Partial<UserPreferences>) => {
const updated = await api
.patch('/api/me/custom-data', {
.patch('/api/users/me/custom-data', {
json: {
customData: {
[key]: {

View file

@ -30,7 +30,7 @@ const ChangePassword = () => {
const onSubmit = async () => {
setIsLoading(true);
await api.patch(`/api/me/password`, { json: { password } }).json();
await api.patch(`/api/users/me/password`, { json: { password } }).json();
setIsLoading(false);
setIsOpen(false);
toast.success(t('settings.password_changed'));

View file

@ -23,6 +23,8 @@ import assertThat from '@/utils/assert-that';
import { AuthedRouter } from './types';
const getComputedUserId = (userId: string, auth: string) => (userId === 'me' ? auth : userId);
export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
router.get(
'/users',
@ -59,7 +61,7 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
params: { userId },
} = ctx.guard;
const user = await findUserById(userId);
const user = await findUserById(getComputedUserId(userId, ctx.auth));
ctx.body = pick(user, ...userInfoSelectFields);
@ -67,6 +69,50 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
}
);
router.get(
'/users/:userId/custom-data',
koaGuard({
params: object({ userId: string() }),
response: arbitraryObjectGuard,
}),
async (ctx, next) => {
const {
params: { userId },
} = ctx.guard;
const { customData } = await findUserById(getComputedUserId(userId, ctx.auth));
ctx.body = customData;
return next();
}
);
router.patch(
'/users/:userId/custom-data',
koaGuard({
params: object({ userId: string() }),
body: object({ customData: arbitraryObjectGuard }),
response: arbitraryObjectGuard,
}),
async (ctx, next) => {
const {
params: { userId: userIdParameter },
body: { customData },
} = ctx.guard;
const userId = getComputedUserId(userIdParameter, ctx.auth);
await findUserById(userId);
const user = await updateUserById(userId, {
customData,
});
ctx.body = user.customData;
return next();
}
);
router.post(
'/users',
koaGuard({
@ -117,9 +163,10 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
}),
async (ctx, next) => {
const {
params: { userId },
params: { userId: userIdParameter },
body,
} = ctx.guard;
const userId = getComputedUserId(userIdParameter, ctx.auth);
await findUserById(userId);
@ -164,9 +211,10 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
}),
async (ctx, next) => {
const {
params: { userId },
params: { userId: userIdParameter },
body: { password },
} = ctx.guard;
const userId = getComputedUserId(userIdParameter, ctx.auth);
await findUserById(userId);
@ -193,6 +241,10 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
params: { userId },
} = ctx.guard;
if (userId === ctx.auth) {
throw new RequestError('user.cannot_delete_self');
}
await findUserById(userId);
await deleteUserById(userId);
@ -208,8 +260,9 @@ export default function adminUserRoutes<T extends AuthedRouter>(router: T) {
koaGuard({ params: object({ userId: string(), target: string() }) }),
async (ctx, next) => {
const {
params: { userId, target },
params: { userId: userIdParameter, target },
} = ctx.guard;
const userId = getComputedUserId(userIdParameter, ctx.auth);
const { identities } = await findUserById(userId);

View file

@ -6,10 +6,13 @@ import { Provider } from 'oidc-provider';
import koaAuth from '@/middleware/koa-auth';
import koaLogSession from '@/middleware/koa-log-session';
import adminUserRoutes from '@/routes/admin-user';
import applicationRoutes from '@/routes/application';
import connectorRoutes from '@/routes/connector';
import dashboardRoutes from '@/routes/dashboard';
import logRoutes from '@/routes/log';
import resourceRoutes from '@/routes/resource';
import roleRoutes from '@/routes/role';
import sessionPasswordlessRoutes from '@/routes/session/passwordless';
import sessionRoutes from '@/routes/session/session';
import sessionSocialRoutes from '@/routes/session/social';
@ -19,10 +22,6 @@ import statusRoutes from '@/routes/status';
import swaggerRoutes from '@/routes/swagger';
import wellKnownRoutes from '@/routes/well-known';
import adminUserRoutes from './admin-user';
import logRoutes from './log';
import meRoutes from './me';
import roleRoutes from './role';
import { AnonymousRouter, AuthedRouter } from './types';
const createRouters = (provider: Provider) => {
@ -44,17 +43,13 @@ const createRouters = (provider: Provider) => {
roleRoutes(managementRouter);
dashboardRoutes(managementRouter);
const meRouter: AuthedRouter = new Router();
meRouter.use(koaAuth());
meRoutes(meRouter);
const anonymousRouter: AnonymousRouter = new Router();
wellKnownRoutes(anonymousRouter, provider);
statusRoutes(anonymousRouter);
// The swagger.json should contain all API routers.
swaggerRoutes(anonymousRouter, [sessionRouter, managementRouter, meRouter, anonymousRouter]);
swaggerRoutes(anonymousRouter, [sessionRouter, managementRouter, anonymousRouter]);
return [sessionRouter, managementRouter, meRouter, anonymousRouter];
return [sessionRouter, managementRouter, anonymousRouter];
};
export default function initRouter(app: Koa, provider: Provider) {

View file

@ -1,69 +0,0 @@
import { arbitraryObjectGuard, userInfoSelectFields } from '@logto/schemas';
import { passwordRegEx } from '@logto/shared';
import pick from 'lodash.pick';
import { object, string } from 'zod';
import { encryptUserPassword } from '@/lib/user';
import koaGuard from '@/middleware/koa-guard';
import { findUserById, updateUserById } from '@/queries/user';
import { AuthedRouter } from './types';
export default function meRoutes<T extends AuthedRouter>(router: T) {
router.get('/me', async (ctx, next) => {
const user = await findUserById(ctx.auth);
ctx.body = pick(user, ...userInfoSelectFields);
return next();
});
router.get('/me/custom-data', async (ctx, next) => {
const { customData } = await findUserById(ctx.auth);
ctx.body = customData;
return next();
});
router.patch(
'/me/custom-data',
koaGuard({ body: object({ customData: arbitraryObjectGuard }) }),
async (ctx, next) => {
const {
body: { customData },
} = ctx.guard;
await findUserById(ctx.auth);
const user = await updateUserById(ctx.auth, {
customData,
});
ctx.body = user.customData;
return next();
}
);
router.patch(
'/me/password',
koaGuard({ body: object({ password: string().regex(passwordRegEx) }) }),
async (ctx, next) => {
const {
body: { password },
} = ctx.guard;
const { passwordEncrypted, passwordEncryptionMethod } = await encryptUserPassword(password);
await updateUserById(ctx.auth, {
passwordEncrypted,
passwordEncryptionMethod,
});
ctx.status = 204;
return next();
}
);
}

View file

@ -11,11 +11,6 @@ paths:
responses:
'204':
description: No Content
/api/me/password:
patch:
responses:
'204':
description: No Content
/api/resources/:id:
delete:
responses:

View file

@ -1,54 +0,0 @@
import { userInfoSelectFields } from '@logto/schemas';
import { assert } from '@silverhand/essentials';
import {
getCurrentUserInfo,
getCurrentUserCustomData,
updateCurrentUserCustomData,
changeCurrentUserPassword,
} from '@/api';
import { createUserByAdmin, signIn } from '@/helpers';
import { generatePassword } from '@/utils';
describe('api `/me`', () => {
it('should get user info successfully', async () => {
const user = await createUserByAdmin();
const userInfo = await getCurrentUserInfo(user.id);
expect(userInfo.id).toBe(user.id);
for (const field of userInfoSelectFields) {
expect(userInfo).toHaveProperty(field);
}
});
it('should get user custom data successfully', async () => {
const user = await createUserByAdmin();
const customData = await getCurrentUserCustomData(user.id);
expect(customData).toEqual({});
});
it('should update user custom data successfully', async () => {
const user = await createUserByAdmin();
const foo = 'bar';
await updateCurrentUserCustomData(user.id, { foo });
const customData = await getCurrentUserCustomData(user.id);
expect(customData).toEqual({ foo });
});
it('should change user password successfully', async () => {
const user = await createUserByAdmin();
const password = generatePassword();
await changeCurrentUserPassword(user.id, password);
assert(user.username, new Error('empty username'));
void expect(signIn(user.username, password)).resolves.not.toThrow();
});
});

View file

@ -39,6 +39,7 @@ const errors = {
identity_not_exists: 'The social account has not been registered yet.',
identity_exists: 'The social account has been registered.',
invalid_role_names: 'role names ({{roleNames}}) are not valid',
cannot_delete_self: 'You cannot delete yourself.',
},
password: {
unsupported_encryption_method: 'The encryption method {{name}} is not supported.',

View file

@ -40,6 +40,7 @@ const errors = {
identity_not_exists: "Le compte social n'a pas encore été enregistré.",
identity_exists: 'Le compte social a été enregistré.',
invalid_role_names: 'les noms de rôles ({{roleNames}}) ne sont pas valides',
cannot_delete_self: 'You cannot delete yourself.',
},
password: {
unsupported_encryption_method: "La méthode de cryptage {{name}} n'est pas prise en charge.",

View file

@ -38,6 +38,7 @@ const errors = {
identity_not_exists: '소셜 계정이 아직 등록되지 않았어요.',
identity_exists: '소셜 계정이 이미 등록되있어요.',
invalid_role_names: '직책 명({{roleNames}})이 유효하지 않아요.',
cannot_delete_self: 'You cannot delete yourself.',
},
password: {
unsupported_encryption_method: '{{name}} 암호화 방법을 지원하지 않아요.',

View file

@ -39,6 +39,7 @@ const errors = {
identity_not_exists: 'Sosyal platform hesabı henüz kaydedilmedi.',
identity_exists: 'Sosyal platform hesabı kaydedildi.',
invalid_role_names: '({{roleNames}}) rol adları geçerli değil.',
cannot_delete_self: 'You cannot delete yourself.',
},
password: {
unsupported_encryption_method: '{{name}} şifreleme metodu desteklenmiyor.',

View file

@ -39,6 +39,7 @@ const errors = {
identity_not_exists: '该社交帐号尚未注册',
identity_exists: '该社交帐号已被注册',
invalid_role_names: '角色名称({{roleNames}})无效',
cannot_delete_self: '你无法删除自己',
},
password: {
unsupported_encryption_method: '不支持的加密方法 {{name}}',