From 2ecd441f3200862fee28a66aadf29c758f0ead24 Mon Sep 17 00:00:00 2001 From: Francis Lachapelle Date: Thu, 2 Dec 2021 14:03:46 -0500 Subject: [PATCH] feat(mail): enable autoreply on specific days or at a specific time Fixes #5328 --- SoObjects/SOGo/SOGoSieveManager.m | 118 ++++++++++--- SoObjects/SOGo/SOGoUserFolder.m | 12 +- Tests/lib/utilities.js | 4 +- Tests/spec/SieveSpec.js | 42 ++++- Tools/SOGoToolUpdateAutoReply.m | 165 +++++++++++++----- .../English.lproj/Localizable.strings | 7 + UI/PreferencesUI/UIxPreferences.m | 9 + UI/Templates/PreferencesUI/UIxPreferences.wox | 127 +++++++++++--- .../js/Preferences/Preferences.service.js | 73 ++++++-- .../js/Preferences/PreferencesController.js | 26 +++ 10 files changed, 470 insertions(+), 113 deletions(-) diff --git a/SoObjects/SOGo/SOGoSieveManager.m b/SoObjects/SOGo/SOGoSieveManager.m index 2b31d9f5ea..1436aa03b7 100644 --- a/SoObjects/SOGo/SOGoSieveManager.m +++ b/SoObjects/SOGo/SOGoSieveManager.m @@ -22,6 +22,7 @@ #import #import +#import #import #import @@ -946,14 +947,14 @@ - (NSException *) updateFiltersForAccount: (SOGoMailAccount *) theAccount 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 @@ - (NSException *) updateFiltersForAccount: (SOGoMailAccount *) theAccount [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 diff --git a/SoObjects/SOGo/SOGoUserFolder.m b/SoObjects/SOGo/SOGoUserFolder.m index ef9847c133..ff0dd437fd 100644 --- a/SoObjects/SOGo/SOGoUserFolder.m +++ b/SoObjects/SOGo/SOGoUserFolder.m @@ -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 #import #import @@ -674,6 +674,14 @@ - (NSString *) davResourceId 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; diff --git a/Tests/lib/utilities.js b/Tests/lib/utilities.js index 7e2bb524a1..d5904fd989 100644 --- a/Tests/lib/utilities.js +++ b/Tests/lib/utilities.js @@ -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] } diff --git a/Tests/spec/SieveSpec.js b/Tests/spec/SieveSpec.js index ddc8b319b7..a748051bb9 100644 --- a/Tests/spec/SieveSpec.js +++ b/Tests/spec/SieveSpec.js @@ -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` diff --git a/Tools/SOGoToolUpdateAutoReply.m b/Tools/SOGoToolUpdateAutoReply.m index a0b175d5b9..2a279685af 100644 --- a/Tools/SOGoToolUpdateAutoReply.m +++ b/Tools/SOGoToolUpdateAutoReply.m @@ -20,6 +20,7 @@ #import #import +#import #import #import @@ -44,6 +45,10 @@ #import "SOGoTool.h" +#define statusquoAutoReply 0 +#define enableAutoReply 1 +#define disableAutoReply 2 + @interface SOGoToolUpdateAutoReply : SOGoTool @end @@ -73,6 +78,103 @@ - (void) usage "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 @@ - (void) updateAutoReplyWithUsername: (NSString *) theUsername 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 @@ - (void) updateAutoReplyWithUsername: (NSString *) theUsername 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); } } } diff --git a/UI/PreferencesUI/English.lproj/Localizable.strings b/UI/PreferencesUI/English.lproj/Localizable.strings index 48ad700106..7880db460f 100644 --- a/UI/PreferencesUI/English.lproj/Localizable.strings +++ b/UI/PreferencesUI/English.lproj/Localizable.strings @@ -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"; diff --git a/UI/PreferencesUI/UIxPreferences.m b/UI/PreferencesUI/UIxPreferences.m index 4cabf9fff4..1f0f76f779 100644 --- a/UI/PreferencesUI/UIxPreferences.m +++ b/UI/PreferencesUI/UIxPreferences.m @@ -506,6 +506,15 @@ - (NSString *) valueForWeekDay return iCalWeekDayString[i]; } +- (int) numberForWeekDay +{ + unsigned int i; + + i = [[self shortWeekDaysList] indexOfObject: item]; + + return i; +} + // // Used by wox template // diff --git a/UI/Templates/PreferencesUI/UIxPreferences.wox b/UI/Templates/PreferencesUI/UIxPreferences.wox index 54b308bd83..18af31a326 100644 --- a/UI/Templates/PreferencesUI/UIxPreferences.wox +++ b/UI/Templates/PreferencesUI/UIxPreferences.wox @@ -636,6 +636,16 @@ +
+ + + +
+
- - - - - - - - - - + + + + + + + + + +
@@ -1053,8 +1063,31 @@
+
+ + +
+
+
+ +
+ + +
+
+
+ -
+

+ +
+
-
+
- +
-
- - -
-
+
+
+ + + + + + +
+ +
+ + + + + + +
-
+
- -
-
+ +
+ + + + + + +
+ +
diff --git a/UI/WebServerResources/js/Preferences/Preferences.service.js b/UI/WebServerResources/js/Preferences/Preferences.service.js index 68c4fe2ab6..6f5a9d1415 100644 --- a/UI/WebServerResources/js/Preferences/Preferences.service.js +++ b/UI/WebServerResources/js/Preferences/Preferences.service.js @@ -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 diff --git a/UI/WebServerResources/js/Preferences/PreferencesController.js b/UI/WebServerResources/js/Preferences/PreferencesController.js index 73cb7ed09a..cb8edb1437 100644 --- a/UI/WebServerResources/js/Preferences/PreferencesController.js +++ b/UI/WebServerResources/js/Preferences/PreferencesController.js @@ -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