Add a new SessionData collection and limit user fields

* Add new SessionData collection to store user session data available to
server and client
* Limit the Users fields sent to the client by `myCards`, `dueCards`,
`brokenCards`, and `globalSearch` using new `Users.safeFields`
* clean-up
This commit is contained in:
John R. Supplee 2021-01-16 19:20:31 +02:00
parent ab183acac3
commit ff626fb559
5 changed files with 113 additions and 81 deletions

View file

@ -50,12 +50,11 @@ BlazeComponent.extendComponent({
results() { results() {
if (this.queryParams) { if (this.queryParams) {
const results = Cards.globalSearch(this.queryParams); const results = Cards.globalSearch(this.queryParams);
const sessionData = SessionData.findOne({ userId: Meteor.userId() });
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('user:', Meteor.user()); console.log('sessionData:', sessionData);
// eslint-disable-next-line no-console
// console.log('user:', Meteor.user().sessionData);
// console.log('errors:', results.errors); // console.log('errors:', results.errors);
this.totalHits.set(Meteor.user().sessionData.totalHits); this.totalHits.set(sessionData.totalHits);
this.resultsCount.set(results.cards.count()); this.resultsCount.set(results.cards.count());
this.queryErrors.set(results.errors); this.queryErrors.set(results.errors);
return results.cards; return results.cards;

View file

@ -1914,14 +1914,6 @@ Cards.globalSearch = queryParams => {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('count:', cards.count()); // console.log('count:', cards.count());
if (Meteor.isServer) {
Users.update(userId, {
$set: {
'sessionData.totalHits': cards.count(),
'sessionData.lastHit': cards.count() > 50 ? 50 : cards.count(),
},
});
}
return { cards, errors }; return { cards, errors };
}; };

View file

@ -377,6 +377,14 @@ Users.initEasySearch(searchInFields, {
returnFields: [...searchInFields, 'profile.avatarUrl'], returnFields: [...searchInFields, 'profile.avatarUrl'],
}); });
Users.safeFields = {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
};
if (Meteor.isClient) { if (Meteor.isClient) {
Users.helpers({ Users.helpers({
isBoardMember() { isBoardMember() {

73
models/usersessiondata.js Normal file
View file

@ -0,0 +1,73 @@
SessionData = new Mongo.Collection('sessiondata');
/**
* A UserSessionData in Wekan. Organization in Trello.
*/
SessionData.attachSchema(
new SimpleSchema({
_id: {
/**
* the organization id
*/
type: Number,
optional: true,
// eslint-disable-next-line consistent-return
autoValue() {
if (this.isInsert && !this.isSet) {
return incrementCounter('counters', 'orgId', 1);
}
},
},
userId: {
/**
* userId of the user
*/
type: String,
optional: false,
},
totalHits: {
/**
* total number of hits in the last report query
*/
type: Number,
optional: true,
},
lastHit: {
/**
* the last hit returned from a report query
*/
type: Number,
optional: true,
},
createdAt: {
/**
* creation date of the team
*/
type: Date,
// eslint-disable-next-line consistent-return
autoValue() {
if (this.isInsert) {
return new Date();
} else if (this.isUpsert) {
return { $setOnInsert: new Date() };
} else {
this.unset();
}
},
},
modifiedAt: {
type: Date,
denyUpdate: false,
// eslint-disable-next-line consistent-return
autoValue() {
if (this.isInsert || this.isUpsert || this.isUpdate) {
return new Date();
} else {
this.unset();
}
},
},
}),
);
export default SessionData;

View file

@ -72,18 +72,7 @@ Meteor.publish('myCards', function() {
Boards.find({ _id: { $in: boards } }), Boards.find({ _id: { $in: boards } }),
Swimlanes.find({ _id: { $in: swimlanes } }), Swimlanes.find({ _id: { $in: swimlanes } }),
Lists.find({ _id: { $in: lists } }), Lists.find({ _id: { $in: lists } }),
Users.find( Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
{ _id: { $in: users } },
{
fields: {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
},
},
),
]; ];
}); });
@ -93,18 +82,7 @@ Meteor.publish('dueCards', function(allUsers = false) {
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
// console.log('all users:', allUsers); // console.log('all users:', allUsers);
const user = Users.findOne( const user = Users.findOne({ _id: this.userId });
{ _id: this.userId },
{
fields: {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
},
},
);
const archivedBoards = []; const archivedBoards = [];
Boards.find({ archived: true }).forEach(board => { Boards.find({ archived: true }).forEach(board => {
@ -115,14 +93,12 @@ Meteor.publish('dueCards', function(allUsers = false) {
let selector = { let selector = {
archived: false, archived: false,
}; };
// for admins and users, allow her to see cards only from boards where
// she is a member
//if (!user.isAdmin) {
selector.$or = [ selector.$or = [
{ permission: 'public' }, { permission: 'public' },
{ members: { $elemMatch: { userId: user._id, isActive: true } } }, { members: { $elemMatch: { userId: user._id, isActive: true } } },
]; ];
//}
Boards.find(selector).forEach(board => { Boards.find(selector).forEach(board => {
permiitedBoards.push(board._id); permiitedBoards.push(board._id);
}); });
@ -193,18 +169,7 @@ Meteor.publish('dueCards', function(allUsers = false) {
Boards.find({ _id: { $in: boards } }), Boards.find({ _id: { $in: boards } }),
Swimlanes.find({ _id: { $in: swimlanes } }), Swimlanes.find({ _id: { $in: swimlanes } }),
Lists.find({ _id: { $in: lists } }), Lists.find({ _id: { $in: lists } }),
Users.find( Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
{ _id: { $in: users } },
{
fields: {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
},
},
),
]; ];
}); });
@ -216,6 +181,25 @@ Meteor.publish('globalSearch', function(queryParams) {
const cards = Cards.globalSearch(queryParams).cards; const cards = Cards.globalSearch(queryParams).cards;
SessionData.upsert(
{ userId: this.userId },
{
$set: {
totalHits: cards.count(),
lastHit: cards.count() > 50 ? 50 : cards.count(),
},
},
);
// eslint-disable-next-line no-console
console.log('SessionData:', SessionData.find().fetch());
// Users.update(this.userId, {
// $set: {
// 'sessionData.totalHits': cards.count(),
// 'sessionData.lastHit': cards.count() > 50 ? 50 : cards.count(),
// },
// });
const boards = []; const boards = [];
const swimlanes = []; const swimlanes = [];
const lists = []; const lists = [];
@ -244,34 +228,21 @@ Meteor.publish('globalSearch', function(queryParams) {
Boards.find({ _id: { $in: boards } }), Boards.find({ _id: { $in: boards } }),
Swimlanes.find({ _id: { $in: swimlanes } }), Swimlanes.find({ _id: { $in: swimlanes } }),
Lists.find({ _id: { $in: lists } }), Lists.find({ _id: { $in: lists } }),
Users.find({ _id: { $in: users } }), Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
SessionData.find({ userId: this.userId }),
]; ];
}); });
Meteor.publish('brokenCards', function() { Meteor.publish('brokenCards', function() {
const user = Users.findOne( const user = Users.findOne({ _id: this.userId });
{ _id: this.userId },
{
fields: {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
},
},
);
const permiitedBoards = [null]; const permiitedBoards = [null];
let selector = {}; let selector = {};
// for admins and users, if user is not an admin allow her to see cards only from boards where
// she is a member
//if (!user.isAdmin) {
selector.$or = [ selector.$or = [
{ permission: 'public' }, { permission: 'public' },
{ members: { $elemMatch: { userId: user._id, isActive: true } } }, { members: { $elemMatch: { userId: user._id, isActive: true } } },
]; ];
//}
Boards.find(selector).forEach(board => { Boards.find(selector).forEach(board => {
permiitedBoards.push(board._id); permiitedBoards.push(board._id);
}); });
@ -328,17 +299,6 @@ Meteor.publish('brokenCards', function() {
Boards.find({ _id: { $in: boards } }), Boards.find({ _id: { $in: boards } }),
Swimlanes.find({ _id: { $in: swimlanes } }), Swimlanes.find({ _id: { $in: swimlanes } }),
Lists.find({ _id: { $in: lists } }), Lists.find({ _id: { $in: lists } }),
Users.find( Users.find({ _id: { $in: users } }, { fields: Users.safeFields }),
{ _id: { $in: users } },
{
fields: {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.avatarUrl': 1,
'profile.initials': 1,
},
},
),
]; ];
}); });