mirror of
https://github.com/inverse-inc/sogo.git
synced 2026-04-04 12:58:50 +00:00
feat(mail): enable autoreply on specific days or at a specific time
Fixes #5328
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSCharacterSet.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSURL.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
@@ -946,14 +947,14 @@ static NSString *sieveScriptName = @"sogo";
|
||||
dateCapability || [[values objectForKey: @"endDate"] intValue] > now))
|
||||
{
|
||||
NSCalendarDate *startDate, *endDate;
|
||||
NSMutableArray *allConditions;
|
||||
NSMutableArray *allConditions, *timeConditions;
|
||||
NSMutableString *vacation_script;
|
||||
NSArray *addresses;
|
||||
NSString *text, *templateFilePath, *customSubject;
|
||||
NSArray *addresses, *weekdays;
|
||||
NSString *text, *templateFilePath, *customSubject, *weekday, *startTime, *endTime, *timeCondition, *timeZone;
|
||||
SOGoTextTemplateFile *templateFile;
|
||||
|
||||
BOOL ignore, alwaysSend, useCustomSubject, discardMails;
|
||||
int days, i;
|
||||
int days, i, seconds;
|
||||
|
||||
allConditions = [NSMutableArray array];
|
||||
days = [[values objectForKey: @"daysBetweenResponse"] intValue];
|
||||
@@ -1009,30 +1010,95 @@ static NSString *sieveScriptName = @"sogo";
|
||||
[allConditions addObject: @"not header :comparator \"i;ascii-casemap\" :matches \"To\" \"Multiple recipients of*\""];
|
||||
}
|
||||
|
||||
// Start date of auto-reply
|
||||
if ([dd vacationPeriodEnabled] &&
|
||||
[[values objectForKey: @"startDateEnabled"] boolValue] &&
|
||||
dateCapability)
|
||||
if ([dd vacationPeriodEnabled] && dateCapability)
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
startDate = [NSCalendarDate dateWithTimeIntervalSince1970:
|
||||
[[values objectForKey: @"startDate"] intValue]];
|
||||
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"ge\" \"date\" \"%@\"",
|
||||
[startDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
|
||||
}
|
||||
// Start date of auto-reply
|
||||
if ([[values objectForKey: @"startDateEnabled"] boolValue])
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
startDate = [NSCalendarDate dateWithTimeIntervalSince1970:
|
||||
[[values objectForKey: @"startDate"] intValue]];
|
||||
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"ge\" \"date\" \"%@\"",
|
||||
[startDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
|
||||
}
|
||||
|
||||
// End date of auto-reply
|
||||
if ([dd vacationPeriodEnabled] &&
|
||||
[[values objectForKey: @"endDateEnabled"] boolValue] &&
|
||||
dateCapability)
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
endDate = [NSCalendarDate dateWithTimeIntervalSince1970:
|
||||
[[values objectForKey: @"endDate"] intValue]];
|
||||
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"le\" \"date\" \"%@\"",
|
||||
[endDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
|
||||
// End date of auto-reply
|
||||
if ([[values objectForKey: @"endDateEnabled"] boolValue])
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
endDate = [NSCalendarDate dateWithTimeIntervalSince1970:
|
||||
[[values objectForKey: @"endDate"] intValue]];
|
||||
[allConditions addObject: [NSString stringWithFormat: @"currentdate :value \"le\" \"date\" \"%@\"",
|
||||
[endDate descriptionWithCalendarFormat: @"%Y-%m-%d"]]];
|
||||
}
|
||||
|
||||
seconds = [[ud timeZone] secondsFromGMT];
|
||||
timeZone = [NSString stringWithFormat: @"%.2i%02i", seconds/60/60, seconds/60%60];
|
||||
timeConditions = [NSMutableArray array];
|
||||
startTime = endTime = nil;
|
||||
|
||||
// Start auto-reply from a specific time
|
||||
if ([[values objectForKey: @"startTimeEnabled"] boolValue])
|
||||
{
|
||||
startTime = [values objectForKey: @"startTime"];
|
||||
timeCondition = [NSString stringWithFormat: @"date :value \"ge\" :zone \"%@\" \"date\" \"time\" \"%@:00\"",
|
||||
timeZone, startTime];
|
||||
[timeConditions addObject: timeCondition];
|
||||
}
|
||||
|
||||
// Stop auto-reply at a specific time
|
||||
if ([[values objectForKey: @"endTimeEnabled"] boolValue])
|
||||
{
|
||||
endTime = [values objectForKey: @"endTime"];
|
||||
timeCondition = [NSString stringWithFormat: @"date :value \"lt\" :zone \"%@\" \"date\" \"time\" \"%@:00\"",
|
||||
timeZone, endTime];
|
||||
[timeConditions addObject: timeCondition];
|
||||
}
|
||||
|
||||
if (startTime && endTime)
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
if ([startTime compare: endTime] == NSOrderedAscending)
|
||||
{
|
||||
// Start time is before end time:
|
||||
// >= startTime && < endTime
|
||||
[allConditions addObjectsFromArray: timeConditions];
|
||||
}
|
||||
else
|
||||
{
|
||||
// End time is before start time:
|
||||
// >= startTime || < endTime
|
||||
timeCondition = [NSString stringWithFormat: @"anyof ( %@ )", [timeConditions componentsJoinedByString: @", "]];
|
||||
[allConditions addObject: timeCondition];
|
||||
}
|
||||
}
|
||||
else if ([timeConditions count])
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
[allConditions addObjectsFromArray: timeConditions];
|
||||
}
|
||||
|
||||
// Auto-reply during specific days
|
||||
if ([[values objectForKey: @"weekdaysEnabled"] boolValue])
|
||||
{
|
||||
[req addObjectUniquely: @"date"];
|
||||
[req addObjectUniquely: @"relational"];
|
||||
weekdays = [values objectForKey: @"days"];
|
||||
NSMutableString *currentWeekday = [NSMutableString stringWithString: @"currentdate :is \"weekday\" ["];
|
||||
for (i = 0; i < [weekdays count]; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
[currentWeekday appendString: @", "];
|
||||
weekday = [weekdays objectAtIndex: i];
|
||||
[currentWeekday appendString: [weekday asSieveQuotedString]];
|
||||
}
|
||||
[currentWeekday appendString: @"]"];
|
||||
[allConditions addObject: currentWeekday];
|
||||
}
|
||||
}
|
||||
|
||||
// Apply conditions
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
/*
|
||||
Copyright (C) 2004-2005 SKYRIX Software AG
|
||||
Copyright (C) 2007-2016 Inverse inc.
|
||||
Copyright (C) 2007-2021 Inverse inc.
|
||||
|
||||
SOGo is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by the
|
||||
@@ -18,6 +17,7 @@
|
||||
02111-1307, USA.
|
||||
*/
|
||||
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
|
||||
#import <NGObjWeb/NSException+HTTP.h>
|
||||
#import <NGObjWeb/SoSecurityManager.h>
|
||||
@@ -674,6 +674,14 @@
|
||||
return [NSString stringWithFormat: @"urn:uuid:%@", nameInContainer];
|
||||
}
|
||||
|
||||
- (NSString *) davCalendarTimeZone
|
||||
{
|
||||
NSTimeZone *tz = [[[context activeUser] userDefaults] timeZone];
|
||||
int secs = [tz secondsFromGMT];
|
||||
|
||||
return [NSString stringWithFormat: @"%02i%02i", secs / 60 / 60, abs(secs % 60)];
|
||||
}
|
||||
|
||||
// - (NSException *) setDavSignature: (NSString *) newSignature
|
||||
// {
|
||||
// SOGoUserDefaults *ud;
|
||||
|
||||
@@ -17,6 +17,7 @@ class TestUtility {
|
||||
url: `${this.webdav.serverUrl}/SOGo/dav/${login}/`,
|
||||
props: [
|
||||
{ name: 'displayname', namespace: DAVNamespace.DAV },
|
||||
{ name: 'calendar-timezone', namespace: DAVNamespace.CALDAV },
|
||||
{ name: 'calendar-user-address-set', namespace: DAVNamespace.CALDAV }
|
||||
],
|
||||
depth: '0',
|
||||
@@ -33,7 +34,8 @@ class TestUtility {
|
||||
|
||||
let displayname = response.props.displayname || ''
|
||||
let email = response.props.calendarUserAddressSet.href[0]
|
||||
this.userInfo[login] = { displayname: displayname, email: email }
|
||||
let timezone = response.props.calendarTimezone || ''
|
||||
this.userInfo[login] = { displayname, email, timezone }
|
||||
}
|
||||
return this.userInfo[login]
|
||||
}
|
||||
|
||||
@@ -27,15 +27,23 @@ describe('Sieve', function() {
|
||||
// kill existing filters
|
||||
await prefs.setOrCreate('SOGoSieveFilters', [], ['defaults'])
|
||||
// vacation filters
|
||||
await prefs.setOrCreate('enabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('autoReplyText', '', ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('customSubjectEnabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('customSubject', '', ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('autoReplyEmailAddresses', [], ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('daysBetweenResponse', 7, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('ignoreLists', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('startDateEnabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('startDate', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('startTimeEnabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('startTime', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('endDateEnabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('endDate', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('enabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('endTimeEnabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('endTime', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('weekdaysEnabled', 0, ['defaults', 'Vacation'])
|
||||
await prefs.setOrCreate('days', [], ['defaults', 'Vacation'])
|
||||
// forwarding filters
|
||||
await prefs.setOrCreate('forwardAddress', [], ['defaults', 'Forward'])
|
||||
await prefs.setOrCreate('keepCopy', 0, ['defaults', 'Forward'])
|
||||
@@ -100,6 +108,38 @@ describe('Sieve', function() {
|
||||
.toBe(sieveVacationIgnoreLists)
|
||||
})
|
||||
|
||||
it('enable vacation script - activation constraints', async function() {
|
||||
const vacationMsg = 'vacation test - activation constraints'
|
||||
const daysInterval = 2
|
||||
const mailaddr = user.email.replace(/mailto:/, '')
|
||||
const now = new Date()
|
||||
const tomorrow = new Date(now.getTime() + 1000*60*60*24)
|
||||
const startDate = tomorrow.getFullYear() + '-' + [
|
||||
'0' + (tomorrow.getMonth() + 1),
|
||||
'0' + tomorrow.getDate()
|
||||
].map(component => component.slice(-2)).join('-')
|
||||
const startTime = '17:00'
|
||||
const timezone = (user.timezone < 0 ? '-':'') + ('000' + Math.abs(user.timezone)).slice(-4)
|
||||
const sieveVacationConstraints = `require ["vacation","date","relational"];\r\nif allof ( currentdate :value "ge" "date" "${startDate}", date :value "ge" :zone "${timezone}" "date" "time" "${startTime}:00" ) { vacation :days ${daysInterval} :addresses ["${mailaddr}"] text:\r\n${vacationMsg}\r\n.\r\n;\r\n}\r\n`
|
||||
let vacation
|
||||
|
||||
vacation = await prefs.get('Vacation')
|
||||
vacation.enabled = 1
|
||||
await prefs.setNoSave('autoReplyText', vacationMsg)
|
||||
await prefs.setNoSave('daysBetweenResponse', daysInterval)
|
||||
await prefs.setNoSave('autoReplyEmailAddresses', [mailaddr])
|
||||
await prefs.setNoSave('startDateEnabled', 1)
|
||||
await prefs.setNoSave('startDate', tomorrow.getTime() / 1000)
|
||||
await prefs.setNoSave('startTimeEnabled', 1)
|
||||
await prefs.setNoSave('startTime', startTime)
|
||||
await prefs.save()
|
||||
|
||||
const createdScript = await _getSogoSieveScript()
|
||||
expect(createdScript)
|
||||
.withContext(`sogo Sieve script`)
|
||||
.toBe(sieveVacationConstraints)
|
||||
})
|
||||
|
||||
it('enable simple forwarding', async function() {
|
||||
const redirectMailaddr = 'nonexistent@inverse.com'
|
||||
const sieveSimpleForward = `redirect "${redirectMailaddr}";\r\n`
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#import <Foundation/NSCalendarDate.h>
|
||||
#import <Foundation/NSDictionary.h>
|
||||
#import <Foundation/NSTimeZone.h>
|
||||
#import <Foundation/NSUserDefaults.h>
|
||||
#import <Foundation/NSValue.h>
|
||||
|
||||
@@ -44,6 +45,10 @@
|
||||
|
||||
#import "SOGoTool.h"
|
||||
|
||||
#define statusquoAutoReply 0
|
||||
#define enableAutoReply 1
|
||||
#define disableAutoReply 2
|
||||
|
||||
@interface SOGoToolUpdateAutoReply : SOGoTool
|
||||
@end
|
||||
|
||||
@@ -73,6 +78,103 @@
|
||||
"The update-autoreply action should be configured as a daily cronjob.\n");
|
||||
}
|
||||
|
||||
- (BOOL) checkConstraintsForRow: (NSDictionary *) infos
|
||||
{
|
||||
NSArray *weekdays, *startTime, *endTime;
|
||||
NSCalendarDate *now, *startDate, *endDate;
|
||||
NSDictionary *defaults, *vacationOptions;
|
||||
NSString *c_defaults;
|
||||
NSTimeZone *timeZone;
|
||||
unsigned int beginOfDaysSecs, endDateTime, startDateTime, result;
|
||||
|
||||
result = statusquoAutoReply;
|
||||
c_defaults = [infos objectForKey: @"c_defaults"];
|
||||
startDate = endDate = nil;
|
||||
|
||||
if ([c_defaults isNotNull])
|
||||
{
|
||||
defaults = [c_defaults objectFromJSONString];
|
||||
vacationOptions = (NSDictionary *) [defaults objectForKey: @"Vacation"];
|
||||
if ([[vacationOptions objectForKey: @"enabled"] boolValue])
|
||||
{
|
||||
timeZone = [NSTimeZone timeZoneWithName: (NSString *)[defaults objectForKey: @"SOGoTimeZone"]];
|
||||
now = [NSCalendarDate calendarDate];
|
||||
[now setTimeZone: timeZone];
|
||||
|
||||
beginOfDaysSecs = [[now beginOfDay] timeIntervalSince1970];
|
||||
|
||||
// We handle the start date
|
||||
if ([[vacationOptions objectForKey: @"startDateEnabled"] boolValue])
|
||||
{
|
||||
startDateTime = [[vacationOptions objectForKey: @"startDate"] intValue];
|
||||
if (beginOfDaysSecs >= startDateTime)
|
||||
result = enableAutoReply;
|
||||
else
|
||||
result = disableAutoReply;
|
||||
}
|
||||
// We handle the end date
|
||||
if ([[vacationOptions objectForKey: @"endDateEnabled"] boolValue])
|
||||
{
|
||||
endDateTime = [[vacationOptions objectForKey: @"endDate"] intValue];
|
||||
if (endDateTime < beginOfDaysSecs)
|
||||
result = disableAutoReply;
|
||||
}
|
||||
if (result != disableAutoReply)
|
||||
{
|
||||
// We handle the start time
|
||||
if ([[vacationOptions objectForKey: @"startTimeEnabled"] boolValue])
|
||||
{
|
||||
startTime = [[vacationOptions objectForKey: @"startTime"] componentsSeparatedByString: @":"];
|
||||
startDate = [NSCalendarDate dateWithYear: [now yearOfCommonEra]
|
||||
month: [now monthOfYear]
|
||||
day: [now dayOfMonth]
|
||||
hour: [[startTime objectAtIndex: 0] intValue]
|
||||
minute: [[startTime objectAtIndex: 1] intValue]
|
||||
second: [now secondOfMinute]
|
||||
timeZone: [now timeZone]];
|
||||
if ([startDate compare: now] == NSOrderedSame ||
|
||||
[startDate compare: now] == NSOrderedAscending)
|
||||
result = enableAutoReply;
|
||||
}
|
||||
// We handle the end time
|
||||
// NOTE: if end time is enabled, start time must be defined
|
||||
if ([[vacationOptions objectForKey: @"endTimeEnabled"] boolValue])
|
||||
{
|
||||
endTime = [[vacationOptions objectForKey: @"endTime"] componentsSeparatedByString: @":"];
|
||||
endDate = [NSCalendarDate dateWithYear: [now yearOfCommonEra]
|
||||
month: [now monthOfYear]
|
||||
day: [now dayOfMonth]
|
||||
hour: [[endTime objectAtIndex: 0] intValue]
|
||||
minute: [[endTime objectAtIndex: 1] intValue]
|
||||
second: [now secondOfMinute]
|
||||
timeZone: [now timeZone]];
|
||||
if ([endDate compare: now] == NSOrderedSame ||
|
||||
[endDate compare: now] == NSOrderedAscending)
|
||||
{
|
||||
if ([startDate compare: endDate] == NSOrderedAscending ||
|
||||
result != enableAutoReply)
|
||||
result = disableAutoReply;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (result != disableAutoReply)
|
||||
{
|
||||
// We handle the weekdays
|
||||
if ([[vacationOptions objectForKey: @"weekdaysEnabled"] boolValue])
|
||||
{
|
||||
weekdays = [vacationOptions objectForKey: @"days"];
|
||||
if ([weekdays containsObject: [NSString stringWithFormat: @"%i", [now dayOfWeek]]])
|
||||
result = enableAutoReply;
|
||||
else
|
||||
result = disableAutoReply;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
- (BOOL) updateAutoReplyForLogin: (NSString *) theLogin
|
||||
withSieveUsername: (NSString *) theUsername
|
||||
andPassword: (NSString *) thePassword
|
||||
@@ -154,13 +256,12 @@
|
||||
GCSChannelManager *cm;
|
||||
EOAdaptorChannel *channel;
|
||||
NSArray *attrs;
|
||||
NSDictionary *infos, *defaults, *vacationOptions;
|
||||
NSString *sql, *profileURL, *user, *c_defaults;
|
||||
NSDictionary *infos;
|
||||
NSString *sql, *profileURL, *user;
|
||||
NSURL *tableURL;
|
||||
SOGoSystemDefaults *sd;
|
||||
unsigned int now, endTime, startTime;
|
||||
unsigned int result;
|
||||
|
||||
now = [[[NSCalendarDate calendarDate] beginOfDay] timeIntervalSince1970];
|
||||
sd = [SOGoSystemDefaults sharedSystemDefaults];
|
||||
profileURL = [sd profileURL];
|
||||
if (!profileURL)
|
||||
@@ -187,44 +288,26 @@
|
||||
user = [infos objectForKey: @"c_uid"];
|
||||
if (verbose)
|
||||
NSLog(@"Checking user %@\n", user);
|
||||
c_defaults = [infos objectForKey: @"c_defaults"];
|
||||
if ([c_defaults isNotNull])
|
||||
result = [self checkConstraintsForRow: infos];
|
||||
if (result == enableAutoReply)
|
||||
{
|
||||
defaults = [c_defaults objectFromJSONString];
|
||||
vacationOptions = (NSDictionary *) [defaults objectForKey: @"Vacation"];
|
||||
if ([[vacationOptions objectForKey: @"enabled"] boolValue])
|
||||
{
|
||||
// We handle the start date
|
||||
if ([[vacationOptions objectForKey: @"startDateEnabled"] boolValue])
|
||||
{
|
||||
startTime = [[vacationOptions objectForKey: @"startDate"] intValue];
|
||||
if (now >= startTime)
|
||||
{
|
||||
if ([self updateAutoReplyForLogin: user
|
||||
withSieveUsername: theUsername
|
||||
andPassword: thePassword
|
||||
disabling: NO])
|
||||
NSLog(@"Enabled auto-reply of user %@", user);
|
||||
else
|
||||
NSLog(@"An error occured while enabling auto-reply of user %@", user);
|
||||
}
|
||||
}
|
||||
// We handle the end date
|
||||
if ([[vacationOptions objectForKey: @"endDateEnabled"] boolValue])
|
||||
{
|
||||
endTime = [[vacationOptions objectForKey: @"endDate"] intValue];
|
||||
if (endTime < now)
|
||||
{
|
||||
if ([self updateAutoReplyForLogin: user
|
||||
withSieveUsername: theUsername
|
||||
andPassword: thePassword
|
||||
disabling: YES])
|
||||
NSLog(@"Removed auto-reply of user %@", user);
|
||||
else
|
||||
NSLog(@"An error occured while removing auto-reply of user %@", user);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ([self updateAutoReplyForLogin: user
|
||||
withSieveUsername: theUsername
|
||||
andPassword: thePassword
|
||||
disabling: NO])
|
||||
NSLog(@"Enabled auto-reply of user %@", user);
|
||||
else
|
||||
NSLog(@"An error occured while enabling auto-reply of user %@", user);
|
||||
}
|
||||
else if (result == disableAutoReply)
|
||||
{
|
||||
if ([self updateAutoReplyForLogin: user
|
||||
withSieveUsername: theUsername
|
||||
andPassword: thePassword
|
||||
disabling: YES])
|
||||
NSLog(@"Removed auto-reply of user %@", user);
|
||||
else
|
||||
NSLog(@"An error occured while removing auto-reply of user %@", user);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,11 +44,18 @@
|
||||
"Add default email addresses" = "Add default email addresses";
|
||||
"Days between responses" = "Days between responses";
|
||||
"Do not send responses to mailing lists" = "Do not send responses to mailing lists";
|
||||
"Activation Constraints" = "Activation Constraints";
|
||||
"Enable auto reply on" = "Enable auto reply on";
|
||||
"First day of vacation" = "First day of vacation";
|
||||
"Disable auto reply on" = "Disable auto reply on";
|
||||
"Last day of vacation" = "Last day of vacation";
|
||||
"Enter date" = "Enter date";
|
||||
/* Enable auto reply at this time of the day */
|
||||
"Enable auto reply at" = "Enable auto reply at";
|
||||
"Enter time" = "Enter time";
|
||||
/* Disable auto reply at this time of the day */
|
||||
"Disable auto reply at" = "Disable auto reply at";
|
||||
"Enable auto reply on these days" = "Enable auto reply on these days";
|
||||
"Always send vacation message response" = "Always send vacation message response";
|
||||
"The vacation message is sent prior to apply your filters." = "The vacation message is sent prior to apply your filters.";
|
||||
"Discard incoming mails during vacation" = "Discard incoming mails during vacation";
|
||||
|
||||
@@ -506,6 +506,15 @@ static NSArray *reminderValues = nil;
|
||||
return iCalWeekDayString[i];
|
||||
}
|
||||
|
||||
- (int) numberForWeekDay
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
i = [[self shortWeekDaysList] indexOfObject: item];
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
//
|
||||
// Used by wox template
|
||||
//
|
||||
|
||||
@@ -636,6 +636,16 @@
|
||||
</md-checkbox>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.SOGoMailMarkAsReadDelay"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
label:aria-label="Automatically mark messages as read">
|
||||
<var:string label:value="Automatically mark messages as read"/>
|
||||
</md-checkbox>
|
||||
</div>
|
||||
|
||||
<div class="hide-xs" layout="row" layout-align="start center" flex="50">
|
||||
<md-checkbox
|
||||
class="md-align-top-left"
|
||||
@@ -1031,17 +1041,17 @@
|
||||
</div>
|
||||
|
||||
<div layout="row">
|
||||
<md-input-container class="md-block" flex="50" flex-xs="100">
|
||||
<label><var:string label:value="Days between responses"/></label>
|
||||
<md-select label:aria-label="Days between responses"
|
||||
ng-model="app.preferences.defaults.Vacation.daysBetweenResponse">
|
||||
<var:foreach list="daysBetweenResponsesList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
</md-option>
|
||||
</var:foreach>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
<md-input-container class="md-block" flex="50" flex-xs="100">
|
||||
<label><var:string label:value="Days between responses"/></label>
|
||||
<md-select label:aria-label="Days between responses"
|
||||
ng-model="app.preferences.defaults.Vacation.daysBetweenResponse">
|
||||
<var:foreach list="daysBetweenResponsesList" item="item">
|
||||
<md-option var:value="item">
|
||||
<var:string value="item"/>
|
||||
</md-option>
|
||||
</var:foreach>
|
||||
</md-select>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -1053,50 +1063,6 @@
|
||||
</md-checkbox>
|
||||
</div>
|
||||
|
||||
<var:if condition="isVacationPeriodEnabled">
|
||||
<div>
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.startDateEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
ng-change="app.toggleVacationStartDate()">
|
||||
<var:string label:value="Enable auto reply on" />
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<label class="md-no-truncate"><var:string label:value="First day of vacation"/></label>
|
||||
<md-datepicker
|
||||
name="vacationStartDate"
|
||||
label:md-placeholder="Enter date"
|
||||
ng-disabled="!app.preferences.defaults.Vacation.startDateEnabled"
|
||||
ng-required="app.preferences.defaults.Vacation.startDateEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.startDate"
|
||||
md-date-filter="app.validateVacationStartDate"
|
||||
sg-reset-on-disabled="sg-reset-on-disabled"><!-- datepicker --></md-datepicker>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.endDateEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
ng-change="app.toggleVacationEndDate()">
|
||||
<var:string label:value="Disable auto reply on" />
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<label class="md-no-truncate"><var:string label:value="Last day of vacation"/></label>
|
||||
<md-datepicker
|
||||
name="vacationEndDate"
|
||||
label:md-placeholder="Enter date"
|
||||
ng-disabled="!app.preferences.defaults.Vacation.endDateEnabled"
|
||||
ng-required="app.preferences.defaults.Vacation.endDateEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.endDate"
|
||||
md-date-filter="app.validateVacationEndDate"
|
||||
sg-reset-on-disabled="sg-reset-on-disabled"><!-- datepicker --></md-datepicker>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</var:if>
|
||||
|
||||
<div>
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.alwaysSend"
|
||||
@@ -1117,6 +1083,113 @@
|
||||
</md-checkbox>
|
||||
</div>
|
||||
|
||||
<var:if condition="isVacationPeriodEnabled">
|
||||
<h4 class="md-title"><var:string label:value="Activation Constraints"/></h4>
|
||||
|
||||
<div layout="row" layout-wrap="layout-wrap">
|
||||
<div class="md-block" flex="50" flex-xs="100">
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.startDateEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
ng-change="app.toggleVacationStartDate()">
|
||||
<var:string label:value="Enable auto reply on" />
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<label class="md-no-truncate"><var:string label:value="First day of vacation"/></label>
|
||||
<md-datepicker
|
||||
name="vacationStartDate"
|
||||
label:md-placeholder="Enter date"
|
||||
ng-disabled="!app.preferences.defaults.Vacation.startDateEnabled"
|
||||
ng-required="app.preferences.defaults.Vacation.startDateEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.startDate"
|
||||
md-date-filter="app.validateVacationStartDate"
|
||||
sg-reset-on-disabled="sg-reset-on-disabled"><!-- datepicker --></md-datepicker>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div class="md-block" flex="50" flex-xs="100">
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.endDateEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
ng-change="app.toggleVacationEndDate()">
|
||||
<var:string label:value="Disable auto reply on" />
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<label class="md-no-truncate"><var:string label:value="Last day of vacation"/></label>
|
||||
<md-datepicker
|
||||
name="vacationEndDate"
|
||||
label:md-placeholder="Enter date"
|
||||
ng-disabled="!app.preferences.defaults.Vacation.endDateEnabled"
|
||||
ng-required="app.preferences.defaults.Vacation.endDateEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.endDate"
|
||||
md-date-filter="app.validateVacationEndDate"
|
||||
sg-reset-on-disabled="sg-reset-on-disabled"><!-- datepicker --></md-datepicker>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div layout="row" layout-wrap="layout-wrap">
|
||||
<div class="md-block" flex="50" flex-xs="100">
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.startTimeEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
ng-change="app.toggleVacationStartTime()">
|
||||
<var:string label:value="Enable auto reply at" />
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<sg-timepicker
|
||||
name="vacationStartTime"
|
||||
label:md-placeholder="Enter time"
|
||||
ng-disabled="!app.preferences.defaults.Vacation.startTimeEnabled"
|
||||
ng-required="app.preferences.defaults.Vacation.startTimeEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.startTime"><!-- timepicker --></sg-timepicker>
|
||||
</md-input-container>
|
||||
</div>
|
||||
|
||||
<div class="md-block" flex="50" flex-xs="100">
|
||||
<md-checkbox
|
||||
ng-disabled="!app.preferences.defaults.Vacation.startTimeEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.endTimeEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0"
|
||||
ng-change="app.toggleVacationEndTime()">
|
||||
<var:string label:value="Disable auto reply at" />
|
||||
</md-checkbox>
|
||||
<md-input-container>
|
||||
<sg-timepicker
|
||||
name="vacationEndTime"
|
||||
label:md-placeholder="Enter time"
|
||||
ng-disabled="!app.preferences.defaults.Vacation.endTimeEnabled"
|
||||
ng-required="app.preferences.defaults.Vacation.endTimeEnabled"
|
||||
ng-model="app.preferences.defaults.Vacation.endTime"><!-- timepicker --></sg-timepicker>
|
||||
</md-input-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="sg-padded--bottom" layout="row" layout-align="start end">
|
||||
<md-checkbox
|
||||
ng-model="app.preferences.defaults.Vacation.weekdaysEnabled"
|
||||
ng-true-value="1"
|
||||
ng-false-value="0">
|
||||
</md-checkbox>
|
||||
<div class="pseudo-input-container layout-padding" flex="50" flex-sm="80" flex-xs="100">
|
||||
<label class="pseudo-input-label"><var:string label:value="Enable auto reply on these days"/></label>
|
||||
<md-grid-list md-cols="7" md-row-height="2em" md-gutter="0.5em"
|
||||
ng-model="app.preferences.defaults.Vacation.days"
|
||||
ng-disabled="app.preferences.defaults.Vacation.weekdaysEnabled"
|
||||
sg-toggle-grid="sg-toggle-grid">
|
||||
<var:foreach list="shortWeekDaysList" item="item">
|
||||
<md-grid-tile var:value="numberForWeekDay"><var:string value="item"/></md-grid-tile>
|
||||
</var:foreach>
|
||||
</md-grid-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</var:if>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</md-tab>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
* @constructor
|
||||
*/
|
||||
function Preferences() {
|
||||
var _this = this, defaultsElement, settingsElement, data;
|
||||
var _this = this, defaultsElement, settingsElement, data, time;
|
||||
|
||||
this.nextAlarm = null;
|
||||
this.nextInboxPoll = null;
|
||||
@@ -90,6 +90,28 @@
|
||||
data.Vacation.endDate = new Date(data.Vacation.startDate.getTime());
|
||||
data.Vacation.endDate.addDays(1);
|
||||
}
|
||||
if (data.Vacation.startTime) {
|
||||
time = data.Vacation.startTime.split(':');
|
||||
data.Vacation.startTime = new Date();
|
||||
data.Vacation.startTime.setHours(parseInt(time[0]), parseInt(time[1]));
|
||||
}
|
||||
else {
|
||||
data.Vacation.startTimeEnabled = 0;
|
||||
data.Vacation.startTime = new Date();
|
||||
data.Vacation.startTime.setHours(parseInt(data.SOGoDayEndTime));
|
||||
data.Vacation.startTime.setMinutes(0);
|
||||
}
|
||||
if (data.Vacation.endTime) {
|
||||
time = data.Vacation.endTime.split(':');
|
||||
data.Vacation.endTime = new Date();
|
||||
data.Vacation.endTime.setHours(parseInt(time[0]), parseInt(time[1]));
|
||||
}
|
||||
else {
|
||||
data.Vacation.endTimeEnabled = 0;
|
||||
data.Vacation.endTime = new Date();
|
||||
data.Vacation.endTime.setHours(parseInt(data.SOGoDayStartTime));
|
||||
data.Vacation.endTime.setMinutes(0);
|
||||
}
|
||||
if (data.Vacation.autoReplyEmailAddresses &&
|
||||
angular.isString(data.Vacation.autoReplyEmailAddresses) &&
|
||||
data.Vacation.autoReplyEmailAddresses.length)
|
||||
@@ -97,6 +119,9 @@
|
||||
} else
|
||||
data.Vacation = {};
|
||||
|
||||
if (angular.isUndefined(data.Vacation.days))
|
||||
data.Vacation.days = [];
|
||||
|
||||
if ((angular.isUndefined(data.Vacation.autoReplyEmailAddresses) ||
|
||||
data.Vacation.autoReplyEmailAddresses.length == 0) &&
|
||||
angular.isDefined(window.defaultEmailAddresses))
|
||||
@@ -413,7 +438,19 @@
|
||||
if (this.inboxSyncToken)
|
||||
params.syncToken = this.inboxSyncToken;
|
||||
|
||||
Preferences.$$resource.post('Mail', '0/folderINBOX/changes', params).then(function(data) {
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
toastController.$inject = ['scope', '$mdToast', 'title', 'body'];
|
||||
function toastController (scope, $mdToast, title, body) {
|
||||
scope.title = title;
|
||||
scope.body = body;
|
||||
scope.close = function() {
|
||||
$mdToast.hide('ok');
|
||||
};
|
||||
}
|
||||
|
||||
return Preferences.$$resource.post('Mail', '0/folderINBOX/changes', params).then(function(data) {
|
||||
if (data.syncToken) {
|
||||
_this.inboxSyncToken = data.syncToken;
|
||||
Preferences.$log.debug("New syncToken is " + _this.inboxSyncToken);
|
||||
@@ -489,18 +526,6 @@
|
||||
if (refreshViewCheck && refreshViewCheck != 'manually')
|
||||
_this.nextInboxPoll = Preferences.$timeout(angular.bind(_this, _this.pollInbox), refreshViewCheck.timeInterval()*1000);
|
||||
});
|
||||
|
||||
/**
|
||||
* @ngInject
|
||||
*/
|
||||
toastController.$inject = ['scope', '$mdToast', 'title', 'body'];
|
||||
function toastController (scope, $mdToast, title, body) {
|
||||
scope.title = title;
|
||||
scope.body = body;
|
||||
scope.close = function() {
|
||||
$mdToast.hide('ok');
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -734,8 +759,9 @@
|
||||
delete preferences.defaults.SOGoMailComposeFontSizeEnabled;
|
||||
|
||||
if (preferences.defaults.Vacation) {
|
||||
if (preferences.defaults.Vacation.startDateEnabled)
|
||||
if (preferences.defaults.Vacation.startDateEnabled) {
|
||||
preferences.defaults.Vacation.startDate = preferences.defaults.Vacation.startDate.getTime()/1000;
|
||||
}
|
||||
else {
|
||||
delete preferences.defaults.Vacation.startDateEnabled;
|
||||
preferences.defaults.Vacation.startDate = 0;
|
||||
@@ -747,6 +773,23 @@
|
||||
preferences.defaults.Vacation.endDate = 0;
|
||||
}
|
||||
|
||||
if (preferences.defaults.Vacation.startTimeEnabled) {
|
||||
preferences.defaults.Vacation.startTime = preferences.defaults.Vacation.startTime.format(this.$mdDateLocaleProvider, '%H:%M');
|
||||
// Set an end time only if a start time is defined
|
||||
if (preferences.defaults.Vacation.endTimeEnabled)
|
||||
preferences.defaults.Vacation.endTime = preferences.defaults.Vacation.endTime.format(this.$mdDateLocaleProvider, '%H:%M');
|
||||
else {
|
||||
delete preferences.defaults.Vacation.endTimeEnabled;
|
||||
preferences.defaults.Vacation.endTime = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
delete preferences.defaults.Vacation.startTimeEnabled;
|
||||
preferences.defaults.Vacation.startTime = 0;
|
||||
delete preferences.defaults.Vacation.endTimeEnabled;
|
||||
preferences.defaults.Vacation.endTime = 0;
|
||||
}
|
||||
|
||||
if (preferences.defaults.Vacation.autoReplyEmailAddresses)
|
||||
preferences.defaults.Vacation.autoReplyEmailAddresses = _.compact(preferences.defaults.Vacation.autoReplyEmailAddresses);
|
||||
else
|
||||
|
||||
@@ -587,6 +587,32 @@
|
||||
|
||||
return r;
|
||||
};
|
||||
|
||||
this.toggleVacationStartTime = function() {
|
||||
var v;
|
||||
|
||||
v = this.preferences.defaults.Vacation;
|
||||
|
||||
if (v.startTimeEnabled) {
|
||||
// Enabling the start date
|
||||
if (!v.startTime) {
|
||||
v.startTime = new Date();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.toggleVacationEndTime = function() {
|
||||
var v;
|
||||
|
||||
v = this.preferences.defaults.Vacation;
|
||||
|
||||
if (v.endTimeEnabled) {
|
||||
// Enabling the end date
|
||||
if (!v.endTime) {
|
||||
v.endTime = new Date();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular
|
||||
|
||||
Reference in New Issue
Block a user