Expose all email addresses in autocompletion
This change is immediately applicable to LDAP-based system address books. However, personal SQL-based address books must have their quick tables recreated. To do so, one must use sogo-tool to backup and restore the user's data. Resolves #3443, #3526pull/210/head
parent
6dc80e1159
commit
fd4b09428f
3
NEWS
3
NEWS
|
@ -1,6 +1,9 @@
|
||||||
3.1.1 (2016-MM-DD)
|
3.1.1 (2016-MM-DD)
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
|
Enhancements
|
||||||
|
- [web] expose all email addresses in autocompletion of message editor (#3443)
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
- [web] fixed creation of chip on blur (sgTransformOnBlur directive)
|
- [web] fixed creation of chip on blur (sgTransformOnBlur directive)
|
||||||
- [web] fixed composition of new messages from Contacts module
|
- [web] fixed composition of new messages from Contacts module
|
||||||
|
|
|
@ -45,7 +45,7 @@ objectclass ( 2.5.6.7 NAME 'organizationalPerson'
|
||||||
SUP person STRUCTURAL
|
SUP person STRUCTURAL
|
||||||
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
|
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
|
||||||
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
|
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
|
||||||
telephoneNumber $ internationaliSDNNumber $
|
telephoneNumber $ internationaliSDNNumber $
|
||||||
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
|
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
|
||||||
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
|
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
|
||||||
|
|
||||||
|
@ -64,10 +64,10 @@ objectclass ( 2.16.840.1.113730.3.2.2
|
||||||
userSMIMECertificate $ userPKCS12 )
|
userSMIMECertificate $ userPKCS12 )
|
||||||
)
|
)
|
||||||
|
|
||||||
objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
|
objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
|
||||||
SUP top AUXILIARY
|
SUP top AUXILIARY
|
||||||
MUST ( cn )
|
MUST ( cn )
|
||||||
MAY( c $
|
MAY( c $
|
||||||
description $
|
description $
|
||||||
displayName $
|
displayName $
|
||||||
facsimileTelephoneNumber $
|
facsimileTelephoneNumber $
|
||||||
|
@ -257,7 +257,7 @@ convention:
|
||||||
given: [ldifRecord objectForKey: @"givenname"]
|
given: [ldifRecord objectForKey: @"givenname"]
|
||||||
additional: nil prefixes: nil suffixes: nil];
|
additional: nil prefixes: nil suffixes: nil];
|
||||||
[self setNickname: [ldifRecord objectForKey: @"mozillanickname"]];
|
[self setNickname: [ldifRecord objectForKey: @"mozillanickname"]];
|
||||||
[self setTitle: [ldifRecord objectForKey: @"title"]];
|
[self setTitle: [ldifRecord objectForKey: @"title"]];
|
||||||
|
|
||||||
fn = [ldifRecord objectForKey: @"displayname"];
|
fn = [ldifRecord objectForKey: @"displayname"];
|
||||||
if (!fn)
|
if (!fn)
|
||||||
|
@ -294,7 +294,7 @@ convention:
|
||||||
|
|
||||||
ou = [ldifRecord objectForKey: @"ou"];
|
ou = [ldifRecord objectForKey: @"ou"];
|
||||||
if ([ou isKindOfClass: [NSArray class]])
|
if ([ou isKindOfClass: [NSArray class]])
|
||||||
units = [NSArray arrayWithArray: ou];
|
units = [NSArray arrayWithArray: (NSArray *)ou];
|
||||||
else if (ou)
|
else if (ou)
|
||||||
units = [NSArray arrayWithObject: ou];
|
units = [NSArray arrayWithObject: ou];
|
||||||
else
|
else
|
||||||
|
@ -308,7 +308,7 @@ convention:
|
||||||
setSingleValue: [ldifRecord objectForKey: @"mozillahomeurl"] forKey: @""];
|
setSingleValue: [ldifRecord objectForKey: @"mozillahomeurl"] forKey: @""];
|
||||||
[[self elementWithTag: @"url" ofType: @"work"]
|
[[self elementWithTag: @"url" ofType: @"work"]
|
||||||
setSingleValue: [ldifRecord objectForKey: @"mozillaworkurl"] forKey: @""];
|
setSingleValue: [ldifRecord objectForKey: @"mozillaworkurl"] forKey: @""];
|
||||||
|
|
||||||
[[self uniqueChildWithTag: @"x-aim"]
|
[[self uniqueChildWithTag: @"x-aim"]
|
||||||
setSingleValue: [ldifRecord objectForKey: @"nsaimid"]
|
setSingleValue: [ldifRecord objectForKey: @"nsaimid"]
|
||||||
forKey: @""];
|
forKey: @""];
|
||||||
|
@ -343,7 +343,7 @@ convention:
|
||||||
|
|
||||||
o = [ldifRecord objectForKey: @"vcardcategories"];
|
o = [ldifRecord objectForKey: @"vcardcategories"];
|
||||||
|
|
||||||
// We can either have an array (from SOGo's web gui) or a
|
// We can either have an array (from SOGo's web gui) or a
|
||||||
// string (from a LDIF import) as the value here.
|
// string (from a LDIF import) as the value here.
|
||||||
if ([o isKindOfClass: [NSArray class]])
|
if ([o isKindOfClass: [NSArray class]])
|
||||||
[self setCategories: o];
|
[self setCategories: o];
|
||||||
|
@ -356,7 +356,7 @@ convention:
|
||||||
/* VCARD -> LDIF */
|
/* VCARD -> LDIF */
|
||||||
- (NSString *) _simpleValueForType: (NSString *) aType
|
- (NSString *) _simpleValueForType: (NSString *) aType
|
||||||
inArray: (NSArray *) anArray
|
inArray: (NSArray *) anArray
|
||||||
excluding: (NSString *) aTypeToExclude
|
excluding: (NSString *) aTypeToExclude
|
||||||
{
|
{
|
||||||
NSArray *elements;
|
NSArray *elements;
|
||||||
NSString *value;
|
NSString *value;
|
||||||
|
@ -377,7 +377,7 @@ convention:
|
||||||
|
|
||||||
if (!aTypeToExclude)
|
if (!aTypeToExclude)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
|
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -609,8 +609,8 @@ convention:
|
||||||
to: [self _simpleValueForType: @"home" inArray: elements
|
to: [self _simpleValueForType: @"home" inArray: elements
|
||||||
excluding: nil]
|
excluding: nil]
|
||||||
inLDIFRecord: ldifRecord];
|
inLDIFRecord: ldifRecord];
|
||||||
|
|
||||||
// If we don't have a "work" or "home" URL but we still have
|
// If we don't have a "work" or "home" URL but we still have
|
||||||
// an URL field present, let's add it to the "home" value
|
// an URL field present, let's add it to the "home" value
|
||||||
if ([[ldifRecord objectForKey: @"mozillaworkurl"] length] == 0 &&
|
if ([[ldifRecord objectForKey: @"mozillaworkurl"] length] == 0 &&
|
||||||
[[ldifRecord objectForKey: @"mozillahomeurl"] length] == 0 &&
|
[[ldifRecord objectForKey: @"mozillahomeurl"] length] == 0 &&
|
||||||
|
@ -640,7 +640,7 @@ convention:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[self _setValue: @"title" to: [self title] inLDIFRecord: ldifRecord];
|
[self _setValue: @"title" to: [self title] inLDIFRecord: ldifRecord];
|
||||||
[self _setupOrgFieldsInLDIFRecord: ldifRecord];
|
[self _setupOrgFieldsInLDIFRecord: ldifRecord];
|
||||||
|
|
||||||
|
@ -683,7 +683,7 @@ convention:
|
||||||
{
|
{
|
||||||
CardElement *org;
|
CardElement *org;
|
||||||
NSString *company;
|
NSString *company;
|
||||||
|
|
||||||
org = [self org];
|
org = [self org];
|
||||||
company = [org flattenedValueAtIndex: 0 forKey: @""];
|
company = [org flattenedValueAtIndex: 0 forKey: @""];
|
||||||
if ([company length] == 0)
|
if ([company length] == 0)
|
||||||
|
@ -696,7 +696,7 @@ convention:
|
||||||
{
|
{
|
||||||
CardElement *n;
|
CardElement *n;
|
||||||
NSString *fn, *firstName, *lastName, *org;
|
NSString *fn, *firstName, *lastName, *org;
|
||||||
|
|
||||||
fn = [self fn];
|
fn = [self fn];
|
||||||
if ([fn length] == 0)
|
if ([fn length] == 0)
|
||||||
{
|
{
|
||||||
|
@ -723,6 +723,29 @@ convention:
|
||||||
return fn;
|
return fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray *) emails
|
||||||
|
{
|
||||||
|
NSArray *elements;
|
||||||
|
NSMutableArray *emails;
|
||||||
|
NSString *email;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
emails = [NSMutableArray array];
|
||||||
|
elements = [self childrenWithTag: @"email"];
|
||||||
|
|
||||||
|
for (i = [elements count]-1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
email = [[elements objectAtIndex: i] flattenedValuesForKey: @""];
|
||||||
|
if ([email caseInsensitiveCompare: [self preferredEMail]] == NSOrderedSame)
|
||||||
|
// First element of array is the preferred email address
|
||||||
|
[emails insertObject: email atIndex: 0];
|
||||||
|
else
|
||||||
|
[emails addObject: email];
|
||||||
|
}
|
||||||
|
|
||||||
|
return emails;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSArray *) secondaryEmails
|
- (NSArray *) secondaryEmails
|
||||||
{
|
{
|
||||||
NSMutableArray *emails;
|
NSMutableArray *emails;
|
||||||
|
@ -735,11 +758,11 @@ convention:
|
||||||
[emails removeObjectsInArray: [self childrenWithTag: @"email"
|
[emails removeObjectsInArray: [self childrenWithTag: @"email"
|
||||||
andAttribute: @"type"
|
andAttribute: @"type"
|
||||||
havingValue: @"pref"]];
|
havingValue: @"pref"]];
|
||||||
|
|
||||||
for (i = [emails count]-1; i >= 0; i--)
|
for (i = [emails count]-1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
email = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
|
email = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
|
||||||
|
|
||||||
if ([email caseInsensitiveCompare: [self preferredEMail]] == NSOrderedSame)
|
if ([email caseInsensitiveCompare: [self preferredEMail]] == NSOrderedSame)
|
||||||
[emails removeObjectAtIndex: i];
|
[emails removeObjectAtIndex: i];
|
||||||
}
|
}
|
||||||
|
@ -771,7 +794,7 @@ convention:
|
||||||
|
|
||||||
if (!aTypeToExclude)
|
if (!aTypeToExclude)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
|
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -824,7 +847,7 @@ convention:
|
||||||
andShortTimeString: nil
|
andShortTimeString: nil
|
||||||
inTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
|
inTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
|
||||||
}
|
}
|
||||||
|
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -849,10 +872,12 @@ convention:
|
||||||
value = [self preferredTel];
|
value = [self preferredTel];
|
||||||
if (value)
|
if (value)
|
||||||
[fields setObject: value forKey: @"c_telephonenumber"];
|
[fields setObject: value forKey: @"c_telephonenumber"];
|
||||||
value = [self preferredEMail];
|
v = [self emails];
|
||||||
if (![value isNotNull])
|
if ([v count] > 0)
|
||||||
value = @"";
|
[fields setObject: [v componentsJoinedByString: @","]
|
||||||
[fields setObject: value forKey: @"c_mail"];
|
forKey: @"c_mail"];
|
||||||
|
else
|
||||||
|
[fields setObject: [NSNull null] forKey: @"c_mail"];
|
||||||
element = [self org];
|
element = [self org];
|
||||||
[fields setObject: [element flattenedValueAtIndex: 0 forKey: @""]
|
[fields setObject: [element flattenedValueAtIndex: 0 forKey: @""]
|
||||||
forKey: @"c_o"];
|
forKey: @"c_o"];
|
||||||
|
|
|
@ -264,9 +264,23 @@ static NSArray *folderListingFields = nil;
|
||||||
data = [contactRecord objectForKey: @"c_mail"];
|
data = [contactRecord objectForKey: @"c_mail"];
|
||||||
if ([data length])
|
if ([data length])
|
||||||
{
|
{
|
||||||
|
NSArray *values;
|
||||||
NSDictionary *email;
|
NSDictionary *email;
|
||||||
email = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil];
|
NSMutableArray *emails;
|
||||||
[contactRecord setObject: [NSArray arrayWithObject: email] forKey: @"emails"];
|
NSString *type, *value;
|
||||||
|
int i, max;
|
||||||
|
|
||||||
|
values = [data componentsSeparatedByString: @","];
|
||||||
|
max = [values count];
|
||||||
|
emails = [NSMutableArray arrayWithCapacity: max];
|
||||||
|
for (i = 0; i < max; i++)
|
||||||
|
{
|
||||||
|
type = (i == 0)? @"pref" : @"home";
|
||||||
|
value = [values objectAtIndex: i];
|
||||||
|
email = [NSDictionary dictionaryWithObjectsAndKeys: type, @"type", value, @"value", nil];
|
||||||
|
[emails addObject: email];
|
||||||
|
}
|
||||||
|
[contactRecord setObject: emails forKey: @"emails"];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -64,7 +64,7 @@
|
||||||
md-selected-item="editor.autocomplete.to.selected"
|
md-selected-item="editor.autocomplete.to.selected"
|
||||||
md-items="user in editor.contactFilter(editor.autocomplete.to.searchText)"
|
md-items="user in editor.contactFilter(editor.autocomplete.to.searchText)"
|
||||||
md-min-length="3"
|
md-min-length="3"
|
||||||
md-delay="300"
|
md-delay="150"
|
||||||
md-no-cache="true"
|
md-no-cache="true"
|
||||||
label:placeholder="Add a recipient">
|
label:placeholder="Add a recipient">
|
||||||
<md-item-template>
|
<md-item-template>
|
||||||
|
|
|
@ -424,6 +424,27 @@
|
||||||
return this.refs.length - 1;
|
return this.refs.length - 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @function explode
|
||||||
|
* @memberof Card.prototype
|
||||||
|
* @desc Create a new Card associated to each email address of this card.
|
||||||
|
* @return an array of Card instances
|
||||||
|
*/
|
||||||
|
Card.prototype.explode = function() {
|
||||||
|
var _this = this, cards = [], data;
|
||||||
|
|
||||||
|
if (this.emails.length > 1) {
|
||||||
|
data = this.$omit();
|
||||||
|
_.forEach(this.emails, function(email) {
|
||||||
|
var card = new Card(angular.extend({}, data, {emails: [email]}));
|
||||||
|
cards.push(card);
|
||||||
|
});
|
||||||
|
return cards;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return [this];
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @function $reset
|
* @function $reset
|
||||||
* @memberof Card.prototype
|
* @memberof Card.prototype
|
||||||
|
|
|
@ -197,8 +197,20 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function contactFilter($query) {
|
function contactFilter($query) {
|
||||||
AddressBook.$filterAll($query);
|
return AddressBook.$filterAll($query).then(function(cards) {
|
||||||
return AddressBook.$cards;
|
// Divide the matching cards by email addresses so the user can select
|
||||||
|
// the recipient address of her choice
|
||||||
|
var explodedCards = [];
|
||||||
|
_.forEach(_.invokeMap(cards, 'explode'), function(manyCards) {
|
||||||
|
_.forEach(manyCards, function(card) {
|
||||||
|
explodedCards.push(card);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
// Remove duplicates
|
||||||
|
return _.uniqBy(explodedCards, function(card) {
|
||||||
|
return card.$$fullname + ' ' + card.$$email;
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRecipient(contact, field) {
|
function addRecipient(contact, field) {
|
||||||
|
|
Loading…
Reference in New Issue