1
0

mediaService.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. const path = require('path');
  2. const fs = require('fs');
  3. const { AccessModel, ACCESS_TYPE, ACCESS_TO, ACCESS_GRANT } = require('./access.js');
  4. function Media()
  5. {
  6. }
  7. function MediaStruct(i) {
  8. this.path = i.path;
  9. this.fileName = path.parse(i.path).name;
  10. this.md5sum = i.md5sum;
  11. this.date = i.date;
  12. this.meta = {};
  13. this.tags = [];
  14. this.fixedTags = [];
  15. this.accessType = -1;
  16. }
  17. MediaStruct.prototype.pushMeta = function(key, value) {
  18. if (key && value && !this.meta[key]) {
  19. let type = '';
  20. let roTypes = [
  21. 'photochamberImport', 'height', 'width', 'iso', 'focal',
  22. 'fNumber', 'exposureTime', 'camera', 'lensModel',
  23. 'exposureTimeStr', 'libraryPath', 'compression',
  24. 'software', 'fileSize', 'geoHash'
  25. ];
  26. if (['photochamberImport', 'dateTime'].indexOf(key) >= 0)
  27. type = 'date';
  28. else if (['height', 'width', 'iso', 'focal', 'fNumber', 'exposureTime'].indexOf(key) >= 0)
  29. type = 'number';
  30. else if (['geoHash', 'gpsLocation'].indexOf(key) >= 0)
  31. type = 'geoData';
  32. else if (['artist', 'camera', 'lensModel', 'exposureTimeStr', 'libraryPath', 'compression',
  33. 'software', 'geoCountry'].indexOf(key) >= 0)
  34. type = 'string';
  35. else if (['fileSize'].indexOf(key) >= 0)
  36. type = 'octet';
  37. else console.log(`Unknown meta type ${key} (${value})`);
  38. this.meta[key] = {
  39. type: type,
  40. canWrite: roTypes.indexOf(key) === -1,
  41. value: value
  42. };
  43. }
  44. }
  45. MediaStruct.prototype.pushTag = function(tag, isFixedTag) {
  46. if (!tag)
  47. return;
  48. if (!isFixedTag && this.tags.indexOf(tag) === -1)
  49. this.tags.push(tag);
  50. if (isFixedTag && this.fixedTags.indexOf(tag) === -1)
  51. this.fixedTags.push(tag);
  52. }
  53. MediaStruct.prototype.computeAccess = function(accessList) {
  54. if (this.accessType > -1)
  55. return this.accessType;
  56. if (!fs.existsSync(this.path))
  57. return this.accessType = ACCESS_GRANT.none;
  58. const checkTag = function(tags, access) {
  59. if (!tags.length)
  60. return false;
  61. for (let i of tags)
  62. if (i.startsWith(access.accessToData+'/') || i === access.accessToData)
  63. return true;
  64. return false;
  65. }
  66. const checkMeta = function(metas, access) {
  67. if (!access.accessToDataDeserialized)
  68. return false;
  69. let metaKey = Object.keys(access.accessToDataDeserialized)[0];
  70. let meta = metas[metaKey]?.value;
  71. return meta && metaKey && meta == access.accessToDataDeserialized[metaKey];
  72. }
  73. this.accessType = ACCESS_GRANT.none;
  74. for (let i of accessList) {
  75. if (i.accessTo === ACCESS_TO.everything ||
  76. (i.accessTo === ACCESS_TO.item && i.accessToData === this.md5sum) ||
  77. (i.accessTo === ACCESS_TO.meta && checkMeta(this.meta, i)) ||
  78. (i.accessTo === ACCESS_TO.tag && checkTag([].concat(this.fixedTags, this.tags), i))) {
  79. if (i.grant === ACCESS_GRANT.write)
  80. return this.accessType = ACCESS_GRANT.write;
  81. this.accessType = ACCESS_GRANT.read;
  82. }
  83. }
  84. return this.accessType;
  85. }
  86. MediaStruct.prototype.HaveAccess = function(accessList) {
  87. return this.computeAccess(accessList) > 0;
  88. }
  89. async function buildAccessList(app, accessIds) {
  90. accessIds = Object.keys(accessIds || {}).reduce((acc, i) => {
  91. accessIds[i].linkId && acc.links.push(accessIds[i].linkId);
  92. accessIds[i].ldapDn && acc.ldap.push(accessIds[i].ldapDn);
  93. accessIds[i].email && acc.emails.push(accessIds[i].email);
  94. return acc;
  95. }, {links:[], emails: [], ldap: []});
  96. accessIds.accData = [].concat(accessIds.ldap, accessIds.emails, accessIds.links);
  97. accessIds.links = accessIds.links.map(x => '?').join(',');
  98. accessIds.emails = accessIds.emails.map(x => '?').join(',');
  99. accessIds.ldap = accessIds.ldap.map(x => '?').join(',');
  100. let accessList = (await app.databaseHelper.runSql(`select * from access where (
  101. (type=${ACCESS_TYPE.ldapAccount} AND typeData in (${accessIds.ldap})) OR
  102. (type=${ACCESS_TYPE.email} AND typeData in (${accessIds.emails})) OR
  103. (type=${ACCESS_TYPE.link} AND typeData in (${accessIds.links})) OR
  104. type=${ACCESS_TYPE.everyOne}
  105. )`, accessIds.accData)).map(data => {
  106. let result = new AccessModel;
  107. result.fromDb(data);
  108. return result;
  109. });
  110. return accessList || [];
  111. }
  112. function reduceReqToMediaStruct(acc, i) {
  113. let obj = acc[i.md5sum] = acc[i.md5sum] || new MediaStruct(i);
  114. obj.pushMeta(i.metaKey, i.metaValue);
  115. obj.pushTag(i.mediaTag, i.isFixedTag);
  116. return acc;
  117. }
  118. module.exports.fetchOne = async function(app, md5sum, accessList) {
  119. let result = ((await app.databaseHelper.runSql(`
  120. select mediaFile.path, mediaFile.md5sum, mediaFile.date,
  121. mediaMeta.key as metaKey, mediaMeta.value as metaValue,
  122. mediaTag.tag as mediaTag, mediaTag.fromMeta as isFixedTag
  123. from mediaFile
  124. left join mediaMeta on mediaMeta.md5sum=mediaFile.md5sum
  125. left join mediaTag on mediaTag.md5sum=mediaFile.md5sum
  126. where mediaFile.md5sum=?`, md5sum)) || []).reduce(reduceReqToMediaStruct, {})[md5sum] || null;
  127. accessList = await buildAccessList(app, accessList);
  128. return result?.HaveAccess(accessList) ? result : null;
  129. }
  130. module.exports.fetchMedias = async function(app, startTs, count) {
  131. let result = ((await app.databaseHelper.runSql(`
  132. select mediaFile.path, mediaFile.md5sum, mediaFile.date,
  133. mediaMeta.key as metaKey, mediaMeta.value as metaValue,
  134. mediaTag.tag as mediaTag, mediaTag.fromMeta as isFixedTag
  135. from mediaFile
  136. left join mediaMeta on mediaMeta.md5sum=mediaFile.md5sum
  137. left join mediaTag on mediaTag.md5sum=mediaFile.md5sum
  138. where mediaFile.md5sum in
  139. (select md5sum from mediaFile `
  140. +(startTs ? "where date <? " : "")
  141. +"order by date desc limit ?)", startTs ? [startTs, count] : [count])) || [])
  142. .reduce(reduceReqToMediaStruct, {});
  143. result = Object.keys(result).map(i => result[i]).sort((a, b) => b.date-a.date);
  144. return result;
  145. };
  146. module.exports.fetchMediasWithAccess = async function(app, startTs, count, access) {
  147. let result = [];
  148. let lastTs = startTs;
  149. access = await buildAccessList(app, access);
  150. while (result.length < count) {
  151. let tmp = await module.exports.fetchMedias(app, lastTs, 25);
  152. if (!tmp.length)
  153. return result;
  154. lastTs = tmp[tmp.length-1].date;
  155. tmp = tmp.filter(i => i.HaveAccess(access));
  156. if (tmp.length)
  157. result = result.concat(tmp);
  158. }
  159. return result.slice(0, count);
  160. };
  161. module.exports.getMediaRange = async function(app) {
  162. let result = await app.databaseHelper.runSql("select min(date) as _min, max(date) as _max from mediaFile");
  163. return [ result?.[0]?._min || 0, result?.[0]?._max || 0 ];
  164. }