Merge branch 'version-2' into version-2-tabletop
This commit is contained in:
0
app/imports/server/action.js
Normal file
0
app/imports/server/action.js
Normal file
@@ -1,4 +1,4 @@
|
||||
import { SyncedCron } from 'meteor/percolate:synced-cron';
|
||||
import { SyncedCron } from 'meteor/littledata:synced-cron';
|
||||
|
||||
SyncedCron.config({
|
||||
// Log job run details to console
|
||||
|
||||
@@ -1,50 +1,50 @@
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import { assertAdmin } from '/imports/api/sharing/sharingPermissions.js';
|
||||
import { SyncedCron } from 'meteor/percolate:synced-cron';
|
||||
import { SyncedCron } from 'meteor/littledata:synced-cron';
|
||||
|
||||
Meteor.startup(() => {
|
||||
const collections = [
|
||||
CreatureProperties,
|
||||
const collections = [
|
||||
CreatureProperties,
|
||||
LibraryNodes,
|
||||
];
|
||||
];
|
||||
|
||||
/**
|
||||
* Deletes all soft removed documents that were removed more than 1 day ago
|
||||
* and were not restored
|
||||
* @return {Number} Number of documents removed
|
||||
*/
|
||||
const deleteOldSoftRemovedDocs = function(){
|
||||
const now = new Date();
|
||||
/**
|
||||
* Deletes all soft removed documents that were removed more than 1 day ago
|
||||
* and were not restored
|
||||
* @return {Number} Number of documents removed
|
||||
*/
|
||||
const deleteOldSoftRemovedDocs = function () {
|
||||
const now = new Date();
|
||||
const yesterday = new Date(now.getTime() - (24 * 60 * 60 * 1000));
|
||||
collections.forEach(collection => {
|
||||
collection.remove({
|
||||
removed: true,
|
||||
removedAt: {$lt: yesterday} // dates *before* yesterday
|
||||
}, function(error){
|
||||
if (error){
|
||||
console.error(JSON.stringify(error, null, 2));
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
collections.forEach(collection => {
|
||||
collection.remove({
|
||||
removed: true,
|
||||
removedAt: { $lt: yesterday } // dates *before* yesterday
|
||||
}, function (error) {
|
||||
if (error) {
|
||||
console.error(JSON.stringify(error, null, 2));
|
||||
}
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
SyncedCron.add({
|
||||
name: 'deleteSoftRemovedDocs',
|
||||
schedule: function(parser) {
|
||||
return parser.text('every 10 minutes');
|
||||
},
|
||||
job: deleteOldSoftRemovedDocs,
|
||||
});
|
||||
SyncedCron.add({
|
||||
name: 'deleteSoftRemovedDocs',
|
||||
schedule: function (parser) {
|
||||
return parser.text('every 10 minutes');
|
||||
},
|
||||
job: deleteOldSoftRemovedDocs,
|
||||
});
|
||||
|
||||
SyncedCron.start();
|
||||
SyncedCron.start();
|
||||
|
||||
// Add a method to manually trigger removal
|
||||
Meteor.methods({
|
||||
deleteOldSoftRemovedDocs() {
|
||||
// Add a method to manually trigger removal
|
||||
Meteor.methods({
|
||||
deleteOldSoftRemovedDocs() {
|
||||
assertAdmin(this.userId);
|
||||
this.unblock();
|
||||
deleteOldSoftRemovedDocs();
|
||||
},
|
||||
});
|
||||
this.unblock();
|
||||
deleteOldSoftRemovedDocs();
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
8
app/imports/server/imageProcessing/createThumbnail.js
Normal file
8
app/imports/server/imageProcessing/createThumbnail.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import * as sharp from 'sharp';
|
||||
|
||||
export default async function createThumbnail(image) {
|
||||
await sharp(image)
|
||||
.resize(320, 240)
|
||||
.png()
|
||||
.toBuffer();
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import ArchivedCreatures from '/imports/api/creature/archive/ArchivedCreatures.js';
|
||||
|
||||
Meteor.publish('archivedCreatures', function(){
|
||||
this.autorun(function (){
|
||||
var userId = this.userId;
|
||||
if (!userId) {
|
||||
return [];
|
||||
}
|
||||
return ArchivedCreatures.find({
|
||||
owner: userId,
|
||||
}, {
|
||||
fields: {
|
||||
creature: 1,
|
||||
owner: 1,
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
35
app/imports/server/publications/docs.js
Normal file
35
app/imports/server/publications/docs.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import { propsByDocsPath } from '/imports/constants/PROPERTIES.js';
|
||||
|
||||
|
||||
// Manual doc paths
|
||||
const docPaths = [
|
||||
'computed-fields',
|
||||
'inline-calculations',
|
||||
'dependency-loops',
|
||||
'docs',
|
||||
'tags',
|
||||
'walkthroughs/create-a-class',
|
||||
];
|
||||
const docs = new Map();
|
||||
docPaths.forEach(path => {
|
||||
docs.set(path, Assets.getText(`docs/${path}.md`))
|
||||
});
|
||||
|
||||
// Doc paths for properties
|
||||
propsByDocsPath.forEach(prop => {
|
||||
docs.set(prop.docsPath, Assets.getText(`docs/${prop.docsPath}.md`));
|
||||
});
|
||||
|
||||
Meteor.publish('docs', function (path) {
|
||||
if (!path) {
|
||||
docs.forEach((text, path) => {
|
||||
this.added('docs', path, { text });
|
||||
});
|
||||
} else {
|
||||
const text = docs.get(path);
|
||||
if (text) {
|
||||
this.added('docs', path, { text });
|
||||
}
|
||||
}
|
||||
this.ready();
|
||||
});
|
||||
@@ -1,16 +1,16 @@
|
||||
import Icons from '/imports/api/icons/Icons.js';
|
||||
|
||||
Meteor.publish('sampleIcons', function(){
|
||||
return Icons.find({}, {limit: 50});
|
||||
Meteor.publish('sampleIcons', function () {
|
||||
return Icons.find({}, { limit: 50 });
|
||||
});
|
||||
|
||||
Meteor.publish('searchIcons', function(searchValue) {
|
||||
Meteor.publish('searchIcons', function (searchValue) {
|
||||
// Don't publish anything if there's no search value
|
||||
if (!searchValue) {
|
||||
return [];
|
||||
}
|
||||
return Icons.find(
|
||||
{ $text: {$search: searchValue} },
|
||||
{ $text: { $search: searchValue } },
|
||||
{
|
||||
// relevant documents have a higher score.
|
||||
fields: {
|
||||
|
||||
@@ -8,6 +8,7 @@ import '/imports/server/publications/icons.js';
|
||||
import '/imports/server/publications/tabletops.js';
|
||||
import '/imports/server/publications/slotFillers.js';
|
||||
import '/imports/server/publications/ownedDocuments.js';
|
||||
import '/imports/server/publications/archivedCreatures.js';
|
||||
import '/imports/server/publications/searchLibraryNodes.js';
|
||||
import '/imports/server/publications/archiveFiles.js';
|
||||
import '/imports/server/publications/userImages.js';
|
||||
import '/imports/server/publications/docs.js';
|
||||
|
||||
@@ -1,27 +1,136 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import LibraryCollections from '/imports/api/library/LibraryCollections.js';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
import { assertViewPermission, assertDocViewPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
import { union } from 'lodash';
|
||||
|
||||
Meteor.publish('libraries', function(){
|
||||
this.autorun(function (){
|
||||
const LIBRARY_NODE_TREE_FIELDS = {
|
||||
_id: 1,
|
||||
name: 1,
|
||||
type: 1,
|
||||
icon: 1,
|
||||
color: 1,
|
||||
order: 1,
|
||||
parent: 1,
|
||||
ancestors: 1,
|
||||
tags: 1,
|
||||
slotFillerCondition: 1,
|
||||
removed: 1,
|
||||
removedAt: 1,
|
||||
// SlotFillers
|
||||
slotQuantityFilled: 1,
|
||||
slotFillerType: 1,
|
||||
// Effect
|
||||
operation: 1,
|
||||
targetTags: 1,
|
||||
stats: 1,
|
||||
// Item
|
||||
quantity: 1,
|
||||
plural: 1,
|
||||
equipped: 1,
|
||||
// Branch
|
||||
branchType: 1,
|
||||
// Damage:
|
||||
damageType: 1,
|
||||
stat: 1,
|
||||
amount: 1,
|
||||
// Class level
|
||||
level: 1,
|
||||
variableName: 1,
|
||||
// Proficiency
|
||||
value: 1,
|
||||
// Reference
|
||||
cache: 1,
|
||||
// Saving throw
|
||||
dc: 1,
|
||||
}
|
||||
|
||||
export { LIBRARY_NODE_TREE_FIELDS };
|
||||
|
||||
Meteor.publish('libraryCollection', function (libraryCollectionId) {
|
||||
this.autorun(function () {
|
||||
let userId = this.userId;
|
||||
if (!userId) return [];
|
||||
this.autorun(function () {
|
||||
const libraryCollectionCursor = LibraryCollections.find({
|
||||
_id: libraryCollectionId,
|
||||
$or: [
|
||||
{ owner: userId },
|
||||
{ writers: userId },
|
||||
{ readers: userId },
|
||||
{ public: true },
|
||||
]
|
||||
});
|
||||
const libraryCollection = libraryCollectionCursor.fetch()[0];
|
||||
if (!libraryCollection) return [ libraryCollectionCursor ];
|
||||
this.autorun(function () {
|
||||
const libraryCursor = Libraries.find({
|
||||
_id: {$in: libraryCollection.libraries},
|
||||
$or: [
|
||||
{ owner: userId },
|
||||
{ writers: userId },
|
||||
{ readers: userId },
|
||||
{ public: true },
|
||||
]
|
||||
}, {
|
||||
sort: { name: 1 }
|
||||
});
|
||||
return [ libraryCollectionCursor, libraryCursor ];
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
Meteor.publish('libraries', function () {
|
||||
this.autorun(function () {
|
||||
let userId = this.userId;
|
||||
if (!userId) {
|
||||
return [];
|
||||
}
|
||||
const user = Meteor.users.findOne(userId, {
|
||||
fields: {subscribedLibraries: 1}
|
||||
fields: { subscribedLibraries: 1, subscribedLibraryCollections: 1 }
|
||||
});
|
||||
const subs = user && user.subscribedLibraries || [];
|
||||
return Libraries.find({
|
||||
$or: [
|
||||
{owner: this.userId},
|
||||
{writers: this.userId},
|
||||
{readers: this.userId},
|
||||
{ _id: {$in: subs}, public: true },
|
||||
]
|
||||
}, {
|
||||
sort: {name: 1}
|
||||
|
||||
this.autorun(function () {
|
||||
// Get the collections the user is subscribed to
|
||||
const subCollections = user && user.subscribedLibraryCollections || [];
|
||||
const libraryCollectionsCursor = LibraryCollections.find({
|
||||
$or: [
|
||||
{ owner: userId },
|
||||
{ writers: userId },
|
||||
{ readers: userId },
|
||||
{ _id: { $in: subCollections }, public: true },
|
||||
]
|
||||
}, {
|
||||
sort: { name: 1 }
|
||||
});
|
||||
|
||||
// Collate all the libraryIds in those collections
|
||||
let collectionLibIds = [];
|
||||
libraryCollectionsCursor.forEach(libCollection => {
|
||||
collectionLibIds = union(collectionLibIds, libCollection.libraries);
|
||||
});
|
||||
|
||||
// Get the libraries the user is subscribed to directly
|
||||
const subs = user && user.subscribedLibraries || [];
|
||||
|
||||
// Combine all the library Ids
|
||||
const libIds = union(collectionLibIds, subs);
|
||||
|
||||
this.autorun(function () {
|
||||
const librariesCursor = Libraries.find({
|
||||
$or: [
|
||||
{ owner: userId },
|
||||
{ writers: userId },
|
||||
{ readers: userId },
|
||||
{ _id: { $in: libIds }, public: true },
|
||||
]
|
||||
}, {
|
||||
sort: { name: 1 }
|
||||
});
|
||||
return [librariesCursor, libraryCollectionsCursor];
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -63,12 +172,35 @@ Meteor.publish('libraryNodes', function(libraryId){
|
||||
LibraryNodes.find({
|
||||
'ancestors.id': libraryId,
|
||||
}, {
|
||||
sort: {order: 1},
|
||||
sort: { order: 1 },
|
||||
fields: LIBRARY_NODE_TREE_FIELDS,
|
||||
}),
|
||||
];
|
||||
});
|
||||
});
|
||||
|
||||
const nodeIdSchema = new SimpleSchema({
|
||||
libraryNodeId: {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
},
|
||||
});
|
||||
|
||||
Meteor.publish('libraryNode', function (libraryNodeId) {
|
||||
if (!libraryNodeId) return [];
|
||||
nodeIdSchema.validate({ libraryNodeId });
|
||||
this.autorun(function () {
|
||||
const userId = this.userId;
|
||||
const nodeCursor = LibraryNodes.find({_id: libraryNodeId});
|
||||
let node = nodeCursor.fetch()[0];
|
||||
try { assertDocViewPermission(node, userId) }
|
||||
catch (e) {
|
||||
return this.error(e);
|
||||
}
|
||||
return [ nodeCursor ];
|
||||
});
|
||||
});
|
||||
|
||||
Meteor.publish('softRemovedLibraryNodes', function(libraryId){
|
||||
if (!libraryId) return [];
|
||||
libraryIdSchema.validate({libraryId});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { check } from 'meteor/check';
|
||||
import Libraries from '/imports/api/library/Libraries.js';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import getCreatureLibraryIds from '/imports/api/library/getCreatureLibraryIds.js';
|
||||
import getUserLibraryIds from '/imports/api/library/getUserLibraryIds.js';
|
||||
import { assertViewPermission } from '/imports/api/sharing/sharingPermissions.js';
|
||||
|
||||
Meteor.publish('selectedLibraryNodes', function(selectedNodeIds){
|
||||
@@ -37,7 +39,7 @@ Meteor.publish('selectedLibraryNodes', function(selectedNodeIds){
|
||||
})];
|
||||
});
|
||||
|
||||
Meteor.publish('searchLibraryNodes', function(){
|
||||
Meteor.publish('searchLibraryNodes', function(creatureId){
|
||||
let self = this;
|
||||
this.autorun(function (){
|
||||
let type = self.data('type');
|
||||
@@ -49,23 +51,12 @@ Meteor.publish('searchLibraryNodes', function(){
|
||||
}
|
||||
|
||||
// Get all the ids of libraries the user can access
|
||||
const user = Meteor.users.findOne(userId, {
|
||||
fields: {subscribedLibraries: 1}
|
||||
});
|
||||
if (!user) return [];
|
||||
|
||||
const subs = user.subscribedLibraries || [];
|
||||
let libraries = Libraries.find({
|
||||
$or: [
|
||||
{owner: this.userId},
|
||||
{writers: this.userId},
|
||||
{readers: this.userId},
|
||||
{_id: {$in: subs}},
|
||||
]
|
||||
}, {
|
||||
fields: {_id: 1, name: 1},
|
||||
});
|
||||
let libraryIds = libraries.map(lib => lib._id);
|
||||
let libraryIds;
|
||||
if (creatureId) {
|
||||
libraryIds = getCreatureLibraryIds(creatureId, userId)
|
||||
} else {
|
||||
libraryIds = getUserLibraryIds(userId)
|
||||
}
|
||||
|
||||
// Build a filter for nodes in those libraries that match the type
|
||||
let filter = {
|
||||
@@ -122,6 +113,7 @@ Meteor.publish('searchLibraryNodes', function(){
|
||||
});
|
||||
|
||||
let cursor = LibraryNodes.find(filter, options);
|
||||
const libraries = Libraries.find({ _id: { $in: libraryIds } });
|
||||
|
||||
Mongo.Collection._publishCursor(libraries, self, 'libraries');
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import CreatureLogs from '/imports/api/creature/log/CreatureLogs.js';
|
||||
import { assertViewPermission } from '/imports/api/creature/creatures/creaturePermissions.js';
|
||||
import computeCreature from '/imports/api/engine/computeCreature.js';
|
||||
import VERSION from '/imports/constants/VERSION.js';
|
||||
import { loadCreature } from '/imports/api/engine/loadCreatures.js';
|
||||
|
||||
let schema = new SimpleSchema({
|
||||
creatureId: {
|
||||
@@ -13,7 +15,8 @@ let schema = new SimpleSchema({
|
||||
},
|
||||
});
|
||||
|
||||
Meteor.publish('singleCharacter', function(creatureId){
|
||||
Meteor.publish('singleCharacter', function (creatureId) {
|
||||
const self = this;
|
||||
try {
|
||||
schema.validate({ creatureId });
|
||||
} catch (e){
|
||||
@@ -21,21 +24,27 @@ Meteor.publish('singleCharacter', function(creatureId){
|
||||
}
|
||||
this.autorun(function (computation){
|
||||
let userId = this.userId;
|
||||
let creatureCursor
|
||||
creatureCursor = Creatures.find({
|
||||
let permissionCreature = Creatures.findOne({
|
||||
_id: creatureId,
|
||||
}, {
|
||||
fields: { owner: 1, readers: 1, writers: 1, public: 1, computeVersion: 1 }
|
||||
});
|
||||
let creature = creatureCursor.fetch()[0];
|
||||
try { assertViewPermission(creature, userId) }
|
||||
catch(e){ return [] }
|
||||
if (creature.computeVersion !== VERSION && computation.firstRun){
|
||||
try { assertViewPermission(permissionCreature, userId) }
|
||||
catch (e) { return [] }
|
||||
loadCreature(creatureId, self);
|
||||
if (permissionCreature.computeVersion !== VERSION && computation.firstRun){
|
||||
try {
|
||||
computeCreature(creatureId)
|
||||
}
|
||||
catch(e){ console.error(e) }
|
||||
}
|
||||
return [
|
||||
creatureCursor,
|
||||
Creatures.find({
|
||||
_id: creatureId,
|
||||
}),
|
||||
CreatureVariables.find({
|
||||
_creatureId: creatureId,
|
||||
}),
|
||||
CreatureProperties.find({
|
||||
'ancestors.id': creatureId,
|
||||
}),
|
||||
|
||||
@@ -3,6 +3,8 @@ import Libraries from '/imports/api/library/Libraries.js';
|
||||
import LibraryNodes from '/imports/api/library/LibraryNodes.js';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import getSlotFillFilter from '/imports/api/creature/creatureProperties/methods/getSlotFillFilter.js'
|
||||
import getCreatureLibraryIds from '/imports/api/library/getCreatureLibraryIds.js';
|
||||
import { LIBRARY_NODE_TREE_FIELDS } from '/imports/server/publications/library.js';
|
||||
|
||||
Meteor.publish('slotFillers', function(slotId, searchTerm){
|
||||
if (searchTerm) check(searchTerm, String);
|
||||
@@ -20,21 +22,18 @@ Meteor.publish('slotFillers', function(slotId, searchTerm){
|
||||
}
|
||||
|
||||
// Get all the ids of libraries the user can access
|
||||
const user = Meteor.users.findOne(userId, {
|
||||
fields: {subscribedLibraries: 1}
|
||||
});
|
||||
const subs = user && user.subscribedLibraries || [];
|
||||
let libraries = Libraries.find({
|
||||
const creatureId = slot.ancestors[0].id;
|
||||
const libraryIds = getCreatureLibraryIds(creatureId, userId);
|
||||
const libraries = Libraries.find({
|
||||
$or: [
|
||||
{owner: this.userId},
|
||||
{writers: this.userId},
|
||||
{readers: this.userId},
|
||||
{_id: {$in: subs}},
|
||||
{ owner: userId },
|
||||
{ writers: userId },
|
||||
{ readers: userId },
|
||||
{ _id: { $in: libraryIds }, public: true },
|
||||
]
|
||||
}, {
|
||||
fields: {_id: 1, name: 1},
|
||||
sort: { name: 1 }
|
||||
});
|
||||
let libraryIds = libraries.map(lib => lib._id);
|
||||
|
||||
// Build a filter for nodes in those libraries that match the slot
|
||||
let filter = getSlotFillFilter({slot, libraryIds});
|
||||
@@ -50,7 +49,8 @@ Meteor.publish('slotFillers', function(slotId, searchTerm){
|
||||
options = {
|
||||
// relevant documents have a higher score.
|
||||
fields: {
|
||||
_score: { $meta: 'textScore' }
|
||||
_score: { $meta: 'textScore' },
|
||||
...LIBRARY_NODE_TREE_FIELDS,
|
||||
},
|
||||
sort: {
|
||||
// `score` property specified in the projection fields above.
|
||||
@@ -61,10 +61,13 @@ Meteor.publish('slotFillers', function(slotId, searchTerm){
|
||||
}
|
||||
} else {
|
||||
delete filter.$text
|
||||
options = {sort: {
|
||||
name: 1,
|
||||
order: 1,
|
||||
}};
|
||||
options = {
|
||||
sort: {
|
||||
name: 1,
|
||||
order: 1,
|
||||
},
|
||||
fields: LIBRARY_NODE_TREE_FIELDS,
|
||||
};
|
||||
}
|
||||
options.limit = limit;
|
||||
|
||||
@@ -72,7 +75,65 @@ Meteor.publish('slotFillers', function(slotId, searchTerm){
|
||||
self.setData('countAll', LibraryNodes.find(filter).count());
|
||||
});
|
||||
self.autorun(function () {
|
||||
Meteor._sleepForMs(1000);
|
||||
return [
|
||||
LibraryNodes.find(filter, options),
|
||||
libraries
|
||||
];
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Meteor.publish('classFillers', function(classId){
|
||||
let self = this;
|
||||
if (!classId) return [];
|
||||
|
||||
this.autorun(function (){
|
||||
let userId = this.userId;
|
||||
if (!userId) {
|
||||
return [];
|
||||
}
|
||||
// Get the class
|
||||
let classProp = CreatureProperties.findOne(classId);
|
||||
if (!classProp){
|
||||
return [];
|
||||
}
|
||||
|
||||
// Get all the ids of libraries the user can access
|
||||
const creatureId = classProp.ancestors[0].id;
|
||||
const libraryIds = getCreatureLibraryIds(creatureId, userId);
|
||||
const libraries = Libraries.find({
|
||||
$or: [
|
||||
{ owner: userId },
|
||||
{ writers: userId },
|
||||
{ readers: userId },
|
||||
{ _id: { $in: libraryIds }, public: true },
|
||||
]
|
||||
}, {
|
||||
sort: { name: 1 }
|
||||
});
|
||||
|
||||
// Build a filter for nodes in those libraries that match the slot
|
||||
let filter = getSlotFillFilter({slot: classProp, libraryIds});
|
||||
|
||||
this.autorun(function(){
|
||||
// Get the limit of the documents the user can fetch
|
||||
var limit = self.data('limit') || 50;
|
||||
check(limit, Number);
|
||||
|
||||
let options = {
|
||||
sort: {
|
||||
name: 1,
|
||||
order: 1,
|
||||
},
|
||||
fields: LIBRARY_NODE_TREE_FIELDS,
|
||||
limit,
|
||||
};
|
||||
|
||||
self.autorun(function () {
|
||||
self.setData('countAll', LibraryNodes.find(filter).count());
|
||||
});
|
||||
self.autorun(function () {
|
||||
return [LibraryNodes.find(filter, options), libraries];
|
||||
});
|
||||
});
|
||||
|
||||
7
app/imports/server/publications/userImages.js
Normal file
7
app/imports/server/publications/userImages.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import UserImages from '/imports/api/files/UserImages.js';
|
||||
|
||||
Meteor.publish('userImages', function () {
|
||||
return UserImages.find({
|
||||
userId: this.userId,
|
||||
}).cursor;
|
||||
});
|
||||
@@ -2,30 +2,33 @@ import SimpleSchema from 'simpl-schema';
|
||||
import '/imports/api/users/Users.js';
|
||||
import Invites from '/imports/api/users/Invites.js';
|
||||
|
||||
Meteor.publish('user', function(){
|
||||
return [
|
||||
Meteor.users.find(this.userId, {fields: {
|
||||
roles: 1,
|
||||
username: 1,
|
||||
apiKey: 1,
|
||||
darkMode: 1,
|
||||
subscribedLibraries: 1,
|
||||
fileStorageUsed: 1,
|
||||
profile: 1,
|
||||
preferences: 1,
|
||||
'services.patreon.id': 1,
|
||||
'services.patreon.entitledCents': 1,
|
||||
'services.patreon.entitledCentsOverride': 1,
|
||||
'services.google.id': 1,
|
||||
'services.google.picture': 1,
|
||||
'services.google.name': 1,
|
||||
'services.google.email': 1,
|
||||
'services.google.locale': 1,
|
||||
}}),
|
||||
Meteor.publish('user', function () {
|
||||
return [
|
||||
Meteor.users.find(this.userId, {
|
||||
fields: {
|
||||
roles: 1,
|
||||
username: 1,
|
||||
apiKey: 1,
|
||||
darkMode: 1,
|
||||
subscribedLibraries: 1,
|
||||
subscribedLibraryCollections: 1,
|
||||
fileStorageUsed: 1,
|
||||
profile: 1,
|
||||
preferences: 1,
|
||||
'services.patreon.id': 1,
|
||||
'services.patreon.entitledCents': 1,
|
||||
'services.patreon.entitledCentsOverride': 1,
|
||||
'services.google.id': 1,
|
||||
'services.google.picture': 1,
|
||||
'services.google.name': 1,
|
||||
'services.google.email': 1,
|
||||
'services.google.locale': 1,
|
||||
}
|
||||
}),
|
||||
Invites.find({
|
||||
$or: [
|
||||
{inviter: this.userId},
|
||||
{invitee: this.userId}
|
||||
{ inviter: this.userId },
|
||||
{ invitee: this.userId }
|
||||
],
|
||||
}, {
|
||||
fields: {
|
||||
@@ -40,19 +43,19 @@ let userIdsSchema = new SimpleSchema({
|
||||
type: Array,
|
||||
optional: true,
|
||||
},
|
||||
'ids.$':{
|
||||
'ids.$': {
|
||||
type: String,
|
||||
regEx: SimpleSchema.RegEx.Id,
|
||||
}
|
||||
})
|
||||
|
||||
Meteor.publish('userPublicProfiles', function(ids){
|
||||
userIdsSchema.validate({ids});
|
||||
if (!this.userId || !ids) return this.ready();
|
||||
return Meteor.users.find({
|
||||
_id: {$in: ids}
|
||||
},{
|
||||
fields: {username: 1},
|
||||
sort: {username: 1},
|
||||
});
|
||||
Meteor.publish('userPublicProfiles', function (ids) {
|
||||
userIdsSchema.validate({ ids });
|
||||
if (!this.userId || !ids) return this.ready();
|
||||
return Meteor.users.find({
|
||||
_id: { $in: ids }
|
||||
}, {
|
||||
fields: { username: 1 },
|
||||
sort: { username: 1 },
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import SimpleSchema from 'simpl-schema';
|
||||
import Creatures from '/imports/api/creature/creatures/Creatures.js';
|
||||
import CreatureProperties from '/imports/api/creature/creatureProperties/CreatureProperties.js';
|
||||
import CreatureVariables from '/imports/api/creature/creatures/CreatureVariables';
|
||||
import { assertViewPermission } from '/imports/api/creature/creatures/creaturePermissions.js';
|
||||
import computeCreature from '/imports/api/engine/computeCreature.js';
|
||||
import VERSION from '/imports/constants/VERSION.js';
|
||||
@@ -40,6 +41,9 @@ Meteor.publish('api-creature', function(creatureId){
|
||||
CreatureProperties.find({
|
||||
'ancestors.id': creatureId,
|
||||
}),
|
||||
CreatureVariables.find({
|
||||
_creatureId: creatureId,
|
||||
}),
|
||||
];
|
||||
}, {
|
||||
url: 'api/creature/:0'
|
||||
|
||||
Reference in New Issue
Block a user