feat(backend): invites, notifications, chat, uploads, teams, groups, hardening
- Pending workspace invites with accept/decline + bell notifications; invite permission extendable via workspace.invite group right - Notifications API (list/unread, mark read, read-all) + realtime push to per-user socket rooms; chat messages notify other members - Workspace team chat API (list/post/delete) + chat:join socket rooms - Image uploads (multer, 5MB image-only) served from /uploads - Teams (managers/members), team-owned workspaces (TEAM badge), team task boards (team_id) and task assignees (workspace members only) - Permission groups with teams.create/edit/invite + workspace.invite, default Team Creators seeding, hasPerm/canManageTeam guards - Public registration disabled after install; admins create users (pending invites auto-link); users gain bg_glass setting - Crash fix: express-async-errors + 400 on malformed IDs instead of unhandled rejections killing the server
This commit is contained in:
@@ -36,7 +36,7 @@ router.get('/discover', async (req, res) => {
|
||||
|
||||
// PATCH /api/users/me — profile + appearance settings
|
||||
router.patch('/me', async (req, res) => {
|
||||
const { name, email, avatar, locale, theme, bg_image, bg_blur } = req.body ?? {};
|
||||
const { name, email, avatar, locale, theme, bg_image, bg_blur, bg_glass } = req.body ?? {};
|
||||
if (name !== undefined && (String(name).trim().length < 1 || String(name).length > 100)) {
|
||||
return res.status(400).json({ error: 'Name must be 1-100 chars' });
|
||||
}
|
||||
@@ -64,9 +64,10 @@ router.patch('/me', async (req, res) => {
|
||||
locale = COALESCE($4, locale),
|
||||
theme = COALESCE($5, theme),
|
||||
bg_image = COALESCE($6, bg_image),
|
||||
bg_blur = COALESCE($7, bg_blur)
|
||||
WHERE id = $8
|
||||
RETURNING id, email, name, is_admin, avatar, locale, theme, bg_image, bg_blur, created_at`,
|
||||
bg_blur = COALESCE($7, bg_blur),
|
||||
bg_glass = COALESCE($8, bg_glass)
|
||||
WHERE id = $9
|
||||
RETURNING id, email, name, is_admin, avatar, locale, theme, bg_image, bg_blur, bg_glass, created_at`,
|
||||
[
|
||||
name !== undefined ? String(name).trim() : null,
|
||||
email !== undefined ? String(email).toLowerCase() : null,
|
||||
@@ -75,6 +76,7 @@ router.patch('/me', async (req, res) => {
|
||||
theme !== undefined ? theme : null,
|
||||
bg_image !== undefined ? String(bg_image).slice(0, 2000) : null,
|
||||
bg_blur !== undefined ? Boolean(bg_blur) : null,
|
||||
bg_glass !== undefined ? Boolean(bg_glass) : null,
|
||||
req.user.id,
|
||||
],
|
||||
);
|
||||
@@ -83,7 +85,8 @@ router.patch('/me', async (req, res) => {
|
||||
user: {
|
||||
id: u.id, email: u.email, name: u.name, isAdmin: !!u.is_admin,
|
||||
avatar: u.avatar || '', locale: u.locale, theme: u.theme,
|
||||
bgImage: u.bg_image || '', bgBlur: u.bg_blur !== false, createdAt: u.created_at,
|
||||
bgImage: u.bg_image || '', bgBlur: u.bg_blur !== false,
|
||||
bgGlass: u.bg_glass !== false, createdAt: u.created_at,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user