@@ -56,6 +56,7 @@
|
|||||||
@if mixin-exists('icon-black-white') {
|
@if mixin-exists('icon-black-white') {
|
||||||
@include icon-black-white('deck', 'deck', 1);
|
@include icon-black-white('deck', 'deck', 1);
|
||||||
@include icon-black-white('archive', 'deck', 1);
|
@include icon-black-white('archive', 'deck', 1);
|
||||||
|
@include icon-black-white('circles', 'deck', 1);
|
||||||
|
|
||||||
.icon-toggle-compact-collapsed {
|
.icon-toggle-compact-collapsed {
|
||||||
@include icon-color('toggle-view-expand', 'deck', $color-black);
|
@include icon-color('toggle-view-expand', 'deck', $color-black);
|
||||||
@@ -68,3 +69,12 @@
|
|||||||
@include icon-color('activity-dark', 'activity', $color-black);
|
@include icon-color('activity-dark', 'activity', $color-black);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.avatardiv.circles {
|
||||||
|
background: var(--color-primary);
|
||||||
|
}
|
||||||
|
.icon-circles {
|
||||||
|
opacity: 1;
|
||||||
|
background-size: 20px;
|
||||||
|
background-position: center center;
|
||||||
|
}
|
||||||
@@ -1292,7 +1292,7 @@ input.input-inline {
|
|||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
||||||
.icon-group {
|
.icon-group, .icon {
|
||||||
padding: 16px;
|
padding: 16px;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|||||||
1
img/circles.svg
Normal file
1
img/circles.svg
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 58 58" width="512" height="512"><g fill="#000"><path d="M54.319 37.839C54.762 35.918 55 33.96 55 32c0-9.095-4.631-17.377-12.389-22.153a1 1 0 1 0-1.049 1.703C48.724 15.96 53 23.604 53 32c0 1.726-.2 3.451-.573 5.147A6.992 6.992 0 0 0 51 37c-3.86 0-7 3.141-7 7s3.14 7 7 7 7-3.141 7-7a7.006 7.006 0 0 0-3.681-6.161zM38.171 54.182A23.867 23.867 0 0 1 29 56a24.047 24.047 0 0 1-17.017-7.092A6.974 6.974 0 0 0 14 44c0-3.859-3.14-7-7-7s-7 3.141-7 7 3.14 7 7 7a6.952 6.952 0 0 0 3.381-.875C15.26 55.136 21.994 58 29 58c3.435 0 6.778-.663 9.936-1.971.51-.211.753-.796.542-1.307a1.001 1.001 0 0 0-1.307-.54zM4 31.213a1 1 0 0 0 1.068-.927c.712-10.089 7.586-18.52 17.22-21.314C23.142 11.874 25.825 14 29 14c3.86 0 7-3.141 7-7s-3.14-7-7-7c-3.851 0-6.985 3.127-6.999 6.975C11.42 9.922 3.851 19.12 3.073 30.146A.999.999 0 0 0 4 31.213z"/></g></svg>
|
||||||
|
After Width: | Height: | Size: 885 B |
@@ -403,6 +403,8 @@ app.controller('BoardController', function ($rootScope, $scope, $stateParams, St
|
|||||||
return 'user';
|
return 'user';
|
||||||
case OC.Share.SHARE_TYPE_GROUP:
|
case OC.Share.SHARE_TYPE_GROUP:
|
||||||
return 'group';
|
return 'group';
|
||||||
|
case OC.Share.SHARE_TYPE_CIRCLE:
|
||||||
|
return 'circles';
|
||||||
default:
|
default:
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
import app from '../app/App.js';
|
import app from '../app/App.js';
|
||||||
/* global app OC */
|
/* global app OC angular */
|
||||||
app.factory('BoardService', function (ApiService, $http, $q) {
|
app.factory('BoardService', function (ApiService, $http, $q) {
|
||||||
var BoardService = function ($http, ep, $q) {
|
var BoardService = function ($http, ep, $q) {
|
||||||
ApiService.call(this, $http, ep, $q);
|
ApiService.call(this, $http, ep, $q);
|
||||||
@@ -59,7 +59,7 @@ app.factory('BoardService', function (ApiService, $http, $q) {
|
|||||||
var searchData = {
|
var searchData = {
|
||||||
format: 'json',
|
format: 'json',
|
||||||
perPage: 4,
|
perPage: 4,
|
||||||
itemType: [0, 1]
|
itemType: [0, 1, 7]
|
||||||
};
|
};
|
||||||
if (search !== "") {
|
if (search !== "") {
|
||||||
searchData.search = search;
|
searchData.search = search;
|
||||||
@@ -79,6 +79,7 @@ app.factory('BoardService', function (ApiService, $http, $q) {
|
|||||||
|
|
||||||
var users = response.ocs.data.exact.users.concat(response.ocs.data.users.slice(0, 4));
|
var users = response.ocs.data.exact.users.concat(response.ocs.data.users.slice(0, 4));
|
||||||
var groups = response.ocs.data.exact.groups.concat(response.ocs.data.groups.slice(0, 4));
|
var groups = response.ocs.data.exact.groups.concat(response.ocs.data.groups.slice(0, 4));
|
||||||
|
var circles = response.ocs.data.exact.groups.concat(response.ocs.data.circles.slice(0, 4));
|
||||||
|
|
||||||
// filter out everyone who is already in the share list
|
// filter out everyone who is already in the share list
|
||||||
angular.forEach(users, function (item) {
|
angular.forEach(users, function (item) {
|
||||||
@@ -105,6 +106,18 @@ app.factory('BoardService', function (ApiService, $http, $q) {
|
|||||||
self.sharees.push(acl);
|
self.sharees.push(acl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
angular.forEach(circles, function (item) {
|
||||||
|
var acl = self.generateAcl(OC.Share.SHARE_TYPE_CIRCLE, item);
|
||||||
|
var exists = false;
|
||||||
|
angular.forEach(self.getCurrent().acl, function (acl) {
|
||||||
|
if (acl.participant.primaryKey === item.value.shareWith) {
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (!exists) {
|
||||||
|
self.sharees.push(acl);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
deferred.resolve(self.sharees);
|
deferred.resolve(self.sharees);
|
||||||
}, function () {
|
}, function () {
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ class Acl extends RelationalEntity {
|
|||||||
|
|
||||||
const PERMISSION_TYPE_USER = 0;
|
const PERMISSION_TYPE_USER = 0;
|
||||||
const PERMISSION_TYPE_GROUP = 1;
|
const PERMISSION_TYPE_GROUP = 1;
|
||||||
|
const PERMISSION_TYPE_CIRCLE = 7;
|
||||||
|
|
||||||
protected $participant;
|
protected $participant;
|
||||||
protected $type;
|
protected $type;
|
||||||
|
|||||||
@@ -24,6 +24,7 @@
|
|||||||
namespace OCA\Deck\Db;
|
namespace OCA\Deck\Db;
|
||||||
|
|
||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
|
use OCP\AppFramework\QueryException;
|
||||||
use OCP\IDBConnection;
|
use OCP\IDBConnection;
|
||||||
use OCP\IUserManager;
|
use OCP\IUserManager;
|
||||||
use OCP\IGroupManager;
|
use OCP\IGroupManager;
|
||||||
@@ -36,6 +37,8 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
private $userManager;
|
private $userManager;
|
||||||
private $groupManager;
|
private $groupManager;
|
||||||
|
|
||||||
|
private $circlesEnabled;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
IDBConnection $db,
|
IDBConnection $db,
|
||||||
LabelMapper $labelMapper,
|
LabelMapper $labelMapper,
|
||||||
@@ -50,6 +53,8 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
$this->stackMapper = $stackMapper;
|
$this->stackMapper = $stackMapper;
|
||||||
$this->userManager = $userManager;
|
$this->userManager = $userManager;
|
||||||
$this->groupManager = $groupManager;
|
$this->groupManager = $groupManager;
|
||||||
|
|
||||||
|
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -136,6 +141,35 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
return $entries;
|
return $entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function findAllByCircles($userId, $limit = null, $offset = null) {
|
||||||
|
if (!$this->circlesEnabled) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$circles = array_map(function($circle) {
|
||||||
|
return $circle->getUniqueId();
|
||||||
|
}, \OCA\Circles\Api\v1\Circles::joinedCircles('', true));
|
||||||
|
if (count($circles) === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$sql = 'SELECT boards.id, title, owner, color, archived, deleted_at, 2 as shared, last_modified FROM `*PREFIX*deck_boards` as boards ' .
|
||||||
|
'INNER JOIN `*PREFIX*deck_board_acl` as acl ON boards.id=acl.board_id WHERE owner != ? AND type=? AND (';
|
||||||
|
for ($i = 0, $iMax = count($circles); $i < $iMax; $i++) {
|
||||||
|
$sql .= 'acl.participant = ? ';
|
||||||
|
if (count($circles) > 1 && $i < count($circles) - 1) {
|
||||||
|
$sql .= ' OR ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$sql .= ');';
|
||||||
|
$entries = $this->findEntities($sql, array_merge([$userId, Acl::PERMISSION_TYPE_CIRCLE], $circles), $limit, $offset);
|
||||||
|
/* @var Board $entry */
|
||||||
|
foreach ($entries as $entry) {
|
||||||
|
$acl = $this->aclMapper->findAll($entry->id);
|
||||||
|
$entry->setAcl($acl);
|
||||||
|
}
|
||||||
|
return $entries;
|
||||||
|
}
|
||||||
|
|
||||||
public function findAll() {
|
public function findAll() {
|
||||||
$sql = 'SELECT id from *PREFIX*deck_boards;';
|
$sql = 'SELECT id from *PREFIX*deck_boards;';
|
||||||
return $this->findEntities($sql);
|
return $this->findEntities($sql);
|
||||||
@@ -200,6 +234,20 @@ class BoardMapper extends DeckMapper implements IPermissionMapper {
|
|||||||
\OC::$server->getLogger()->debug('Group ' . $acl->getId() . ' not found when mapping acl ' . $acl->getParticipant());
|
\OC::$server->getLogger()->debug('Group ' . $acl->getId() . ' not found when mapping acl ' . $acl->getParticipant());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
// TODO: get circles list
|
||||||
|
if ($acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||||
|
try {
|
||||||
|
$circle = \OCA\Circles\Api\v1\Circles::detailsCircle($acl->getParticipant());
|
||||||
|
if ($circle) {
|
||||||
|
return new Circle($circle);
|
||||||
|
}
|
||||||
|
} catch (QueryException $e) {
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// TODO catch not found
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
// TODO: get circles list
|
||||||
throw new \Exception('Unknown permission type for mapping Acl');
|
throw new \Exception('Unknown permission type for mapping Acl');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
45
lib/Db/Circle.php
Normal file
45
lib/Db/Circle.php
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @copyright Copyright (c) 2017 Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @author Julius Härtl <jus@bitgrid.net>
|
||||||
|
*
|
||||||
|
* @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 OCA\Deck\Db;
|
||||||
|
|
||||||
|
|
||||||
|
class Circle extends RelationalObject {
|
||||||
|
|
||||||
|
/** @var \OCA\Circles\Model\Circle */
|
||||||
|
protected $object;
|
||||||
|
|
||||||
|
public function __construct(\OCA\Circles\Model\Circle $circle) {
|
||||||
|
$primaryKey = $circle->getUniqueId();
|
||||||
|
parent::__construct($primaryKey, $circle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getObjectSerialization() {
|
||||||
|
return [
|
||||||
|
'uid' => $this->object->getUniqueId(),
|
||||||
|
'displayname' => $this->object->getName(),
|
||||||
|
'typeString' => $this->object->getTypeString(),
|
||||||
|
'circleOwner' => $this->object->getOwner()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -97,7 +97,8 @@ class BoardService {
|
|||||||
$userInfo = $this->getBoardPrerequisites();
|
$userInfo = $this->getBoardPrerequisites();
|
||||||
$userBoards = $this->boardMapper->findAllByUser($userInfo['user'], null, null, $since);
|
$userBoards = $this->boardMapper->findAllByUser($userInfo['user'], null, null, $since);
|
||||||
$groupBoards = $this->boardMapper->findAllByGroups($userInfo['user'], $userInfo['groups'],null, null, $since);
|
$groupBoards = $this->boardMapper->findAllByGroups($userInfo['user'], $userInfo['groups'],null, null, $since);
|
||||||
$complete = array_merge($userBoards, $groupBoards);
|
$circleBoards = $this->boardMapper->findAllByCircles($userInfo['user'], null, null, $since);
|
||||||
|
$complete = array_merge($userBoards, $groupBoards, $circleBoards);
|
||||||
$result = [];
|
$result = [];
|
||||||
/** @var Board $item */
|
/** @var Board $item */
|
||||||
foreach ($complete as &$item) {
|
foreach ($complete as &$item) {
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ use OCA\Deck\NoPermissionException;
|
|||||||
use OCP\AppFramework\Db\DoesNotExistException;
|
use OCP\AppFramework\Db\DoesNotExistException;
|
||||||
use OCP\AppFramework\Db\Entity;
|
use OCP\AppFramework\Db\Entity;
|
||||||
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
use OCP\AppFramework\Db\MultipleObjectsReturnedException;
|
||||||
|
use OCP\AppFramework\QueryException;
|
||||||
use OCP\IConfig;
|
use OCP\IConfig;
|
||||||
use OCP\IGroupManager;
|
use OCP\IGroupManager;
|
||||||
use OCP\ILogger;
|
use OCP\ILogger;
|
||||||
@@ -61,6 +62,8 @@ class PermissionService {
|
|||||||
/** @var array */
|
/** @var array */
|
||||||
private $users = [];
|
private $users = [];
|
||||||
|
|
||||||
|
private $circlesEnabled = false;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
ILogger $logger,
|
ILogger $logger,
|
||||||
AclMapper $aclMapper,
|
AclMapper $aclMapper,
|
||||||
@@ -79,6 +82,8 @@ class PermissionService {
|
|||||||
$this->shareManager = $shareManager;
|
$this->shareManager = $shareManager;
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
|
|
||||||
|
$this->circlesEnabled = \OC::$server->getAppManager()->isEnabledForUser('circles');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -182,6 +187,16 @@ class PermissionService {
|
|||||||
if ($acl->getType() === Acl::PERMISSION_TYPE_USER && $acl->getParticipant() === $this->userId) {
|
if ($acl->getType() === Acl::PERMISSION_TYPE_USER && $acl->getParticipant() === $this->userId) {
|
||||||
return $acl->getPermission($permission);
|
return $acl->getPermission($permission);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->circlesEnabled && $acl->getType() === Acl::PERMISSION_TYPE_CIRCLE) {
|
||||||
|
try {
|
||||||
|
\OCA\Circles\Api\v1\Circles::getMember($acl->getParticipant(), $this->userId, 1);
|
||||||
|
return $acl->getPermission($permission);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
// TODO: getMember doesn't work for personal circles
|
||||||
|
$this->logger->info('Member not found in circle that was accessed. This should not happen.');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// check for groups
|
// check for groups
|
||||||
$hasGroupPermission = false;
|
$hasGroupPermission = false;
|
||||||
|
|||||||
@@ -33,6 +33,10 @@
|
|||||||
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_GROUP">
|
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_GROUP">
|
||||||
{{ sharee.participant.displayname }} (<?php p($l->t('Group')); ?>)
|
{{ sharee.participant.displayname }} (<?php p($l->t('Group')); ?>)
|
||||||
</span>
|
</span>
|
||||||
|
<div class="avatardiv circles" ng-if="sharee.type==OC.Share.SHARE_TYPE_CIRCLE"><i class="icon icon-circles icon-white"></i></div>
|
||||||
|
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_CIRCLE">
|
||||||
|
{{ sharee.participant.displayname }} (<?php p($l->t('Circle')); ?>)
|
||||||
|
</span>
|
||||||
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_USER">
|
<span class="has-tooltip username" ng-if="sharee.type==OC.Share.SHARE_TYPE_USER">
|
||||||
{{ sharee.participant.displayname }}
|
{{ sharee.participant.displayname }}
|
||||||
</span>
|
</span>
|
||||||
@@ -53,13 +57,17 @@
|
|||||||
<li ng-repeat="acl in boardservice.getCurrent().acl track by acl.participant.primaryKey">
|
<li ng-repeat="acl in boardservice.getCurrent().acl track by acl.participant.primaryKey">
|
||||||
<span class="icon-loading-small" style="display:none;" title="<?php p($l->t('Loading')); ?>"></span>
|
<span class="icon-loading-small" style="display:none;" title="<?php p($l->t('Loading')); ?>"></span>
|
||||||
<div class="avatardiv" avatar data-contactsmenu="true" data-user="{{ acl.participant.uid }}" data-displayname="{{ acl.participant.displayname }}" ng-if="acl.type==OC.Share.SHARE_TYPE_USER"></div>
|
<div class="avatardiv" avatar data-contactsmenu="true" data-user="{{ acl.participant.uid }}" data-displayname="{{ acl.participant.displayname }}" ng-if="acl.type==OC.Share.SHARE_TYPE_USER"></div>
|
||||||
<div class="avatardiv" ng-if="acl.type==OC.Share.SHARE_TYPE_GROUP"><i class="icon icon-{{aclTypeString(acl)}}" ></i></div>
|
<div class="avatardiv" ng-if="acl.type!=OC.Share.SHARE_TYPE_USER"><i class="icon icon-{{aclTypeString(acl)}}" ></i></div>
|
||||||
|
|
||||||
|
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_USER">
|
||||||
|
{{ acl.participant.displayname }}
|
||||||
|
</span>
|
||||||
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_GROUP">
|
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_GROUP">
|
||||||
{{ acl.participant.displayname }} (<?php p($l->t('Group')); ?>)
|
{{ acl.participant.displayname }} (<?php p($l->t('Group')); ?>)
|
||||||
</span>
|
</span>
|
||||||
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_USER">
|
<span class="has-tooltip username" ng-if="acl.type==OC.Share.SHARE_TYPE_CIRCLE">
|
||||||
{{ acl.participant.displayname }}
|
{{ acl.participant.displayname }} (<?php p($l->t('Circle')); ?> {{ acl.participant.typeString }})
|
||||||
|
<div>{{ acl.participant.circleOwner.display_name }}</div>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<span class="sharingOptionsGroup">
|
<span class="sharingOptionsGroup">
|
||||||
|
|||||||
@@ -123,6 +123,10 @@ class BoardServiceTest extends TestCase {
|
|||||||
->method('findAllByGroups')
|
->method('findAllByGroups')
|
||||||
->with('admin', ['a', 'b', 'c'])
|
->with('admin', ['a', 'b', 'c'])
|
||||||
->willReturn([$b2, $b3]);
|
->willReturn([$b2, $b3]);
|
||||||
|
$this->boardMapper->expects($this->once())
|
||||||
|
->method('findAllByCircles')
|
||||||
|
->with('admin')
|
||||||
|
->willReturn([]);
|
||||||
$user = $this->createMock(IUser::class);
|
$user = $this->createMock(IUser::class);
|
||||||
$this->groupManager->method('getUserGroupIds')
|
$this->groupManager->method('getUserGroupIds')
|
||||||
->willReturn(['a', 'b', 'c']);
|
->willReturn(['a', 'b', 'c']);
|
||||||
|
|||||||
Reference in New Issue
Block a user