2015-02-25 23:21:07 +01:00
|
|
|
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
'use strict';
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
/**
|
|
|
|
* @name Preferences
|
|
|
|
* @constructor
|
|
|
|
*/
|
|
|
|
function Preferences() {
|
2017-06-01 19:46:57 +02:00
|
|
|
var _this = this, defaultsElement, settingsElement, data;
|
2015-02-25 23:21:07 +01:00
|
|
|
|
2020-07-29 22:31:19 +02:00
|
|
|
this.nextAlarm = null;
|
|
|
|
this.nextInboxPoll = null;
|
|
|
|
this.currentToast = Preferences.$q.when(true); // Show only one toast at a time (see https://github.com/angular/material/issues/2799)
|
|
|
|
this.lastUid = null;
|
|
|
|
this.notifications = {};
|
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
this.defaults = {};
|
2019-06-27 23:43:11 +02:00
|
|
|
this.settings = {Mail: {}};
|
2015-02-25 23:21:07 +01:00
|
|
|
|
2017-06-01 19:46:57 +02:00
|
|
|
defaultsElement = Preferences.$document[0].getElementById('UserDefaults');
|
|
|
|
if (defaultsElement) {
|
|
|
|
try {
|
|
|
|
data = angular.fromJson(defaultsElement.textContent || defaultsElement.innerHTML);
|
|
|
|
} catch (e) {
|
|
|
|
Preferences.$log.error("Can't parse user's defaults: " + e.message);
|
|
|
|
data = {};
|
|
|
|
}
|
2016-08-11 17:59:43 +02:00
|
|
|
|
2017-10-12 21:44:14 +02:00
|
|
|
// Split mail labels keys and values
|
|
|
|
data.SOGoMailLabelsColorsKeys = [];
|
|
|
|
data.SOGoMailLabelsColorsValues = [];
|
|
|
|
_.forEach(data.SOGoMailLabelsColors, function (value, key) {
|
|
|
|
data.SOGoMailLabelsColorsKeys.push(key);
|
2018-05-14 16:31:41 +02:00
|
|
|
data.SOGoMailLabelsColorsValues.push(value); // value is an array of the user-defined name and color
|
|
|
|
if (key.charAt(0) == '$') {
|
|
|
|
Object.defineProperty(data.SOGoMailLabelsColors, '_' + key,
|
|
|
|
Object.getOwnPropertyDescriptor(data.SOGoMailLabelsColors, key));
|
|
|
|
delete data.SOGoMailLabelsColors[key];
|
|
|
|
}
|
2017-10-12 21:44:14 +02:00
|
|
|
});
|
2015-08-17 16:10:57 +02:00
|
|
|
|
2017-03-22 18:26:43 +01:00
|
|
|
_.forEach(data.SOGoSieveFilters, function(filter) {
|
|
|
|
_.forEach(filter.actions, function(action) {
|
|
|
|
if (action.method == 'addflag' &&
|
|
|
|
action.argument.charAt(0) == '$')
|
|
|
|
action.argument = '_' + action.argument;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2016-10-31 20:12:47 +01:00
|
|
|
if (data.SOGoRememberLastModule)
|
|
|
|
data.SOGoLoginModule = "Last";
|
|
|
|
|
2016-02-11 17:40:36 +01:00
|
|
|
// Mail editor autosave is a number of minutes or 0 if disabled
|
|
|
|
data.SOGoMailAutoSave = parseInt(data.SOGoMailAutoSave) || 0;
|
|
|
|
|
2017-09-20 22:50:41 +02:00
|
|
|
data.SOGoMailComposeWindowEnabled = angular.isDefined(data.SOGoMailComposeWindow);
|
|
|
|
|
2016-02-11 22:45:58 +01:00
|
|
|
// Specify a base font size for HTML messages when SOGoMailComposeFontSize is not zero
|
|
|
|
data.SOGoMailComposeFontSizeEnabled = parseInt(data.SOGoMailComposeFontSize) > 0;
|
|
|
|
|
2016-02-12 18:03:26 +01:00
|
|
|
if (window.CKEDITOR && data.SOGoMailComposeFontSizeEnabled) {
|
2016-02-11 22:45:58 +01:00
|
|
|
// HTML editor is enabled; set user's preferred font size
|
|
|
|
window.CKEDITOR.config.fontSize_defaultLabel = data.SOGoMailComposeFontSize;
|
|
|
|
window.CKEDITOR.addCss('.cke_editable { font-size: ' + data.SOGoMailComposeFontSize + 'px; }');
|
|
|
|
}
|
|
|
|
|
2017-12-19 15:53:48 +01:00
|
|
|
_.forEach(data.AuxiliaryMailAccounts, function (mailAccount) {
|
|
|
|
if (isNaN(parseInt(mailAccount.port)))
|
|
|
|
mailAccount.port = null;
|
|
|
|
});
|
|
|
|
|
2020-06-22 23:12:05 +02:00
|
|
|
// We convert our date objects into real date, otherwise we'll have strings
|
2015-08-17 16:10:57 +02:00
|
|
|
// or undefined values and the md-datepicker does NOT like this.
|
|
|
|
if (data.Vacation) {
|
2016-06-13 21:39:57 +02:00
|
|
|
if (data.Vacation.startDate)
|
|
|
|
data.Vacation.startDate = new Date(parseInt(data.Vacation.startDate) * 1000);
|
|
|
|
else {
|
|
|
|
data.Vacation.startDateEnabled = 0;
|
|
|
|
data.Vacation.startDate = new Date();
|
2016-10-21 00:07:52 +02:00
|
|
|
data.Vacation.startDate = data.Vacation.startDate.beginOfDay();
|
|
|
|
data.Vacation.startDate.addDays(1);
|
2016-06-13 21:39:57 +02:00
|
|
|
}
|
2015-08-17 16:10:57 +02:00
|
|
|
if (data.Vacation.endDate)
|
|
|
|
data.Vacation.endDate = new Date(parseInt(data.Vacation.endDate) * 1000);
|
|
|
|
else {
|
|
|
|
data.Vacation.endDateEnabled = 0;
|
2016-10-21 00:07:52 +02:00
|
|
|
data.Vacation.endDate = new Date(data.Vacation.startDate.getTime());
|
|
|
|
data.Vacation.endDate.addDays(1);
|
2015-08-17 16:10:57 +02:00
|
|
|
}
|
2018-08-29 16:54:17 +02:00
|
|
|
if (data.Vacation.autoReplyEmailAddresses &&
|
2020-06-02 20:22:20 +02:00
|
|
|
angular.isString(data.Vacation.autoReplyEmailAddresses) &&
|
2018-08-29 16:54:17 +02:00
|
|
|
data.Vacation.autoReplyEmailAddresses.length)
|
2020-06-02 20:22:20 +02:00
|
|
|
data.Vacation.autoReplyEmailAddresses = data.Vacation.autoReplyEmailAddresses.split(/, */);
|
2015-12-09 20:06:07 +01:00
|
|
|
} else
|
2015-08-17 16:10:57 +02:00
|
|
|
data.Vacation = {};
|
2015-12-09 20:06:07 +01:00
|
|
|
|
2020-06-02 20:22:20 +02:00
|
|
|
if ((angular.isUndefined(data.Vacation.autoReplyEmailAddresses) ||
|
|
|
|
data.Vacation.autoReplyEmailAddresses.length == 0) &&
|
2015-12-09 20:06:07 +01:00
|
|
|
angular.isDefined(window.defaultEmailAddresses))
|
|
|
|
data.Vacation.autoReplyEmailAddresses = window.defaultEmailAddresses;
|
|
|
|
|
2015-12-10 01:28:26 +01:00
|
|
|
if (angular.isUndefined(data.Vacation.daysBetweenResponse))
|
2015-12-09 20:06:07 +01:00
|
|
|
data.Vacation.daysBetweenResponse = 7;
|
|
|
|
|
2016-06-13 21:39:57 +02:00
|
|
|
if (angular.isUndefined(data.Vacation.startDate)) {
|
|
|
|
data.Vacation.startDateEnabled = 0;
|
|
|
|
data.Vacation.startDate = new Date();
|
|
|
|
}
|
|
|
|
|
2015-12-10 01:28:26 +01:00
|
|
|
if (angular.isUndefined(data.Vacation.endDate)) {
|
2015-08-17 16:10:57 +02:00
|
|
|
data.Vacation.endDateEnabled = 0;
|
|
|
|
data.Vacation.endDate = new Date();
|
|
|
|
}
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2020-06-22 23:12:05 +02:00
|
|
|
if (data.Forward) {
|
|
|
|
if (angular.isString(data.Forward.forwardAddress))
|
|
|
|
data.Forward.forwardAddress = data.Forward.forwardAddress.split(/, */);
|
|
|
|
else if (!angular.isArray(data.Forward.forwardAddress))
|
|
|
|
data.Forward.forwardAddress = [];
|
|
|
|
}
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2018-09-11 21:17:31 +02:00
|
|
|
// Split calendar categories colors keys and values
|
|
|
|
if (angular.isUndefined(data.SOGoCalendarCategories))
|
2015-12-10 01:28:26 +01:00
|
|
|
data.SOGoCalendarCategories = [];
|
2018-09-11 21:17:31 +02:00
|
|
|
data.SOGoCalendarCategoriesColorsValues = [];
|
|
|
|
_.forEach(data.SOGoCalendarCategories, function (value) {
|
|
|
|
data.SOGoCalendarCategoriesColorsValues.push(data.SOGoCalendarCategoriesColors[value]);
|
|
|
|
});
|
2015-12-10 01:28:26 +01:00
|
|
|
|
|
|
|
if (angular.isUndefined(data.SOGoContactsCategories))
|
|
|
|
data.SOGoContactsCategories = [];
|
2017-10-10 20:55:22 +02:00
|
|
|
else
|
|
|
|
data.SOGoContactsCategories = _.compact(data.SOGoContactsCategories);
|
2015-12-10 01:28:26 +01:00
|
|
|
|
2015-08-17 16:10:57 +02:00
|
|
|
angular.extend(_this.defaults, data);
|
2015-07-08 20:15:39 +02:00
|
|
|
|
2016-01-26 13:20:02 +01:00
|
|
|
// Configure date locale
|
2016-02-10 22:18:12 +01:00
|
|
|
_this.$mdDateLocaleProvider = Preferences.$mdDateLocaleProvider;
|
|
|
|
angular.extend(_this.$mdDateLocaleProvider, data.locale);
|
2016-07-04 23:11:48 +02:00
|
|
|
angular.extend(_this.$mdDateLocaleProvider, {
|
|
|
|
firstDayOfWeek: data.SOGoFirstDayOfWeek,
|
|
|
|
firstWeekOfYear: data.SOGoFirstWeekOfYear
|
|
|
|
});
|
2016-02-10 22:18:12 +01:00
|
|
|
_this.$mdDateLocaleProvider.firstDayOfWeek = parseInt(data.SOGoFirstDayOfWeek);
|
|
|
|
_this.$mdDateLocaleProvider.weekNumberFormatter = function(weekNumber) {
|
2016-01-11 22:32:12 +01:00
|
|
|
return l('Week %d', weekNumber);
|
|
|
|
};
|
2019-02-27 15:51:43 +01:00
|
|
|
_this.$mdDateLocaleProvider.msgCalendar = l('Calendar');
|
2016-02-10 22:18:12 +01:00
|
|
|
_this.$mdDateLocaleProvider.msgOpenCalendar = l('Open Calendar');
|
|
|
|
_this.$mdDateLocaleProvider.parseDate = function(dateString) {
|
2017-06-01 19:46:57 +02:00
|
|
|
return dateString? dateString.parseDate(_this.$mdDateLocaleProvider, _this.defaults.SOGoShortDateFormat) : new Date(NaN);
|
2016-01-11 22:32:12 +01:00
|
|
|
};
|
2016-02-10 22:18:12 +01:00
|
|
|
_this.$mdDateLocaleProvider.formatDate = function(date) {
|
2017-06-01 19:46:57 +02:00
|
|
|
return date? date.format(_this.$mdDateLocaleProvider, date.$dateFormat || _this.defaults.SOGoShortDateFormat) : '';
|
2016-01-11 22:32:12 +01:00
|
|
|
};
|
2016-06-10 17:38:35 +02:00
|
|
|
_this.$mdDateLocaleProvider.parseTime = function(timeString) {
|
2017-06-01 19:46:57 +02:00
|
|
|
return timeString? timeString.parseDate(_this.$mdDateLocaleProvider, _this.defaults.SOGoTimeFormat) : new Date(NaN);
|
2016-06-10 17:38:35 +02:00
|
|
|
};
|
2016-02-10 22:18:12 +01:00
|
|
|
_this.$mdDateLocaleProvider.formatTime = function(date) {
|
2017-06-01 19:46:57 +02:00
|
|
|
return date? date.format(_this.$mdDateLocaleProvider, _this.defaults.SOGoTimeFormat) : '';
|
2016-01-11 22:32:12 +01:00
|
|
|
};
|
2019-02-26 15:58:09 +01:00
|
|
|
_this.$mdDateLocaleProvider.isDateComplete = function(dateString) {
|
|
|
|
dateString = dateString.trim();
|
|
|
|
// The default function of Angular Material doesn't handle non-latin characters.
|
|
|
|
// This one does.
|
2019-06-12 22:37:43 +02:00
|
|
|
var re = /^((([a-zA-Z]|[^\x00-\x7F]){2,}|[0-9]{1,4})([ .,]+|[/-])){2}(([a-zA-Z]|[^\x00-\x7F]){3,}|[0-9]{1,4})$/;
|
2019-02-26 15:58:09 +01:00
|
|
|
return re.test(dateString);
|
|
|
|
};
|
2017-06-01 19:46:57 +02:00
|
|
|
}
|
2016-01-11 22:32:12 +01:00
|
|
|
|
2017-06-01 19:46:57 +02:00
|
|
|
settingsElement = Preferences.$document[0].getElementById('UserSettings');
|
|
|
|
if (settingsElement) {
|
|
|
|
try {
|
|
|
|
data = angular.fromJson(settingsElement.textContent || settingsElement.innerHTML);
|
|
|
|
} catch (e) {
|
|
|
|
Preferences.$log.error("Can't parse user's settings: " + e.message);
|
|
|
|
data = {};
|
|
|
|
}
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2016-01-11 22:32:12 +01:00
|
|
|
// We convert our PreventInvitationsWhitelist hash into a array of user
|
2015-12-07 17:05:01 +01:00
|
|
|
if (data.Calendar) {
|
2016-06-22 03:29:44 +02:00
|
|
|
if (data.Calendar.PreventInvitationsWhitelist) {
|
2015-05-06 18:12:27 +02:00
|
|
|
data.Calendar.PreventInvitationsWhitelist = _.map(data.Calendar.PreventInvitationsWhitelist, function(value, key) {
|
2016-06-22 03:29:44 +02:00
|
|
|
var match = /^(.+)\s<(\S+)>$/.exec(value),
|
|
|
|
user = new Preferences.$User({uid: key, cn: match[1], c_email: match[2]});
|
|
|
|
if (!user.$$image)
|
2017-06-01 19:46:57 +02:00
|
|
|
user.$$image = _this.avatar(user.c_email, 32, {no_404: true});
|
2016-06-22 03:29:44 +02:00
|
|
|
return user;
|
2015-05-06 18:12:27 +02:00
|
|
|
});
|
2016-06-22 03:29:44 +02:00
|
|
|
}
|
2015-12-07 17:05:01 +01:00
|
|
|
else
|
|
|
|
data.Calendar.PreventInvitationsWhitelist = [];
|
|
|
|
}
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2015-07-08 20:15:39 +02:00
|
|
|
angular.extend(_this.settings, data);
|
2017-06-01 19:46:57 +02:00
|
|
|
}
|
2015-02-25 23:21:07 +01:00
|
|
|
}
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
/**
|
|
|
|
* @memberof Preferences
|
|
|
|
* @desc The factory we'll use to register with Angular
|
|
|
|
* @returns the Preferences constructor
|
|
|
|
*/
|
2020-07-29 22:31:19 +02:00
|
|
|
Preferences.$factory = ['$window', '$document', '$q', '$timeout', '$log', '$state', '$mdDateLocale', '$mdToast', 'sgSettings', 'Gravatar', 'Resource', 'User', function($window, $document, $q, $timeout, $log, $state, $mdDateLocaleProvider, $mdToast, Settings, Gravatar, Resource, User) {
|
2015-02-25 23:21:07 +01:00
|
|
|
angular.extend(Preferences, {
|
2020-07-29 22:31:19 +02:00
|
|
|
$window: $window,
|
2017-06-01 19:46:57 +02:00
|
|
|
$document: $document,
|
2015-02-25 23:21:07 +01:00
|
|
|
$q: $q,
|
|
|
|
$timeout: $timeout,
|
|
|
|
$log: $log,
|
2020-07-29 22:31:19 +02:00
|
|
|
$state: $state,
|
2016-01-11 22:32:12 +01:00
|
|
|
$mdDateLocaleProvider: $mdDateLocaleProvider,
|
2020-07-29 22:31:19 +02:00
|
|
|
$toast: $mdToast,
|
2016-06-22 03:29:44 +02:00
|
|
|
$gravatar: Gravatar,
|
2015-08-03 17:53:54 +02:00
|
|
|
$$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),
|
2016-06-22 03:29:44 +02:00
|
|
|
$resourcesURL: Settings.resourcesURL(),
|
2015-04-20 23:28:43 +02:00
|
|
|
$User: User
|
2015-02-25 23:21:07 +01:00
|
|
|
});
|
|
|
|
|
2015-07-08 20:15:39 +02:00
|
|
|
return new Preferences(); // return unique instance
|
2015-02-25 23:21:07 +01:00
|
|
|
}];
|
|
|
|
|
2015-07-29 21:16:43 +02:00
|
|
|
/* Initialize module if necessary */
|
|
|
|
try {
|
|
|
|
angular.module('SOGo.PreferencesUI');
|
|
|
|
}
|
|
|
|
catch(e) {
|
|
|
|
angular.module('SOGo.PreferencesUI', ['SOGo.Common']);
|
|
|
|
}
|
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
/* Factory registration in Angular module */
|
|
|
|
angular.module('SOGo.PreferencesUI')
|
2015-05-06 04:06:13 +02:00
|
|
|
.factory('Preferences', Preferences.$factory);
|
2015-02-25 23:21:07 +01:00
|
|
|
|
2015-07-08 20:15:39 +02:00
|
|
|
/**
|
|
|
|
* @function ready
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Combine promises used to load user's defaults and settings.
|
|
|
|
* @return a combined promise
|
|
|
|
*/
|
|
|
|
Preferences.prototype.ready = function() {
|
2017-06-01 19:46:57 +02:00
|
|
|
Preferences.$log.warn('Preferences.ready is deprecated -- access settings/defaults directly.');
|
|
|
|
return Preferences.$q.when(true);
|
2015-07-08 20:15:39 +02:00
|
|
|
};
|
|
|
|
|
2016-06-22 03:29:44 +02:00
|
|
|
/**
|
|
|
|
* @function avatar
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Get the avatar URL associated to an email address
|
|
|
|
* @return a combined promise
|
|
|
|
*/
|
|
|
|
Preferences.prototype.avatar = function(email, size, options) {
|
|
|
|
var _this = this;
|
2017-06-01 19:46:57 +02:00
|
|
|
var alternate_avatar = _this.defaults.SOGoAlternateAvatar, url;
|
|
|
|
if (_this.defaults.SOGoGravatarEnabled)
|
|
|
|
url = Preferences.$gravatar(email, size, alternate_avatar, options);
|
|
|
|
else
|
|
|
|
url = [Preferences.$resourcesURL, 'img', 'ic_person_grey_24px.svg'].join('/');
|
|
|
|
if (options && options.dstObject && options.dstAttr)
|
|
|
|
options.dstObject[options.dstAttr] = url;
|
|
|
|
return url;
|
2020-01-31 22:51:33 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function hasActiveExternalSieveScripts
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Check if the user has an external Sieve script enabled.
|
|
|
|
*/
|
|
|
|
Preferences.prototype.hasActiveExternalSieveScripts = function(value) {
|
|
|
|
var _this = this;
|
|
|
|
|
|
|
|
if (typeof value !== 'undefined') {
|
|
|
|
this.defaults.hasActiveExternalSieveScripts = value;
|
|
|
|
}
|
|
|
|
else if (typeof this.defaults.hasActiveExternalSieveScripts !== 'undefined') {
|
|
|
|
return this.defaults.hasActiveExternalSieveScripts;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Fetch information from server
|
|
|
|
this.defaults.hasActiveExternalSieveScripts = false; // default until we receive an answer
|
|
|
|
Preferences.$$resource.quietFetch('activeExternalSieveScripts')
|
|
|
|
.then(function() {
|
|
|
|
_this.defaults.hasActiveExternalSieveScripts = true;
|
|
|
|
}, function(response) {
|
|
|
|
_this.defaults.hasActiveExternalSieveScripts = false;
|
|
|
|
if (response.status === 404) {
|
|
|
|
return Preferences.$q.resolve(true);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2016-06-22 03:29:44 +02:00
|
|
|
};
|
|
|
|
|
2020-07-29 22:31:19 +02:00
|
|
|
/**
|
|
|
|
* @function supportsNotifications
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Check if the browser supports the Notifications API
|
|
|
|
* @returns true if the browser is compatible
|
|
|
|
* @see {@link https://notifications.spec.whatwg.org/|Notifications API}
|
|
|
|
*/
|
|
|
|
Preferences.prototype.supportsNotifications = function () {
|
|
|
|
if (typeof Notification === 'undefined') {
|
|
|
|
Preferences.$log.warn("Notifications are not available for your browser.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function authorizeNotifications
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Request authorization to send notifications
|
|
|
|
*/
|
|
|
|
Preferences.prototype.authorizeNotifications = function () {
|
|
|
|
if (this.supportsNotifications()) {
|
|
|
|
Notification.requestPermission(function (permission) {
|
|
|
|
return permission;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function createNotification
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Display a HTML5 notification
|
|
|
|
* @param {string} id - a unique identifier
|
|
|
|
* @param {string} title
|
|
|
|
* @param {object} config - parameters of the notification (body, icon, onClick)
|
|
|
|
*/
|
|
|
|
Preferences.prototype.createNotification = function (id, title, config) {
|
|
|
|
var _this = this,
|
|
|
|
params = _.pick(config, ['body', 'icon']);
|
|
|
|
if (this.supportsNotifications ()) {
|
|
|
|
params.tag = id;
|
|
|
|
params.lang = '';
|
|
|
|
params.dir = 'auto';
|
|
|
|
this.notifications[id] = new Notification(title, params);
|
|
|
|
this.notifications[id].onclick = function () {
|
|
|
|
config.onClick();
|
|
|
|
_this.notifications[id].close();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function viewInboxMessage
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Go to the specified message of the main account's inbox
|
|
|
|
* @param {string} uid - the message UID
|
|
|
|
*/
|
|
|
|
Preferences.prototype.viewInboxMessage = function(uid) {
|
|
|
|
if (Preferences.$state.get('mail.account')) {
|
|
|
|
// Currently in Mail module -- view message
|
|
|
|
Preferences.$state.go('mail.account.mailbox.message', { accountId: 0, mailboxId: 'INBOX', messageId: uid });
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// On a different module -- reload page
|
|
|
|
Preferences.$window.location = Preferences.$$resource.path('Mail', 'view#!/Mail/0/INBOX/' + uid);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function pollInbox
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Poll server for new messages in main account's inbox, display notifications or toasts
|
|
|
|
*/
|
|
|
|
Preferences.prototype.pollInbox = function() {
|
|
|
|
var _this = this, params;
|
|
|
|
|
|
|
|
params = {
|
|
|
|
sortingAttributes: {
|
|
|
|
sort: 'arrival',
|
|
|
|
asc: 0,
|
|
|
|
noHeaders: 0,
|
|
|
|
dry: 1
|
|
|
|
},
|
|
|
|
filters: [
|
|
|
|
{
|
|
|
|
searchBy: 'flags',
|
|
|
|
searchInput: 'unseen'
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
if (this.nextInboxPoll)
|
|
|
|
Preferences.$timeout.cancel(this.nextInboxPoll);
|
|
|
|
|
|
|
|
Preferences.$$resource.post('Mail', '0/folderINBOX/view', params).then(function(data) {
|
|
|
|
var uids = data.uids;
|
|
|
|
var uidHeaderIndex = data.headers[0].indexOf('uid');
|
|
|
|
var fromHeaderIndex = data.headers[0].indexOf('From');
|
|
|
|
var subjectHeaderIndex = data.headers[0].indexOf('Subject');
|
|
|
|
if (data.threaded) {
|
|
|
|
data.uids.splice(0, 1);
|
|
|
|
uids = _.map(data.uids, 0);
|
|
|
|
}
|
|
|
|
if (_this.lastUid) {
|
|
|
|
_.find(uids, function (uid, index) {
|
|
|
|
var headers, id, href, toast;
|
|
|
|
if (uid > _this.lastUid) {
|
|
|
|
// New unseen message
|
|
|
|
Preferences.$log.debug('Show notification for message ' + uid);
|
|
|
|
headers = _.find(data.headers, function(h) {
|
|
|
|
return h[uidHeaderIndex] == uid;
|
|
|
|
});
|
|
|
|
if (_this.defaults.SOGoDesktopNotifications) {
|
|
|
|
id = 'mail-inbox-' + uid;
|
|
|
|
href = Preferences.$state.href('mail.account.mailbox.message', { accountId: 0, mailboxId: 'INBOX', messageId: uid });
|
|
|
|
_this.createNotification(id, headers[subjectHeaderIndex], {
|
|
|
|
body: headers[fromHeaderIndex][0].name || headers[fromHeaderIndex][0].email,
|
|
|
|
icon: '/SOGo.woa/WebServerResources/img/email-256px.png',
|
|
|
|
onClick: function () {
|
|
|
|
_this.viewInboxMessage(uid);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
toast = {
|
2020-09-30 20:14:24 +02:00
|
|
|
locals: {
|
|
|
|
title: headers[subjectHeaderIndex],
|
|
|
|
body: headers[fromHeaderIndex][0].name || headers[fromHeaderIndex][0].email
|
|
|
|
},
|
2020-07-29 22:31:19 +02:00
|
|
|
template: [
|
|
|
|
'<md-toast role="alert">',
|
|
|
|
' <div class="md-toast-content">',
|
|
|
|
' <div layout="row" layout-align="start center" flex>',
|
|
|
|
' <md-icon class="md-primary md-hue-1">email</md-icon>',
|
|
|
|
' <div class="sg-padded--left">',
|
2020-09-30 20:14:24 +02:00
|
|
|
' <span md-truncate ng-bind="title"></span>',
|
|
|
|
' <div class="sg-hint" md-truncate ng-bind="body"></div>',
|
2020-07-29 22:31:19 +02:00
|
|
|
' </div>',
|
|
|
|
' <div flex></div>',
|
|
|
|
' <md-button ng-click="close()">',
|
|
|
|
l('View'),
|
|
|
|
' </md-button>',
|
|
|
|
' </div>',
|
|
|
|
' </div>',
|
|
|
|
'</md-toast>'
|
|
|
|
].join(''),
|
|
|
|
position: 'top right',
|
|
|
|
hideDelay: 5000,
|
|
|
|
controller: toastController
|
|
|
|
};
|
|
|
|
_this.currentToast = _this.currentToast.then(function () {
|
|
|
|
return Preferences.$toast.show(toast)
|
|
|
|
.then(function(response) {
|
|
|
|
if (response === 'ok') {
|
|
|
|
_this.viewInboxMessage(uid);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
return false; // Continue to next unseen message
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return true; // No more new messages
|
|
|
|
}
|
|
|
|
});
|
|
|
|
if (uids[0] > _this.lastUid) {
|
|
|
|
_this.lastUid = uids[0];
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_this.lastUid = uids[0];
|
|
|
|
}
|
|
|
|
}).finally(function () {
|
|
|
|
var refreshViewCheck = _this.defaults.SOGoRefreshViewCheck;
|
|
|
|
if (refreshViewCheck && refreshViewCheck != 'manually')
|
|
|
|
_this.nextInboxPoll = Preferences.$timeout(angular.bind(_this, _this.pollInbox), refreshViewCheck.timeInterval()*1000);
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ngInject
|
|
|
|
*/
|
2020-09-30 20:14:24 +02:00
|
|
|
toastController.$inject = ['scope', '$mdToast', 'title', 'body'];
|
|
|
|
function toastController (scope, $mdToast, title, body) {
|
|
|
|
scope.title = title;
|
|
|
|
scope.body = body;
|
2020-07-29 22:31:19 +02:00
|
|
|
scope.close = function() {
|
|
|
|
$mdToast.hide('ok');
|
|
|
|
};
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function getAlarms
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Fetch the list of alarms from the server and schedule the last one
|
|
|
|
*/
|
|
|
|
Preferences.prototype.getAlarms = function() {
|
|
|
|
var _this = this;
|
|
|
|
var now = new Date();
|
|
|
|
var browserTime = Math.floor(now.getTime()/1000);
|
|
|
|
|
|
|
|
Preferences.$$resource.fetch('Calendar', 'alarmslist?browserTime=' + browserTime).then(function(data) {
|
|
|
|
var alarms = data.alarms.sort(function reverseSortByAlarmTime(a, b) {
|
|
|
|
var x = parseInt(a[2]);
|
|
|
|
var y = parseInt(b[2]);
|
|
|
|
return (y - x);
|
|
|
|
});
|
|
|
|
if (alarms.length > 0) {
|
|
|
|
var next = alarms.pop();
|
|
|
|
var now = new Date();
|
|
|
|
var utc = Math.floor(now.getTime()/1000);
|
|
|
|
var url = next[0] + '/' + next[1];
|
|
|
|
var alarmTime = parseInt(next[2]);
|
|
|
|
var delay = alarmTime;
|
|
|
|
if (alarmTime > 0) delay -= utc;
|
|
|
|
var d = new Date(alarmTime*1000);
|
|
|
|
//console.log ("now = " + now.toUTCString());
|
|
|
|
//console.log ("next event " + url + " in " + delay + " seconds (on " + d.toUTCString() + ")");
|
|
|
|
|
|
|
|
var f = angular.bind(_this, _this.showAlarm, url);
|
|
|
|
|
|
|
|
if (_this.nextAlarm)
|
|
|
|
Preferences.$timeout.cancel(_this.nextAlarm);
|
|
|
|
|
|
|
|
_this.nextAlarm = Preferences.$timeout(f, delay*1000);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function showAlarm
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Show the latest alarm using a notification and a toast
|
|
|
|
* @param url The URL of the calendar component for snoozing
|
|
|
|
*/
|
|
|
|
Preferences.prototype.showAlarm = function(url) {
|
|
|
|
var _this = this;
|
|
|
|
|
|
|
|
Preferences.$$resource.fetch('Calendar/' + url, '?resetAlarm=yes').then(function(data) {
|
|
|
|
var today = new Date().beginOfDay(),
|
|
|
|
day = data.startDate.split(/T/)[0].asDate(),
|
|
|
|
period = [],
|
|
|
|
id;
|
|
|
|
if (day.getTime() != today.getTime() || data.localizedStartDate != data.localizedEndDate) {
|
|
|
|
period.push(data.localizedStartDate);
|
|
|
|
}
|
|
|
|
if (!data.isAllDay) {
|
|
|
|
period.push(data.localizedStartTime);
|
|
|
|
period.push('-');
|
|
|
|
}
|
|
|
|
if (data.localizedStartDate != data.localizedEndDate) {
|
|
|
|
period.push(data.localizedEndDate);
|
|
|
|
}
|
|
|
|
if (!data.isAllDay) {
|
|
|
|
period.push(data.localizedEndTime);
|
|
|
|
}
|
|
|
|
if (_this.defaults.SOGoDesktopNotifications) {
|
|
|
|
id = 'calendar-' + data.id;
|
|
|
|
_this.createNotification(id, data.summary, {
|
|
|
|
body: period.join(' '),
|
|
|
|
icon: '/SOGo.woa/WebServerResources/img/event-256px.png',
|
|
|
|
onClick: function () {
|
|
|
|
if (Preferences.$state.get('calendars.view')) {
|
|
|
|
// Currently in Calendar module -- go to event's day
|
|
|
|
Preferences.$state.go('calendars.view', { view: 'day', day: day.getDayString()});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// On a different module -- reload page
|
|
|
|
Preferences.$window.location = Preferences.$$resource.path('Calendar', 'view#!/calendar/day/' + day.getDayString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
_this.currentToast = _this.currentToast.then(function () {
|
|
|
|
return Preferences.$toast.show({
|
|
|
|
position: 'top right',
|
|
|
|
hideDelay: 0,
|
|
|
|
template: [
|
|
|
|
'<md-toast>',
|
|
|
|
' <div class="md-toast-content">',
|
|
|
|
' <div layout="column" layout="start end">',
|
|
|
|
' <p class="sg-padded--top">{{ summary }}</p>',
|
|
|
|
' <div layout="row" layout-align="start center">',
|
|
|
|
' <md-input-container>',
|
|
|
|
' <label style="color: white">{{ "Snooze for " | loc }}</label>',
|
|
|
|
' <md-select ng-model="reminder">',
|
|
|
|
' <md-option value="5">',
|
|
|
|
l('5 minutes'),
|
|
|
|
' </md-option>',
|
|
|
|
' <md-option value="10">',
|
|
|
|
l('10 minutes'),
|
|
|
|
' </md-option>',
|
|
|
|
' <md-option value="15">',
|
|
|
|
l('15 minutes'),
|
|
|
|
' </md-option>',
|
|
|
|
' <md-option value="30">',
|
|
|
|
l('30 minutes'),
|
|
|
|
' </md-option>',
|
|
|
|
' <md-option value="45">',
|
|
|
|
l('45 minutes'),
|
|
|
|
' </md-option>',
|
|
|
|
' <md-option value="60">',
|
|
|
|
l('1 hour'),
|
|
|
|
' </md-option>',
|
|
|
|
' <md-option value="1440">',
|
|
|
|
l('1 day'),
|
|
|
|
' </md-option>',
|
|
|
|
' </md-select>',
|
|
|
|
' </md-input-container>',
|
|
|
|
' <md-button ng-click="snooze()">',
|
|
|
|
l('Snooze'),
|
|
|
|
' </md-button>',
|
|
|
|
' <md-button ng-click="close()">',
|
|
|
|
l('Close'),
|
|
|
|
' </md-button>',
|
|
|
|
' </div>',
|
|
|
|
' </div>',
|
|
|
|
' </div>',
|
|
|
|
'</md-toast>'
|
|
|
|
].join(''),
|
|
|
|
locals: {
|
|
|
|
url: url
|
|
|
|
},
|
|
|
|
controller: AlarmController
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @ngInject
|
|
|
|
*/
|
|
|
|
AlarmController.$inject = ['scope', 'url'];
|
|
|
|
function AlarmController(scope, url) {
|
|
|
|
scope.summary = data.summary;
|
|
|
|
scope.reminder = '10';
|
|
|
|
scope.close = function() {
|
|
|
|
Preferences.$toast.hide();
|
|
|
|
};
|
|
|
|
scope.snooze = function() {
|
|
|
|
Preferences.$$resource.fetch(url, 'view?snoozeAlarm=' + scope.reminder);
|
|
|
|
Preferences.$toast.hide();
|
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
/**
|
|
|
|
* @function $save
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Save the preferences to the server.
|
|
|
|
*/
|
2015-05-06 18:12:27 +02:00
|
|
|
Preferences.prototype.$save = function() {
|
2015-02-25 23:21:07 +01:00
|
|
|
var _this = this;
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2015-05-19 17:32:12 +02:00
|
|
|
return Preferences.$$resource.save("Preferences", this.$omit(true))
|
2015-02-25 23:21:07 +01:00
|
|
|
.then(function(data) {
|
|
|
|
// Make a copy of the data for an eventual reset
|
|
|
|
//_this.$shadowData = _this.$omit(true);
|
|
|
|
return data;
|
|
|
|
});
|
2015-05-06 18:12:27 +02:00
|
|
|
};
|
2015-02-25 23:21:07 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $omit
|
|
|
|
* @memberof Preferences.prototype
|
|
|
|
* @desc Return a sanitized object used to send to the server.
|
|
|
|
* @param {Boolean} [deep] - make a deep copy if true
|
|
|
|
* @return an object literal copy of the Preferences instance
|
|
|
|
*/
|
2015-05-06 18:12:27 +02:00
|
|
|
Preferences.prototype.$omit = function(deep) {
|
2015-11-24 21:05:03 +01:00
|
|
|
var preferences, labels, whitelist;
|
|
|
|
|
|
|
|
preferences = {};
|
|
|
|
whitelist = {};
|
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
angular.forEach(this, function(value, key) {
|
2015-03-21 20:34:18 +01:00
|
|
|
if (key != 'constructor' && key[0] != '$') {
|
2015-02-25 23:21:07 +01:00
|
|
|
if (deep)
|
|
|
|
preferences[key] = angular.copy(value);
|
|
|
|
else
|
|
|
|
preferences[key] = value;
|
|
|
|
}
|
|
|
|
});
|
2015-03-21 20:34:18 +01:00
|
|
|
|
2017-10-12 21:44:14 +02:00
|
|
|
// Merge back mail labels keys and values
|
|
|
|
preferences.defaults.SOGoMailLabelsColors = {};
|
|
|
|
_.forEach(preferences.defaults.SOGoMailLabelsColorsKeys, function(key, i) {
|
|
|
|
preferences.defaults.SOGoMailLabelsColors[key] = preferences.defaults.SOGoMailLabelsColorsValues[i];
|
|
|
|
});
|
|
|
|
delete preferences.defaults.SOGoMailLabelsColorsKeys;
|
|
|
|
delete preferences.defaults.SOGoMailLabelsColorsValues;
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2017-03-22 18:26:43 +01:00
|
|
|
_.forEach(preferences.defaults.SOGoSieveFilters, function(filter) {
|
|
|
|
_.forEach(filter.actions, function(action) {
|
|
|
|
if (action.method == 'addflag' &&
|
|
|
|
action.argument.charAt(0) == '_' &&
|
|
|
|
action.argument.charAt(1) == '$')
|
|
|
|
action.argument = action.argument.substring(1);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-09-10 18:22:53 +02:00
|
|
|
// See Account.prototype.$omit
|
|
|
|
_.forEach(preferences.defaults.AuxiliaryMailAccounts, function (account) {
|
|
|
|
var identities = [];
|
|
|
|
_.forEach(account.identities, function (identity) {
|
|
|
|
if (!identity.isReadOnly)
|
|
|
|
identities.push(_.pick(identity, ['email', 'fullName', 'replyTo', 'signature', 'isDefault']));
|
|
|
|
});
|
|
|
|
account.identities = identities;
|
|
|
|
});
|
|
|
|
|
2017-09-20 22:50:41 +02:00
|
|
|
if (!preferences.defaults.SOGoMailComposeWindowEnabled)
|
|
|
|
delete preferences.defaults.SOGoMailComposeWindow;
|
|
|
|
delete preferences.defaults.SOGoMailComposeWindowEnabled;
|
|
|
|
|
2016-02-11 22:45:58 +01:00
|
|
|
if (!preferences.defaults.SOGoMailComposeFontSizeEnabled)
|
|
|
|
preferences.defaults.SOGoMailComposeFontSize = 0;
|
2016-02-12 18:03:26 +01:00
|
|
|
delete preferences.defaults.SOGoMailComposeFontSizeEnabled;
|
2016-02-11 22:45:58 +01:00
|
|
|
|
2015-08-17 16:10:57 +02:00
|
|
|
if (preferences.defaults.Vacation) {
|
2016-06-13 21:39:57 +02:00
|
|
|
if (preferences.defaults.Vacation.startDateEnabled)
|
|
|
|
preferences.defaults.Vacation.startDate = preferences.defaults.Vacation.startDate.getTime()/1000;
|
2017-06-01 19:46:57 +02:00
|
|
|
else {
|
|
|
|
delete preferences.defaults.Vacation.startDateEnabled;
|
2016-06-13 21:39:57 +02:00
|
|
|
preferences.defaults.Vacation.startDate = 0;
|
2017-06-01 19:46:57 +02:00
|
|
|
}
|
2015-08-17 16:10:57 +02:00
|
|
|
if (preferences.defaults.Vacation.endDateEnabled)
|
|
|
|
preferences.defaults.Vacation.endDate = preferences.defaults.Vacation.endDate.getTime()/1000;
|
2017-06-01 19:46:57 +02:00
|
|
|
else {
|
|
|
|
delete preferences.defaults.Vacation.endDateEnabled;
|
2015-08-17 16:10:57 +02:00
|
|
|
preferences.defaults.Vacation.endDate = 0;
|
2017-06-01 19:46:57 +02:00
|
|
|
}
|
2015-08-17 16:10:57 +02:00
|
|
|
|
|
|
|
if (preferences.defaults.Vacation.autoReplyEmailAddresses)
|
2020-06-02 20:22:20 +02:00
|
|
|
preferences.defaults.Vacation.autoReplyEmailAddresses = _.compact(preferences.defaults.Vacation.autoReplyEmailAddresses);
|
2015-09-19 01:55:37 +02:00
|
|
|
else
|
|
|
|
preferences.defaults.Vacation.autoReplyEmailAddresses = [];
|
2015-08-17 16:10:57 +02:00
|
|
|
}
|
2015-04-20 23:28:43 +02:00
|
|
|
|
2015-04-28 19:56:50 +02:00
|
|
|
if (preferences.defaults.Forward && preferences.defaults.Forward.forwardAddress)
|
2020-06-02 20:22:20 +02:00
|
|
|
preferences.defaults.Forward.forwardAddress = _.compact(preferences.defaults.Forward.forwardAddress);
|
2015-04-28 19:56:50 +02:00
|
|
|
|
2018-09-11 21:17:31 +02:00
|
|
|
// Merge back calendar categories colors keys and values
|
|
|
|
preferences.defaults.SOGoCalendarCategoriesColors = {};
|
|
|
|
_.forEach(preferences.defaults.SOGoCalendarCategories, function(key, i) {
|
|
|
|
preferences.defaults.SOGoCalendarCategoriesColors[key] = preferences.defaults.SOGoCalendarCategoriesColorsValues[i];
|
|
|
|
});
|
|
|
|
delete preferences.defaults.SOGoCalendarCategoriesColorsValues;
|
|
|
|
|
2015-04-20 23:28:43 +02:00
|
|
|
if (preferences.settings.Calendar && preferences.settings.Calendar.PreventInvitationsWhitelist) {
|
2016-03-03 19:38:54 +01:00
|
|
|
_.forEach(preferences.settings.Calendar.PreventInvitationsWhitelist, function(user) {
|
2015-11-24 21:05:03 +01:00
|
|
|
whitelist[user.uid] = user.$shortFormat();
|
2015-04-20 23:28:43 +02:00
|
|
|
});
|
2015-11-24 21:05:03 +01:00
|
|
|
preferences.settings.Calendar.PreventInvitationsWhitelist = whitelist;
|
2015-04-20 23:28:43 +02:00
|
|
|
}
|
2015-05-06 18:12:27 +02:00
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
return preferences;
|
2015-05-06 18:12:27 +02:00
|
|
|
};
|
|
|
|
|
2015-02-25 23:21:07 +01:00
|
|
|
})();
|