user.queries.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. const { addMinutes } = require("date-fns");
  2. const { v4: uuid } = require("uuid");
  3. const { ROLES } = require("../consts");
  4. const utils = require("../utils");
  5. const redis = require("../redis");
  6. const knex = require("../knex");
  7. const env = require("../env");
  8. async function find(match) {
  9. if ((match.email || match.apikey) && env.REDIS_ENABLED) {
  10. const key = redis.key.user(match.email || match.apikey);
  11. const cachedUser = await redis.client.get(key);
  12. if (cachedUser) return JSON.parse(cachedUser);
  13. }
  14. const query = knex("users");
  15. Object.entries(match).forEach(([key, value]) => {
  16. query.andWhere(key, ...(Array.isArray(value) ? value : [value]));
  17. });
  18. const user = await query.first();
  19. if (user && env.REDIS_ENABLED) {
  20. const emailKey = redis.key.user(user.email);
  21. redis.client.set(emailKey, JSON.stringify(user), "EX", 60 * 15);
  22. if (user.apikey) {
  23. const apikeyKey = redis.key.user(user.apikey);
  24. redis.client.set(apikeyKey, JSON.stringify(user), "EX", 60 * 15);
  25. }
  26. }
  27. return user;
  28. }
  29. async function add(params, user) {
  30. const data = {
  31. email: params.email,
  32. password: params.password,
  33. verification_token: uuid(),
  34. verification_expires: utils.dateToUTC(addMinutes(new Date(), 60))
  35. };
  36. if (user) {
  37. await knex("users")
  38. .where("id", user.id)
  39. .update({ ...data, updated_at: utils.dateToUTC(new Date()) });
  40. } else {
  41. await knex("users").insert(data);
  42. }
  43. if (env.REDIS_ENABLED) {
  44. redis.remove.user(user);
  45. }
  46. return {
  47. ...user,
  48. ...data
  49. };
  50. }
  51. async function update(match, update, methods) {
  52. const query = knex("users");
  53. Object.entries(match).forEach(([key, value]) => {
  54. query.andWhere(key, ...(Array.isArray(value) ? value : [value]));
  55. });
  56. const updateQuery = query.clone();
  57. if (methods?.increments) {
  58. methods.increments.forEach(columnName => {
  59. updateQuery.increment(columnName);
  60. });
  61. }
  62. await updateQuery.update({ ...update, updated_at: utils.dateToUTC(new Date()) });
  63. const users = await query.select("*");
  64. if (env.REDIS_ENABLED) {
  65. users.forEach(redis.remove.user);
  66. }
  67. return users;
  68. }
  69. async function remove(user) {
  70. const deletedUser = await knex("users").where("id", user.id).delete();
  71. if (env.REDIS_ENABLED) {
  72. redis.remove.user(user);
  73. }
  74. return !!deletedUser;
  75. }
  76. const selectable_admin = [
  77. "users.id",
  78. "users.email",
  79. "users.verified",
  80. "users.role",
  81. "users.banned",
  82. "users.banned_by_id",
  83. "users.created_at",
  84. "users.updated_at"
  85. ];
  86. function normalizeMatch(match) {
  87. const newMatch = { ...match }
  88. if (newMatch.banned !== undefined) {
  89. newMatch["users.banned"] = newMatch.banned;
  90. delete newMatch.banned;
  91. }
  92. return newMatch;
  93. }
  94. async function getAdmin(match, params) {
  95. const query = knex("users")
  96. .select(...selectable_admin)
  97. .select("l.links_count")
  98. .select("d.domains")
  99. .fromRaw("users")
  100. .where(normalizeMatch(match))
  101. .offset(params.skip)
  102. .limit(params.limit)
  103. .orderBy("users.id", "desc")
  104. .groupBy(1)
  105. .groupBy("l.links_count")
  106. .groupBy("d.domains");
  107. if (params?.search) {
  108. const id = parseInt(params?.search);
  109. if (Number.isNaN(id)) {
  110. query.andWhereILike("users.email", "%" + params?.search + "%");
  111. } else {
  112. query.andWhere("users.id", params?.search);
  113. }
  114. }
  115. if (params?.domains !== undefined) {
  116. query.andWhere("d.domains", params?.domains ? "is not" : "is", null);
  117. }
  118. if (params?.links !== undefined) {
  119. query.andWhere("links_count", params?.links ? "is not" : "is", null);
  120. }
  121. query.leftJoin(
  122. knex("domains")
  123. .select("user_id", knex.raw("string_agg(address, ', ') AS domains"))
  124. .groupBy("user_id").as("d"),
  125. "users.id",
  126. "d.user_id"
  127. )
  128. query.leftJoin(
  129. knex("links").select("user_id").count("id as links_count").groupBy("user_id").as("l"),
  130. "users.id",
  131. "l.user_id"
  132. );
  133. return query;
  134. }
  135. async function totalAdmin(match, params) {
  136. const query = knex("users")
  137. .count("users.id")
  138. .fromRaw('users')
  139. .where(normalizeMatch(match));
  140. if (params?.search) {
  141. const id = parseInt(params?.search);
  142. if (Number.isNaN(id)) {
  143. query.andWhereILike("users.email", "%" + params?.search + "%");
  144. } else {
  145. query.andWhere("users.id", params?.search);
  146. }
  147. }
  148. if (params?.domains !== undefined) {
  149. query.andWhere("domains", params?.domains ? "is not" : "is", null);
  150. query.leftJoin(
  151. knex("domains")
  152. .select("user_id", knex.raw("string_agg(address, ', ') AS domains"))
  153. .groupBy("user_id").as("d"),
  154. "users.id",
  155. "d.user_id"
  156. );
  157. }
  158. if (params?.links !== undefined) {
  159. query.andWhere("links", params?.links ? "is not" : "is", null);
  160. query.leftJoin(
  161. knex("links").select("user_id").count("id as links").groupBy("user_id").as("l"),
  162. "users.id",
  163. "l.user_id"
  164. );
  165. }
  166. const [{count}] = await query;
  167. return typeof count === "number" ? count : parseInt(count);
  168. }
  169. async function create(params) {
  170. const [user] = await knex("users").insert({
  171. email: params.email,
  172. password: params.password,
  173. role: params.role ?? ROLES.USER,
  174. verified: params.verified ?? false,
  175. banned: params.banned ?? false,
  176. }, "*");
  177. return user;
  178. }
  179. module.exports = {
  180. add,
  181. create,
  182. find,
  183. getAdmin,
  184. remove,
  185. totalAdmin,
  186. update,
  187. }