generated from azures04/Base-REST-API
Add bans, user cache, auth routes & token changes
Introduce user bans and caching, extend schemas, and add auth/user endpoints. Adds bans DDL and banRepo plus adminService to manage bans; introduces modules/cache for in-memory user caching used by authService and userService. Updates users and credentials DDLs (role, isDisabled, shouldReset). Changes tokensService to include role in access tokens and store refresh tokens as SHA-256 hashes. Updates repos (credentials create RETURNING, usersRepo.updateProfile positional params), enhances authService with isLogged/isNotLogged middleware, ban checks, and refreshed token flow. Adds auth routes (login, logout, refresh, register) and user routes (/me).
This commit is contained in:
@@ -1,11 +1,13 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `users` (
|
CREATE TABLE IF NOT EXISTS `users` (
|
||||||
`id` UUID PRIMARY KEY DEFAULT UUID(),
|
`id` UUID PRIMARY KEY DEFAULT UUID(),
|
||||||
|
`role` VARCHAR(16) NOT NULL DEFAULT 'user',
|
||||||
`serverId` UUID NULL,
|
`serverId` UUID NULL,
|
||||||
`identifier` VARCHAR(255) NOT NULL UNIQUE,
|
|
||||||
`remoteId` VARCHAR(255) NULL,
|
`remoteId` VARCHAR(255) NULL,
|
||||||
`displayName` VARCHAR(512) NOT NULL,
|
|
||||||
`avatarUrl` TEXT NULL,
|
`avatarUrl` TEXT NULL,
|
||||||
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
`identifier` VARCHAR(255) NOT NULL UNIQUE,
|
||||||
|
`isDisabled` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
|
`displayName` VARCHAR(512) NOT NULL,
|
||||||
|
|
||||||
CONSTRAINT `fk_users_serverId` FOREIGN KEY (`serverId`) REFERENCES `servers` (`id`) ON DELETE CASCADE,
|
CONSTRAINT `fk_users_serverId` FOREIGN KEY (`serverId`) REFERENCES `servers` (`id`) ON DELETE CASCADE,
|
||||||
CONSTRAINT `uq_users_server_remote` UNIQUE (`serverId`, `remoteId`)
|
CONSTRAINT `uq_users_server_remote` UNIQUE (`serverId`, `remoteId`)
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
CREATE TABLE IF NOT EXISTS `credentials` (
|
CREATE TABLE IF NOT EXISTS `credentials` (
|
||||||
`userId` UUID PRIMARY KEY,
|
`userId` UUID PRIMARY KEY,
|
||||||
`passwordHash` TEXT NOT NULL,
|
`passwordHash` TEXT NOT NULL,
|
||||||
|
`shouldReset` BOOLEAN NOT NULL DEFAULT FALSE,
|
||||||
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
`updatedAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
CONSTRAINT `fk_credentials_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
CONSTRAINT `fk_credentials_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
CREATE TABLE IF NOT EXISTS `bans` (
|
||||||
|
`id` UUID PRIMARY KEY DEFAULT UUID(),
|
||||||
|
`userId` UUID NOT NULL,
|
||||||
|
`message` TEXT NOT NULL,
|
||||||
|
`isActive` BOOLEAN NOT NULL DEFAULT TRUE,
|
||||||
|
`expiresAt` TIMESTAMP NOT NULL,
|
||||||
|
`createdAt` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
CONSTRAINT `fk_ban_userId` FOREIGN KEY (`userId`) REFERENCES `users` (`id`) ON DELETE CASCADE
|
||||||
|
)
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
const usersCache = new Map()
|
||||||
|
|
||||||
|
function putUser(userId, userObject) {
|
||||||
|
return usersCache.set(userId, userObject)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUser(userId) {
|
||||||
|
return usersCache.get(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteUser(userId) {
|
||||||
|
return usersCache.delete(userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
users: {
|
||||||
|
put: putUser,
|
||||||
|
get: getUser,
|
||||||
|
delete: deleteUser
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
const { pool } = require("../modules/database")
|
||||||
|
const { DefaultError } = require("../errors/errors")
|
||||||
|
|
||||||
|
async function banUser(userId, message, expiresAt) {
|
||||||
|
try {
|
||||||
|
const sql = "INSERT INTO bans (userId, message, expiresAt) VALUES (?, ?, ?) RETURNING *"
|
||||||
|
const rows = await pool.query(sql, [userId, message, expiresAt])
|
||||||
|
return rows[0] || null
|
||||||
|
} catch (error) {
|
||||||
|
throw new DefaultError(500, "Internal Server Error", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isBanned(userId) {
|
||||||
|
try {
|
||||||
|
const sql = "SELECT * FROM bans WHERE userId = ? AND isActive = TRUE LIMIT 1"
|
||||||
|
const rows = await pool.query(sql, [userId])
|
||||||
|
return rows[0] || null
|
||||||
|
} catch (error) {
|
||||||
|
throw new DefaultError(500, "Internal Server Error", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unbanUser(banId) {
|
||||||
|
try {
|
||||||
|
const sql = "UPDATE bans SET isActive = FALSE WHERE id = ?"
|
||||||
|
const rows = await pool.query(sql, [banId])
|
||||||
|
return rows.affectedRows > 0
|
||||||
|
} catch (error) {
|
||||||
|
throw new DefaultError(500, "Internal Server Error", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getBanHistory(userId) {
|
||||||
|
try {
|
||||||
|
const sql = "SELECT * FROM bans WHERE id = userId"
|
||||||
|
const rows = await pool.query(sql, [userId, limit])
|
||||||
|
return rows.affectedRows > 0
|
||||||
|
} catch (error) {
|
||||||
|
throw new DefaultError(500, "Internal Server Error", error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
banUser,
|
||||||
|
isBanned,
|
||||||
|
unbanUser,
|
||||||
|
getBanHistory
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ async function findByUserId(userId) {
|
|||||||
|
|
||||||
async function create(userId, passwordHash) {
|
async function create(userId, passwordHash) {
|
||||||
try {
|
try {
|
||||||
const sql = "INSERT INTO credentials (userId, passwordHash) VALUES (?, ?)"
|
const sql = "INSERT INTO credentials (userId, passwordHash) VALUES (?, ?) RETURNING *"
|
||||||
const rows = await pool.query(sql, [userId, passwordHash])
|
const rows = await pool.query(sql, [userId, passwordHash])
|
||||||
return rows || null
|
return rows || null
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -58,27 +58,30 @@ async function isLocal(id) {
|
|||||||
async function updateProfile(id, displayName, avatarUrl) {
|
async function updateProfile(id, displayName, avatarUrl) {
|
||||||
try {
|
try {
|
||||||
const fields = []
|
const fields = []
|
||||||
const params = { id }
|
const params = []
|
||||||
|
|
||||||
if (displayName !== undefined) {
|
if (displayName !== undefined) {
|
||||||
fields.push('`displayName` = :displayName')
|
fields.push('`displayName` = ?')
|
||||||
params.displayName = displayName
|
params.push(displayName)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (avatarUrl !== undefined) {
|
if (avatarUrl !== undefined) {
|
||||||
fields.push('`avatarUrl` = :avatarUrl')
|
fields.push('`avatarUrl` = ?')
|
||||||
params.avatarUrl = avatarUrl
|
params.push(avatarUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fields.length === 0) {
|
if (fields.length === 0) {
|
||||||
return findById(id)
|
return findById(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
const sql = `UPDATE users SET ${fields.join(', ')} WHERE id = :id`
|
params.push(id)
|
||||||
|
|
||||||
|
const sql = `UPDATE users SET ${fields.join(', ')} WHERE id = ?`
|
||||||
await pool.query(sql, params)
|
await pool.query(sql, params)
|
||||||
|
|
||||||
return findById(id)
|
return findById(id)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.error(error)
|
||||||
throw new DefaultError(500, "Internal Server Error", error)
|
throw new DefaultError(500, "Internal Server Error", error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const express = require("express")
|
||||||
|
const authService = require("../../../../services/authService")
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.post("/", authService.isNotLogged, async (req, res) => {
|
||||||
|
if (process.env.LOGIN_ENABLED != "true") {
|
||||||
|
return res.status(401).json({ error: "login_disabled", error_description: "The administrator has disabled internal login." })
|
||||||
|
}
|
||||||
|
const { identifier, password } = req.body
|
||||||
|
const user = await authService.loginLocal({ identifier, password })
|
||||||
|
return res.status(201).json(user)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
const express = require("express")
|
||||||
|
const authService = require("../../../../services/authService")
|
||||||
|
const tokensService = require("../../../../services/tokensService")
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.post("/", authService.isLogged, async (req, res) => {
|
||||||
|
const { refresh_token } = req.body
|
||||||
|
await tokensService.revokeRefreshToken(refresh_token)
|
||||||
|
return res.status(200).json(user)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
const express = require("express")
|
||||||
|
const authService = require("../../../../services/authService")
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.post("/", authService.isLogged, async (req, res) => {
|
||||||
|
const { refresh_token } = req.body
|
||||||
|
const tokens = await authService.refreshAccessToken({ refreshToken: refresh_token })
|
||||||
|
return res.status(200).json(tokens)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
const express = require("express")
|
||||||
|
const authService = require("../../../../services/authService")
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.post("/", authService.isNotLogged, async (req, res) => {
|
||||||
|
if (process.env.REGISTER_ENABLED != "true") {
|
||||||
|
return res.status(401).json({ error: "registration_disabled", error_description: "The administrator has disabled internal registration." })
|
||||||
|
}
|
||||||
|
const { identifier, password, avatarURL, displayName } = req.body
|
||||||
|
const user = await authService.registerLocal({ identifier, password, profile: { avatarURL, displayName } })
|
||||||
|
return res.status(201).json(user)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
const express = require("express")
|
||||||
|
const authService = require("../../../../services/authService")
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.use("", authService.isLogged)
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
const express = require("express")
|
||||||
|
const userService = require("../../../../services/userService")
|
||||||
|
const router = express.Router()
|
||||||
|
|
||||||
|
router.get("/", async (req, res) => {
|
||||||
|
const user = await userService.getProfile({ userId: req.user.id })
|
||||||
|
return res.status(200).json(user)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.patch("/avatar", async (req, res) => {
|
||||||
|
const { avatarURL } = req.body
|
||||||
|
const updatedProfile = await userService.updateProfile({ userId: req.user.id, profile: { avatarURL } })
|
||||||
|
return res.status(200).json(updatedProfile)
|
||||||
|
})
|
||||||
|
|
||||||
|
router.patch("/displayname", async (req, res) => {
|
||||||
|
const { displayName } = req.body
|
||||||
|
const updatedProfile = await userService.updateProfile({ userId: req.user.id, profile: { displayName } })
|
||||||
|
return res.status(200).json(updatedProfile)
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
const { DefaultError } = require("../errors/errors")
|
||||||
|
const banRepo = require("../repositories/banRepo")
|
||||||
|
|
||||||
|
async function banUser(userId, message, expiresAt) {
|
||||||
|
const existingBan = await banRepo.isBanned(userId)
|
||||||
|
if (existingBan) {
|
||||||
|
throw new DefaultError(409, "Already has an active ban.", "Duplicate active ban.")
|
||||||
|
}
|
||||||
|
return await banRepo.banUser(userId, message, expiresAt)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function unbanUser(banId) {
|
||||||
|
const existingBan = await banRepo.isBanned(userId)
|
||||||
|
if (!existingBan) {
|
||||||
|
throw new DefaultError(404, "No active ban.", "No active ban found.")
|
||||||
|
}
|
||||||
|
return await banRepo.unbanUser(banId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function isUserBanned(userId) {
|
||||||
|
const ban = await banRepo.isBanned(userId)
|
||||||
|
if (!ban) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new Date(ban.expiresAt) <= new Date()) {
|
||||||
|
await banRepo.deactivate(ban.id)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
banUser,
|
||||||
|
unbanUser,
|
||||||
|
isUserBanned
|
||||||
|
}
|
||||||
+45
-6
@@ -1,5 +1,7 @@
|
|||||||
|
const cache = require("../modules/cache")
|
||||||
const bcrypt = require("bcryptjs")
|
const bcrypt = require("bcryptjs")
|
||||||
const usersRepo = require("../repositories/usersRepo")
|
const usersRepo = require("../repositories/usersRepo")
|
||||||
|
const adminService = require("./adminService")
|
||||||
const tokensService = require("./tokensService")
|
const tokensService = require("./tokensService")
|
||||||
const identitiesRepo = require("../repositories/identitiesRepo")
|
const identitiesRepo = require("../repositories/identitiesRepo")
|
||||||
const credentialsRepo = require("../repositories/credentialsRepo")
|
const credentialsRepo = require("../repositories/credentialsRepo")
|
||||||
@@ -10,7 +12,7 @@ async function registerLocal({ identifier, password, profile = { displayName, av
|
|||||||
const user = await usersRepo.create(identifier, process.env.SERVER_UUID, null, profile.displayName, profile.avatarURL)
|
const user = await usersRepo.create(identifier, process.env.SERVER_UUID, null, profile.displayName, profile.avatarURL)
|
||||||
const hashedPassword = await bcrypt.hash(password, Number(process.env.BCRYPT_SALT))
|
const hashedPassword = await bcrypt.hash(password, Number(process.env.BCRYPT_SALT))
|
||||||
const credentials = await credentialsRepo.create(user.id, hashedPassword)
|
const credentials = await credentialsRepo.create(user.id, hashedPassword)
|
||||||
if (Array.isArray(credentials)) {
|
if (credentials.length == 0) {
|
||||||
throw new DefaultError(500, "Internal Server Error", "UserRegistration")
|
throw new DefaultError(500, "Internal Server Error", "UserRegistration")
|
||||||
}
|
}
|
||||||
return user
|
return user
|
||||||
@@ -41,13 +43,13 @@ async function loginLocal({ identifier, password }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function refreshAccessToken({ userId, refreshToken }) {
|
async function refreshAccessToken({ refreshToken }) {
|
||||||
try {
|
try {
|
||||||
await tokensService.verifyRefreshToken(refreshToken)
|
const payload = await tokensService.verifyRefreshToken(refreshToken)
|
||||||
await tokensService.revokeRefreshToken(refreshToken)
|
await tokensService.revokeRefreshToken(refreshToken)
|
||||||
const user = await usersRepo.findById(userId)
|
const user = await usersRepo.findById(payload.userId)
|
||||||
const newAccessToken = await tokensService.signToken(user)
|
const newAccessToken = await tokensService.signToken(user)
|
||||||
const newRefreshToken = await tokensService.signRefreshToken(userId)
|
const newRefreshToken = await tokensService.signRefreshToken(user.id)
|
||||||
return { accessToken: newAccessToken, refreshToken: newRefreshToken }
|
return { accessToken: newAccessToken, refreshToken: newRefreshToken }
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
@@ -74,10 +76,47 @@ async function resetPassword({ userId, newPassword }) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function isNotLogged(req, res, next) {
|
||||||
|
if (req.headers.authorization && req.headers.authorization.startsWith("Bearer")) {
|
||||||
|
throw new DefaultError(401, "You must be logged out to do this action", "Auth header")
|
||||||
|
}
|
||||||
|
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function isLogged(req, res, next) {
|
||||||
|
if (!req.headers.authorization) {
|
||||||
|
throw new DefaultError(401, "You must be logged in to do this action", "Auth header")
|
||||||
|
}
|
||||||
|
if (!req.headers.authorization.startsWith("Bearer ")) {
|
||||||
|
throw new DefaultError(422, "Wrong auth header format", "WhereIsBearer")
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenVerified = await tokensService.verifyAccessToken(req.headers.authorization.replace("Bearer ", ""))
|
||||||
|
const isBanned = await adminService.isUserBanned(tokenVerified.id)
|
||||||
|
if (isBanned) {
|
||||||
|
throw new DefaultError(403, "You're not allowed to do this action", "Banned")
|
||||||
|
}
|
||||||
|
|
||||||
|
let user = cache.users.get(tokenVerified.id)
|
||||||
|
if (!user) {
|
||||||
|
user = await usersRepo.findById(tokenVerified.id)
|
||||||
|
if (!user) {
|
||||||
|
throw new DefaultError(404, "User not found", "UserNotFound")
|
||||||
|
}
|
||||||
|
cache.users.put(tokenVerified.id, user)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.user = user
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
isLogged,
|
||||||
loginLocal,
|
loginLocal,
|
||||||
|
isNotLogged,
|
||||||
resetPassword,
|
resetPassword,
|
||||||
registerLocal,
|
registerLocal,
|
||||||
changePassword,
|
changePassword,
|
||||||
refreshAccessToken
|
refreshAccessToken,
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
const jwt = require("jsonwebtoken")
|
const jwt = require("jsonwebtoken")
|
||||||
|
const crypto = require("node:crypto")
|
||||||
const security = require("../modules/security")
|
const security = require("../modules/security")
|
||||||
const tokenRepo = require("../repositories/refreshTokensRepo")
|
const tokenRepo = require("../repositories/refreshTokensRepo")
|
||||||
const { DefaultError } = require("../errors/errors")
|
const { DefaultError } = require("../errors/errors")
|
||||||
@@ -12,7 +13,8 @@ async function signToken(user) {
|
|||||||
id: user.id,
|
id: user.id,
|
||||||
identifier: user.identifier,
|
identifier: user.identifier,
|
||||||
displayName: user.displayName,
|
displayName: user.displayName,
|
||||||
avatarUrl: user.avatarUrl
|
avatarUrl: user.avatarUrl,
|
||||||
|
role: user.role
|
||||||
}
|
}
|
||||||
const token = await jwt.sign(payload, privateKey, {
|
const token = await jwt.sign(payload, privateKey, {
|
||||||
algorithm: "RS256",
|
algorithm: "RS256",
|
||||||
@@ -31,7 +33,6 @@ async function verifyAccessToken(token) {
|
|||||||
algorithms: ["RS256"],
|
algorithms: ["RS256"],
|
||||||
issuer: process.env.FQDN
|
issuer: process.env.FQDN
|
||||||
})
|
})
|
||||||
console.log(result)
|
|
||||||
return result
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
@@ -56,7 +57,8 @@ async function signRefreshToken(userId) {
|
|||||||
expiresIn: expiresIn
|
expiresIn: expiresIn
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
await tokenRepo.create(userId, token, expiresAtInMs)
|
const hash = crypto.createHash("sha256").update(token).digest("hex")
|
||||||
|
await tokenRepo.create(userId, hash, expiresAtInMs)
|
||||||
return token
|
return token
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
@@ -80,11 +82,12 @@ async function verifyRefreshToken(token) {
|
|||||||
if (!result) {
|
if (!result) {
|
||||||
throw new DefaultError(500, "Internal Server Error")
|
throw new DefaultError(500, "Internal Server Error")
|
||||||
}
|
}
|
||||||
const refreshTokenInDb = await tokenRepo.findByTokenHash(token)
|
const hash = crypto.createHash("sha256").update(token).digest("hex")
|
||||||
|
const refreshTokenInDb = await tokenRepo.findByTokenHash(hash)
|
||||||
if (refreshTokenInDb == null) {
|
if (refreshTokenInDb == null) {
|
||||||
throw new DefaultError(403, "Bad refresh token", "Refresh token doesn't exists")
|
throw new DefaultError(403, "Bad refresh token", "Refresh token doesn't exists")
|
||||||
}
|
}
|
||||||
return true
|
return result
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
const userRepo = require("../repositories/usersRepo")
|
const userRepo = require("../repositories/usersRepo")
|
||||||
|
const cache = require("../modules/cache")
|
||||||
|
|
||||||
async function getProfile({ userId }) {
|
async function getProfile({ userId }) {
|
||||||
|
const cachedUser = cache.users.get(userId)
|
||||||
|
if (cachedUser) {
|
||||||
|
return cachedUser
|
||||||
|
}
|
||||||
return await userRepo.findById(userId)
|
return await userRepo.findById(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateProfile({ userId, profile = { displayName, avatarURL } }) {
|
async function updateProfile({ userId, profile = { displayName, avatarURL } }) {
|
||||||
|
cache.users.delete(userId)
|
||||||
return await userRepo.updateProfile(userId, profile.displayName, profile.avatarURL)
|
return await userRepo.updateProfile(userId, profile.displayName, profile.avatarURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user