Libraries can now be deleted

This commit is contained in:
Stefan Zermatten
2020-03-05 14:00:16 +02:00
parent dfa3b057b0
commit 66e70c8c94
8 changed files with 210 additions and 23 deletions

View File

@@ -116,21 +116,9 @@ const insertCreature = new ValidatedMethod({
});
const removeCreature = new ValidatedMethod({
name: 'Creatures.methods.remove',
validate: null,
run({charId}) {
let creature = Creatures.findOne(_id);
assertOwnership(creature, this.userId);
let _id = CreatureProperties.insert(creatureProperty);
let property = CreatureProperties.findOne(_id);
recomputeCreatures(property);
},
});
const updateCreature = new ValidatedMethod({
name: 'Creatures.methods.update',
validate({_id, path, value, ack}){
validate({_id, path, value}){
if (!_id) return false;
// Allowed fields
let allowedFields = ['name', 'alignment', 'gender', 'picture', 'settings'];

View File

@@ -1,6 +1,8 @@
import SimpleSchema from 'simpl-schema';
import SharingSchema from '/imports/api/sharing/SharingSchema.js';
import simpleSchemaMixin from '/imports/api/creature/mixins/simpleSchemaMixin.js';
import { assertEditPermission, assertOwnership } from '/imports/api/sharing/sharingPermissions.js';
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
/**
* Libraries are trees of library nodes where each node represents a character
@@ -41,6 +43,24 @@ const insertLibrary = new ValidatedMethod({
},
});
const updateLibraryName = new ValidatedMethod({
name: 'Libraries.methods.updateName',
validate: new SimpleSchema({
_id: {
type: String,
regEx: SimpleSchema.RegEx.id
},
name: {
type: String,
},
}).validator(),
run({_id, name}){
let library = Libraries.findOne(_id);
assertEditPermission(library, this.userId);
Libraries.update(_id, {$set: {name}});
},
});
const setLibraryDefault = new ValidatedMethod({
name: 'Libraries.methods.makeLibraryDefault',
validate: new SimpleSchema({
@@ -60,4 +80,22 @@ const setLibraryDefault = new ValidatedMethod({
},
});
export { LibrarySchema, insertLibrary, setLibraryDefault };
const removeLibrary = new ValidatedMethod({
name: 'Libraries.methods.remove',
validate: new SimpleSchema({
_id: {
type: String,
regEx: SimpleSchema.RegEx.id
},
}).validator(),
run({_id}){
let library = Libraries.findOne(_id);
console.log({library, _id});
assertOwnership(library, this.userId);
Libraries.remove(_id);
this.unblock();
LibraryNodes.remove({'ancestors.id': _id});
}
})
export { LibrarySchema, insertLibrary, setLibraryDefault, updateLibraryName, removeLibrary };

View File

@@ -10,7 +10,7 @@ function assertIdValid(userId){
function assertdocExists(doc){
if (!doc){
throw new Meteor.Error("Edit permission denied",
throw new Meteor.Error("Permission denied",
`No such document exists`);
}
}

View File

@@ -70,6 +70,7 @@
<script>
import Creatures from '/imports/api/creature/Creatures.js';
import removeCreature from '/imports/api/creature/removeCreature.js';
import isDarkColor from '/imports/ui/utility/isDarkColor.js';
import { mapMutations } from "vuex";
import { theme } from '/imports/ui/theme.js';
@@ -121,12 +122,24 @@
});
},
deleteCharacter(){
let that = this;
this.$store.commit('pushDialogStack', {
component: 'character-delete-dialog',
component: 'delete-confirmation-dialog',
elementId: 'creature-menu',
data: {
id: this.creatureId,
name: this.character.name,
typeName: 'Character'
},
callback(confirmation){
if(!confirmation) return;
removeCreature.call({charId: that.creatureId}, (error, result) => {
if (error) {
console.error(error);
} else {
that.$router.push('/characterList');
}
});
}
});
},
isDarkColor,

View File

@@ -0,0 +1,54 @@
<template lang="html">
<dialog-base>
<div slot="toolbar">
Delete {{typeName}}
</div>
<div>
<p v-if="name">
Type "{{name}}" to permanenetly delete
</p>
<v-text-field v-if="name" v-model="inputName"/>
<div class="layout row justify-center">
<v-btn
v-show="nameMatch"
class="primary"
@click="$store.dispatch('popDialogStack', true);"
>Delete forever</v-btn>
</div>
</div>
<v-spacer slot="actions"/>
<v-btn
slot="actions"
flat
@click="$store.dispatch('popDialogStack')"
>Cancel</v-btn>
</dialog-base>
</template>
<script>
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
export default {
components: {
DialogBase,
},
props: {
typeName: String,
name: String,
},
data(){return {
inputName: undefined,
}},
computed: {
nameMatch(){
if (!this.name) return true;
let uppername = this.name.toUpperCase();
let upperInputName = this.inputName && this.inputName.toUpperCase();
return uppername === upperInputName;
},
},
};
</script>
<style lang="css" scoped>
</style>

View File

@@ -2,13 +2,14 @@ import AttributeDialog from '/imports/ui/properties/attributes/AttributeDialog.v
import AttributeDialogContainer from '/imports/ui/properties/attributes/AttributeDialogContainer.vue';
import AttributeCreationDialog from '/imports/ui/properties/attributes/AttributeCreationDialog.vue';
import CreatureFormDialog from '/imports/ui/creature/CreatureFormDialog.vue';
import CharacterDeleteDialog from '/imports/ui/creature/character/CharacterDeleteDialog.vue';
import CreaturePropertyCreationDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyCreationDialog.vue';
import CreaturePropertyDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyDialog.vue'
import CreaturePropertyFromLibraryDialog from '/imports/ui/creature/creatureProperties/CreaturePropertyFromLibraryDialog.vue'
import DeleteConfirmationDialog from '/imports/ui/dialogStack/DeleteConfirmationDialog.vue';
import FeatureCreationDialog from '/imports/ui/properties/features/FeatureCreationDialog.vue';
import FeatureDialogContainer from '/imports/ui/properties/features/FeatureDialogContainer.vue';
import LibraryCreationDialog from '/imports/ui/library/LibraryCreationDialog.vue';
import LibraryEditDialog from '/imports/ui/library/LibraryEditDialog.vue';
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
import LibraryNodeEditDialog from '/imports/ui/library/LibraryNodeEditDialog.vue';
import ShareDialog from '/imports/ui/sharing/ShareDialog.vue';
@@ -19,13 +20,14 @@ export default {
AttributeDialogContainer,
AttributeCreationDialog,
CreatureFormDialog,
CharacterDeleteDialog,
CreaturePropertyCreationDialog,
CreaturePropertyDialog,
CreaturePropertyFromLibraryDialog,
DeleteConfirmationDialog,
FeatureCreationDialog,
FeatureDialogContainer,
LibraryCreationDialog,
LibraryEditDialog,
LibraryNodeCreationDialog,
LibraryNodeEditDialog,
ShareDialog,

View File

@@ -27,10 +27,8 @@
:selected-node-id="selectedNodeId"
/>
<v-card-actions>
<v-spacer/>
<v-btn
flat
color="primary"
flat small
style="background-color: inherit; margin-top: 0;"
@click="insertLibraryNode(library._id)"
:data-id="`insert-node-${library._id}`"
@@ -38,6 +36,12 @@
<v-icon>add</v-icon>
New property
</v-btn>
<v-spacer/>
<v-btn flat small icon
@click="editLibrary(library._id)"
>
<v-icon>create</v-icon>
</v-btn>
</v-card-actions>
</v-card>
</v-expansion-panel-content>
@@ -97,6 +101,13 @@ export default {
}
});
},
editLibrary(_id){
this.$store.commit('pushDialogStack', {
component: 'library-edit-dialog',
elementId: _id,
data: {_id},
});
},
insertLibraryNode(libraryId){
this.$store.commit('pushDialogStack', {
component: 'library-node-creation-dialog',
@@ -111,7 +122,12 @@ export default {
}
});
},
}
},
watch: {
expandedLibrary(value){
console.log(value)
},
},
}
</script>

View File

@@ -0,0 +1,76 @@
<template lang="html">
<dialog-base>
<template slot="toolbar">
<div>
{{model && model.name}}
</div>
<v-spacer/>
<v-btn flat icon @click="remove">
<v-icon>delete</v-icon>
</v-btn>
</template>
<template v-if="model">
<text-field label="name" :value="model.name" @change="updateName"/>
</template>
<template slot="actions">
<v-spacer/>
<v-btn
flat
@click="$store.dispatch('popDialogStack')"
data-id="delete-library-button"
>
Done
</v-btn>
</template>
</dialog-base>
</template>
<script>
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
import Libraries, { updateLibraryName, removeLibrary } from '/imports/api/library/Libraries.js';
export default {
components: {
DialogBase,
},
props: {
_id: String,
},
methods: {
updateName(value, ack){
updateLibraryName.call({_id: this._id, name: value}, (error, result) =>{
ack(error && error.reason || error);
});
},
remove(){
let that = this;
this.$store.commit('pushDialogStack', {
component: 'delete-confirmation-dialog',
elementId: 'delete-library-button',
data: {
name: this.model.name,
typeName: 'Library'
},
callback(confirmation){
if(!confirmation) return;
removeLibrary.call({_id: that._id}, (error, result) => {
if (error) {
console.error(error);
} else {
that.$store.dispatch('popDialogStack')
}
});
}
});
},
},
meteor: {
model(){
return Libraries.findOne(this._id);
},
}
}
</script>
<style lang="css" scoped>
</style>