kutt/server/queries/user.queries.js

252 lines
6.0 KiB
JavaScript
Raw Normal View History

2024-08-11 18:41:03 +03:30
const { addMinutes } = require("date-fns");
const { v4: uuid } = require("uuid");
2020-01-30 18:51:52 +03:30
2024-11-19 07:58:57 +03:30
const { ROLES } = require("../consts");
2024-10-07 09:08:40 +03:30
const utils = require("../utils");
2024-08-11 18:41:03 +03:30
const redis = require("../redis");
const knex = require("../knex");
2024-10-21 14:59:55 +03:30
const env = require("../env");
2020-01-30 18:51:52 +03:30
2024-08-11 18:41:03 +03:30
async function find(match) {
if ((match.id || match.apikey) && env.REDIS_ENABLED) {
const key = redis.key.user(match.id || match.apikey);
2024-08-11 18:41:03 +03:30
const cachedUser = await redis.client.get(key);
if (cachedUser) return JSON.parse(cachedUser);
2020-01-30 18:51:52 +03:30
}
2024-09-25 15:44:55 +03:30
const query = knex("users");
Object.entries(match).forEach(([key, value]) => {
query.andWhere(key, ...(Array.isArray(value) ? value : [value]));
});
const user = await query.first();
2024-08-11 18:41:03 +03:30
2024-10-21 14:59:55 +03:30
if (user && env.REDIS_ENABLED) {
const idKey = redis.key.user(user.id);
redis.client.set(idKey, JSON.stringify(user), "EX", 60 * 15);
2024-08-11 18:41:03 +03:30
2020-01-30 18:51:52 +03:30
if (user.apikey) {
const apikeyKey = redis.key.user(user.apikey);
2024-10-21 14:59:55 +03:30
redis.client.set(apikeyKey, JSON.stringify(user), "EX", 60 * 15);
2020-01-30 18:51:52 +03:30
}
}
2024-08-11 18:41:03 +03:30
2020-01-30 18:51:52 +03:30
return user;
}
2024-08-11 18:41:03 +03:30
async function add(params, user) {
2020-01-30 18:51:52 +03:30
const data = {
email: params.email,
password: params.password,
...(params.role && { role: params.role }),
...(params.verified !== undefined && { verified: params.verified }),
2020-01-30 18:51:52 +03:30
verification_token: uuid(),
2024-10-07 09:08:40 +03:30
verification_expires: utils.dateToUTC(addMinutes(new Date(), 60))
2020-01-30 18:51:52 +03:30
};
2024-08-11 18:41:03 +03:30
2020-01-30 18:51:52 +03:30
if (user) {
2024-08-11 18:41:03 +03:30
await knex("users")
2020-01-30 18:51:52 +03:30
.where("id", user.id)
2024-10-07 09:08:40 +03:30
.update({ ...data, updated_at: utils.dateToUTC(new Date()) });
2020-01-30 18:51:52 +03:30
} else {
2024-08-11 18:41:03 +03:30
await knex("users").insert(data);
2020-01-30 18:51:52 +03:30
}
2024-08-11 18:41:03 +03:30
2024-10-21 14:59:55 +03:30
if (env.REDIS_ENABLED) {
redis.remove.user(user);
}
2024-08-11 18:41:03 +03:30
2020-01-30 18:51:52 +03:30
return {
...user,
...data
};
2024-08-11 18:41:03 +03:30
}
2020-01-30 18:51:52 +03:30
2024-09-24 17:25:06 +03:30
async function update(match, update, methods) {
2024-11-24 14:56:58 +03:30
const user = await knex.transaction(async function(trx) {
const query = trx("users");
Object.entries(match).forEach(([key, value]) => {
query.andWhere(key, ...(Array.isArray(value) ? value : [value]));
});
2024-09-14 00:17:21 +02:00
2024-11-24 14:56:58 +03:30
const user = await query.select("id").first();
if (!user) return null;
const updateQuery = trx("users").where("id", user.id);
if (methods?.increments) {
methods.increments.forEach(columnName => {
updateQuery.increment(columnName);
});
}
await updateQuery.update({ ...update, updated_at: utils.dateToUTC(new Date()) });
const updatedUser = await trx("users").where("id", user.id).first();
return updatedUser;
2020-01-30 18:51:52 +03:30
});
2024-11-24 14:56:58 +03:30
if (env.REDIS_ENABLED && user) {
redis.remove.user(user);
2024-09-24 17:25:06 +03:30
}
2024-09-14 00:17:21 +02:00
2024-11-24 14:56:58 +03:30
return user;
2024-08-11 18:41:03 +03:30
}
2024-08-11 18:41:03 +03:30
async function remove(user) {
const deletedUser = await knex("users").where("id", user.id).delete();
2024-10-21 14:59:55 +03:30
if (env.REDIS_ENABLED) {
redis.remove.user(user);
}
2024-08-11 18:41:03 +03:30
return !!deletedUser;
2024-08-11 18:41:03 +03:30
}
2024-11-19 07:58:57 +03:30
const selectable_admin = [
"users.id",
"users.email",
"users.verified",
"users.role",
"users.banned",
"users.banned_by_id",
"users.created_at",
"users.updated_at"
];
function normalizeMatch(match) {
const newMatch = { ...match }
if (newMatch.banned !== undefined) {
newMatch["users.banned"] = newMatch.banned;
delete newMatch.banned;
}
return newMatch;
}
async function getAdmin(match, params) {
const query = knex("users")
.select(...selectable_admin)
.select("l.links_count")
.select("d.domains")
.fromRaw("users")
.where(normalizeMatch(match))
.offset(params.skip)
.limit(params.limit)
.orderBy("users.id", "desc")
.groupBy(1)
.groupBy("l.links_count")
.groupBy("d.domains");
if (params?.search) {
const id = parseInt(params?.search);
if (Number.isNaN(id)) {
query.andWhereILike("users.email", "%" + params?.search + "%");
} else {
query.andWhere("users.id", params?.search);
}
}
if (params?.domains !== undefined) {
query.andWhere("d.domains", params?.domains ? "is not" : "is", null);
}
if (params?.links !== undefined) {
query.andWhere("links_count", params?.links ? "is not" : "is", null);
}
query.leftJoin(
knex("domains")
.select("user_id", knex.raw("string_agg(address, ', ') AS domains"))
.groupBy("user_id").as("d"),
"users.id",
"d.user_id"
)
query.leftJoin(
knex("links").select("user_id").count("id as links_count").groupBy("user_id").as("l"),
"users.id",
"l.user_id"
);
return query;
}
async function totalAdmin(match, params) {
const query = knex("users")
2025-01-04 13:26:06 +03:30
.count("users.id as count")
2024-11-19 07:58:57 +03:30
.fromRaw('users')
.where(normalizeMatch(match));
if (params?.search) {
const id = parseInt(params?.search);
if (Number.isNaN(id)) {
query.andWhereILike("users.email", "%" + params?.search + "%");
} else {
query.andWhere("users.id", params?.search);
}
}
if (params?.domains !== undefined) {
query.andWhere("domains", params?.domains ? "is not" : "is", null);
query.leftJoin(
knex("domains")
.select("user_id", knex.raw("string_agg(address, ', ') AS domains"))
.groupBy("user_id").as("d"),
"users.id",
"d.user_id"
);
}
if (params?.links !== undefined) {
query.andWhere("links", params?.links ? "is not" : "is", null);
query.leftJoin(
knex("links").select("user_id").count("id as links").groupBy("user_id").as("l"),
"users.id",
"l.user_id"
);
}
const [{count}] = await query;
return typeof count === "number" ? count : parseInt(count);
}
async function create(params) {
const [user] = await knex("users").insert({
email: params.email,
password: params.password,
role: params.role ?? ROLES.USER,
verified: params.verified ?? false,
banned: params.banned ?? false,
}, "*");
return user;
}
// check if there exists a user
async function findAny() {
if (env.REDIS_ENABLED) {
const anyuser = await redis.client.get("any-user");
if (anyuser) return true;
}
const anyuser = await knex("users").select("id").first();
if (env.REDIS_ENABLED && anyuser) {
redis.client.set("any-user", JSON.stringify(anyuser), "EX", 60 * 5);
}
return !!anyuser;
}
2024-08-11 18:41:03 +03:30
module.exports = {
add,
2024-11-19 07:58:57 +03:30
create,
2024-08-11 18:41:03 +03:30
find,
findAny,
2024-11-19 07:58:57 +03:30
getAdmin,
2024-08-11 18:41:03 +03:30
remove,
2024-11-19 07:58:57 +03:30
totalAdmin,
2024-08-11 18:41:03 +03:30
update,
}