Continued work on tabletops, hidden from main app and all methods disallowed for non-admins

This commit is contained in:
Stefan Zermatten
2020-07-26 19:45:07 +02:00
parent 0f20cd4bd9
commit c7985af83b
7 changed files with 190 additions and 7 deletions

View File

@@ -0,0 +1,115 @@
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.js';
import Tabletops, { assertUserInTabletop } from '/imports/api/tabletop/Tabletops.js';
let Messages = new Mongo.Collection('messages');
let MessagesSchema = new SimpleSchema({
tabletopId: {
type: String,
regEx: SimpleSchema.RegEx.id,
},
content: {
type: String,
max: 1000,
},
timestamp: {
type: Date,
index: 1,
},
userId: {
type: String,
regEx: SimpleSchema.RegEx.id,
},
username: {
type: String,
},
});
Messages.attachSchema(MessagesSchema);
const sendMessage = new ValidatedMethod({
name: 'messages.send',
validate: new SimpleSchema({
content: {
type: String,
max: 1000,
},
tabletopId: {
type: String,
regEx: SimpleSchema.RegEx.id,
},
}).validator(),
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 10,
timeInterval: 5000,
},
run({content, tabletopId}) {
let user = Meteor.user();
if (!user) {
throw new Meteor.Error('messages.send.denied',
'You need to be logged in to send a message');
}
assertUserInTabletop(tabletopId, this.userId);
return Messages.insert({
content,
tabletopId,
timestamp: new Date(),
userId: user._id,
username: user.username,
});
},
});
const removeMessages = new ValidatedMethod({
name: 'messages.remove',
validate: new SimpleSchema({
messageId: {
type: String,
regEx: SimpleSchema.RegEx.id,
},
}).validator(),
mixins: [RateLimiterMixin],
rateLimit: {
numRequests: 5,
timeInterval: 5000,
},
run({messageId, tabletopId}) {
if (!this.userId) {
throw new Meteor.Error('messages.remove.denied',
'You need to be logged in to remove a tabletop');
}
let message = Messages.findOne(messageId);
let tabletop = Tabletops.findOne(message.tabletopId);
if (this.userId !== message.userId && this.userId !== tabletop.gameMaster){
throw new Meteor.Error('messages.remove.denied',
'You don\'t have permission to remove this message');
}
let removed = Messages.remove({
_id: messageId,
});
Creatures.update({
tabletop: tabletopId,
}, {
$unset: {tabletop: 1},
});
return removed;
},
});
export default Messages;
export { sendMessage, removeMessages };

View File

@@ -64,7 +64,7 @@ function assertUserIsTabletopOwner(tabletopId, userId){
}
}
function assertUserInTabletop(tabletopId, userId){
export function assertUserInTabletop(tabletopId, userId){
let tabletop = Tabletops.findOne(tabletopId);
if (!tabletop){
throw new Meteor.Error('Tabletop does not exist',
@@ -76,6 +76,13 @@ function assertUserInTabletop(tabletopId, userId){
}
}
function assertUserIsAdmin(userId){
if (!Meteor.users.isAdmin(userId)){
throw new Meteor.Error('Admin only',
'This is restricted to admins for now');
}
}
const insertTabletop = new ValidatedMethod({
name: 'tabletops.insert',
@@ -94,6 +101,7 @@ const insertTabletop = new ValidatedMethod({
'You need to be logged in to insert a tabletop');
}
assertUserHasPaidBenefits(this.userId);
assertUserIsAdmin(this.userId);
return Tabletops.insert({
gameMaster: this.userId,
@@ -126,6 +134,8 @@ const removeTabletop = new ValidatedMethod({
}
assertUserHasPaidBenefits(this.userId);
assertUserIsTabletopOwner(tabletopId, this.userId);
assertUserIsAdmin(this.userId);
let removed = Tabletops.remove({
_id: tabletopId,
});
@@ -170,6 +180,8 @@ const addCreaturesToTabletop = new ValidatedMethod({
}
assertUserHasPaidBenefits(this.userId);
assertUserInTabletop(tabletopId, this.userId);
assertUserIsAdmin(this.userId);
Creatures.update({
_id: {$in: creatureIds},
$or: [

View File

@@ -1,5 +1,6 @@
import Tabletops from '/imports/api/tabletop/Tabletops.js';
import Creatures from '/imports/api/creature/Creatures.js';
import Messages from '/imports/api/tabletop/Messages.js';
Meteor.publish('tabletops', function(){
var userId = this.userId;
@@ -46,6 +47,14 @@ Meteor.publish('tabletop', function(tabletopId){
initiativeRoll: 1,
},
});
return [ tabletopCursor, creatureSummaries]
let recentMessages = Messages.find({
tabletopId,
}, {
sort: {
timeStamp: -1,
},
limit: 100,
});
return [ tabletopCursor, creatureSummaries, recentMessages]
})
});

View File

@@ -2,7 +2,7 @@
lang="html"
functional
>
<v-list-tile>
<v-list-tile v-bind="$attrs">
<v-list-tile-avatar :color="model.color || 'grey'">
<img
v-if="model.avatarPicture"

View File

@@ -4,6 +4,9 @@
Add Characters
</v-toolbar-title>
<v-list>
<p v-if="!creatures.length">
There are no creatures to add or you have already added them all
</p>
<creature-list-tile
v-for="creature in creatures"
:key="creature._id"
@@ -43,11 +46,11 @@ export default {
},
},
data(){return {
selected: new Set(this.startingSelection),
selected: new Set(),
}},
meteor: {
creatures(){
return Creatures.find({});
return Creatures.find({_id: {$nin: this.startingSelection}});
},
},
methods: {

View File

@@ -23,7 +23,7 @@
</section>
<section class="play-area">
<tabletop-map />
<tabletop-log />
<tabletop-log :tabletop-id="model._id" />
</section>
<section class="action-row">
<mini-character-sheet />

View File

@@ -1,9 +1,53 @@
<template lang="html">
<div class="tabletop-log" />
<div class="tabletop-log">
<div class="messages layout column justify-end align-end">
<div
v-for="message in messages"
:key="message._id"
class="message"
>
{{ message.content }}
</div>
</div>
<v-textarea
v-model="messageContent"
@keyup.enter.prevent="sendMessage"
/>
</div>
</template>
<script>
import Messages, { sendMessage } from '/imports/api/tabletop/Messages.js';
export default {
props: {
tabletopId: {
type: String,
required: true,
},
},
data(){ return {
messageContent: '',
}},
meteor: {
messages() {
return Messages.find({
tabletopId: this.tabletopId,
}, {
sort: {
timeStamp: 1,
},
});
}
},
methods: {
sendMessage(){
sendMessage.call({
content: this.messageContent,
tabletopId: this.tabletopId,
});
this.messageContent = '';
},
},
}
</script>