mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
refactor(core): split profile route (#6802)
This commit is contained in:
parent
859495b13b
commit
f8d21e49fa
2 changed files with 127 additions and 105 deletions
123
packages/core/src/routes/profile/identities.ts
Normal file
123
packages/core/src/routes/profile/identities.ts
Normal file
|
@ -0,0 +1,123 @@
|
|||
import { UserScope } from '@logto/core-kit';
|
||||
import { VerificationType, AccountCenterControlValue } from '@logto/schemas';
|
||||
import { z } from 'zod';
|
||||
|
||||
import koaGuard from '#src/middleware/koa-guard.js';
|
||||
|
||||
import RequestError from '../../errors/RequestError/index.js';
|
||||
import { buildVerificationRecordByIdAndType } from '../../libraries/verification.js';
|
||||
import assertThat from '../../utils/assert-that.js';
|
||||
import type { UserRouter, RouterInitArgs } from '../types.js';
|
||||
|
||||
export default function identitiesRoutes<T extends UserRouter>(
|
||||
...[router, { queries, libraries }]: RouterInitArgs<T>
|
||||
) {
|
||||
const {
|
||||
users: { updateUserById, findUserById, deleteUserIdentity },
|
||||
} = queries;
|
||||
|
||||
const {
|
||||
users: { checkIdentifierCollision },
|
||||
} = libraries;
|
||||
|
||||
router.post(
|
||||
'/profile/identities',
|
||||
koaGuard({
|
||||
body: z.object({
|
||||
newIdentifierVerificationRecordId: z.string(),
|
||||
}),
|
||||
status: [204, 400, 401],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { id: userId, scopes, identityVerified } = ctx.auth;
|
||||
assertThat(
|
||||
identityVerified,
|
||||
new RequestError({ code: 'verification_record.permission_denied', status: 401 })
|
||||
);
|
||||
const { newIdentifierVerificationRecordId } = ctx.guard.body;
|
||||
const { fields } = ctx.accountCenter;
|
||||
assertThat(
|
||||
fields.social === AccountCenterControlValue.Edit,
|
||||
'account_center.filed_not_editable'
|
||||
);
|
||||
|
||||
assertThat(scopes.has(UserScope.Identities), 'auth.unauthorized');
|
||||
|
||||
// Check new identifier
|
||||
const newVerificationRecord = await buildVerificationRecordByIdAndType({
|
||||
type: VerificationType.Social,
|
||||
id: newIdentifierVerificationRecordId,
|
||||
queries,
|
||||
libraries,
|
||||
});
|
||||
assertThat(newVerificationRecord.isVerified, 'verification_record.not_found');
|
||||
|
||||
const {
|
||||
socialIdentity: { target, userInfo },
|
||||
} = await newVerificationRecord.toUserProfile();
|
||||
|
||||
await checkIdentifierCollision({ identity: { target, id: userInfo.id } }, userId);
|
||||
|
||||
const user = await findUserById(userId);
|
||||
|
||||
assertThat(!user.identities[target], 'user.identity_already_in_use');
|
||||
|
||||
const updatedUser = await updateUserById(userId, {
|
||||
identities: {
|
||||
...user.identities,
|
||||
[target]: {
|
||||
userId: userInfo.id,
|
||||
details: userInfo,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
ctx.appendDataHookContext('User.Data.Updated', { user: updatedUser });
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/profile/identities/:target',
|
||||
koaGuard({
|
||||
params: z.object({ target: z.string() }),
|
||||
status: [204, 400, 401, 404],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { id: userId, scopes, identityVerified } = ctx.auth;
|
||||
assertThat(
|
||||
identityVerified,
|
||||
new RequestError({ code: 'verification_record.permission_denied', status: 401 })
|
||||
);
|
||||
const { target } = ctx.guard.params;
|
||||
const { fields } = ctx.accountCenter;
|
||||
assertThat(
|
||||
fields.social === AccountCenterControlValue.Edit,
|
||||
'account_center.filed_not_editable'
|
||||
);
|
||||
|
||||
assertThat(scopes.has(UserScope.Identities), 'auth.unauthorized');
|
||||
|
||||
const user = await findUserById(userId);
|
||||
|
||||
assertThat(
|
||||
user.identities[target],
|
||||
new RequestError({
|
||||
code: 'user.identity_not_exist',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const updatedUser = await deleteUserIdentity(userId, target);
|
||||
|
||||
ctx.appendDataHookContext('User.Data.Updated', { user: updatedUser });
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
/* eslint-disable max-lines */
|
||||
import { emailRegEx, phoneRegEx, usernameRegEx, UserScope } from '@logto/core-kit';
|
||||
import {
|
||||
VerificationType,
|
||||
|
@ -18,12 +17,12 @@ import assertThat from '../../utils/assert-that.js';
|
|||
import { PasswordValidator } from '../experience/classes/libraries/password-validator.js';
|
||||
import type { UserRouter, RouterInitArgs } from '../types.js';
|
||||
|
||||
import identitiesRoutes from './identities.js';
|
||||
import koaAccountCenter from './middlewares/koa-account-center.js';
|
||||
import { getAccountCenterFilteredProfile, getScopedProfile } from './utils/get-scoped-profile.js';
|
||||
|
||||
export default function profileRoutes<T extends UserRouter>(
|
||||
...[router, { queries, libraries }]: RouterInitArgs<T>
|
||||
) {
|
||||
export default function profileRoutes<T extends UserRouter>(...args: RouterInitArgs<T>) {
|
||||
const [router, { queries, libraries }] = args;
|
||||
const {
|
||||
users: { updateUserById, findUserById, deleteUserIdentity },
|
||||
signInExperiences: { findDefaultSignInExperience },
|
||||
|
@ -268,105 +267,5 @@ export default function profileRoutes<T extends UserRouter>(
|
|||
}
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/profile/identities',
|
||||
koaGuard({
|
||||
body: z.object({
|
||||
newIdentifierVerificationRecordId: z.string(),
|
||||
}),
|
||||
status: [204, 400, 401],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { id: userId, scopes, identityVerified } = ctx.auth;
|
||||
assertThat(
|
||||
identityVerified,
|
||||
new RequestError({ code: 'verification_record.permission_denied', status: 401 })
|
||||
);
|
||||
const { newIdentifierVerificationRecordId } = ctx.guard.body;
|
||||
const { fields } = ctx.accountCenter;
|
||||
assertThat(
|
||||
fields.social === AccountCenterControlValue.Edit,
|
||||
'account_center.filed_not_editable'
|
||||
);
|
||||
|
||||
assertThat(scopes.has(UserScope.Identities), 'auth.unauthorized');
|
||||
|
||||
// Check new identifier
|
||||
const newVerificationRecord = await buildVerificationRecordByIdAndType({
|
||||
type: VerificationType.Social,
|
||||
id: newIdentifierVerificationRecordId,
|
||||
queries,
|
||||
libraries,
|
||||
});
|
||||
assertThat(newVerificationRecord.isVerified, 'verification_record.not_found');
|
||||
|
||||
const {
|
||||
socialIdentity: { target, userInfo },
|
||||
} = await newVerificationRecord.toUserProfile();
|
||||
|
||||
await checkIdentifierCollision({ identity: { target, id: userInfo.id } }, userId);
|
||||
|
||||
const user = await findUserById(userId);
|
||||
|
||||
assertThat(!user.identities[target], 'user.identity_already_in_use');
|
||||
|
||||
const updatedUser = await updateUserById(userId, {
|
||||
identities: {
|
||||
...user.identities,
|
||||
[target]: {
|
||||
userId: userInfo.id,
|
||||
details: userInfo,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
ctx.appendDataHookContext('User.Data.Updated', { user: updatedUser });
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/profile/identities/:target',
|
||||
koaGuard({
|
||||
params: z.object({ target: z.string() }),
|
||||
status: [204, 400, 401, 404],
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const { id: userId, scopes, identityVerified } = ctx.auth;
|
||||
assertThat(
|
||||
identityVerified,
|
||||
new RequestError({ code: 'verification_record.permission_denied', status: 401 })
|
||||
);
|
||||
const { target } = ctx.guard.params;
|
||||
const { fields } = ctx.accountCenter;
|
||||
assertThat(
|
||||
fields.social === AccountCenterControlValue.Edit,
|
||||
'account_center.filed_not_editable'
|
||||
);
|
||||
|
||||
assertThat(scopes.has(UserScope.Identities), 'auth.unauthorized');
|
||||
|
||||
const user = await findUserById(userId);
|
||||
|
||||
assertThat(
|
||||
user.identities[target],
|
||||
new RequestError({
|
||||
code: 'user.identity_not_exist',
|
||||
status: 404,
|
||||
})
|
||||
);
|
||||
|
||||
const updatedUser = await deleteUserIdentity(userId, target);
|
||||
|
||||
ctx.appendDataHookContext('User.Data.Updated', { user: updatedUser });
|
||||
|
||||
ctx.status = 204;
|
||||
|
||||
return next();
|
||||
}
|
||||
);
|
||||
identitiesRoutes(...args);
|
||||
}
|
||||
/* eslint-enable max-lines */
|
||||
|
|
Loading…
Reference in a new issue