diff --git a/app/imports/api/creature/log/CreatureLogs.js b/app/imports/api/creature/log/CreatureLogs.js index 1cab572f..bd1495c8 100644 --- a/app/imports/api/creature/log/CreatureLogs.js +++ b/app/imports/api/creature/log/CreatureLogs.js @@ -4,6 +4,8 @@ import LogContentSchema from '/imports/api/creature/log/LogContentSchema.js'; import { ValidatedMethod } from 'meteor/mdg:validated-method'; import { RateLimiterMixin } from 'ddp-rate-limiter-mixin'; import {assertEditPermission} from '/imports/api/creature/creatures/creaturePermissions.js'; +import {assertUserInTabletop} from '/imports/api/tabletop/methods/shared/tabletopPermissions.js'; + import {parse, prettifyParseError} from '/imports/parser/parser.js'; import resolve, { toString } from '/imports/parser/resolve.js'; const PER_CREATURE_LOG_LIMIT = 100; @@ -40,6 +42,12 @@ let CreatureLogSchema = new SimpleSchema({ regEx: SimpleSchema.RegEx.Id, index: 1, }, + tabletopId: { + type: String, + regEx: SimpleSchema.RegEx.Id, + index: 1, + optional: true, + }, creatureName: { type: String, optional: true, @@ -105,6 +113,7 @@ const insertCreatureLog = new ValidatedMethod({ 'settings.discordWebhook': 1, name: 1, avatarPicture: 1, + tabletop: 1, }}); assertEditPermission(creature, this.userId); // Build the new log @@ -113,6 +122,25 @@ const insertCreatureLog = new ValidatedMethod({ }, }); +const insertTabletopLog = new ValidatedMethod({ + name: 'creatureLogs.methods.insertTabletopLog', + mixins: [RateLimiterMixin], + rateLimit: { + numRequests: 5, + timeInterval: 5000, + }, + validate: new SimpleSchema({ + log: CreatureLogSchema.omit('date'), + }).validator(), + run({log}){ + const tabletopId = log.tabletopId; + assertUserInTabletop(tabletopId, this.userId); + // Build the new log + let id = insertCreatureLogWork({log, method: this}) + return id; + }, +}); + export function insertCreatureLogWork({log, creature, method}){ // Build the new log if (typeof log === 'string'){ @@ -120,12 +148,19 @@ export function insertCreatureLogWork({log, creature, method}){ } if (!log.content?.length) return; log.date = new Date(); + if (creature) log.tabletopId = creature.tabletop; // Insert it let id = CreatureLogs.insert(log); if (Meteor.isServer){ method?.unblock(); - removeOldLogs(creature._id); - logWebhook({log, creature}); + if (creature){ + removeOldLogs(creature._id); + logWebhook({log, creature}); + } + if (log.tabletopId){ + // Todo remove old tabletop logs + // Log webhook if it's different to creature webhook + } } return id; } @@ -210,4 +245,4 @@ const logRoll = new ValidatedMethod({ }); export default CreatureLogs; -export { CreatureLogSchema, insertCreatureLog, logRoll}; +export { CreatureLogSchema, insertCreatureLog, logRoll, insertTabletopLog}; diff --git a/app/imports/api/files/s3FileStorage.js b/app/imports/api/files/s3FileStorage.js index 43dafb33..30e43cc3 100644 --- a/app/imports/api/files/s3FileStorage.js +++ b/app/imports/api/files/s3FileStorage.js @@ -214,7 +214,7 @@ if (Meteor.isServer && Meteor.settings.useS3) { } } else { if (Meteor.isServer){ - console.log('No S3 details specified, files will be stored in the local filesystem'); + // console.log('No S3 details specified, files will be stored in the local filesystem'); } createS3FilesCollection = function({ collectionName, diff --git a/app/imports/server/publications/tabletops.js b/app/imports/server/publications/tabletops.js index 30345f79..83bc84c1 100644 --- a/app/imports/server/publications/tabletops.js +++ b/app/imports/server/publications/tabletops.js @@ -1,6 +1,7 @@ import Tabletops from '/imports/api/tabletop/Tabletops.js'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; -import Messages from '/imports/api/tabletop/Messages.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js'; Meteor.publish('tabletops', function(){ var userId = this.userId; @@ -47,14 +48,17 @@ Meteor.publish('tabletop', function(tabletopId){ initiativeRoll: 1, }, }); - let recentMessages = Messages.find({ + const creatureIds = creatureSummaries.map(c => c._id); + let properties = CreatureProperties.find({ + 'ancestors.0.id': {$in: creatureIds}, + removed: {$ne: true}, + }); + const logs = CreatureLogs.find({ tabletopId, }, { - sort: { - timeStamp: -1, - }, - limit: 100, + limit: 50, + sort: {date: -1}, }); - return [ tabletopCursor, creatureSummaries, recentMessages] + return [ tabletopCursor, creatureSummaries, properties, logs] }) }); diff --git a/app/imports/ui/creature/character/CharacterSheet.vue b/app/imports/ui/creature/character/CharacterSheet.vue index 2ae33224..d09b28ae 100644 --- a/app/imports/ui/creature/character/CharacterSheet.vue +++ b/app/imports/ui/creature/character/CharacterSheet.vue @@ -1,4 +1,4 @@ -if @@ -41,15 +77,29 @@ import addCreaturesToTabletop from '/imports/api/tabletop/methods/addCreaturesTo import TabletopCreatureCard from '/imports/ui/tabletop/TabletopCreatureCard.vue'; import TabletopMap from '/imports/ui/tabletop/TabletopMap.vue'; import Creatures from '/imports/api/creature/creatures/Creatures.js'; -import TabletopActionCards from '/imports/ui/tabletop/TabletopActionCards.vue'; import MiniCharacterSheet from '/imports/ui/creature/character/MiniCharacterSheet.vue'; import snackbar from '/imports/ui/components/snackbars/SnackbarQueue.js'; +import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js'; +import ActionCard from '/imports/ui/properties/components/actions/ActionCard.vue'; +import { assertEditPermission } from '/imports/api/creature/creatures/creaturePermissions.js'; + +function getProperties(ancestorId, type){ + if (!ancestorId) return []; + return CreatureProperties.find({ + 'ancestors.id': ancestorId, + type, + removed: {$ne: true}, + inactive: {$ne: true}, + }, { + sort: {order: 1} + }); +} export default { components: { TabletopCreatureCard, TabletopMap, - TabletopActionCards, + ActionCard, MiniCharacterSheet, }, props: { @@ -58,6 +108,10 @@ export default { required: true, }, }, + reactiveProvide: { + name: 'context', + include: ['editPermission'], + }, data(){ return { activeCreature: undefined, }}, @@ -70,6 +124,20 @@ export default { creatures(){ return Creatures.find({tabletop: this.model._id}); }, + actions(){ + return getProperties(this.activeCreature, 'action').map(a => { + delete a.summary; + return a; + }); + }, + editPermission(){ + try { + assertEditPermission(this.activeCreature, Meteor.userId()); + return true; + } catch (e) { + return false; + } + }, }, methods: { addCreature(){ @@ -89,6 +157,29 @@ export default { }); }, }); + }, + openCharacterSheetDialog(){ + this.$store.commit('pushDialogStack', { + component: 'character-sheet-dialog', + elementId: 'mini-character-sheet', + data: { + creatureId: this.activeCreature, + }, + }); + }, + clickProperty({_id}){ + this.$store.commit('pushDialogStack', { + component: 'creature-property-dialog', + elementId: `${_id}`, + data: {_id}, + }); + }, + transformScroll(event) { + if (!event.deltaY) { + return; + } + event.currentTarget.scrollLeft += event.deltaY + event.deltaX; + event.preventDefault(); } } } @@ -97,8 +188,17 @@ export default { diff --git a/app/imports/ui/tabletop/TabletopCreatureCard.vue b/app/imports/ui/tabletop/TabletopCreatureCard.vue index 80c1561b..1cb51cf5 100644 --- a/app/imports/ui/tabletop/TabletopCreatureCard.vue +++ b/app/imports/ui/tabletop/TabletopCreatureCard.vue @@ -1,6 +1,11 @@ diff --git a/app/imports/ui/tabletop/TabletopLog.vue b/app/imports/ui/tabletop/TabletopLog.vue index 35ac1ad1..b907ca21 100644 --- a/app/imports/ui/tabletop/TabletopLog.vue +++ b/app/imports/ui/tabletop/TabletopLog.vue @@ -1,51 +1,50 @@