Improved sharing dialog, setting a sheet as public now working
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import SimpleSchema from 'simpl-schema';
|
import SimpleSchema from 'simpl-schema';
|
||||||
|
import '/imports/api/sharing/sharing.js';
|
||||||
|
|
||||||
let SharingSchema = new SimpleSchema({
|
let SharingSchema = new SimpleSchema({
|
||||||
owner: {
|
owner: {
|
||||||
@@ -28,7 +29,7 @@ let SharingSchema = new SimpleSchema({
|
|||||||
},
|
},
|
||||||
public: {
|
public: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
optional: true,
|
defaultValue: false,
|
||||||
index: 1,
|
index: 1,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
20
app/imports/api/sharing/sharing.js
Normal file
20
app/imports/api/sharing/sharing.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
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';
|
||||||
|
|
||||||
|
const setPublic = new ValidatedMethod({
|
||||||
|
name: 'sharing.methods.setPublic',
|
||||||
|
validate: new SimpleSchema({
|
||||||
|
docRef: RefSchema,
|
||||||
|
public: { type: Boolean },
|
||||||
|
}).validator(),
|
||||||
|
run({docRef, public}){
|
||||||
|
let doc = fetchDocByRef(docRef);
|
||||||
|
assertOwnership(doc, this.userId);
|
||||||
|
getCollectionByName(docRef.collection).update(docRef.id, {$set: {public}});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
export { setPublic };
|
||||||
@@ -134,8 +134,9 @@ Meteor.users.findUserByUsernameOrEmail = new ValidatedMethod({
|
|||||||
},
|
},
|
||||||
}).validator(),
|
}).validator(),
|
||||||
run({usernameOrEmail}){
|
run({usernameOrEmail}){
|
||||||
let user = Accounts.findUserByUsername(username) ||
|
if (Meteor.isClient) return;
|
||||||
Accounts.findUserByEmail(email);
|
let user = Accounts.findUserByUsername(usernameOrEmail) ||
|
||||||
|
Accounts.findUserByEmail(usernameOrEmail);
|
||||||
return user && user._id;
|
return user && user._id;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -71,7 +71,14 @@ export default {
|
|||||||
this.loading = false;
|
this.loading = false;
|
||||||
this.dirty = false;
|
this.dirty = false;
|
||||||
this.error = !!error;
|
this.error = !!error;
|
||||||
this.ackErrors = error || null;
|
if (!error){
|
||||||
|
this.ackErrors = null;
|
||||||
|
} else if (typeof error === 'string'){
|
||||||
|
this.ackErrors = error;
|
||||||
|
} else {
|
||||||
|
this.ackErrors = 'Something went wrong'
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
change(val){
|
change(val){
|
||||||
this.dirty = true;
|
this.dirty = true;
|
||||||
|
|||||||
@@ -9,9 +9,30 @@
|
|||||||
</v-btn>
|
</v-btn>
|
||||||
<span>{{character.name}}</span>
|
<span>{{character.name}}</span>
|
||||||
<v-spacer/>
|
<v-spacer/>
|
||||||
<v-btn flat icon @click="showCharacterForm" data-id="character-form-button">
|
<v-menu bottom left transition="slide-y-transition" data-id="creature-menu">
|
||||||
<v-icon>more</v-icon>
|
<template v-slot:activator="{ on }">
|
||||||
</v-btn>
|
<v-btn icon v-on="on">
|
||||||
|
<v-icon>more_vert</v-icon>
|
||||||
|
</v-btn>
|
||||||
|
</template>
|
||||||
|
<v-list>
|
||||||
|
<v-list-tile @click="deleteCharacter">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>delete</v-icon> Delete
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile @click="showCharacterForm">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>create</v-icon> Edit details
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
<v-list-tile @click="showShareDialog">
|
||||||
|
<v-list-tile-title>
|
||||||
|
<v-icon>share</v-icon> Sharing
|
||||||
|
</v-list-tile-title>
|
||||||
|
</v-list-tile>
|
||||||
|
</v-list>
|
||||||
|
</v-menu>
|
||||||
<v-tabs
|
<v-tabs
|
||||||
slot="extension"
|
slot="extension"
|
||||||
v-model="tab"
|
v-model="tab"
|
||||||
@@ -81,12 +102,27 @@
|
|||||||
showCharacterForm(){
|
showCharacterForm(){
|
||||||
this.$store.commit('pushDialogStack', {
|
this.$store.commit('pushDialogStack', {
|
||||||
component: 'creature-form-dialog',
|
component: 'creature-form-dialog',
|
||||||
elementId: 'character-form-button',
|
elementId: 'creature-menu',
|
||||||
data: {
|
data: {
|
||||||
_id: this.creatureId,
|
_id: this.creatureId,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
showShareDialog(){
|
||||||
|
this.$store.commit('pushDialogStack', {
|
||||||
|
component: 'share-dialog',
|
||||||
|
elementId: 'creature-menu',
|
||||||
|
data: {
|
||||||
|
docRef: {
|
||||||
|
id: this.creatureId,
|
||||||
|
collection: 'creatures',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
deleteCharacter(){
|
||||||
|
console.log('todo');
|
||||||
|
},
|
||||||
isDarkColor,
|
isDarkColor,
|
||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import FeatureDialogContainer from '/imports/ui/properties/features/FeatureDialo
|
|||||||
import LibraryCreationDialog from '/imports/ui/library/LibraryCreationDialog.vue';
|
import LibraryCreationDialog from '/imports/ui/library/LibraryCreationDialog.vue';
|
||||||
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
|
import LibraryNodeCreationDialog from '/imports/ui/library/LibraryNodeCreationDialog.vue';
|
||||||
import LibraryNodeEditDialog from '/imports/ui/library/LibraryNodeEditDialog.vue';
|
import LibraryNodeEditDialog from '/imports/ui/library/LibraryNodeEditDialog.vue';
|
||||||
|
import ShareDialog from '/imports/ui/sharing/ShareDialog.vue';
|
||||||
import SkillDialogContainer from '/imports/ui/properties/skills/SkillDialogContainer.vue';
|
import SkillDialogContainer from '/imports/ui/properties/skills/SkillDialogContainer.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
@@ -25,5 +26,6 @@ export default {
|
|||||||
LibraryCreationDialog,
|
LibraryCreationDialog,
|
||||||
LibraryNodeCreationDialog,
|
LibraryNodeCreationDialog,
|
||||||
LibraryNodeEditDialog,
|
LibraryNodeEditDialog,
|
||||||
|
ShareDialog,
|
||||||
SkillDialogContainer,
|
SkillDialogContainer,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,40 +1,40 @@
|
|||||||
<template lang="html">
|
<template lang="html">
|
||||||
<dialog-base>
|
<dialog-base>
|
||||||
<div slot="toolbar">
|
<div slot="toolbar">
|
||||||
Sharing {{name}}
|
Sharing
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div v-if="model">
|
||||||
<smart-select
|
<smart-select
|
||||||
label="Who can view"
|
label="Who can view"
|
||||||
:items="[
|
:items="[
|
||||||
{text: 'Only people I share with', value: false},
|
{text: 'Only people I share with', value: 'false'},
|
||||||
{text: 'Anyone with link', value: true}
|
{text: 'Anyone with link', value: 'true'}
|
||||||
]"
|
]"
|
||||||
:value="model.public"
|
:value="!!model.public + ''"
|
||||||
:error-messages="errors.public"
|
|
||||||
@change="(value, ack) => setSheetPublic({value, ack})"
|
@change="(value, ack) => setSheetPublic({value, ack})"
|
||||||
/>
|
/>
|
||||||
<div class="layout row">
|
<div class="layout row">
|
||||||
<text-field
|
<text-field
|
||||||
label="Username or email"
|
label="Username or email"
|
||||||
|
:value="userSearched"
|
||||||
@change="(value, ack) => getUser({value, ack})"
|
@change="(value, ack) => getUser({value, ack})"
|
||||||
:debounceTime="300"
|
:debounceTime="300"
|
||||||
/>
|
/>
|
||||||
<v-btn :disabled="userFoundState !== found">
|
<v-btn :disabled="userFoundState !== 'found'">
|
||||||
Share
|
Share
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<div class="sharedWith">
|
<div class="sharedWith">
|
||||||
<h3>Can Edit</h3>
|
<h3 v-if="writers.length">Can Edit</h3>
|
||||||
<div v-for="userId in model.writers">
|
<div v-for="user in writers">
|
||||||
{{username(userId)}}
|
{{user}}
|
||||||
<v-btn flat icon>
|
<v-btn flat icon>
|
||||||
<v-icon>delete</v-icon>
|
<v-icon>delete</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</div>
|
</div>
|
||||||
<h3>Can View</h3>
|
<h3 v-if="readers.length">Can View</h3>
|
||||||
<div v-for="userId in model.readers">
|
<div v-for="user in readers">
|
||||||
{{username(userId)}}
|
{{user}}
|
||||||
<v-btn flat icon>
|
<v-btn flat icon>
|
||||||
<v-icon>delete</v-icon>
|
<v-icon>delete</v-icon>
|
||||||
</v-btn>
|
</v-btn>
|
||||||
@@ -45,21 +45,38 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { setPublic } from '/imports/api/sharing/sharing.js';
|
||||||
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
import fetchDocByRef from '/imports/api/parenting/fetchDocByRef.js';
|
||||||
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
import DialogBase from '/imports/ui/dialogStack/DialogBase.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
DialogBase,
|
DialogBase,
|
||||||
},
|
},
|
||||||
data(){ return {
|
data(){ return {
|
||||||
|
userSearched: undefined,
|
||||||
userFoundState: 'idle',
|
userFoundState: 'idle',
|
||||||
userId: undefined,
|
userId: undefined,
|
||||||
}},
|
}},
|
||||||
props: {
|
props: {
|
||||||
ref: Object,
|
docRef: Object,
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
setSheetPublic({value, ack}){
|
||||||
|
setPublic.call({
|
||||||
|
docRef: this.docRef,
|
||||||
|
public: value === 'true',
|
||||||
|
}, (error, value) => {
|
||||||
|
ack(error && error.reason || error);
|
||||||
|
});
|
||||||
|
},
|
||||||
getUser({value, ack}){
|
getUser({value, ack}){
|
||||||
|
this.userSearched = value;
|
||||||
|
if (!value){
|
||||||
|
this.userFoundState = 'idle';
|
||||||
|
ack();
|
||||||
|
return;
|
||||||
|
}
|
||||||
Meteor.users.findUserByUsernameOrEmail.call({
|
Meteor.users.findUserByUsernameOrEmail.call({
|
||||||
usernameOrEmail: value
|
usernameOrEmail: value
|
||||||
}, (error, result) => {
|
}, (error, result) => {
|
||||||
@@ -69,8 +86,13 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
this.userId = result;
|
this.userId = result;
|
||||||
if (result){
|
if (result){
|
||||||
this.userFoundState = 'found';
|
if (result === this.model.owner){
|
||||||
ack();
|
this.userFoundState = 'failed';
|
||||||
|
ack('User is already the owner')
|
||||||
|
} else {
|
||||||
|
this.userFoundState = 'found';
|
||||||
|
ack();
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
this.userFoundState = 'notFound';
|
this.userFoundState = 'notFound';
|
||||||
ack('User not found');
|
ack('User not found');
|
||||||
@@ -81,15 +103,26 @@ export default {
|
|||||||
},
|
},
|
||||||
meteor: {
|
meteor: {
|
||||||
model(){
|
model(){
|
||||||
return fetchDocByRef(this.ref);
|
if (!this.docRef || !this.docRef.id) return;
|
||||||
|
let model = fetchDocByRef(this.docRef);
|
||||||
|
console.log({model})
|
||||||
|
return model;
|
||||||
},
|
},
|
||||||
username(userId){
|
readers(){
|
||||||
let user = Meteor.users.findOne(userId);
|
if (this.model){
|
||||||
return user && user.username;
|
return Meteor.users.find({_id: {$in: this.model.readers}})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
writers(){
|
||||||
|
if (this.model){
|
||||||
|
return Meteor.users.find({_id: {$in: this.model.writers}})
|
||||||
|
}
|
||||||
},
|
},
|
||||||
$subscribe: {
|
$subscribe: {
|
||||||
'userPublicProfiles'(){
|
'userPublicProfiles'(){
|
||||||
return [...this.model.writers, ...this.model.readers];
|
let model = this.model;
|
||||||
|
if (!model) return false;
|
||||||
|
return [model.owner, ...model.writers, ...model.readers];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user