1
0

api.js 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. const mime = require("mime-types");
  2. const fs = require('fs');
  3. const Path = require('path');
  4. const Security = require('../src/security.js');
  5. const MediaService = require('../model/mediaService.js');
  6. const MediaFileMetaModel = require('../model/mediaItemMeta.js').MediaFileMetaModel;
  7. const MediaFileTagModel = require('../model/mediaItemTag.js').MediaFileTagModel;
  8. const { AccessModel, ACCESS_TYPE, ACCESS_GRANT } = require('../model/access.js');
  9. function MediaToJson(mediaData) {
  10. if (mediaData.accessType === ACCESS_GRANT.readNoMeta)
  11. mediaData.meta = {
  12. height: mediaData.meta?.height,
  13. width: mediaData.meta?.width
  14. };
  15. return mediaData;
  16. }
  17. module.exports = { register: app => {
  18. app.router.get("/api/access/list", (req, res) => {
  19. app.routerUtils.onApiRequest(req, res);
  20. app.routerUtils.jsonResponse(res, req.sessionObj?.accessList || {});
  21. });
  22. app.router.post("/api/access/link", async (req, res) => { // /api/access/link, post: { linkIds: [string] (JSON) }
  23. app.routerUtils.onApiRequest(req, res);
  24. if (!req.post?.linkIds?.length)
  25. return app.routerUtils.httpResponse(res, 400, "Missing argument");
  26. for (let i of JSON.parse(req.post.linkIds)) {
  27. if (await app.databaseHelper.findOne(AccessModel, { type: ACCESS_TYPE.link, typeData: i }))
  28. Security.addLinkToSession(req, i);
  29. }
  30. app.routerUtils.jsonResponse(res, req.sessionObj.accessList);
  31. });
  32. app.router.del("/api/access/:id", (req, res) => {
  33. app.routerUtils.onApiRequest(req, res);
  34. const result = Security.removeFromSession(req, req.params.id);
  35. app.routerUtils.jsonResponse(res, result);
  36. });
  37. app.router.del("/api/media/:id/tag/:tag", async (req, res) => {
  38. app.routerUtils.onApiRequest(req, res);
  39. if (!req.params.id ||!req.params.tag)
  40. return app.routerUtils.onBadRequest(res);
  41. let data = await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList);
  42. if (!data || data.accessType !== ACCESS_GRANT.write)
  43. return app.routerUtils.onPageNotFound(res);
  44. await app.databaseHelper.remove(MediaFileTagModel, { md5sum: data.md5sum, tag: decodeURIComponent(req.params.tag), fromMeta: 0 });
  45. app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
  46. });
  47. app.router.put("/api/media/:id/tag", async (req, res) => {
  48. app.routerUtils.onApiRequest(req, res);
  49. if (!req.params.id ||!req.body?.tag)
  50. return app.routerUtils.onBadRequest(res);
  51. let data = await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList);
  52. if (!data || data.accessType !== ACCESS_GRANT.write)
  53. return app.routerUtils.onPageNotFound(res);
  54. const requestedTag = req.body.tag;
  55. for (let existingTag of [...data.tags, ...data.fixedTags]) {
  56. if (existingTag === requestedTag || existingTag.startsWith(`${requestedTag}/`)) {
  57. return app.routerUtils.jsonResponse(res, data);
  58. }
  59. }
  60. let tag = new MediaFileTagModel(data.md5sum, requestedTag, false);
  61. await app.databaseHelper.insertOne(tag);
  62. app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
  63. });
  64. app.router.patch("/api/media/:id/meta/:key", async (req, res) => {
  65. app.routerUtils.onApiRequest(req, res);
  66. if (!req.params.id ||!req.params.key || !Number.isInteger(req.body?.value?.length))
  67. return app.routerUtils.onBadRequest(res);
  68. let data = await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList);
  69. if (!data || data.accessType !== ACCESS_GRANT.write)
  70. return app.routerUtils.onPageNotFound(res);
  71. if (!req.body.value) {
  72. await app.databaseHelper.remove(MediaFileMetaModel, { md5sum: data.md5sum, key: req.params.key, fromFile: 0 });
  73. } else {
  74. let newMediaItemMedia = new MediaFileMetaModel(data.md5sum, req.params.key, req.body.value, false);
  75. await app.databaseHelper.upsertOne(newMediaItemMedia);
  76. }
  77. app.routerUtils.jsonResponse(res, MediaToJson(await MediaService.fetchOne(app, req.params.id, req.sessionObj?.accessList)));
  78. });
  79. app.router.get("/api/media/list", async (req, res) => {
  80. app.routerUtils.onApiRequest(req, res);
  81. let first = undefined,
  82. last = undefined;
  83. if (req.body?.chronology !== undefined) {
  84. let range = await MediaService.getMediaRange(app);
  85. first = range[0];
  86. last = range[1];
  87. }
  88. let fromDate = parseInt(req.body?.from);
  89. let count = parseInt(req.body?.count);
  90. app.routerUtils.jsonResponse(res, {
  91. data: (await MediaService.fetchMediasWithAccess(
  92. app,
  93. isNaN(fromDate) ? 0 : fromDate,
  94. isNaN(count) ? 25 : Math.min(150, count),
  95. req.sessionObj?.accessList)).map(MediaToJson),
  96. first: first,
  97. last: last
  98. });
  99. });
  100. app.router.get("/api/media/:md5sum", async (req, res) => {
  101. app.routerUtils.onApiRequest(req, res);
  102. let data = MediaToJson(await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList));
  103. if (!data)
  104. return app.routerUtils.onPageNotFound(res);
  105. app.routerUtils.jsonResponse(res, data);
  106. });
  107. app.router.get("/api/media/thumbnail/:md5sum.jpg", async (req, res) => {
  108. app.routerUtils.onApiRequest(req, res);
  109. let data = await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList);
  110. if (!data)
  111. return app.routerUtils.onPageNotFound(res);
  112. try {
  113. let thumbnail = null;
  114. try {
  115. thumbnail = await (await app.libraryManager.findMedia(data.path))?.createThumbnail(req.body?.w || 0, req.body?.h || 0, req.body?.q || 6);
  116. } catch (err) {
  117. return app.routerUtils.apiError(res);
  118. }
  119. if (!thumbnail)
  120. return app.routerUtils.onPageNotFound(res);
  121. //if (data.accessType === ACCESS_GRANT.readNoMeta) -> trim metadata
  122. res.setHeader("Content-Type", "image/jpeg");
  123. res.setHeader("Content-Length", fs.statSync(thumbnail.name)?.size || undefined);
  124. res.setHeader("Cache-Control", "private, max-age=2630000"); // 1 month cache
  125. let rd = fs.createReadStream(thumbnail.name);
  126. rd.once('end', () => thumbnail.removeCallback());
  127. rd.pipe(res);
  128. }
  129. catch (err) {
  130. console.error(err);
  131. app.routerUtils.onPageNotFound(res);
  132. }
  133. });
  134. app.router.get("/api/media/original/:md5sum", async (req, res) => {
  135. app.routerUtils.onApiRequest(req, res);
  136. let data = await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList);
  137. if (!data)
  138. return app.routerUtils.onPageNotFound(res);
  139. //if (data.accessType === ACCESS_GRANT.readNoMeta) -> trim metadata
  140. const fileName = Path.basename(data.path);
  141. res.setHeader("Content-Type", mime.lookup(data.path));
  142. res.setHeader("Content-Length", fs.statSync(data.path)?.size || undefined);
  143. res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
  144. res.setHeader("Cache-Control", "private, max-age=2630000"); // 1 month cache
  145. fs.createReadStream(data.path).pipe(res);
  146. });
  147. }};