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, #3526
pull/210/head
Francis Lachapelle 2016-05-25 10:25:53 -04:00
parent 6dc80e1159
commit fd4b09428f
6 changed files with 103 additions and 28 deletions

3
NEWS
View File

@ -1,6 +1,9 @@
3.1.1 (2016-MM-DD)
------------------
Enhancements
- [web] expose all email addresses in autocompletion of message editor (#3443)
Bug fixes
- [web] fixed creation of chip on blur (sgTransformOnBlur directive)
- [web] fixed composition of new messages from Contacts module

View File

@ -45,7 +45,7 @@ objectclass ( 2.5.6.7 NAME 'organizationalPerson'
SUP person STRUCTURAL
MAY ( title $ x121Address $ registeredAddress $ destinationIndicator $
preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $
telephoneNumber $ internationaliSDNNumber $
telephoneNumber $ internationaliSDNNumber $
facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $
postalAddress $ physicalDeliveryOfficeName $ ou $ st $ l ) )
@ -64,10 +64,10 @@ objectclass ( 2.16.840.1.113730.3.2.2
userSMIMECertificate $ userPKCS12 )
)
objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
SUP top AUXILIARY
objectclass ( 1.3.6.1.4.1.13769.9.1 NAME 'mozillaAbPersonAlpha'
SUP top AUXILIARY
MUST ( cn )
MAY( c $
MAY( c $
description $
displayName $
facsimileTelephoneNumber $
@ -257,7 +257,7 @@ convention:
given: [ldifRecord objectForKey: @"givenname"]
additional: nil prefixes: nil suffixes: nil];
[self setNickname: [ldifRecord objectForKey: @"mozillanickname"]];
[self setTitle: [ldifRecord objectForKey: @"title"]];
[self setTitle: [ldifRecord objectForKey: @"title"]];
fn = [ldifRecord objectForKey: @"displayname"];
if (!fn)
@ -294,7 +294,7 @@ convention:
ou = [ldifRecord objectForKey: @"ou"];
if ([ou isKindOfClass: [NSArray class]])
units = [NSArray arrayWithArray: ou];
units = [NSArray arrayWithArray: (NSArray *)ou];
else if (ou)
units = [NSArray arrayWithObject: ou];
else
@ -308,7 +308,7 @@ convention:
setSingleValue: [ldifRecord objectForKey: @"mozillahomeurl"] forKey: @""];
[[self elementWithTag: @"url" ofType: @"work"]
setSingleValue: [ldifRecord objectForKey: @"mozillaworkurl"] forKey: @""];
[[self uniqueChildWithTag: @"x-aim"]
setSingleValue: [ldifRecord objectForKey: @"nsaimid"]
forKey: @""];
@ -343,7 +343,7 @@ convention:
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.
if ([o isKindOfClass: [NSArray class]])
[self setCategories: o];
@ -356,7 +356,7 @@ convention:
/* VCARD -> LDIF */
- (NSString *) _simpleValueForType: (NSString *) aType
inArray: (NSArray *) anArray
excluding: (NSString *) aTypeToExclude
excluding: (NSString *) aTypeToExclude
{
NSArray *elements;
NSString *value;
@ -377,7 +377,7 @@ convention:
if (!aTypeToExclude)
break;
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
break;
@ -609,8 +609,8 @@ convention:
to: [self _simpleValueForType: @"home" inArray: elements
excluding: nil]
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
if ([[ldifRecord objectForKey: @"mozillaworkurl"] length] == 0 &&
[[ldifRecord objectForKey: @"mozillahomeurl"] length] == 0 &&
@ -640,7 +640,7 @@ convention:
}
}
}
[self _setValue: @"title" to: [self title] inLDIFRecord: ldifRecord];
[self _setupOrgFieldsInLDIFRecord: ldifRecord];
@ -683,7 +683,7 @@ convention:
{
CardElement *org;
NSString *company;
org = [self org];
company = [org flattenedValueAtIndex: 0 forKey: @""];
if ([company length] == 0)
@ -696,7 +696,7 @@ convention:
{
CardElement *n;
NSString *fn, *firstName, *lastName, *org;
fn = [self fn];
if ([fn length] == 0)
{
@ -723,6 +723,29 @@ convention:
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
{
NSMutableArray *emails;
@ -735,11 +758,11 @@ convention:
[emails removeObjectsInArray: [self childrenWithTag: @"email"
andAttribute: @"type"
havingValue: @"pref"]];
for (i = [emails count]-1; i >= 0; i--)
{
email = [[emails objectAtIndex: i] flattenedValuesForKey: @""];
if ([email caseInsensitiveCompare: [self preferredEMail]] == NSOrderedSame)
[emails removeObjectAtIndex: i];
}
@ -771,7 +794,7 @@ convention:
if (!aTypeToExclude)
break;
if (![ce hasAttribute: @"type" havingValue: aTypeToExclude])
break;
@ -824,7 +847,7 @@ convention:
andShortTimeString: nil
inTimeZone: [NSTimeZone timeZoneWithName: @"GMT"]];
}
return date;
}
@ -849,10 +872,12 @@ convention:
value = [self preferredTel];
if (value)
[fields setObject: value forKey: @"c_telephonenumber"];
value = [self preferredEMail];
if (![value isNotNull])
value = @"";
[fields setObject: value forKey: @"c_mail"];
v = [self emails];
if ([v count] > 0)
[fields setObject: [v componentsJoinedByString: @","]
forKey: @"c_mail"];
else
[fields setObject: [NSNull null] forKey: @"c_mail"];
element = [self org];
[fields setObject: [element flattenedValueAtIndex: 0 forKey: @""]
forKey: @"c_o"];

View File

@ -264,9 +264,23 @@ static NSArray *folderListingFields = nil;
data = [contactRecord objectForKey: @"c_mail"];
if ([data length])
{
NSArray *values;
NSDictionary *email;
email = [NSDictionary dictionaryWithObjectsAndKeys: @"pref", @"type", data, @"value", nil];
[contactRecord setObject: [NSArray arrayWithObject: email] forKey: @"emails"];
NSMutableArray *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
{

View File

@ -64,7 +64,7 @@
md-selected-item="editor.autocomplete.to.selected"
md-items="user in editor.contactFilter(editor.autocomplete.to.searchText)"
md-min-length="3"
md-delay="300"
md-delay="150"
md-no-cache="true"
label:placeholder="Add a recipient">
<md-item-template>

View File

@ -424,6 +424,27 @@
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
* @memberof Card.prototype

View File

@ -197,8 +197,20 @@
}
function contactFilter($query) {
AddressBook.$filterAll($query);
return AddressBook.$cards;
return AddressBook.$filterAll($query).then(function(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) {