diff --git a/app/imports/api/sharing/sharing.js b/app/imports/api/sharing/sharing.js index d48bfd23..5c63c275 100644 --- a/app/imports/api/sharing/sharing.js +++ b/app/imports/api/sharing/sharing.js @@ -3,18 +3,64 @@ 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'; const setPublic = new ValidatedMethod({ name: 'sharing.methods.setPublic', validate: new SimpleSchema({ docRef: RefSchema, - public: { type: Boolean }, + isPublic: { type: Boolean }, }).validator(), - run({docRef, public}){ + run({docRef, isPublic}){ let doc = fetchDocByRef(docRef); assertOwnership(doc, this.userId); - getCollectionByName(docRef.collection).update(docRef.id, {$set: {public}}); + return getCollectionByName(docRef.collection).update(docRef.id, { + $set: {public: isPublic}, + }); }, }); -export { setPublic }; +const updateUserSharePermissions = new ValidatedMethod({ + name: 'sharing.methods.updateUserSharePermissions', + validate: new SimpleSchema({ + docRef: RefSchema, + userId: { + type: String, + regEx: SimpleSchema.RegEx.Id, + }, + role: { + type: String, + allowedValues: ['reader', 'writer', 'none'], + }, + }).validator(), + run({docRef, userId, role}){ + let doc = fetchDocByRef(docRef); + if (role === 'none'){ + // only asser 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 }, + }); + } + }, +}); + +export { setPublic, updateUserSharePermissions }; diff --git a/app/imports/api/users/Users.js b/app/imports/api/users/Users.js index 99c26525..39f8863d 100644 --- a/app/imports/api/users/Users.js +++ b/app/imports/api/users/Users.js @@ -66,6 +66,16 @@ const userSchema = new SimpleSchema({ }, 'subscribedLibraries.$': { type: String, + regEx: SimpleSchema.RegEx.Id, + }, + subscribedCharacters: { + type: Array, + defaultValue: [], + max: 100, + }, + 'subscribedCharacters.$': { + type: String, + regEx: SimpleSchema.RegEx.Id, }, }); @@ -151,6 +161,31 @@ Meteor.users.setUsername = new ValidatedMethod({ } }); +Meteor.users.subscribeToLibrary = new ValidatedMethod({ + name: 'Users.methods.subscribeToLibrary', + validate: new SimpleSchema({ + libraryId:{ + type: String, + regEx: SimpleSchema.RegEx.Id, + }, + subscribe: { + type: Boolean, + }, + }).validator(), + run({libraryId, subscribe}){ + if (!this.userId) throw 'Can only subscribe if logged in'; + if (subscribe){ + return Meteor.users.update(this.userId, { + $addToSet: {subscribedLibraries: libraryId}, + }); + } else { + return Meteor.users.update(this.userId, { + $pullAll: {subscribedLibraries: libraryId}, + }); + } + } +}); + Meteor.users.findUserByUsernameOrEmail = new ValidatedMethod({ name: 'Users.methods.findUserByUsernameOrEmail', validate: new SimpleSchema({ diff --git a/app/imports/server/publications/users.js b/app/imports/server/publications/users.js index 4dea49f3..dbf3b242 100644 --- a/app/imports/server/publications/users.js +++ b/app/imports/server/publications/users.js @@ -8,6 +8,7 @@ Meteor.publish('user', function(){ username: 1, apiKey: 1, darkMode: 1, + subscribedLibraries: 1, 'services.patreon.id': 1, 'services.patreon.entitledCents': 1, 'services.patreon.entitledCentsOverride': 1, diff --git a/app/imports/ui/components/tree/TreeNodeList.vue b/app/imports/ui/components/tree/TreeNodeList.vue index f966aa5f..02d3aa01 100644 --- a/app/imports/ui/components/tree/TreeNodeList.vue +++ b/app/imports/ui/components/tree/TreeNodeList.vue @@ -1,33 +1,33 @@ + + diff --git a/app/imports/ui/library/SingleLibraryToolbarItems.vue b/app/imports/ui/library/SingleLibraryToolbarItems.vue new file mode 100644 index 00000000..498d3add --- /dev/null +++ b/app/imports/ui/library/SingleLibraryToolbarItems.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/app/imports/ui/pages/SingleLibraryPage.vue b/app/imports/ui/pages/SingleLibraryPage.vue new file mode 100644 index 00000000..dc15640e --- /dev/null +++ b/app/imports/ui/pages/SingleLibraryPage.vue @@ -0,0 +1,16 @@ + + + diff --git a/app/imports/ui/router.js b/app/imports/ui/router.js index 3a1c4cc1..844c8745 100644 --- a/app/imports/ui/router.js +++ b/app/imports/ui/router.js @@ -6,6 +6,8 @@ import LAUNCH_DATE from '/imports/constants/LAUNCH_DATE.js'; import Home from '/imports/ui/pages/Home.vue'; import CharacterList from '/imports/ui/pages/CharacterList.vue'; import Library from '/imports/ui/pages/Library.vue'; +import SingleLibraryPage from '/imports/ui/pages/SingleLibraryPage.vue' +import SingleLibraryToolbarItems from '/imports/ui/library/SingleLibraryToolbarItems.vue' import CharacterSheetPage from '/imports/ui/pages/CharacterSheetPage.vue'; import CharacterSheetToolbarItems from '/imports/ui/creature/character/CharacterSheetToolbarItems.vue'; import CharacterSheetToolbarExtension from '/imports/ui/creature/character/CharacterSheetToolbarExtension.vue'; @@ -100,6 +102,17 @@ RouterFactory.configure(factory => { title: 'Library', }, beforeEnter: ensurePatronTier5, + },{ + name: 'singleLibrary', + path: '/library/:id', + components: { + default: SingleLibraryPage, + toolbarItems: SingleLibraryToolbarItems, + }, + meta: { + title: 'Library', + }, + beforeEnter: ensurePatronTier5, },{ path: '/character/:id/:urlName', components: { diff --git a/app/imports/ui/sharing/ShareDialog.vue b/app/imports/ui/sharing/ShareDialog.vue index dce6850c..ef16b982 100644 --- a/app/imports/ui/sharing/ShareDialog.vue +++ b/app/imports/ui/sharing/ShareDialog.vue @@ -13,6 +13,15 @@ :value="!!model.public + ''" @change="(value, ack) => setSheetPublic({value, ack})" /> +
- + Share
-
-

- Can Edit -

-
+ - {{ user }} - - delete - -
-

- Can View -

-
- {{ user }} - - delete - -
-
+ + + {{ user.username || user._id }} + + + {{ user.permission === 'writer' ? 'Can edit' : 'Can view' }} + + + + + + + + + create + + Can edit + + + + remove_red_eye + + View only + + + + delete + + Remove + + + + + + + + +