0
Fork 0
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:
Wang Sijie 2021-11-18 11:26:34 +08:00 committed by GitHub
parent 6d5b9e5bcc
commit 9c3b67ae46
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 3 deletions

View file

@ -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,
});
}
};

View file

@ -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();
}
);
}