219 lines
5.7 KiB
JavaScript
219 lines
5.7 KiB
JavaScript
import SimpleSchema from 'simpl-schema';
|
|
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
|
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables.js';
|
|
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 { parse, prettifyParseError } from '/imports/parser/parser.js';
|
|
import resolve, { toString } from '/imports/parser/resolve.js';
|
|
const PER_CREATURE_LOG_LIMIT = 100;
|
|
import STORAGE_LIMITS from '/imports/constants/STORAGE_LIMITS.js';
|
|
|
|
if (Meteor.isServer) {
|
|
var sendWebhookAsCreature = require('/imports/server/discord/sendWebhook.js').sendWebhookAsCreature;
|
|
}
|
|
|
|
let CreatureLogs = new Mongo.Collection('creatureLogs');
|
|
|
|
let CreatureLogSchema = new SimpleSchema({
|
|
content: {
|
|
type: Array,
|
|
defaultValue: [],
|
|
maxCount: STORAGE_LIMITS.logContentCount,
|
|
},
|
|
'content.$': {
|
|
type: LogContentSchema,
|
|
},
|
|
// The real-world date that it occured, usually sorted by date
|
|
date: {
|
|
type: Date,
|
|
autoValue: function () {
|
|
// If the date isn't set, set it to now
|
|
if (!this.isSet) {
|
|
return new Date();
|
|
}
|
|
},
|
|
index: 1,
|
|
},
|
|
creatureId: {
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
index: 1,
|
|
},
|
|
creatureName: {
|
|
type: String,
|
|
optional: true,
|
|
max: STORAGE_LIMITS.name,
|
|
},
|
|
});
|
|
|
|
CreatureLogs.attachSchema(CreatureLogSchema);
|
|
|
|
function removeOldLogs(creatureId) {
|
|
// Find the first log that is over the limit
|
|
let firstExpiredLog = CreatureLogs.find({
|
|
creatureId
|
|
}, {
|
|
sort: { date: -1 },
|
|
skip: PER_CREATURE_LOG_LIMIT,
|
|
});
|
|
if (!firstExpiredLog) return;
|
|
// Remove all logs older than the one over the limit
|
|
CreatureLogs.remove({
|
|
creatureId,
|
|
date: { $lte: firstExpiredLog.date },
|
|
});
|
|
}
|
|
|
|
function logToMessageData(log) {
|
|
let embed = {
|
|
fields: [],
|
|
};
|
|
log.content.forEach(field => {
|
|
if (!field.name) field.name = '\u200b';
|
|
if (!field.value) field.value = '\u200b';
|
|
embed.fields.push(field);
|
|
});
|
|
return { embeds: [embed] };
|
|
}
|
|
|
|
function logWebhook({ log, creature }) {
|
|
if (Meteor.isServer) {
|
|
sendWebhookAsCreature({
|
|
creature,
|
|
data: logToMessageData(log),
|
|
});
|
|
}
|
|
}
|
|
|
|
const insertCreatureLog = new ValidatedMethod({
|
|
name: 'creatureLogs.methods.insert',
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
validate: new SimpleSchema({
|
|
log: CreatureLogSchema.omit('date'),
|
|
}).validator(),
|
|
run({ log }) {
|
|
const creatureId = log.creatureId;
|
|
const creature = Creatures.findOne(creatureId, {
|
|
fields: {
|
|
readers: 1,
|
|
writers: 1,
|
|
owner: 1,
|
|
'settings.discordWebhook': 1,
|
|
name: 1,
|
|
avatarPicture: 1,
|
|
}
|
|
});
|
|
assertEditPermission(creature, this.userId);
|
|
// Build the new log
|
|
let id = insertCreatureLogWork({ log, creature, method: this })
|
|
return id;
|
|
},
|
|
});
|
|
|
|
export function insertCreatureLogWork({ log, creature, method }) {
|
|
// Build the new log
|
|
if (typeof log === 'string') {
|
|
log = { content: [{ value: log }] };
|
|
}
|
|
if (!log.content?.length) return;
|
|
log.date = new Date();
|
|
// Insert it
|
|
let id = CreatureLogs.insert(log);
|
|
if (Meteor.isServer) {
|
|
method?.unblock();
|
|
removeOldLogs(creature._id);
|
|
logWebhook({ log, creature });
|
|
}
|
|
return id;
|
|
}
|
|
|
|
|
|
function equalIgnoringWhitespace(a, b) {
|
|
if (typeof a !== 'string' || typeof b !== 'string') return a === b;
|
|
return a.replace(/\s/g, '') === b.replace(/\s/g, '');
|
|
}
|
|
|
|
const logRoll = new ValidatedMethod({
|
|
name: 'creatureLogs.methods.logForCreature',
|
|
mixins: [RateLimiterMixin],
|
|
rateLimit: {
|
|
numRequests: 5,
|
|
timeInterval: 5000,
|
|
},
|
|
validate: new SimpleSchema({
|
|
roll: {
|
|
type: String,
|
|
},
|
|
creatureId: {
|
|
type: String,
|
|
regEx: SimpleSchema.RegEx.Id,
|
|
},
|
|
}).validator(),
|
|
run({ roll, creatureId }) {
|
|
const creature = Creatures.findOne(creatureId, {
|
|
fields: {
|
|
readers: 1,
|
|
writers: 1,
|
|
owner: 1,
|
|
'settings.discordWebhook': 1,
|
|
name: 1,
|
|
avatarPicture: 1,
|
|
}
|
|
});
|
|
assertEditPermission(creature, this.userId);
|
|
const variables = CreatureVariables.findOne({ _creatureId: creatureId });
|
|
let logContent = []
|
|
let parsedResult = undefined;
|
|
try {
|
|
parsedResult = parse(roll);
|
|
} catch (e) {
|
|
let error = prettifyParseError(e);
|
|
logContent.push({ name: 'Parse Error', value: error });
|
|
}
|
|
if (parsedResult) try {
|
|
let {
|
|
result: compiled,
|
|
context
|
|
} = resolve('compile', parsedResult, variables);
|
|
const compiledString = toString(compiled);
|
|
if (!equalIgnoringWhitespace(compiledString, roll)) logContent.push({
|
|
value: roll
|
|
});
|
|
logContent.push({
|
|
value: compiledString
|
|
});
|
|
let { result: rolled } = resolve('roll', compiled, variables, context);
|
|
let rolledString = toString(rolled);
|
|
if (rolledString !== compiledString) logContent.push({
|
|
value: rolledString
|
|
});
|
|
let { result } = resolve('reduce', rolled, variables, context);
|
|
let resultString = toString(result);
|
|
if (resultString !== rolledString) logContent.push({
|
|
value: resultString
|
|
});
|
|
} catch (e) {
|
|
console.error(e);
|
|
logContent = [{ name: 'Calculation error' }];
|
|
}
|
|
const log = {
|
|
content: logContent,
|
|
creatureId,
|
|
date: new Date(),
|
|
};
|
|
|
|
let id = insertCreatureLogWork({ log, creature, method: this });
|
|
|
|
return id;
|
|
},
|
|
});
|
|
|
|
export default CreatureLogs;
|
|
export { CreatureLogSchema, insertCreatureLog, logRoll, PER_CREATURE_LOG_LIMIT };
|