mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
feat(core): users basic API (#133)
This commit is contained in:
parent
6d5b9e5bcc
commit
9c3b67ae46
2 changed files with 108 additions and 3 deletions
|
@ -3,7 +3,9 @@ import { sql } from 'slonik';
|
|||
|
||||
import { buildInsertInto } from '@/database/insert-into';
|
||||
import pool from '@/database/pool';
|
||||
import { convertToIdentifiers } from '@/database/utils';
|
||||
import { buildUpdateWhere } from '@/database/update-where';
|
||||
import { convertToIdentifiers, OmitAutoSetFields } from '@/database/utils';
|
||||
import RequestError from '@/errors/RequestError';
|
||||
|
||||
const { table, fields } = convertToIdentifiers(Users);
|
||||
|
||||
|
@ -36,3 +38,29 @@ export const hasUserWithId = async (id: string) =>
|
|||
`);
|
||||
|
||||
export const insertUser = buildInsertInto<UserDBEntry>(pool, Users, { returning: true });
|
||||
|
||||
export const findAllUsers = async () =>
|
||||
pool.many<UserDBEntry>(sql`
|
||||
select ${sql.join(Object.values(fields), sql`, `)}
|
||||
from ${table}
|
||||
`);
|
||||
|
||||
const updateUser = buildUpdateWhere<UserDBEntry>(pool, Users, true);
|
||||
|
||||
export const updateUserById = async (id: string, set: Partial<OmitAutoSetFields<UserDBEntry>>) =>
|
||||
updateUser({ set, where: { id } });
|
||||
|
||||
export const deleteUserById = async (id: string) => {
|
||||
const { rowCount } = await pool.query(sql`
|
||||
delete from ${table}
|
||||
where id=${id}
|
||||
`);
|
||||
if (rowCount < 1) {
|
||||
throw new RequestError({
|
||||
code: 'entity.not_exists_with_id',
|
||||
name: Users.tableSingular,
|
||||
id,
|
||||
status: 404,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { PasswordEncryptionMethod } from '@logto/schemas';
|
||||
import { PasswordEncryptionMethod, userInfoSelectFields } from '@logto/schemas';
|
||||
import pick from 'lodash.pick';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { Provider } from 'oidc-provider';
|
||||
import { object, string } from 'zod';
|
||||
|
@ -6,7 +7,14 @@ import { object, string } from 'zod';
|
|||
import RequestError from '@/errors/RequestError';
|
||||
import { generateUserId } from '@/lib/user';
|
||||
import koaGuard from '@/middleware/koa-guard';
|
||||
import { hasUser, insertUser } from '@/queries/user';
|
||||
import {
|
||||
deleteUserById,
|
||||
findAllUsers,
|
||||
findUserById,
|
||||
hasUser,
|
||||
insertUser,
|
||||
updateUserById,
|
||||
} from '@/queries/user';
|
||||
import { encryptPassword } from '@/utils/password';
|
||||
|
||||
import { AnonymousRouter } from './types';
|
||||
|
@ -58,4 +66,73 @@ export default function userRoutes<T extends AnonymousRouter>(router: T, provide
|
|||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.get('/users', async (ctx, next) => {
|
||||
const users = await findAllUsers();
|
||||
ctx.body = users.map((user) => pick(user, ...userInfoSelectFields));
|
||||
return next();
|
||||
});
|
||||
|
||||
router.get(
|
||||
'/users/:userId',
|
||||
koaGuard({
|
||||
params: object({ userId: string().min(1) }),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
params: { userId },
|
||||
} = ctx.guard;
|
||||
const user = await findUserById(userId);
|
||||
ctx.body = pick(user, ...userInfoSelectFields);
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.patch(
|
||||
'/users/:userId/password',
|
||||
koaGuard({
|
||||
params: object({ userId: string().min(1) }),
|
||||
body: object({ password: string().min(6) }),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
params: { userId },
|
||||
body: { password },
|
||||
} = ctx.guard;
|
||||
|
||||
await findUserById(userId);
|
||||
|
||||
const passwordEncryptionSalt = nanoid();
|
||||
const passwordEncryptionMethod = PasswordEncryptionMethod.SaltAndPepper;
|
||||
const passwordEncrypted = encryptPassword(
|
||||
userId,
|
||||
password,
|
||||
passwordEncryptionSalt,
|
||||
passwordEncryptionMethod
|
||||
);
|
||||
|
||||
await updateUserById(userId, {
|
||||
passwordEncryptionSalt,
|
||||
passwordEncrypted,
|
||||
});
|
||||
const user = await findUserById(userId);
|
||||
ctx.body = pick(user, ...userInfoSelectFields);
|
||||
return next();
|
||||
}
|
||||
);
|
||||
|
||||
router.delete(
|
||||
'/users/:userId',
|
||||
koaGuard({
|
||||
params: object({ userId: string().min(1) }),
|
||||
}),
|
||||
async (ctx, next) => {
|
||||
const {
|
||||
params: { userId },
|
||||
} = ctx.guard;
|
||||
await deleteUserById(userId);
|
||||
ctx.status = 204;
|
||||
return next();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue