diff --git a/README.md b/README.md
index acb4602fc..aa6a7abeb 100644
--- a/README.md
+++ b/README.md
@@ -43,6 +43,26 @@ In non-SSL environments (like on development setups) it is necessary to set two
`./occ config:app:set circles --value 1 local_is_non_ssl`
+## Allow mirroring circles as groups
+
+```bash
+./occ maintenance:mode --on
+
+./occ config:app:set circles --value 1 group_backend # Mirroring circles as groups
+./occ config:app:set circles --value 0 allow_listed_circles # Hide circles in shared list, useful with the 'group_backend' option
+
+# ./occ config:app:set circles --value "🌀 " group_backend_name_prefix # You can customize group name prefix
+# ./occ config:app:set circles --value " " group_backend_name_suffix # Remove default group name suffix with a `space` character
+
+./occ config:app:set circles --value 12 allow_circles # Only show 'public' and 'closed' circles
+./occ config:app:set circles --value 1 skip_invitation_to_closed_circles
+
+./occ config:app:set circles --value 0 allow_files_filtered_by_circles # Disable files list filtering by circles in the 'files' application
+./occ config:app:set circles --value 0 allow_adding_any_group_members # Adding group members only for groups where the current user is a member or global administrators
+
+./occ maintenance:mode --off
+```
+
# Credits
App Icon by [Madebyoliver](http://www.flaticon.com/authors/madebyoliver) under Creative Commons BY 3.0
diff --git a/appinfo/app.php b/appinfo/app.php
index a2dfb5939..709bd1e79 100644
--- a/appinfo/app.php
+++ b/appinfo/app.php
@@ -34,7 +34,4 @@
$app = \OC::$server->query(Application::class);
-$app->registerNavigation();
-$app->registerFilesNavigation();
-$app->registerFilesPlugin();
-
+$app->register();
diff --git a/lib/Activity/ProviderParser.php b/lib/Activity/ProviderParser.php
index 6254d40b7..99af607b1 100644
--- a/lib/Activity/ProviderParser.php
+++ b/lib/Activity/ProviderParser.php
@@ -32,6 +32,7 @@
use OCA\Circles\Model\FederatedLink;
use OCA\Circles\Model\Member;
use OCA\Circles\Service\MiscService;
+use OCA\Circles\Service\ConfigService;
use OCP\Activity\IEvent;
use OCP\Activity\IManager;
use OCP\IL10N;
@@ -39,7 +40,6 @@
class ProviderParser {
-
/** @var MiscService */
protected $miscService;
@@ -52,13 +52,28 @@ class ProviderParser {
/** @var IManager */
protected $activityManager;
+ /** @var ConfigService */
+ protected $configService;
+
+ /**
+ * @param IURLGenerator $url
+ * @param IManager $activityManager
+ * @param IL10N $l10n
+ * @param MiscService $miscService
+ * @param ConfigService $configService
+ */
public function __construct(
- IURLGenerator $url, IManager $activityManager, IL10N $l10n, MiscService $miscService
+ IURLGenerator $url,
+ IManager $activityManager,
+ IL10N $l10n,
+ MiscService $miscService,
+ ConfigService $configService
) {
$this->url = $url;
$this->activityManager = $activityManager;
$this->l10n = $l10n;
$this->miscService = $miscService;
+ $this->configService = $configService;
}
@@ -299,7 +314,7 @@ protected function generateViewerParameter(Circle $circle) {
*/
protected function generateExternalMemberParameter(Member $member) {
return [
- 'type' => 'user',
+ 'type' => $member->getTypeName(),
'id' => $member->getUserId(),
'name' => $member->getDisplayName() . ' (' . $member->getTypeString() . ')',
'_parsed' => $member->getDisplayName()
diff --git a/lib/Activity/ProviderSubjectMember.php b/lib/Activity/ProviderSubjectMember.php
index 486cb0543..37cf1ba06 100644
--- a/lib/Activity/ProviderSubjectMember.php
+++ b/lib/Activity/ProviderSubjectMember.php
@@ -68,7 +68,9 @@ public function parseSubjectMemberJoin(IEvent $event, Circle $circle, Member $me
* @throws FakeException
*/
private function parseSubjectMemberJoinClosedCircle(IEvent $event, Circle $circle, Member $member) {
- if ($circle->getType() !== Circle::CIRCLES_CLOSED) {
+ if ($circle->getType() !== Circle::CIRCLES_CLOSED ||
+ $this->configService->isInvitationSkipped()
+ ) {
return;
}
@@ -141,7 +143,9 @@ private function parseSubjectMemberAddNotLocalMember(IEvent $event, Circle $circ
* @throws FakeException
*/
private function parseSubjectMemberAddClosedCircle(IEvent $event, Circle $circle, Member $member) {
- if ($circle->getType() !== Circle::CIRCLES_CLOSED) {
+ if ($circle->getType() !== Circle::CIRCLES_CLOSED ||
+ $this->configService->isInvitationSkipped()
+ ) {
return;
}
diff --git a/lib/Api/Sharees.php b/lib/Api/Sharees.php
index 2755f93ce..7c80409de 100644
--- a/lib/Api/Sharees.php
+++ b/lib/Api/Sharees.php
@@ -30,6 +30,7 @@
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Member;
use OCA\Circles\Service\CirclesService;
+use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\MiscService;
use OCP\Share;
@@ -61,12 +62,20 @@ protected static function getContainer() {
// public static function search($search, $limit, $offset) {
public static function search($search) {
$c = self::getContainer();
+
+ $type = Circle::CIRCLES_ALL;
+ $circlesAreVisible = $c->query(ConfigService::class)
+ ->isListedCirclesAllowed();
+ if (!$circlesAreVisible) {
+ $type = $type - Circle::CIRCLES_CLOSED - Circle::CIRCLES_PUBLIC;
+ }
+
$userId = \OC::$server->getUserSession()
->getUser()
->getUID();
$data = $c->query(CirclesService::class)
- ->listCircles($userId, Circle::CIRCLES_ALL, $search, Member::LEVEL_MEMBER);
+ ->listCircles($userId, $type, $search, Member::LEVEL_MEMBER);
$result = array(
'exact' => ['circles'],
'circles' => []
@@ -111,4 +120,4 @@ private static function addResultEntry(&$result, $entry, $exact = false) {
}
-}
\ No newline at end of file
+}
diff --git a/lib/Api/v1/Circles.php b/lib/Api/v1/Circles.php
index 294e9433e..03f494a9f 100644
--- a/lib/Api/v1/Circles.php
+++ b/lib/Api/v1/Circles.php
@@ -37,6 +37,7 @@
use OCA\Circles\Model\Member;
use OCA\Circles\Model\SharingFrame;
use OCA\Circles\Service\CirclesService;
+use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\FederatedLinkService;
use OCA\Circles\Service\MembersService;
use OCA\Circles\Service\MiscService;
@@ -181,6 +182,43 @@ public static function leaveCircle($circleUniqueId) {
public static function listCircles($type, $name = '', $level = 0, $userId = '', $forceAll = false) {
$c = self::getContainer();
+ $configService = $c->query(ConfigService::class);
+ $circlesAreVisible = $configService->isListedCirclesAllowed();
+ $circlesAllowed = (int)$configService->getAppValue(ConfigService::CIRCLES_ALLOW_CIRCLES);
+
+ if (!$circlesAreVisible) {
+ switch (true) {
+ case ($type === Circle::CIRCLES_CLOSED):
+ case ($type === Circle::CIRCLES_PUBLIC):
+ case (Circle::CIRCLES_CLOSED + Circle::CIRCLES_PUBLIC === $circlesAllowed):
+ return [];
+ break;
+ case ($type === Circle::CIRCLES_ALL &&
+ $circlesAllowed === Circle::CIRCLES_ALL
+ ):
+ $type = $type - Circle::CIRCLES_CLOSED - Circle::CIRCLES_PUBLIC;
+ break;
+ case ($type > Circle::CIRCLES_CLOSED &&
+ $type < Circle::CIRCLES_PUBLIC &&
+ $circlesAllowed === Circle::CIRCLES_ALL
+ ):
+ $type = $type - Circle::CIRCLES_CLOSED;
+ break;
+ case ($type > Circle::CIRCLES_PUBLIC &&
+ $type < (Circle::CIRCLES_PUBLIC + Circle::CIRCLES_CLOSED) &&
+ $circlesAllowed === Circle::CIRCLES_ALL
+ ):
+ $type = $type - Circle::CIRCLES_PUBLIC;
+ break;
+ case ($type > (Circle::CIRCLES_PUBLIC + Circle::CIRCLES_CLOSED) &&
+ $type < Circle::CIRCLES_ALL &&
+ $circlesAllowed === Circle::CIRCLES_ALL
+ ):
+ $type = $type - Circle::CIRCLES_PUBLIC - Circle::CIRCLES_CLOSED;
+ break;
+ }
+ }
+
if ($userId === '') {
$userId = \OC::$server->getUserSession()
->getUser()
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 1b3c247dc..4e5762a7c 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -29,16 +29,18 @@
namespace OCA\Circles\AppInfo;
-use OC;
use OCA\Circles\Api\v1\Circles;
use OCA\Circles\Notification\Notifier;
use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\DavService;
+use OCA\Circles\Service\GroupsBackendService;
use OCA\Files\App as FilesApp;
use OCP\App\ManagerEvent;
use OCP\AppFramework\App;
use OCP\AppFramework\IAppContainer;
use OCP\AppFramework\QueryException;
+use OCP\IGroup;
+use OCP\EventDispatcher\IEventDispatcher;
use OCP\Util;
require_once __DIR__ . '/../../appinfo/autoload.php';
@@ -56,22 +58,36 @@ class Application extends App {
/** @var IAppContainer */
private $container;
+ /** @var \OC\ServerServer */
+ private $server;
+
+ /** @var IEventDispatcher */
+ private $dispatcher;
+
/**
* @param array $params
*/
public function __construct(array $params = array()) {
parent::__construct(self::APP_NAME, $params);
+ }
+ public function register()
+ {
$this->container = $this->getContainer();
+ $this->server = $this->container->getServer();
+ $this->dispatcher = $this->server->query(IEventDispatcher::class);
- $manager = OC::$server->getNotificationManager();
+ $manager = $this->server->getNotificationManager();
$manager->registerNotifierService(Notifier::class);
+ $this->registerNavigation();
+ $this->registerFilesNavigation();
+ $this->registerFilesPlugin();
$this->registerHooks();
$this->registerDavHooks();
+ $this->registerGroupsBackendHooks();
}
-
/**
* Register Hooks
*/
@@ -91,7 +107,7 @@ public function registerHooks() {
public function registerNavigation() {
/** @var ConfigService $configService */
try {
- $configService = OC::$server->query(ConfigService::class);
+ $configService = $this->server->query(ConfigService::class);
} catch (QueryException $e) {
return;
}
@@ -104,8 +120,8 @@ public function registerNavigation() {
->getNavigationManager();
$appManager->add(
function() {
- $urlGen = OC::$server->getURLGenerator();
- $navName = OC::$server->getL10N(self::APP_NAME)
+ $urlGen = $this->server->getURLGenerator();
+ $navName = $this->server->getL10N(self::APP_NAME)
->t('Circles');
return [
@@ -121,8 +137,17 @@ function() {
}
public function registerFilesPlugin() {
- $eventDispatcher = OC::$server->getEventDispatcher();
- $eventDispatcher->addListener(
+ try {
+ /** @var ConfigService $configService */
+ $configService = $this->server->query(ConfigService::class);
+ if (!$configService->isFilesFilteredCirclesAllowed()) {
+ return;
+ }
+ } catch (QueryException $e) {
+ return;
+ }
+
+ $this->dispatcher->addListener(
'OCA\Files::loadAdditionalScripts',
function() {
Circles::addJavascriptAPI();
@@ -140,10 +165,20 @@ function() {
*
*/
public function registerFilesNavigation() {
+ try {
+ /** @var ConfigService $configService */
+ $configService = $this->server->query(ConfigService::class);
+ if (!$configService->isFilesFilteredCirclesAllowed()) {
+ return;
+ }
+ } catch (QueryException $e) {
+ return;
+ }
+
$appManager = FilesApp::getNavigationManager();
$appManager->add(
function() {
- $l = OC::$server->getL10N('circles');
+ $l = $this->server->getL10N('circles');
return [
'id' => 'circlesfilter',
@@ -160,24 +195,63 @@ function() {
public function registerDavHooks() {
try {
/** @var ConfigService $configService */
- $configService = OC::$server->query(ConfigService::class);
+ $configService = $this->server->query(ConfigService::class);
if (!$configService->isContactsBackend()) {
return;
}
/** @var DavService $davService */
- $davService = OC::$server->query(DavService::class);
+ $davService = $this->server->query(DavService::class);
} catch (QueryException $e) {
return;
}
- $event = OC::$server->getEventDispatcher();
+ $this->dispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, [$davService, 'onAppEnabled']);
+ $this->dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::createCard', [$davService, 'onCreateCard']);
+ $this->dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::updateCard', [$davService, 'onUpdateCard']);
+ $this->dispatcher->addListener('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', [$davService, 'onDeleteCard']);
+ }
- $event->addListener(ManagerEvent::EVENT_APP_ENABLE, [$davService, 'onAppEnabled']);
- $event->addListener('\OCA\DAV\CardDAV\CardDavBackend::createCard', [$davService, 'onCreateCard']);
- $event->addListener('\OCA\DAV\CardDAV\CardDavBackend::updateCard', [$davService, 'onUpdateCard']);
- $event->addListener('\OCA\DAV\CardDAV\CardDavBackend::deleteCard', [$davService, 'onDeleteCard']);
+ public function registerGroupsBackendHooks() {
+ try {
+ /** @var ConfigService $configService */
+ $configService = $this->server->query(ConfigService::class);
+ if (!$configService->isGroupsBackend()) {
+ return;
+ }
+
+ /** @var GroupsBackendService $groupsBackendService */
+ $groupsBackendService = $this->server->query(GroupsBackendService::class);
+ } catch (QueryException $e) {
+ return;
+ }
+
+ $this->dispatcher->addListener(ManagerEvent::EVENT_APP_ENABLE, [$groupsBackendService, 'onAppEnabled']);
+ $this->dispatcher->addListener('\OCA\Circles::onCircleCreation', [$groupsBackendService, 'onCircleCreation']);
+ $this->dispatcher->addListener('\OCA\Circles::onCircleDestruction', [$groupsBackendService, 'onCircleDestruction']);
+ $this->dispatcher->addListener('\OCA\Circles::onMemberNew', [$groupsBackendService, 'onMemberNew']);
+ $this->dispatcher->addListener('\OCA\Circles::onMemberInvited', [$groupsBackendService, 'onMemberInvited']);
+ $this->dispatcher->addListener('\OCA\Circles::onMemberRequesting', [$groupsBackendService, 'onMemberRequesting']);
+ $this->dispatcher->addListener('\OCA\Circles::onMemberLeaving', [$groupsBackendService, 'onMemberLeaving']);
+ $this->dispatcher->addListener('\OCA\Circles::onMemberLevel', [$groupsBackendService, 'onMemberLevel']);
+ $this->dispatcher->addListener('\OCA\Circles::onMemberOwner', [$groupsBackendService, 'onMemberOwner']);
+ $this->dispatcher->addListener('\OCA\Circles::onGroupLink', [$groupsBackendService, 'onGroupLink']);
+ $this->dispatcher->addListener('\OCA\Circles::onGroupUnlink', [$groupsBackendService, 'onGroupUnlink']);
+ $this->dispatcher->addListener('\OCA\Circles::onGroupLevel', [$groupsBackendService, 'onGroupLevel']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRequestSent', [$groupsBackendService, 'onLinkRequestSent']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRequestReceived', [$groupsBackendService, 'onLinkRequestReceived']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRequestRejected', [$groupsBackendService, 'onLinkRequestRejected']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRequestCanceled', [$groupsBackendService, 'onLinkRequestCanceled']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRequestAccepted', [$groupsBackendService, 'onLinkRequestAccepted']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRequestAccepting', [$groupsBackendService, 'onLinkRequestAccepting']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkUp', [$groupsBackendService, 'onLinkUp']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkDown', [$groupsBackendService, 'onLinkDown']);
+ $this->dispatcher->addListener('\OCA\Circles::onLinkRemove', [$groupsBackendService, 'onLinkRemove']);
+ $this->dispatcher->addListener('\OCA\Circles::onSettingsChange', [$groupsBackendService, 'onSettingsChange']);
+
+ $this->dispatcher->addListener(IGroup::class . '::postAddUser', [$groupsBackendService, 'onGroupPostAddUser']);
+ $this->dispatcher->addListener(IGroup::class . '::postRemoveUser', [$groupsBackendService, 'onGroupPostRemoveUser']);
+ $this->dispatcher->addListener(IGroup::class . '::postDelete', [$groupsBackendService, 'onGroupPostDelete']);
}
}
-
diff --git a/lib/Db/CirclesRequest.php b/lib/Db/CirclesRequest.php
index aca9d7fec..d49304634 100644
--- a/lib/Db/CirclesRequest.php
+++ b/lib/Db/CirclesRequest.php
@@ -130,6 +130,36 @@ public function forceGetCircleByName($name) {
}
+ /**
+ * forceGetCircleByGroupId();
+ *
+ * returns data of a circle from its Group ID.
+ *
+ * WARNING: This function does not filters data regarding the current user/viewer.
+ * In case of interaction with users, do not use this method.
+ *
+ * @param $groupId
+ *
+ * @return null|Circle
+ */
+ public function forceGetCircleByGroupId($groupId) {
+ $qb = $this->getCirclesSelectSql();
+
+ $this->limitToGroupId($qb, $groupId);
+
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ $cursor->closeCursor();
+
+ if ($data === false) {
+ return null;
+ }
+
+ $entry = $this->parseCirclesSelectSql($data);
+
+ return $entry;
+ }
+
/**
* @param string $userId
* @param int $type
@@ -331,7 +361,8 @@ public function updateCircle(Circle $circle, $userId) {
$qb = $this->getCirclesUpdateSql($circle->getUniqueId(true));
$qb->set('name', $qb->createNamedParameter($circle->getName()))
->set('description', $qb->createNamedParameter($circle->getDescription()))
- ->set('settings', $qb->createNamedParameter($circle->getSettings(true)));
+ ->set('settings', $qb->createNamedParameter($circle->getSettings(true)))
+ ->set('group_id', $qb->createNamedParameter($circle->getGroupId()));
$qb->execute();
}
diff --git a/lib/Db/CirclesRequestBuilder.php b/lib/Db/CirclesRequestBuilder.php
index 9f773c8fe..9226aa2c8 100644
--- a/lib/Db/CirclesRequestBuilder.php
+++ b/lib/Db/CirclesRequestBuilder.php
@@ -392,7 +392,7 @@ protected function getCirclesSelectSql() {
$qb->selectDistinct('c.unique_id')
->addSelect(
'c.id', 'c.name', 'c.description', 'c.settings', 'c.type', 'contact_addressbook',
- 'contact_groupname', 'c.creation'
+ 'contact_groupname', 'c.creation', 'c.group_id'
)
->from(CoreRequestBuilder::TABLE_CIRCLES, 'c');
$this->default_select_alias = 'c';
@@ -419,6 +419,7 @@ protected function parseCirclesSelectSql($data) {
if ($data['contact_groupname'] !== null) {
$circle->setContactGroupName($data['contact_groupname']);
}
+ $circle->setGroupId($data['group_id']);
$circle->setSettings($data['settings']);
$circle->setType($data['type']);
$circle->setCreation($data['creation']);
diff --git a/lib/Db/MembersRequest.php b/lib/Db/MembersRequest.php
index 54bd6961e..e60c8f048 100644
--- a/lib/Db/MembersRequest.php
+++ b/lib/Db/MembersRequest.php
@@ -637,6 +637,14 @@ public function unlinkAllFromGroup($groupId) {
}
+ public function unlinkFromGroup($circleId, $groupId) {
+ $qb = $this->getGroupsDeleteSql($groupId);
+ $this->limitToCircleId($qb, $circleId);
+
+ $qb->execute();
+ }
+
+
/**
* @param string $contactId
*
@@ -731,4 +739,3 @@ public function removeMembersByContactId(string $contactId, int $type = 0) {
}
-
diff --git a/lib/Migration/Version0017Date20200221173726.php b/lib/Migration/Version0017Date20200221173726.php
new file mode 100644
index 000000000..e27d834a1
--- /dev/null
+++ b/lib/Migration/Version0017Date20200221173726.php
@@ -0,0 +1,81 @@
+
+ * @copyright 2019
+ * @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 .
+ *
+ */
+
+declare(strict_types=1);
+
+namespace OCA\Circles\Migration;
+
+use Closure;
+use Doctrine\DBAL\Schema\SchemaException;
+use Doctrine\DBAL\Types\Type;
+use OCP\DB\ISchemaWrapper;
+use OCP\IDBConnection;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+/**
+ * Auto-generated migration step: Please modify to your needs!
+ */
+class Version0017Date20200221173726 extends SimpleMigrationStep {
+
+
+ /** @var IDBConnection */
+ private $connection;
+
+
+ /**
+ * @param IDBConnection $connection
+ */
+ public function __construct(IDBConnection $connection) {
+ $this->connection = $connection;
+ }
+
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ *
+ * @return null|ISchemaWrapper
+ * @throws SchemaException
+ */
+ public function changeSchema(IOutput $output, Closure $schemaClosure, array $options) {
+ /** @var ISchemaWrapper $schema */
+ $schema = $schemaClosure();
+
+ $table = $schema->getTable('circles_circles');
+ $table->addColumn(
+ 'group_id', 'string', [
+ 'notnull' => false,
+ 'default' => '',
+ 'length' => 64,
+ ]
+ );
+
+ return $schema;
+ }
+
+}
diff --git a/lib/Model/BaseCircle.php b/lib/Model/BaseCircle.php
index 523662cff..3bd78c0a4 100644
--- a/lib/Model/BaseCircle.php
+++ b/lib/Model/BaseCircle.php
@@ -82,6 +82,8 @@ class BaseCircle {
/** @var int */
private $contactAddressBook = 0;
+ /** @var string */
+ private $groupId = '';
/** @var string */
private $creation;
@@ -307,6 +309,23 @@ public function getContactGroupName() {
return $this->contactGroupName;
}
+ /**
+ * @param string $groupId
+ *
+ * @return BaseCircle
+ */
+ public function setGroupId($groupId) {
+ $this->groupId = (string) $groupId;
+
+ return $this;
+ }
+
+ /**
+ * @return string
+ */
+ public function getGroupId() {
+ return (string) $this->groupId;
+ }
/**
* @param string|array $settings
diff --git a/lib/Model/BaseMember.php b/lib/Model/BaseMember.php
index 60c177b71..d37596eec 100644
--- a/lib/Model/BaseMember.php
+++ b/lib/Model/BaseMember.php
@@ -439,4 +439,17 @@ public function getTypeString() {
return 'none';
}
+
+ public function getTypeName() {
+ switch ($this->getType()) {
+ case self::TYPE_USER:
+ case self::TYPE_MAIL:
+ case self::TYPE_CONTACT:
+ return 'user';
+ case self::TYPE_GROUP:
+ return 'user-group';
+ }
+
+ return 'none';
+ }
}
diff --git a/lib/Model/Circle.php b/lib/Model/Circle.php
index 506ee313c..bdad2c37c 100644
--- a/lib/Model/Circle.php
+++ b/lib/Model/Circle.php
@@ -75,6 +75,7 @@ public function jsonSerialize() {
'viewer' => $this->getHigherViewer(),
'description' => $this->getDescription(),
'settings' => $this->getSettings(),
+ 'group_id' => $this->getGroupId(),
'type' => $this->getType(),
'creation' => $this->getCreation(),
'type_string' => $this->getTypeString(),
@@ -253,5 +254,3 @@ public static function typeLongString($type) {
}
-
-
diff --git a/lib/Model/Member.php b/lib/Model/Member.php
index af6f8c1f9..03c2612b3 100644
--- a/lib/Model/Member.php
+++ b/lib/Model/Member.php
@@ -63,6 +63,7 @@ public function inviteToCircle($circleType) {
public function joinCircle($circleType) {
switch ($circleType) {
+ case Circle::CIRCLES_PERSONAL:
case Circle::CIRCLES_SECRET:
case Circle::CIRCLES_PUBLIC:
return $this->addMemberToCircle();
@@ -264,5 +265,3 @@ public function hasToBeInviteAble() {
}
}
-
-
diff --git a/lib/Search/LocalGroups.php b/lib/Search/LocalGroups.php
index 7c2e3f202..594490ac8 100644
--- a/lib/Search/LocalGroups.php
+++ b/lib/Search/LocalGroups.php
@@ -26,26 +26,48 @@
namespace OCA\Circles\Search;
+use OC;
use OCA\Circles\ISearch;
use OCA\Circles\Model\Member;
use OCA\Circles\Model\SearchResult;
+use OCP\IUser;
+use OCA\Circles\Service\ConfigService;
class LocalGroups implements ISearch {
+ /** @var ConfigService */
+ private $configService;
+
+ /**
+ * @param ConfigService $configService
+ */
+ public function __construct(ConfigService $configService)
+ {
+ $this->configService = $configService;
+ }
+
/**
* {@inheritdoc}
*/
public function search($search) {
$result = [];
- $groupManager = \OC::$server->getGroupManager();
+ $groupManager = OC::$server->getGroupManager();
$groups = $groupManager->search($search);
+ $user = OC::$server->getUserSession()->getUser();
foreach ($groups as $group) {
- $result[] = new SearchResult($group->getGID(), Member::TYPE_GROUP);
+ if ($this->configService->isAddingAnyGroupMembersAllowed() ||
+ (
+ $user instanceof IUser &&
+ ($group->inGroup($user) || $groupManager->isAdmin($user->getUID()))
+ )
+ ) {
+ $result[] = new SearchResult($group->getGID(), Member::TYPE_GROUP);
+ }
}
return $result;
}
-}
\ No newline at end of file
+}
diff --git a/lib/Service/CirclesService.php b/lib/Service/CirclesService.php
index 92f3c85b2..0cd6aaaac 100644
--- a/lib/Service/CirclesService.php
+++ b/lib/Service/CirclesService.php
@@ -318,6 +318,14 @@ public function settingsCircle($circleUniqueId, $settings) {
$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
$this->hasToBeOwner($circle->getHigherViewer());
+ $oldSettings = array_merge(
+ $circle->getSettings(),
+ [
+ 'circle_name' => $circle->getName(),
+ 'circle_desc' => $circle->getDescription(),
+ ]
+ );
+
if (!$this->viewerIsAdmin()) {
$settings['members_limit'] = $circle->getSetting('members_limit');
}
@@ -329,7 +337,7 @@ public function settingsCircle($circleUniqueId, $settings) {
$this->circlesRequest->updateCircle($circle, $this->userId);
- $this->eventsService->onSettingsChange($circle);
+ $this->eventsService->onSettingsChange($circle, $oldSettings);
} catch (\Exception $e) {
throw $e;
}
@@ -577,11 +585,11 @@ public function checkThatCircleIsNotFull(Circle $circle) {
$circle->getUniqueId(), Member::LEVEL_MEMBER, true
);
- $limit = $circle->getSetting('members_limit');
+ $limit = (int) $circle->getSetting('members_limit');
if ($limit === -1) {
return;
}
- if ($limit === 0 || $limit === '' || $limit === null) {
+ if ($limit === 0) {
$limit = $this->configService->getAppValue(ConfigService::CIRCLES_MEMBERS_LIMIT);
}
diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php
index c1497c7ac..02a873c41 100644
--- a/lib/Service/ConfigService.php
+++ b/lib/Service/ConfigService.php
@@ -26,6 +26,7 @@
namespace OCA\Circles\Service;
+use OC;
use OCA\Circles\Model\Circle;
use OCP\IConfig;
use OCP\IRequest;
@@ -37,10 +38,16 @@ class ConfigService {
const CIRCLES_ALLOW_CIRCLES = 'allow_circles';
const CIRCLES_CONTACT_BACKEND = 'contact_backend';
const CIRCLES_STILL_FRONTEND = 'still_frontend';
+ const CIRCLES_GROUP_BACKEND = 'group_backend';
+ const CIRCLES_GROUP_BACKEND_NAME_PREFIX = 'group_backend_name_prefix';
+ const CIRCLES_GROUP_BACKEND_NAME_SUFFIX = 'group_backend_name_suffix';
const CIRCLES_SWAP_TO_TEAMS = 'swap_to_teams';
const CIRCLES_ALLOW_FEDERATED_CIRCLES = 'allow_federated';
const CIRCLES_MEMBERS_LIMIT = 'members_limit';
const CIRCLES_ACCOUNTS_ONLY = 'accounts_only';
+ const CIRCLES_ALLOW_FILES_CIRCLES_FILTER = 'allow_files_filtered_by_circles';
+ const CIRCLES_ALLOW_LISTED_CIRCLES = 'allow_listed_circles';
+ const CIRCLES_ALLOW_ANY_GROUP_MEMBERS = 'allow_adding_any_group_members';
const CIRCLES_ALLOW_LINKED_GROUPS = 'allow_linked_groups';
const CIRCLES_ALLOW_NON_SSL_LINKS = 'allow_non_ssl_links';
const CIRCLES_NON_SSL_LOCAL = 'local_is_non_ssl';
@@ -53,19 +60,25 @@ class ConfigService {
const CIRCLES_TEST_ASYNC_COUNT = 'test_async_count';
private $defaults = [
- self::CIRCLES_ALLOW_CIRCLES => Circle::CIRCLES_ALL,
- self::CIRCLES_CONTACT_BACKEND => '0',
- self::CIRCLES_STILL_FRONTEND => '0',
- self::CIRCLES_TEST_ASYNC_INIT => '0',
- self::CIRCLES_SWAP_TO_TEAMS => '0',
- self::CIRCLES_ACCOUNTS_ONLY => '0',
- self::CIRCLES_MEMBERS_LIMIT => '50',
- self::CIRCLES_ALLOW_LINKED_GROUPS => '0',
- self::CIRCLES_ALLOW_FEDERATED_CIRCLES => '0',
- self::CIRCLES_ALLOW_NON_SSL_LINKS => '0',
- self::CIRCLES_NON_SSL_LOCAL => '0',
- self::CIRCLES_ACTIVITY_ON_CREATION => '1',
- self::CIRCLES_SKIP_INVITATION_STEP => '0'
+ self::CIRCLES_ALLOW_CIRCLES => Circle::CIRCLES_ALL,
+ self::CIRCLES_CONTACT_BACKEND => '0',
+ self::CIRCLES_STILL_FRONTEND => '0',
+ self::CIRCLES_GROUP_BACKEND => '0',
+ self::CIRCLES_GROUP_BACKEND_NAME_PREFIX => '',
+ self::CIRCLES_GROUP_BACKEND_NAME_SUFFIX => '',
+ self::CIRCLES_TEST_ASYNC_INIT => '0',
+ self::CIRCLES_SWAP_TO_TEAMS => '0',
+ self::CIRCLES_ACCOUNTS_ONLY => '0',
+ self::CIRCLES_MEMBERS_LIMIT => '50',
+ self::CIRCLES_ALLOW_FILES_CIRCLES_FILTER => '1',
+ self::CIRCLES_ALLOW_LISTED_CIRCLES => '1',
+ self::CIRCLES_ALLOW_ANY_GROUP_MEMBERS => '1',
+ self::CIRCLES_ALLOW_LINKED_GROUPS => '0',
+ self::CIRCLES_ALLOW_FEDERATED_CIRCLES => '0',
+ self::CIRCLES_ALLOW_NON_SSL_LINKS => '0',
+ self::CIRCLES_NON_SSL_LOCAL => '0',
+ self::CIRCLES_ACTIVITY_ON_CREATION => '1',
+ self::CIRCLES_SKIP_INVITATION_STEP => '0'
];
/** @var string */
@@ -86,6 +99,15 @@ class ConfigService {
/** @var int */
private $allowedCircle = -1;
+ /** @var int */
+ private $allowFilesFilteredByCircles = -1;
+
+ /** @var int */
+ private $allowedListedCircles = -1;
+
+ /** @var int */
+ private $allowAddingAnyGroupMembers = -1;
+
/** @var int */
private $allowedLinkedGroups = -1;
@@ -98,6 +120,12 @@ class ConfigService {
/** @var int */
private $localNonSSL = -1;
+ /** @var string */
+ private $groupBackendNamePrefix = null;
+
+ /** @var string */
+ private $groupBackendNameSuffix = null;
+
/**
* ConfigService constructor.
*
@@ -139,6 +167,48 @@ public function isCircleAllowed($type) {
return ((int)$type & (int)$this->allowedCircle);
}
+ /**
+ * returns if the files list could be filtered by circles
+ *
+ * @return bool
+ */
+ public function isFilesFilteredCirclesAllowed() {
+ if ($this->allowFilesFilteredByCircles === -1) {
+ $this->allowFilesFilteredByCircles =
+ (int)$this->getAppValue(self::CIRCLES_ALLOW_FILES_CIRCLES_FILTER);
+ }
+
+ return ($this->allowFilesFilteredByCircles === 1);
+ }
+
+ /**
+ * returns if the circles are allowed to be listed outside the Circles application.
+ *
+ * @return bool
+ */
+ public function isListedCirclesAllowed() {
+ if ($this->allowedListedCircles === -1) {
+ $this->allowedListedCircles =
+ (int)$this->getAppValue(self::CIRCLES_ALLOW_LISTED_CIRCLES);
+ }
+
+ return ($this->allowedListedCircles === 1);
+ }
+
+ /**
+ * returns if the current user is allowed to add any group members.
+ * even if he isn't a member of these groups
+ *
+ * @return bool
+ */
+ public function isAddingAnyGroupMembersAllowed() {
+ if ($this->allowAddingAnyGroupMembers === -1) {
+ $this->allowAddingAnyGroupMembers =
+ (int)$this->getAppValue(self::CIRCLES_ALLOW_ANY_GROUP_MEMBERS);
+ }
+
+ return ($this->allowAddingAnyGroupMembers === 1);
+ }
/**
* @return bool
@@ -383,6 +453,41 @@ public function contactsBackendType(): int {
return (int)$this->getAppValue(ConfigService::CIRCLES_CONTACT_BACKEND);
}
+ /**
+ * @return bool
+ */
+ public function isGroupsBackend(): bool {
+ return ($this->getAppValue(ConfigService::CIRCLES_GROUP_BACKEND) !== '0');
+ }
+
+ /**
+ * returns the prefix of the group name
+ *
+ * @return string|null
+ */
+ public function getGroupBackendNamePrefix() {
+ if ($this->groupBackendNamePrefix === null && $this->isGroupsBackend()) {
+ $this->groupBackendNamePrefix = ltrim((string) $this->getAppValue(self::CIRCLES_GROUP_BACKEND_NAME_PREFIX));
+ }
+
+ return $this->groupBackendNamePrefix;
+ }
+
+ /**
+ * returns the suffix of the group name
+ *
+ * @return string|null
+ */
+ public function getGroupBackendNameSuffix() {
+ if ($this->groupBackendNameSuffix === null && $this->isGroupsBackend()) {
+ $l = OC::$server->getL10N('circles');
+ $defaultSuffix = ' '.$l->t('Circle');
+ $customSuffix = (string) $this->getAppValue(self::CIRCLES_GROUP_BACKEND_NAME_SUFFIX);
+ $this->groupBackendNameSuffix = rtrim($customSuffix ?: $defaultSuffix);
+ }
+
+ return $this->groupBackendNameSuffix;
+ }
/**
* @return bool
diff --git a/lib/Service/DavService.php b/lib/Service/DavService.php
index 448bb2213..baa508c9a 100644
--- a/lib/Service/DavService.php
+++ b/lib/Service/DavService.php
@@ -46,7 +46,7 @@
use OCP\App\ManagerEvent;
use OCP\Federation\ICloudIdManager;
use OCP\IUserManager;
-use Symfony\Component\EventDispatcher\GenericEvent;
+use OCP\EventDispatcher\GenericEvent;
/**
diff --git a/lib/Service/EventsService.php b/lib/Service/EventsService.php
index 6495c2279..b3fb183d9 100644
--- a/lib/Service/EventsService.php
+++ b/lib/Service/EventsService.php
@@ -39,10 +39,10 @@
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\EventDispatcher\IEventDispatcher;
+use OCP\EventDispatcher\GenericEvent;
use OCP\Notification\IManager as INotificationManager;
use OCP\Notification\INotification;
-use Symfony\Component\EventDispatcher\EventDispatcher;
-use Symfony\Component\EventDispatcher\GenericEvent;
class EventsService {
@@ -65,7 +65,7 @@ class EventsService {
/** @var IURLGenerator */
private $urlGenerator;
- /** @var EventDispatcher */
+ /** @var IEventDispatcher */
private $eventDispatcher;
/** @var CirclesRequest */
@@ -90,7 +90,7 @@ class EventsService {
* @param INotificationManager $notificationManager
* @param IUserManager $userManager
* @param IURLGenerator $urlGenerator
- * @param EventDispatcher $eventDispatcher
+ * @param IEventDispatcher $eventDispatcher
* @param CirclesRequest $circlesRequest
* @param MembersRequest $membersRequest
* @param ConfigService $configService
@@ -99,7 +99,7 @@ class EventsService {
public function __construct(
$userId, ITimeFactory $time, IActivityManager $activityManager,
INotificationManager $notificationManager, IUserManager $userManager, IURLGenerator $urlGenerator,
- EventDispatcher $eventDispatcher, CirclesRequest $circlesRequest, MembersRequest $membersRequest,
+ IEventDispatcher $eventDispatcher, CirclesRequest $circlesRequest, MembersRequest $membersRequest,
ConfigService $configService, MiscService $miscService
) {
$this->userId = $userId;
@@ -126,21 +126,22 @@ public function __construct(
* @param Circle $circle
*/
public function onCircleCreation(Circle $circle) {
- if ($this->configService->getAppValue(ConfigService::CIRCLES_ACTIVITY_ON_CREATION) !== '1'
- || ($circle->getType() !== Circle::CIRCLES_PUBLIC
- && $circle->getType() !== Circle::CIRCLES_CLOSED)) {
+ if ($circle->getType() !== Circle::CIRCLES_PUBLIC
+ && $circle->getType() !== Circle::CIRCLES_CLOSED) {
return;
}
- $event = $this->generateEvent('circles_as_non_member');
- $event->setSubject('circle_create', ['circle' => json_encode($circle)]);
+ if ($this->configService->getAppValue(ConfigService::CIRCLES_ACTIVITY_ON_CREATION) === '1') {
+ $event = $this->generateEvent('circles_as_non_member');
+ $event->setSubject('circle_create', ['circle' => json_encode($circle)]);
- $this->userManager->callForSeenUsers(
- function($user) use ($event) {
- /** @var IUser $user */
- $this->publishEvent($event, [$user]);
- }
- );
+ $this->userManager->callForSeenUsers(
+ function($user) use ($event) {
+ /** @var IUser $user */
+ $this->publishEvent($event, [$user]);
+ }
+ );
+ }
$this->dispatch('\OCA\Circles::onCircleCreation', ['circle' => $circle]);
}
@@ -213,6 +214,7 @@ public function onMemberNew(Circle $circle, Member $member) {
)
)
);
+
$this->dispatch('\OCA\Circles::onMemberNew', ['circle' => $circle, 'member' => $member]);
$this->notificationOnMemberNew($circle, $member);
@@ -340,6 +342,7 @@ public function onMemberLeaving(Circle $circle, Member $member) {
)
)
);
+
$this->dispatch('\OCA\Circles::onMemberLeaving', ['circle' => $circle, 'member' => $member]);
$this->deleteNotification('membership', $member->getMemberId());
@@ -747,9 +750,10 @@ public function onLinkRemove(Circle $circle, FederatedLink $link) {
* Called when the circle's settings are changed
*
* @param Circle $circle
+ * @param array $oldSettings
*/
- public function onSettingsChange(Circle $circle) {
- $this->dispatch('\OCA\Circles::onSettingsChange', ['circle' => $circle]);
+ public function onSettingsChange(Circle $circle, array $oldSettings = []) {
+ $this->dispatch('\OCA\Circles::onSettingsChange', ['circle' => $circle, 'oldSettings' => $oldSettings]);
}
diff --git a/lib/Service/GroupsBackendService.php b/lib/Service/GroupsBackendService.php
new file mode 100644
index 000000000..98f91ff85
--- /dev/null
+++ b/lib/Service/GroupsBackendService.php
@@ -0,0 +1,442 @@
+
+ * @copyright 2017
+ * @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 .
+ *
+ */
+
+namespace OCA\Circles\Service;
+
+// use Exception;
+use OCP\App\ManagerEvent;
+use OCA\Circles\Db\CirclesRequest;
+use OCA\Circles\Db\MembersRequest;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\Member;
+use OCP\EventDispatcher\GenericEvent;
+use Symfony\Component\EventDispatcher\GenericEvent as SymfonyGenericEvent;
+use OCP\IGroup;
+use OCP\IUser;
+use OCP\IGroupManager;
+use OCP\IUserManager;
+
+/**
+ * Class GroupsBackendService
+ *
+ * @package OCA\Circles\Service
+ */
+class GroupsBackendService {
+
+ /** @var string */
+ protected $userId;
+
+ /** @var Circle */
+ protected $circle;
+
+ /** @var Member */
+ protected $member;
+
+ /** @var IGroup */
+ protected $group;
+
+ /** @var IUser */
+ protected $user;
+
+ /** @var ConfigService */
+ protected $configService;
+
+ /** @var MiscService */
+ protected $miscService;
+
+ /** @var CirclesRequest */
+ protected $circlesRequest;
+
+ /** @var MembersRequest */
+ protected $membersRequest;
+
+ /** @var IGroupManager */
+ protected $groupManager;
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /**
+ * GroupsBackendService constructor.
+ *
+ * @param string $userId
+ * @param CirclesRequest $circlesRequest
+ * @param MembersRequest $membersRequest
+ * @param IGroupManager $groupManager
+ * @param IUserManager $userManager
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ $userId,
+ CirclesRequest $circlesRequest,
+ MembersRequest $membersRequest,
+ IGroupManager $groupManager,
+ IUserManager $userManager,
+ ConfigService $configService,
+ MiscService $miscService
+ ) {
+ $this->userId = $userId;
+ $this->circlesRequest = $circlesRequest;
+ $this->membersRequest = $membersRequest;
+ $this->groupManager = $groupManager;
+ $this->userManager = $userManager;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+ /**
+ * @param ManagerEvent $event
+ */
+ public function onAppEnabled(ManagerEvent $event) {
+ if ($event->getAppID() !== 'circles') {
+ return;
+ }
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onCircleCreation(GenericEvent $event) {
+ $this->circle = $event->getArgument('circle');
+ // '\OC\Group', 'postDelete'
+ // '\OC\Group', 'postAddUser'
+ // '\OC\Group', 'postRemoveUser'
+ // $eventName ='\OC\Group::postCreate';
+
+ // $listeners = $this->eventDispatcher->getSymfonyDispatcher()->getListeners($eventName);
+ // $this->miscService->log('number of listeners: '. count($listeners), 1);
+
+ // foreach ($listeners as $listener) {
+ // $this->miscService->log('remove listener: '. json_encode($listener), 1);
+ // $this->eventDispatcher->getSymfonyDispatcher()->removeListener($eventName, $listener);
+ // }
+
+ $this->group = $this->groupManager->createGroup($this->getCircleGroupName());
+
+ // foreach ($listeners as $listener) {
+ // $this->miscService->log('add listener: '. json_encode($listener), 1);
+ // $this->eventDispatcher->getSymfonyDispatcher()->addListener($eventName, $listener);
+ // }
+
+ if ($this->group) {
+ $this->member = $this->circle->getOwner();
+
+ $this->circle->setGroupId($this->group->getGID());
+ $this->circlesRequest->updateCircle($this->circle, $this->member->getUserId());
+
+ if ($this->member->getType() === Member::TYPE_USER) {
+ $this->user = $this->userManager->get($this->member->getUserId());
+ if ($this->user) {
+ $this->group->addUser($this->user);
+ }
+ }
+ }
+
+ $this->miscService->log('onCircleCreation: '. json_encode($this->circle), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onCircleDestruction(GenericEvent $event) {
+ $this->circle = $event->getArgument('circle');
+ $gid = $this->circle->getGroupId();
+ $this->group = $this->groupManager->get($gid);
+
+ if ($this->group) {
+ $this->group->delete();
+ }
+
+ $this->miscService->log('onCircleDestruction: '. json_encode($this->circle), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onMemberNew(GenericEvent $event) {
+ $this->circle = $event->getArgument('circle');
+ $this->member = $event->getArgument('member');
+
+ if ($this->member->getType() === Member::TYPE_USER) {
+ $gid = $this->circle->getGroupId();
+ $this->group = $this->groupManager->get($gid);
+ $this->user = $this->userManager->get($this->member->getUserId());
+
+ if ($this->group && $this->user) {
+ $this->group->addUser($this->user);
+ }
+ }
+
+ $this->miscService->log('onMemberNew: '. json_encode($this->circle).json_encode($this->member), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onMemberInvited(GenericEvent $event) {
+ $this->miscService->log('onMemberInvited: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onMemberRequesting(GenericEvent $event) {
+ $this->miscService->log('onMemberRequesting: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onMemberLeaving(GenericEvent $event) {
+ $this->circle = $event->getArgument('circle');
+ $this->member = $event->getArgument('member');
+
+ if ($this->member->getType() === Member::TYPE_USER) {
+ $gid = $this->circle->getGroupId();
+ $this->group = $this->groupManager->get($gid);
+ $this->user = $this->userManager->get($this->member->getUserId());
+
+ if ($this->group && $this->user) {
+ $this->group->removeUser($this->user);
+ }
+ }
+
+ $this->miscService->log('onMemberLeaving: '. json_encode($this->circle).json_encode($this->member), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onMemberLevel(GenericEvent $event) {
+ $this->miscService->log('onMemberLevel: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onMemberOwner(GenericEvent $event) {
+ $this->miscService->log('onMemberOwner: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onGroupLink(GenericEvent $event) {
+ $this->miscService->log('onGroupLink: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onGroupUnlink(GenericEvent $event) {
+ $this->miscService->log('onGroupUnlink: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onGroupLevel(GenericEvent $event) {
+ $this->miscService->log('onGroupLevel: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRequestSent(GenericEvent $event) {
+ $this->miscService->log('onLinkRequestSent: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRequestReceived(GenericEvent $event) {
+ $this->miscService->log('onLinkRequestReceived: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRequestRejected(GenericEvent $event) {
+ $this->miscService->log('onLinkRequestRejected: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRequestCanceled(GenericEvent $event) {
+ $this->miscService->log('onLinkRequestCanceled: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRequestAccepted(GenericEvent $event) {
+ $this->miscService->log('onLinkRequestAccepted: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRequestAccepting(GenericEvent $event) {
+ $this->miscService->log('onLinkRequestAccepting: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkUp(GenericEvent $event) {
+ $this->miscService->log('onLinkUp: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkDown(GenericEvent $event) {
+ $this->miscService->log('onLinkDown: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onLinkRemove(GenericEvent $event) {
+ $this->miscService->log('onLinkRemove: '. json_encode($event), 1);
+ }
+
+ /**
+ * @param GenericEvent $event
+ */
+ public function onSettingsChange(GenericEvent $event) {
+ $this->circle = $event->getArgument('circle');
+ $oldSettings = $event->getArgument('oldSettings');
+
+ $this->circle = $event->getArgument('circle');
+ $gid = $this->circle->getGroupId();
+ $this->group = $this->groupManager->get($gid);
+
+ $this->setCircleGroupName($this->getCircleGroupName());
+
+ $this->miscService->log('onSettingsChange: '. json_encode($this->circle).json_encode($oldSettings), 1);
+ }
+
+ /**
+ * When a group add a user, add it as a member of the associate Circle
+ *
+ * @param SymfonyGenericEvent $event
+ */
+ public function onGroupPostAddUser(SymfonyGenericEvent $event) {
+ $this->group = $event->getSubject();
+ $this->user = $event->getArgument('user');
+
+ $this->miscService->log('onGroupPostAddUser: '.json_encode($event).json_encode($this->group).json_encode($this->user), 1);
+ if ($this->group instanceof IGroup && $this->group->getGID()) {
+ $this->circle = $this->circlesRequest->forceGetCircleByGroupId($this->group->getGID());
+ if ($this->circle) {
+ $this->member = $this->membersRequest->getFreshNewMember(
+ $this->circle->getUniqueId(), $this->user->getUID(), Member::TYPE_USER
+ );
+ $this->member->addMemberToCircle();
+ $this->membersRequest->updateMember($this->member);
+ }
+ }
+ }
+
+ /**
+ * When a group remove a user, remove it as a member of the associate Circle
+ *
+ * @param SymfonyGenericEvent $event
+ */
+ public function onGroupPostRemoveUser(SymfonyGenericEvent $event) {
+ $this->group = $event->getSubject();
+ $this->user = $event->getArgument('user');
+
+ $this->miscService->log('onGroupPostRemoveUser: '.json_encode($event).json_encode($this->group).json_encode($this->user), 1);
+ if ($this->group instanceof IGroup && $this->group->getGID()) {
+ $this->circle = $this->circlesRequest->forceGetCircleByGroupId($this->group->getGID());
+ if ($this->circle) {
+ try {
+ $this->member = $this->membersRequest->forceGetMember(
+ $this->circle->getUniqueId(), $this->user->getUID(), Member::TYPE_USER
+ );
+ $this->member->hasToBeMember();
+ $this->member->cantBeOwner();
+ } catch (MemberDoesNotExistException $e) {
+ $this->member = null;
+ } catch (MemberIsOwnerException $e) {
+ $this->member = null;
+ }
+ if ($this->member) {
+ $this->membersRequest->removeMember($this->member);
+ }
+ }
+ }
+ }
+
+ /**
+ * When a group is removed, remove its associated Circle, if any
+ *
+ * @param SymfonyGenericEvent $event
+ */
+ public function onGroupPostDelete(SymfonyGenericEvent $event) {
+ $this->group = $event->getSubject();
+ $this->miscService->log('onGroupPostDelete: '.json_encode($event).json_encode($this->group), 1);
+ if ($this->group instanceof IGroup && $this->group->getGID()) {
+ $circle = $this->circlesRequest->forceGetCircleByGroupId($this->group->getGID());
+ if ($circle) {
+ $this->circlesRequest->destroyCircle($circle->getUniqueId());
+ }
+ }
+ }
+
+ /**
+ * @return string|null
+ */
+ protected function getCircleGroupName()
+ {
+ if ($this->circle instanceof Circle) {
+ return $this->configService->getGroupBackendNamePrefix().
+ $this->circle->getName().
+ $this->configService->getGroupBackendNameSuffix();
+ }
+
+ return;
+ }
+
+ /**
+ * @param string $displayName
+ * @return bool
+ */
+ protected function setCircleGroupName($displayName)
+ {
+ if ($this->group && method_exists($this->group, 'setDisplayName')) {
+ $this->miscService->log('setCircleGroupName: '. json_encode($displayName), 1);
+ return $this->group->setDisplayName($displayName);
+ }
+
+ return false;
+ }
+}
diff --git a/lib/Service/GroupsService.php b/lib/Service/GroupsService.php
index f0cbd7878..673241d68 100644
--- a/lib/Service/GroupsService.php
+++ b/lib/Service/GroupsService.php
@@ -54,6 +54,9 @@ class GroupsService {
/** @var IUserManager */
private $userManager;
+ /** @var ConfigService */
+ private $configService;
+
/** @var CirclesRequest */
private $circlesRequest;
@@ -76,6 +79,7 @@ class GroupsService {
* @param IL10N $l10n
* @param IGroupManager $groupManager
* @param IUserManager $userManager
+ * @param ConfigService $configService
* @param CirclesRequest $circlesRequest
* @param MembersRequest $membersRequest
* @param CirclesService $circlesService
@@ -84,7 +88,7 @@ class GroupsService {
*/
public function __construct(
$userId, IL10N $l10n, IGroupManager $groupManager, IUserManager $userManager,
- CirclesRequest $circlesRequest,
+ ConfigService $configService, CirclesRequest $circlesRequest,
MembersRequest $membersRequest, CirclesService $circlesService,
EventsService $eventsService, MiscService $miscService
) {
@@ -92,6 +96,7 @@ public function __construct(
$this->l10n = $l10n;
$this->groupManager = $groupManager;
$this->userManager = $userManager;
+ $this->configService = $configService;
$this->circlesRequest = $circlesRequest;
$this->membersRequest = $membersRequest;
$this->circlesService = $circlesService;
@@ -132,8 +137,13 @@ public function linkGroup($circleUniqueId, $groupId) {
$count++;
}
- if ($count > $circle->getSetting('members_limit')) {
- throw new \Exception('Group contains too many members');
+ $limit = (int) $circle->getSetting('members_limit');
+ if ($limit === 0) {
+ $limit = $this->configService->getAppValue(ConfigService::CIRCLES_MEMBERS_LIMIT);
+ }
+
+ if ($limit !== -1 && $count > $limit) {
+ throw new \Exception($this->l10n->t('Group contains too many members'));
}
$group = $this->getFreshNewMember($circleUniqueId, $groupId);
@@ -270,7 +280,7 @@ public function unlinkGroup($circleUniqueId, $groupId) {
$group->cantBeOwner();
$higherViewer->hasToBeHigherLevel($group->getLevel());
- $this->membersRequest->unlinkAllFromGroup($groupId);
+ $this->membersRequest->unlinkFromGroup($circleUniqueId, $groupId);
$this->eventsService->onGroupUnlink($circle, $group);
diff --git a/lib/Service/MembersService.php b/lib/Service/MembersService.php
index c025187e4..400aa3212 100644
--- a/lib/Service/MembersService.php
+++ b/lib/Service/MembersService.php
@@ -48,7 +48,9 @@
use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException;
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Member;
+use OCP\IGroup;
use OCP\IL10N;
+use OCP\IUser;
use OCP\IUserManager;
@@ -176,6 +178,7 @@ public function addMember($circleUniqueId, $ident, $type, bool $force = false) {
*/
private function addSingleMember(Circle $circle, $ident, $type) {
$this->verifyIdentBasedOnItsType($ident, $type);
+ $this->verifyIdentWithGroupBackend($circle, $ident, $type);
$member = $this->membersRequest->getFreshNewMember($circle->getUniqueId(), $ident, $type);
$member->hasToBeInviteAble();
@@ -284,6 +287,33 @@ private function addContact(Member $member) {
}
+ /**
+ * Verify the availability of an ident when Group Backend is enabled
+ *
+ * @param Circle $circle
+ * @param string $ident
+ * @param int $type
+ *
+ * @throws Exception
+ */
+ private function verifyIdentWithGroupBackend(Circle $circle, $ident, $type) {
+ if ($this->configService->isGroupsBackend() &&
+ in_array($type, [Member::TYPE_MAIL, Member::TYPE_CONTACT], true) &&
+ in_array($circle->getType(), [Circle::CIRCLES_CLOSED, Circle::CIRCLES_PUBLIC], true)
+ ) {
+ if ($type === Member::TYPE_MAIL) {
+ $errorMessage = 'You cannot add a mail address as member of your Circle';
+ }
+ if ($type === Member::TYPE_CONTACT) {
+ $errorMessage = 'You cannot add a contact as member of your Circle';
+ }
+ throw new EmailAccountInvalidFormatException(
+ $this->l10n->t($errorMessage)
+ );
+ }
+ }
+
+
/**
* Verify the availability of an ident, based on its type.
*
@@ -387,8 +417,18 @@ private function verifyIdentContact(&$ident, $type) {
*/
private function addGroupMembers(Circle $circle, $groupId) {
- $group = OC::$server->getGroupManager()
- ->get($groupId);
+ $groupManager = OC::$server->getGroupManager();
+ $group = $groupManager->get($groupId);
+
+ $user = OC::$server->getUserSession()->getUser();
+
+ if (!$this->configService->isAddingAnyGroupMembersAllowed() &&
+ $group instanceof IGroup && $user instanceof IUser &&
+ !$group->inGroup($user) && !$groupManager->isAdmin($user->getUID())
+ ) {
+ $group = null;
+ }
+
if ($group === null) {
throw new GroupDoesNotExistException($this->l10n->t('This group does not exist'));
}
@@ -656,4 +696,3 @@ public function onUserRemoved($userId) {
}
-
diff --git a/templates/navigate.php b/templates/navigate.php
index 84aac63d8..43031a079 100644
--- a/templates/navigate.php
+++ b/templates/navigate.php
@@ -359,12 +359,12 @@