diff --git a/NEWS b/NEWS
index 08d66c4ae..c3667f995 100644
--- a/NEWS
+++ b/NEWS
@@ -30,6 +30,7 @@ Bug fixes
- [web] fixed handling of attendees when updating an event
- [web] show tooltips over long calendar/ab names (#232)
- [web] one-click option to give all permissions for user (#1637)
+ - [web] never query gravatar.com when disabled
3.1.2 (2016-06-06)
------------------
diff --git a/UI/Templates/PreferencesUI/UIxPreferences.wox b/UI/Templates/PreferencesUI/UIxPreferences.wox
index e313289fd..9d1f51b16 100644
--- a/UI/Templates/PreferencesUI/UIxPreferences.wox
+++ b/UI/Templates/PreferencesUI/UIxPreferences.wox
@@ -445,12 +445,14 @@
diff --git a/UI/WebServerResources/img/ic_person_grey_24px.svg b/UI/WebServerResources/img/ic_person_grey_24px.svg
new file mode 100644
index 000000000..ada722383
--- /dev/null
+++ b/UI/WebServerResources/img/ic_person_grey_24px.svg
@@ -0,0 +1,4 @@
+
diff --git a/UI/WebServerResources/js/Common/Common.app.js b/UI/WebServerResources/js/Common/Common.app.js
index 51054e169..9fdbbe742 100644
--- a/UI/WebServerResources/js/Common/Common.app.js
+++ b/UI/WebServerResources/js/Common/Common.app.js
@@ -9,6 +9,9 @@
baseURL: function() {
return ApplicationBaseURL || null;
},
+ resourcesURL: function() {
+ return ResourcesURL || null;
+ },
activeUser: function(param) {
var settings = {
login: UserLogin || null,
diff --git a/UI/WebServerResources/js/Common/User.service.js b/UI/WebServerResources/js/Common/User.service.js
index 8d8597d2d..ac97426a0 100644
--- a/UI/WebServerResources/js/Common/User.service.js
+++ b/UI/WebServerResources/js/Common/User.service.js
@@ -17,12 +17,11 @@
* @desc The factory we'll use to register with Angular.
* @return the User constructor
*/
- User.factory = ['$q', '$log', 'sgSettings', 'Resource', 'Gravatar', function($q, $log, Settings, Resource, Gravatar) {
+ User.factory = ['$q', '$log', 'sgSettings', 'Resource', function($q, $log, Settings, Resource) {
angular.extend(User, {
$q: $q,
$log: $log,
$$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),
- $gravatar: Gravatar,
$query: '',
$users: []
});
@@ -114,7 +113,9 @@
if (!this.$$shortFormat)
this.$$shortFormat = this.$shortFormat();
if (!this.$$image)
- this.$$image = this.image || User.$gravatar(this.c_email, 32, User.$alternateAvatar, {no_404: true});
+ this.$$image = this.image;
+ // NOTE: We can't assign a Gravatar at this stage since we would need the Preferences module
+ // which already depend on the User module.
// An empty attribute to trick md-autocomplete when adding users from the ACLs editor
this.empty = ' ';
diff --git a/UI/WebServerResources/js/Contacts/Card.service.js b/UI/WebServerResources/js/Contacts/Card.service.js
index ef88ce7b5..61b9bbf61 100644
--- a/UI/WebServerResources/js/Contacts/Card.service.js
+++ b/UI/WebServerResources/js/Contacts/Card.service.js
@@ -38,12 +38,11 @@
* @desc The factory we'll use to register with Angular.
* @returns the Card constructor
*/
- Card.$factory = ['$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', 'Gravatar', function($timeout, Settings, Card_STATUS, Resource, Preferences, Gravatar) {
+ Card.$factory = ['$timeout', 'sgSettings', 'sgCard_STATUS', 'Resource', 'Preferences', function($timeout, Settings, Card_STATUS, Resource, Preferences) {
angular.extend(Card, {
STATUS: Card_STATUS,
$$resource: new Resource(Settings.activeUser('folderURL') + 'Contacts', Settings.activeUser()),
$timeout: $timeout,
- $gravatar: Gravatar,
$Preferences: Preferences
});
// Initialize categories from user's defaults
@@ -146,7 +145,7 @@
if (!this.$$email)
this.$$email = this.$preferredEmail(partial);
if (!this.$$image)
- this.$$image = this.image || Card.$gravatar(this.$preferredEmail(partial), 32, Card.$alternateAvatar, {no_404: true});
+ this.$$image = this.image || Card.$Preferences.avatar(this.$$email, 32, {no_404: true});
if (this.isgroup)
this.c_component = 'vlist';
this.$loaded = angular.isDefined(this.c_name)? Card.STATUS.LOADED : Card.STATUS.NOT_LOADED;
diff --git a/UI/WebServerResources/js/Mailer/Message.service.js b/UI/WebServerResources/js/Mailer/Message.service.js
index 2b578e48f..184aa8261 100644
--- a/UI/WebServerResources/js/Mailer/Message.service.js
+++ b/UI/WebServerResources/js/Mailer/Message.service.js
@@ -39,14 +39,14 @@
* @desc The factory we'll use to register with Angular
* @returns the Message constructor
*/
- Message.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgMessage_STATUS', 'Gravatar', 'Resource', 'Preferences', function($q, $timeout, $log, Settings, Message_STATUS, Gravatar, Resource, Preferences) {
+ Message.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgMessage_STATUS', 'Resource', 'Preferences', function($q, $timeout, $log, Settings, Message_STATUS, Resource, Preferences) {
angular.extend(Message, {
STATUS: Message_STATUS,
$q: $q,
$timeout: $timeout,
$log: $log,
- $gravatar: Gravatar,
- $$resource: new Resource(Settings.activeUser('folderURL') + 'Mail', Settings.activeUser())
+ $$resource: new Resource(Settings.activeUser('folderURL') + 'Mail', Settings.activeUser()),
+ $avatar: angular.bind(Preferences, Preferences.avatar)
});
// Initialize tags form user's defaults
Preferences.ready().then(function() {
@@ -172,7 +172,7 @@
* @function $formatFullAddresses
* @memberof Message.prototype
* @desc Format all sender and recipients addresses with a complete description (name ).
- * This function also generates a gravatar for each email address, and a short name
+ * This function also generates the avatar URL for each email address and a short name
*/
Message.prototype.$formatFullAddresses = function() {
var _this = this;
@@ -188,16 +188,15 @@
// Name is already short
data.shortname = data.name;
else if (data.name.split(' ').length)
- // If we have "Alice Foo" as name, we grab "Alice"
- data.shortname = data.name.split(' ')[0].replace('\'','');
+ // If we have "Alice Foo" or "Foo, Alice" as name, we grab "Alice"
+ data.shortname = _.first(_.last(data.name.split(/, */)).split(/ +/)).replace('\'','');
}
else if (data.email) {
data.full = '<' + data.email + '>';
data.shortname = data.email.split('@')[0];
}
- // Generate the gravatar
- data.image = Message.$gravatar(data.email, 32);
+ data.image = Message.$avatar(data.email, 32);
// If the current user is the recepient, overwrite
// the short name with 'me'
@@ -342,13 +341,6 @@
part.type == 'UIxMailPartImageViewer' ||
part.type == 'UIxMailPartLinkViewer') {
- // UIxMailPartICalViewer injects 'participants'
- if (part.participants) {
- _.forEach(part.participants, function(participant) {
- participant.image = Message.$gravatar(participant.email, 32);
- });
- }
-
if (part.type == 'UIxMailPartImageViewer')
part.msgclass = 'msg-attachment-image';
else if (part.type == 'UIxMailPartLinkViewer')
diff --git a/UI/WebServerResources/js/Preferences/Preferences.service.js b/UI/WebServerResources/js/Preferences/Preferences.service.js
index 3fc00d05d..4a6f7e18b 100644
--- a/UI/WebServerResources/js/Preferences/Preferences.service.js
+++ b/UI/WebServerResources/js/Preferences/Preferences.service.js
@@ -116,11 +116,17 @@
this.settingsPromise = Preferences.$$resource.fetch("jsonSettings").then(function(data) {
// We convert our PreventInvitationsWhitelist hash into a array of user
if (data.Calendar) {
- if (data.Calendar.PreventInvitationsWhitelist)
+ if (data.Calendar.PreventInvitationsWhitelist) {
data.Calendar.PreventInvitationsWhitelist = _.map(data.Calendar.PreventInvitationsWhitelist, function(value, key) {
- var match = /^(.+)\s<(\S+)>$/.exec(value);
- return new Preferences.$User({uid: key, cn: match[1], c_email: match[2]});
+ var match = /^(.+)\s<(\S+)>$/.exec(value),
+ user = new Preferences.$User({uid: key, cn: match[1], c_email: match[2]});
+ if (!user.$$image)
+ _this.avatar(user.c_email, 32, {no_404: true}).then(function(url) {
+ user.$$image = url;
+ });
+ return user;
});
+ }
else
data.Calendar.PreventInvitationsWhitelist = [];
}
@@ -136,14 +142,15 @@
* @desc The factory we'll use to register with Angular
* @returns the Preferences constructor
*/
- Preferences.$factory = ['$q', '$timeout', '$log', '$mdDateLocale', 'sgSettings', 'Resource', 'User', function($q, $timeout, $log, $mdDateLocaleProvider, Settings, Resource, User) {
+ Preferences.$factory = ['$q', '$timeout', '$log', '$mdDateLocale', 'sgSettings', 'Gravatar', 'Resource', 'User', function($q, $timeout, $log, $mdDateLocaleProvider, Settings, Gravatar, Resource, User) {
angular.extend(Preferences, {
$q: $q,
$timeout: $timeout,
$log: $log,
$mdDateLocaleProvider: $mdDateLocaleProvider,
+ $gravatar: Gravatar,
$$resource: new Resource(Settings.activeUser('folderURL'), Settings.activeUser()),
- activeUser: Settings.activeUser(),
+ $resourcesURL: Settings.resourcesURL(),
$User: User
});
@@ -172,6 +179,26 @@
return Preferences.$q.all([this.defaultsPromise, this.settingsPromise]);
};
+ /**
+ * @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;
+ return this.ready().then(function() {
+ 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;
+ });
+ };
+
/**
* @function $save
* @memberof Preferences.prototype
diff --git a/UI/WebServerResources/js/Preferences/PreferencesController.js b/UI/WebServerResources/js/Preferences/PreferencesController.js
index 8b46a7792..4e98cc00c 100644
--- a/UI/WebServerResources/js/Preferences/PreferencesController.js
+++ b/UI/WebServerResources/js/Preferences/PreferencesController.js
@@ -29,7 +29,7 @@
vm.editMailFilter = editMailFilter;
vm.removeMailFilter = removeMailFilter;
vm.addDefaultEmailAddresses = addDefaultEmailAddresses;
- vm.userFilter = User.$filter;
+ vm.userFilter = userFilter;
vm.confirmChanges = confirmChanges;
vm.save = save;
vm.canChangePassword = canChangePassword;
@@ -230,6 +230,23 @@
form.$setDirty();
}
+ function userFilter(search, excludedUsers) {
+ return User.$filter(search, excludedUsers).then(function(users) {
+ // Set users avatars
+ _.forEach(users, function(user) {
+ if (!user.$$image) {
+ if (user.image)
+ user.$$image = user.image;
+ else
+ vm.preferences.avatar(user.c_email, 32, {no_404: true}).then(function(url) {
+ user.$$image = url;
+ });
+ }
+ });
+ return users;
+ });
+ }
+
function confirmChanges($event, form) {
var target;
diff --git a/UI/WebServerResources/scss/components/chips/chips.scss b/UI/WebServerResources/scss/components/chips/chips.scss
index 1eabd79ff..8ec4d77b4 100644
--- a/UI/WebServerResources/scss/components/chips/chips.scss
+++ b/UI/WebServerResources/scss/components/chips/chips.scss
@@ -56,7 +56,8 @@ md-chips {
}
// Enlarge the default autocompletion menu
-.sg-chips-autocomplete {
+.sg-chips-autocomplete,
+.sg-chips-autocomplete input {
width: (3 * $contact-chip-name-width);
@media (max-width: $layout-breakpoint-xs) {
// Enlarge the autocompletion menu on small devices to fit the entire screen