feat(mail): enable autoreply on specific days or at a specific time

Fixes #5328
This commit is contained in:
Francis Lachapelle
2021-12-02 14:03:46 -05:00
parent 6807d1df8b
commit 2ecd441f32
10 changed files with 498 additions and 141 deletions

View File

@@ -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

View File

@@ -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;

View File

@@ -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]
}

View File

@@ -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`

View File

@@ -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);
}
}
}

View File

@@ -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";

View File

@@ -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
//

View File

@@ -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>

View File

@@ -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

View File

@@ -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