Home Reference Source

cables_dev/cables_electron/src/utils/ops_util.js

  1. import { utilProvider, SharedOpsUtil } from "cables-shared-api";
  2. import path from "path";
  3. import mkdirp from "mkdirp";
  4. import fs from "fs";
  5. import projectsUtil from "./projects_util.js";
  6. import filesUtil from "./files_util.js";
  7. class OpsUtil extends SharedOpsUtil
  8. {
  9. constructor(provider)
  10. {
  11. super(provider);
  12. this.PREFIX_LOCAL_OPS = "Ops.Local.";
  13. }
  14. validateAndFormatOpCode(code)
  15. {
  16. return {
  17. "formatedCode": this._helperUtil.removeTrailingSpaces(code),
  18. "error": false,
  19. "message": null
  20. };
  21. }
  22. isLocalOp(opName)
  23. {
  24. if (!opName) return false;
  25. return opName.startsWith(this.PREFIX_LOCAL_OPS);
  26. }
  27. isCoreOp(opName)
  28. {
  29. if (!opName || this.isLocalOp(opName)) return false;
  30. const opsDir = this._cables.getCoreOpsPath();
  31. const opDir = this.getOpSourceDir(opName);
  32. return opDir.startsWith(opsDir);
  33. }
  34. addPermissionsToOps(opDocs, user, teams = [], project = null)
  35. {
  36. if (!opDocs) return opDocs;
  37. opDocs.forEach((opDoc) =>
  38. {
  39. const file = this.getOpAbsoluteFileName(opDoc.name);
  40. opDoc.allowEdit = true;
  41. if (file)
  42. {
  43. try
  44. {
  45. fs.accessSync(file, fs.constants.R_OK | fs.constants.W_OK);
  46. opDoc.allowEdit = true;
  47. }
  48. catch (e)
  49. {
  50. // not allowed to read/write
  51. opDoc.allowEdit = false;
  52. }
  53. }
  54. });
  55. return opDocs;
  56. }
  57. userHasWriteRightsOp(user, opName, teams = [], project = null, ignoreAdmin = false)
  58. {
  59. if (!user) return false;
  60. if (!opName) return false;
  61. if (!opName.startsWith(this.PREFIX_OPS)) return false;
  62. if (opName.indexOf("..") > -1) return false;
  63. if (opName.indexOf(" ") > -1) return false;
  64. if (opName.startsWith(".")) return false;
  65. if (opName.endsWith(".")) return false;
  66. const validName = this.isOpNameValid(opName);
  67. if (!validName) return false;
  68. const file = this.getOpAbsoluteFileName(opName);
  69. if (file)
  70. {
  71. if (fs.existsSync(file))
  72. {
  73. try
  74. {
  75. fs.accessSync(file, fs.constants.R_OK | fs.constants.W_OK);
  76. return true;
  77. }
  78. catch (e)
  79. {
  80. // not allowed to read/write
  81. return false;
  82. }
  83. }
  84. else if (this._cables.inPackage(file))
  85. {
  86. return false;
  87. }
  88. else
  89. {
  90. return true;
  91. }
  92. }
  93. return true;
  94. }
  95. getOpAbsolutePath(opName)
  96. {
  97. return projectsUtil.getAbsoluteOpDirFromHierarchy(opName);
  98. }
  99. getOpSourceDir(opName, relative = false)
  100. {
  101. if (!opName) return null;
  102. if (relative) return super.getOpSourceDir(opName, relative);
  103. return projectsUtil.getAbsoluteOpDirFromHierarchy(opName);
  104. }
  105. getOpTargetDir(opName, relative = false)
  106. {
  107. let targetDir = "";
  108. if (relative)
  109. {
  110. if (opName.endsWith(".")) opName = opName.substring(0, opName.length - 1);
  111. return path.join(opName, "/");
  112. }
  113. else
  114. {
  115. targetDir = projectsUtil.getAbsoluteOpDirFromHierarchy(opName);
  116. }
  117. return targetDir;
  118. }
  119. getOpSourceNoHierarchy(opName, relative = false)
  120. {
  121. return super.getOpSourceDir(opName, relative);
  122. }
  123. getOpRenameConsequences(newName, oldName, targetDir = null)
  124. {
  125. return [];
  126. }
  127. /**
  128. * @typedef {Object} OpRenameProblems
  129. * @property {String} [source_does_not_exist]
  130. * @property {String} [overruled_by_other_op]
  131. * @property {String} [namespace_empty]
  132. * @property {String} [patch_op_illegal_namespace]
  133. * @property {String} [name_ends_with_dot]
  134. * @property {String} [name_ends_with_underscore]
  135. * @property {String} [name_not_op_namespace]
  136. * @property {String} [target_exists]
  137. * @property {String} [name_taken]
  138. * @property {String} [name_too_short]
  139. * @property {String} [name_contains_doubledot]
  140. * @property {String} [name_contains_illegal_characters]
  141. * @property {String} [patch_op_rename_illegal]
  142. * @property {String} [namespace_starts_with_numbers]
  143. * @property {String} [namespace_starts_with_whitespace]
  144. * @property {String} [namespace_starts_with_dash]
  145. * @property {String} [namespace_not_uppercase]
  146. * @property {String} [op_used_elsewhere]
  147. * @property {String} [no_rights_target]
  148. * @property {String} [no_rights_source]
  149. * @property {String} [not_found_source]
  150. * @property {String} [bad_op_hierarchy]
  151. * @property {String} [overruled_by_other_op]
  152. * @property {String} [illegal_ops]
  153. * @property {String} [version_suggestion]
  154. */
  155. /**
  156. * @returns {OpRenameProblems}
  157. */
  158. getOpRenameProblems(newName, oldName, userObj, teams = [], newOpProject = null, oldOpProject = null, opUsages = [], checkUsages = true, targetDir = null)
  159. {
  160. const problems = super.getOpRenameProblems(newName, oldName, userObj, teams, newOpProject, oldOpProject, opUsages, checkUsages);
  161. if (problems.no_rights_target && targetDir)
  162. {
  163. if (fs.existsSync(targetDir))
  164. {
  165. try
  166. {
  167. fs.accessSync(targetDir, fs.constants.R_OK | fs.constants.W_OK);
  168. delete problems.no_rights_target;
  169. }
  170. catch (e)
  171. {
  172. // not allowed to read/write
  173. }
  174. }
  175. else
  176. {
  177. try
  178. {
  179. mkdirp.sync(targetDir);
  180. delete problems.no_rights_target;
  181. }
  182. catch (e)
  183. {
  184. // not allowed to create targetDir
  185. }
  186. }
  187. }
  188. if (problems.target_exists && targetDir)
  189. {
  190. const newOpDir = path.join(targetDir, this.getOpTargetDir(newName, true), this.getOpFileName(newName));
  191. if (!fs.existsSync(newOpDir))
  192. {
  193. delete problems.target_exists;
  194. const existingOpDir = this.getOpSourceDir(newName);
  195. problems.overruled_by_other_op = "The new Op would conflict with the Op at:<br/> <a onclick=\"CABLESUILOADER.talkerAPI.send('openDir', { 'dir': '" + existingOpDir + "'});\">" + existingOpDir + "</a>";
  196. }
  197. }
  198. return problems;
  199. }
  200. getOpAssetPorts(op, includeLibraryAssets = false)
  201. {
  202. const assetPorts = [];
  203. if (!op) return assetPorts;
  204. if (!op.portsIn) return assetPorts;
  205. for (let i = 0; i < op.portsIn.length; i++)
  206. {
  207. const port = op.portsIn[i];
  208. if (
  209. port.value &&
  210. typeof port.value == "string" &&
  211. port.name &&
  212. port.value.length &&
  213. (port.display === "file" ||
  214. port.name.toLowerCase().indexOf("file") > -1 ||
  215. port.name.toLowerCase().indexOf("url") > -1 ||
  216. // port names in cubemapfromtextures !
  217. port.name.toLowerCase().indexOf("posx") > -1 ||
  218. port.name.toLowerCase().indexOf("posy") > -1 ||
  219. port.name.toLowerCase().indexOf("posz") > -1 ||
  220. port.name.toLowerCase().indexOf("negx") > -1 ||
  221. port.name.toLowerCase().indexOf("negy") > -1 ||
  222. port.name.toLowerCase().indexOf("negz") > -1)
  223. )
  224. {
  225. if (!port.value.toLowerCase().startsWith("/assets/library"))
  226. {
  227. assetPorts.push(port);
  228. }
  229. else if (includeLibraryAssets)
  230. {
  231. assetPorts.push(port);
  232. }
  233. }
  234. }
  235. return assetPorts;
  236. }
  237. getOpNameByAbsoluteFileName(fileName)
  238. {
  239. if (!fileName) return "";
  240. const parts = path.parse(fileName);
  241. if (parts && parts.name) return parts.name;
  242. return "";
  243. }
  244. updateOpCode(opName, author, code)
  245. {
  246. filesUtil.unregisterOpChangeListeners([opName]);
  247. const newCode = super.updateOpCode(opName, author, code);
  248. setTimeout(() =>
  249. {
  250. filesUtil.registerOpChangeListeners([opName]);
  251. }, 1000);
  252. return newCode;
  253. }
  254. getOpNpmPackages(opName)
  255. {
  256. let toInstall = [];
  257. const opDoc = this._docsUtil.getDocForOp(opName);
  258. if (opDoc && opDoc.hasOwnProperty("dependencies"))
  259. {
  260. const npmDeps = opDoc.dependencies.filter((dep) => { return dep.type === "npm"; });
  261. npmDeps.forEach((npmDep) =>
  262. {
  263. if (npmDep.src)
  264. {
  265. if (!toInstall.includes(npmDep.src))
  266. {
  267. toInstall.push(npmDep.src);
  268. }
  269. }
  270. });
  271. }
  272. return toInstall;
  273. }
  274. renameToCoreOp(oldName, newName, currentUser, cb = null)
  275. {
  276. let oldOpDir = this.getOpSourceDir(oldName);
  277. let newOpDir = oldOpDir.replace(oldName, newName);
  278. return this._renameOp(oldName, newName, currentUser, true, true, false, oldOpDir, newOpDir, cb);
  279. }
  280. renameToExtensionOp(oldName, newName, currentUser, cb = null)
  281. {
  282. let oldOpDir = this.getOpSourceDir(oldName);
  283. let newOpDir = oldOpDir.replace(oldName, newName);
  284. return this._renameOp(oldName, newName, currentUser, true, true, false, oldOpDir, newOpDir, cb);
  285. }
  286. renameToTeamOp(oldName, newName, currentUser, cb = null)
  287. {
  288. let oldOpDir = this.getOpSourceDir(oldName);
  289. let newOpDir = oldOpDir.replace(oldName, newName);
  290. return this._renameOp(oldName, newName, currentUser, false, true, false, oldOpDir, newOpDir, cb);
  291. }
  292. renameToUserOp(oldName, newName, currentUser, cb = null)
  293. {
  294. let oldOpDir = this.getOpSourceDir(oldName);
  295. let newOpDir = oldOpDir.replace(oldName, newName);
  296. return this._renameOp(oldName, newName, currentUser, false, true, false, oldOpDir, newOpDir, cb);
  297. }
  298. renameToPatchOp(oldName, newName, currentUser, removeOld, newId, cb = null)
  299. {
  300. let oldOpDir = this.getOpSourceDir(oldName);
  301. let newOpDir = oldOpDir.replace(oldName, newName);
  302. return this._renameOp(oldName, newName, currentUser, false, removeOld, newId, oldOpDir, newOpDir, cb);
  303. }
  304. getPatchOpNamespace(opName)
  305. {
  306. return this.getNamespace(opName);
  307. }
  308. getPatchOpsNamespaceForProject(proj)
  309. {
  310. return this.PREFIX_LOCAL_OPS;
  311. }
  312. userHasReadRightsOp(user, opName, teams = null, project = null, opOwner = null)
  313. {
  314. return true;
  315. }
  316. getCollectionName(opName)
  317. {
  318. if (!opName) return null;
  319. if (opName.startsWith(this.PREFIX_LOCAL_OPS)) return this.PREFIX_LOCAL_OPS;
  320. return super.getCollectionName(opName);
  321. }
  322. }
  323. export default new OpsUtil(utilProvider);