summaryrefslogtreecommitdiffstats
path: root/models
diff options
context:
space:
mode:
authorSam X. Chen <sam.xi.chen@gmail.com>2019-07-09 16:36:50 -0400
committerSam X. Chen <sam.xi.chen@gmail.com>2019-07-09 16:36:50 -0400
commit2c44f834530d09cfc6645acb8dd84ffd9e4eeb6b (patch)
treebf979ad0958f8135a14f155515f6b59cc178298e /models
parenta545f8c1a2278f3f143c41abc32c394e75a4cd19 (diff)
downloadwekan-2c44f834530d09cfc6645acb8dd84ffd9e4eeb6b.tar.gz
wekan-2c44f834530d09cfc6645acb8dd84ffd9e4eeb6b.tar.bz2
wekan-2c44f834530d09cfc6645acb8dd84ffd9e4eeb6b.zip
Add Feature: system timelines will be showing any modification for duat startat endat receivedat, also notification to the watchers and if card is due, watchers will be notified
Diffstat (limited to 'models')
-rw-r--r--models/activities.js13
-rw-r--r--models/cards.js90
2 files changed, 101 insertions, 2 deletions
diff --git a/models/activities.js b/models/activities.js
index e76f3ad1..3ad316a7 100644
--- a/models/activities.js
+++ b/models/activities.js
@@ -197,6 +197,18 @@ if (Meteor.isServer) {
// params.label = label.name;
// params.labelId = activity.labelId;
//}
+ if (
+ (!activity.timeKey || activity.timeKey === 'dueAt') &&
+ activity.timeValue
+ ) {
+ // due time reminder
+ title = 'act-withDue';
+ }
+ ['timeValue', 'timeOldValue'].forEach(key => {
+ // copy time related keys & values to params
+ const value = activity[key];
+ if (value) params[key] = value;
+ });
if (board) {
const watchingUsers = _.pluck(
_.where(board.watchers, { level: 'watching' }),
@@ -212,7 +224,6 @@ if (Meteor.isServer) {
_.intersection(participants, trackingUsers),
);
}
-
Notifications.getUsers(watchers).forEach(user => {
Notifications.notify(user, title, description, params);
});
diff --git a/models/cards.js b/models/cards.js
index 211618a1..115bed7c 100644
--- a/models/cards.js
+++ b/models/cards.js
@@ -1553,6 +1553,60 @@ function cardRemover(userId, doc) {
});
}
+const findDueCards = days => {
+ const seekDue = ($from, $to, activityType) => {
+ Cards.find({
+ dueAt: { $gte: $from, $lt: $to },
+ }).forEach(card => {
+ const username = Users.findOne(card.userId).username;
+ const activity = {
+ userId: card.userId,
+ username,
+ activityType,
+ boardId: card.boardId,
+ cardId: card._id,
+ cardTitle: card.title,
+ listId: card.listId,
+ timeValue: card.dueAt,
+ swimlaneId: card.swimlaneId,
+ };
+ Activities.insert(activity);
+ });
+ };
+ const now = new Date(),
+ aday = 3600 * 24 * 1e3,
+ then = day => new Date(now.setHours(0, 0, 0, 0) + day * aday);
+ seekDue(then(1), then(days), 'almostdue');
+ seekDue(then(0), then(1), 'duenow');
+ seekDue(then(-days), now, 'pastdue');
+};
+const addCronJob = _.debounce(
+ Meteor.bindEnvironment(function findDueCardsDebounced() {
+ const notifydays = parseInt(process.env.NOTIFY_DUE_DAYS, 10) || 2; // default as 2 days b4 and after
+ if (!(notifydays > 0 && notifydays < 15)) {
+ // notifying due is disabled
+ return;
+ }
+ const notifyitvl = process.env.NOTIFY_DUE_ITVL; //passed in the itvl has to be a number standing for the hour of current time
+ const defaultitvl = 8; // default every morning at 8am, if the passed env variable has parsing error use default
+ const itvl = parseInt(notifyitvl, 10) || defaultitvl;
+ const scheduler = (job => () => {
+ const now = new Date();
+ const hour = 3600 * 1e3;
+ if (now.getHours() === itvl) {
+ if (typeof job === 'function') {
+ job();
+ }
+ }
+ Meteor.setTimeout(scheduler, hour);
+ })(() => {
+ findDueCards(notifydays);
+ });
+ scheduler();
+ }),
+ 500,
+);
+
if (Meteor.isServer) {
// Cards are often fetched within a board, so we create an index to make these
// queries more efficient.
@@ -1565,12 +1619,17 @@ if (Meteor.isServer) {
// With a huge database, this result in a very slow app and high CPU on the mongodb side.
// To correct it, add Index to parentId:
Cards._collection._ensureIndex({ parentId: 1 });
+ /*let notifydays = parseInt(process.env.NOTIFY_DUE_DAYS) || 2; // default as 2 days b4 and after
+ let notifyitvl = parseInt(process.env.NOTIFY_DUE_ITVL) || 3600 * 24 * 1e3; // default interval as one day
+ Meteor.call("findDueCards",notifydays,notifyitvl);*/
+ Meteor.defer(() => {
+ addCronJob();
+ });
});
Cards.after.insert((userId, doc) => {
cardCreation(userId, doc);
});
-
// New activity for card (un)archivage
Cards.after.update((userId, doc, fieldNames) => {
cardState(userId, doc, fieldNames);
@@ -1600,6 +1659,35 @@ if (Meteor.isServer) {
cardCustomFields(userId, doc, fieldNames, modifier);
});
+ // Add a new activity if modify time related field like dueAt startAt etc
+ Cards.before.update((userId, doc, fieldNames, modifier) => {
+ const dla = 'dateLastActivity';
+ const fields = fieldNames.filter(name => name !== dla);
+ const timingaction = ['receivedAt', 'dueAt', 'startAt', 'endAt'];
+ const action = fields[0];
+ if (fields.length > 0 && _.contains(timingaction, action)) {
+ // add activities for user change these attributes
+ const value = modifier.$set[action];
+ const oldvalue = doc[action] || '';
+ const activityType = `a-${action}`;
+ const card = Cards.findOne(doc._id);
+ const username = Users.findOne(userId).username;
+ const activity = {
+ userId,
+ username,
+ activityType,
+ boardId: doc.boardId,
+ cardId: doc._id,
+ cardTitle: doc.title,
+ timeKey: action,
+ timeValue: value,
+ timeOldValue: oldvalue,
+ listId: card.listId,
+ swimlaneId: card.swimlaneId,
+ };
+ Activities.insert(activity);
+ }
+ });
// Remove all activities associated with a card if we remove the card
// Remove also card_comments / checklists / attachments
Cards.before.remove((userId, doc) => {