| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- const mime = require("mime-types");
- const fs = require('fs');
- const Path = require('path');
- const Security = require('../src/security.js');
- const MediaService = require('../model/mediaService.js');
- const MediaFileMetaModel = require('../model/mediaItemMeta.js').MediaFileMetaModel;
- const MediaFileTagModel = require('../model/mediaItemTag.js').MediaFileTagModel;
- const { AccessModel, ACCESS_TYPE, ACCESS_GRANT, ACCESS_TO } = require('../model/access.js');
- function MediaToJson(mediaData) {
- if (!mediaData)
- return null;
- if (mediaData.accessType === ACCESS_GRANT.readNoMeta)
- mediaData.meta = {
- height: mediaData.meta?.height,
- width: mediaData.meta?.width
- };
- return mediaData;
- }
- function accessToJson(access) {
- const typeStr = [ "unknown", "ldapAccount", "email", "link", "every one" ][access.type];
- const accessToStr = [ "unknown", "item", "tag", "meta", "everything", "admin"][access.accessTo];
- const grantStr = [ "none", "read", "write", "read without meta"][access.grant];
- return {
- id: access.id,
- type: typeStr,
- typeLabel: access.typeLabel,
- typeData: access.typeData,
- accessTo: accessToStr,
- accessToData: access.accessToData,
- grant: grantStr
- };
- }
- async function accessListToJson(app, req) {
- let result = {
- ...(req.sessionObj?.accessList || {})
- };
- result.isAdmin = await req.sessionObj?.accessList?.isAdmin?.(app, result) || false;
- delete result.isAdmin_;
- return result;
- }
- module.exports = { register: app => {
- app.router.post("/api/database/reload", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!await req.sessionObj?.accessList?.isAdmin(app, req.sessionObj?.accessList))
- return app.routerUtils.onBadRequest(res);
- app.libraryManager.updateLibraries(app);
- app.routerUtils.jsonResponse(res, {});
- });
- app.router.get("/api/access/list", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- app.routerUtils.jsonResponse(res, await accessListToJson(app, req));
- });
- app.router.post("/api/access/link", async (req, res) => { // /api/access/link, post: { linkIds: [string] (JSON) }
- app.routerUtils.onApiRequest(req, res);
- if (!req.post?.linkIds?.length)
- return app.routerUtils.httpResponse(res, 400, "Missing argument");
- try {
- for (let i of JSON.parse(req.post.linkIds)) {
- const access = await app.databaseHelper.findOne(AccessModel, { type: ACCESS_TYPE.link, typeData: i });
- if (access) {
- Security.addLinkToSession(req, access.id, i, access.typeLabel);
- if (access.accessTo == ACCESS_TO.admin)
- Security.setAdmin(req, true);
- }
- }
- }
- catch (err) {
- console.error(err);
- return app.routerUtils.onBadRequest(res);
- }
- app.routerUtils.jsonResponse(res, await accessListToJson(app, req));
- });
- app.router.del("/api/access/:id", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- Security.removeFromSession(req, req.params.id);
- const access = await app.databaseHelper.fetch(AccessModel, { id: Object.keys(req.sessionObj.accessList).map(i => req.sessionObj.accessList[i]).filter(x => x.dbId).map(x => x.dbId), accessTo: ACCESS_TO.admin });
- const result = Security.setAdmin(req, !!(access?.length || 0));
- app.routerUtils.jsonResponse(res, result);
- });
- app.router.post("/api/accessAdmin/create", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!await req.sessionObj?.accessList?.isAdmin(app, req.sessionObj?.accessList) || !req.body)
- return app.routerUtils.onBadRequest(res);
- let access = new AccessModel();
- access.type = parseInt(req.body.typeId);
- access.typeData = req.body.typeData;
- access.typeLabel = req.body.typeLabel;
- access.accessTo = parseInt(req.body.accessToId);
- access.accessToData = req.body.accessToData;
- access.grant = parseInt(req.body.grant);
- try {
- await app.databaseHelper.insertOne(access);
- }
- catch (err) {
- console.error(err);
- return app.routerUtils.onBadRequest(res);
- }
- app.routerUtils.jsonResponse(res, accessToJson(access));
- });
- app.router.del("/api/accessAdmin/:id", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!await req.sessionObj?.accessList?.isAdmin(app, req.sessionObj?.accessList) || !req.params.id)
- return app.routerUtils.onBadRequest(res);
- app.databaseHelper.remove(AccessModel, { id: parseInt(req.params.id) });
- app.routerUtils.jsonResponse(res, {});
- });
- app.router.post("/api/accessAdmin/:id", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!await req.sessionObj?.accessList?.isAdmin(app, req.sessionObj?.accessList) || !req.params.id || !req.body)
- return app.routerUtils.onBadRequest(res);
- const access = (await app.databaseHelper.fetch(AccessModel, { id: parseInt(req.params.id) }))?.[0];
- if (!access)
- return app.routerUtils.onBadRequest(res);
- access.typeLabel = req.body.typeLabel;
- access.typeData = req.body.typeData;
- access.accessTo = parseInt(req.body.accessToId);
- access.accessToData = req.body.accessToData;
- access.grant = parseInt(req.body.grant);
- try {
- app.databaseHelper.upsertOne(access);
- }
- catch (err) {
- console.error(err);
- return app.routerUtils.onBadRequest(res);
- }
- app.routerUtils.jsonResponse(res, accessToJson(access));
- });
- app.router.get("/api/accessAdmin/list", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!await req.sessionObj?.accessList?.isAdmin(app, req.sessionObj?.accessList))
- return app.routerUtils.onBadRequest(res);
- app.routerUtils.jsonResponse(res, (await app.databaseHelper.fetch(AccessModel)).map(accessToJson));
- });
- app.router.post("/api/media/:id/tag/del/:tag", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!req.params.id ||!req.params.tag)
- return app.routerUtils.onBadRequest(res);
- let checksum = [ req.params.id ];
- if (req.params.id === "list") {
- if (!req.body?.['list[]'])
- return app.routerUtils.onBadRequest(res);
- checksum = req.body['list[]'];
- }
- let data = await MediaService.fetchMultiple(app, checksum, req.sessionObj?.accessList, 0);
- data = Object.keys(data).map(x => data[x]).filter(x => x.ACCESS_TYPE != ACCESS_GRANT.write);
- await Promise.all(data.map(x => MediaService.updateVersionInDb(app, x.fixedSum)));
- await app.databaseHelper.remove(MediaFileTagModel, { md5sum: data.map(x => x.fixedSum), tag: decodeURIComponent(req.params.tag), fromMeta: 0 });
- const allMedias = await MediaService.fetchMultiple(app, checksum, req.sessionObj?.accessList, 0);
- app.routerUtils.jsonResponse(res, Object.keys(allMedias).map(x => allMedias[x]).map(x => MediaToJson(x)));
- });
- app.router.put("/api/media/:id/tag", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- const requestedTag = req.body?.tag;
- if (!req.params.id ||!requestedTag)
- return app.routerUtils.onBadRequest(res);
- let checksum = [ req.params.id ];
- if (req.params.id === "list") {
- if (!req.body?.['list[]'])
- return app.routerUtils.onBadRequest(res);
- checksum = req.body['list[]'];
- }
- let data = await MediaService.fetchMultiple(app, checksum, req.sessionObj?.accessList, 0);
- data = Object.keys(data)
- .map(x => data[x])
- .filter(x => {
- if (x.ACCESS_TYPE != ACCESS_GRANT.write)
- return true;
- for (let existingTag of [...x.tags, ...x.fixedTags]) {
- if (existingTag === requestedTag || existingTag.startsWith(`${requestedTag}/`)) {
- return true;
- }
- }
- });
- await Promise.all(data.map(x => MediaService.updateVersionInDb(app, x.fixedSum)));
- let tag = data.map(x => new MediaFileTagModel(x.fixedSum, requestedTag, false));
- try {
- await app.databaseHelper.insertMultipleSameTable(tag);
- }
- catch (err) {
- console.error(err);
- return app.routerUtils.onBadRequest(res);
- }
- const allMedias = await MediaService.fetchMultiple(app, checksum, req.sessionObj?.accessList, 0);
- app.routerUtils.jsonResponse(res, Object.keys(allMedias).map(x => allMedias[x]).map(x => MediaToJson(x)));
- });
- app.router.patch("/api/media/:id/meta/:key", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- if (!req.params.id ||!req.params.key || !Number.isInteger(req.body?.value?.length))
- return app.routerUtils.onBadRequest(res);
- let checksum = [ req.params.id ];
- if (req.params.id === "list") {
- if (!req.body?.['list[]'])
- return app.routerUtils.onBadRequest(res);
- checksum = req.body['list[]'];
- }
- let data = await MediaService.fetchMultiple(app, checksum, req.sessionObj?.accessList, 0);
- data = Object.keys(data)
- .map(x => data[x])
- .filter(x => x.ACCESS_TYPE != ACCESS_GRANT.write);
- if (!(await MediaService.updateMeta(app, data.map(x => x.fixedSum), req.params.key, req.body.value)))
- return app.routerUtils.onBadRequest(res);
- const allMedias = await MediaService.fetchMultiple(app, checksum, req.sessionObj?.accessList, 0);
- app.routerUtils.jsonResponse(res, Object.keys(allMedias).map(x => allMedias[x]).map(x => MediaToJson(x)));
- });
- app.router.get("/api/media/list", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- let first = undefined,
- last = undefined,
- maxVersion = undefined;
- if (req.body?.chronology !== undefined) {
- let range = await MediaService.getMediaRange(app);
- first = range.min;
- last = range.max;
- maxVersion = range.maxVersion;
- }
- let fromDate = parseInt(req.body?.from);
- let count = parseInt(req.body?.count);
- app.routerUtils.jsonResponse(res, {
- data: (await MediaService.fetchMediasWithAccess(
- app,
- isNaN(fromDate) ? 0 : fromDate,
- isNaN(count) ? 25 : Math.min(350, count),
- req.sessionObj?.accessList,
- req.body?.version || 0)).map(MediaToJson),
- first: first,
- last: last,
- maxVersion: maxVersion
- });
- });
- app.router.get("/api/media/sumlist", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- app.routerUtils.jsonResponse(res, {
- data: await MediaService.fetchMediasSumWithAccess(
- app,
- req.sessionObj?.accessList)
- });
- });
- app.router.del("/api/media/:md5sum", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- let data = MediaToJson(await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList, 0));
- if (!data)
- return app.routerUtils.onPageNotFound(res);
- await MediaService.removeMedia(app, data);
- app.routerUtils.jsonResponse(res, {});
- });
- app.router.get("/api/media/:md5sum", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- let data = MediaToJson(await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList, 0));
- if (!data)
- return app.routerUtils.onPageNotFound(res);
- app.routerUtils.jsonResponse(res, data);
- });
- app.router.get("/api/media/thumbnail/:md5sum.jpg", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- let data = await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList, 0);
- if (!data)
- return app.routerUtils.onPageNotFound(res);
- try {
- let thumbnail = null;
- req.body = req.body || {};
- req.body.w = parseInt(req.body.w || 0);
- req.body.h = parseInt(req.body.h || 0);
- req.body.q = parseInt(req.body.q || 6);
- try {
- thumbnail = await (await app.libraryManager.findMedia(data.path))?.createThumbnail(req.body.w, req.body.h, req.body.q);
- } catch (err) {
- return app.routerUtils.apiError(res);
- }
- if (!thumbnail)
- return app.routerUtils.onPageNotFound(res);
- res.setHeader("Content-Type", "image/jpeg");
- res.setHeader("Content-Length", fs.statSync(thumbnail.name)?.size || undefined);
- res.setHeader("Cache-Control", "private, max-age=2630000"); // 1 month cache
- let rd = fs.createReadStream(thumbnail.name);
- rd.once('end', () => thumbnail.removeCallback());
- rd.pipe(res);
- }
- catch (err) {
- console.error(err);
- app.routerUtils.onPageNotFound(res);
- }
- });
- app.router.get("/api/media/original/:md5sum", async (req, res) => {
- app.routerUtils.onApiRequest(req, res);
- let data = await MediaService.fetchOne(app, req.params.md5sum, req.sessionObj?.accessList, 0);
- if (!data)
- return app.routerUtils.onPageNotFound(res);
- const fileName = Path.basename(data.path);
- res.setHeader("Cache-Control", "private, max-age=2630000"); // 1 month cache
- if (data.accessType === ACCESS_GRANT.readNoMeta || req.body?.trim !== undefined) {
- console.log("remove meta");//-> trim metadata
- }
- res.setHeader("Content-Disposition", `attachment; filename="${fileName}"`);
- res.setHeader("Content-Type", mime.lookup(data.path));
- res.setHeader("Content-Length", fs.statSync(data.path)?.size || undefined);
- fs.createReadStream(data.path).pipe(res);
- });
- }};
|