users.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import express from "express";
  2. import internalUser from "../internal/user.js";
  3. import Access from "../lib/access.js";
  4. import jwtdecode from "../lib/express/jwt-decode.js";
  5. import userIdFromMe from "../lib/express/user-id-from-me.js";
  6. import apiValidator from "../lib/validator/api.js";
  7. import validator from "../lib/validator/index.js";
  8. import { express as logger } from "../logger.js";
  9. import { getValidationSchema } from "../schema/index.js";
  10. import { isSetup } from "../setup.js";
  11. const router = express.Router({
  12. caseSensitive: true,
  13. strict: true,
  14. mergeParams: true,
  15. });
  16. /**
  17. * /api/users
  18. */
  19. router
  20. .route("/")
  21. .options((_, res) => {
  22. res.sendStatus(204);
  23. })
  24. .all(jwtdecode())
  25. /**
  26. * GET /api/users
  27. *
  28. * Retrieve all users
  29. */
  30. .get(async (req, res, next) => {
  31. try {
  32. const data = await validator(
  33. {
  34. additionalProperties: false,
  35. properties: {
  36. expand: {
  37. $ref: "common#/properties/expand",
  38. },
  39. query: {
  40. $ref: "common#/properties/query",
  41. },
  42. },
  43. },
  44. {
  45. expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
  46. query: typeof req.query.query === "string" ? req.query.query : null,
  47. },
  48. );
  49. const users = await internalUser.getAll(res.locals.access, data.expand, data.query);
  50. res.status(200).send(users);
  51. } catch (err) {
  52. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  53. next(err);
  54. }
  55. })
  56. /**
  57. * POST /api/users
  58. *
  59. * Create a new User
  60. */
  61. .post(async (req, res, next) => {
  62. const body = req.body;
  63. try {
  64. // If we are in setup mode, we don't check access for current user
  65. const setup = await isSetup();
  66. if (!setup) {
  67. logger.info("Creating a new user in setup mode");
  68. const access = new Access(null);
  69. await access.load(true);
  70. res.locals.access = access;
  71. // We are in setup mode, set some defaults for this first new user, such as making
  72. // them an admin.
  73. body.is_disabled = false;
  74. if (typeof body.roles !== "object" || body.roles === null) {
  75. body.roles = [];
  76. }
  77. if (body.roles.indexOf("admin") === -1) {
  78. body.roles.push("admin");
  79. }
  80. }
  81. const payload = await apiValidator(getValidationSchema("/users", "post"), body);
  82. const user = await internalUser.create(res.locals.access, payload);
  83. res.status(201).send(user);
  84. } catch (err) {
  85. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  86. next(err);
  87. }
  88. });
  89. /**
  90. * Specific user
  91. *
  92. * /api/users/123
  93. */
  94. router
  95. .route("/:user_id")
  96. .options((_, res) => {
  97. res.sendStatus(204);
  98. })
  99. .all(jwtdecode())
  100. .all(userIdFromMe)
  101. /**
  102. * GET /users/123 or /users/me
  103. *
  104. * Retrieve a specific user
  105. */
  106. .get(async (req, res, next) => {
  107. try {
  108. const data = await validator(
  109. {
  110. required: ["user_id"],
  111. additionalProperties: false,
  112. properties: {
  113. user_id: {
  114. $ref: "common#/properties/id",
  115. },
  116. expand: {
  117. $ref: "common#/properties/expand",
  118. },
  119. },
  120. },
  121. {
  122. user_id: req.params.user_id,
  123. expand: typeof req.query.expand === "string" ? req.query.expand.split(",") : null,
  124. },
  125. );
  126. const user = await internalUser.get(res.locals.access, {
  127. id: data.user_id,
  128. expand: data.expand,
  129. omit: internalUser.getUserOmisionsByAccess(res.locals.access, data.user_id),
  130. });
  131. res.status(200).send(user);
  132. } catch (err) {
  133. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  134. next(err);
  135. }
  136. })
  137. /**
  138. * PUT /api/users/123
  139. *
  140. * Update and existing user
  141. */
  142. .put(async (req, res, next) => {
  143. try {
  144. const payload = await apiValidator(getValidationSchema("/users/{userID}", "put"), req.body);
  145. payload.id = req.params.user_id;
  146. const result = await internalUser.update(res.locals.access, payload);
  147. res.status(200).send(result);
  148. } catch (err) {
  149. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  150. next(err);
  151. }
  152. })
  153. /**
  154. * DELETE /api/users/123
  155. *
  156. * Update and existing user
  157. */
  158. .delete(async (req, res, next) => {
  159. try {
  160. const result = await internalUser.delete(res.locals.access, { id: req.params.user_id });
  161. res.status(200).send(result);
  162. } catch (err) {
  163. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  164. next(err);
  165. }
  166. });
  167. /**
  168. * Specific user auth
  169. *
  170. * /api/users/123/auth
  171. */
  172. router
  173. .route("/:user_id/auth")
  174. .options((_, res) => {
  175. res.sendStatus(204);
  176. })
  177. .all(jwtdecode())
  178. .all(userIdFromMe)
  179. /**
  180. * PUT /api/users/123/auth
  181. *
  182. * Update password for a user
  183. */
  184. .put(async (req, res, next) => {
  185. try {
  186. const payload = await apiValidator(getValidationSchema("/users/{userID}/auth", "put"), req.body);
  187. payload.id = req.params.user_id;
  188. const result = await internalUser.setPassword(res.locals.access, payload);
  189. res.status(200).send(result);
  190. } catch (err) {
  191. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  192. next(err);
  193. }
  194. });
  195. /**
  196. * Specific user permissions
  197. *
  198. * /api/users/123/permissions
  199. */
  200. router
  201. .route("/:user_id/permissions")
  202. .options((_, res) => {
  203. res.sendStatus(204);
  204. })
  205. .all(jwtdecode())
  206. .all(userIdFromMe)
  207. /**
  208. * PUT /api/users/123/permissions
  209. *
  210. * Set some or all permissions for a user
  211. */
  212. .put(async (req, res, next) => {
  213. try {
  214. const payload = await apiValidator(getValidationSchema("/users/{userID}/permissions", "put"), req.body);
  215. payload.id = req.params.user_id;
  216. const result = await internalUser.setPermissions(res.locals.access, payload);
  217. res.status(200).send(result);
  218. } catch (err) {
  219. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  220. next(err);
  221. }
  222. });
  223. /**
  224. * Specific user login as
  225. *
  226. * /api/users/123/login
  227. */
  228. router
  229. .route("/:user_id/login")
  230. .options((_, res) => {
  231. res.sendStatus(204);
  232. })
  233. .all(jwtdecode())
  234. /**
  235. * POST /api/users/123/login
  236. *
  237. * Log in as a user
  238. */
  239. .post(async (req, res, next) => {
  240. try {
  241. const result = await internalUser.loginAs(res.locals.access, {
  242. id: Number.parseInt(req.params.user_id, 10),
  243. });
  244. res.status(200).send(result);
  245. } catch (err) {
  246. logger.debug(`${req.method.toUpperCase()} ${req.path}: ${err}`);
  247. next(err);
  248. }
  249. });
  250. export default router;