summaryrefslogtreecommitdiffstats
path: root/models/users.js
diff options
context:
space:
mode:
Diffstat (limited to 'models/users.js')
-rw-r--r--models/users.js278
1 files changed, 215 insertions, 63 deletions
diff --git a/models/users.js b/models/users.js
index 7e23835c..a1bc5b0f 100644
--- a/models/users.js
+++ b/models/users.js
@@ -1,3 +1,5 @@
+import { SyncedCron } from 'meteor/percolate:synced-cron';
+
// Sandstorm context is detected using the METEOR_SETTINGS environment variable
// in the package definition.
const isSandstorm =
@@ -165,7 +167,20 @@ Users.attachSchema(
/**
* enabled notifications for the user
*/
- type: [String],
+ type: [Object],
+ optional: true,
+ },
+ 'profile.notifications.$.activity': {
+ /**
+ * The id of the activity this notification references
+ */
+ type: String,
+ },
+ 'profile.notifications.$.read': {
+ /**
+ * the date on which this notification was read
+ */
+ type: Date,
optional: true,
},
'profile.showCardsCountAt': {
@@ -175,6 +190,13 @@ Users.attachSchema(
type: Number,
optional: true,
},
+ 'profile.startDayOfWeek': {
+ /**
+ * startDayOfWeek field of the user
+ */
+ type: Number,
+ optional: true,
+ },
'profile.starredBoards': {
/**
* list of starred board IDs
@@ -362,8 +384,8 @@ if (Meteor.isClient) {
return board && board.hasWorker(this._id);
},
- isBoardAdmin() {
- const board = Boards.findOne(Session.get('currentBoard'));
+ isBoardAdmin(boardId = Session.get('currentBoard')) {
+ const board = Boards.findOne(boardId);
return board && board.hasAdmin(this._id);
},
});
@@ -371,12 +393,20 @@ if (Meteor.isClient) {
Users.helpers({
boards() {
- return Boards.find({ 'members.userId': this._id });
+ return Boards.find(
+ { 'members.userId': this._id },
+ { sort: { sort: 1 /* boards default sorting */ } },
+ );
},
starredBoards() {
const { starredBoards = [] } = this.profile || {};
- return Boards.find({ archived: false, _id: { $in: starredBoards } });
+ return Boards.find(
+ { archived: false, _id: { $in: starredBoards } },
+ {
+ sort: { sort: 1 /* boards default sorting */ },
+ },
+ );
},
hasStarred(boardId) {
@@ -386,7 +416,12 @@ Users.helpers({
invitedBoards() {
const { invitedBoards = [] } = this.profile || {};
- return Boards.find({ archived: false, _id: { $in: invitedBoards } });
+ return Boards.find(
+ { archived: false, _id: { $in: invitedBoards } },
+ {
+ sort: { sort: 1 /* boards default sorting */ },
+ },
+ );
},
isInvitedTo(boardId) {
@@ -429,6 +464,20 @@ Users.helpers({
return _.contains(notifications, activityId);
},
+ notifications() {
+ const { notifications = [] } = this.profile || {};
+ for (const index in notifications) {
+ if (!notifications.hasOwnProperty(index)) continue;
+ const notification = notifications[index];
+ // this preserves their db sort order for editing
+ notification.dbIndex = index;
+ notification.activity = Activities.findOne(notification.activity);
+ }
+ // this sorts them newest to oldest to match Trello's behavior
+ notifications.reverse();
+ return notifications;
+ },
+
hasShowDesktopDragHandles() {
const profile = this.profile || {};
return profile.showDesktopDragHandles || false;
@@ -479,6 +528,15 @@ Users.helpers({
return profile.language || 'en';
},
+ getStartDayOfWeek() {
+ const profile = this.profile || {};
+ if (typeof profile.startDayOfWeek === 'undefined') {
+ // default is 'Monday' (1)
+ return 1;
+ }
+ return profile.startDayOfWeek;
+ },
+
getTemplatesBoardId() {
return (this.profile || {}).templatesBoardId;
},
@@ -573,7 +631,7 @@ Users.mutations({
addNotification(activityId) {
return {
$addToSet: {
- 'profile.notifications': activityId,
+ 'profile.notifications': { activity: activityId },
},
};
},
@@ -581,7 +639,7 @@ Users.mutations({
removeNotification(activityId) {
return {
$pull: {
- 'profile.notifications': activityId,
+ 'profile.notifications': { activity: activityId },
},
};
},
@@ -610,6 +668,10 @@ Users.mutations({
return { $set: { 'profile.showCardsCountAt': limit } };
},
+ setStartDayOfWeek(startDay) {
+ return { $set: { 'profile.startDayOfWeek': startDay } };
+ },
+
setBoardView(view) {
return {
$set: {
@@ -620,16 +682,6 @@ Users.mutations({
});
Meteor.methods({
- setUsername(username, userId) {
- check(username, String);
- check(userId, String);
- const nUsersWithUsername = Users.find({ username }).count();
- if (nUsersWithUsername > 0) {
- throw new Meteor.Error('username-already-taken');
- } else {
- Users.update(userId, { $set: { username } });
- }
- },
setListSortBy(value) {
check(value, String);
Meteor.user().setListSortBy(value);
@@ -650,51 +702,101 @@ Meteor.methods({
check(limit, Number);
Meteor.user().setShowCardsCountAt(limit);
},
- setEmail(email, userId) {
- if (Array.isArray(email)) {
- email = email.shift();
- }
- check(email, String);
- const existingUser = Users.findOne(
- { 'emails.address': email },
- { fields: { _id: 1 } },
- );
- if (existingUser) {
- throw new Meteor.Error('email-already-taken');
- } else {
- Users.update(userId, {
- $set: {
- emails: [
- {
- address: email,
- verified: false,
- },
- ],
- },
- });
- }
- },
- setUsernameAndEmail(username, email, userId) {
- check(username, String);
- if (Array.isArray(email)) {
- email = email.shift();
- }
- check(email, String);
- check(userId, String);
- Meteor.call('setUsername', username, userId);
- Meteor.call('setEmail', email, userId);
- },
- setPassword(newPassword, userId) {
- check(userId, String);
- check(newPassword, String);
- if (Meteor.user().isAdmin) {
- Accounts.setPassword(userId, newPassword);
- }
+ changeStartDayOfWeek(startDay) {
+ check(startDay, Number);
+ Meteor.user().setStartDayOfWeek(startDay);
},
});
if (Meteor.isServer) {
Meteor.methods({
+ setCreateUser(fullname, username, password, isAdmin, isActive, email) {
+ if (Meteor.user() && Meteor.user().isAdmin) {
+ check(fullname, String);
+ check(username, String);
+ check(password, String);
+ check(isAdmin, String);
+ check(isActive, String);
+ check(email, String);
+
+ const nUsersWithUsername = Users.find({ username }).count();
+ const nUsersWithEmail = Users.find({ email }).count();
+ if (nUsersWithUsername > 0) {
+ throw new Meteor.Error('username-already-taken');
+ } else if (nUsersWithEmail > 0) {
+ throw new Meteor.Error('email-already-taken');
+ } else {
+ Accounts.createUser({
+ fullname,
+ username,
+ password,
+ isAdmin,
+ isActive,
+ email: email.toLowerCase(),
+ from: 'admin',
+ });
+ }
+ }
+ },
+ setUsername(username, userId) {
+ if (Meteor.user() && Meteor.user().isAdmin) {
+ check(username, String);
+ check(userId, String);
+ const nUsersWithUsername = Users.find({ username }).count();
+ if (nUsersWithUsername > 0) {
+ throw new Meteor.Error('username-already-taken');
+ } else {
+ Users.update(userId, { $set: { username } });
+ }
+ }
+ },
+ setEmail(email, userId) {
+ if (Meteor.user() && Meteor.user().isAdmin) {
+ if (Array.isArray(email)) {
+ email = email.shift();
+ }
+ check(email, String);
+ const existingUser = Users.findOne(
+ { 'emails.address': email },
+ { fields: { _id: 1 } },
+ );
+ if (existingUser) {
+ throw new Meteor.Error('email-already-taken');
+ } else {
+ Users.update(userId, {
+ $set: {
+ emails: [
+ {
+ address: email,
+ verified: false,
+ },
+ ],
+ },
+ });
+ }
+ }
+ },
+ setUsernameAndEmail(username, email, userId) {
+ if (Meteor.user() && Meteor.user().isAdmin) {
+ check(username, String);
+ if (Array.isArray(email)) {
+ email = email.shift();
+ }
+ check(email, String);
+ check(userId, String);
+ Meteor.call('setUsername', username, userId);
+ Meteor.call('setEmail', email, userId);
+ }
+ },
+ setPassword(newPassword, userId) {
+ if (Meteor.user() && Meteor.user().isAdmin) {
+ check(userId, String);
+ check(newPassword, String);
+ if (Meteor.user().isAdmin) {
+ Accounts.setPassword(userId, newPassword);
+ }
+ }
+ },
// we accept userId, username, email
inviteUserToBoard(username, boardId) {
check(username, String);
@@ -726,8 +828,9 @@ if (Meteor.isServer) {
throw new Meteor.Error('error-user-notAllowSelf');
} else {
if (posAt <= 0) throw new Meteor.Error('error-user-doesNotExist');
- if (Settings.findOne().disableRegistration)
+ if (Settings.findOne({ disableRegistration: true })) {
throw new Meteor.Error('error-user-notCreated');
+ }
// Set in lowercase email before creating account
const email = username.toLowerCase();
username = email.substring(0, posAt);
@@ -748,6 +851,16 @@ if (Meteor.isServer) {
board.addMember(user._id);
user.addInvite(boardId);
+ //Check if there is a subtasks board
+ if (board.subtasksDefaultBoardId) {
+ const subBoard = Boards.findOne(board.subtasksDefaultBoardId);
+ //If there is, also add user to that board
+ if (subBoard) {
+ subBoard.addMember(user._id);
+ user.addInvite(subBoard._id);
+ }
+ }
+
try {
const params = {
user: user.username,
@@ -862,6 +975,39 @@ if (Meteor.isServer) {
});
}
+const addCronJob = _.debounce(
+ Meteor.bindEnvironment(function notificationCleanupDebounced() {
+ // passed in the removeAge has to be a number standing for the number of days after a notification is read before we remove it
+ const envRemoveAge =
+ process.env.NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE;
+ // default notifications will be removed 2 days after they are read
+ const defaultRemoveAge = 2;
+ const removeAge = parseInt(envRemoveAge, 10) || defaultRemoveAge;
+
+ SyncedCron.add({
+ name: 'notification_cleanup',
+ schedule: parser => parser.text('every 1 days'),
+ job: () => {
+ for (const user of Users.find()) {
+ if (!user.profile || !user.profile.notifications) continue;
+ for (const notification of user.profile.notifications) {
+ if (notification.read) {
+ const removeDate = new Date(notification.read);
+ removeDate.setDate(removeDate.getDate() + removeAge);
+ if (removeDate <= new Date()) {
+ user.removeNotification(notification.activity);
+ }
+ }
+ }
+ }
+ },
+ });
+
+ SyncedCron.start();
+ }),
+ 500,
+);
+
if (Meteor.isServer) {
// Let mongoDB ensure username unicity
Meteor.startup(() => {
@@ -875,6 +1021,9 @@ if (Meteor.isServer) {
},
{ unique: true },
);
+ Meteor.defer(() => {
+ addCronJob();
+ });
});
// OLD WAY THIS CODE DID WORK: When user is last admin of board,
@@ -1180,10 +1329,13 @@ if (Meteor.isServer) {
let data = Meteor.users.findOne({ _id: id });
if (data !== undefined) {
if (action === 'takeOwnership') {
- data = Boards.find({
- 'members.userId': id,
- 'members.isAdmin': true,
- }).map(function(board) {
+ data = Boards.find(
+ {
+ 'members.userId': id,
+ 'members.isAdmin': true,
+ },
+ { sort: { sort: 1 /* boards default sorting */ } },
+ ).map(function(board) {
if (board.hasMember(req.userId)) {
board.removeMember(req.userId);
}