Contacts menu
* load list of contacts from the server * show last message of each contact Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
This commit is contained in:
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -20,10 +20,21 @@
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
-moz-user-select: none;
|
-moz-user-select: none;
|
||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
/* Dropdown menu arrow */
|
/* Header menu */
|
||||||
&.menu:after,
|
.menu {
|
||||||
.menu:after {
|
position: absolute;
|
||||||
|
top: 45px;
|
||||||
|
background-color: #fff;
|
||||||
|
box-shadow: 0 1px 10px rgba(150, 150, 150, 0.75);
|
||||||
|
border-radius: 0 0 3px 3px;
|
||||||
|
display: none;
|
||||||
|
box-sizing: border-box;
|
||||||
|
z-index: 2000;
|
||||||
|
|
||||||
|
/* Dropdown arrow */
|
||||||
|
&:after {
|
||||||
border: 10px solid transparent;
|
border: 10px solid transparent;
|
||||||
border-bottom-color: $color-main-background;
|
border-bottom-color: $color-main-background;
|
||||||
bottom: 100%;
|
bottom: 100%;
|
||||||
|
@ -199,19 +210,12 @@ nav {
|
||||||
|
|
||||||
#navigation {
|
#navigation {
|
||||||
position: relative;
|
position: relative;
|
||||||
top: 45px;
|
|
||||||
left: -100%;
|
left: -100%;
|
||||||
width: 160px;
|
width: 160px;
|
||||||
margin-top: 0;
|
|
||||||
background-color: $color-main-background;
|
background-color: $color-main-background;
|
||||||
box-shadow: 0 1px 10px $color-box-shadow;
|
box-shadow: 0 1px 10px $color-box-shadow;
|
||||||
border-radius: 3px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
display: none;
|
|
||||||
box-sizing: border-box;
|
|
||||||
z-index: 2000;
|
|
||||||
&:after {
|
&:after {
|
||||||
|
/* position of dropdown arrow */
|
||||||
left: 47%;
|
left: 47%;
|
||||||
bottom: 100%;
|
bottom: 100%;
|
||||||
border: solid transparent;
|
border: solid transparent;
|
||||||
|
@ -407,17 +411,9 @@ nav {
|
||||||
}
|
}
|
||||||
|
|
||||||
#expanddiv {
|
#expanddiv {
|
||||||
position: absolute;
|
|
||||||
right: 13px;
|
right: 13px;
|
||||||
top: 45px;
|
|
||||||
z-index: 2000;
|
|
||||||
display: none;
|
|
||||||
background: $color-main-background;
|
background: $color-main-background;
|
||||||
box-shadow: 0 1px 10px $color-box-shadow;
|
box-shadow: 0 1px 10px $color-box-shadow;
|
||||||
border-radius: 3px;
|
|
||||||
border-top-left-radius: 0;
|
|
||||||
border-top-right-radius: 0;
|
|
||||||
box-sizing: border-box;
|
|
||||||
&:after {
|
&:after {
|
||||||
/* position of dropdown arrow */
|
/* position of dropdown arrow */
|
||||||
right: 13px;
|
right: 13px;
|
||||||
|
|
|
@ -438,6 +438,10 @@ img, object, video, button, textarea, input, select {
|
||||||
background-image: url('../img/places/calendar-dark.svg?v=1');
|
background-image: url('../img/places/calendar-dark.svg?v=1');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.icon-contacts {
|
||||||
|
background-image: url('../img/places/contacts.svg?v=1');
|
||||||
|
}
|
||||||
|
|
||||||
.icon-contacts-dark {
|
.icon-contacts-dark {
|
||||||
background-image: url('../img/places/contacts-dark.svg?v=1');
|
background-image: url('../img/places/contacts-dark.svg?v=1');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1057,6 +1057,121 @@ span.ui-icon {
|
||||||
margin: 3px 7px 30px 0;
|
margin: 3px 7px 30px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ---- CONTACTS MENU ---- */
|
||||||
|
|
||||||
|
#contactsmenu {
|
||||||
|
.menutoggle {
|
||||||
|
background-size: 16px 16px;
|
||||||
|
padding: 14px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: .7;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#contactsmenu > .menu {
|
||||||
|
/* show ~4.5 entries */
|
||||||
|
height: 278px;
|
||||||
|
width: 350px;
|
||||||
|
right: 13px;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
right: 61px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.emptycontent {
|
||||||
|
margin-top: 5vh !important;
|
||||||
|
margin-bottom: 2vh;
|
||||||
|
.icon-loading {
|
||||||
|
position: inherit;
|
||||||
|
}
|
||||||
|
.icon-search {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
max-height: calc(100% - 50px);
|
||||||
|
overflow-y: auto;
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
a {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
padding: 12px 0;
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.contact {
|
||||||
|
display: flex;
|
||||||
|
position: relative;
|
||||||
|
align-items: center;
|
||||||
|
padding: 3px 3px 3px 10px;
|
||||||
|
border-bottom: 1px solid #eeeeee;
|
||||||
|
|
||||||
|
:last-of-type {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.body {
|
||||||
|
flex-grow: 1;
|
||||||
|
padding-left: 8px;
|
||||||
|
|
||||||
|
div {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-name, .last-message {
|
||||||
|
/* TODO: don't use fixed width */
|
||||||
|
max-width: 204px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.last-message {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.top-action, .second-action, .other-actions {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
padding: 14px;
|
||||||
|
opacity: .5;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* actions menu */
|
||||||
|
.menu {
|
||||||
|
top: 47px;
|
||||||
|
margin-right: 13px;
|
||||||
|
}
|
||||||
|
.popovermenu::after {
|
||||||
|
right: 2px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#contactsmenu-search {
|
||||||
|
width: calc(100% - 16px);
|
||||||
|
margin: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ---- TOOLTIPS ---- */
|
/* ---- TOOLTIPS ---- */
|
||||||
|
|
||||||
.extra-data {
|
.extra-data {
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="32" width="32" viewbox="0 0 32 32"><path style="block-progression:tb;text-transform:none;text-indent:0" d="M9.24 6.67c-1.955 0-3.613 1.43-3.613 3.275.014.583.066 1.302.414 2.823v.037l.038.038c.112.32.275.503.49.753.215.25.47.544.715.79l.075.076c.048.21.107.436.15.64.117.54.105.922.076 1.053-.84.295-1.885.647-2.823 1.054-.526.228-1.002.433-1.392.677-.39.244-.777.43-.903.978a.473.473 0 0 0 0 .076c-.123 1.13-.31 2.793-.452 3.915a.618.618 0 0 0 .3.603c1.704.92 4.32 1.29 6.927 1.28 2.607-.01 5.202-.403 6.85-1.28a.618.618 0 0 0 .3-.603c-.044-.35-.1-1.14-.15-1.92-.05-.778-.09-1.543-.15-1.994a.607.607 0 0 0-.15-.3c-.524-.626-1.306-1.008-2.22-1.393-.836-.352-1.815-.717-2.786-1.13-.055-.12-.11-.473 0-1.016.03-.144.074-.3.113-.45l.263-.3c.216-.248.447-.506.64-.754.192-.25.35-.462.452-.753l.037-.038c.393-1.588.393-2.25.413-2.823v-.037c0-1.845-1.658-3.275-3.613-3.275zm10.336-3.005c-2.85 0-5.268 2.084-5.268 4.774.02.85.096 1.898.604 4.115v.055l.055.055c.162.466.4.733.713 1.097s.687.793 1.043 1.153c.04.042.068.068.11.11.07.306.155.636.22.932.168.788.15 1.346.11 1.537-1.226.43-2.75.942-4.117 1.536-.768.334-1.462.632-2.03.988-.57.356-1.134.625-1.317 1.427a.67.67 0 0 0 0 .11c-.18 1.648-.452 4.07-.66 5.707a.9.9 0 0 0 .44.878c2.48 1.34 6.295 1.88 10.096 1.865s7.584-.586 9.987-1.865a.9.9 0 0 0 .44-.878c-.067-.512-.148-1.665-.22-2.8-.072-1.133-.134-2.25-.22-2.907a.884.884 0 0 0-.22-.44c-.763-.91-1.903-1.468-3.237-2.03-1.217-.513-2.645-1.045-4.06-1.646-.08-.177-.16-.69 0-1.483.042-.212.108-.44.164-.658.133-.15.237-.272.384-.44.315-.36.652-.735.933-1.098.28-.362.51-.673.66-1.097l.053-.055c.574-2.315.574-3.28.604-4.116V8.44c0-2.69-2.418-4.775-5.268-4.775z" fill="#fff"/></svg>
|
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);
|
|
@ -40,6 +40,7 @@
|
||||||
"sharedialogresharerinfoview.js",
|
"sharedialogresharerinfoview.js",
|
||||||
"sharedialogshareelistview.js",
|
"sharedialogshareelistview.js",
|
||||||
"octemplate.js",
|
"octemplate.js",
|
||||||
|
"contactsmenu.js",
|
||||||
"eventsource.js",
|
"eventsource.js",
|
||||||
"config.js",
|
"config.js",
|
||||||
"public/appconfig.js",
|
"public/appconfig.js",
|
||||||
|
|
|
@ -654,8 +654,13 @@ var OCP = {},
|
||||||
/**
|
/**
|
||||||
* For menu toggling
|
* For menu toggling
|
||||||
* @todo Write documentation
|
* @todo Write documentation
|
||||||
|
*
|
||||||
|
* @param {jQuery} $toggle
|
||||||
|
* @param {jQuery} $menuEl
|
||||||
|
* @param {function|undefined} toggle callback invoked everytime the menu is opened
|
||||||
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
registerMenu: function($toggle, $menuEl) {
|
registerMenu: function($toggle, $menuEl, toggle) {
|
||||||
var self = this;
|
var self = this;
|
||||||
$menuEl.addClass('menu');
|
$menuEl.addClass('menu');
|
||||||
$toggle.on('click.menu', function(event) {
|
$toggle.on('click.menu', function(event) {
|
||||||
|
@ -671,7 +676,7 @@ var OCP = {},
|
||||||
// close it
|
// close it
|
||||||
self.hideMenus();
|
self.hideMenus();
|
||||||
}
|
}
|
||||||
$menuEl.slideToggle(OC.menuSpeed);
|
$menuEl.slideToggle(OC.menuSpeed, toggle);
|
||||||
OC._currentMenu = $menuEl;
|
OC._currentMenu = $menuEl;
|
||||||
OC._currentMenuToggle = $toggle;
|
OC._currentMenuToggle = $toggle;
|
||||||
});
|
});
|
||||||
|
@ -1473,8 +1478,16 @@ function initCore() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setupContactsMenu() {
|
||||||
|
new OC.ContactsMenu({
|
||||||
|
el: $('#contactsmenu .menu'),
|
||||||
|
trigger: $('#contactsmenu .menutoggle')
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
setupMainMenu();
|
setupMainMenu();
|
||||||
setupUserMenu();
|
setupUserMenu();
|
||||||
|
setupContactsMenu();
|
||||||
|
|
||||||
// move triangle of apps dropdown to align with app name triangle
|
// move triangle of apps dropdown to align with app name triangle
|
||||||
// 2 is the additional offset between the triangles
|
// 2 is the additional offset between the triangles
|
||||||
|
|
|
@ -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);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
|
@ -57,6 +57,7 @@ $application->registerRoutes($this, [
|
||||||
['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'],
|
['name' => 'Preview#getPreview', 'url' => '/core/preview.png', 'verb' => 'GET'],
|
||||||
['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'],
|
['name' => 'Css#getCss', 'url' => '/css/{appName}/{fileName}', 'verb' => 'GET'],
|
||||||
['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'],
|
['name' => 'Js#getJs', 'url' => '/js/{appName}/{fileName}', 'verb' => 'GET'],
|
||||||
|
['name' => 'contactsMenu#index', 'url' => '/contactsmenu/contacts', 'verb' => 'GET'],
|
||||||
],
|
],
|
||||||
'ocs' => [
|
'ocs' => [
|
||||||
['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
|
['root' => '/cloud', 'name' => 'OCS#getCapabilities', 'url' => '/capabilities', 'verb' => 'GET'],
|
||||||
|
|
|
@ -118,6 +118,10 @@
|
||||||
autocomplete="off" tabindex="5">
|
autocomplete="off" tabindex="5">
|
||||||
<button class="icon-close-white" type="reset"></button>
|
<button class="icon-close-white" type="reset"></button>
|
||||||
</form>
|
</form>
|
||||||
|
<div id="contactsmenu">
|
||||||
|
<div class="icon-contacts menutoggle"></div>
|
||||||
|
<div class="menu"></div>
|
||||||
|
</div>
|
||||||
<div id="settings">
|
<div id="settings">
|
||||||
<div id="expand" tabindex="6" role="link" class="menutoggle">
|
<div id="expand" tabindex="6" role="link" class="menutoggle">
|
||||||
<div class="avatardiv<?php if ($_['userAvatarSet']) { print_unescaped(' avatardiv-shown'); } else { print_unescaped('" style="display: none'); } ?>">
|
<div class="avatardiv<?php if ($_['userAvatarSet']) { print_unescaped(' avatardiv-shown'); } else { print_unescaped('" style="display: none'); } ?>">
|
||||||
|
@ -161,5 +165,6 @@
|
||||||
<?php print_unescaped($_['content']); ?>
|
<?php print_unescaped($_['content']); ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -374,13 +374,9 @@ class ClassLoader
|
||||||
|
|
||||||
$first = $class[0];
|
$first = $class[0];
|
||||||
if (isset($this->prefixLengthsPsr4[$first])) {
|
if (isset($this->prefixLengthsPsr4[$first])) {
|
||||||
$subPath = $class;
|
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
|
||||||
while (false !== $lastPos = strrpos($subPath, '\\')) {
|
if (0 === strpos($class, $prefix)) {
|
||||||
$subPath = substr($subPath, 0, $lastPos);
|
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
|
||||||
$search = $subPath.'\\';
|
|
||||||
if (isset($this->prefixDirsPsr4[$search])) {
|
|
||||||
foreach ($this->prefixDirsPsr4[$search] as $dir) {
|
|
||||||
$length = $this->prefixLengthsPsr4[$first][$search];
|
|
||||||
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
|
||||||
return $file;
|
return $file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
Copyright (c) Nils Adermann, Jordi Boggiano
|
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|
|
@ -80,6 +80,11 @@ return array(
|
||||||
'OCP\\Console\\ConsoleEvent' => $baseDir . '/lib/public/Console/ConsoleEvent.php',
|
'OCP\\Console\\ConsoleEvent' => $baseDir . '/lib/public/Console/ConsoleEvent.php',
|
||||||
'OCP\\Constants' => $baseDir . '/lib/public/Constants.php',
|
'OCP\\Constants' => $baseDir . '/lib/public/Constants.php',
|
||||||
'OCP\\Contacts' => $baseDir . '/lib/public/Contacts.php',
|
'OCP\\Contacts' => $baseDir . '/lib/public/Contacts.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IAction' => $baseDir . '/lib/public/Contacts/ContactsMenu/IAction.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IActionFactory' => $baseDir . '/lib/public/Contacts/ContactsMenu/IActionFactory.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IEntry' => $baseDir . '/lib/public/Contacts/ContactsMenu/IEntry.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\ILinkAction' => $baseDir . '/lib/public/Contacts/ContactsMenu/ILinkAction.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IProvider' => $baseDir . '/lib/public/Contacts/ContactsMenu/IProvider.php',
|
||||||
'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php',
|
'OCP\\Contacts\\IManager' => $baseDir . '/lib/public/Contacts/IManager.php',
|
||||||
'OCP\\DB' => $baseDir . '/lib/public/DB.php',
|
'OCP\\DB' => $baseDir . '/lib/public/DB.php',
|
||||||
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => $baseDir . '/lib/public/DB/QueryBuilder/ICompositeExpression.php',
|
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => $baseDir . '/lib/public/DB/QueryBuilder/ICompositeExpression.php',
|
||||||
|
@ -373,6 +378,14 @@ return array(
|
||||||
'OC\\Console\\Application' => $baseDir . '/lib/private/Console/Application.php',
|
'OC\\Console\\Application' => $baseDir . '/lib/private/Console/Application.php',
|
||||||
'OC\\Console\\TimestampFormatter' => $baseDir . '/lib/private/Console/TimestampFormatter.php',
|
'OC\\Console\\TimestampFormatter' => $baseDir . '/lib/private/Console/TimestampFormatter.php',
|
||||||
'OC\\ContactsManager' => $baseDir . '/lib/private/ContactsManager.php',
|
'OC\\ContactsManager' => $baseDir . '/lib/private/ContactsManager.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\ActionFactory' => $baseDir . '/lib/private/Contacts/ContactsMenu/ActionFactory.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\ActionProviderStore' => $baseDir . '/lib/private/Contacts/ContactsMenu/ActionProviderStore.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Actions\\LinkAction' => $baseDir . '/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\ContactsStore' => $baseDir . '/lib/private/Contacts/ContactsMenu/ContactsStore.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Entry' => $baseDir . '/lib/private/Contacts/ContactsMenu/Entry.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Manager' => $baseDir . '/lib/private/Contacts/ContactsMenu/Manager.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Providers\\DetailsProvider' => $baseDir . '/lib/private/Contacts/ContactsMenu/Providers/DetailsProvider.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Providers\\EMailProvider' => $baseDir . '/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php',
|
||||||
'OC\\Core\\Application' => $baseDir . '/core/Application.php',
|
'OC\\Core\\Application' => $baseDir . '/core/Application.php',
|
||||||
'OC\\Core\\Command\\App\\CheckCode' => $baseDir . '/core/Command/App/CheckCode.php',
|
'OC\\Core\\Command\\App\\CheckCode' => $baseDir . '/core/Command/App/CheckCode.php',
|
||||||
'OC\\Core\\Command\\App\\Disable' => $baseDir . '/core/Command/App/Disable.php',
|
'OC\\Core\\Command\\App\\Disable' => $baseDir . '/core/Command/App/Disable.php',
|
||||||
|
@ -444,6 +457,7 @@ return array(
|
||||||
'OC\\Core\\Command\\User\\ResetPassword' => $baseDir . '/core/Command/User/ResetPassword.php',
|
'OC\\Core\\Command\\User\\ResetPassword' => $baseDir . '/core/Command/User/ResetPassword.php',
|
||||||
'OC\\Core\\Command\\User\\Setting' => $baseDir . '/core/Command/User/Setting.php',
|
'OC\\Core\\Command\\User\\Setting' => $baseDir . '/core/Command/User/Setting.php',
|
||||||
'OC\\Core\\Controller\\AvatarController' => $baseDir . '/core/Controller/AvatarController.php',
|
'OC\\Core\\Controller\\AvatarController' => $baseDir . '/core/Controller/AvatarController.php',
|
||||||
|
'OC\\Core\\Controller\\ContactsMenuController' => $baseDir . '/core/Controller/ContactsMenuController.php',
|
||||||
'OC\\Core\\Controller\\CssController' => $baseDir . '/core/Controller/CssController.php',
|
'OC\\Core\\Controller\\CssController' => $baseDir . '/core/Controller/CssController.php',
|
||||||
'OC\\Core\\Controller\\JsController' => $baseDir . '/core/Controller/JsController.php',
|
'OC\\Core\\Controller\\JsController' => $baseDir . '/core/Controller/JsController.php',
|
||||||
'OC\\Core\\Controller\\LoginController' => $baseDir . '/core/Controller/LoginController.php',
|
'OC\\Core\\Controller\\LoginController' => $baseDir . '/core/Controller/LoginController.php',
|
||||||
|
|
|
@ -110,6 +110,11 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
||||||
'OCP\\Console\\ConsoleEvent' => __DIR__ . '/../../..' . '/lib/public/Console/ConsoleEvent.php',
|
'OCP\\Console\\ConsoleEvent' => __DIR__ . '/../../..' . '/lib/public/Console/ConsoleEvent.php',
|
||||||
'OCP\\Constants' => __DIR__ . '/../../..' . '/lib/public/Constants.php',
|
'OCP\\Constants' => __DIR__ . '/../../..' . '/lib/public/Constants.php',
|
||||||
'OCP\\Contacts' => __DIR__ . '/../../..' . '/lib/public/Contacts.php',
|
'OCP\\Contacts' => __DIR__ . '/../../..' . '/lib/public/Contacts.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IAction' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IAction.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IActionFactory' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IActionFactory.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IEntry' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IEntry.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\ILinkAction' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/ILinkAction.php',
|
||||||
|
'OCP\\Contacts\\ContactsMenu\\IProvider' => __DIR__ . '/../../..' . '/lib/public/Contacts/ContactsMenu/IProvider.php',
|
||||||
'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php',
|
'OCP\\Contacts\\IManager' => __DIR__ . '/../../..' . '/lib/public/Contacts/IManager.php',
|
||||||
'OCP\\DB' => __DIR__ . '/../../..' . '/lib/public/DB.php',
|
'OCP\\DB' => __DIR__ . '/../../..' . '/lib/public/DB.php',
|
||||||
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ICompositeExpression.php',
|
'OCP\\DB\\QueryBuilder\\ICompositeExpression' => __DIR__ . '/../../..' . '/lib/public/DB/QueryBuilder/ICompositeExpression.php',
|
||||||
|
@ -403,6 +408,14 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
||||||
'OC\\Console\\Application' => __DIR__ . '/../../..' . '/lib/private/Console/Application.php',
|
'OC\\Console\\Application' => __DIR__ . '/../../..' . '/lib/private/Console/Application.php',
|
||||||
'OC\\Console\\TimestampFormatter' => __DIR__ . '/../../..' . '/lib/private/Console/TimestampFormatter.php',
|
'OC\\Console\\TimestampFormatter' => __DIR__ . '/../../..' . '/lib/private/Console/TimestampFormatter.php',
|
||||||
'OC\\ContactsManager' => __DIR__ . '/../../..' . '/lib/private/ContactsManager.php',
|
'OC\\ContactsManager' => __DIR__ . '/../../..' . '/lib/private/ContactsManager.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\ActionFactory' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/ActionFactory.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\ActionProviderStore' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/ActionProviderStore.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Actions\\LinkAction' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Actions/LinkAction.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\ContactsStore' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/ContactsStore.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Entry' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Entry.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Manager' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Manager.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Providers\\DetailsProvider' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Providers/DetailsProvider.php',
|
||||||
|
'OC\\Contacts\\ContactsMenu\\Providers\\EMailProvider' => __DIR__ . '/../../..' . '/lib/private/Contacts/ContactsMenu/Providers/EMailProvider.php',
|
||||||
'OC\\Core\\Application' => __DIR__ . '/../../..' . '/core/Application.php',
|
'OC\\Core\\Application' => __DIR__ . '/../../..' . '/core/Application.php',
|
||||||
'OC\\Core\\Command\\App\\CheckCode' => __DIR__ . '/../../..' . '/core/Command/App/CheckCode.php',
|
'OC\\Core\\Command\\App\\CheckCode' => __DIR__ . '/../../..' . '/core/Command/App/CheckCode.php',
|
||||||
'OC\\Core\\Command\\App\\Disable' => __DIR__ . '/../../..' . '/core/Command/App/Disable.php',
|
'OC\\Core\\Command\\App\\Disable' => __DIR__ . '/../../..' . '/core/Command/App/Disable.php',
|
||||||
|
@ -474,6 +487,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
|
||||||
'OC\\Core\\Command\\User\\ResetPassword' => __DIR__ . '/../../..' . '/core/Command/User/ResetPassword.php',
|
'OC\\Core\\Command\\User\\ResetPassword' => __DIR__ . '/../../..' . '/core/Command/User/ResetPassword.php',
|
||||||
'OC\\Core\\Command\\User\\Setting' => __DIR__ . '/../../..' . '/core/Command/User/Setting.php',
|
'OC\\Core\\Command\\User\\Setting' => __DIR__ . '/../../..' . '/core/Command/User/Setting.php',
|
||||||
'OC\\Core\\Controller\\AvatarController' => __DIR__ . '/../../..' . '/core/Controller/AvatarController.php',
|
'OC\\Core\\Controller\\AvatarController' => __DIR__ . '/../../..' . '/core/Controller/AvatarController.php',
|
||||||
|
'OC\\Core\\Controller\\ContactsMenuController' => __DIR__ . '/../../..' . '/core/Controller/ContactsMenuController.php',
|
||||||
'OC\\Core\\Controller\\CssController' => __DIR__ . '/../../..' . '/core/Controller/CssController.php',
|
'OC\\Core\\Controller\\CssController' => __DIR__ . '/../../..' . '/core/Controller/CssController.php',
|
||||||
'OC\\Core\\Controller\\JsController' => __DIR__ . '/../../..' . '/core/Controller/JsController.php',
|
'OC\\Core\\Controller\\JsController' => __DIR__ . '/../../..' . '/core/Controller/JsController.php',
|
||||||
'OC\\Core\\Controller\\LoginController' => __DIR__ . '/../../..' . '/core/Controller/LoginController.php',
|
'OC\\Core\\Controller\\LoginController' => __DIR__ . '/../../..' . '/core/Controller/LoginController.php',
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -50,6 +50,7 @@ use OC\AppFramework\Utility\SimpleContainer;
|
||||||
use OC\AppFramework\Utility\TimeFactory;
|
use OC\AppFramework\Utility\TimeFactory;
|
||||||
use OC\Authentication\LoginCredentials\Store;
|
use OC\Authentication\LoginCredentials\Store;
|
||||||
use OC\Command\AsyncBus;
|
use OC\Command\AsyncBus;
|
||||||
|
use OC\Contacts\ContactsMenu\ActionFactory;
|
||||||
use OC\Diagnostics\EventLogger;
|
use OC\Diagnostics\EventLogger;
|
||||||
use OC\Diagnostics\NullEventLogger;
|
use OC\Diagnostics\NullEventLogger;
|
||||||
use OC\Diagnostics\NullQueryLogger;
|
use OC\Diagnostics\NullQueryLogger;
|
||||||
|
@ -108,6 +109,8 @@ use OCP\IDBConnection;
|
||||||
use OCP\IL10N;
|
use OCP\IL10N;
|
||||||
use OCP\IServerContainer;
|
use OCP\IServerContainer;
|
||||||
use OCP\ITempManager;
|
use OCP\ITempManager;
|
||||||
|
use OCP\Contacts\ContactsMenu\IActionFactory;
|
||||||
|
use OCP\IURLGenerator;
|
||||||
use OCP\RichObjectStrings\IValidator;
|
use OCP\RichObjectStrings\IValidator;
|
||||||
use OCP\Security\IContentSecurityPolicyManager;
|
use OCP\Security\IContentSecurityPolicyManager;
|
||||||
use OCP\Share\IShareHelper;
|
use OCP\Share\IShareHelper;
|
||||||
|
@ -133,9 +136,17 @@ class Server extends ServerContainer implements IServerContainer {
|
||||||
parent::__construct();
|
parent::__construct();
|
||||||
$this->webRoot = $webRoot;
|
$this->webRoot = $webRoot;
|
||||||
|
|
||||||
|
$this->registerService(\OCP\IServerContainer::class, function(IServerContainer $c) {
|
||||||
|
return $c;
|
||||||
|
});
|
||||||
|
|
||||||
$this->registerAlias(\OCP\Contacts\IManager::class, \OC\ContactsManager::class);
|
$this->registerAlias(\OCP\Contacts\IManager::class, \OC\ContactsManager::class);
|
||||||
$this->registerAlias('ContactsManager', \OCP\Contacts\IManager::class);
|
$this->registerAlias('ContactsManager', \OCP\Contacts\IManager::class);
|
||||||
|
|
||||||
|
$this->registerAlias(IActionFactory::class, ActionFactory::class);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
$this->registerService(\OCP\IPreview::class, function (Server $c) {
|
$this->registerService(\OCP\IPreview::class, function (Server $c) {
|
||||||
return new PreviewManager(
|
return new PreviewManager(
|
||||||
$c->getConfig(),
|
$c->getConfig(),
|
||||||
|
|
|
@ -118,6 +118,7 @@ class OC_Template extends \OC\Template\Base {
|
||||||
OC_Util::addScript('jquery-ui-fixes');
|
OC_Util::addScript('jquery-ui-fixes');
|
||||||
OC_Util::addScript('files/fileinfo');
|
OC_Util::addScript('files/fileinfo');
|
||||||
OC_Util::addScript('files/client');
|
OC_Util::addScript('files/client');
|
||||||
|
OC_Util::addScript('contactsmenu');
|
||||||
|
|
||||||
if (\OC::$server->getConfig()->getSystemValue('debug')) {
|
if (\OC::$server->getConfig()->getSystemValue('debug')) {
|
||||||
// Add the stuff we need always
|
// Add the stuff we need always
|
||||||
|
|
|
@ -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