const redis = require("../redis"); const utils = require("../utils"); const knex = require("../knex"); const env = require("../env"); async function find(match) { if (match.address && env.REDIS_ENABLED) { const cachedDomain = await redis.client.get(redis.key.domain(match.address)); if (cachedDomain) return JSON.parse(cachedDomain); } const domain = await knex("domains").where(match).first(); if (domain && env.REDIS_ENABLED) { const key = redis.key.domain(domain.address); redis.client.set(key, JSON.stringify(domain), "EX", 60 * 15); } return domain; } function get(match) { return knex("domains").where(match); } async function add(params) { params.address = params.address.toLowerCase(); const existingDomain = await knex("domains").where("address", params.address).first(); let id = existingDomain?.id; const newDomain = { address: params.address, homepage: params.homepage, user_id: params.user_id, banned: !!params.banned, banned_by_id: params.banned_by_id }; if (id) { await knex("domains").where("id", id).update({ ...newDomain, updated_at: params.updated_at || utils.dateToUTC(new Date()) }); } else { // Mysql and sqlite don't support returning but return the inserted id by default const [createdDomain] = await knex("domains").insert(newDomain).returning("id"); id = createdDomain.id; } // Query domain instead of using returning as sqlite and mysql don't support it const domain = await knex("domains").where("id", id).first(); if (env.REDIS_ENABLED) { redis.remove.domain(domain); } return domain; } async function update(match, update) { await knex("domains") .where(match) .update({ ...update, updated_at: utils.dateToUTC(new Date()) }); const domains = await knex("domains").select("*").where(match); if (env.REDIS_ENABLED) { domains.forEach(redis.remove.domain); } return domains; } function normalizeMatch(match) { const newMatch = { ...match }; if (newMatch.address) { newMatch["domains.address"] = newMatch.address; delete newMatch.address; } if (newMatch.user_id) { newMatch["domains.user_id"] = newMatch.user_id; delete newMatch.user_id; } if (newMatch.uuid) { newMatch["domains.uuid"] = newMatch.uuid; delete newMatch.uuid; } if (newMatch.banned !== undefined) { newMatch["domains.banned"] = newMatch.banned; delete newMatch.banned; } return newMatch; } const selectable_admin = [ "domains.id", "domains.address", "domains.homepage", "domains.banned", "domains.created_at", "domains.updated_at", "domains.user_id", "domains.uuid", "users.email as email", "links_count" ]; async function getAdmin(match, params) { const query = knex("domains").select(...selectable_admin); Object.entries(normalizeMatch(match)).forEach(([key, value]) => { query.andWhere(key, ...(Array.isArray(value) ? value : [value])); }); query .offset(params.skip) .limit(params.limit) .fromRaw("domains") .orderBy("domains.id", "desc") .groupBy(1) .groupBy("l.links_count") .groupBy("users.email"); if (params?.user) { const id = parseInt(params?.user); if (Number.isNaN(id)) { query.andWhereILike("users.email", "%" + params.user + "%"); } else { query.andWhere("domains.user_id", id); } } if (params?.search) { query.andWhereRaw( "concat_ws(' ', domains.address, domains.homepage) ILIKE '%' || ? || '%'", [params.search] ); } if (params?.links !== undefined) { query.andWhere("links_count", params?.links ? "is not" : "is", null); } query.leftJoin( knex("links").select("domain_id").count("id as links_count").groupBy("domain_id").as("l"), "domains.id", "l.domain_id" ); query.leftJoin("users", "domains.user_id", "users.id"); return query; } async function totalAdmin(match, params) { const query = knex("domains"); Object.entries(normalizeMatch(match)).forEach(([key, value]) => { query.andWhere(key, ...(Array.isArray(value) ? value : [value])); }); if (params?.user) { const id = parseInt(params?.user); if (Number.isNaN(id)) { query.andWhereILike("users.email", "%" + params.user + "%"); } else { query.andWhere("domains.user_id", id); } } if (params?.search) { query.andWhereILike("domains.address", "%" + params.search + "%"); } if (params?.links !== undefined) { query.leftJoin( knex("links").select("domain_id").count("id as links_count").groupBy("domain_id").as("l"), "domains.id", "l.domain_id" ); query.andWhere("links_count", params?.links ? "is not" : "is", null); } query.leftJoin("users", "domains.user_id", "users.id"); query.count("domains.id"); const [{ count }] = await query; return typeof count === "number" ? count : parseInt(count); } async function remove(domain) { const deletedDomain = await knex("domains").where("id", domain.id).delete(); if (env.REDIS_ENABLED) { redis.remove.domain(domain); } return !!deletedDomain; } module.exports = { add, find, get, getAdmin, remove, totalAdmin, update, }