diff --git a/app/imports/api/creature/creatureProperties/methods/index.js b/app/imports/api/creature/creatureProperties/methods/index.js index 63e26999..72fe3da3 100644 --- a/app/imports/api/creature/creatureProperties/methods/index.js +++ b/app/imports/api/creature/creatureProperties/methods/index.js @@ -1,4 +1,4 @@ -import '//imports/api/creature/creatureProperties/methods/adjustQuantity.js'; +import '/imports/api/creature/creatureProperties/methods/adjustQuantity.js'; import '/imports/api/creature/creatureProperties/methods/damagePropertiesByName.js'; import '/imports/api/creature/creatureProperties/methods/damageProperty.js'; import '/imports/api/creature/creatureProperties/methods/dealDamage.js'; diff --git a/app/imports/api/library/LibraryNodes.js b/app/imports/api/library/LibraryNodes.js index a62c3c0e..eb9692fd 100644 --- a/app/imports/api/library/LibraryNodes.js +++ b/app/imports/api/library/LibraryNodes.js @@ -11,6 +11,7 @@ import { assertEditPermission } from '/imports/api/sharing/sharingPermissions.js import { softRemove } from '/imports/api/parenting/softRemove.js'; import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema.js'; import { storedIconsSchema } from '/imports/api/icons/Icons.js'; +import '/imports/api/library/methods/index.js'; let LibraryNodes = new Mongo.Collection('libraryNodes'); @@ -79,27 +80,6 @@ const insertNode = new ValidatedMethod({ }, }); -const duplicateNode = new ValidatedMethod({ - name: 'libraryNodes.duplicate', - validate: new SimpleSchema({ - _id: { - type: String, - regEx: SimpleSchema.RegEx.Id, - } - }).validator(), - mixins: [RateLimiterMixin], - rateLimit: { - numRequests: 5, - timeInterval: 5000, - }, - run({_id}) { - let libraryNode = LibraryNodes.findOne(_id); - assertNodeEditPermission(libraryNode, this.userId); - delete libraryNode._id; - return LibraryNodes.insert(libraryNode); - }, -}) - const updateLibraryNode = new ValidatedMethod({ name: 'libraryNodes.update', validate({_id, path}){ @@ -195,7 +175,6 @@ export default LibraryNodes; export { LibraryNodeSchema, insertNode, - duplicateNode, updateLibraryNode, pullFromLibraryNode, pushToLibraryNode, diff --git a/app/imports/api/library/methods/duplicateLibraryNode.js b/app/imports/api/library/methods/duplicateLibraryNode.js new file mode 100644 index 00000000..2fa6782e --- /dev/null +++ b/app/imports/api/library/methods/duplicateLibraryNode.js @@ -0,0 +1,85 @@ +import { ValidatedMethod } from 'meteor/mdg:validated-method'; +import SimpleSchema from 'simpl-schema'; +import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; +import LibraryNodes from '/imports/api/library/LibraryNodes.js'; +import { assertDocEditPermission } from '/imports/api/sharing/sharingPermissions.js'; +import { + setLineageOfDocs, + renewDocIds +} from '/imports/api/parenting/parenting.js'; +import { reorderDocs } from '/imports/api/parenting/order.js'; + +var snackbar; +if (Meteor.isClient){ + snackbar = require( + '/imports/ui/components/snackbars/SnackbarQueue.js' + ).snackbar +} + +const DUPLICATE_CHILDREN_LIMIT = 50; + +const duplicateLibraryNode = new ValidatedMethod({ + name: 'libraryNodes.duplicate', + validate: new SimpleSchema({ + _id: { + type: String, + regEx: SimpleSchema.RegEx.Id, + } + }).validator(), + mixins: [RateLimiterMixin], + rateLimit: { + numRequests: 5, + timeInterval: 5000, + }, + run({_id}) { + let libraryNode = LibraryNodes.findOne(_id); + assertDocEditPermission(libraryNode, this.userId); + let libraryNodeId = Random.id(); + libraryNode._id = libraryNodeId; + + let nodes = LibraryNodes.find({ + 'ancestors.id': _id, + removed: {$ne: true}, + }, { + limit: DUPLICATE_CHILDREN_LIMIT + 1, + sort: {order: 1}, + }).fetch(); + + if (nodes.length > DUPLICATE_CHILDREN_LIMIT){ + nodes.pop(); + if (Meteor.isClient){ + snackbar({ + text: `Only the first ${DUPLICATE_CHILDREN_LIMIT} children were duplicated`, + }); + } + } + + // re-map all the ancestors + setLineageOfDocs({ + docArray: nodes, + newAncestry : [ + ...libraryNode.ancestors, + {id: libraryNodeId, collection: 'libraryNodes'} + ], + oldParent : {id: _id, collection: 'libraryNodes'}, + }); + + // Give the docs new IDs without breaking internal references + renewDocIds({docArray: nodes}); + + // Order the root node + libraryNode.order += 0.5; + + LibraryNodes.batchInsert([libraryNode, ...nodes]); + + // Tree structure changed by inserts, reorder the tree + reorderDocs({ + collection: LibraryNodes, + ancestorId: libraryNode.ancestors[0].id, + }); + + return libraryNodeId; + }, +}); + +export default duplicateLibraryNode; diff --git a/app/imports/api/library/methods/index.js b/app/imports/api/library/methods/index.js new file mode 100644 index 00000000..771eba44 --- /dev/null +++ b/app/imports/api/library/methods/index.js @@ -0,0 +1 @@ +import '/imports/api/library/methods/duplicateLibraryNode.js';