2014-11-25 22:09:55 +01:00
|
|
|
/* -*- Mode: javascript; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
|
|
|
|
|
|
|
(function() {
|
|
|
|
'use strict';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @name Mailbox
|
|
|
|
* @constructor
|
|
|
|
* @param {object} futureMailboxData - either an object literal or a promise
|
|
|
|
*/
|
2014-11-30 14:50:26 +01:00
|
|
|
function Mailbox(account, futureMailboxData) {
|
|
|
|
this.$account = account;
|
2014-11-25 22:09:55 +01:00
|
|
|
// Data is immediately available
|
|
|
|
if (typeof futureMailboxData.then !== 'function') {
|
|
|
|
angular.extend(this, futureMailboxData);
|
|
|
|
this.id = this.$id();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// The promise will be unwrapped first
|
|
|
|
// NOTE: this condition never happen for the moment
|
|
|
|
this.$unwrap(futureMailboxData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @memberof Mailbox
|
|
|
|
* @desc The factory we'll use to register with Angular
|
|
|
|
* @returns the Mailbox constructor
|
|
|
|
*/
|
|
|
|
Mailbox.$factory = ['$q', '$timeout', '$log', 'sgSettings', 'sgResource', 'sgMessage', 'sgMailbox_PRELOAD', function($q, $timeout, $log, Settings, Resource, Message, PRELOAD) {
|
|
|
|
angular.extend(Mailbox, {
|
|
|
|
$q: $q,
|
|
|
|
$timeout: $timeout,
|
|
|
|
$log: $log,
|
|
|
|
$$resource: new Resource(Settings.baseURL, Settings.activeUser),
|
|
|
|
$Message: Message,
|
|
|
|
PRELOAD: PRELOAD
|
|
|
|
});
|
|
|
|
|
|
|
|
return Mailbox; // return constructor
|
|
|
|
}];
|
|
|
|
|
|
|
|
angular.module('SOGo.MailerUI')
|
|
|
|
/* Factory constants */
|
|
|
|
.constant('sgMailbox_PRELOAD', {
|
|
|
|
LOOKAHEAD: 50,
|
|
|
|
SIZE: 100
|
|
|
|
})
|
|
|
|
/* Factory registration in Angular module */
|
|
|
|
.factory('sgMailbox', Mailbox.$factory);
|
|
|
|
|
2014-11-30 14:50:26 +01:00
|
|
|
/**
|
|
|
|
* @function $delete
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Delete the mailbox from the server
|
|
|
|
* @returns a promise of the HTTP operation
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$delete = function() {
|
|
|
|
var _this = this,
|
|
|
|
d = Mailbox.$q.defer(),
|
|
|
|
promise;
|
|
|
|
|
|
|
|
promise = Mailbox.$$resource.remove(this.id);
|
|
|
|
|
|
|
|
promise.then(function() {
|
|
|
|
_this.$account.$getMailboxes();
|
|
|
|
d.resolve(true);
|
|
|
|
}, function(data, status) {
|
|
|
|
d.reject(data);
|
|
|
|
});
|
|
|
|
return d.promise;
|
|
|
|
};
|
|
|
|
|
2014-11-25 22:09:55 +01:00
|
|
|
/**
|
|
|
|
* @memberof Mailbox
|
|
|
|
* @desc Fetch list of mailboxes of a specific account
|
2014-11-30 14:50:26 +01:00
|
|
|
* @param {string} accountId - the account
|
2014-11-25 22:09:55 +01:00
|
|
|
* @see {@link Account.$getMailboxes}
|
|
|
|
*/
|
2014-11-30 14:50:26 +01:00
|
|
|
Mailbox.$find = function(account) {
|
2014-11-25 22:09:55 +01:00
|
|
|
var path, futureMailboxData;
|
|
|
|
|
2014-11-30 14:50:26 +01:00
|
|
|
path = Mailbox.$absolutePath(account.id);
|
2014-11-25 22:09:55 +01:00
|
|
|
futureMailboxData = this.$$resource.post(path, 'view', {sortingAttributes: {sort: 'date', asc: false}});
|
|
|
|
|
2014-11-30 14:50:26 +01:00
|
|
|
return Mailbox.$unwrapCollection(account, futureMailboxData); // a collection of mailboxes
|
2014-11-25 22:09:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @memberof Mailbox
|
|
|
|
* @desc Unwrap to a collection of Mailbox instances.
|
2014-11-30 14:50:26 +01:00
|
|
|
* @param {string} account - the account
|
2014-11-25 22:09:55 +01:00
|
|
|
* @param {promise} futureMailboxData - a promise of the mailboxes metadata
|
|
|
|
* @returns a promise of a collection of Mailbox objects
|
|
|
|
*/
|
2014-11-30 14:50:26 +01:00
|
|
|
Mailbox.$unwrapCollection = function(account, futureMailboxData) {
|
2014-11-25 22:09:55 +01:00
|
|
|
var collection = [],
|
|
|
|
// Local recursive function
|
|
|
|
createMailboxes = function(mailbox) {
|
|
|
|
for (var i = 0; i < mailbox.children.length; i++) {
|
2014-11-30 14:50:26 +01:00
|
|
|
mailbox.children[i] = new Mailbox(account, mailbox.children[i]);
|
2014-11-25 22:09:55 +01:00
|
|
|
createMailboxes(mailbox.children[i]);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
//collection.$futureMailboxData = futureMailboxData;
|
|
|
|
|
|
|
|
return futureMailboxData.then(function(data) {
|
|
|
|
return Mailbox.$timeout(function() {
|
|
|
|
// Each entry is spun up as a Mailbox instance
|
|
|
|
angular.forEach(data.mailboxes, function(data, index) {
|
2014-11-30 14:50:26 +01:00
|
|
|
var mailbox = new Mailbox(account, data);
|
2014-11-25 22:09:55 +01:00
|
|
|
createMailboxes(mailbox); // recursively create all sub-mailboxes
|
|
|
|
collection.push(mailbox);
|
|
|
|
});
|
|
|
|
return collection;
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @memberof Mailbox
|
|
|
|
* @desc Build the path of the mailbox (or account only).
|
|
|
|
* @param {string} accountId - the account ID
|
|
|
|
* @param {string} [mailboxPath] - an array of the mailbox path components
|
|
|
|
* @returns a string representing the path relative to the mail module
|
|
|
|
*/
|
|
|
|
Mailbox.$absolutePath = function(accountId, mailboxPath) {
|
|
|
|
var path = [];
|
|
|
|
|
|
|
|
if (mailboxPath) {
|
|
|
|
path = _.map(mailboxPath.split('/'), function(component) {
|
|
|
|
return 'folder' + component.asCSSIdentifier();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
path.splice(0, 0, accountId); // insert account ID
|
|
|
|
|
|
|
|
return path.join('/');
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $id
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Build the unique ID to identified the mailbox.
|
|
|
|
* @returns a string representing the path relative to the mail module
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$id = function() {
|
2014-11-30 14:50:26 +01:00
|
|
|
return Mailbox.$absolutePath(this.$account.id, this.path);
|
2014-11-25 22:09:55 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $update
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Fetch the messages metadata of the mailbox.
|
|
|
|
* @returns a promise of the HTTP operation
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$update = function() {
|
|
|
|
var futureMailboxData;
|
|
|
|
|
|
|
|
futureMailboxData = Mailbox.$$resource.post(this.id, 'view', {sortingAttributes: {sort: 'date', asc: false}});
|
|
|
|
|
|
|
|
return this.$unwrap(futureMailboxData);
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $loadMessage
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Check if the message is loaded and in any case, fetch more messages headers from the server.
|
|
|
|
* @returns true if the message metadata are already fetched
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$loadMessage = function(messageId) {
|
|
|
|
var startIndex = this.uidsMap[messageId],
|
|
|
|
endIndex,
|
|
|
|
max = this.$messages.length,
|
|
|
|
loaded = false,
|
|
|
|
uids,
|
|
|
|
futureHeadersData;
|
|
|
|
if (angular.isDefined(this.uidsMap[messageId]) && startIndex < this.$messages.length) {
|
|
|
|
// Index is valid
|
|
|
|
if (angular.isDefined(this.$messages[startIndex].subject)) {// || this.$messages[startIndex].loading) {
|
|
|
|
// Message headers are loaded or data is coming
|
|
|
|
loaded = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Preload more headers if possible
|
|
|
|
endIndex = Math.min(startIndex + Mailbox.PRELOAD.LOOKAHEAD, max - 1);
|
|
|
|
if (!angular.isDefined(this.$messages[endIndex].subject)
|
|
|
|
&& !angular.isDefined(this.$messages[endIndex].loading)) {
|
|
|
|
endIndex = Math.min(startIndex + Mailbox.PRELOAD.SIZE, max);
|
|
|
|
for (uids = []; startIndex < endIndex && startIndex < max; startIndex++) {
|
|
|
|
if (angular.isDefined(this.$messages[startIndex].subject) || this.$messages[startIndex].loading) {
|
|
|
|
// Message at this index is already loaded; increase the end index
|
|
|
|
endIndex++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Message at this index will be loaded
|
|
|
|
uids.push(this.$messages[startIndex].uid);
|
|
|
|
this.$messages[startIndex].loading = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Mailbox.$log.debug('Loading UIDs ' + uids.join(' '));
|
|
|
|
futureHeadersData = Mailbox.$$resource.post(this.id, 'headers', {uids: uids});
|
|
|
|
this.$unwrapHeaders(futureHeadersData);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return loaded;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $omit
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Return a sanitized object used to send to the server.
|
|
|
|
* @return an object literal copy of the Mailbox instance
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$omit = function() {
|
|
|
|
var mailbox = {};
|
|
|
|
angular.forEach(this, function(value, key) {
|
|
|
|
if (key != 'constructor' &&
|
|
|
|
key != 'children' &&
|
|
|
|
key[0] != '$') {
|
|
|
|
mailbox[key] = value;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return mailbox;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $unwrap
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Unwrap a promise and instanciate new Message objects using received data.
|
|
|
|
* @param {promise} futureMailboxData - a promise of the Mailbox's metadata
|
|
|
|
* @returns a promise of the HTTP operation
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$unwrap = function(futureMailboxData) {
|
|
|
|
var _this = this,
|
|
|
|
deferred = Mailbox.$q.defer();
|
|
|
|
|
|
|
|
this.$futureMailboxData = futureMailboxData;
|
|
|
|
this.$futureMailboxData.then(function(data) {
|
|
|
|
Mailbox.$timeout(function() {
|
|
|
|
var uids, headers;
|
|
|
|
|
|
|
|
angular.extend(_this, data);
|
|
|
|
_this.$messages = [];
|
|
|
|
_this.uidsMap = {};
|
|
|
|
|
|
|
|
if (_this.uids) {
|
|
|
|
// First entry of 'headers' are keys
|
|
|
|
headers = _.invoke(_this.headers[0], 'toLowerCase');
|
|
|
|
_this.headers.splice(0, 1);
|
|
|
|
|
|
|
|
// First entry of 'uids' are keys when threaded view is enabled
|
|
|
|
if (_this.threaded) {
|
|
|
|
uids = _this.uids[0];
|
|
|
|
_this.uids.splice(0, 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Instanciate Message objects
|
|
|
|
_.reduce(_this.uids, function(msgs, msg, i) {
|
|
|
|
var data;
|
|
|
|
if (_this.threaded)
|
|
|
|
data = _.object(uids, msg);
|
|
|
|
else
|
|
|
|
data = {uid: msg.toString()};
|
|
|
|
|
|
|
|
// Build map of UID <=> index
|
|
|
|
_this.uidsMap[data.uid] = i;
|
|
|
|
|
2014-11-30 14:50:26 +01:00
|
|
|
msgs.push(new Mailbox.$Message(_this.$account.id, _this.path, data));
|
2014-11-25 22:09:55 +01:00
|
|
|
|
|
|
|
return msgs;
|
|
|
|
}, _this.$messages);
|
|
|
|
|
|
|
|
// Extend Message objects with received headers
|
|
|
|
_.each(_this.headers, function(data) {
|
|
|
|
var msg = _.object(headers, data),
|
|
|
|
i = _this.uidsMap[msg.uid.toString()];
|
|
|
|
_.extend(_this.$messages[i], msg);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
Mailbox.$log.debug('mailbox ' + _this.id + ' ready');
|
|
|
|
deferred.resolve(_this.$messages);
|
|
|
|
});
|
|
|
|
}, function(data) {
|
|
|
|
angular.extend(_this, data);
|
|
|
|
_this.isError = true;
|
|
|
|
deferred.reject();
|
|
|
|
});
|
|
|
|
|
|
|
|
return deferred.promise;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @function $unwrapHeaders
|
|
|
|
* @memberof Mailbox.prototype
|
|
|
|
* @desc Unwrap a promise and extend matching Message objects using received data.
|
|
|
|
* @param {promise} futureHeadersData - a promise of some messages metadata
|
|
|
|
*/
|
|
|
|
Mailbox.prototype.$unwrapHeaders = function(futureHeadersData) {
|
|
|
|
var _this = this;
|
|
|
|
|
|
|
|
futureHeadersData.then(function(data) {
|
|
|
|
Mailbox.$timeout(function() {
|
|
|
|
var headers, j;
|
|
|
|
if (data.length > 0) {
|
|
|
|
// First entry of 'headers' are keys
|
|
|
|
headers = _.invoke(data[0], 'toLowerCase');
|
|
|
|
data.splice(0, 1);
|
|
|
|
_.each(data, function(messageHeaders) {
|
|
|
|
messageHeaders = _.object(headers, messageHeaders);
|
|
|
|
j = _this.uidsMap[messageHeaders.uid.toString()];
|
|
|
|
if (angular.isDefined(j)) {
|
|
|
|
_.extend(_this.$messages[j], messageHeaders);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
})();
|