You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
281 lines
7.4 KiB
281 lines
7.4 KiB
4 years ago
|
import { Router } from 'express';
|
||
|
import { getRepository } from 'typeorm';
|
||
|
import { User } from '../../entity/User';
|
||
|
import { UserSettings } from '../../entity/UserSettings';
|
||
|
import { UserSettingsNotificationsResponse } from '../../interfaces/api/userSettingsInterfaces';
|
||
|
import { Permission } from '../../lib/permissions';
|
||
|
import logger from '../../logger';
|
||
|
import { isAuthenticated } from '../../middleware/auth';
|
||
|
|
||
|
const isOwnProfileOrAdmin = (): Middleware => {
|
||
|
const authMiddleware: Middleware = (req, res, next) => {
|
||
|
if (
|
||
|
!req.user?.hasPermission(Permission.MANAGE_USERS) &&
|
||
|
req.user?.id !== Number(req.params.id)
|
||
|
) {
|
||
|
return next({
|
||
|
status: 403,
|
||
|
message: "You do not have permission to view this user's settings.",
|
||
|
});
|
||
|
}
|
||
|
next();
|
||
|
};
|
||
|
return authMiddleware;
|
||
|
};
|
||
|
|
||
|
const userSettingsRoutes = Router({ mergeParams: true });
|
||
|
|
||
|
userSettingsRoutes.get<{ id: string }, { username?: string }>(
|
||
|
'/main',
|
||
|
isOwnProfileOrAdmin(),
|
||
|
async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
return res.status(200).json({ username: user.username });
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
userSettingsRoutes.post<
|
||
|
{ id: string },
|
||
|
{ username?: string },
|
||
|
{ username?: string }
|
||
|
>('/main', isOwnProfileOrAdmin(), async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
user.username = req.body.username;
|
||
|
|
||
|
await userRepository.save(user);
|
||
|
|
||
|
return res.status(200).json({ username: user.username });
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
});
|
||
|
|
||
|
userSettingsRoutes.get<{ id: string }, { hasPassword: boolean }>(
|
||
|
'/password',
|
||
|
isOwnProfileOrAdmin(),
|
||
|
async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
select: ['id', 'password'],
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
return res.status(200).json({ hasPassword: !!user.password });
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
userSettingsRoutes.post<
|
||
|
{ id: string },
|
||
|
null,
|
||
|
{ currentPassword?: string; newPassword: string }
|
||
|
>('/password', isOwnProfileOrAdmin(), async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
const userWithPassword = await userRepository.findOne({
|
||
|
select: ['id', 'password'],
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user || !userWithPassword) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
if (req.body.newPassword.length < 8) {
|
||
|
return next({
|
||
|
status: 400,
|
||
|
message: 'Password must be at least 8 characters',
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// If the user has the permission to manage users and they are not
|
||
|
// editing themselves, we will just set the new password
|
||
|
if (
|
||
|
req.user?.hasPermission(Permission.MANAGE_USERS) &&
|
||
|
req.user?.id !== user.id
|
||
|
) {
|
||
|
await user.setPassword(req.body.newPassword);
|
||
|
await userRepository.save(user);
|
||
|
logger.debug('Password overriden by user.', {
|
||
|
label: 'User Settings',
|
||
|
userEmail: user.email,
|
||
|
changingUser: req.user.email,
|
||
|
});
|
||
|
return res.status(204).send();
|
||
|
}
|
||
|
|
||
|
// If the user has a password, we need to check the currentPassword is correct
|
||
|
if (
|
||
|
user.password &&
|
||
|
(!req.body.currentPassword ||
|
||
|
!(await userWithPassword.passwordMatch(req.body.currentPassword)))
|
||
|
) {
|
||
|
logger.debug(
|
||
|
'Attempt to change password for user failed. Invalid current password provided.',
|
||
|
{ label: 'User Settings', userEmail: user.email }
|
||
|
);
|
||
|
return next({ status: 403, message: 'Current password is invalid.' });
|
||
|
}
|
||
|
|
||
|
await user.setPassword(req.body.newPassword);
|
||
|
await userRepository.save(user);
|
||
|
|
||
|
return res.status(204).send();
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
});
|
||
|
|
||
|
userSettingsRoutes.get<{ id: string }, UserSettingsNotificationsResponse>(
|
||
|
'/notifications',
|
||
|
isOwnProfileOrAdmin(),
|
||
|
async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
return res.status(200).json({
|
||
|
enableNotifications: user.settings?.enableNotifications ?? true,
|
||
|
discordId: user.settings?.discordId,
|
||
|
});
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
userSettingsRoutes.post<
|
||
|
{ id: string },
|
||
|
UserSettingsNotificationsResponse,
|
||
|
UserSettingsNotificationsResponse
|
||
|
>('/notifications', isOwnProfileOrAdmin(), async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
if (!user.settings) {
|
||
|
user.settings = new UserSettings({
|
||
|
user: req.user,
|
||
|
enableNotifications: req.body.enableNotifications,
|
||
|
discordId: req.body.discordId,
|
||
|
});
|
||
|
} else {
|
||
|
user.settings.enableNotifications = req.body.enableNotifications;
|
||
|
user.settings.discordId = req.body.discordId;
|
||
|
}
|
||
|
|
||
|
userRepository.save(user);
|
||
|
|
||
|
return res.status(200).json({
|
||
|
enableNotifications: user.settings.enableNotifications,
|
||
|
discordId: user.settings.discordId,
|
||
|
});
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
});
|
||
|
|
||
|
userSettingsRoutes.get<{ id: string }, { permissions?: number }>(
|
||
|
'/permissions',
|
||
|
isAuthenticated(Permission.MANAGE_USERS),
|
||
|
async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
return res.status(200).json({ permissions: user.permissions });
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
userSettingsRoutes.post<
|
||
|
{ id: string },
|
||
|
{ permissions?: number },
|
||
|
{ permissions: number }
|
||
|
>(
|
||
|
'/permissions',
|
||
|
isAuthenticated(Permission.MANAGE_USERS),
|
||
|
async (req, res, next) => {
|
||
|
const userRepository = getRepository(User);
|
||
|
|
||
|
try {
|
||
|
const user = await userRepository.findOne({
|
||
|
where: { id: Number(req.params.id) },
|
||
|
});
|
||
|
|
||
|
if (!user) {
|
||
|
return next({ status: 404, message: 'User not found.' });
|
||
|
}
|
||
|
|
||
|
user.permissions = req.body.permissions;
|
||
|
|
||
|
await userRepository.save(user);
|
||
|
|
||
|
return res.status(200).json({ permissions: user.permissions });
|
||
|
} catch (e) {
|
||
|
next({ status: 500, message: e.message });
|
||
|
}
|
||
|
}
|
||
|
);
|
||
|
|
||
|
export default userSettingsRoutes;
|