Added basic ownership transfer for shared documents

This commit is contained in:
Stefan Zermatten
2021-08-10 19:01:31 +02:00
parent e21586e9ce
commit 8162c76185
6 changed files with 159 additions and 59 deletions

View File

@@ -1,5 +1,4 @@
import '/imports/api/creature/creatures/methods/insertCreature.js';
import '/imports/api/creature/creatures/methods/removeCreature.js';
import '/imports/api/creature/creatures/methods/restCreature.js';
import '/imports/api/creature/creatures/methods/transferCreatureOwnership.js';
import '/imports/api/creature/creatures/methods/updateCreature.js';

View File

@@ -1,55 +0,0 @@
import SimpleSchema from 'simpl-schema';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
import { RateLimiterMixin } from 'ddp-rate-limiter-mixin';
import Creatures from '/imports/api/creature/creatures/Creatures.js';
import { assertOwnership } from '/imports/api/creature/creatures/creaturePermissions.js';
import { getUserTier } from '/imports/api/users/patreon/tiers.js';
const transferCreatureOwnership = new ValidatedMethod({
name: 'creatures.methods.transferOwnership',
validate: new SimpleSchema({
creatureId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
},
userId: {
type: String,
regEx: SimpleSchema.RegEx.Id,
},
}).validator(),
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 5,
timeInterval: 5000,
},
run({creatureId, userId}) {
assertOwnership(creatureId, this.userId);
let tier = getUserTier(userId);
let currentCharacterCount = Creatures.find({
owner: userId,
}, {
fields: {_id: 1},
}).count();
if (
tier.characterSlots !== -1 &&
currentCharacterCount >= tier.characterSlots
){
throw new Meteor.Error('Creatures.methods.transferOwnership.denied',
'The new owner is already at their character limit')
}
Creatures.update(creatureId, {
$set: {owner: userId},
});
return creatureId;
},
});
export default transferCreatureOwnership;

View File

@@ -5,6 +5,7 @@ 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',
@@ -47,7 +48,7 @@ const updateUserSharePermissions = new ValidatedMethod({
run({docRef, userId, role}){
let doc = fetchDocByRef(docRef);
if (role === 'none'){
// only asser ownership if you aren't removing yourself
// only assert ownership if you aren't removing yourself
if (this.userId !== userId){
assertOwnership(doc, this.userId);
}
@@ -74,4 +75,58 @@ const updateUserSharePermissions = new ValidatedMethod({
},
});
export { setPublic, updateUserSharePermissions };
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, updateUserSharePermissions, transferOwnership };

View File

@@ -21,6 +21,7 @@ import ShareDialog from '/imports/ui/sharing/ShareDialog.vue';
import SlotDetailsDialog from '/imports/ui/creature/slots/SlotDetailsDialog.vue';
import SlotFillDialog from '/imports/ui/creature/slots/SlotFillDialog.vue';
import TierTooLowDialog from '/imports/ui/user/TierTooLowDialog.vue';
import TransferOwnershipDialog from '/imports/ui/sharing/TransferOwnershipDialog.vue';
import UsernameDialog from '/imports/ui/user/UsernameDialog.vue';
export default {
@@ -47,5 +48,6 @@ export default {
SlotDetailsDialog,
SlotFillDialog,
TierTooLowDialog,
TransferOwnershipDialog,
UsernameDialog,
};

View File

@@ -17,7 +17,7 @@
v-if="model.public && docRef.collection === 'libraries'"
readonly
label="Link"
:value="'https://beta.dicecloud.com' + this.$router.resolve({
:value="'https://beta.dicecloud.com' + $router.resolve({
name: 'singleLibrary',
params: { id: model._id },
}).href"
@@ -56,6 +56,7 @@
<v-menu
bottom
left
:data-id="'menu-' + user._id"
>
<template #activator="{ on }">
<v-btn
@@ -84,6 +85,15 @@
</v-list-item-action>
<v-list-item-title>View only</v-list-item-title>
</v-list-item>
<v-list-item
v-if="user.permission === 'writer'"
@click="makeOwner(user)"
>
<v-list-item-action>
<v-icon>mdi-signature</v-icon>
</v-list-item-action>
<v-list-item-title>Transfer Onwership</v-list-item-title>
</v-list-item>
<v-list-item @click="updateSharing(user._id, 'none')">
<v-list-item-action>
<v-icon>mdi-delete</v-icon>
@@ -181,6 +191,16 @@ export default {
userId,
role,
});
},
makeOwner(user){
this.$store.commit('pushDialogStack', {
component: 'transfer-ownership-dialog',
elementId: 'menu-' + user._id,
data: {
docRef: this.docRef,
user,
},
});
},
},
meteor: {

View File

@@ -0,0 +1,79 @@
<template lang="html">
<dialog-base>
<v-toolbar-title slot="toolbar">
Transfer Ownership
</v-toolbar-title>
<v-alert
type="error"
outlined
>
<template v-if="error">
<p>
{{ error }}
</p>
</template>
<template v-else>
<p>
Are you sure you want to transfer ownership to {{ user.username || user._id }}?
</p><p>
This can only be undone by the user you are transferring ownership to.
</p><p>
You will still have edit permission.
</p>
</template>
</v-alert>
<v-layout justify-center>
<v-btn
color="accent"
@click="transfer"
>
Transfer
<template v-if="user.username">
to {{ user.username }}
</template>
</v-btn>
</v-layout>
</dialog-base>
</template>
<script lang="js">
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import { transferOwnership } from '/imports/api/sharing/sharing.js';
export default {
components: {
DialogBase,
},
props: {
docRef: {
type: Object,
required: true,
},
user: {
type: Object,
required: true,
},
},
data(){ return {
error: undefined,
}},
methods: {
transfer(){
transferOwnership.call({
docRef: this.docRef,
userId: this.user._id
}, error => {
if (!error){
this.error = undefined;
this.$store.dispatch('popDialogStack')
return;
}
this.error = error.reason || error.message || error.toString();
});
},
},
}
</script>
<style lang="css" scoped>
</style>