* load list of contacts from the server * show last message of each contact Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>pull/3233/head
parent
db94b5d4af
commit
d091793ceb
@ -0,0 +1,61 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Core\Controller; |
||||
|
||||
use OC\Contacts\ContactsMenu\Manager; |
||||
use OCP\AppFramework\Controller; |
||||
use OCP\AppFramework\Http\JSONResponse; |
||||
use OCP\IRequest; |
||||
|
||||
class ContactsMenuController extends Controller { |
||||
|
||||
/** @var Manager */ |
||||
private $manager; |
||||
|
||||
/** @var string */ |
||||
private $userId; |
||||
|
||||
/** |
||||
* @param IRequest $request |
||||
* @param string $UserId |
||||
* @param Manager $manager |
||||
*/ |
||||
public function __construct(IRequest $request, $UserId, Manager $manager) { |
||||
parent::__construct('core', $request); |
||||
$this->userId = $UserId; |
||||
$this->manager = $manager; |
||||
} |
||||
|
||||
/** |
||||
* @NoAdminRequired |
||||
* |
||||
* @param string|null filter |
||||
* @return JSONResponse |
||||
*/ |
||||
public function index($filter = null) { |
||||
return $this->manager->getEntries($this->userId, $filter); |
||||
} |
||||
|
||||
} |
||||
|
After Width: | Height: | Size: 1.7 KiB |
@ -0,0 +1,515 @@ |
||||
/* global OC.Backbone, Handlebars, Promise, _ */ |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
(function(OC, $, _, Handlebars) { |
||||
'use strict'; |
||||
|
||||
var MENU_TEMPLATE = '' |
||||
+ '<input id="contactsmenu-search" type="search" placeholder="Search contacts …" value="{{searchTerm}}">' |
||||
+ '<div class="content">' |
||||
+ '</div>'; |
||||
var CONTACTS_LIST_TEMPLATE = '' |
||||
+ '{{#unless contacts.length}}' |
||||
+ '<div class="emptycontent">' |
||||
+ ' <a class="icon-search"></a>' |
||||
+ ' <h2>' + t('core', 'No contacts found') + '</h2>' |
||||
+ '</div>' |
||||
+ '{{/unless}}' |
||||
+ '<div id="contactsmenu-contacts"></div>' |
||||
+ '{{#if contactsAppEnabled}}<div class="footer"><a href="{{contactsAppURL}}">' + t('core', 'Show all contacts …') + '</a></div>{{/if}}'; |
||||
var LOADING_TEMPLATE = '' |
||||
+ '<div class="emptycontent">' |
||||
+ ' <a class="icon-loading"></a>' |
||||
+ ' <h2>{{loadingText}}</h2>' |
||||
+ '</div>'; |
||||
var ERROR_TEMPLATE = '' |
||||
+ '<div class="emptycontent">' |
||||
+ ' <h2>' + t('core', 'Could not load your contacts.') + '</h2>' |
||||
+ '</div>'; |
||||
var CONTACT_TEMPLATE = '' |
||||
+ '{{#if contact.avatar}}' |
||||
+ '<img src="{{contact.avatar}}" class="avatar">' |
||||
+ '{{else}}' |
||||
+ '<div class="avatar"></div>' |
||||
+ '{{/if}}' |
||||
+ '<div class="body">' |
||||
+ ' <div class="full-name">{{contact.fullName}}</div>' |
||||
+ ' <div class="last-message">{{contact.lastMessage}}</div>' |
||||
+ '</div>' |
||||
+ '{{#if contact.topAction}}' |
||||
+ '<a class="top-action {{contact.topAction.icon}}" href="{{contact.topAction.hyperlink}}"></a>' |
||||
+ '{{/if}}' |
||||
+ '{{#if contact.hasManyActions}}' |
||||
+ ' <span class="other-actions icon-more"></span>' |
||||
+ ' <div class="menu popovermenu">' |
||||
+ ' <ul>' |
||||
+ ' {{#each contact.actions}}' |
||||
+ ' <li>' |
||||
+ ' <a href="{{hyperlink}}">' |
||||
+ ' <span class="{{icon}}"></span>' |
||||
+ ' <span>{{title}}</span>' |
||||
+ ' </a>' |
||||
+ ' </li>' |
||||
+ ' {{/each}}' |
||||
+ ' </ul>' |
||||
+ ' </div>' |
||||
+ '{{/if}}' |
||||
+ '{{#if contact.hasTwoActions}}' |
||||
+ '<a class="second-action {{contact.secondAction.icon}}" href="{{contact.secondAction.hyperlink}}"></a>' |
||||
+ '{{/if}}'; |
||||
|
||||
/** |
||||
* @class Contact |
||||
*/ |
||||
var Contact = OC.Backbone.Model.extend({ |
||||
defaults: { |
||||
fullName: '', |
||||
lastMessage: '', |
||||
actions: [], |
||||
hasOneAction: false, |
||||
hasTwoActions: false, |
||||
hasManyActions: false |
||||
}, |
||||
|
||||
/** |
||||
* @returns {undefined} |
||||
*/ |
||||
initialize: function() { |
||||
// Add needed property for easier template rendering
|
||||
if (this.get('actions').length === 0) { |
||||
this.set('hasOneAction', true); |
||||
} else if (this.get('actions').length === 1) { |
||||
this.set('hasTwoActions', true); |
||||
this.set('secondAction', this.get('actions')[0]); |
||||
} else { |
||||
this.set('hasManyActions', true); |
||||
} |
||||
} |
||||
}); |
||||
|
||||
/** |
||||
* @class ContactCollection |
||||
*/ |
||||
var ContactCollection = OC.Backbone.Collection.extend({ |
||||
model: Contact |
||||
}); |
||||
|
||||
/** |
||||
* @class ContactsListView |
||||
*/ |
||||
var ContactsListView = OC.Backbone.View.extend({ |
||||
|
||||
/** @type {ContactsCollection} */ |
||||
_collection: undefined, |
||||
|
||||
/** @type {array} */ |
||||
_subViews: [], |
||||
|
||||
/** |
||||
* @param {object} options |
||||
* @returns {undefined} |
||||
*/ |
||||
initialize: function(options) { |
||||
this._collection = options.collection; |
||||
}, |
||||
|
||||
/** |
||||
* @returns {self} |
||||
*/ |
||||
render: function() { |
||||
var self = this; |
||||
self.$el.html(''); |
||||
self._subViews = []; |
||||
|
||||
self._collection.forEach(function(contact) { |
||||
var item = new ContactsListItemView({ |
||||
model: contact |
||||
}); |
||||
item.render(); |
||||
self.$el.append(item.$el); |
||||
item.on('toggle:actionmenu', self._onChildActionMenuToggle, self); |
||||
self._subViews.push(item); |
||||
}); |
||||
|
||||
return self; |
||||
}, |
||||
|
||||
/** |
||||
* Event callback to propagate opening (another) entry's action menu |
||||
* |
||||
* @param {type} $src |
||||
* @returns {undefined} |
||||
*/ |
||||
_onChildActionMenuToggle: function($src) { |
||||
this._subViews.forEach(function(view) { |
||||
view.trigger('parent:toggle:actionmenu', $src); |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
/** |
||||
* @class CotnactsListItemView |
||||
*/ |
||||
var ContactsListItemView = OC.Backbone.View.extend({ |
||||
|
||||
/** @type {string} */ |
||||
className: 'contact', |
||||
|
||||
/** @type {undefined|function} */ |
||||
_template: undefined, |
||||
|
||||
/** @type {Contact} */ |
||||
_model: undefined, |
||||
|
||||
/** @type {boolean} */ |
||||
_actionMenuShown: false, |
||||
|
||||
events: { |
||||
'click .icon-more': '_onToggleActionsMenu' |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} data |
||||
* @returns {undefined} |
||||
*/ |
||||
template: function(data) { |
||||
if (!this._template) { |
||||
this._template = Handlebars.compile(CONTACT_TEMPLATE); |
||||
} |
||||
return this._template(data); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} options |
||||
* @returns {undefined} |
||||
*/ |
||||
initialize: function(options) { |
||||
this._model = options.model; |
||||
this.on('parent:toggle:actionmenu', this._onOtherActionMenuOpened, this); |
||||
}, |
||||
|
||||
/** |
||||
* @returns {self} |
||||
*/ |
||||
render: function() { |
||||
this.$el.html(this.template({ |
||||
contact: this._model.toJSON() |
||||
})); |
||||
this.delegateEvents(); |
||||
|
||||
// Show placeholder iff no avatar is available (avatar is rendered as img, not div)
|
||||
this.$('div.avatar').imageplaceholder(this._model.get('fullName')); |
||||
|
||||
return this; |
||||
}, |
||||
|
||||
/** |
||||
* Toggle the visibility of the action popover menu |
||||
* |
||||
* @private |
||||
* @returns {undefined} |
||||
*/ |
||||
_onToggleActionsMenu: function() { |
||||
this._actionMenuShown = !this._actionMenuShown; |
||||
if (this._actionMenuShown) { |
||||
this.$('.menu').show(); |
||||
} else { |
||||
this.$('.menu').hide(); |
||||
} |
||||
this.trigger('toggle:actionmenu', this.$el); |
||||
}, |
||||
|
||||
/** |
||||
* @private |
||||
* @argument {jQuery} $src |
||||
* @returns {undefined} |
||||
*/ |
||||
_onOtherActionMenuOpened: function($src) { |
||||
if (this.$el.is($src)) { |
||||
// Ignore
|
||||
return; |
||||
} |
||||
this._actionMenuShown = false; |
||||
this.$('.menu').hide(); |
||||
} |
||||
}); |
||||
|
||||
/** |
||||
* @class ContactsMenuView |
||||
*/ |
||||
var ContactsMenuView = OC.Backbone.View.extend({ |
||||
|
||||
/** @type {undefined|function} */ |
||||
_loadingTemplate: undefined, |
||||
|
||||
/** @type {undefined|function} */ |
||||
_errorTemplate: undefined, |
||||
|
||||
/** @type {undefined|function} */ |
||||
_contentTemplate: undefined, |
||||
|
||||
/** @type {undefined|function} */ |
||||
_contactsTemplate: undefined, |
||||
|
||||
/** @type {undefined|ContactCollection} */ |
||||
_contacts: undefined, |
||||
|
||||
events: { |
||||
'input #contactsmenu-search': '_onSearch' |
||||
}, |
||||
|
||||
/** |
||||
* @returns {undefined} |
||||
*/ |
||||
_onSearch: _.debounce(function() { |
||||
this.trigger('search', this.$('#contactsmenu-search').val()); |
||||
}, 700), |
||||
|
||||
/** |
||||
* @param {object} data |
||||
* @returns {string} |
||||
*/ |
||||
loadingTemplate: function(data) { |
||||
if (!this._loadingTemplate) { |
||||
this._loadingTemplate = Handlebars.compile(LOADING_TEMPLATE); |
||||
} |
||||
return this._loadingTemplate(data); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} data |
||||
* @returns {string} |
||||
*/ |
||||
errorTemplate: function(data) { |
||||
if (!this._errorTemplate) { |
||||
this._errorTemplate = Handlebars.compile(ERROR_TEMPLATE); |
||||
} |
||||
return this._errorTemplate(data); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} data |
||||
* @returns {string} |
||||
*/ |
||||
contentTemplate: function(data) { |
||||
if (!this._contentTemplate) { |
||||
this._contentTemplate = Handlebars.compile(MENU_TEMPLATE); |
||||
} |
||||
return this._contentTemplate(data); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} data |
||||
* @returns {string} |
||||
*/ |
||||
contactsTemplate: function(data) { |
||||
if (!this._contactsTemplate) { |
||||
this._contactsTemplate = Handlebars.compile(CONTACTS_LIST_TEMPLATE); |
||||
} |
||||
return this._contactsTemplate(data); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} options |
||||
* @returns {undefined} |
||||
*/ |
||||
initialize: function(options) { |
||||
this.options = options; |
||||
}, |
||||
|
||||
/** |
||||
* @param {string} text |
||||
* @returns {undefined} |
||||
*/ |
||||
showLoading: function(text) { |
||||
this.render(); |
||||
this._contacts = undefined; |
||||
this.$('.content').html(this.loadingTemplate({ |
||||
loadingText: text |
||||
})); |
||||
}, |
||||
|
||||
/** |
||||
* @returns {undefined} |
||||
*/ |
||||
showError: function() { |
||||
this.render(); |
||||
this._contacts = undefined; |
||||
this.$('.content').html(this.errorTemplate()); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} viewData |
||||
* @param {string} searchTerm |
||||
* @returns {undefined} |
||||
*/ |
||||
showContacts: function(viewData, searchTerm) { |
||||
this._contacts = viewData.contacts; |
||||
this.render({ |
||||
contacts: viewData.contacts |
||||
}); |
||||
|
||||
var list = new ContactsListView({ |
||||
collection: viewData.contacts |
||||
}); |
||||
list.render(); |
||||
this.$('.content').html(this.contactsTemplate({ |
||||
contacts: viewData.contacts, |
||||
searchTerm: searchTerm, |
||||
contactsAppEnabled: viewData.contactsAppEnabled, |
||||
contactsAppURL: OC.generateUrl('/apps/contacts') |
||||
})); |
||||
this.$('#contactsmenu-contacts').html(list.$el); |
||||
}, |
||||
|
||||
/** |
||||
* @param {object} data |
||||
* @returns {self} |
||||
*/ |
||||
render: function(data) { |
||||
var searchVal = this.$('#contactsmenu-search').val(); |
||||
this.$el.html(this.contentTemplate(data)); |
||||
|
||||
// Focus search
|
||||
this.$('#contactsmenu-search').val(searchVal); |
||||
this.$('#contactsmenu-search').focus(); |
||||
return this; |
||||
} |
||||
|
||||
}); |
||||
|
||||
/** |
||||
* @param {Object} options |
||||
* @param {jQuery} options.el |
||||
* @param {jQuery} options.trigger |
||||
* @class ContactsMenu |
||||
*/ |
||||
var ContactsMenu = function(options) { |
||||
this.initialize(options); |
||||
}; |
||||
|
||||
ContactsMenu.prototype = { |
||||
/** @type {jQuery} */ |
||||
$el: undefined, |
||||
|
||||
/** @type {jQuery} */ |
||||
_$trigger: undefined, |
||||
|
||||
/** @type {ContactsMenuView} */ |
||||
_view: undefined, |
||||
|
||||
/** @type {Promise} */ |
||||
_contactsPromise: undefined, |
||||
|
||||
/** |
||||
* @param {Object} options |
||||
* @param {jQuery} options.el - the element to render the menu in |
||||
* @param {jQuery} options.trigger - the element to click on to open the menu |
||||
* @returns {undefined} |
||||
*/ |
||||
initialize: function(options) { |
||||
this.$el = options.el; |
||||
this._$trigger = options.trigger; |
||||
|
||||
this._view = new ContactsMenuView({ |
||||
el: this.$el |
||||
}); |
||||
this._view.on('search', function(searchTerm) { |
||||
this._loadContacts(searchTerm); |
||||
}, this); |
||||
|
||||
OC.registerMenu(this._$trigger, this.$el, function() { |
||||
this._toggleVisibility(true); |
||||
}.bind(this)); |
||||
this.$el.on('beforeHide', function() { |
||||
this._toggleVisibility(false); |
||||
}.bind(this)); |
||||
}, |
||||
|
||||
/** |
||||
* @private |
||||
* @param {boolean} show |
||||
* @returns {Promise} |
||||
*/ |
||||
_toggleVisibility: function(show) { |
||||
if (show) { |
||||
return this._loadContacts(); |
||||
} else { |
||||
this.$el.html(''); |
||||
return Promise.resolve(); |
||||
} |
||||
}, |
||||
|
||||
/** |
||||
* @private |
||||
* @param {string|undefined} searchTerm |
||||
* @returns {Promise} |
||||
*/ |
||||
_getContacts: function(searchTerm) { |
||||
var url = OC.generateUrl('/contactsmenu/contacts'); |
||||
return Promise.resolve($.ajax(url, { |
||||
method: 'GET', |
||||
data: { |
||||
filter: searchTerm |
||||
} |
||||
})); |
||||
}, |
||||
|
||||
/** |
||||
* @param {string|undefined} searchTerm |
||||
* @returns {undefined} |
||||
*/ |
||||
_loadContacts: function(searchTerm) { |
||||
var self = this; |
||||
|
||||
if (!self._contactsPromise) { |
||||
self._contactsPromise = self._getContacts(searchTerm); |
||||
} |
||||
|
||||
if (_.isUndefined(searchTerm) || searchTerm === '') { |
||||
self._view.showLoading(t('core', 'Loading your contacts …')); |
||||
} else { |
||||
self._view.showLoading(t('core', 'Looking for {term} …', { |
||||
term: searchTerm |
||||
})); |
||||
} |
||||
return self._contactsPromise.then(function(data) { |
||||
// Convert contact entries to Backbone collection
|
||||
data.contacts = new ContactCollection(data.contacts); |
||||
|
||||
self._view.showContacts(data, searchTerm); |
||||
}, function(e) { |
||||
self._view.showError(); |
||||
console.error('could not load contacts', e); |
||||
}).then(function() { |
||||
// Delete promise, so that contacts are fetched again when the
|
||||
// menu is opened the next time.
|
||||
delete self._contactsPromise; |
||||
}).catch(console.error.bind(this)); |
||||
} |
||||
}; |
||||
|
||||
OC.ContactsMenu = ContactsMenu; |
||||
|
||||
})(OC, $, _, Handlebars); |
||||
@ -0,0 +1,255 @@ |
||||
/* global expect, sinon, _, spyOn, Promise */ |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
* |
||||
*/ |
||||
|
||||
describe('Contacts menu', function() { |
||||
var $triggerEl, |
||||
$menuEl, |
||||
menu; |
||||
|
||||
/** |
||||
* @private |
||||
* @returns {Promise} |
||||
*/ |
||||
function openMenu() { |
||||
return menu._toggleVisibility(true); |
||||
} |
||||
|
||||
beforeEach(function(done) { |
||||
$triggerEl = $('<div class="menutoggle">'); |
||||
$menuEl = $('<div class="menu">'); |
||||
|
||||
menu = new OC.ContactsMenu({ |
||||
el: $menuEl, |
||||
trigger: $triggerEl |
||||
}); |
||||
done(); |
||||
}); |
||||
|
||||
it('shows a loading message while data is being fetched', function() { |
||||
fakeServer.respondWith('GET', OC.generateUrl('/contactsmenu/contacts'), [ |
||||
200, |
||||
{}, |
||||
'' |
||||
]); |
||||
|
||||
openMenu(); |
||||
|
||||
expect($menuEl.html()).toContain('Loading your contacts …'); |
||||
}); |
||||
|
||||
it('shows an error message when loading the contacts data fails', function(done) { |
||||
spyOn(console, 'error'); |
||||
fakeServer.respondWith('GET', OC.generateUrl('/contactsmenu/contacts'), [ |
||||
500, |
||||
{}, |
||||
'' |
||||
]); |
||||
|
||||
var opening = openMenu(); |
||||
|
||||
expect($menuEl.html()).toContain('Loading your contacts …'); |
||||
fakeServer.respond(); |
||||
|
||||
opening.then(function() { |
||||
expect($menuEl.html()).toContain('Could not load your contacts.'); |
||||
expect(console.error).toHaveBeenCalledTimes(1); |
||||
done(); |
||||
}, function(e) { |
||||
done.fail(e); |
||||
}); |
||||
}); |
||||
|
||||
it('loads data successfully', function(done) { |
||||
spyOn(menu, '_getContacts').and.returnValue(Promise.resolve({ |
||||
contacts: [ |
||||
{ |
||||
id: null, |
||||
fullName: 'Acosta Lancaster', |
||||
topAction: { |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:deboraoliver%40centrexin.com' |
||||
}, |
||||
actions: [ |
||||
{ |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:mathisholland%40virxo.com' |
||||
}, |
||||
{ |
||||
title: 'Details', |
||||
icon: 'icon-info', |
||||
hyperlink: 'https:\/\/localhost\/index.php\/apps\/contacts' |
||||
} |
||||
], |
||||
lastMessage: '' |
||||
}, |
||||
{ |
||||
id: null, |
||||
fullName: 'Adeline Snider', |
||||
topAction: { |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:ceciliasoto%40essensia.com' |
||||
}, |
||||
actions: [ |
||||
{ |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:pearliesellers%40inventure.com' |
||||
}, |
||||
{ |
||||
title: 'Details', |
||||
icon: 'icon-info', |
||||
hyperlink: 'https://localhost\/index.php\/apps\/contacts' |
||||
} |
||||
], |
||||
lastMessage: 'cu' |
||||
} |
||||
], |
||||
contactsAppEnabled: true |
||||
})); |
||||
|
||||
openMenu().then(function() { |
||||
expect(menu._getContacts).toHaveBeenCalled(); |
||||
expect($menuEl.html()).toContain('Acosta Lancaster'); |
||||
expect($menuEl.html()).toContain('Adeline Snider'); |
||||
expect($menuEl.html()).toContain('Show all contacts …'); |
||||
done(); |
||||
}, function(e) { |
||||
done.fail(e); |
||||
}); |
||||
|
||||
}); |
||||
|
||||
it('doesn\'t show a link to the contacts app if it\'s disabled', function(done) { |
||||
spyOn(menu, '_getContacts').and.returnValue(Promise.resolve({ |
||||
contacts: [ |
||||
{ |
||||
id: null, |
||||
fullName: 'Acosta Lancaster', |
||||
topAction: { |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:deboraoliver%40centrexin.com' |
||||
}, |
||||
actions: [ |
||||
{ |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:mathisholland%40virxo.com' |
||||
}, |
||||
{ |
||||
title: 'Details', |
||||
icon: 'icon-info', |
||||
hyperlink: 'https:\/\/localhost\/index.php\/apps\/contacts' |
||||
} |
||||
], |
||||
lastMessage: '' |
||||
} |
||||
], |
||||
contactsAppEnabled: false |
||||
})); |
||||
|
||||
openMenu().then(function() { |
||||
expect(menu._getContacts).toHaveBeenCalled(); |
||||
expect($menuEl.html()).not.toContain('Show all contacts …'); |
||||
done(); |
||||
}, function(e) { |
||||
done.fail(e); |
||||
}); |
||||
}); |
||||
|
||||
it('shows only one entry\'s action menu at a time', function(done) { |
||||
spyOn(menu, '_getContacts').and.returnValue(Promise.resolve({ |
||||
contacts: [ |
||||
{ |
||||
id: null, |
||||
fullName: 'Acosta Lancaster', |
||||
topAction: { |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:deboraoliver%40centrexin.com' |
||||
}, |
||||
actions: [ |
||||
{ |
||||
title: 'Details', |
||||
icon: 'icon-info', |
||||
hyperlink: 'https:\/\/localhost\/index.php\/apps\/contacts' |
||||
} |
||||
], |
||||
lastMessage: '' |
||||
}, |
||||
{ |
||||
id: null, |
||||
fullName: 'Adeline Snider', |
||||
topAction: { |
||||
title: 'Mail', |
||||
icon: 'icon-mail', |
||||
hyperlink: 'mailto:ceciliasoto%40essensia.com' |
||||
}, |
||||
actions: [ |
||||
{ |
||||
title: 'Details', |
||||
icon: 'icon-info', |
||||
hyperlink: 'https://localhost\/index.php\/apps\/contacts' |
||||
} |
||||
], |
||||
lastMessage: 'cu' |
||||
} |
||||
], |
||||
contactsAppEnabled: true |
||||
})); |
||||
|
||||
openMenu().then(function() { |
||||
expect(menu._getContacts).toHaveBeenCalled(); |
||||
expect($menuEl.html()).toContain('Adeline Snider'); |
||||
expect($menuEl.html()).toContain('Show all contacts …'); |
||||
|
||||
// Both menus are closed at the beginning
|
||||
expect($menuEl.find('.contact').eq(0).find('.menu').is(':visible')).toBeFalsy(); |
||||
expect($menuEl.find('.contact').eq(1).find('.menu').is(':visible')).toBeFalsy(); |
||||
|
||||
// Open the first one
|
||||
$menuEl.find('.contact').eq(0).find('.other-actions').click(); |
||||
expect($menuEl.find('.contact').eq(0).find('.menu').css('display')).toBe('block'); |
||||
expect($menuEl.find('.contact').eq(1).find('.menu').css('display')).toBe('none'); |
||||
|
||||
// Open the second one
|
||||
$menuEl.find('.contact').eq(1).find('.other-actions').click(); |
||||
expect($menuEl.find('.contact').eq(0).find('.menu').css('display')).toBe('none'); |
||||
expect($menuEl.find('.contact').eq(1).find('.menu').css('display')).toBe('block'); |
||||
|
||||
// Close the second one
|
||||
$menuEl.find('.contact').eq(1).find('.other-actions').click(); |
||||
expect($menuEl.find('.contact').eq(0).find('.menu').css('display')).toBe('none'); |
||||
expect($menuEl.find('.contact').eq(1).find('.menu').css('display')).toBe('none'); |
||||
|
||||
done(); |
||||
}, function(e) { |
||||
done.fail(e); |
||||
}); |
||||
}); |
||||
|
||||
}); |
||||
@ -0,0 +1,57 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu; |
||||
|
||||
use OC\Contacts\ContactsMenu\Actions\LinkAction; |
||||
use OCP\Contacts\ContactsMenu\IActionFactory; |
||||
use OCP\Contacts\ContactsMenu\ILinkAction; |
||||
|
||||
class ActionFactory implements IActionFactory { |
||||
|
||||
/** |
||||
* @param string $icon |
||||
* @param string $name |
||||
* @param string $href |
||||
* @return ILinkAction |
||||
*/ |
||||
public function newLinkAction($icon, $name, $href) { |
||||
$action = new LinkAction(); |
||||
$action->setName($name); |
||||
$action->setIcon($icon); |
||||
$action->setHref($href); |
||||
return $action; |
||||
} |
||||
|
||||
/** |
||||
* @param string $icon |
||||
* @param string $name |
||||
* @param string $email |
||||
* @return ILinkAction |
||||
*/ |
||||
public function newEMailAction($icon, $name, $email) { |
||||
return $this->newLinkAction($icon, $name, 'mailto:' . urlencode($email)); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,82 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu; |
||||
|
||||
use OC\Contacts\ContactsMenu\Providers\EMailProvider; |
||||
use OCP\AppFramework\QueryException; |
||||
use OCP\Contacts\ContactsMenu\IProvider; |
||||
use OCP\ILogger; |
||||
use OCP\IServerContainer; |
||||
|
||||
class ActionProviderStore { |
||||
|
||||
/** @var IServerContainer */ |
||||
private $serverContainer; |
||||
|
||||
/** @var ILogger */ |
||||
private $logger; |
||||
|
||||
/** |
||||
* @param IServerContainer $serverContainer |
||||
*/ |
||||
public function __construct(IServerContainer $serverContainer, ILogger $logger) { |
||||
$this->serverContainer = $serverContainer; |
||||
$this->logger = $logger; |
||||
} |
||||
|
||||
/** |
||||
* @return IProvider[] |
||||
* @throws Exception |
||||
*/ |
||||
public function getProviders() { |
||||
// TODO: include apps |
||||
$providerClasses = $this->getServerProviderClasses(); |
||||
$providers = []; |
||||
|
||||
foreach ($providerClasses as $class) { |
||||
try { |
||||
$providers[] = $this->serverContainer->query($class); |
||||
} catch (QueryException $ex) { |
||||
$this->logger->logException($ex, [ |
||||
'message' => "Could not load contacts menu action provider $class", |
||||
'app' => 'core', |
||||
]); |
||||
throw new \Exception("Could not load contacts menu action provider"); |
||||
} |
||||
} |
||||
|
||||
return $providers; |
||||
} |
||||
|
||||
/** |
||||
* @return string[] |
||||
*/ |
||||
private function getServerProviderClasses() { |
||||
return [ |
||||
EMailProvider::class, |
||||
]; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,103 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu\Actions; |
||||
|
||||
use OCP\Contacts\ContactsMenu\ILinkAction; |
||||
|
||||
class LinkAction implements ILinkAction { |
||||
|
||||
/** @var string */ |
||||
private $icon; |
||||
|
||||
/** @var string */ |
||||
private $name; |
||||
|
||||
/** @var string */ |
||||
private $href; |
||||
|
||||
/** @var int */ |
||||
private $priority = 10; |
||||
|
||||
/** |
||||
* @param string $icon absolute URI to an icon |
||||
*/ |
||||
public function setIcon($icon) { |
||||
$this->icon = $icon; |
||||
} |
||||
|
||||
/** |
||||
* @param string $name |
||||
*/ |
||||
public function setName($name) { |
||||
$this->name = $name; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getName() { |
||||
return $this->name; |
||||
} |
||||
|
||||
/** |
||||
* @param int $priority |
||||
*/ |
||||
public function setPriority($priority) { |
||||
$this->priority = $priority; |
||||
} |
||||
|
||||
/** |
||||
* @return int |
||||
*/ |
||||
public function getPriority() { |
||||
return $this->priority; |
||||
} |
||||
|
||||
/** |
||||
* @param string $href |
||||
*/ |
||||
public function setHref($href) { |
||||
$this->href = $href; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getHref() { |
||||
return $this->href; |
||||
} |
||||
|
||||
/** |
||||
* @return array |
||||
*/ |
||||
public function jsonSerialize() { |
||||
return [ |
||||
'title' => $this->name, |
||||
'icon' => $this->icon, |
||||
'hyperlink' => $this->href, |
||||
]; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,89 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu; |
||||
|
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
use OCP\Contacts\IManager; |
||||
|
||||
class ContactsStore { |
||||
|
||||
/** @var IManager */ |
||||
private $contactsManager; |
||||
|
||||
/** |
||||
* @param IManager $contactsManager |
||||
*/ |
||||
public function __construct(IManager $contactsManager) { |
||||
$this->contactsManager = $contactsManager; |
||||
} |
||||
|
||||
/** |
||||
* @param string|null $filter |
||||
* @return IEntry[] |
||||
*/ |
||||
public function getContacts($filter) { |
||||
$allContacts = $this->contactsManager->search($filter ?: '', [ |
||||
'FN', |
||||
]); |
||||
|
||||
return array_map(function(array $contact) { |
||||
return $this->contactArrayToEntry($contact); |
||||
}, $allContacts); |
||||
} |
||||
|
||||
/** |
||||
* @param array $contact |
||||
* @return Entry |
||||
*/ |
||||
private function contactArrayToEntry(array $contact) { |
||||
$entry = new Entry(); |
||||
|
||||
if (isset($contact['id'])) { |
||||
$entry->setId($contact['id']); |
||||
} |
||||
|
||||
if (isset($contact['FN'])) { |
||||
$entry->setFullName($contact['FN']); |
||||
} |
||||
|
||||
$avatarPrefix = "VALUE=uri:"; |
||||
if (isset($contact['PHOTO']) && strpos($contact['PHOTO'], $avatarPrefix) === 0) { |
||||
$entry->setAvatar(substr($contact['PHOTO'], strlen($avatarPrefix))); |
||||
} |
||||
|
||||
if (isset($contact['EMAIL'])) { |
||||
foreach ($contact['EMAIL'] as $email) { |
||||
$entry->addEMailAddress($email); |
||||
} |
||||
} |
||||
|
||||
// Attach all other properties to the entry too because some |
||||
// providers might make use of it. |
||||
$entry->setProperties($contact); |
||||
|
||||
return $entry; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,169 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu; |
||||
|
||||
use OCP\Contacts\ContactsMenu\IAction; |
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
|
||||
class Entry implements IEntry { |
||||
|
||||
/** @var string|int|null */ |
||||
private $id = null; |
||||
|
||||
/** @var string */ |
||||
private $fullName = ''; |
||||
|
||||
/** @var string[] */ |
||||
private $emailAddresses = []; |
||||
|
||||
/** @var string|null */ |
||||
private $avatar; |
||||
|
||||
/** @var IAction[] */ |
||||
private $actions = []; |
||||
|
||||
/** @var array */ |
||||
private $properties = []; |
||||
|
||||
/** |
||||
* @param string $id |
||||
*/ |
||||
public function setId($id) { |
||||
$this->id = $id; |
||||
} |
||||
|
||||
/** |
||||
* @param string $displayName |
||||
*/ |
||||
public function setFullName($displayName) { |
||||
$this->fullName = $displayName; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getFullName() { |
||||
return $this->fullName; |
||||
} |
||||
|
||||
/** |
||||
* @param string $address |
||||
*/ |
||||
public function addEMailAddress($address) { |
||||
$this->emailAddresses[] = $address; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getEMailAddresses() { |
||||
return $this->emailAddresses; |
||||
} |
||||
|
||||
/** |
||||
* @param string $avatar |
||||
*/ |
||||
public function setAvatar($avatar) { |
||||
$this->avatar = $avatar; |
||||
} |
||||
|
||||
/** |
||||
* @return string |
||||
*/ |
||||
public function getAvatar() { |
||||
return $this->avatar; |
||||
} |
||||
|
||||
/** |
||||
* @param IAction $action |
||||
*/ |
||||
public function addAction(IAction $action) { |
||||
$this->actions[] = $action; |
||||
$this->sortActions(); |
||||
} |
||||
|
||||
/** |
||||
* @return IAction[] |
||||
*/ |
||||
public function getActions() { |
||||
return $this->actions; |
||||
} |
||||
|
||||
/** |
||||
* sort the actions by priority and name |
||||
*/ |
||||
private function sortActions() { |
||||
usort($this->actions, function(IAction $action1, IAction $action2) { |
||||
$prio1 = $action1->getPriority(); |
||||
$prio2 = $action2->getPriority(); |
||||
|
||||
if ($prio1 === $prio2) { |
||||
// Ascending order for same priority |
||||
return strcasecmp($action1->getName(), $action2->getName()); |
||||
} |
||||
|
||||
// Descending order when priority differs |
||||
return $prio2 - $prio1; |
||||
}); |
||||
} |
||||
|
||||
/** |
||||
* @param array $contact key-value array containing additional properties |
||||
*/ |
||||
public function setProperties(array $contact) { |
||||
$this->properties = $contact; |
||||
} |
||||
|
||||
/** |
||||
* @param string $key |
||||
* @return mixed |
||||
*/ |
||||
public function getProperty($key) { |
||||
if (!isset($this->properties[$key])) { |
||||
return null; |
||||
} |
||||
return $this->properties[$key]; |
||||
} |
||||
|
||||
/** |
||||
* @return array |
||||
*/ |
||||
public function jsonSerialize() { |
||||
$topAction = !empty($this->actions) ? $this->actions[0]->jsonSerialize() : null; |
||||
$otherActions = array_map(function(IAction $action) { |
||||
return $action->jsonSerialize(); |
||||
}, array_slice($this->actions, 1)); |
||||
|
||||
return [ |
||||
'id' => $this->id, |
||||
'fullName' => $this->fullName, |
||||
'avatar' => $this->getAvatar(), |
||||
'topAction' => $topAction, |
||||
'actions' => $otherActions, |
||||
'lastMessage' => '', |
||||
]; |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,98 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu; |
||||
|
||||
use OCP\App\IAppManager; |
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
use OCP\IURLGenerator; |
||||
|
||||
class Manager { |
||||
|
||||
/** @var ContactsStore */ |
||||
private $store; |
||||
|
||||
/** @var ActionProviderStore */ |
||||
private $actionProviderStore; |
||||
|
||||
/** @var IAppManager */ |
||||
private $appManager; |
||||
|
||||
/** @var IURLGenerator */ |
||||
private $urlGenerator; |
||||
|
||||
/** |
||||
* @param ContactsStore $store |
||||
* @param ActionProviderStore $actionProviderStore |
||||
* @param IAppManager $appManager |
||||
*/ |
||||
public function __construct(ContactsStore $store, ActionProviderStore $actionProviderStore, IAppManager $appManager) { |
||||
$this->store = $store; |
||||
$this->actionProviderStore = $actionProviderStore; |
||||
$this->appManager = $appManager; |
||||
} |
||||
|
||||
/** |
||||
* @param string $userId |
||||
* @param string $filter |
||||
* @return array |
||||
*/ |
||||
public function getEntries($userId, $filter) { |
||||
$entries = $this->store->getContacts($filter); |
||||
|
||||
$sortedEntries = $this->sortEntries($entries); |
||||
$topEntries = array_slice($sortedEntries, 0, 25); |
||||
$this->processEntries($topEntries); |
||||
|
||||
$contactsEnabled = $this->appManager->isEnabledForUser('contacts', $userId); |
||||
return [ |
||||
'contacts' => $topEntries, |
||||
'contactsAppEnabled' => $contactsEnabled, |
||||
]; |
||||
} |
||||
|
||||
/** |
||||
* @param IEntry[] $entries |
||||
* @return IEntry[] |
||||
*/ |
||||
private function sortEntries(array $entries) { |
||||
usort($entries, function(IEntry $entryA, IEntry $entryB) { |
||||
return strcasecmp($entryA->getFullName(), $entryB->getFullName()); |
||||
}); |
||||
return $entries; |
||||
} |
||||
|
||||
/** |
||||
* @param IEntry[] $entries |
||||
*/ |
||||
private function processEntries(array $entries) { |
||||
$providers = $this->actionProviderStore->getProviders(); |
||||
foreach ($entries as $entry) { |
||||
foreach ($providers as $provider) { |
||||
$provider->process($entry); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,56 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OC\Contacts\ContactsMenu\Providers; |
||||
|
||||
use OCP\Contacts\ContactsMenu\IActionFactory; |
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
use OCP\Contacts\ContactsMenu\IProvider; |
||||
|
||||
class EMailProvider implements IProvider { |
||||
|
||||
/** @var IActionFactory */ |
||||
private $actionFactory; |
||||
|
||||
/** |
||||
* @param IActionFactory $actionFactory |
||||
*/ |
||||
public function __construct(IActionFactory $actionFactory) { |
||||
$this->actionFactory = $actionFactory; |
||||
} |
||||
|
||||
/** |
||||
* @param IEntry $entry |
||||
*/ |
||||
public function process(IEntry $entry) { |
||||
foreach ($entry->getEMailAddresses() as $address) { |
||||
// TODO: absolute path |
||||
// TODO: meaningful URL |
||||
// TODO: l10n |
||||
$action = $this->actionFactory->newEMailAction('icon-mail', 'Mail', $address); |
||||
$entry->addAction($action); |
||||
} |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,65 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCP\Contacts\ContactsMenu; |
||||
|
||||
use JsonSerializable; |
||||
|
||||
/** |
||||
* Apps should use the IActionFactory to create new action objects |
||||
* |
||||
* @since 12.0 |
||||
*/ |
||||
interface IAction extends JsonSerializable { |
||||
|
||||
/** |
||||
* @param string $icon absolute URI to an icon |
||||
* @since 12.0 |
||||
*/ |
||||
public function setIcon($icon); |
||||
|
||||
/** |
||||
* @return string localized action name, e.g. 'Call' |
||||
* @since 12.0 |
||||
*/ |
||||
public function getName(); |
||||
|
||||
/** |
||||
* @param string $name localized action name, e.g. 'Call' |
||||
* @since 12.0 |
||||
*/ |
||||
public function setName($name); |
||||
|
||||
/** |
||||
* @param int $priority priorize actions, high order ones are shown on top |
||||
* @since 12.0 |
||||
*/ |
||||
public function setPriority($priority); |
||||
|
||||
/** |
||||
* @return int priority to priorize actions, high order ones are shown on top |
||||
* @since 12.0 |
||||
*/ |
||||
public function getPriority(); |
||||
} |
||||
@ -0,0 +1,54 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCP\Contacts\ContactsMenu; |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
*/ |
||||
interface IActionFactory { |
||||
|
||||
/** |
||||
* Construct and return a new link action for the contacts menu |
||||
* |
||||
* @since 12.0 |
||||
* |
||||
* @param string $icon full path to the action's icon |
||||
* @param string $name localized name of the action |
||||
* @param string $href target URL |
||||
* @return ILinkAction |
||||
*/ |
||||
public function newLinkAction($icon, $name, $href); |
||||
|
||||
/** |
||||
* Construct and return a new email action for the contacts menu |
||||
* |
||||
* @since 12.0 |
||||
* |
||||
* @param string $icon full path to the action's icon |
||||
* @param string $name localized name of the action |
||||
* @param string $email target e-mail address |
||||
* @return ILinkAction |
||||
*/ |
||||
public function newEMailAction($icon, $name, $email); |
||||
} |
||||
@ -0,0 +1,66 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCP\Contacts\ContactsMenu; |
||||
|
||||
use JsonSerializable; |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
*/ |
||||
interface IEntry extends JsonSerializable { |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @return string |
||||
*/ |
||||
public function getFullName(); |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @return string[] |
||||
*/ |
||||
public function getEMailAddresses(); |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @return string|null image URI |
||||
*/ |
||||
public function getAvatar(); |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @param IAction $action an action to show in the contacts menu |
||||
*/ |
||||
public function addAction(IAction $action); |
||||
|
||||
/** |
||||
* Get an arbitrary property from the contact |
||||
* |
||||
* @since 12.0 |
||||
* @param string $key |
||||
* @return mixed the value of the property or null |
||||
*/ |
||||
public function getProperty($key); |
||||
} |
||||
@ -0,0 +1,43 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCP\Contacts\ContactsMenu; |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
*/ |
||||
interface ILinkAction extends IAction { |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @param string $href the target URL of the action |
||||
*/ |
||||
public function setHref($href); |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @return string |
||||
*/ |
||||
public function getHref(); |
||||
} |
||||
@ -0,0 +1,37 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace OCP\Contacts\ContactsMenu; |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
*/ |
||||
interface IProvider { |
||||
|
||||
/** |
||||
* @since 12.0 |
||||
* @param IEntry $entry |
||||
*/ |
||||
public function process(IEntry $entry); |
||||
} |
||||
@ -0,0 +1,73 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Controller; |
||||
|
||||
use OC\Contacts\ContactsMenu\Manager; |
||||
use OC\Core\Controller\ContactsMenuController; |
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
use OCP\IRequest; |
||||
use PHPUnit_Framework_MockObject_MockObject; |
||||
use Test\TestCase; |
||||
|
||||
class ContactsMenuControllerTest extends TestCase { |
||||
|
||||
/** @var IRequest|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $request; |
||||
|
||||
/** @var string */ |
||||
private $userId; |
||||
|
||||
/** @var Manager|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $contactsManager; |
||||
|
||||
/** @var ContactsMenuController */ |
||||
private $controller; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->request = $this->createMock(IRequest::class); |
||||
$this->userId = 'user4563'; |
||||
$this->contactsManager = $this->createMock(Manager::class); |
||||
|
||||
$this->controller = new ContactsMenuController($this->request, $this->userId, $this->contactsManager); |
||||
} |
||||
|
||||
public function testIndex() { |
||||
$entries = [ |
||||
$this->createMock(IEntry::class), |
||||
$this->createMock(IEntry::class), |
||||
]; |
||||
$this->contactsManager->expects($this->once()) |
||||
->method('getEntries') |
||||
->with($this->equalTo($this->userId), $this->equalTo(null)) |
||||
->willReturn($entries); |
||||
|
||||
$response = $this->controller->index(); |
||||
|
||||
$this->assertEquals($entries, $response); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,67 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu; |
||||
|
||||
use OC\Contacts\ContactsMenu\ActionFactory; |
||||
use OCP\Contacts\ContactsMenu\IAction; |
||||
use Test\TestCase; |
||||
|
||||
class ActionFactoryTest extends TestCase { |
||||
|
||||
/** @var ActionFactory */ |
||||
private $actionFactory; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->actionFactory = new ActionFactory(); |
||||
} |
||||
|
||||
public function testNewLinkAction() { |
||||
$icon = 'icon-test'; |
||||
$name = 'Test'; |
||||
$href = 'some/url'; |
||||
|
||||
$action = $this->actionFactory->newLinkAction($icon, $name, $href); |
||||
|
||||
$this->assertInstanceOf(IAction::class, $action); |
||||
$this->assertEquals($name, $action->getName()); |
||||
$this->assertEquals(10, $action->getPriority()); |
||||
} |
||||
|
||||
public function testNewEMailAction() { |
||||
$icon = 'icon-test'; |
||||
$name = 'Test'; |
||||
$href = 'user@example.com'; |
||||
|
||||
$action = $this->actionFactory->newEMailAction($icon, $name, $href); |
||||
|
||||
$this->assertInstanceOf(IAction::class, $action); |
||||
$this->assertEquals($name, $action->getName()); |
||||
$this->assertEquals(10, $action->getPriority()); |
||||
$this->assertEquals('mailto:user%40example.com', $action->getHref()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,82 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu; |
||||
|
||||
use Exception; |
||||
use OC\Contacts\ContactsMenu\ActionProviderStore; |
||||
use OC\Contacts\ContactsMenu\Providers\EMailProvider; |
||||
use OCP\AppFramework\QueryException; |
||||
use OCP\ILogger; |
||||
use OCP\IServerContainer; |
||||
use PHPUnit_Framework_MockObject_MockObject; |
||||
use Test\TestCase; |
||||
|
||||
class ActionProviderStoreTest extends TestCase { |
||||
|
||||
/** @var IServerContainer|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $serverContainer; |
||||
|
||||
/** @var ILogger|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $logger; |
||||
|
||||
/** @var ActionProviderStore */ |
||||
private $actionProviderStore; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->serverContainer = $this->createMock(IServerContainer::class); |
||||
$this->logger = $this->createMock(ILogger::class); |
||||
$this->actionProviderStore = new ActionProviderStore($this->serverContainer, $this->logger); |
||||
} |
||||
|
||||
public function testGetProviders() { |
||||
$emailProvider = $this->createMock(EMailProvider::class); |
||||
$this->serverContainer->expects($this->exactly(2)) |
||||
->method('query') |
||||
->will($this->returnValueMap([ |
||||
[EMailProvider::class, $emailProvider], |
||||
])); |
||||
|
||||
$providers = $this->actionProviderStore->getProviders(); |
||||
|
||||
$this->assertCount(1, $providers); |
||||
$this->assertInstanceOf(EMailProvider::class, $providers[0]); |
||||
} |
||||
|
||||
/** |
||||
* @expectedException Exception |
||||
*/ |
||||
public function testGetProvidersWithQueryException() { |
||||
$emailProvider = $this->createMock(EMailProvider::class); |
||||
$detailsProvider = $this->createMock(DetailsProvider::class); |
||||
$this->serverContainer->expects($this->once()) |
||||
->method('query') |
||||
->willThrowException(new QueryException()); |
||||
|
||||
$providers = $this->actionProviderStore->getProviders(); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,90 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu\Actions; |
||||
|
||||
use OC\Contacts\ContactsMenu\Actions\LinkAction; |
||||
use Test\TestCase; |
||||
|
||||
class LinkActionTest extends TestCase { |
||||
|
||||
private $action; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->action = new LinkAction(); |
||||
} |
||||
|
||||
public function testSetIcon() { |
||||
$icon = 'icon-test'; |
||||
|
||||
$this->action->setIcon($icon); |
||||
$json = $this->action->jsonSerialize(); |
||||
|
||||
$this->assertArrayHasKey('icon', $json); |
||||
$this->assertEquals($json['icon'], $icon); |
||||
} |
||||
|
||||
public function testGetSetName() { |
||||
$name = 'Jane Doe'; |
||||
|
||||
$this->assertNull($this->action->getName()); |
||||
$this->action->setName($name); |
||||
$this->assertEquals($name, $this->action->getName()); |
||||
} |
||||
|
||||
public function testGetSetPriority() { |
||||
$prio = 50; |
||||
|
||||
$this->assertEquals(10, $this->action->getPriority()); |
||||
$this->action->setPriority($prio); |
||||
$this->assertEquals($prio, $this->action->getPriority()); |
||||
} |
||||
|
||||
public function testSetHref() { |
||||
$this->action->setHref('/some/url'); |
||||
|
||||
$json = $this->action->jsonSerialize(); |
||||
$this->assertArrayHasKey('hyperlink', $json); |
||||
$this->assertEquals($json['hyperlink'], '/some/url'); |
||||
} |
||||
|
||||
public function testJsonSerialize() { |
||||
$this->action->setIcon('icon-contacts'); |
||||
$this->action->setName('Nickie Works'); |
||||
$this->action->setPriority(33); |
||||
$this->action->setHref('example.com'); |
||||
$expected = [ |
||||
'title' => 'Nickie Works', |
||||
'icon' => 'icon-contacts', |
||||
'hyperlink' => 'example.com', |
||||
]; |
||||
|
||||
$json = $this->action->jsonSerialize(); |
||||
|
||||
$this->assertEquals($expected, $json); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,121 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu; |
||||
|
||||
use OC\Contacts\ContactsMenu\ContactsStore; |
||||
use OCP\Contacts\IManager; |
||||
use PHPUnit_Framework_MockObject_MockObject; |
||||
use Test\TestCase; |
||||
|
||||
class ContactsStoreTest extends TestCase { |
||||
|
||||
/** @var ContactsStore */ |
||||
private $contactsStore; |
||||
|
||||
/** @var IManager|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $contactsManager; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->contactsManager = $this->createMock(IManager::class); |
||||
|
||||
$this->contactsStore = new ContactsStore($this->contactsManager); |
||||
} |
||||
|
||||
public function testGetContactsWithoutFilter() { |
||||
$this->contactsManager->expects($this->once()) |
||||
->method('search') |
||||
->with($this->equalTo(''), $this->equalTo(['FN'])) |
||||
->willReturn([ |
||||
[ |
||||
'id' => 123, |
||||
], |
||||
[ |
||||
'id' => 567, |
||||
'FN' => 'Darren Roner', |
||||
'EMAIL' => [ |
||||
'darren@roner.au' |
||||
], |
||||
], |
||||
]); |
||||
|
||||
$entries = $this->contactsStore->getContacts(''); |
||||
|
||||
$this->assertCount(2, $entries); |
||||
$this->assertEquals([ |
||||
'darren@roner.au' |
||||
], $entries[1]->getEMailAddresses()); |
||||
} |
||||
|
||||
public function testGetContactsWithoutBinaryImage() { |
||||
$this->contactsManager->expects($this->once()) |
||||
->method('search') |
||||
->with($this->equalTo(''), $this->equalTo(['FN'])) |
||||
->willReturn([ |
||||
[ |
||||
'id' => 123, |
||||
], |
||||
[ |
||||
'id' => 567, |
||||
'FN' => 'Darren Roner', |
||||
'EMAIL' => [ |
||||
'darren@roner.au' |
||||
], |
||||
'PHOTO' => base64_encode('photophotophoto'), |
||||
], |
||||
]); |
||||
|
||||
$entries = $this->contactsStore->getContacts(''); |
||||
|
||||
$this->assertCount(2, $entries); |
||||
$this->assertNull($entries[1]->getAvatar()); |
||||
} |
||||
|
||||
public function testGetContactsWithoutAvatarURI() { |
||||
$this->contactsManager->expects($this->once()) |
||||
->method('search') |
||||
->with($this->equalTo(''), $this->equalTo(['FN'])) |
||||
->willReturn([ |
||||
[ |
||||
'id' => 123, |
||||
], |
||||
[ |
||||
'id' => 567, |
||||
'FN' => 'Darren Roner', |
||||
'EMAIL' => [ |
||||
'darren@roner.au' |
||||
], |
||||
'PHOTO' => 'VALUE=uri:https://photo', |
||||
], |
||||
]); |
||||
|
||||
$entries = $this->contactsStore->getContacts(''); |
||||
|
||||
$this->assertCount(2, $entries); |
||||
$this->assertEquals('https://photo', $entries[1]->getAvatar()); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,113 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu; |
||||
|
||||
use OC\Contacts\ContactsMenu\Actions\LinkAction; |
||||
use OC\Contacts\ContactsMenu\Entry; |
||||
use OCP\Contacts\ContactsMenu\IAction; |
||||
use Test\TestCase; |
||||
|
||||
class EntryTest extends \PHPUnit_Framework_TestCase { |
||||
|
||||
/** @var Entry */ |
||||
private $entry; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->entry = new Entry(); |
||||
} |
||||
|
||||
public function testSetId() { |
||||
$this->entry->setId(123); |
||||
} |
||||
|
||||
public function testSetGetFullName() { |
||||
$fn = 'Danette Chaille'; |
||||
$this->assertEquals('', $this->entry->getFullName()); |
||||
$this->entry->setFullName($fn); |
||||
$this->assertEquals($fn, $this->entry->getFullName()); |
||||
} |
||||
|
||||
public function testAddGetEMailAddresses() { |
||||
$this->assertEmpty($this->entry->getEMailAddresses()); |
||||
$this->entry->addEMailAddress('user@example.com'); |
||||
$this->assertEquals(['user@example.com'], $this->entry->getEMailAddresses()); |
||||
} |
||||
|
||||
public function testAddAndSortAction() { |
||||
// Three actions, two with equal priority |
||||
$action1 = new LinkAction(); |
||||
$action2 = new LinkAction(); |
||||
$action3 = new LinkAction(); |
||||
$action1->setPriority(10); |
||||
$action1->setName('Bravo'); |
||||
|
||||
$action2->setPriority(0); |
||||
$action2->setName('Batman'); |
||||
|
||||
$action3->setPriority(10); |
||||
$action3->setName('Alfa'); |
||||
|
||||
$this->entry->addAction($action1); |
||||
$this->entry->addAction($action2); |
||||
$this->entry->addAction($action3); |
||||
$sorted = $this->entry->getActions(); |
||||
|
||||
$this->assertSame($action3, $sorted[0]); |
||||
$this->assertSame($action1, $sorted[1]); |
||||
$this->assertSame($action2, $sorted[2]); |
||||
} |
||||
|
||||
public function testSetGetProperties() { |
||||
$props = [ |
||||
'prop1' => 123, |
||||
'prop2' => 'string', |
||||
]; |
||||
|
||||
$this->entry->setProperties($props); |
||||
|
||||
$this->assertNull($this->entry->getProperty('doesntexist')); |
||||
$this->assertEquals(123, $this->entry->getProperty('prop1')); |
||||
$this->assertEquals('string', $this->entry->getProperty('prop2')); |
||||
} |
||||
|
||||
public function testJsonSerialize() { |
||||
$expectedJson = [ |
||||
'id' => 123, |
||||
'fullName' => 'Guadalupe Frisbey', |
||||
'topAction' => null, |
||||
'actions' => [], |
||||
'lastMessage' => '', |
||||
]; |
||||
|
||||
$this->entry->setId(123); |
||||
$this->entry->setFullName('Guadalupe Frisbey'); |
||||
$json = $this->entry->jsonSerialize(); |
||||
|
||||
$this->assertEquals($expectedJson, $json); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,100 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu; |
||||
|
||||
use OC\Contacts\ContactsMenu\ActionProviderStore; |
||||
use OC\Contacts\ContactsMenu\ContactsStore; |
||||
use OC\Contacts\ContactsMenu\Manager; |
||||
use OCP\App\IAppManager; |
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
use OCP\Contacts\ContactsMenu\IProvider; |
||||
use PHPUnit_Framework_MockObject_MockObject; |
||||
use Test\TestCase; |
||||
|
||||
class ManagerTest extends TestCase { |
||||
|
||||
/** @var ContactsStore|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $contactsStore; |
||||
|
||||
/** @var IAppManager|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $appManager; |
||||
|
||||
/** @var ActionProviderStore|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $actionProviderStore; |
||||
|
||||
/** @var Manager */ |
||||
private $manager; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->contactsStore = $this->createMock(ContactsStore::class); |
||||
$this->actionProviderStore = $this->createMock(ActionProviderStore::class); |
||||
$this->appManager = $this->createMock(IAppManager::class); |
||||
|
||||
$this->manager = new Manager($this->contactsStore, $this->actionProviderStore, $this->appManager); |
||||
} |
||||
|
||||
private function generateTestEntries() { |
||||
$entries = []; |
||||
foreach (range('Z', 'A') as $char) { |
||||
$entry = $this->createMock(IEntry::class); |
||||
$entry->expects($this->any()) |
||||
->method('getFullName') |
||||
->willReturn('Contact ' . $char); |
||||
$entries[] = $entry; |
||||
} |
||||
return $entries; |
||||
} |
||||
|
||||
public function testGetFilteredEntries() { |
||||
$filter = 'con'; |
||||
$user = 'user849'; |
||||
$entries = $this->generateTestEntries(); |
||||
$provider = $this->createMock(IProvider::class); |
||||
$this->contactsStore->expects($this->once()) |
||||
->method('getContacts') |
||||
->with($filter) |
||||
->willReturn($entries); |
||||
$this->actionProviderStore->expects($this->once()) |
||||
->method('getProviders') |
||||
->willReturn([$provider]); |
||||
$provider->expects($this->exactly(25)) |
||||
->method('process'); |
||||
$this->appManager->expects($this->once()) |
||||
->method('isEnabledForUser') |
||||
->with($this->equalTo('contacts'), $user) |
||||
->willReturn(false); |
||||
$expected = [ |
||||
'contacts' => array_slice($entries, 0, 25), |
||||
'contactsAppEnabled' => false, |
||||
]; |
||||
|
||||
$data = $this->manager->getEntries($user, $filter); |
||||
|
||||
$this->assertEquals($expected, $data); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,69 @@ |
||||
<?php |
||||
|
||||
/** |
||||
* @copyright 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @author 2017 Christoph Wurst <christoph@winzerhof-wurst.at> |
||||
* |
||||
* @license GNU AGPL version 3 or any later version |
||||
* |
||||
* This program is free software: you can redistribute it and/or modify |
||||
* it under the terms of the GNU Affero General Public License as |
||||
* published by the Free Software Foundation, either version 3 of the |
||||
* License, or (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU Affero General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU Affero General Public License |
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
* |
||||
*/ |
||||
|
||||
namespace Tests\Contacts\ContactsMenu\Providers; |
||||
|
||||
use OC\Contacts\ContactsMenu\Providers\EMailProvider; |
||||
use OCP\Contacts\ContactsMenu\IActionFactory; |
||||
use OCP\Contacts\ContactsMenu\IEntry; |
||||
use OCP\Contacts\ContactsMenu\ILinkAction; |
||||
use PHPUnit_Framework_MockObject_MockObject; |
||||
use Test\TestCase; |
||||
|
||||
class EMailproviderTest extends TestCase { |
||||
|
||||
/** @var IActionFactory|PHPUnit_Framework_MockObject_MockObject */ |
||||
private $actionFactory; |
||||
|
||||
/** @var EMailProvider */ |
||||
private $provider; |
||||
|
||||
protected function setUp() { |
||||
parent::setUp(); |
||||
|
||||
$this->actionFactory = $this->createMock(IActionFactory::class); |
||||
$this->provider = new EMailProvider($this->actionFactory); |
||||
} |
||||
|
||||
public function testProcess() { |
||||
$entry = $this->createMock(IEntry::class); |
||||
$action = $this->createMock(ILinkAction::class); |
||||
|
||||
$entry->expects($this->once()) |
||||
->method('getEMailAddresses') |
||||
->willReturn([ |
||||
'user@example.com', |
||||
]); |
||||
$this->actionFactory->expects($this->once()) |
||||
->method('newEMailAction') |
||||
->with($this->equalTo('icon-mail'), $this->equalTo('Mail'), $this->equalTo('user@example.com')) |
||||
->willReturn($action); |
||||
$entry->expects($this->once()) |
||||
->method('addAction') |
||||
->with($action); |
||||
|
||||
$this->provider->process($entry); |
||||
} |
||||
|
||||
} |
||||
Loading…
Reference in new issue