mirror of
https://github.com/wekan/wekan.git
synced 2025-04-22 04:57:07 -04:00
Merge branch 'master' of github.com:wekan/wekan
This commit is contained in:
commit
5d6c68a9cf
8 changed files with 90 additions and 31 deletions
|
@ -309,26 +309,46 @@ BlazeComponent.extendComponent({
|
|||
events(start, end, timezone, callback) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const events = [];
|
||||
const pushEvent = function(card, title, start, end, extraCls) {
|
||||
start = start || card.startAt;
|
||||
end = end || card.endAt;
|
||||
title = title || card.title;
|
||||
const className =
|
||||
(extraCls ? `${extraCls} ` : '') +
|
||||
(card.color ? `calendar-event-${card.color}` : '');
|
||||
events.push({
|
||||
id: card._id,
|
||||
title,
|
||||
start,
|
||||
end: end || card.endAt,
|
||||
allDay:
|
||||
Math.abs(end.getTime() - start.getTime()) / 1000 === 24 * 3600,
|
||||
url: FlowRouter.url('card', {
|
||||
boardId: currentBoard._id,
|
||||
slug: currentBoard.slug,
|
||||
cardId: card._id,
|
||||
}),
|
||||
className,
|
||||
});
|
||||
};
|
||||
currentBoard
|
||||
.cardsInInterval(start.toDate(), end.toDate())
|
||||
.forEach(function(card) {
|
||||
events.push({
|
||||
id: card._id,
|
||||
title: card.title,
|
||||
start: card.startAt,
|
||||
end: card.endAt,
|
||||
allDay:
|
||||
Math.abs(card.endAt.getTime() - card.startAt.getTime()) /
|
||||
1000 ===
|
||||
24 * 3600,
|
||||
url: FlowRouter.url('card', {
|
||||
boardId: currentBoard._id,
|
||||
slug: currentBoard.slug,
|
||||
cardId: card._id,
|
||||
}),
|
||||
className: card.color ? `calendar-event-${card.color}` : null,
|
||||
});
|
||||
pushEvent(card);
|
||||
});
|
||||
currentBoard
|
||||
.cardsDueInBetween(start.toDate(), end.toDate())
|
||||
.forEach(function(card) {
|
||||
pushEvent(
|
||||
card,
|
||||
`${card.title} ${TAPi18n.__('card-due')}`,
|
||||
card.dueAt,
|
||||
new Date(card.dueAt.getTime() + 36e5),
|
||||
);
|
||||
});
|
||||
events.sort(function(first, second) {
|
||||
return first.id > second.id ? 1 : -1;
|
||||
});
|
||||
callback(events);
|
||||
},
|
||||
eventResize(event, delta, revertFunc) {
|
||||
|
|
|
@ -21,7 +21,15 @@ DatePicker = BlazeComponent.extendComponent({
|
|||
function(evt) {
|
||||
this.find('#date').value = moment(evt.date).format('L');
|
||||
this.error.set('');
|
||||
this.find('#time').focus();
|
||||
const timeInput = this.find('#time');
|
||||
timeInput.focus();
|
||||
if (!timeInput.value) {
|
||||
const currentHour = evt.date.getHours();
|
||||
const defaultMoment = moment(
|
||||
currentHour > 0 ? evt.date : '1970-01-01 08:00:00',
|
||||
); // default to 8:00 am local time
|
||||
timeInput.value = defaultMoment.format('LT');
|
||||
}
|
||||
}.bind(this),
|
||||
);
|
||||
|
||||
|
|
|
@ -731,12 +731,12 @@
|
|||
"almostdue": "current due time %s is approaching",
|
||||
"pastdue": "current due time %s is past",
|
||||
"duenow": "current due time %s is today",
|
||||
"act-newDue": "__card__ has 1st due reminder [__board__]",
|
||||
"act-withDue": "__card__ due reminders [__board__]",
|
||||
"act-newDue": "__list__/__card__ has 1st due reminder [__board__]",
|
||||
"act-withDue": "__list__/__card__ due reminders [__board__]",
|
||||
"act-almostdue": "was reminding the current due (__timeValue__) of __card__ is approaching",
|
||||
"act-pastdue": "was reminding the current due (__timeValue__) of __card__ is past",
|
||||
"act-duenow": "was reminding the current due (__timeValue__) of __card__ is now",
|
||||
"act-atUserComment": "You were mentioned in [__board__] __card__",
|
||||
"act-atUserComment": "You were mentioned in [__board__] __list__/__card__",
|
||||
"delete-user-confirm-popup": "Are you sure you want to delete this account? There is no undo.",
|
||||
"accounts-allowUserDelete": "Allow users to self delete their account",
|
||||
"hide-minicard-label-text": "Hide minicard label text",
|
||||
|
|
|
@ -289,6 +289,7 @@ if (Meteor.isServer) {
|
|||
activities: { $in: [description, 'all'] },
|
||||
}).fetch();
|
||||
if (integrations.length > 0) {
|
||||
params.watchers = watchers;
|
||||
integrations.forEach(integration => {
|
||||
Meteor.call(
|
||||
'outgoingWebhooks',
|
||||
|
|
|
@ -699,6 +699,13 @@ Boards.helpers({
|
|||
return result;
|
||||
},
|
||||
|
||||
cardsDueInBetween(start, end) {
|
||||
return Cards.find({
|
||||
boardId: this._id,
|
||||
dueAt: { $gte: start, $lte: end },
|
||||
});
|
||||
},
|
||||
|
||||
cardsInInterval(start, end) {
|
||||
return Cards.find({
|
||||
boardId: this._id,
|
||||
|
|
|
@ -1579,18 +1579,38 @@ const findDueCards = days => {
|
|||
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');
|
||||
if (!days) return;
|
||||
if (!days.map) days = [days];
|
||||
days.map(day => {
|
||||
let args = [];
|
||||
if (day === 0) {
|
||||
args = [then(0), then(1), 'duenow'];
|
||||
} else if (day > 0) {
|
||||
args = [then(1), then(day), 'almostdue'];
|
||||
} else {
|
||||
args = [then(day), now, 'pastdue'];
|
||||
}
|
||||
seekDue(...args);
|
||||
});
|
||||
};
|
||||
const addCronJob = _.debounce(
|
||||
Meteor.bindEnvironment(function findDueCardsDebounced() {
|
||||
const notifydays =
|
||||
parseInt(process.env.NOTIFY_DUE_DAYS_BEFORE_AND_AFTER, 10) || 2; // default as 2 days before and after
|
||||
if (!(notifydays > 0 && notifydays < 15)) {
|
||||
// notifying due is disabled
|
||||
const envValue = process.env.NOTIFY_DUE_DAYS_BEFORE_AND_AFTER;
|
||||
if (!envValue) {
|
||||
return;
|
||||
}
|
||||
const notifydays = envValue
|
||||
.split(',')
|
||||
.map(value => {
|
||||
const iValue = parseInt(value, 10);
|
||||
if (!(iValue > 0 && iValue < 15)) {
|
||||
// notifying due is disabled
|
||||
return false;
|
||||
} else {
|
||||
return iValue;
|
||||
}
|
||||
})
|
||||
.filter(Boolean);
|
||||
const notifyitvl = process.env.NOTIFY_DUE_AT_HOUR_OF_DAY; //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;
|
||||
|
|
|
@ -13,11 +13,14 @@ Meteor.startup(() => {
|
|||
const lan = user.getLanguage();
|
||||
const subject = TAPi18n.__(title, params, lan); // the original function has a fault, i believe the title should be used according to original author
|
||||
const existing = user.getEmailBuffer().length > 0;
|
||||
const text = `${existing ? `<br/>\n${subject}<br/>\n` : ''}${
|
||||
const htmlEnabled =
|
||||
Meteor.settings.public &&
|
||||
Meteor.settings.public.RICHER_CARD_COMMENT_EDITOR !== false;
|
||||
const text = `${existing ? `\n${subject}\n` : ''}${
|
||||
params.user
|
||||
} ${TAPi18n.__(description, quoteParams, lan)}<br/>\n${params.url}`;
|
||||
} ${TAPi18n.__(description, quoteParams, lan)}\n${params.url}`;
|
||||
|
||||
user.addEmailBuffer(text);
|
||||
user.addEmailBuffer(htmlEnabled ? text.replace(/\n/g, '<br/>') : text);
|
||||
|
||||
// unlike setTimeout(func, delay, args),
|
||||
// Meteor.setTimeout(func, delay) does not accept args :-(
|
||||
|
|
|
@ -108,7 +108,7 @@ DESCRIPTION_BIGEVENTS_PATTERN="Big events pattern: Notify always due etc regardl
|
|||
DEFAULT_BIGEVENTS_PATTERN="NONE"
|
||||
KEY_BIGEVENTS_PATTERN="bigevents-pattern"
|
||||
|
||||
DESCRIPTION_NOTIFY_DUE_DAYS_BEFORE_AND_AFTER="Notify due days, default 2 days before and after. 0 = due notifications disabled. Default: 2"
|
||||
DESCRIPTION_NOTIFY_DUE_DAYS_BEFORE_AND_AFTER="Notify due days, accepts ',' delimited string, i.e. 2,0 means notify will be sent out 2 days before and right on due day. Default: empty"
|
||||
DEFAULT_NOTIFY_DUE_DAYS_BEFORE_AND_AFTER=""
|
||||
KEY_NOTIFY_DUE_DAYS_BEFORE_AND_AFTER="notify-due-days-before-and-after"
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue