import SimpleSchema from 'simpl-schema'; import { assertOwnership } from '/imports/api/sharing/sharingPermissions.js'; import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js'; import getCollectionByName from '/imports/api/parenting/getCollectionByName.js'; import { RefSchema } from '/imports/api/parenting/ChildSchema.js'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import { getUserTier } from '/imports/api/users/patreon/tiers.js'; const setPublic = new ValidatedMethod({ name: 'sharing.setPublic', validate: new SimpleSchema({ docRef: RefSchema, isPublic: { type: Boolean }, }).validator(), mixins: [RateLimiterMixin], rateLimit: { numRequests: 5, timeInterval: 5000, }, run({ docRef, isPublic }) { let doc = fetchDocByRef(docRef); assertOwnership(doc, this.userId); return getCollectionByName(docRef.collection).update(docRef.id, { $set: { public: isPublic }, }); }, }); const setReadersCanCopy = new ValidatedMethod({ name: 'sharing.setReadersCanCopy', validate: new SimpleSchema({ docRef: RefSchema, readersCanCopy: { type: Boolean }, }).validator(), mixins: [RateLimiterMixin], rateLimit: { numRequests: 5, timeInterval: 5000, }, run({ docRef, readersCanCopy }) { let doc = fetchDocByRef(docRef); assertOwnership(doc, this.userId); return getCollectionByName(docRef.collection).update(docRef.id, { $set: { readersCanCopy }, }); }, }); const updateUserSharePermissions = new ValidatedMethod({ name: 'sharing.updateUserSharePermissions', validate: new SimpleSchema({ docRef: RefSchema, userId: { type: String, regEx: SimpleSchema.RegEx.Id, }, role: { type: String, allowedValues: ['reader', 'writer', 'none'], }, }).validator(), mixins: [RateLimiterMixin], rateLimit: { numRequests: 5, timeInterval: 5000, }, run({ docRef, userId, role }) { let doc = fetchDocByRef(docRef); if (role === 'none') { // only assert ownership if you aren't removing yourself if (this.userId !== userId) { assertOwnership(doc, this.userId); } return getCollectionByName(docRef.collection).update(docRef.id, { $pullAll: { readers: userId, writers: userId }, }); } if (doc.owner === userId) { throw new Meteor.Error('Sharing update failed', 'User is already the owner of this document'); } assertOwnership(doc, this.userId); if (role === 'reader') { return getCollectionByName(docRef.collection).update(docRef.id, { $addToSet: { readers: userId }, $pullAll: { writers: userId }, }); } else if (role === 'writer') { return getCollectionByName(docRef.collection).update(docRef.id, { $addToSet: { writers: userId }, $pullAll: { readers: userId }, }); } }, }); const transferOwnership = new ValidatedMethod({ name: 'sharing.transferOwnership', validate: new SimpleSchema({ docRef: RefSchema, userId: { type: String, regEx: SimpleSchema.RegEx.Id, }, }).validator(), mixins: [RateLimiterMixin], rateLimit: { numRequests: 5, timeInterval: 5000, }, run({ docRef, userId }) { let doc = fetchDocByRef(docRef); assertOwnership(doc, this.userId); let collection = getCollectionByName(docRef.collection); let tier = getUserTier(userId); if (docRef.collection === 'creatures') { let currentCharacterCount = collection.find({ owner: userId, }, { fields: { _id: 1 }, }).count(); if ( tier.characterSlots !== -1 && currentCharacterCount >= tier.characterSlots ) { throw new Meteor.Error('Sharing.methods.transferOwnership.denied', 'The new owner is already at their character limit') } } else if (docRef.collection === 'libraries') { if (!tier.paidBenefits) { throw new Meteor.Error('Sharing.methods.transferOwnership.denied', 'The new owner\'s Patreon tier does not have access to library ownership'); } } // First remove current permissions for the user collection.update(docRef.id, { $pullAll: { writers: userId, readers: userId }, }); // Then make the user the owner and the current owner a writer return collection.update(docRef.id, { $set: { owner: userId }, $addToSet: { writers: this.userId }, }); }, }); export { setPublic, setReadersCanCopy, updateUserSharePermissions, transferOwnership };