Merge feature-nested-sets into develop
This commit is contained in:
@@ -3,60 +3,17 @@ import { Mongo } from 'meteor/mongo';
|
||||
import { ValidatedMethod } from 'meteor/mdg:validated-method';
|
||||
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
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';
|
||||
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
|
||||
import { restore } from '/imports/api/parenting/softRemove.js';
|
||||
import { getAncestry, updateParent } from '/imports/api/parenting/parenting.js';
|
||||
import { nodeArrayToTree } from '/imports/api/parenting/nodesToTree';
|
||||
import { getDocsInDepthFirstOrder } from '/imports/api/parenting/getDescendantsInDepthFirstOrder';
|
||||
import { softRemove } from '/imports/api/parenting/softRemove';
|
||||
import SoftRemovableSchema from '/imports/api/parenting/SoftRemovableSchema';
|
||||
import { storedIconsSchema } from '/imports/api/icons/Icons';
|
||||
import '/imports/api/library/methods/index';
|
||||
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS';
|
||||
import { restore } from '/imports/api/parenting/softRemove';
|
||||
import { getFilter, rebuildNestedSets, changeParent } from '/imports/api/parenting/parentingFunctions';
|
||||
import ChildSchema from '/imports/api/parenting/ChildSchema';
|
||||
|
||||
const Docs = new Mongo.Collection('docs');
|
||||
|
||||
const RefSchema = new SimpleSchema({
|
||||
id: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
index: 1
|
||||
},
|
||||
collection: {
|
||||
type: String,
|
||||
max: STORAGE_LIMITS.collectionName,
|
||||
},
|
||||
urlName: {
|
||||
type: String,
|
||||
regEx: /[a-z]+(?:[a-z]|-)+/,
|
||||
min: 2,
|
||||
max: STORAGE_LIMITS.variableName,
|
||||
optional: true,
|
||||
},
|
||||
name: {
|
||||
type: String,
|
||||
max: STORAGE_LIMITS.description,
|
||||
optional: true,
|
||||
},
|
||||
});
|
||||
|
||||
let ChildSchema = new SimpleSchema({
|
||||
order: {
|
||||
type: Number,
|
||||
},
|
||||
parent: {
|
||||
type: RefSchema,
|
||||
optional: true,
|
||||
},
|
||||
ancestors: {
|
||||
type: Array,
|
||||
defaultValue: [],
|
||||
maxCount: STORAGE_LIMITS.ancestorCount,
|
||||
},
|
||||
'ancestors.$': {
|
||||
type: RefSchema,
|
||||
},
|
||||
});
|
||||
|
||||
let DocSchema = new SimpleSchema({
|
||||
_id: {
|
||||
type: String,
|
||||
@@ -106,38 +63,14 @@ function assertDocsEditPermission(userId) {
|
||||
function getDocLink(doc, urlName) {
|
||||
if (!urlName) urlName = doc.urlName;
|
||||
const address = ['/docs'];
|
||||
doc.ancestors?.forEach(a => {
|
||||
const ancestorDocs = Docs.find(getFilter.ancestors(doc));
|
||||
ancestorDocs?.forEach(a => {
|
||||
address.push(a.urlName);
|
||||
});
|
||||
address.push(urlName);
|
||||
return address.join('/');
|
||||
}
|
||||
|
||||
function rebuildDocAncestors(docId) {
|
||||
const newDoc = Docs.findOne(docId);
|
||||
Docs.find({ 'ancestors.id': docId }).forEach(doc => {
|
||||
doc.ancestors.forEach((a, i) => {
|
||||
if (a.id === docId) {
|
||||
Docs.update(doc._id, {
|
||||
$set: {
|
||||
[`ancestors.${i}`]: {
|
||||
id: newDoc._id,
|
||||
collection: 'docs',
|
||||
urlName: newDoc.urlName,
|
||||
name: newDoc.name,
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
doc = Docs.findOne(doc._id);
|
||||
const newLink = getDocLink(doc);
|
||||
if (doc.href !== newLink) {
|
||||
Docs.update(doc._id, { $set: { href: newLink } })
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add a means of seeding new servers with documentation
|
||||
if (Meteor.isClient) {
|
||||
Docs.getJsonDocs = function () {
|
||||
@@ -162,18 +95,11 @@ const insertDoc = new ValidatedMethod({
|
||||
numRequests: 5,
|
||||
timeInterval: 5000,
|
||||
},
|
||||
run({ doc, parentRef }) {
|
||||
run({ doc, parentId }) {
|
||||
delete doc._id;
|
||||
assertDocsEditPermission(this.userId);
|
||||
// get the new ancestry for the properties
|
||||
if (parentRef) {
|
||||
var { ancestors } = getAncestry({
|
||||
parentRef,
|
||||
inheritedFields: { name: 1, urlName: 1 },
|
||||
});
|
||||
}
|
||||
doc.parent = parentRef;
|
||||
doc.ancestors = ancestors;
|
||||
|
||||
doc.parentId = parentId;
|
||||
|
||||
const lastOrder = Docs.find({}, { sort: { order: -1 } }).fetch()[0]?.order || 0;
|
||||
doc.order = lastOrder + 1;
|
||||
@@ -185,7 +111,7 @@ const insertDoc = new ValidatedMethod({
|
||||
}
|
||||
|
||||
const docId = Docs.insert(doc);
|
||||
reorderDocs();
|
||||
rebuildNestedSets(Docs);
|
||||
return docId;
|
||||
},
|
||||
});
|
||||
@@ -223,13 +149,9 @@ const updateDoc = new ValidatedMethod({
|
||||
}
|
||||
modifier.$set = modifier.$set || {};
|
||||
modifier.$set.href = newLink;
|
||||
rebuildDocAncestors(_id);
|
||||
}
|
||||
const updates = Docs.update(_id, modifier);
|
||||
if (pathString === 'name' || pathString === 'urlName') {
|
||||
rebuildDocAncestors(_id);
|
||||
}
|
||||
reorderDocs();
|
||||
rebuildNestedSets(Docs);
|
||||
return updates;
|
||||
},
|
||||
});
|
||||
@@ -279,7 +201,7 @@ const softRemoveDoc = new ValidatedMethod({
|
||||
run({ _id }) {
|
||||
assertDocsEditPermission(this.userId);
|
||||
softRemove({ _id, collection: Docs });
|
||||
reorderDocs();
|
||||
rebuildNestedSets(Docs);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -295,8 +217,8 @@ const restoreDoc = new ValidatedMethod({
|
||||
},
|
||||
run({ _id }) {
|
||||
assertDocsEditPermission(this.userId);
|
||||
restore({ _id, collection: Docs });
|
||||
reorderDocs();
|
||||
restore('docs', _id);
|
||||
rebuildNestedSets(Docs);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -316,17 +238,18 @@ const organizeDoc = new ValidatedMethod({
|
||||
timeInterval: 5000,
|
||||
},
|
||||
run({ docId, parentId, order }) {
|
||||
let doc = Docs.findOne(docId);
|
||||
const doc = Docs.findOne(docId);
|
||||
const parent = Docs.findOne(parentId);
|
||||
// The user must be able to edit both the doc and its parent to move it
|
||||
// successfully
|
||||
assertDocsEditPermission(this.userId);
|
||||
|
||||
// Change the doc's parent
|
||||
updateParent({ docRef: { id: docId, collection: 'docs' }, parentRef: { id: parentId, collection: 'docs' } });
|
||||
changeParent(doc, parent, Docs);
|
||||
// Change the doc's order to be a half step ahead of its target location
|
||||
Docs.update(doc._id, { $set: { order } });
|
||||
|
||||
reorderDocs();
|
||||
rebuildNestedSets(Docs);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -349,52 +272,10 @@ const reorderDoc = new ValidatedMethod({
|
||||
Docs.update(docId, {
|
||||
$set: { order }
|
||||
});
|
||||
reorderDocs();
|
||||
rebuildNestedSets(Docs);
|
||||
},
|
||||
});
|
||||
|
||||
function reorderDocs() {
|
||||
const docs = Docs.find({ removed: { $ne: true } }, { sort: { order: 1 } }).fetch();
|
||||
const forest = nodeArrayToTree(docs);
|
||||
const orderedDocs = getDocsInDepthFirstOrder(forest);
|
||||
const bulkWrite = [];
|
||||
orderedDocs.forEach((doc, index) => {
|
||||
if (doc.order !== index) {
|
||||
bulkWrite.push({
|
||||
updateOne: {
|
||||
filter: { _id: doc._id },
|
||||
update: { $set: { order: index } },
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
if (Meteor.isServer && bulkWrite.length) {
|
||||
Docs.rawCollection().bulkWrite(
|
||||
bulkWrite,
|
||||
{ ordered: false },
|
||||
function (e) {
|
||||
if (e) {
|
||||
console.error('Bulk write failed: ');
|
||||
console.error(e);
|
||||
}
|
||||
// Rebuild the ancestors of all the docs
|
||||
// This is a pretty slow way to do anything, but docs hardly ever get rearranged
|
||||
docs.forEach(doc => {
|
||||
rebuildDocAncestors(doc._id);
|
||||
});
|
||||
}
|
||||
);
|
||||
} else {
|
||||
bulkWrite.forEach(op => {
|
||||
Docs.update(
|
||||
op.updateOne.filter,
|
||||
op.updateOne.update,
|
||||
{ selector: { type: 'any' } }
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
DocSchema,
|
||||
insertDoc,
|
||||
|
||||
Reference in New Issue
Block a user