user.queries.js 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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.id || match.apikey) && env.REDIS_ENABLED) {
  10. const key = redis.key.user(match.id || 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 idKey = redis.key.user(user.id);
  21. redis.client.set(idKey, 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. ...(params.role && { role: params.role }),
  34. ...(params.verified !== undefined && { verified: params.verified }),
  35. verification_token: uuid(),
  36. verification_expires: utils.dateToUTC(addMinutes(new Date(), 60))
  37. };
  38. if (user) {
  39. await knex("users")
  40. .where("id", user.id)
  41. .update({ ...data, updated_at: utils.dateToUTC(new Date()) });
  42. } else {
  43. await knex("users").insert(data);
  44. }
  45. if (env.REDIS_ENABLED) {
  46. redis.remove.user(user);
  47. }
  48. return {
  49. ...user,
  50. ...data
  51. };
  52. }
  53. async function update(match, update, methods) {
  54. const user = await knex.transaction(async function(trx) {
  55. const query = trx("users");
  56. Object.entries(match).forEach(([key, value]) => {
  57. query.andWhere(key, ...(Array.isArray(value) ? value : [value]));
  58. });
  59. const user = await query.select("id").first();
  60. if (!user) return null;
  61. const updateQuery = trx("users").where("id", user.id);
  62. if (methods?.increments) {
  63. methods.increments.forEach(columnName => {
  64. updateQuery.increment(columnName);
  65. });
  66. }
  67. await updateQuery.update({ ...update, updated_at: utils.dateToUTC(new Date()) });
  68. const updatedUser = await trx("users").where("id", user.id).first();
  69. return updatedUser;
  70. });
  71. if (env.REDIS_ENABLED && user) {
  72. redis.remove.user(user);
  73. }
  74. return user;
  75. }
  76. async function remove(user) {
  77. const deletedUser = await knex("users").where("id", user.id).delete();
  78. if (env.REDIS_ENABLED) {
  79. redis.remove.user(user);
  80. }
  81. return !!deletedUser;
  82. }
  83. const selectable_admin = [
  84. "users.id",
  85. "users.email",
  86. "users.verified",
  87. "users.role",
  88. "users.banned",
  89. "users.banned_by_id",
  90. "users.created_at",
  91. "users.updated_at"
  92. ];
  93. function normalizeMatch(match) {
  94. const newMatch = { ...match }
  95. if (newMatch.banned !== undefined) {
  96. newMatch["users.banned"] = newMatch.banned;
  97. delete newMatch.banned;
  98. }
  99. return newMatch;
  100. }
  101. async function getAdmin(match, params) {
  102. const query = knex("users")
  103. .select(...selectable_admin)
  104. .select("l.links_count")
  105. .select("d.domains")
  106. .fromRaw("users")
  107. .where(normalizeMatch(match))
  108. .offset(params.skip)
  109. .limit(params.limit)
  110. .orderBy("users.id", "desc")
  111. .groupBy(1)
  112. .groupBy("l.links_count")
  113. .groupBy("d.domains");
  114. if (params?.search) {
  115. const id = parseInt(params?.search);
  116. if (Number.isNaN(id)) {
  117. query.andWhereILike("users.email", "%" + params?.search + "%");
  118. } else {
  119. query.andWhere("users.id", params?.search);
  120. }
  121. }
  122. if (params?.domains !== undefined) {
  123. query.andWhere("d.domains", params?.domains ? "is not" : "is", null);
  124. }
  125. if (params?.links !== undefined) {
  126. query.andWhere("links_count", params?.links ? "is not" : "is", null);
  127. }
  128. query.leftJoin(
  129. knex("domains")
  130. .select("user_id", knex.raw("string_agg(address, ', ') AS domains"))
  131. .groupBy("user_id").as("d"),
  132. "users.id",
  133. "d.user_id"
  134. )
  135. query.leftJoin(
  136. knex("links").select("user_id").count("id as links_count").groupBy("user_id").as("l"),
  137. "users.id",
  138. "l.user_id"
  139. );
  140. return query;
  141. }
  142. async function totalAdmin(match, params) {
  143. const query = knex("users")
  144. .count("users.id")
  145. .fromRaw('users')
  146. .where(normalizeMatch(match));
  147. if (params?.search) {
  148. const id = parseInt(params?.search);
  149. if (Number.isNaN(id)) {
  150. query.andWhereILike("users.email", "%" + params?.search + "%");
  151. } else {
  152. query.andWhere("users.id", params?.search);
  153. }
  154. }
  155. if (params?.domains !== undefined) {
  156. query.andWhere("domains", params?.domains ? "is not" : "is", null);
  157. query.leftJoin(
  158. knex("domains")
  159. .select("user_id", knex.raw("string_agg(address, ', ') AS domains"))
  160. .groupBy("user_id").as("d"),
  161. "users.id",
  162. "d.user_id"
  163. );
  164. }
  165. if (params?.links !== undefined) {
  166. query.andWhere("links", params?.links ? "is not" : "is", null);
  167. query.leftJoin(
  168. knex("links").select("user_id").count("id as links").groupBy("user_id").as("l"),
  169. "users.id",
  170. "l.user_id"
  171. );
  172. }
  173. const [{count}] = await query;
  174. return typeof count === "number" ? count : parseInt(count);
  175. }
  176. async function create(params) {
  177. const [user] = await knex("users").insert({
  178. email: params.email,
  179. password: params.password,
  180. role: params.role ?? ROLES.USER,
  181. verified: params.verified ?? false,
  182. banned: params.banned ?? false,
  183. }, "*");
  184. return user;
  185. }
  186. // check if there exists a user
  187. async function findAny() {
  188. if (env.REDIS_ENABLED) {
  189. const anyuser = await redis.client.get("any-user");
  190. if (anyuser) return true;
  191. }
  192. const anyuser = await knex("users").select("id").first();
  193. if (env.REDIS_ENABLED && anyuser) {
  194. redis.client.set("any-user", JSON.stringify(anyuser), "EX", 60 * 5);
  195. }
  196. return !!anyuser;
  197. }
  198. module.exports = {
  199. add,
  200. create,
  201. find,
  202. findAny,
  203. getAdmin,
  204. remove,
  205. totalAdmin,
  206. update,
  207. }