Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/circles.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorMaxence Lange <maxence@artificial-owl.com>2020-04-10 09:47:25 +0300
committerMaxence Lange <maxence@artificial-owl.com>2020-04-14 13:59:38 +0300
commitf4ef2b19e65a2e7769477d967fcc603134983fea (patch)
tree9921f184dd1e18d59097defb6395b7bd7563336d /lib
parent1d753124975adff0262ae297f8710dae7fc64550 (diff)
gs+circles
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Api/Sharees.php2
-rw-r--r--lib/AppInfo/Application.php35
-rw-r--r--lib/Circles/FileSharingBroadcaster.php5
-rw-r--r--lib/Collaboration/v1/CollaboratorSearchPlugin.php2
-rw-r--r--lib/Command/CirclesList.php14
-rw-r--r--lib/Command/CirclesSync.php93
-rw-r--r--lib/Command/Clean.php31
-rw-r--r--lib/Command/MembersCreate.php92
-rw-r--r--lib/Command/MembersLevel.php5
-rw-r--r--lib/Command/MembersList.php3
-rw-r--r--lib/Command/MembersRemove.php2
-rw-r--r--lib/Controller/BaseController.php17
-rw-r--r--lib/Controller/CirclesController.php2
-rw-r--r--lib/Controller/GlobalScaleController.php159
-rw-r--r--lib/Controller/MembersController.php16
-rw-r--r--lib/Cron/GlobalSync.php74
-rw-r--r--lib/Db/CircleProviderRequestBuilder.php1
-rw-r--r--lib/Db/CirclesRequest.php68
-rw-r--r--lib/Db/CirclesRequestBuilder.php14
-rw-r--r--lib/Db/CoreRequestBuilder.php79
-rw-r--r--lib/Db/GSEventsRequest.php100
-rw-r--r--lib/Db/GSEventsRequestBuilder.php115
-rw-r--r--lib/Db/GSSharesRequest.php225
-rw-r--r--lib/Db/GSSharesRequestBuilder.php183
-rw-r--r--lib/Db/MembersRequest.php53
-rw-r--r--lib/Db/MembersRequestBuilder.php18
-rw-r--r--lib/Exceptions/GSKeyException.php34
-rw-r--r--lib/Exceptions/GSStatusException.php34
-rw-r--r--lib/Exceptions/GlobalScaleDSyncException.php32
-rw-r--r--lib/Exceptions/GlobalScaleEventException.php32
-rw-r--r--lib/Exceptions/JsonException.php34
-rw-r--r--lib/Exceptions/ModelException.php34
-rw-r--r--lib/GlobalScale/AGlobalScaleEvent.php265
-rw-r--r--lib/GlobalScale/CircleCreate.php88
-rw-r--r--lib/GlobalScale/CircleDestroy.php82
-rw-r--r--lib/GlobalScale/CircleStatus.php96
-rw-r--r--lib/GlobalScale/CircleUpdate.php111
-rw-r--r--lib/GlobalScale/FileShare.php281
-rw-r--r--lib/GlobalScale/GSMount/Mount.php111
-rw-r--r--lib/GlobalScale/GSMount/MountManager.php118
-rw-r--r--lib/GlobalScale/GSMount/MountProvider.php131
-rw-r--r--lib/GlobalScale/GlobalSync.php173
-rw-r--r--lib/GlobalScale/MemberAdd.php137
-rw-r--r--lib/GlobalScale/MemberJoin.php116
-rw-r--r--lib/GlobalScale/MemberLeave.php94
-rw-r--r--lib/GlobalScale/MemberLevel.php182
-rw-r--r--lib/GlobalScale/MemberRemove.php110
-rw-r--r--lib/Migration/Version0017Date20191210153032.php198
-rw-r--r--lib/Model/BaseCircle.php12
-rw-r--r--lib/Model/BaseMember.php20
-rw-r--r--lib/Model/Circle.php28
-rw-r--r--lib/Model/GlobalScale/GSEvent.php428
-rw-r--r--lib/Model/GlobalScale/GSShare.php322
-rw-r--r--lib/Model/GlobalScale/GSShareMountpoint.php155
-rw-r--r--lib/Model/GlobalScale/GSWrapper.php242
-rw-r--r--lib/Model/Member.php1
-rw-r--r--lib/Model/SearchResult.php42
-rw-r--r--lib/Model/SharingFrame.php6
-rw-r--r--lib/Search/Contacts.php2
-rw-r--r--lib/Search/GlobalScaleUsers.php124
-rw-r--r--lib/Search/LocalUsers.php2
-rw-r--r--lib/Service/BroadcastService.php40
-rw-r--r--lib/Service/CirclesService.php134
-rw-r--r--lib/Service/ConfigService.php73
-rw-r--r--lib/Service/DavService.php2
-rw-r--r--lib/Service/GSDownstreamService.php164
-rw-r--r--lib/Service/GSUpstreamService.php534
-rw-r--r--lib/Service/GlobalScaleService.php226
-rw-r--r--lib/Service/MembersService.php212
-rw-r--r--lib/Service/SearchService.php4
-rw-r--r--lib/Service/ShareService.php4
-rw-r--r--lib/ShareByCircleProvider.php49
72 files changed, 6366 insertions, 361 deletions
diff --git a/lib/Api/Sharees.php b/lib/Api/Sharees.php
index 2755f93c..06856ea6 100644
--- a/lib/Api/Sharees.php
+++ b/lib/Api/Sharees.php
@@ -111,4 +111,4 @@ class Sharees {
}
-} \ No newline at end of file
+}
diff --git a/lib/AppInfo/Application.php b/lib/AppInfo/Application.php
index 1b3c247d..fd3df98b 100644
--- a/lib/AppInfo/Application.php
+++ b/lib/AppInfo/Application.php
@@ -31,6 +31,8 @@ namespace OCA\Circles\AppInfo;
use OC;
use OCA\Circles\Api\v1\Circles;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\GlobalScale\GSMount\MountProvider;
use OCA\Circles\Notification\Notifier;
use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\DavService;
@@ -53,11 +55,18 @@ class Application extends App {
const CLIENT_TIMEOUT = 3;
+
+ /** @var ConfigService */
+ private $configService;
+
/** @var IAppContainer */
private $container;
/**
* @param array $params
+ *
+ * @throws GSStatusException
+ * @throws QueryException
*/
public function __construct(array $params = array()) {
parent::__construct(self::APP_NAME, $params);
@@ -67,12 +76,29 @@ class Application extends App {
$manager = OC::$server->getNotificationManager();
$manager->registerNotifierService(Notifier::class);
+ $this->configService = OC::$server->query(ConfigService::class);
+
+ $this->registerMountProvider();
$this->registerHooks();
$this->registerDavHooks();
}
/**
+ * @throws GSStatusException
+ * @throws QueryException
+ */
+ public function registerMountProvider() {
+ if (!$this->configService->getGSStatus(ConfigService::GS_ENABLED)) {
+ return;
+ }
+
+ $mountProviderCollection = \OC::$server->getMountProviderCollection();
+ $mountProviderCollection->registerProvider($this->container->query(MountProvider::class));
+ }
+
+
+ /**
* Register Hooks
*/
public function registerHooks() {
@@ -89,14 +115,7 @@ class Application extends App {
* Register Navigation elements
*/
public function registerNavigation() {
- /** @var ConfigService $configService */
- try {
- $configService = OC::$server->query(ConfigService::class);
- } catch (QueryException $e) {
- return;
- }
-
- if (!$configService->stillFrontEnd()) {
+ if (!$this->configService->stillFrontEnd()) {
return;
}
diff --git a/lib/Circles/FileSharingBroadcaster.php b/lib/Circles/FileSharingBroadcaster.php
index f6028991..ed52f207 100644
--- a/lib/Circles/FileSharingBroadcaster.php
+++ b/lib/Circles/FileSharingBroadcaster.php
@@ -33,7 +33,6 @@ use OC\Share20\Share;
use OCA\Circles\AppInfo\Application;
use OCA\Circles\Db\SharesRequest;
use OCA\Circles\Db\TokensRequest;
-use OCA\Circles\Exceptions\TokenDoesNotExistException;
use OCA\Circles\IBroadcaster;
use OCA\Circles\Model\Circle;
use OCA\Circles\Model\Member;
@@ -192,6 +191,7 @@ class FileSharingBroadcaster implements IBroadcaster {
/**
* {@inheritdoc}
* @throws IllegalIDChangeException
+ * @throws Exception
*/
public function createShareToMember(SharingFrame $frame, Member $member) {
if (!$frame->is0Circle()) {
@@ -205,9 +205,8 @@ class FileSharingBroadcaster implements IBroadcaster {
$share = $this->generateShare($payload['share']);
if ($member->getType() === Member::TYPE_MAIL || $member->getType() === Member::TYPE_CONTACT) {
+ $circle = $frame->getCircle();
try {
- $circle = $frame->getCircle();
-
// federated shared in contact
$clouds = $this->getCloudsFromContact($member->getUserId());
if ($this->federatedEnabled && !empty($clouds)) {
diff --git a/lib/Collaboration/v1/CollaboratorSearchPlugin.php b/lib/Collaboration/v1/CollaboratorSearchPlugin.php
index 0195266e..703eee62 100644
--- a/lib/Collaboration/v1/CollaboratorSearchPlugin.php
+++ b/lib/Collaboration/v1/CollaboratorSearchPlugin.php
@@ -79,4 +79,4 @@ class CollaboratorSearchPlugin implements ISearchPlugin {
],
];
}
-} \ No newline at end of file
+}
diff --git a/lib/Command/CirclesList.php b/lib/Command/CirclesList.php
index 029bb4bf..506e7f0e 100644
--- a/lib/Command/CirclesList.php
+++ b/lib/Command/CirclesList.php
@@ -29,6 +29,7 @@
namespace OCA\Circles\Command;
+use daita\MySmallPhpTools\Traits\TArrayTools;
use OC\Core\Command\Base;
use OCA\Circles\Db\CirclesRequest;
use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
@@ -50,6 +51,9 @@ use Symfony\Component\Console\Output\OutputInterface;
class CirclesList extends Base {
+ use TArrayTools;
+
+
/** @var IL10N */
private $l10n;
@@ -103,19 +107,23 @@ class CirclesList extends Base {
}
$table = new Table($output);
- $table->setHeaders(['ID', 'Name', 'Type', 'Owner']);
+ $table->setHeaders(['ID', 'Name', 'Type', 'Owner', 'Instance', 'Limit', 'Description']);
$table->render();
$output->writeln('');
$c = 0;
foreach ($circles as $circle) {
+ $owner = $circle->getOwner();
+ $settings = $circle->getSettings();
$table->appendRow(
[
$circle->getUniqueId(),
$circle->getName(),
$circle->getTypeLongString(),
- $circle->getOwner()
- ->getUserId()
+ $owner->getUserId(),
+ $owner->getInstance(),
+ $this->getInt('members_limit', $settings, -1),
+ substr($circle->getDescription(), 0, 30)
]
);
}
diff --git a/lib/Command/CirclesSync.php b/lib/Command/CirclesSync.php
new file mode 100644
index 00000000..cf5a23f0
--- /dev/null
+++ b/lib/Command/CirclesSync.php
@@ -0,0 +1,93 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Command;
+
+use OC\Core\Command\Base;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\Service\GSUpstreamService;
+use OCP\IL10N;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Output\OutputInterface;
+
+
+/**
+ * Class CirclesSync
+ *
+ * @package OCA\Circles\Command
+ */
+class CirclesSync extends Base {
+
+
+ /** @var IL10N */
+ private $l10n;
+
+ /** @var GSUpstreamService */
+ private $gsUpstreamService;
+
+
+ /**
+ * CirclesSync constructor.
+ *
+ * @param IL10N $l10n
+ * @param GSUpstreamService $gsUpstreamService
+ */
+ public function __construct(IL10N $l10n, GSUpstreamService $gsUpstreamService) {
+ parent::__construct();
+ $this->l10n = $l10n;
+ $this->gsUpstreamService = $gsUpstreamService;
+ }
+
+
+ /**
+ *
+ */
+ protected function configure() {
+ parent::configure();
+ $this->setName('circles:manage:sync')
+ ->setDescription('sync circles in GlobalScale env');
+ }
+
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ *
+ * @return int
+ * @throws GSStatusException
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+ $this->gsUpstreamService->synchronize();
+
+ return 0;
+ }
+
+}
+
diff --git a/lib/Command/Clean.php b/lib/Command/Clean.php
index 2f55faab..af8fc663 100644
--- a/lib/Command/Clean.php
+++ b/lib/Command/Clean.php
@@ -34,6 +34,7 @@ use OCA\Circles\Db\MembersRequest;
use OCA\Circles\Exceptions\CircleDoesNotExistException;
use OCP\IDBConnection;
use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
@@ -69,20 +70,32 @@ class Clean extends Base {
protected function configure() {
parent::configure();
$this->setName('circles:clean')
- ->setDescription('remove all extra data from database');
+ ->setDescription('remove all extra data from database')
+ ->addOption('all', '', InputOption::VALUE_NONE, 'remove all data from the app');
}
- protected function execute(InputInterface $input, OutputInterface $output) {
- try {
- $this->fixUserType();
- $this->removeCirclesWithNoOwner();
- $this->removeMembersWithNoCircles();
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ *
+ * @return int
+ */
+ protected function execute(InputInterface $input, OutputInterface $output): int {
+
+ if ($input->getOption('all')) {
+ $this->circlesRequest->cleanDatabase();
- $output->writeln('done');
- } catch (Exception $e) {
- $output->writeln($e->getMessage());
+ return 0;
}
+
+ $this->fixUserType();
+ $this->removeCirclesWithNoOwner();
+ $this->removeMembersWithNoCircles();
+
+ $output->writeln('done');
+
+ return 0;
}
diff --git a/lib/Command/MembersCreate.php b/lib/Command/MembersCreate.php
index 0edaf78a..7f4e0cc1 100644
--- a/lib/Command/MembersCreate.php
+++ b/lib/Command/MembersCreate.php
@@ -29,11 +29,20 @@
namespace OCA\Circles\Command;
+use daita\MySmallPhpTools\Exceptions\RequestContentException;
+use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
+use daita\MySmallPhpTools\Exceptions\RequestResultNotJsonException;
+use daita\MySmallPhpTools\Exceptions\RequestResultSizeException;
+use daita\MySmallPhpTools\Exceptions\RequestServerException;
+use daita\MySmallPhpTools\Model\Request;
+use daita\MySmallPhpTools\Traits\TRequest;
use Exception;
use OC\Core\Command\Base;
use OC\User\NoUserException;
use OCA\Circles\Db\MembersRequest;
+use OCA\Circles\Exceptions\GSStatusException;
use OCA\Circles\Model\Member;
+use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\MembersService;
use OCP\IL10N;
use OCP\IUserManager;
@@ -50,6 +59,9 @@ use Symfony\Component\Console\Output\OutputInterface;
class MembersCreate extends Base {
+ use TRequest;
+
+
/** @var IL10N */
private $l10n;
@@ -62,6 +74,9 @@ class MembersCreate extends Base {
/** @var MembersRequest */
private $membersRequest;
+ /** @var ConfigService */
+ private $configService;
+
/**
* MembersCreate constructor.
@@ -70,15 +85,18 @@ class MembersCreate extends Base {
* @param IUserManager $userManager
* @param MembersService $membersService
* @param MembersRequest $membersRequest
+ * @param ConfigService $configService
*/
public function __construct(
- IL10N $l10n, IUserManager $userManager, MembersService $membersService, MembersRequest $membersRequest
+ IL10N $l10n, IUserManager $userManager, MembersService $membersService,
+ MembersRequest $membersRequest, ConfigService $configService
) {
parent::__construct();
$this->l10n = $l10n;
$this->userManager = $userManager;
$this->membersService = $membersService;
$this->membersRequest = $membersRequest;
+ $this->configService = $configService;
}
@@ -105,11 +123,17 @@ class MembersCreate extends Base {
$userId = $input->getArgument('user');
$level = $input->getArgument('level');
+ $instance = '';
$user = $this->userManager->get($userId);
if ($user === null) {
+ $userId = $this->findUserFromLookup($userId, $instance);
+ } else {
+ $userId = $user->getUID();
+ }
+
+ if ($userId === '') {
throw new NoUserException('user does not exist');
}
- $userId = $user->getUID();
$levels = [
'member' => Member::LEVEL_MEMBER,
@@ -124,14 +148,72 @@ class MembersCreate extends Base {
$level = $levels[strtolower($level)];
- $this->membersService->addMember($circleId, $userId, Member::TYPE_USER, true);
- $this->membersService->levelMember($circleId, $userId, Member::TYPE_USER, $level, true);
+ $this->membersService->addMember($circleId, $userId, Member::TYPE_USER, $instance, true);
+ $this->membersService->levelMember($circleId, $userId, Member::TYPE_USER, $instance, $level, true);
- $member = $this->membersRequest->forceGetMember($circleId, $userId, Member::TYPE_USER);
+ $member = $this->membersRequest->forceGetMember($circleId, $userId, Member::TYPE_USER, $instance);
echo json_encode($member, JSON_PRETTY_PRINT) . "\n";
return 0;
}
+
+ /**
+ * @param string $search
+ * @param string $instance
+ *
+ * @return string
+ */
+ private function findUserFromLookup(string $search, string &$instance = ''): string {
+ $userId = '';
+
+ /** @var string $lookup */
+ try {
+ $lookup = $this->configService->getGSStatus(ConfigService::GS_LOOKUP);
+ } catch (GSStatusException $e) {
+ return '';
+ }
+
+ $request = new Request('/users', Request::TYPE_GET);
+ $request->setProtocols(['https', 'http']);
+ $request->addData('search', $search);
+ $request->setAddressFromUrl($lookup);
+
+ try {
+ $users = $this->retrieveJson($request);
+ } catch (
+ RequestContentException |
+ RequestNetworkException |
+ RequestResultSizeException |
+ RequestServerException |
+ RequestResultNotJsonException $e
+ ) {
+ return '';
+ }
+
+ $result = [];
+ foreach ($users as $user) {
+ if (!array_key_exists('userid', $user)) {
+ continue;
+ }
+
+ list(, $host) = explode('@', $user['federationId']);
+ if (strtolower($user['userid']['value']) === strtolower($search)) {
+ $userId = $user['userid']['value'];
+ $instance = $host;
+ }
+
+ $result[] = $user['userid']['value'] . ' <info>@' . $host . '</info>';
+ }
+
+// if ($userId === '') {
+// foreach($result as $item) {
+// $output->writeln($item);
+// }
+// }
+
+ return $userId;
+ }
+
}
diff --git a/lib/Command/MembersLevel.php b/lib/Command/MembersLevel.php
index 6d2b2e2b..f0eab421 100644
--- a/lib/Command/MembersLevel.php
+++ b/lib/Command/MembersLevel.php
@@ -118,11 +118,12 @@ class MembersLevel extends Base {
$member = $this->membersService->getMemberById($memberId);
$this->membersService->levelMember(
- $member->getCircleId(), $member->getUserId(), Member::TYPE_USER, $level, true
+ $member->getCircleId(), $member->getUserId(), Member::TYPE_USER, $member->getInstance(), $level,
+ true
);
$member = $this->membersRequest->forceGetMember(
- $member->getCircleId(), $member->getUserId(), Member::TYPE_USER
+ $member->getCircleId(), $member->getUserId(), Member::TYPE_USER, $member->getInstance()
);
echo json_encode($member, JSON_PRETTY_PRINT) . "\n";
diff --git a/lib/Command/MembersList.php b/lib/Command/MembersList.php
index ce956ad4..2c5c8536 100644
--- a/lib/Command/MembersList.php
+++ b/lib/Command/MembersList.php
@@ -109,7 +109,7 @@ class MembersList extends Base {
$output = $output->section();
$table = new Table($output);
- $table->setHeaders(['ID', 'Name', 'Level']);
+ $table->setHeaders(['ID', 'Username', 'Instance', 'Level']);
$table->render();
$output->writeln('');
@@ -119,6 +119,7 @@ class MembersList extends Base {
[
$member->getMemberId(),
$member->getUserId(),
+ $member->getInstance(),
$member->getLevelString(),
]
);
diff --git a/lib/Command/MembersRemove.php b/lib/Command/MembersRemove.php
index 990bb4a1..9cf97944 100644
--- a/lib/Command/MembersRemove.php
+++ b/lib/Command/MembersRemove.php
@@ -87,7 +87,7 @@ class MembersRemove extends Base {
$memberId = $input->getArgument('member_id');
$member = $this->membersService->getMemberById($memberId);
- $this->membersService->removeMember($member->getCircleId(), $member->getUserId(), $member->getType(), true);
+ $this->membersService->removeMember($member->getCircleId(), $member->getUserId(), $member->getType(), $member->getInstance(), true);
return 0;
}
diff --git a/lib/Controller/BaseController.php b/lib/Controller/BaseController.php
index 35630feb..58ef1b0c 100644
--- a/lib/Controller/BaseController.php
+++ b/lib/Controller/BaseController.php
@@ -33,8 +33,9 @@ use OCA\Circles\Service\CirclesService;
use OCA\Circles\Service\ConfigService;
use OCA\Circles\Service\FederatedLinkService;
use OCA\Circles\Service\GroupsService;
+use OCA\Circles\Service\GSDownstreamService;
+use OCA\Circles\Service\GSUpstreamService;
use OCA\Circles\Service\MembersService;
-
use OCA\Circles\Service\MiscService;
use OCA\Circles\Service\SearchService;
use OCA\Circles\Service\SharingFrameService;
@@ -63,6 +64,12 @@ class BaseController extends Controller {
/** @var MembersService */
protected $membersService;
+ /** @var GSUpstreamService */
+ protected $gsUpstreamService;
+
+ /** @var GSDownstreamService */
+ protected $gsDownstreamService;
+
/** @var GroupsService */
protected $groupsService;
@@ -90,6 +97,7 @@ class BaseController extends Controller {
* @param CirclesService $circlesService
* @param SearchService $searchService
* @param MembersService $membersService
+ * @param GSUpstreamService $gsUpstreamService
* @param GroupsService $groupsService
* @param SharingFrameService $sharingFrameService
* @param BroadcastService $broadcastService
@@ -105,6 +113,8 @@ class BaseController extends Controller {
CirclesService $circlesService,
SearchService $searchService,
MembersService $membersService,
+ GSUpstreamService $gsUpstreamService,
+ GSDownstreamService $gsDownstreamService,
GroupsService $groupsService,
SharingFrameService $sharingFrameService,
BroadcastService $broadcastService,
@@ -113,12 +123,15 @@ class BaseController extends Controller {
) {
parent::__construct($appName, $request);
+
$this->userId = $userId;
$this->l10n = $l10n;
$this->configService = $configService;
$this->circlesService = $circlesService;
$this->searchService = $searchService;
$this->membersService = $membersService;
+ $this->gsUpstreamService = $gsUpstreamService;
+ $this->gsDownstreamService = $gsDownstreamService;
$this->groupsService = $groupsService;
$this->sharingFrameService = $sharingFrameService;
$this->broadcastService = $broadcastService;
@@ -166,5 +179,3 @@ class BaseController extends Controller {
}
}
-
-
diff --git a/lib/Controller/CirclesController.php b/lib/Controller/CirclesController.php
index 256da074..45dbac3e 100644
--- a/lib/Controller/CirclesController.php
+++ b/lib/Controller/CirclesController.php
@@ -30,7 +30,6 @@ use Exception;
use OCA\Circles\Exceptions\CircleNameFirstCharException;
use OCA\Circles\Exceptions\CircleNameTooShortException;
use OCA\Circles\Exceptions\CircleTypeDisabledException;
-use OCA\Circles\Exceptions\FederatedCircleNotAllowedException;
use OCP\AppFramework\Http\DataResponse;
class CirclesController extends BaseController {
@@ -148,7 +147,6 @@ class CirclesController extends BaseController {
return $this->success(['circle_id' => $uniqueId, 'member' => $data]);
} catch (Exception $e) {
-
return $this->fail(['circle_id' => $uniqueId, 'error' => $e->getMessage()]);
}
}
diff --git a/lib/Controller/GlobalScaleController.php b/lib/Controller/GlobalScaleController.php
new file mode 100644
index 00000000..bfc32be4
--- /dev/null
+++ b/lib/Controller/GlobalScaleController.php
@@ -0,0 +1,159 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Controller;
+
+
+use daita\MySmallPhpTools\Traits\TAsync;
+use daita\MySmallPhpTools\Traits\TStringTools;
+use Exception;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCP\AppFramework\Http\DataResponse;
+
+
+/**
+ * Class GlobalScaleController
+ *
+ * @package OCA\Circles\Controller
+ */
+class GlobalScaleController extends BaseController {
+
+
+ use TStringTools;
+ use TAsync;
+
+
+ /**
+ * Event is generated by any instance of GS and sent to the instance that owns the Circles, that
+ * will broadcast the event to other if ok
+ *
+ * @PublicPage
+ * @NoCSRFRequired
+ *
+ * @return DataResponse
+ */
+ public function event(): DataResponse {
+ $data = file_get_contents('php://input');
+
+ try {
+ $event = new GSEvent();
+ $event->importFromJson($data);
+ $this->gsDownstreamService->requestedEvent($event);
+
+ return $this->success(['success' => $event]);
+ } catch (Exception $e) {
+ return $this->fail(['data' => $data, 'error' => $e->getMessage()]);
+ }
+ }
+
+
+ /**
+ * Async process and broadcast the event to every instances of GS
+ * This should be initiated by the instance that owns the Circles.
+ *
+ * @PublicPage
+ * @NoCSRFRequired
+ *
+ * @param string $token
+ *
+ * @throws Exception
+ */
+ public function asyncBroadcast(string $token) {
+ try {
+ $wrappers = $this->gsUpstreamService->getEventsByToken($token);
+ } catch (Exception $e) {
+ $this->miscService->log(
+ 'exception during async: ' . ['token' => $token, 'error' => $e->getMessage()]
+ );
+ $this->fail(['token' => $token, 'error' => $e->getMessage()]);
+ }
+
+ $this->async();
+ foreach ($wrappers as $wrapper) {
+ try {
+ $this->gsUpstreamService->broadcastWrapper($wrapper, $this->request->getServerProtocol());
+ } catch (GSStatusException $e) {
+ }
+ }
+
+ $this->gsUpstreamService->manageResults($token);
+
+ exit();
+ }
+
+
+ /**
+ * Event is sent by instance that owns the Circles.
+ *
+ * @PublicPage
+ * @NoCSRFRequired
+ *
+ * @return DataResponse
+ */
+ public function broadcast(): DataResponse {
+ $data = file_get_contents('php://input');
+
+ try {
+ $event = new GSEvent();
+ $event->importFromJson($data);
+
+ $this->gsDownstreamService->onNewEvent($event);
+
+ return $this->success(['result' => $event->getResult()]);
+ } catch (Exception $e) {
+ return $this->fail(['data' => $data, 'error' => $e->getMessage()]);
+ }
+ }
+
+
+ /**
+ * Status Event. This is an event to check status of items between instances.
+ *
+ * @PublicPage
+ * @NoCSRFRequired
+ *
+ * @return DataResponse
+ */
+ public function status(): DataResponse {
+ $data = file_get_contents('php://input');
+
+ try {
+ $event = new GSEvent();
+ $event->importFromJson($data);
+ $this->gsDownstreamService->statusEvent($event);
+
+ return $this->success(['success' => $event]);
+ } catch (Exception $e) {
+ return $this->fail(['data' => $data, 'error' => $e->getMessage()]);
+ }
+ }
+
+}
+
diff --git a/lib/Controller/MembersController.php b/lib/Controller/MembersController.php
index 6fc212cf..ac21b16e 100644
--- a/lib/Controller/MembersController.php
+++ b/lib/Controller/MembersController.php
@@ -40,15 +40,16 @@ class MembersController extends BaseController {
* @param string $uniqueId
* @param $ident
* @param $type
+ * @param string $instance
*
* @return DataResponse
*/
- public function addMember($uniqueId, $ident, $type) {
+ public function addMember($uniqueId, $ident, $type, $instance) {
try {
$this->mustHaveFrontEndEnabled();
- $data = $this->membersService->addMember($uniqueId, $ident, (int)$type);
+ $data = $this->membersService->addMember($uniqueId, $ident, (int)$type, $instance);
} catch (\Exception $e) {
return $this->fail(
[
@@ -114,22 +115,24 @@ class MembersController extends BaseController {
* @param string $uniqueId
* @param string $member
* @param int $type
+ * @param string $instance
* @param int $level
*
* @return DataResponse
*/
- public function levelMember($uniqueId, $member, $type, $level) {
+ public function levelMember($uniqueId, $member, $type, $instance, $level) {
try {
$this->mustHaveFrontEndEnabled();
- $data = $this->membersService->levelMember($uniqueId, $member, (int)$type, $level);
+ $data = $this->membersService->levelMember($uniqueId, $member, (int)$type, $instance, $level);
} catch (\Exception $e) {
return
$this->fail(
[
'circle_id' => $uniqueId,
'user_id' => $member,
+ 'instance' => $instance,
'user_type' => (int)$type,
'display' => MiscService::getDisplay($member, (int)$type),
'level' => $level,
@@ -158,15 +161,16 @@ class MembersController extends BaseController {
* @param string $uniqueId
* @param string $member
* @param int $type
+ * @param $instance
*
* @return DataResponse
*/
- public function removeMember($uniqueId, $member, $type) {
+ public function removeMember($uniqueId, $member, $type, $instance) {
try {
$this->mustHaveFrontEndEnabled();
- $data = $this->membersService->removeMember($uniqueId, $member, (int)$type);
+ $data = $this->membersService->removeMember($uniqueId, $member, (int)$type, $instance);
} catch (\Exception $e) {
return
$this->fail(
diff --git a/lib/Cron/GlobalSync.php b/lib/Cron/GlobalSync.php
new file mode 100644
index 00000000..ef25f420
--- /dev/null
+++ b/lib/Cron/GlobalSync.php
@@ -0,0 +1,74 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Cron;
+
+
+use OC\BackgroundJob\TimedJob;
+use OCA\Circles\AppInfo\Application;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\Service\GSUpstreamService;
+use OCP\AppFramework\QueryException;
+
+
+/**
+ * Class GlobalSync
+ *
+ * @package OCA\Cicles\Cron
+ */
+class GlobalSync extends TimedJob {
+
+
+ /**
+ * Cache constructor.
+ */
+ public function __construct() {
+ $this->setInterval(10);
+ }
+
+
+ /**
+ * @param $argument
+ *
+ * @throws QueryException
+ */
+ protected function run($argument) {
+ $app = new Application();
+ $c = $app->getContainer();
+
+ /** @var GSUpstreamService $gsUpstreamService */
+ $gsUpstreamService = $c->query(GSUpstreamService::class);
+ try {
+ $gsUpstreamService->synchronize();
+ } catch (GSStatusException $e) {
+ }
+ }
+
+}
+
diff --git a/lib/Db/CircleProviderRequestBuilder.php b/lib/Db/CircleProviderRequestBuilder.php
index 1a8e0d90..b65c30e3 100644
--- a/lib/Db/CircleProviderRequestBuilder.php
+++ b/lib/Db/CircleProviderRequestBuilder.php
@@ -308,6 +308,7 @@ class CircleProviderRequestBuilder extends CoreRequestBuilder {
$andX->add($expr->eq('mcm.user_id', $qb->createNamedParameter($userId)));
$andX->add($expr->gt('mcm.level', $qb->createNamedParameter(0)));
+ $andX->add($expr->eq('mcm.instance', $qb->createNamedParameter('')));
$andX->add($expr->eq('mcm.user_type', $qb->createNamedParameter(Member::TYPE_USER)));
$subQb->andWhere($andX);
diff --git a/lib/Db/CirclesRequest.php b/lib/Db/CirclesRequest.php
index aca9d7fe..d97b17c9 100644
--- a/lib/Db/CirclesRequest.php
+++ b/lib/Db/CirclesRequest.php
@@ -1,4 +1,6 @@
-<?php
+<?php declare(strict_types=1);
+
+
/**
* Circles - Bring cloud-users closer together.
*
@@ -64,9 +66,7 @@ class CirclesRequest extends CirclesRequestBuilder {
throw new CircleDoesNotExistException($this->l10n->t('Circle not found'));
}
- $entry = $this->parseCirclesSelectSql($data);
-
- return $entry;
+ return $this->parseCirclesSelectSql($data);
}
@@ -132,6 +132,7 @@ class CirclesRequest extends CirclesRequestBuilder {
/**
* @param string $userId
+ * @param string $instanceId
* @param int $type
* @param string $name
* @param int $level
@@ -141,13 +142,16 @@ class CirclesRequest extends CirclesRequestBuilder {
* @return Circle[]
* @throws ConfigNoCircleAvailableException
*/
- public function getCircles($userId, $type = 0, $name = '', $level = 0, $forceAll = false, string $ownerId = '') {
+ public function getCircles(
+ string $userId, int $type = 0, string $name = '', int $level = 0, bool $forceAll = false,
+ string $ownerId = ''
+ ) {
if ($type === 0) {
$type = Circle::CIRCLES_ALL;
}
$qb = $this->getCirclesSelectSql();
- $this->leftJoinUserIdAsViewer($qb, $userId);
+ $this->leftJoinUserIdAsViewer($qb, $userId, '');
$this->leftJoinOwner($qb, $ownerId);
$this->leftJoinNCGroupAndUser($qb, $userId, '`c`.`unique_id`');
@@ -173,20 +177,25 @@ class CirclesRequest extends CirclesRequestBuilder {
*
* @param string $circleUniqueId
* @param string $viewerId
+ * @param string $instanceId
* @param bool $forceAll
*
* @return Circle
* @throws CircleDoesNotExistException
* @throws ConfigNoCircleAvailableException
*/
- public function getCircle($circleUniqueId, $viewerId, $forceAll = false) {
+ public function getCircle(
+ string $circleUniqueId, string $viewerId, string $instanceId = '', bool $forceAll = false
+ ) {
$qb = $this->getCirclesSelectSql();
$this->limitToShortenUniqueId($qb, $circleUniqueId, Circle::SHORT_UNIQUE_ID_LENGTH);
- $this->leftJoinUserIdAsViewer($qb, $viewerId);
+ $this->leftJoinUserIdAsViewer($qb, $viewerId, $instanceId);
$this->leftJoinOwner($qb);
- $this->leftJoinNCGroupAndUser($qb, $viewerId, '`c`.`unique_id`');
+ if ($instanceId === '') {
+ $this->leftJoinNCGroupAndUser($qb, $viewerId, '`c`.`unique_id`');
+ }
$this->limitRegardingCircleType($qb, $viewerId, $circleUniqueId, Circle::CIRCLES_ALL, '', $forceAll);
@@ -199,9 +208,11 @@ class CirclesRequest extends CirclesRequestBuilder {
}
$circle = $this->parseCirclesSelectSql($data);
- $circle->setGroupViewer(
- $this->membersRequest->forceGetHigherLevelGroupFromUser($circleUniqueId, $viewerId)
- );
+ if ($instanceId === '') {
+ $circle->setGroupViewer(
+ $this->membersRequest->forceGetHigherLevelGroupFromUser($circleUniqueId, $viewerId)
+ );
+ }
return $circle;
}
@@ -214,19 +225,8 @@ class CirclesRequest extends CirclesRequestBuilder {
* Will returns the circle
*
* @param Circle $circle
- * @param $userId
- *
- * @throws CircleAlreadyExistsException
*/
- public function createCircle(Circle &$circle, $userId) {
-
- if (!$this->isCircleUnique($circle, $userId)) {
- throw new CircleAlreadyExistsException(
- $this->l10n->t('A circle with that name exists')
- );
- }
-
- $circle->generateUniqueId();
+ public function createCircle(Circle $circle) {
$qb = $this->getCirclesInsertSql();
$qb->setValue('unique_id', $qb->createNamedParameter($circle->getUniqueId(true)))
->setValue('name', $qb->createNamedParameter($circle->getName()))
@@ -236,13 +236,6 @@ class CirclesRequest extends CirclesRequestBuilder {
->setValue('settings', $qb->createNamedParameter($circle->getSettings(true)))
->setValue('type', $qb->createNamedParameter($circle->getType()));
$qb->execute();
-
- $owner = new Member($userId, Member::TYPE_USER);
- $owner->setCircleId($circle->getUniqueId())
- ->setLevel(Member::LEVEL_OWNER)
- ->setStatus(Member::STATUS_MEMBER);
- $circle->setOwner($owner)
- ->setViewer($owner);
}
@@ -265,9 +258,9 @@ class CirclesRequest extends CirclesRequestBuilder {
* @param string $userId
*
* @return bool
+ * @throws ConfigNoCircleAvailableException
*/
- private function isCircleUnique(Circle $circle, $userId) {
-
+ public function isCircleUnique(Circle $circle, $userId = '') {
if ($circle->getType() === Circle::CIRCLES_PERSONAL) {
return $this->isPersonalCircleUnique($circle, $userId);
}
@@ -295,8 +288,12 @@ class CirclesRequest extends CirclesRequestBuilder {
* @param string $userId
*
* @return bool
+ * @throws ConfigNoCircleAvailableException
*/
- private function isPersonalCircleUnique(Circle $circle, $userId) {
+ private function isPersonalCircleUnique(Circle $circle, $userId = '') {
+ if ($userId === '') {
+ return true;
+ }
$list = $this->getCircles(
$userId, Circle::CIRCLES_PERSONAL, $circle->getName(),
@@ -320,8 +317,7 @@ class CirclesRequest extends CirclesRequestBuilder {
*
* @throws CircleAlreadyExistsException
*/
- public function updateCircle(Circle $circle, $userId) {
-
+ public function updateCircle(Circle $circle, $userId = '') {
if (!$this->isCircleUnique($circle, $userId)) {
throw new CircleAlreadyExistsException(
$this->l10n->t('A circle with that name exists')
diff --git a/lib/Db/CirclesRequestBuilder.php b/lib/Db/CirclesRequestBuilder.php
index 9f773c8f..7e6da65a 100644
--- a/lib/Db/CirclesRequestBuilder.php
+++ b/lib/Db/CirclesRequestBuilder.php
@@ -91,7 +91,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
/**
* @param IQueryBuilder $qb
- * @param $userId
+ * @param string $userId
* @param string $circleUniqueId
* @param $type
* @param $name
@@ -100,7 +100,8 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
* @throws ConfigNoCircleAvailableException
*/
protected function limitRegardingCircleType(
- IQueryBuilder &$qb, $userId, $circleUniqueId, $type, $name, $forceAll = false
+ IQueryBuilder &$qb, string $userId, $circleUniqueId, int $type,
+ string $name, bool $forceAll = false
) {
$orTypes = $this->generateLimit($qb, $circleUniqueId, $userId, $type, $name, $forceAll);
if (sizeof($orTypes) === 0) {
@@ -160,6 +161,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
$andX = $expr->andX();
$andX->add($expr->eq('c.type', $qb->createNamedParameter(Circle::CIRCLES_PERSONAL)));
+ $andX->add($expr->eq('o.instance', $qb->createNamedParameter('')));
if (!$forceAll) {
$andX->add($expr->eq('o.user_id', $qb->createNamedParameter((string)$userId)));
@@ -252,8 +254,9 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
*
* @param IQueryBuilder $qb
* @param string $userId
+ * @param string $instanceId
*/
- public function leftJoinUserIdAsViewer(IQueryBuilder &$qb, $userId) {
+ public function leftJoinUserIdAsViewer(IQueryBuilder &$qb, string $userId, string $instanceId) {
if ($qb->getType() !== QueryBuilder::SELECT) {
return;
@@ -264,6 +267,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->selectAlias('u.user_id', 'viewer_userid')
+ ->selectAlias('u.instance', 'viewer_instance')
->selectAlias('u.status', 'viewer_status')
->selectAlias('u.member_id', 'viewer_member_id')
->selectAlias('u.level', 'viewer_level')
@@ -278,6 +282,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
)
),
$expr->eq('u.user_id', $qb->createNamedParameter($userId)),
+ $expr->eq('u.instance', $qb->createNamedParameter($instanceId)),
$expr->eq('u.user_type', $qb->createNamedParameter(Member::TYPE_USER))
)
);
@@ -301,6 +306,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->selectAlias('o.user_id', 'owner_userid')
+ ->selectAlias('o.instance', 'owner_instance')
->selectAlias('o.status', 'owner_status')
->selectAlias('o.level', 'owner_level')
->leftJoin(
@@ -427,6 +433,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
$user = new Member($data['viewer_userid'], Member::TYPE_USER, $circle->getUniqueId());
$user->setStatus($data['viewer_status']);
$user->setMemberId($data['viewer_member_id']);
+ $user->setInstance($data['viewer_instance']);
$user->setLevel($data['viewer_level']);
$circle->setViewer($user);
}
@@ -434,6 +441,7 @@ class CirclesRequestBuilder extends CoreRequestBuilder {
if (key_exists('owner_level', $data)) {
$owner = new Member($data['owner_userid'], Member::TYPE_USER, $circle->getUniqueId());
$owner->setStatus($data['owner_status']);
+ $owner->setInstance($data['owner_instance']);
$owner->setLevel($data['owner_level']);
$circle->setOwner($owner);
}
diff --git a/lib/Db/CoreRequestBuilder.php b/lib/Db/CoreRequestBuilder.php
index 65309f67..33846a0a 100644
--- a/lib/Db/CoreRequestBuilder.php
+++ b/lib/Db/CoreRequestBuilder.php
@@ -30,9 +30,26 @@ class CoreRequestBuilder {
const TABLE_SHARES = 'circles_shares';
const TABLE_LINKS = 'circles_links';
const TABLE_TOKENS = 'circles_tokens';
+ const TABLE_GSEVENTS = 'circles_gsevents';
+ const TABLE_GSSHARES = 'circles_gsshares';
+ const TABLE_GSSHARES_MOUNTPOINT = 'circles_gsshares_mp';
const NC_TABLE_GROUP_USER = 'group_user';
+ /** @var array */
+ private $tables = [
+ self::TABLE_CIRCLES,
+ self::TABLE_MEMBERS,
+ self::TABLE_GROUPS,
+ self::TABLE_SHARES,
+ self::TABLE_LINKS,
+ self::TABLE_TOKENS,
+ self::TABLE_GSEVENTS,
+ self::TABLE_GSSHARES,
+ self::TABLE_GSSHARES_MOUNTPOINT
+ ];
+
+
/** @var IDBConnection */
protected $dbConnection;
@@ -153,6 +170,17 @@ class CoreRequestBuilder {
/**
+ * Limit the request to the owner
+ *
+ * @param IQueryBuilder $qb
+ * @param $owner
+ */
+ protected function limitToOwner(IQueryBuilder &$qb, $owner) {
+ $this->limitToDBField($qb, 'owner', $owner);
+ }
+
+
+ /**
* Limit the request to the Member by its Id.
*
* @param IQueryBuilder $qb
@@ -175,6 +203,17 @@ class CoreRequestBuilder {
/**
+ * Limit the request to the Instance.
+ *
+ * @param IQueryBuilder $qb
+ * @param string $instance
+ */
+ protected function limitToInstance(IQueryBuilder &$qb, string $instance) {
+ $this->limitToDBField($qb, 'instance', $instance);
+ }
+
+
+ /**
* Limit the request to the Circle by its Id.
*
* @param IQueryBuilder $qb
@@ -197,6 +236,27 @@ class CoreRequestBuilder {
/**
+ * Limit the request to the Circle by its Id.
+ *
+ * @param IQueryBuilder $qb
+ * @param string $mountpoint
+ */
+ protected function limitToMountpoint(IQueryBuilder &$qb, string $mountpoint) {
+ $this->limitToDBField($qb, 'share_id', $mountpoint);
+ }
+
+ /**
+ * Limit the request to the Circle by its Id.
+ *
+ * @param IQueryBuilder $qb
+ * @param string $hash
+ */
+ protected function limitToMountpointHash(IQueryBuilder &$qb, string $hash) {
+ $this->limitToDBField($qb, 'share_id', $hash);
+ }
+
+
+ /**
* Limit the request to the Circle by its Shorten Unique Id.
*
* @param IQueryBuilder $qb
@@ -473,6 +533,25 @@ class CoreRequestBuilder {
$this->leftJoinedNCGroupAndUser = true;
}
+
+
+ /**
+ *
+ */
+ public function cleanDatabase(): void {
+ foreach ($this->tables as $table) {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete($table);
+ $qb->execute();
+ }
+
+ $qb = $this->dbConnection->getQueryBuilder();
+ $expr = $qb->expr();
+ $qb->delete(self::TABLE_FILE_SHARES);
+ $qb->where($expr->eq('share_type', $qb->createNamedParameter(self::SHARE_TYPE)));
+ $qb->execute();
+ }
+
}
diff --git a/lib/Db/GSEventsRequest.php b/lib/Db/GSEventsRequest.php
new file mode 100644
index 00000000..13e6a1e1
--- /dev/null
+++ b/lib/Db/GSEventsRequest.php
@@ -0,0 +1,100 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Db;
+
+
+use OCA\Circles\Exceptions\JsonException;
+use OCA\Circles\Exceptions\ModelException;
+use OCA\Circles\Model\GlobalScale\GSWrapper;
+
+
+/**
+ * Class GSEventsRequest
+ *
+ * @package OCA\Circles\Db
+ */
+class GSEventsRequest extends GSEventsRequestBuilder {
+
+
+ /**
+ * @param GSWrapper $wrapper
+ *
+ * @return GSWrapper
+ */
+ public function create(GSWrapper $wrapper): GSWrapper {
+ $qb = $this->getGSEventsInsertSql();
+ $qb->setValue('token', $qb->createNamedParameter($wrapper->getToken()))
+ ->setValue('event', $qb->createNamedParameter(json_encode($wrapper->getEvent())))
+ ->setValue('instance', $qb->createNamedParameter($wrapper->getInstance()))
+ ->setValue('severity', $qb->createNamedParameter($wrapper->getSeverity()))
+ ->setValue('status', $qb->createNamedParameter($wrapper->getStatus()))
+ ->setValue('creation', $qb->createNamedParameter($wrapper->getCreation()));
+
+ $qb->execute();
+
+ return $wrapper;
+ }
+
+ /**
+ * @param GSWrapper $wrapper
+ */
+ public function update(GSWrapper $wrapper): void {
+ $qb = $this->getGSEventsUpdateSql();
+ $qb->set('event', $qb->createNamedParameter(json_encode($wrapper->getEvent())))
+ ->set('status', $qb->createNamedParameter($wrapper->getStatus()));
+
+ $this->limitToInstance($qb, $wrapper->getInstance());
+ $this->limitToToken($qb, $wrapper->getToken());
+
+ $qb->execute();
+ }
+
+
+ /**
+ * @param string $token
+ *
+ * @return GSWrapper[]
+ * @throws JsonException
+ * @throws ModelException
+ */
+ public function getByToken(string $token): array {
+ $qb = $this->getGSEventsSelectSql();
+ $this->limitToToken($qb, $token);
+
+ $wrappers = [];
+ $cursor = $qb->execute();
+ while ($data = $cursor->fetch()) {
+ $wrappers[] = $this->parseGSEventsSelectSql($data);
+ }
+ $cursor->closeCursor();
+
+ return $wrappers;
+ }
+
+}
+
diff --git a/lib/Db/GSEventsRequestBuilder.php b/lib/Db/GSEventsRequestBuilder.php
new file mode 100644
index 00000000..7297ed6c
--- /dev/null
+++ b/lib/Db/GSEventsRequestBuilder.php
@@ -0,0 +1,115 @@
+<?php
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Db;
+
+
+use OCA\Circles\Exceptions\JsonException;
+use OCA\Circles\Exceptions\ModelException;
+use OCA\Circles\Model\GlobalScale\GSWrapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+
+/**
+ * Class GSEventsRequestBuilder
+ *
+ * @package OCA\Circles\Db
+ */
+class GSEventsRequestBuilder extends CoreRequestBuilder {
+
+
+ /**
+ * Base of the Sql Insert request for Shares
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSEventsInsertSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->insert(self::TABLE_GSEVENTS);
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Update request for Groups
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSEventsUpdateSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->update(self::TABLE_GSEVENTS);
+
+ return $qb;
+ }
+
+
+ /**
+ * @return IQueryBuilder
+ */
+ protected function getGSEventsSelectSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+
+ /** @noinspection PhpMethodParametersCountMismatchInspection */
+ $qb->select('gse.token', 'gse.event', 'gse.instance', 'gse.severity', 'gse.status', 'gse.creation')
+ ->from(self::TABLE_GSEVENTS, 'gse');
+
+ $this->default_select_alias = 'gse';
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Delete request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSEventsDeleteSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::TABLE_GSEVENTS);
+
+ return $qb;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSWrapper
+ * @throws JsonException
+ * @throws ModelException
+ */
+ protected function parseGSEventsSelectSql($data): GSWrapper {
+ $wrapper = new GSWrapper();
+ $wrapper->import($data);
+
+ return $wrapper;
+ }
+
+}
diff --git a/lib/Db/GSSharesRequest.php b/lib/Db/GSSharesRequest.php
new file mode 100644
index 00000000..278117e8
--- /dev/null
+++ b/lib/Db/GSSharesRequest.php
@@ -0,0 +1,225 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Db;
+
+
+use daita\MySmallPhpTools\Traits\TStringTools;
+use OCA\Circles\Model\GlobalScale\GSShare;
+use OCA\Circles\Model\GlobalScale\GSShareMountpoint;
+use OCA\Circles\Model\Member;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+use OCP\Share\Exceptions\ShareNotFound;
+
+
+/**
+ * Class GSSharesRequest
+ *
+ * @package OCA\Circles\Db
+ */
+class GSSharesRequest extends GSSharesRequestBuilder {
+
+
+ use TStringTools;
+
+
+ /**
+ * @param GSShare $gsShare
+ */
+ public function create(GSShare $gsShare): void {
+ $hash = $this->token();
+ $qb = $this->getGSSharesInsertSql();
+ $qb->setValue('circle_id', $qb->createNamedParameter($gsShare->getCircleId()))
+ ->setValue('owner', $qb->createNamedParameter($gsShare->getOwner()))
+ ->setValue('instance', $qb->createNamedParameter($gsShare->getInstance()))
+ ->setValue('token', $qb->createNamedParameter($gsShare->getToken()))
+ ->setValue('parent', $qb->createNamedParameter($gsShare->getParent()))
+ ->setValue('mountpoint', $qb->createNamedParameter($gsShare->getMountPoint()))
+ ->setValue('mountpoint_hash', $qb->createNamedParameter($hash));
+ $qb->execute();
+ }
+
+
+ /**
+ * @param string $userId
+ *
+ * @return GSShare[]
+ */
+ public function getForUser(string $userId): array {
+ $qb = $this->getGSSharesSelectSql();
+
+ $this->joinMembership($qb, $userId);
+ $this->leftJoinMountPoint($qb, $userId);
+
+ $shares = [];
+ $cursor = $qb->execute();
+ while ($data = $cursor->fetch()) {
+ $shares[] = $this->parseGSSharesSelectSql($data);
+ }
+ $cursor->closeCursor();
+
+ return $shares;
+ }
+
+
+ /**
+ * @param Member $member
+ */
+ public function removeGSSharesFromMember(Member $member) {
+ $qb = $this->getGSSharesDeleteSql();
+ $this->limitToCircleId($qb, $member->getCircleId());
+ $this->limitToInstance($qb, $member->getInstance());
+ $this->limitToOwner($qb, $member->getUserId());
+
+ $qb->execute();
+ }
+
+
+ /**
+ * @param IQueryBuilder $qb
+ * @param string $userId
+ */
+ private function joinMembership(IQueryBuilder $qb, string $userId) {
+ $qb->from(CoreRequestBuilder::TABLE_MEMBERS, 'm');
+
+ $expr = $qb->expr();
+ $andX = $expr->andX();
+
+ $andX->add($expr->eq('m.user_id', $qb->createNamedParameter($userId)));
+ $andX->add($expr->eq('m.instance', $qb->createNamedParameter('')));
+ $andX->add($expr->gt('m.level', $qb->createNamedParameter(0)));
+ $andX->add($expr->eq('m.user_type', $qb->createNamedParameter(Member::TYPE_USER)));
+ $andX->add($expr->eq('m.circle_id', 'gsh.circle_id'));
+
+ $qb->andWhere($andX);
+ }
+
+
+ private function leftJoinMountPoint(IQueryBuilder $qb, string $userId) {
+ $expr = $qb->expr();
+ $pf = '' . $this->default_select_alias . '.';
+
+ $on = $expr->andX();
+ $on->add($expr->eq('mp.user_id', $qb->createNamedParameter($userId)));
+ $on->add($expr->eq('mp.share_id', $pf . 'id'));
+
+ /** @noinspection PhpMethodParametersCountMismatchInspection */
+ $qb->selectAlias('mp.mountPoint', 'gsshares_mountpoint')
+ ->leftJoin($this->default_select_alias, CoreRequestBuilder::TABLE_GSSHARES_MOUNTPOINT, 'mp', $on);
+ }
+
+
+ /**
+ * @param string $userId
+ * @param string $target
+ *
+ * @return GSShareMountpoint
+ * @throws ShareNotFound
+ */
+ public function getShareMountPointByPath(string $userId, string $target): GSShareMountpoint {
+ $qb = $this->getGSSharesMountpointSelectSql();
+
+ $targetHash = md5($target);
+ $this->limitToUserId($qb, $userId);
+ $this->limitToMountpointHash($qb, $targetHash);
+
+ $shares = [];
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+
+ if ($data === false) {
+ throw new ShareNotFound();
+ }
+
+ return $this->parseGSSharesMountpointSelectSql($data);
+ }
+
+
+ /**
+ * @param int $gsShareId
+ * @param string $userId
+ *
+ * @return GSShareMountpoint
+ * @throws ShareNotFound
+ */
+ public function getShareMountPointById(int $gsShareId, string $userId): GSShareMountpoint {
+ $qb = $this->getGSSharesMountpointSelectSql();
+
+ $this->limitToShareId($qb, $gsShareId);
+ $this->limitToUserId($qb, $userId);
+
+ $shares = [];
+ $cursor = $qb->execute();
+ $data = $cursor->fetch();
+ if ($data === false) {
+ throw new ShareNotFound();
+ }
+
+ return $this->parseGSSharesMountpointSelectSql($data);
+ }
+
+
+ /**
+ * @param GSShareMountpoint $mountpoint
+ */
+ public function generateShareMountPoint(GSShareMountpoint $mountpoint) {
+ $qb = $this->getGSSharesMountpointInsertSql();
+
+ $hash = ($mountpoint->getMountPoint() === '-') ? '' : md5($mountpoint->getMountPoint());
+
+ $qb->setValue('user_id', $qb->createNamedParameter($mountpoint->getUserId()))
+ ->setValue('share_id', $qb->createNamedParameter($mountpoint->getShareId()))
+ ->setValue('mountpoint', $qb->createNamedParameter($mountpoint->getMountPoint()))
+ ->setValue('mountpoint_hash', $qb->createNamedParameter($hash));
+ $qb->execute();
+ }
+
+
+ /**
+ * @param GSShareMountpoint $mountpoint
+ *
+ * @return bool
+ */
+ public function updateShareMountPoint(GSShareMountpoint $mountpoint) {
+ $qb = $this->getGSSharesMountpointUpdateSql();
+
+ $hash = ($mountpoint->getMountPoint() === '-') ? '' : md5($mountpoint->getMountPoint());
+
+ $qb->set('mountpoint', $qb->createNamedParameter($mountpoint->getMountPoint()))
+ ->set('mountpoint_hash', $qb->createNamedParameter($hash));
+
+ $this->limitToShareId($qb, $mountpoint->getShareId());
+ $this->limitToUserId($qb, $mountpoint->getUserId());
+ $nb = $qb->execute();
+
+ return ($nb === 1);
+ }
+
+
+
+}
+
diff --git a/lib/Db/GSSharesRequestBuilder.php b/lib/Db/GSSharesRequestBuilder.php
new file mode 100644
index 00000000..b7d42d30
--- /dev/null
+++ b/lib/Db/GSSharesRequestBuilder.php
@@ -0,0 +1,183 @@
+<?php
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Db;
+
+
+use OCA\Circles\Model\GlobalScale\GSShare;
+use OCA\Circles\Model\GlobalScale\GSShareMountpoint;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+
+/**
+ * Class GSSharesRequestBuilder
+ *
+ * @package OCA\Circles\Db
+ */
+class GSSharesRequestBuilder extends CoreRequestBuilder {
+
+
+ /**
+ * Base of the Sql Insert request for Shares
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesInsertSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->insert(self::TABLE_GSSHARES);
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Insert request for Shares Mountpoint
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesMountpointInsertSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->insert(self::TABLE_GSSHARES_MOUNTPOINT);
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Update request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesUpdateSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->update(self::TABLE_GSSHARES);
+
+ return $qb;
+ }
+
+
+ /**
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesMountpointUpdateSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->update(self::TABLE_GSSHARES_MOUNTPOINT);
+
+ return $qb;
+ }
+
+
+ /**
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesSelectSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+
+ /** @noinspection PhpMethodParametersCountMismatchInspection */
+ $qb->select(
+ 'gsh.id', 'gsh.circle_id', 'gsh.owner', 'gsh.instance', 'gsh.token', 'gsh.parent',
+ 'gsh.mountpoint', 'gsh.mountpoint_hash'
+ )
+ ->from(self::TABLE_GSSHARES, 'gsh');
+
+ $this->default_select_alias = 'gsh';
+
+ return $qb;
+ }
+
+
+ /**
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesMountpointSelectSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+
+ /** @noinspection PhpMethodParametersCountMismatchInspection */
+ $qb->select(
+ 'gsmp.user_id', 'gsmp.share_id', 'gsmp.mountpoint', 'gsmp.mountpoint_hash'
+ )
+ ->from(self::TABLE_GSSHARES_MOUNTPOINT, 'gsmp');
+
+ $this->default_select_alias = 'gsmp';
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Delete request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesDeleteSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::TABLE_GSSHARES);
+
+ return $qb;
+ }
+
+
+ /**
+ * Base of the Sql Delete request
+ *
+ * @return IQueryBuilder
+ */
+ protected function getGSSharesMountpointDeleteSql() {
+ $qb = $this->dbConnection->getQueryBuilder();
+ $qb->delete(self::TABLE_GSSHARES_MOUNTPOINT);
+
+ return $qb;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSShare
+ */
+ protected function parseGSSharesSelectSql($data): GSShare {
+ $share = new GSShare();
+ $share->importFromDatabase($data);
+
+ return $share;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSShareMountpoint
+ */
+ protected function parseGSSharesMountpointSelectSql($data): GSShareMountpoint {
+ $share = new GSShareMountpoint();
+ $share->importFromDatabase($data);
+
+ return $share;
+ }
+
+}
diff --git a/lib/Db/MembersRequest.php b/lib/Db/MembersRequest.php
index 54bd6961..f07fdcc7 100644
--- a/lib/Db/MembersRequest.php
+++ b/lib/Db/MembersRequest.php
@@ -51,14 +51,21 @@ class MembersRequest extends MembersRequestBuilder {
* @param string $userId
* @param $type
*
+ * @param string $instance
+ *
* @return Member
* @throws MemberDoesNotExistException
*/
- public function forceGetMember($circleUniqueId, $userId, $type) {
+ public function forceGetMember($circleUniqueId, $userId, $type, string $instance = '') {
$qb = $this->getMembersSelectSql();
+ if ($instance === $this->configService->getLocalCloudId()) {
+ $instance = '';
+ }
+
$this->limitToUserId($qb, $userId);
$this->limitToUserType($qb, $type);
+ $this->limitToInstance($qb, $instance);
$this->limitToCircleId($qb, $circleUniqueId);
$cursor = $qb->execute();
@@ -187,7 +194,9 @@ class MembersRequest extends MembersRequestBuilder {
* @param bool $check
*/
public function checkMember(Member $member, bool $check) {
- $qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
+ $qb = $this->getMembersUpdateSql(
+ $member->getCircleId(), $member->getUserId(), $member->getInstance(), $member->getType()
+ );
$qb->set('contact_checked', $qb->createNamedParameter(($check) ? 1 : 0));
$qb->execute();
@@ -321,21 +330,19 @@ class MembersRequest extends MembersRequestBuilder {
*
* @param string $circleUniqueId
* @param string $name
- * @param $type
+ * @param int $type
+ *
+ * @param string $instance
*
* @return Member
- * @throws MemberAlreadyExistsException
- * @throws \Exception
*/
- public function getFreshNewMember($circleUniqueId, $name, $type) {
+ public function getFreshNewMember($circleUniqueId, string $name, int $type, string $instance) {
try {
-
- $member = $this->forceGetMember($circleUniqueId, $name, $type);
-
+ $member = $this->forceGetMember($circleUniqueId, $name, $type, $instance);
} catch (MemberDoesNotExistException $e) {
$member = new Member($name, $type, $circleUniqueId);
- $this->createMember($member);
+ $member->setInstance($instance);
}
// if ($member->alreadyExistOrJoining()) {
@@ -454,12 +461,18 @@ class MembersRequest extends MembersRequestBuilder {
$member->setMemberId($this->token(14));
}
+ $instance = $member->getInstance();
+ if ($instance === $this->configService->getLocalCloudId()) {
+ $instance = '';
+ }
+
try {
$qb = $this->getMembersInsertSql();
$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
->setValue('member_id', $qb->createNamedParameter($member->getMemberId()))
->setValue('user_type', $qb->createNamedParameter($member->getType()))
+ ->setValue('instance', $qb->createNamedParameter($instance))
->setValue('level', $qb->createNamedParameter($member->getLevel()))
->setValue('status', $qb->createNamedParameter($member->getStatus()))
->setValue('contact_id', $qb->createNamedParameter($member->getContactId()))
@@ -535,7 +548,14 @@ class MembersRequest extends MembersRequestBuilder {
* @param Member $member
*/
public function updateMember(Member $member) {
- $qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
+ $instance = $member->getInstance();
+ if ($instance === $this->configService->getLocalCloudId()) {
+ $instance = '';
+ }
+
+ $qb = $this->getMembersUpdateSql(
+ $member->getCircleId(), $member->getUserId(), $instance, $member->getType()
+ );
$qb->set('level', $qb->createNamedParameter($member->getLevel()))
->set('status', $qb->createNamedParameter($member->getStatus()));
@@ -548,7 +568,9 @@ class MembersRequest extends MembersRequestBuilder {
* @param Member $member
*/
public function updateContactMeta(Member $member) {
- $qb = $this->getMembersUpdateSql($member->getCircleId(), $member);
+ $qb = $this->getMembersUpdateSql(
+ $member->getCircleId(), $member->getUserId(), $member->getInstance(), $member->getType()
+ );
$qb->set('contact_meta', $qb->createNamedParameter(json_encode($member->getContactMeta())));
$qb->execute();
@@ -604,9 +626,15 @@ class MembersRequest extends MembersRequestBuilder {
* @param Member $member
*/
public function removeMember(Member $member) {
+ $instance = $member->getInstance();
+ if ($instance === $this->configService->getLocalCloudId()) {
+ $instance = '';
+ }
+
$qb = $this->getMembersDeleteSql();
$this->limitToCircleId($qb, $member->getCircleId());
$this->limitToUserId($qb, $member->getUserId());
+ $this->limitToInstance($qb, $instance);
$this->limitToUserType($qb, $member->getType());
if ($member->getContactId() !== '') {
$this->limitToContactId($qb, $member->getContactId());
@@ -731,4 +759,3 @@ class MembersRequest extends MembersRequestBuilder {
}
-
diff --git a/lib/Db/MembersRequestBuilder.php b/lib/Db/MembersRequestBuilder.php
index 35d437a5..1e306ec5 100644
--- a/lib/Db/MembersRequestBuilder.php
+++ b/lib/Db/MembersRequestBuilder.php
@@ -81,8 +81,8 @@ class MembersRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select(
- 'm.user_id', 'm.user_type', 'm.circle_id', 'm.level', 'm.status', 'm.note', 'm.contact_id',
- 'm.member_id', 'm.contact_meta', 'm.joined'
+ 'm.user_id', 'm.instance', 'm.user_type', 'm.circle_id', 'm.level', 'm.status', 'm.note',
+ 'm.contact_id', 'm.member_id', 'm.contact_meta', 'm.joined'
)
->from(self::TABLE_MEMBERS, 'm')
->orderBy('m.joined');
@@ -147,12 +147,14 @@ class MembersRequestBuilder extends CoreRequestBuilder {
/**
* Base of the Sql Updte request for Members
*
- * @param int $circleId
- * @param Member $member
+ * @param string /$circleId
+ * @param string $userId
+ * @param string $instance
+ * @param int $type
*
* @return IQueryBuilder
*/
- protected function getMembersUpdateSql($circleId, Member $member) {
+ protected function getMembersUpdateSql(string $circleId, string $userId, string $instance, int $type) {
$qb = $this->dbConnection->getQueryBuilder();
$expr = $qb->expr();
@@ -161,8 +163,9 @@ class MembersRequestBuilder extends CoreRequestBuilder {
->where(
$expr->andX(
$expr->eq('circle_id', $qb->createNamedParameter($circleId)),
- $expr->eq('user_id', $qb->createNamedParameter($member->getUserId())),
- $expr->eq('user_type', $qb->createNamedParameter($member->getType()))
+ $expr->eq('user_id', $qb->createNamedParameter($userId)),
+ $expr->eq('instance', $qb->createNamedParameter($instance)),
+ $expr->eq('user_type', $qb->createNamedParameter($type))
)
);
@@ -217,6 +220,7 @@ class MembersRequestBuilder extends CoreRequestBuilder {
}
$member->setLevel($data['level']);
+ $member->setInstance($data['instance']);
$member->setStatus($data['status']);
$member->setJoined($this->timezoneService->convertTimeForCurrentUser($data['joined']));
diff --git a/lib/Exceptions/GSKeyException.php b/lib/Exceptions/GSKeyException.php
new file mode 100644
index 00000000..da4fa59b
--- /dev/null
+++ b/lib/Exceptions/GSKeyException.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Exceptions;
+
+
+class GSKeyException extends \Exception {
+
+}
+
+
diff --git a/lib/Exceptions/GSStatusException.php b/lib/Exceptions/GSStatusException.php
new file mode 100644
index 00000000..0e3de475
--- /dev/null
+++ b/lib/Exceptions/GSStatusException.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Exceptions;
+
+
+class GSStatusException extends \Exception {
+
+}
+
+
diff --git a/lib/Exceptions/GlobalScaleDSyncException.php b/lib/Exceptions/GlobalScaleDSyncException.php
new file mode 100644
index 00000000..e485f212
--- /dev/null
+++ b/lib/Exceptions/GlobalScaleDSyncException.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Exceptions;
+
+class GlobalScaleDSyncException extends \Exception {
+
+}
+
diff --git a/lib/Exceptions/GlobalScaleEventException.php b/lib/Exceptions/GlobalScaleEventException.php
new file mode 100644
index 00000000..cf721d09
--- /dev/null
+++ b/lib/Exceptions/GlobalScaleEventException.php
@@ -0,0 +1,32 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Exceptions;
+
+class GlobalScaleEventException extends \Exception {
+
+}
+
diff --git a/lib/Exceptions/JsonException.php b/lib/Exceptions/JsonException.php
new file mode 100644
index 00000000..2760a1c7
--- /dev/null
+++ b/lib/Exceptions/JsonException.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Exceptions;
+
+
+class JsonException extends \Exception {
+
+}
+
+
diff --git a/lib/Exceptions/ModelException.php b/lib/Exceptions/ModelException.php
new file mode 100644
index 00000000..ad64949e
--- /dev/null
+++ b/lib/Exceptions/ModelException.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Exceptions;
+
+
+class ModelException extends \Exception {
+
+}
+
+
diff --git a/lib/GlobalScale/AGlobalScaleEvent.php b/lib/GlobalScale/AGlobalScaleEvent.php
new file mode 100644
index 00000000..432a8f15
--- /dev/null
+++ b/lib/GlobalScale/AGlobalScaleEvent.php
@@ -0,0 +1,265 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Db\CirclesRequest;
+use OCA\Circles\Db\GSSharesRequest;
+use OCA\Circles\Db\MembersRequest;
+use OCA\Circles\Db\SharesRequest;
+use OCA\Circles\Db\TokensRequest;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+use OCA\Circles\Service\CirclesService;
+use OCA\Circles\Service\ConfigService;
+use OCA\Circles\Service\EventsService;
+use OCA\Circles\Service\MembersService;
+use OCA\Circles\Service\MiscService;
+use OCP\Files\IRootFolder;
+use OCP\IUserManager;
+
+
+/**
+ * Class AGlobalScaleEvent
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+abstract class AGlobalScaleEvent {
+
+
+ /** @var IRootFolder */
+ protected $rootFolder;
+
+ /** @var IUserManager */
+ protected $userManager;
+
+ /** @var SharesRequest */
+ protected $sharesRequest;
+
+ /** @var TokensRequest */
+ protected $tokensRequest;
+
+ /** @var CirclesRequest */
+ protected $circlesRequest;
+
+ /** @var MembersRequest */
+ protected $membersRequest;
+
+ /** @var GSSharesRequest */
+ protected $gsSharesRequest;
+
+ /** @var CirclesService */
+ protected $circlesService;
+
+ /** @var MembersService */
+ protected $membersService;
+
+ /** @var EventsService */
+ protected $eventsService;
+
+ /** @var ConfigService */
+ protected $configService;
+
+ /** @var MiscService */
+ protected $miscService;
+
+
+ /**
+ * AGlobalScaleEvent constructor.
+ *
+ * @param IRootFolder $rootFolder
+ * @param IUserManager $userManager
+ * @param SharesRequest $sharesRequest
+ * @param TokensRequest $tokensRequest
+ * @param CirclesRequest $circlesRequest
+ * @param MembersRequest $membersRequest
+ * @param GSSharesRequest $gsSharesRequest
+ * @param CirclesService $circlesService
+ * @param MembersService $membersService
+ * @param EventsService $eventsService
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ IRootFolder $rootFolder,
+ IUserManager $userManager,
+ SharesRequest $sharesRequest,
+ TokensRequest $tokensRequest,
+ CirclesRequest $circlesRequest,
+ MembersRequest $membersRequest,
+ GSSharesRequest $gsSharesRequest,
+ CirclesService $circlesService,
+ MembersService $membersService,
+ EventsService $eventsService,
+ ConfigService $configService,
+ MiscService $miscService
+ ) {
+ $this->rootFolder = $rootFolder;
+ $this->userManager = $userManager;
+ $this->sharesRequest = $sharesRequest;
+ $this->tokensRequest = $tokensRequest;
+ $this->circlesRequest = $circlesRequest;
+ $this->membersRequest = $membersRequest;
+ $this->gsSharesRequest = $gsSharesRequest;
+ $this->circlesService = $circlesService;
+ $this->membersService = $membersService;
+ $this->eventsService = $eventsService;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ *
+ * @param bool $mustBeCheck
+ *
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeCheck = false): void {
+ if ($localCheck && !$event->isForced()) {
+ $this->checkViewer($event, $mustBeCheck);
+ }
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ abstract public function manage(GSEvent $event): void;
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ abstract public function result(array $events): void;
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $mustBeChecked
+ *
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ private function checkViewer(GSEvent $event, bool $mustBeChecked) {
+ if (!$event->hasCircle()
+ || !$event->getCircle()
+ ->hasViewer()) {
+ if ($mustBeChecked) {
+ throw new GlobalScaleEventException('GSEvent cannot be checked');
+ } else {
+ return;
+ }
+ }
+
+ $circle = $event->getCircle();
+ $viewer = $circle->getViewer();
+ $this->cleanMember($viewer);
+
+ $localCircle = $this->circlesRequest->getCircle(
+ $circle->getUniqueId(), $viewer->getUserId(), $viewer->getInstance()
+ );
+
+ if (!$this->compareMembers($viewer, $localCircle->getViewer())) {
+ throw new GlobalScaleDSyncException('Viewer seems DSync');
+ }
+
+ $event->setCircle($localCircle);
+ }
+
+
+ /**
+ * @param Member $member1
+ * @param Member $member2
+ *
+ * @return bool
+ */
+ protected function compareMembers(Member $member1, Member $member2) {
+ if ($member1->getInstance() === '') {
+ $member1->setInstance($this->configService->getLocalCloudId());
+ }
+
+ if ($member2->getInstance() === '') {
+ $member2->setInstance($this->configService->getLocalCloudId());
+ }
+
+
+ if ($member1->getCircleId() !== $member2->getCircleId()
+ || $member1->getUserId() !== $member2->getUserId()
+ || $member1->getType() <> $member2->getType()
+ || $member1->getLevel() <> $member2->getLevel()
+ || $member1->getStatus() !== $member2->getStatus()
+ || $member1->getInstance() !== $member2->getInstance()) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param Circle $circle1
+ * @param Circle $circle2
+ *
+ * @return bool
+ */
+ protected function compareCircles(Circle $circle1, Circle $circle2): bool {
+ if ($circle1->getName() !== $circle2->getName()
+ || $circle1->getDescription() !== $circle2->getDescription()
+ || $circle1->getSettings(true) !== $circle2->getSettings(true)
+ || $circle1->getType() !== $circle2->getType()
+ || $circle1->getUniqueId() !== $circle2->getUniqueId()) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ protected function cleanMember(Member $member) {
+ if ($member->getInstance() === $this->configService->getLocalCloudId()) {
+ $member->setInstance('');
+ }
+ }
+
+}
+
diff --git a/lib/GlobalScale/CircleCreate.php b/lib/GlobalScale/CircleCreate.php
new file mode 100644
index 00000000..8314032a
--- /dev/null
+++ b/lib/GlobalScale/CircleCreate.php
@@ -0,0 +1,88 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+
+
+/**
+ * Class CircleCreate
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class CircleCreate extends AGlobalScaleEvent {
+
+
+ /**
+ * Circles are created on the original instance, so return false;
+ *
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ //parent::verify($event, $localCheck, $mustBeChecked);
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws CircleAlreadyExistsException
+ * @throws MemberAlreadyExistsException
+ */
+ public function manage(GSEvent $event): void {
+ if (!$event->hasCircle()) {
+ return;
+ }
+
+ $circle = $event->getCircle();
+ $this->circlesRequest->createCircle($circle);
+
+ $owner = $circle->getOwner();
+ if ($owner->getInstance() === '') {
+ $owner->setInstance($event->getSource());
+ }
+ $this->membersRequest->createMember($owner);
+
+ $this->eventsService->onCircleCreation($circle);
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+}
+
diff --git a/lib/GlobalScale/CircleDestroy.php b/lib/GlobalScale/CircleDestroy.php
new file mode 100644
index 00000000..5c0b76fc
--- /dev/null
+++ b/lib/GlobalScale/CircleDestroy.php
@@ -0,0 +1,82 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class CircleDestroy
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class CircleDestroy extends AGlobalScaleEvent {
+
+
+ /**
+ * Circles are destroyed from the original instance, or by admin
+ *
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ //parent::verify($event, $localCheck, $mustBeChecked);
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ public function manage(GSEvent $event): void {
+ if (!$event->hasCircle()) {
+ return;
+ }
+
+ $circle = $event->getCircle();
+ $this->eventsService->onCircleDestruction($circle);
+
+ $this->membersRequest->removeAllFromCircle($circle->getUniqueId());
+ $this->circlesRequest->destroyCircle($circle->getUniqueId());
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+
+}
+
diff --git a/lib/GlobalScale/CircleStatus.php b/lib/GlobalScale/CircleStatus.php
new file mode 100644
index 00000000..8480d7be
--- /dev/null
+++ b/lib/GlobalScale/CircleStatus.php
@@ -0,0 +1,96 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class CircleStatus
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class CircleStatus extends AGlobalScaleEvent {
+
+
+ const STATUS_ERROR = -1;
+ const STATUS_OK = 1;
+ const STATUS_NOT_OWNER = 8;
+ const STATUS_NOT_FOUND = 404;
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ public function manage(GSEvent $event): void {
+ $circle = $event->getCircle();
+ $status = self::STATUS_ERROR;
+
+ try {
+ $this->circlesRequest->forceGetCircle($circle->getUniqueId());
+ $owners = $this->membersRequest->forceGetMembers($circle->getUniqueId(), Member::LEVEL_OWNER);
+ if (!empty($owners)) {
+ $owner = $owners[0];
+ if ($owner->getInstance() === '') {
+ $status = self::STATUS_OK;
+ } else {
+ $status = self::STATUS_NOT_OWNER;
+ $event->getData()
+ ->sObj('supposedOwner', $owner);
+ }
+ }
+ } catch (CircleDoesNotExistException $e) {
+ $status = self::STATUS_NOT_FOUND;
+ }
+
+ $event->getData()
+ ->sInt('status', $status);
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+}
+
diff --git a/lib/GlobalScale/CircleUpdate.php b/lib/GlobalScale/CircleUpdate.php
new file mode 100644
index 00000000..86847bb7
--- /dev/null
+++ b/lib/GlobalScale/CircleUpdate.php
@@ -0,0 +1,111 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleAlreadyExistsException;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class CircleUpdate
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class CircleUpdate extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ *
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ parent::verify($event, $localCheck, true);
+
+ $circle = $event->getCircle();
+ $data = $event->getData();
+ $viewer = $circle->getHigherViewer();
+ if (!$data->gBool('local_admin') && $viewer->getLevel() !== Member::LEVEL_OWNER) {
+ throw new GlobalScaleDSyncException('Member is not Owner');
+ }
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws CircleAlreadyExistsException
+ */
+ public function manage(GSEvent $event): void {
+ if (!$event->hasCircle()) {
+ return;
+ }
+
+ $circle = $event->getCircle();
+ $settings = $event->getData()
+ ->gArray('settings');
+ $ak = array_keys($settings);
+ foreach ($ak AS $k) {
+ $circle->setSetting($k, $settings[$k]);
+ }
+
+ $owner = $circle->getHigherViewer();
+ $this->circlesRequest->updateCircle($circle, $owner->getUserId());
+
+ $oldSettings = array_merge(
+ $circle->getSettings(),
+ [
+ 'circle_name' => $circle->getName(),
+ 'circle_desc' => $circle->getDescription(),
+ ]
+ );
+
+ $this->eventsService->onSettingsChange($circle, $oldSettings);
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+}
+
diff --git a/lib/GlobalScale/FileShare.php b/lib/GlobalScale/FileShare.php
new file mode 100644
index 00000000..da8b4bd5
--- /dev/null
+++ b/lib/GlobalScale/FileShare.php
@@ -0,0 +1,281 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use daita\MySmallPhpTools\Model\SimpleDataStore;
+use Exception;
+use OC\Share20\Share;
+use OCA\Circles\Exceptions\BroadcasterIsNotCompatibleException;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\Exceptions\TokenDoesNotExistException;
+use OCA\Circles\IBroadcaster;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\GlobalScale\GSShare;
+use OCA\Circles\Model\Member;
+use OCA\Circles\Model\SharingFrame;
+use OCA\Circles\Service\ConfigService;
+use OCA\Circles\Service\MiscService;
+use OCP\AppFramework\QueryException;
+use OCP\Files\NotFoundException;
+use OCP\Share\Exceptions\IllegalIDChangeException;
+use OCP\Share\Exceptions\ShareNotFound;
+use OCP\Share\IShare;
+
+
+/**
+ * Class FileShare
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class FileShare extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ *
+ * @throws GSStatusException
+ * @throws TokenDoesNotExistException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ // TODO: might be a bad idea, all process of the sharing should be managed from here.
+ // Even if we are not in a GS setup.
+ // The reason is that if a mail needs to be send, all mail address associated to the circle needs to be retrieved
+ if (!$this->configService->getGSStatus(ConfigService::GS_ENABLED)) {
+ return;
+ }
+ \OC::$server->getLogger()->log(3, '### 0');
+ // if event/file is local, we generate a federate share for the same circle on other instances
+ if ($event->getSource() === $this->configService->getLocalCloudId()) {
+ $circle = $event->getCircle();
+
+ \OC::$server->getLogger()->log(3, '### 1');
+
+ try {
+ $share = $this->getShareFromData($event->getData());
+ } catch (Exception $e) {
+ return;
+ }
+
+ \OC::$server->getLogger()->log(3, '### 2');
+
+
+ $this->miscService->log('### ' . json_encode($event->getData()));
+
+ try {
+ $node = $share->getNode();
+ $filename = $node->getName();
+ } catch (NotFoundException $e) {
+ $filename = '/testTest.md';
+ }
+
+ $event->getData()
+ ->s('gs_federated', $share->getToken())
+ ->s('gs_filename', '/' . $filename);
+ }
+
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws GSStatusException
+ */
+ public function manage(GSEvent $event): void {
+ // TODO: might be a bad idea, all process of the sharing should be managed from here.
+ // Even if we are not in a GS setup.
+ // The reason is that if a mail needs to be send, all mail address associated to the circle needs to be retrieved
+ if (!$this->configService->getGSStatus(ConfigService::GS_ENABLED)) {
+ return;
+ }
+
+ // if event is not local, we create a federated file to the right instance of Nextcloud, using the right token
+ if ($event->getSource() !== $this->configService->getLocalCloudId()) {
+ try {
+ $share = $this->getShareFromData($event->getData());
+ } catch (Exception $e) {
+ return;
+ }
+
+ $data = $event->getData();
+ $token = $data->g('gs_federated');
+ $filename = $data->g('gs_filename');
+
+ $gsShare = new GSShare($share->getSharedWith(), $token);
+ $gsShare->setOwner($share->getShareOwner());
+ $gsShare->setInstance($event->getSource());
+ $gsShare->setParent(-1);
+ $gsShare->setMountPoint($filename);
+
+ $this->gsSharesRequest->create($gsShare);
+ }
+
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws BroadcasterIsNotCompatibleException
+ * @throws GSStatusException
+ */
+ private function generateFederatedShare(GSEvent $event) {
+ $data = $event->getData();
+ $frame = SharingFrame::fromJSON(json_encode($data->gAll()));
+
+ try {
+ $broadcaster = \OC::$server->query((string)$frame->getHeader('broadcast'));
+ if (!($broadcaster instanceof IBroadcaster)) {
+ throw new BroadcasterIsNotCompatibleException();
+ }
+
+ $frameCircle = $frame->getCircle();
+ $circle = $this->circlesRequest->forceGetCircle($frameCircle->getUniqueId());
+ } catch (QueryException | CircleDoesNotExistException $e) {
+ return;
+ }
+
+ $this->feedBroadcaster($broadcaster, $frame, $circle);
+ }
+
+
+ /**
+ * @param IBroadcaster $broadcaster
+ * @param SharingFrame $frame
+ * @param Circle $circle
+ */
+ private function feedBroadcaster(IBroadcaster $broadcaster, SharingFrame $frame, Circle $circle) {
+ $broadcaster->init();
+
+ if ($circle->getType() !== Circle::CIRCLES_PERSONAL) {
+ $broadcaster->createShareToCircle($frame, $circle);
+ }
+
+ $members =
+ $this->membersRequest->forceGetMembers($circle->getUniqueId(), Member::LEVEL_MEMBER, true);
+ foreach ($members AS $member) {
+ $this->parseMember($member);
+
+ if ($member->isBroadcasting()) {
+ $broadcaster->createShareToMember($frame, $member);
+ }
+
+ if ($member->getInstance() !== '') {
+ $this->miscService->log('#### GENERATE FEDERATED CIRCLES SHARE ' . $member->getInstance());
+ }
+ }
+ }
+
+
+ /**
+ * @param Member $member
+ */
+ private function parseMember(Member &$member) {
+ $this->parseMemberFromContact($member);
+ }
+
+
+ /**
+ * on Type Contact, we convert the type to MAIL and retrieve the first mail of the list.
+ * If no email, we set the member as not broadcasting.
+ *
+ * @param Member $member
+ */
+ private function parseMemberFromContact(Member &$member) {
+ if ($member->getType() !== Member::TYPE_CONTACT) {
+ return;
+ }
+
+ $contact = MiscService::getContactData($member->getUserId());
+ if (!key_exists('EMAIL', $contact)) {
+ $member->broadcasting(false);
+
+ return;
+ }
+
+ $member->setType(Member::TYPE_MAIL);
+ $member->setUserId(array_shift($contact['EMAIL']));
+ }
+
+
+ /**
+ * @param SimpleDataStore $data
+ *
+ * @return IShare
+ * @throws ShareNotFound
+ * @throws IllegalIDChangeException
+ */
+ private function getShareFromData(SimpleDataStore $data) {
+ $frame = SharingFrame::fromArray($data->gArray('frame'));
+ $payload = $frame->getPayload();
+ if (!key_exists('share', $payload)) {
+ throw new ShareNotFound();
+ }
+
+ return $this->generateShare($payload['share']);
+ }
+
+
+ /**
+ * recreate the share from the JSON payload.
+ *
+ * @param array $data
+ *
+ * @return IShare
+ * @throws IllegalIDChangeException
+ */
+ private function generateShare($data): IShare {
+ $share = new Share($this->rootFolder, $this->userManager);
+ $share->setId($data['id']);
+ $share->setSharedBy($data['sharedBy']);
+ $share->setSharedWith($data['sharedWith']);
+ $share->setNodeId($data['nodeId']);
+ $share->setShareOwner($data['shareOwner']);
+ $share->setPermissions($data['permissions']);
+ $share->setToken($data['token']);
+ $share->setPassword($data['password']);
+
+ return $share;
+ }
+
+
+}
diff --git a/lib/GlobalScale/GSMount/Mount.php b/lib/GlobalScale/GSMount/Mount.php
new file mode 100644
index 00000000..6c269768
--- /dev/null
+++ b/lib/GlobalScale/GSMount/Mount.php
@@ -0,0 +1,111 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @copyright 2020
+ * @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\Circles\GlobalScale\GSMount;
+
+
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use Exception;
+use OC\Files\Mount\MountPoint;
+use OC\Files\Mount\MoveableMount;
+
+
+/**
+ * Class Mount
+ *
+ * @package OCA\Circles\GlobalScale\GSMount
+ */
+class Mount extends MountPoint implements MoveableMount {
+
+
+ use TArrayTools;
+
+
+ /** @var MountManager */
+ protected $mountManager;
+
+ /** @var int */
+ private $gsShareId = -1;
+
+ /**
+ * Mount constructor.
+ *
+ * @param $storage
+ * @param string $mountPoint
+ * @param array $options
+ * @param MountManager $manager
+ * @param null $loader
+ *
+ * @throws Exception
+ */
+ public function __construct(
+ $storage, string $mountPoint, array $options, MountManager $manager, $loader = null
+ ) {
+ parent::__construct($storage, $mountPoint, $options, $loader);
+ $this->gsShareId = $this->getInt('gsShareId', $options);
+ $this->mountManager = $manager;
+ }
+
+
+ /**
+ * Move the mount point to $target
+ *
+ * @param string $target the target mount point
+ *
+ * @return bool
+ */
+ public function moveMount($target) {
+ $result = $this->mountManager->renameShare($this->gsShareId, $target);
+ $this->setMountPoint($target);
+
+ return $result;
+ }
+
+ /**
+ * Remove the mount points
+ *
+ * @return mixed
+ * @return bool
+ */
+ public function removeMount() {
+ return $this->mountManager->unshare($this->gsShareId);
+ }
+
+
+ /**
+ * Get the type of mount point, used to distinguish things like shares and external storages
+ * in the web interface
+ *
+ * @return string
+ */
+ public function getMountType() {
+ return 'shared';
+ }
+}
+
diff --git a/lib/GlobalScale/GSMount/MountManager.php b/lib/GlobalScale/GSMount/MountManager.php
new file mode 100644
index 00000000..92f88f41
--- /dev/null
+++ b/lib/GlobalScale/GSMount/MountManager.php
@@ -0,0 +1,118 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @copyright 2020
+ * @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\Circles\GlobalScale\GSMount;
+
+
+use OCA\Circles\Db\GSSharesRequest;
+use OCA\Circles\Model\GlobalScale\GSShareMountpoint;
+use OCP\Share\Exceptions\ShareNotFound;
+
+
+/**
+ * Class MountManager
+ *
+ * @package OCA\Circles\GlobalScale\GSMount
+ */
+class MountManager {
+
+
+ /** @var string */
+ private $userId;
+
+ /** @var GSSharesRequest */
+ private $gsSharesRequest;
+
+
+ /**
+ * MountManager constructor.
+ *
+ * @param string $userId
+ * @param GSSharesRequest $gsSharesRequest
+ */
+ public function __construct($userId, GSSharesRequest $gsSharesRequest) {
+ $this->userId = $userId;
+ $this->gsSharesRequest = $gsSharesRequest;
+ }
+
+
+ /**
+ * @param int $gsShareId
+ * @param string $target
+ *
+ * @return bool
+ */
+ public function renameShare(int $gsShareId, string $target) {
+ try {
+ if ($target !== '-') {
+ $target = $this->stripPath($target);
+ $this->gsSharesRequest->getShareMountPointByPath($this->userId, $target);
+
+ return false;
+ }
+ } catch (ShareNotFound $e) {
+ }
+
+ $mountPoint = new GSShareMountpoint($gsShareId, $this->userId, $target);
+ try {
+ $this->gsSharesRequest->getShareMountPointById($gsShareId, $this->userId);
+ $this->gsSharesRequest->updateShareMountPoint($mountPoint);
+ } catch (ShareNotFound $e) {
+ $this->gsSharesRequest->generateShareMountPoint($mountPoint);
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param int $gsShareId
+ *
+ * @return bool
+ */
+ public function unshare(int $gsShareId) {
+ return $this->renameShare($gsShareId, '-');
+ }
+
+
+ /**
+ * remove '/user/files' from the path and trailing slashes
+ *
+ * @param string $path
+ *
+ * @return string
+ */
+ protected function stripPath($path) {
+ $prefix = '/' . $this->userId . '/files';
+
+ return rtrim(substr($path, strlen($prefix)), '/');
+ }
+
+
+}
diff --git a/lib/GlobalScale/GSMount/MountProvider.php b/lib/GlobalScale/GSMount/MountProvider.php
new file mode 100644
index 00000000..85574f57
--- /dev/null
+++ b/lib/GlobalScale/GSMount/MountProvider.php
@@ -0,0 +1,131 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @copyright 2020
+ * @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\Circles\GlobalScale\GSMount;
+
+
+use Exception;
+use OC;
+use OCA\Circles\Db\GSSharesRequest;
+use OCA\Circles\Model\GlobalScale\GSShare;
+use OCP\AppFramework\QueryException;
+use OCP\Federation\ICloudIdManager;
+use OCP\Files\Config\IMountProvider;
+use OCP\Files\Mount\IMountPoint;
+use OCP\Files\Storage\IStorageFactory;
+use OCP\IUser;
+
+
+/**
+ * Class MountProvider
+ *
+ * @package OCA\Circles\GlobalScale\GSMount
+ */
+class MountProvider implements IMountProvider {
+
+
+ const STORAGE = '\OCA\Files_Sharing\External\Storage';
+
+
+ /** @var MountManager */
+ private $mountManager;
+
+ /** @var ICloudIdManager */
+ private $cloudIdManager;
+
+ /** @var GSSharesRequest */
+ private $gsSharesRequest;
+
+
+ /**
+ * MountProvider constructor.
+ *
+ * @param MountManager $mountManager
+ * @param ICloudIdManager $cloudIdManager
+ * @param GSSharesRequest $gsSharesRequest
+ */
+ public function __construct(
+ MountManager $mountManager, ICloudIdManager $cloudIdManager, GSSharesRequest $gsSharesRequest
+ ) {
+ $this->mountManager = $mountManager;
+ $this->cloudIdManager = $cloudIdManager;
+ $this->gsSharesRequest = $gsSharesRequest;
+ }
+
+
+ /**
+ * @param IUser $user
+ * @param IStorageFactory $loader
+ *
+ * @return IMountPoint[]
+ * @throws QueryException
+ */
+ public function getMountsForUser(IUser $user, IStorageFactory $loader): array {
+ $shares = $this->gsSharesRequest->getForUser($user->getUID());
+
+ $mounts = [];
+ foreach ($shares as $share) {
+ try {
+ if ($share->getMountPoint() !== '-') {
+ $mounts[] = $this->generateMount($share, $user->getUID(), $loader);
+ }
+ } catch (Exception $e) {
+ }
+ }
+
+ return $mounts;
+ }
+
+
+ /**
+ * @param GSShare $share
+ * @param string $userId
+ * @param IStorageFactory $storageFactory
+ *
+ * @return Mount
+ * @throws Exception
+ */
+ public function generateMount(
+ GSShare $share, string $userId, IStorageFactory $storageFactory
+ ) {
+ // might be better to test https first, then http. as this would only work from webclient !
+ $data = $share->toMount($userId, $_SERVER['REQUEST_SCHEME']);
+ $data['manager'] = $this->mountManager;
+ $data['gsShareId'] = $share->getId();
+ $data['cloudId'] = $this->cloudIdManager->getCloudId($data['owner'], $data['remote']);
+ $data['certificateManager'] = OC::$server->getCertificateManager($userId);
+ $data['HttpClientService'] = OC::$server->getHTTPClientService();
+
+ return new Mount(
+ self::STORAGE, $share->getMountPoint($userId), $data, $this->mountManager, $storageFactory
+ );
+ }
+
+}
+
diff --git a/lib/GlobalScale/GlobalSync.php b/lib/GlobalScale/GlobalSync.php
new file mode 100644
index 00000000..466ab61d
--- /dev/null
+++ b/lib/GlobalScale/GlobalSync.php
@@ -0,0 +1,173 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleAlreadyExistsException;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberDoesNotExistException;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class MemberCreate
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class GlobalSync extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ public function manage(GSEvent $event): void {
+ $data = $event->getData();
+ $circles = [];
+ foreach ($data->gAll() as $circle) {
+ $circle = Circle::fromArray($circle);
+ $circles[] = $circle;
+
+ $this->syncCircle($circle, $event->getSource());
+ $this->removeDeprecateMembers($circle, $event->getSource());
+ }
+
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+
+
+ /**
+ * @param Circle $circle
+ * @param string $source
+ */
+ private function syncCircle(Circle $circle, string $source): void {
+ try {
+ $knownCircle = $this->circlesRequest->forceGetCircle($circle->getUniqueId());
+
+ if (!$this->compareCircles($knownCircle, $circle)) {
+ try {
+ $this->circlesRequest->updateCircle($circle);
+ } catch (CircleAlreadyExistsException $e) {
+ }
+ }
+ } catch (CircleDoesNotExistException $e) {
+ try {
+ $this->circlesRequest->createCircle($circle);
+ } catch (CircleAlreadyExistsException $e) {
+ }
+ }
+
+ foreach ($circle->getMembers() as $member) {
+ if ($member->getInstance() === '') {
+ $member->setInstance($source);
+ }
+
+ try {
+ $knownMember = $this->membersRequest->forceGetMember(
+ $circle->getUniqueId(), $member->getUserId(), $member->getType(), $member->getInstance()
+ );
+
+ if ($this->compareMembers($knownMember, $member)) {
+ continue;
+ }
+
+ $this->miscService->log(
+ 'updating member :' . json_encode($member) . ' from ' . json_encode($knownMember), 2
+ );
+ $this->membersRequest->updateMember($member);
+ } catch (MemberDoesNotExistException $e) {
+ try {
+ $this->miscService->log(
+ 'creating member :' . json_encode($member), 2
+ );
+ $this->membersRequest->createMember($member);
+ } catch (MemberAlreadyExistsException $e) {
+ }
+ }
+ }
+
+ }
+
+
+ private function removeDeprecateMembers(Circle $circle, string $source): void {
+ $knownMembers = $this->membersRequest->forceGetMembers($circle->getUniqueId());
+
+ foreach ($knownMembers as $knownItem) {
+ try {
+ $this->getMember($knownItem, $circle->getMembers(), $source);
+ } catch (MemberDoesNotExistException $e) {
+ $this->miscService->log('removing deprecated member :' . json_encode($knownItem), 2);
+ $this->membersRequest->removeMember($knownItem);
+ $this->gsSharesRequest->removeGSSharesFromMember($knownItem);
+ }
+ }
+ }
+
+
+ /**
+ * @param Member $item
+ * @param Member[] $members
+ * @param string $source
+ *
+ * @throws MemberDoesNotExistException
+ */
+ private function getMember(Member $item, array $members, string $source) {
+ foreach ($members as $member) {
+ if ($member->getInstance() === '') {
+ $member->setInstance($source);
+ }
+
+ if ($this->compareMembers($member, $item)) {
+ return;
+ }
+ }
+
+ throw new MemberDoesNotExistException();
+ }
+
+}
+
diff --git a/lib/GlobalScale/MemberAdd.php b/lib/GlobalScale/MemberAdd.php
new file mode 100644
index 00000000..5332dbba
--- /dev/null
+++ b/lib/GlobalScale/MemberAdd.php
@@ -0,0 +1,137 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use daita\MySmallPhpTools\Model\SimpleDataStore;
+use OC\User\NoUserException;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\CircleTypeNotValidException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\EmailAccountInvalidFormatException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberCantJoinCircleException;
+use OCA\Circles\Exceptions\MemberIsNotModeratorException;
+use OCA\Circles\Exceptions\MembersLimitException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+
+
+/**
+ * Class MemberAdd
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class MemberAdd extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ *
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws EmailAccountInvalidFormatException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ * @throws MemberAlreadyExistsException
+ * @throws MemberCantJoinCircleException
+ * @throws MembersLimitException
+ * @throws NoUserException
+ * @throws CircleTypeNotValidException
+ * @throws MemberIsNotModeratorException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ parent::verify($event, $localCheck, true);
+
+ $eventMember = $event->getMember();
+ $this->cleanMember($eventMember);
+
+ if ($eventMember->getInstance() === '') {
+ $eventMember->setInstance($event->getSource());
+ }
+
+ $ident = $eventMember->getUserId();
+ $this->membersService->verifyIdentBasedOnItsType(
+ $ident, $eventMember->getType(), $eventMember->getInstance()
+ );
+
+ $circle = $event->getCircle();
+ if (!$event->isForced()) {
+ $circle->getHigherViewer()
+ ->hasToBeModerator();
+ }
+
+ $member = $this->membersRequest->getFreshNewMember(
+ $circle->getUniqueId(), $ident, $eventMember->getType(), $eventMember->getInstance()
+ );
+ $member->hasToBeInviteAble();
+
+ $this->circlesService->checkThatCircleIsNotFull($circle);
+ $this->membersService->addMemberBasedOnItsType($circle, $member);
+
+ $event->setMember($member);
+
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws MemberAlreadyExistsException
+ */
+ public function manage(GSEvent $event): void {
+ $circle = $event->getCircle();
+ $member = $event->getMember();
+ if ($member->getJoined() === '') {
+ $this->membersRequest->createMember($member);
+ } else {
+ $this->membersRequest->updateMember($member);
+ }
+
+ $this->eventsService->onMemberNew($circle, $member);
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ // $instances = array_keys($events);
+// foreach ($instances as $instance) {
+// $event = $events[$instance];
+// $this->miscService->log('---- ' . $instance . ' -- ' . json_encode($event->getResult()));
+// }
+ }
+
+}
+
diff --git a/lib/GlobalScale/MemberJoin.php b/lib/GlobalScale/MemberJoin.php
new file mode 100644
index 00000000..5848e7c4
--- /dev/null
+++ b/lib/GlobalScale/MemberJoin.php
@@ -0,0 +1,116 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use daita\MySmallPhpTools\Model\SimpleDataStore;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberCantJoinCircleException;
+use OCA\Circles\Exceptions\MemberIsBlockedException;
+use OCA\Circles\Exceptions\MembersLimitException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class MemberJoin
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class MemberJoin extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ *
+ * @throws MemberAlreadyExistsException
+ * @throws MemberCantJoinCircleException
+ * @throws MemberIsBlockedException
+ * @throws MembersLimitException
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ parent::verify($event, false, false);
+
+ $circle = $event->getCircle();
+ $eventMember = $event->getMember();
+
+ $member = $this->membersRequest->getFreshNewMember(
+ $circle->getUniqueId(), $eventMember->getUserId(), Member::TYPE_USER, $eventMember->getInstance()
+ );
+ $member->hasToBeAbleToJoinTheCircle();
+ $member->joinCircle($circle->getType());
+
+ $this->circlesService->checkThatCircleIsNotFull($circle);
+ $event->setMember($member);
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws MemberAlreadyExistsException
+ */
+ public function manage(GSEvent $event): void {
+ $circle = $event->getCircle();
+ $member = $event->getMember();
+
+ if ($member->getJoined() === '') {
+ $this->membersRequest->createMember($member);
+ } else {
+ $this->membersRequest->updateMember($member);
+ }
+
+ $this->eventsService->onMemberNew($circle, $member);
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+// $instances = array_keys($events);
+// foreach ($instances as $instance) {
+// $event = $events[$instance];
+// $this->miscService->log('---- ' . $instance . ' -- ' . json_encode($event->getResult()));
+// }
+ }
+
+}
+
diff --git a/lib/GlobalScale/MemberLeave.php b/lib/GlobalScale/MemberLeave.php
new file mode 100644
index 00000000..faab541b
--- /dev/null
+++ b/lib/GlobalScale/MemberLeave.php
@@ -0,0 +1,94 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\MemberDoesNotExistException;
+use OCA\Circles\Exceptions\MemberIsOwnerException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+
+
+/**
+ * Class MemberLeave
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class MemberLeave extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ *
+ * @throws MemberDoesNotExistException
+ * @throws MemberIsOwnerException
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ parent::verify($event, $localCheck, true);
+
+ $member = $event->getMember();
+
+ $member->hasToBeMemberOrAlmost();
+ $member->cantBeOwner();
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ public function manage(GSEvent $event): void {
+ $circle = $event->getCircle();
+ $member = $event->getMember();
+
+ $this->eventsService->onMemberLeaving($circle, $member);
+
+ $this->membersRequest->removeMember($member);
+ $this->sharesRequest->removeSharesFromMember($member);
+ $this->gsSharesRequest->removeGSSharesFromMember($member);
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+
+}
+
diff --git a/lib/GlobalScale/MemberLevel.php b/lib/GlobalScale/MemberLevel.php
new file mode 100644
index 00000000..d2f69b90
--- /dev/null
+++ b/lib/GlobalScale/MemberLevel.php
@@ -0,0 +1,182 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use Exception;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\MemberDoesNotExistException;
+use OCA\Circles\Exceptions\MemberIsNotModeratorException;
+use OCA\Circles\Exceptions\MemberIsNotOwnerException;
+use OCA\Circles\Exceptions\MemberIsOwnerException;
+use OCA\Circles\Exceptions\MemberTypeCantEditLevelException;
+use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class MemberLevel
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class MemberLevel extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ *
+ * @param bool $mustBeChecked
+ *
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ * @throws MemberTypeCantEditLevelException
+ * @throws Exception
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = true): void {
+ parent::verify($event, $localCheck, true);
+
+ $member = $event->getMember();
+ $level = $event->getData()
+ ->gInt('level');
+ if ($member->getLevel() === $level) {
+ throw new GlobalScaleDSyncException('level is not changed during the process');
+ }
+
+ $member->levelHasToBeEditable();
+ $circle = $event->getCircle();
+
+ if ($level === Member::LEVEL_OWNER) {
+ $this->verifySwitchOwner($event, $circle, $member);
+ } else {
+ $this->verifyMemberLevel($event, $circle, $member, $level);
+ }
+
+ $this->miscService->log('$$$$ 3 ' . json_encode($event));
+
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws Exception
+ */
+ public function manage(GSEvent $event): void {
+ $level = $event->getData()
+ ->gInt('level');
+
+ $this->miscService->log('$$$$ 4 ' . json_encode($event));
+
+ $member = $event->getMember();
+ $this->cleanMember($member);
+ $this->miscService->log('$$$$ 5 ' . json_encode($event));
+
+ $member->setLevel($level);
+ $this->membersRequest->updateMember($member);
+
+ $this->miscService->log('#### ' . json_encode($event));
+ if ($level === Member::LEVEL_OWNER) {
+ $circle = $event->getCircle();
+ $isMod = $circle->getOwner();
+ if ($isMod->getInstance() === '') {
+ $isMod->setInstance($event->getSource());
+ }
+
+ $this->miscService->log('???? ' . $isMod->getInstance());
+
+ $isMod->setLevel(Member::LEVEL_ADMIN);
+ $this->miscService->log('#### 001 ' . json_encode($event));
+
+ $this->membersRequest->updateMember($isMod);
+ $this->miscService->log('#### 002 ' . json_encode($event));
+
+ }
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+
+
+ /**
+ * @param GSEvent $event
+ * @param Circle $circle
+ * @param Member $member
+ * @param int $level
+ *
+ * @throws MemberDoesNotExistException
+ * @throws MemberIsOwnerException
+ * @throws MemberIsNotModeratorException
+ * @throws ModeratorIsNotHighEnoughException
+ */
+ private function verifyMemberLevel(GSEvent $event, Circle $circle, Member &$member, int $level) {
+ $member->hasToBeMember();
+ $member->cantBeOwner();
+
+ if (!$event->isForced()) {
+ $isMod = $circle->getHigherViewer();
+ $isMod->hasToBeModerator();
+ $isMod->hasToBeHigherLevel($level);
+ $isMod->hasToBeHigherLevel($member->getLevel());
+ }
+ }
+
+ /**
+ * @param GSEvent $event
+ * @param Circle $circle
+ * @param Member $member
+ *
+ * @throws MemberDoesNotExistException
+ * @throws MemberIsNotOwnerException
+ * @throws MemberIsOwnerException
+ */
+ private function verifySwitchOwner(GSEvent $event, Circle $circle, Member &$member) {
+ if (!$event->isForced()) {
+ $isMod = $circle->getHigherViewer();
+ $this->circlesService->hasToBeOwner($isMod);
+ }
+
+ $member->hasToBeMember();
+ $member->cantBeOwner();
+ }
+
+}
+
diff --git a/lib/GlobalScale/MemberRemove.php b/lib/GlobalScale/MemberRemove.php
new file mode 100644
index 00000000..34580461
--- /dev/null
+++ b/lib/GlobalScale/MemberRemove.php
@@ -0,0 +1,110 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\GlobalScale;
+
+
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberDoesNotExistException;
+use OCA\Circles\Exceptions\MemberIsNotModeratorException;
+use OCA\Circles\Exceptions\MemberIsOwnerException;
+use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+
+
+/**
+ * Class MemberDelete
+ *
+ * @package OCA\Circles\GlobalScale
+ */
+class MemberRemove extends AGlobalScaleEvent {
+
+
+ /**
+ * @param GSEvent $event
+ * @param bool $localCheck
+ * @param bool $mustBeChecked
+ *
+ * @throws MemberDoesNotExistException
+ * @throws MemberIsNotModeratorException
+ * @throws MemberIsOwnerException
+ * @throws ModeratorIsNotHighEnoughException
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ public function verify(GSEvent $event, bool $localCheck = false, bool $mustBeChecked = false): void {
+ parent::verify($event, $localCheck, true);
+
+ $circle = $event->getCircle();
+ $member = $event->getMember();
+
+ $member->hasToBeMemberOrAlmost();
+ $member->cantBeOwner();
+
+ if (!$event->isForced()) {
+ $circle->getHigherViewer()
+ ->hasToBeModerator();
+ $circle->getHigherViewer()
+ ->hasToBeHigherLevel($member->getLevel());
+ }
+ }
+
+
+ /**
+ * @param GSEvent[] $events
+ */
+ public function result(array $events): void {
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws MemberAlreadyExistsException
+ */
+ public function manage(GSEvent $event): void {
+ $circle = $event->getCircle();
+ $member = $event->getMember();
+
+ $this->eventsService->onMemberLeaving($circle, $member);
+ $this->membersRequest->removeMember($member);
+
+ $this->gsSharesRequest->removeGSSharesFromMember($member);
+ $this->sharesRequest->removeSharesFromMember($member);
+ $this->tokensRequest->removeTokensFromMember($member);
+ }
+
+}
+
diff --git a/lib/Migration/Version0017Date20191210153032.php b/lib/Migration/Version0017Date20191210153032.php
new file mode 100644
index 00000000..e9843bc7
--- /dev/null
+++ b/lib/Migration/Version0017Date20191210153032.php
@@ -0,0 +1,198 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Migration;
+
+
+use Closure;
+use Doctrine\DBAL\Schema\SchemaException;
+use OCP\DB\ISchemaWrapper;
+use OCP\Migration\IOutput;
+use OCP\Migration\SimpleMigrationStep;
+
+
+class Version0017Date20191210153032 extends SimpleMigrationStep {
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function preSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
+ }
+
+ /**
+ * @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();
+
+ if (!$schema->hasTable('circles_gsevents')) {
+ $table = $schema->createTable('circles_gsevents');
+ $table->addColumn(
+ 'token', 'string', [
+ 'notnull' => false,
+ 'length' => 63,
+ ]
+ );
+ $table->addColumn(
+ 'event', 'text', [
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'instance', 'string', [
+ 'length' => 255,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'severity', 'integer', [
+ 'length' => 3,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'status', 'integer', [
+ 'length' => 3,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'creation', 'bigint', [
+ 'length' => 14,
+ 'notnull' => false
+ ]
+ );
+ $table->addUniqueIndex(['token', 'instance']);
+ }
+
+ if (!$schema->hasTable('circles_gsshares')) {
+ $table = $schema->createTable('circles_gsshares');
+ $table->addColumn(
+ 'id', 'integer', [
+ 'notnull' => false,
+ 'length' => 11,
+ 'autoincrement' => true,
+ 'unsigned' => true
+ ]
+ );
+ $table->addColumn(
+ 'circle_id', 'string', [
+ 'length' => 15,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'owner', 'string', [
+ 'length' => 15,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'instance', 'string', [
+ 'length' => 255,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'token', 'string', [
+ 'notnull' => false,
+ 'length' => 63
+ ]
+ );
+ $table->addColumn(
+ 'parent', 'integer', [
+ 'notnull' => false,
+ 'length' => 11,
+ ]
+ );
+ $table->addColumn(
+ 'mountpoint', 'text', [
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'mountpoint_hash', 'string', [
+ 'length' => 64,
+ 'notnull' => false
+ ]
+ );
+ $table->setPrimaryKey(['id']);
+ $table->addUniqueIndex(['circle_id', 'mountpoint_hash']);
+ }
+
+ if (!$schema->hasTable('circles_gsshares_mp')) {
+ $table = $schema->createTable('circles_gsshares_mp');
+ $table->addColumn(
+ 'share_id', 'integer', [
+ 'length' => 11,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'user_id', 'string', [
+ 'length' => 127,
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'mountpoint', 'text', [
+ 'notnull' => false
+ ]
+ );
+ $table->addColumn(
+ 'mountpoint_hash', 'string', [
+ 'length' => 64,
+ 'notnull' => false
+ ]
+ );
+ $table->setPrimaryKey(['share_id', 'user_id']);
+ }
+
+ return $schema;
+ }
+
+
+ /**
+ * @param IOutput $output
+ * @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
+ * @param array $options
+ */
+ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
+ }
+
+}
+
diff --git a/lib/Model/BaseCircle.php b/lib/Model/BaseCircle.php
index 523662cf..b8802589 100644
--- a/lib/Model/BaseCircle.php
+++ b/lib/Model/BaseCircle.php
@@ -53,7 +53,7 @@ class BaseCircle {
protected $l10n;
/** @var string */
- private $uniqueId;
+ private $uniqueId = '';
/** @var string */
private $name;
@@ -62,7 +62,7 @@ class BaseCircle {
private $owner;
/** @var Member */
- private $viewer;
+ private $viewer = null;
/** @var Member */
private $viewerGroup;
@@ -210,6 +210,12 @@ class BaseCircle {
return $this;
}
+
+ public function hasViewer(): bool {
+ return ($this->viewer !== null);
+ }
+
+
/**
* @return Member
*/
@@ -436,7 +442,7 @@ class BaseCircle {
}
/**
- * @return array
+ * @return Member[]
*/
public function getMembers() {
return $this->members;
diff --git a/lib/Model/BaseMember.php b/lib/Model/BaseMember.php
index d37596ee..af1cb21c 100644
--- a/lib/Model/BaseMember.php
+++ b/lib/Model/BaseMember.php
@@ -87,7 +87,10 @@ class BaseMember implements \JsonSerializable {
private $note;
/** @var string */
- private $joined;
+ private $instance = '';
+
+ /** @var string */
+ private $joined = '';
/** @var int */
private $joinedSince;
@@ -228,6 +231,17 @@ class BaseMember implements \JsonSerializable {
}
+ public function setInstance($instance) {
+ $this->instance = $instance;
+
+ return $this;
+ }
+
+ public function getInstance() {
+ return $this->instance;
+ }
+
+
public function setContactId($contactId) {
$this->contactId = $contactId;
@@ -367,13 +381,16 @@ class BaseMember implements \JsonSerializable {
$member = new Member();
$member->setCircleId($arr['circle_id']);
+ $member->setMemberId($arr['member_id']);
$member->setLevel($arr['level']);
$member->setType(MiscService::get($arr, 'user_type'));
$member->setType(MiscService::get($arr, 'type', $member->getType()));
+ $member->setInstance($arr['instance']);
$member->setUserId($arr['user_id']);
$member->setStatus($arr['status']);
+ $member->setInstance($arr['instance']);
$member->setNote($arr['note']);
$member->setJoined($arr['joined']);
@@ -402,6 +419,7 @@ class BaseMember implements \JsonSerializable {
'level' => $this->getLevel(),
'level_string' => $this->getLevelString(),
'status' => $this->getStatus(),
+ 'instance' => $this->getInstance(),
'note' => $this->getNote(),
'joined' => $this->getJoined()
];
diff --git a/lib/Model/Circle.php b/lib/Model/Circle.php
index 506ee313..82868777 100644
--- a/lib/Model/Circle.php
+++ b/lib/Model/Circle.php
@@ -26,11 +26,16 @@
namespace OCA\Circles\Model;
+use daita\MySmallPhpTools\Traits\TArrayTools;
use OCA\Circles\Exceptions\CircleTypeNotValidException;
use OCA\Circles\Exceptions\FederatedCircleNotAllowedException;
class Circle extends BaseCircle implements \JsonSerializable {
+
+ use TArrayTools;
+
+
/** @var bool */
private $fullJson = false;
@@ -65,6 +70,18 @@ class Circle extends BaseCircle implements \JsonSerializable {
}
+ /**
+ * @param bool $fullJson
+ *
+ * @return $this
+ */
+ public function setFullJson(bool $fullJson): self {
+ $this->fullJson = $fullJson;
+
+ return $this;
+ }
+
+
public function jsonSerialize() {
$json = [
'id' => $this->getId(),
@@ -123,7 +140,7 @@ class Circle extends BaseCircle implements \JsonSerializable {
* @return $this
*/
public static function fromArray($arr) {
- if ($arr === null) {
+ if ($arr === null || empty($arr)) {
return new Circle();
}
@@ -140,6 +157,15 @@ class Circle extends BaseCircle implements \JsonSerializable {
$circle->setViewer(self::getMemberFromArray($arr, 'user'));
$circle->setOwner(self::getMemberFromArray($arr, 'owner'));
+ if (array_key_exists('members', $arr) && is_array($arr['members'])) {
+ $members = [];
+ foreach ($arr['members'] as $item) {
+ $members[] = Member::fromArray($item);
+ }
+ $circle->setMembers($members);
+ }
+
+
return $circle;
}
diff --git a/lib/Model/GlobalScale/GSEvent.php b/lib/Model/GlobalScale/GSEvent.php
new file mode 100644
index 00000000..41748335
--- /dev/null
+++ b/lib/Model/GlobalScale/GSEvent.php
@@ -0,0 +1,428 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Model\GlobalScale;
+
+
+use daita\MySmallPhpTools\Model\SimpleDataStore;
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use JsonSerializable;
+use OCA\Circles\Exceptions\JsonException;
+use OCA\Circles\Exceptions\ModelException;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\Member;
+
+
+/**
+ * Class GSEvent
+ *
+ * @package OCA\Circles\Model\GlobalScale
+ */
+class GSEvent implements JsonSerializable {
+
+
+ const SEVERITY_LOW = 1;
+ const SEVERITY_HIGH = 3;
+
+ const GLOBAL_SYNC = 'GlobalScale\GlobalSync';
+ const CIRCLE_STATUS = 'GlobalScale\CircleStatus';
+
+ const CIRCLE_CREATE = 'GlobalScale\CircleCreate';
+ const CIRCLE_UPDATE = 'GlobalScale\CircleUpdate';
+ const CIRCLE_DESTROY = 'GlobalScale\CircleDestroy';
+ const MEMBER_ADD = 'GlobalScale\MemberAdd';
+ const MEMBER_JOIN = 'GlobalScale\MemberJoin';
+ const MEMBER_INVITE = 'GlobalScale\MemberInvite';
+ const MEMBER_LEAVE = 'GlobalScale\MemberLeave';
+ const MEMBER_LEVEL = 'GlobalScale\MemberLevel';
+ const MEMBER_UPDATE = 'GlobalScale\MemberUpdate';
+ const MEMBER_REMOVE = 'GlobalScale\MemberRemove';
+
+ const FILE_SHARE = 'GlobalScale\FileShare';
+
+
+ use TArrayTools;
+
+
+ /** @var string */
+ private $type = '';
+
+ /** @var string */
+ private $source = '';
+
+ /** @var Circle */
+ private $circle;
+
+ /** @var Member */
+ private $member;
+
+ /** @var SimpleDataStore */
+ private $data;
+
+ /** @var int */
+ private $severity = self::SEVERITY_LOW;
+
+ /** @var SimpleDataStore */
+ private $result;
+
+ /** @var string */
+ private $key = '';
+
+ /** @var bool */
+ private $local = false;
+
+ /** @var bool */
+ private $force = false;
+
+
+ /**
+ * GSEvent constructor.
+ *
+ * @param string $type
+ * @param bool $local
+ * @param bool $force
+ */
+ function __construct(string $type = '', bool $local = false, bool $force = false) {
+ $this->type = $type;
+ $this->local = $local;
+ $this->force = $force;
+ $this->data = new SimpleDataStore();
+ $this->result = new SimpleDataStore();
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getType(): string {
+ return $this->type;
+ }
+
+ /**
+ * @param mixed $type
+ *
+ * @return GSEvent
+ */
+ public function setType($type): self {
+ $this->type = $type;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getSource(): string {
+ return $this->source;
+ }
+
+ /**
+ * @param string $source
+ *
+ * @return GSEvent
+ */
+ public function setSource(string $source): self {
+ $this->source = $source;
+
+ if ($this->hasMember() && $this->member->getInstance() === '') {
+ $this->member->setInstance($source);
+ }
+
+ if ($this->hasCircle()
+ && $this->getCircle()
+ ->hasViewer()
+ && $this->getCircle()
+ ->getViewer()
+ ->getInstance() === '') {
+ $this->getCircle()
+ ->getViewer()
+ ->setInstance($source);
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isLocal(): bool {
+ return $this->local;
+ }
+
+ /**
+ * @param bool $local
+ *
+ * @return GSEvent
+ */
+ public function setLocal(bool $local): self {
+ $this->local = $local;
+
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isForced(): bool {
+ return $this->force;
+ }
+
+ /**
+ * @param bool $force
+ *
+ * @return GSEvent
+ */
+ public function setForced(bool $force): self {
+ $this->force = $force;
+
+ return $this;
+ }
+
+
+ /**
+ * @return Circle
+ */
+ public function getCircle(): Circle {
+ return $this->circle;
+ }
+
+ /**
+ * @param Circle $circle
+ *
+ * @return GSEvent
+ */
+ public function setCircle(Circle $circle): self {
+ $this->circle = $circle;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasCircle(): bool {
+ return ($this->circle !== null);
+ }
+
+
+ /**
+ * @return Member
+ */
+ public function getMember(): Member {
+ return $this->member;
+ }
+
+ /**
+ * @param Member $member
+ *
+ * @return GSEvent
+ */
+ public function setMember(Member $member): self {
+ $this->member = $member;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasMember(): bool {
+ return ($this->member !== null);
+ }
+
+
+ /**
+ * @param SimpleDataStore $data
+ *
+ * @return GSEvent
+ */
+ public function setData(SimpleDataStore $data): self {
+ $this->data = $data;
+
+ return $this;
+ }
+
+ /**
+ * @return SimpleDataStore
+ */
+ public function getData(): SimpleDataStore {
+ return $this->data;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getSeverity(): int {
+ return $this->severity;
+ }
+
+ /**
+ * @param int $severity
+ *
+ * @return GSEvent
+ */
+ public function setSeverity(int $severity): self {
+ $this->severity = $severity;
+
+ return $this;
+ }
+
+
+ /**
+ * @return SimpleDataStore
+ */
+ public function getResult(): SimpleDataStore {
+ return $this->result;
+ }
+
+ /**
+ * @param SimpleDataStore $result
+ *
+ * @return GSEvent
+ */
+ public function setResult(SimpleDataStore $result): self {
+ $this->result = $result;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getKey(): string {
+ return $this->key;
+ }
+
+ /**
+ * @param string $key
+ *
+ * @return GSEvent
+ */
+ public function setKey(string $key): self {
+ $this->key = $key;
+
+ return $this;
+ }
+
+
+ /**
+ * @return bool
+ */
+ public function isValid(): bool {
+ if ($this->getType() === '') {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
+ * @param string $json
+ *
+ * @return GSEvent
+ * @throws JsonException
+ * @throws ModelException
+ */
+ public function importFromJson(string $json): self {
+ $data = json_decode($json, true);
+
+ if (!is_array($data)) {
+ throw new JsonException('invalid JSON');
+ }
+
+ return $this->import($data);
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSEvent
+ * @throws ModelException
+ */
+ public function import(array $data): self {
+ $this->setType($this->get('type', $data));
+ $this->setSeverity($this->getInt('severity', $data));
+ $this->setData(new SimpleDataStore($this->getArray('data', $data)));
+ $this->setResult(new SimpleDataStore($this->getArray('result', $data)));
+ $this->setSource($this->get('source', $data));
+ $this->setKey($this->get('key', $data));
+ $this->setForced($this->getBool('force', $data));
+
+ if (array_key_exists('circle', $data)) {
+ $this->setCircle(Circle::fromArray($data['circle']));
+ }
+
+ if (array_key_exists('member', $data)) {
+ $this->setMember(Member::fromArray($data['member']));
+ }
+
+ if (!$this->isValid()) {
+ throw new ModelException('invalid GSEvent');
+ }
+
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ function jsonSerialize(): array {
+ $arr = [
+ 'type' => $this->getType(),
+ 'severity' => $this->getSeverity(),
+ 'data' => $this->getData(),
+ 'result' => $this->getResult(),
+ 'key' => $this->getKey(),
+ 'source' => $this->getSource(),
+ 'force' => $this->isForced()
+ ];
+
+ if ($this->hasCircle()) {
+ $arr['circle'] = $this->getCircle();
+ }
+ if ($this->hasMember()) {
+ $arr['member'] = $this->getMember();
+ }
+
+ $this->cleanArray($arr);
+
+ return $arr;
+ }
+
+
+}
+
diff --git a/lib/Model/GlobalScale/GSShare.php b/lib/Model/GlobalScale/GSShare.php
new file mode 100644
index 00000000..bc3472d6
--- /dev/null
+++ b/lib/Model/GlobalScale/GSShare.php
@@ -0,0 +1,322 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Model\GlobalScale;
+
+
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use JsonSerializable;
+
+
+/**
+ * Class GSShare
+ *
+ * @package OCA\Circles\Model\GlobalScale
+ */
+class GSShare implements JsonSerializable {
+
+
+ use TArrayTools;
+
+
+ /** @var int */
+ private $id = 0;
+
+ /** @var string */
+ private $circleId = '';
+
+ /** @var string */
+ private $defaultMountPoint = '';
+
+ /** @var string */
+ private $mountPoint = '';
+
+ /** @var int */
+ private $parent = -1;
+
+ /** @var string */
+ private $owner = '';
+
+ /** @var string */
+ private $instance = '';
+
+ /** @var string */
+ private $token = '';
+
+ /** @var string */
+ private $password = '';
+
+
+ /**
+ * GSShare constructor.
+ *
+ * @param string $circleId
+ * @param string $token
+ */
+ public function __construct(string $circleId = '', string $token = '') {
+ $this->circleId = $circleId;
+ $this->token = $token;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getId(): int {
+ return $this->id;
+ }
+
+ public function setId(int $id): self {
+ $this->id = $id;
+
+ return $this;
+ }
+
+
+ /**
+ *
+ * @return string
+ */
+ public function getCircleId(): string {
+ return $this->circleId;
+ }
+
+ /**
+ * @param string $circleId
+ *
+ * @return GSShare
+ */
+ public function setCircleId(string $circleId): self {
+ $this->circleId = $circleId;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getDefaultMountPoint(): string {
+ return $this->defaultMountPoint;
+ }
+
+ /**
+ * @param string $mountPoint
+ *
+ * @return GSShare
+ */
+ public function setDefaultMountPoint(string $mountPoint): self {
+ $this->defaultMountPoint = $mountPoint;
+
+ return $this;
+ }
+
+
+ /**
+ * @param string $userId
+ *
+ * @return string
+ */
+ public function getMountPoint(string $userId = ''): string {
+ $mountPoint = $this->mountPoint;
+
+ if ($mountPoint === '') {
+ $mountPoint = $this->defaultMountPoint;
+ }
+
+ if ($userId === '') {
+ return $mountPoint;
+ }
+
+ return '/' . $userId . '/files/' . ltrim($mountPoint, '/');
+ }
+
+ /**
+ * @param string $mountPoint
+ *
+ * @return GSShare
+ */
+ public function setMountPoint(string $mountPoint): self {
+ $this->mountPoint = $mountPoint;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getParent(): int {
+ return $this->parent;
+ }
+
+ /**
+ * @param int $parent
+ *
+ * @return GSShare
+ */
+ public function setParent(int $parent): self {
+ $this->parent = $parent;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getOwner(): string {
+ return $this->owner;
+ }
+
+ /**
+ * @param string $owner
+ *
+ * @return GSShare
+ */
+ public function setOwner(string $owner): self {
+ $this->owner = $owner;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getInstance(): string {
+ return $this->instance;
+ }
+
+ /**
+ * @param string $instance
+ *
+ * @return GSShare
+ */
+ public function setInstance(string $instance): self {
+ $this->instance = $instance;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getToken(): string {
+ return $this->token;
+ }
+
+
+ /**
+ * @param string $token
+ *
+ * @return GSShare
+ */
+ public function setToken(string $token): self {
+ $this->token = $token;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getPassword(): string {
+ return $this->password;
+ }
+
+ /**
+ * @param string $password
+ *
+ * @return GSShare
+ */
+ public function setPassword(string $password): self {
+ $this->password = $password;
+
+ return $this;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSShare
+ */
+ public function importFromDatabase(array $data): self {
+ $this->setId($this->getInt('id', $data));
+ $this->setCircleId($this->get('circle_id', $data));
+ $this->setOwner($this->get('owner', $data));
+ $this->setInstance($this->get('instance', $data));
+ $this->setToken($this->get('token', $data));
+ $this->setParent($this->getInt('parent', $data));
+ $this->setMountPoint($this->get('gsshares_mountpoint', $data));
+ $this->setDefaultMountPoint($this->get('mountpoint', $data));
+
+ return $this;
+ }
+
+
+ /**
+ * @param string $userId
+ * @param string $protocol
+ *
+ * @return array
+ */
+ public function toMount(string $userId, string $protocol = 'https'): array {
+ return [
+ 'owner' => $this->getOwner(),
+ 'remote' => $protocol . '://' . $this->getInstance(),
+ 'token' => $this->getToken(),
+ 'share_token' => $this->getToken(),
+ 'password' => $this->getPassword(),
+ 'mountpoint' => $this->getMountPoint($userId)
+ ];
+ }
+
+
+ /**
+ * @return array
+ */
+ function jsonSerialize(): array {
+ return [
+ 'id' => $this->getId(),
+ 'defaultMountPoint' => $this->getDefaultMountPoint(),
+ 'mountPoint' => $this->getMountPoint(),
+ 'parent' => $this->getParent(),
+ 'owner' => $this->getOwner(),
+ 'instance' => $this->getInstance(),
+ 'token' => $this->getToken(),
+ 'password' => $this->getPassword()
+ ];
+ }
+
+}
+
diff --git a/lib/Model/GlobalScale/GSShareMountpoint.php b/lib/Model/GlobalScale/GSShareMountpoint.php
new file mode 100644
index 00000000..c6f69ec2
--- /dev/null
+++ b/lib/Model/GlobalScale/GSShareMountpoint.php
@@ -0,0 +1,155 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Model\GlobalScale;
+
+
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use JsonSerializable;
+
+
+/**
+ * Class GSShare
+ *
+ * @package OCA\Circles\Model\GlobalScale
+ */
+class GSShareMountpoint implements JsonSerializable {
+
+
+ use TArrayTools;
+
+
+ /** @var int */
+ private $shareId = 0;
+
+ /** @var string */
+ private $userId = '';
+
+ /** @var string */
+ private $mountPoint = '';
+
+
+ /**
+ * GSShareMountpoint constructor.
+ *
+ * @param int $shareId
+ * @param string $userId
+ * @param string $mountPoint
+ */
+ public function __construct(int $shareId = 0, string $userId = '', string $mountPoint = '') {
+ $this->shareId = $shareId;
+ $this->userId = $userId;
+ $this->mountPoint = $mountPoint;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getUserId(): string {
+ return $this->userId;
+ }
+
+ /**
+ * @param string $userId
+ *
+ * @return GSShareMountpoint
+ */
+ public function setUserId(string $userId): self {
+ $this->userId = $userId;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getShareId(): int {
+ return $this->shareId;
+ }
+
+ /**
+ * @param int $shareId
+ *
+ * @return $this
+ */
+ public function setShareId(int $shareId): self {
+ $this->shareId = $shareId;
+
+ return $this;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getMountPoint(): string {
+ return $this->mountPoint;
+ }
+
+ /**
+ * @param string $mountPoint
+ *
+ * @return GSShareMountpoint
+ */
+ public function setMountPoint(string $mountPoint): self {
+ $this->mountPoint = $mountPoint;
+
+ return $this;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSShareMountpoint
+ */
+ public function importFromDatabase(array $data): self {
+ $this->setShareId($this->getInt('share_id', $data));
+ $this->setUserId($this->get('user_id', $data));
+ $this->setMountPoint($this->get('mountpoint', $data));
+
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ function jsonSerialize(): array {
+ return [
+ 'userId' => $this->getUserId(),
+ 'shareId' => $this->getShareId(),
+ 'mountPoint' => $this->getMountPoint(),
+ ];
+ }
+
+}
+
diff --git a/lib/Model/GlobalScale/GSWrapper.php b/lib/Model/GlobalScale/GSWrapper.php
new file mode 100644
index 00000000..436df679
--- /dev/null
+++ b/lib/Model/GlobalScale/GSWrapper.php
@@ -0,0 +1,242 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Model\GlobalScale;
+
+
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use JsonSerializable;
+use OCA\Circles\Exceptions\JsonException;
+use OCA\Circles\Exceptions\ModelException;
+
+
+/**
+ * Class GSEvent
+ *
+ * @package OCA\Circles\Model\GlobalScale
+ */
+class GSWrapper implements JsonSerializable {
+
+
+ use TArrayTools;
+
+
+ const STATUS_INIT = 0;
+ const STATUS_FAILED = 1;
+ const STATUS_DONE = 8;
+ const STATUS_OVER = 9;
+
+
+ /** @var string */
+ private $token = '';
+
+ /** @var GSEvent */
+ private $event;
+
+ /** @var string */
+ private $instance = '';
+
+ /** @var int */
+ private $severity = GSEvent::SEVERITY_LOW;
+
+ /** @var int */
+ private $status = 0;
+
+ /** @var int */
+ private $creation;
+
+
+ function __construct() {
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getToken(): string {
+ return $this->token;
+ }
+
+ /**
+ * @param string $token
+ *
+ * @return GSWrapper
+ */
+ public function setToken(string $token): self {
+ $this->token = $token;
+
+ return $this;
+ }
+
+
+ /**
+ * @return GSEvent
+ */
+ public function getEvent(): GSEvent {
+ return $this->event;
+ }
+
+ /**
+ * @param GSEvent $event
+ *
+ * @return GSWrapper
+ */
+ public function setEvent(GSEvent $event): self {
+ $this->event = $event;
+
+ return $this;
+ }
+
+ /**
+ * @return bool
+ */
+ public function hasEvent(): bool {
+ return ($this->event !== null);
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getInstance(): string {
+ return $this->instance;
+ }
+
+ /**
+ * @param string $instance
+ *
+ * @return GSWrapper
+ */
+ public function setInstance(string $instance): self {
+ $this->instance = $instance;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getSeverity(): int {
+ return $this->severity;
+ }
+
+ /**
+ * @param int $severity
+ *
+ * @return GSWrapper
+ */
+ public function setSeverity(int $severity): self {
+ $this->severity = $severity;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getStatus(): int {
+ return $this->status;
+ }
+
+ /**
+ * @param int $status
+ *
+ * @return GSWrapper
+ */
+ public function setStatus(int $status): self {
+ $this->status = $status;
+
+ return $this;
+ }
+
+
+ /**
+ * @return int
+ */
+ public function getCreation(): int {
+ return $this->creation;
+ }
+
+ /**
+ * @param int $creation
+ *
+ * @return GSWrapper
+ */
+ public function setCreation(int $creation): self {
+ $this->creation = $creation;
+
+ return $this;
+ }
+
+
+ /**
+ * @param array $data
+ *
+ * @return GSWrapper
+ * @throws JsonException
+ * @throws ModelException
+ */
+ public function import(array $data): self {
+ $this->setToken($this->get('token', $data));
+ $this->setInstance($this->get('instance', $data));
+ $this->setSeverity($this->getInt('severity', $data, GSEvent::SEVERITY_LOW));
+ $this->setStatus($this->getInt('status', $data, GSWrapper::STATUS_INIT));
+
+ $event = new GSEvent();
+ $event->importFromJson($this->get('event', $data));
+
+ $this->setEvent($event);
+
+ $this->setCreation($this->getInt('creation', $data));
+
+ return $this;
+ }
+
+
+ /**
+ * @return array
+ */
+ function jsonSerialize(): array {
+ $arr = [
+ 'id' => $this->getToken(),
+ 'event' => $this->getEvent(),
+ 'severity' => $this->getSeverity(),
+ 'status' => $this->getStatus(),
+ 'creation' => $this->getCreation()
+ ];
+
+ $this->cleanArray($arr);
+
+ return $arr;
+ }
+
+}
+
diff --git a/lib/Model/Member.php b/lib/Model/Member.php
index af6f8c1f..be17d640 100644
--- a/lib/Model/Member.php
+++ b/lib/Model/Member.php
@@ -139,7 +139,6 @@ class Member extends BaseMember {
* @throws ModeratorIsNotHighEnoughException
*/
public function hasToBeHigherLevel($level) {
-
if ($this->getLevel() <= $level) {
throw new ModeratorIsNotHighEnoughException(
$this->l10n->t('Insufficient privileges')
diff --git a/lib/Model/SearchResult.php b/lib/Model/SearchResult.php
index e1bee72f..e6c6fc92 100644
--- a/lib/Model/SearchResult.php
+++ b/lib/Model/SearchResult.php
@@ -27,18 +27,6 @@
namespace OCA\Circles\Model;
-use OCA\Circles\Exceptions\CircleTypeNotValidException;
-use OCA\Circles\Exceptions\MemberAlreadyExistsException;
-use OCA\Circles\Exceptions\MemberCantJoinCircleException;
-use OCA\Circles\Exceptions\MemberDoesNotExistException;
-use OCA\Circles\Exceptions\MemberIsBlockedException;
-use OCA\Circles\Exceptions\MemberIsNotAdminException;
-use OCA\Circles\Exceptions\MemberIsNotModeratorException;
-use OCA\Circles\Exceptions\MemberIsNotOwnerException;
-use OCA\Circles\Exceptions\MemberIsOwnerException;
-use OCA\Circles\Exceptions\MemberTypeCantEditLevelException;
-use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException;
-
class SearchResult implements \JsonSerializable {
/** @var string */
@@ -47,6 +35,9 @@ class SearchResult implements \JsonSerializable {
/** @var int */
private $type;
+ /** @var string */
+ private $instance = '';
+
/** @var array */
private $data = [];
@@ -58,9 +49,10 @@ class SearchResult implements \JsonSerializable {
* @param int $type
* @param array $data
*/
- function __construct($ident = '', $type = 0, $data = []) {
+ function __construct($ident = '', $type = 0, $instance = '', $data = []) {
$this->setIdent($ident);
$this->setType($type);
+ $this->setInstance($instance);
$this->setData($data);
}
@@ -81,6 +73,21 @@ class SearchResult implements \JsonSerializable {
/**
+ * @param string $instance
+ */
+ public function setInstance($instance) {
+ $this->instance = $instance;
+ }
+
+ /**
+ * @return string
+ */
+ public function getInstance() {
+ return $this->instance;
+ }
+
+
+ /**
* @param int $type
*/
public function setType($type) {
@@ -125,10 +132,11 @@ class SearchResult implements \JsonSerializable {
function jsonSerialize() {
return [
- 'ident' => $this->getIdent(),
- 'type' => $this->getType(),
- 'data' => $this->getData()
+ 'ident' => $this->getIdent(),
+ 'instance' => $this->getInstance(),
+ 'type' => $this->getType(),
+ 'data' => $this->getData()
];
}
-} \ No newline at end of file
+}
diff --git a/lib/Model/SharingFrame.php b/lib/Model/SharingFrame.php
index 988897e4..904c8913 100644
--- a/lib/Model/SharingFrame.php
+++ b/lib/Model/SharingFrame.php
@@ -283,6 +283,12 @@ class SharingFrame implements \JsonSerializable {
public static function fromJSON($json) {
$arr = json_decode($json, true);
+
+ return self::fromArray($arr);
+ }
+
+
+ public static function fromArray($arr) {
if (!is_array($arr) || !key_exists('source', $arr)) {
return null;
}
diff --git a/lib/Search/Contacts.php b/lib/Search/Contacts.php
index c28ea46e..0663cc16 100644
--- a/lib/Search/Contacts.php
+++ b/lib/Search/Contacts.php
@@ -49,7 +49,7 @@ class Contacts implements ISearch {
}
$data = $this->generateDataArray($contact);
- $result[] = new SearchResult($contact['UID'], Member::TYPE_CONTACT, $data);
+ $result[] = new SearchResult($contact['UID'], Member::TYPE_CONTACT, '', $data);
}
return $result;
diff --git a/lib/Search/GlobalScaleUsers.php b/lib/Search/GlobalScaleUsers.php
new file mode 100644
index 00000000..55cf1e04
--- /dev/null
+++ b/lib/Search/GlobalScaleUsers.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+namespace OCA\Circles\Search;
+
+use daita\MySmallPhpTools\Exceptions\RequestContentException;
+use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
+use daita\MySmallPhpTools\Exceptions\RequestResultNotJsonException;
+use daita\MySmallPhpTools\Exceptions\RequestResultSizeException;
+use daita\MySmallPhpTools\Exceptions\RequestServerException;
+use daita\MySmallPhpTools\Model\Request;
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use daita\MySmallPhpTools\Traits\TRequest;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\ISearch;
+use OCA\Circles\Model\Member;
+use OCA\Circles\Model\SearchResult;
+use OCA\Circles\Service\ConfigService;
+use OCA\Circles\Service\MiscService;
+
+
+/**
+ * Class GlobalScaleUsers
+ *
+ * @package OCA\Circles\Search
+ */
+class GlobalScaleUsers implements ISearch {
+
+
+ use TRequest;
+ use TArrayTools;
+
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * GlobalScaleUsers constructor.
+ *
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(ConfigService $configService, MiscService $miscService) {
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function search($search) {
+
+ /** @var string $lookup */
+ try {
+ $lookup = $this->configService->getGSStatus(ConfigService::GS_LOOKUP);
+ } catch (GSStatusException $e) {
+ return;
+ }
+
+ $request = new Request('/users', Request::TYPE_GET);
+ $request->setProtocols(['https', 'http']);
+ $request->addData('search', $search);
+ $request->setAddressFromUrl($lookup);
+
+ try {
+ $users = $this->retrieveJson($request);
+ } catch (
+ RequestContentException |
+ RequestNetworkException |
+ RequestResultSizeException |
+ RequestServerException |
+ RequestResultNotJsonException $e
+ ) {
+ $this->miscService->log('Issue while retrieving instances from lookup: ' . $e->getMessage());
+
+ return [];
+ }
+
+ $result = [];
+ foreach ($users as $user) {
+ list(, $instance) = explode('@', $this->get('federationId', $user), 2);
+ if ($instance === $this->configService->getLocalCloudId()) {
+ continue;
+ }
+
+ $result[] =
+ new SearchResult(
+ $this->get('userid.value', $user), Member::TYPE_USER, $instance,
+ ['display' => $this->get('name.value', $user)]
+ );
+ }
+
+ return $result;
+ }
+}
+
+
diff --git a/lib/Search/LocalUsers.php b/lib/Search/LocalUsers.php
index bb46e7e0..94a7829b 100644
--- a/lib/Search/LocalUsers.php
+++ b/lib/Search/LocalUsers.php
@@ -44,7 +44,7 @@ class LocalUsers implements ISearch {
foreach ($users as $user) {
$result[] =
new SearchResult(
- $user->getUID(), Member::TYPE_USER, ['display' => $user->getDisplayName()]
+ $user->getUID(), Member::TYPE_USER, '', ['display' => $user->getDisplayName()]
);
}
diff --git a/lib/Service/BroadcastService.php b/lib/Service/BroadcastService.php
index 2a1d41b7..2ad94542 100644
--- a/lib/Service/BroadcastService.php
+++ b/lib/Service/BroadcastService.php
@@ -27,21 +27,26 @@
namespace OCA\Circles\Service;
+use daita\MySmallPhpTools\Model\SimpleDataStore;
use Exception;
use OCA\Circles\Db\CirclesRequest;
use OCA\Circles\Db\MembersRequest;
-use OCA\Circles\Exceptions\BroadcasterIsNotCompatibleException;
use OCA\Circles\IBroadcaster;
use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
use OCA\Circles\Model\Member;
use OCA\Circles\Model\SharingFrame;
class BroadcastService {
+
/** @var string */
private $userId;
+ /** @var GSUpstreamService */
+ private $gsUpstreamService;
+
/** @var ConfigService */
private $configService;
@@ -62,6 +67,7 @@ class BroadcastService {
* @param ConfigService $configService
* @param CirclesRequest $circlesRequest
* @param MembersRequest $membersRequest
+ * @param GSUpstreamService $gsUpstreamService
* @param MiscService $miscService
*/
public function __construct(
@@ -69,12 +75,14 @@ class BroadcastService {
ConfigService $configService,
CirclesRequest $circlesRequest,
MembersRequest $membersRequest,
+ GSUpstreamService $gsUpstreamService,
MiscService $miscService
) {
$this->userId = $userId;
$this->configService = $configService;
$this->circlesRequest = $circlesRequest;
$this->membersRequest = $membersRequest;
+ $this->gsUpstreamService = $gsUpstreamService;
$this->miscService = $miscService;
}
@@ -97,19 +105,22 @@ class BroadcastService {
return;
}
- try {
- $broadcaster = \OC::$server->query((string)$frame->getHeader('broadcast'));
- if (!($broadcaster instanceof IBroadcaster)) {
- throw new BroadcasterIsNotCompatibleException();
- }
-
- $frameCircle = $frame->getCircle();
- $circle = $this->circlesRequest->forceGetCircle($frameCircle->getUniqueId());
-
- $this->feedBroadcaster($broadcaster, $frame, $circle);
- } catch (Exception $e) {
- throw $e;
- }
+ $event = new GSEvent(GSEvent::FILE_SHARE, true);
+ $event->setSeverity(GSEvent::SEVERITY_HIGH);
+ $event->setCircle($frame->getCircle());
+ $event->setSource($this->configService->getLocalCloudId());
+ $event->setData(new SimpleDataStore(['frame' => json_decode(json_encode($frame), true)]));
+ $this->gsUpstreamService->newEvent($event);
+
+// $broadcaster = \OC::$server->query((string)$frame->getHeader('broadcast'));
+// if (!($broadcaster instanceof IBroadcaster)) {
+// throw new BroadcasterIsNotCompatibleException();
+// }
+//
+// $frameCircle = $frame->getCircle();
+// $circle = $this->circlesRequest->forceGetCircle($frameCircle->getUniqueId());
+//
+// $this->feedBroadcaster($broadcaster, $frame, $circle);
}
@@ -170,3 +181,4 @@ class BroadcastService {
}
}
+
diff --git a/lib/Service/CirclesService.php b/lib/Service/CirclesService.php
index 0cd6aaaa..7a4d4c2d 100644
--- a/lib/Service/CirclesService.php
+++ b/lib/Service/CirclesService.php
@@ -31,6 +31,7 @@ namespace OCA\Circles\Service;
use Exception;
+use OC;
use OCA\Circles\AppInfo\Application;
use OCA\Circles\Db\CircleProviderRequest;
use OCA\Circles\Db\CirclesRequest;
@@ -40,12 +41,14 @@ use OCA\Circles\Db\SharesRequest;
use OCA\Circles\Exceptions\CircleAlreadyExistsException;
use OCA\Circles\Exceptions\CircleDoesNotExistException;
use OCA\Circles\Exceptions\CircleTypeDisabledException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
use OCA\Circles\Exceptions\FederatedCircleNotAllowedException;
+use OCA\Circles\Exceptions\MemberAlreadyExistsException;
use OCA\Circles\Exceptions\MemberDoesNotExistException;
-use OCA\Circles\Exceptions\MemberIsNotModeratorException;
use OCA\Circles\Exceptions\MemberIsNotOwnerException;
use OCA\Circles\Exceptions\MembersLimitException;
use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
use OCA\Circles\Model\Member;
use OCP\IGroupManager;
use OCP\IL10N;
@@ -76,6 +79,9 @@ class CirclesService {
/** @var FederatedLinksRequest */
private $federatedLinksRequest;
+ /** @var GSUpstreamService */
+ private $gsUpstreamService;
+
/** @var EventsService */
private $eventsService;
@@ -97,6 +103,7 @@ class CirclesService {
* @param MembersRequest $membersRequest
* @param SharesRequest $sharesRequest
* @param FederatedLinksRequest $federatedLinksRequest
+ * @param GSUpstreamService $gsUpstreamService
* @param EventsService $eventsService
* @param CircleProviderRequest $circleProviderRequest
* @param MiscService $miscService
@@ -110,6 +117,7 @@ class CirclesService {
MembersRequest $membersRequest,
SharesRequest $sharesRequest,
FederatedLinksRequest $federatedLinksRequest,
+ GSUpstreamService $gsUpstreamService,
EventsService $eventsService,
CircleProviderRequest $circleProviderRequest,
MiscService $miscService
@@ -122,6 +130,7 @@ class CirclesService {
$this->membersRequest = $membersRequest;
$this->sharesRequest = $sharesRequest;
$this->federatedLinksRequest = $federatedLinksRequest;
+ $this->gsUpstreamService = $gsUpstreamService;
$this->eventsService = $eventsService;
$this->circleProviderRequest = $circleProviderRequest;
$this->miscService = $miscService;
@@ -139,7 +148,8 @@ class CirclesService {
* @return Circle
* @throws CircleAlreadyExistsException
* @throws CircleTypeDisabledException
- * @throws \OCA\Circles\Exceptions\MemberAlreadyExistsException
+ * @throws MemberAlreadyExistsException
+ * @throws Exception
*/
public function createCircle($type, $name, string $ownerId = '') {
$type = $this->convertTypeStringToBitValue($type);
@@ -163,14 +173,24 @@ class CirclesService {
$ownerId = $this->userId;
}
- try {
- $this->circlesRequest->createCircle($circle, $ownerId);
- $this->membersRequest->createMember($circle->getOwner());
- } catch (CircleAlreadyExistsException $e) {
- throw $e;
+ if (!$this->circlesRequest->isCircleUnique($circle, $ownerId)) {
+ throw new CircleAlreadyExistsException(
+ $this->l10n->t('A circle with that name exists')
+ );
}
- $this->eventsService->onCircleCreation($circle);
+ $circle->generateUniqueId();
+
+ $owner = new Member($ownerId, Member::TYPE_USER);
+ $owner->setCircleId($circle->getUniqueId())
+ ->setLevel(Member::LEVEL_OWNER)
+ ->setStatus(Member::STATUS_MEMBER);
+ $circle->setOwner($owner)
+ ->setViewer($owner);
+
+ $event = new GSEvent(GSEvent::CIRCLE_CREATE, true);
+ $event->setCircle($circle);
+ $this->gsUpstreamService->newEvent($event);
return $circle;
}
@@ -225,7 +245,7 @@ class CirclesService {
public function detailsCircle($circleUniqueId, $forceAll = false) {
try {
- $circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId, $forceAll);
+ $circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId, '', $forceAll);
if ($this->viewerIsAdmin()
|| $circle->getHigherViewer()
->isLevel(Member::LEVEL_MEMBER)
@@ -235,7 +255,7 @@ class CirclesService {
$this->detailsCircleLinkedGroups($circle);
$this->detailsCircleFederatedCircles($circle);
}
- } catch (\Exception $e) {
+ } catch (Exception $e) {
throw $e;
}
@@ -264,6 +284,7 @@ class CirclesService {
/**
+ * // TODO - check this on GS setup
* get the Linked Group list and add the result to the Circle.
*
* @param Circle $circle
@@ -310,37 +331,24 @@ class CirclesService {
* @param array $settings
*
* @return Circle
- * @throws \Exception
+ * @throws Exception
*/
- public function settingsCircle($circleUniqueId, $settings) {
-
- try {
- $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');
- }
+ public function settingsCircle(string $circleUniqueId, array $settings) {
+ $circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
+ $this->hasToBeOwner($circle->getHigherViewer());
- $ak = array_keys($settings);
- foreach ($ak AS $k) {
- $circle->setSetting($k, $settings[$k]);
- }
+ if (!$this->viewerIsAdmin()) {
+ $settings['members_limit'] = $circle->getSetting('members_limit');
+ }
- $this->circlesRequest->updateCircle($circle, $this->userId);
+ // can only be run from the instance of the circle's owner.
+ $event = new GSEvent(GSEvent::CIRCLE_UPDATE);
+ $event->setCircle($circle);
+ $event->getData()
+ ->sBool('local_admin', $this->viewerIsAdmin())
+ ->sArray('settings', $settings);
- $this->eventsService->onSettingsChange($circle, $oldSettings);
- } catch (\Exception $e) {
- throw $e;
- }
+ $this->gsUpstreamService->newEvent($event);
return $circle;
}
@@ -352,24 +360,20 @@ class CirclesService {
* @param string $circleUniqueId
*
* @return null|Member
- * @throws \Exception
+ * @throws Exception
*/
public function joinCircle($circleUniqueId) {
-
try {
$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
-
$member = $this->membersRequest->getFreshNewMember(
- $circleUniqueId, $this->userId, Member::TYPE_USER
+ $circleUniqueId, $this->userId, Member::TYPE_USER, ''
);
- $member->hasToBeAbleToJoinTheCircle();
- $this->checkThatCircleIsNotFull($circle);
-
- $member->joinCircle($circle->getType());
- $this->membersRequest->updateMember($member);
- $this->eventsService->onMemberNew($circle, $member);
- } catch (\Exception $e) {
+ $event = new GSEvent(GSEvent::MEMBER_JOIN);
+ $event->setCircle($circle);
+ $event->setMember($member);
+ $this->gsUpstreamService->newEvent($event);
+ } catch (Exception $e) {
throw $e;
}
@@ -383,20 +387,16 @@ class CirclesService {
* @param string $circleUniqueId
*
* @return null|Member
- * @throws \Exception
+ * @throws Exception
*/
public function leaveCircle($circleUniqueId) {
-
$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
$member = $circle->getViewer();
- $member->hasToBeMemberOrAlmost();
- $member->cantBeOwner();
-
- $this->eventsService->onMemberLeaving($circle, $member);
-
- $this->membersRequest->removeMember($member);
- $this->sharesRequest->removeSharesFromMember($member);
+ $event = new GSEvent(GSEvent::MEMBER_LEAVE);
+ $event->setCircle($circle);
+ $event->setMember($member);
+ $this->gsUpstreamService->newEvent($event);
return $member;
}
@@ -411,10 +411,10 @@ class CirclesService {
*
* @throws CircleDoesNotExistException
* @throws MemberIsNotOwnerException
- * @throws \OCA\Circles\Exceptions\ConfigNoCircleAvailableException
+ * @throws ConfigNoCircleAvailableException
+ * @throws Exception
*/
public function removeCircle($circleUniqueId, bool $force = false) {
-
if ($force) {
$circle = $this->circlesRequest->forceGetCircle($circleUniqueId);
} else {
@@ -422,11 +422,12 @@ class CirclesService {
$this->hasToBeOwner($circle->getHigherViewer());
}
+ // removing a Circle is done only by owner, so can already be done by local user, or admin, or occ
+ // at this point, we already know that all condition are filled. we can force it.
+ $event = new GSEvent(GSEvent::CIRCLE_DESTROY, false, true);
+ $event->setCircle($circle);
- $this->eventsService->onCircleDestruction($circle);
-
- $this->membersRequest->removeAllFromCircle($circleUniqueId);
- $this->circlesRequest->destroyCircle($circleUniqueId);
+ $this->gsUpstreamService->newEvent($event);
}
@@ -442,6 +443,7 @@ class CirclesService {
/**
+ * // TODO - check this on GS setup
* When a user is removed.
* Before deleting a user from the cloud, we assign a new owner to his Circles.
* Remove the Circle if it has no admin.
@@ -467,6 +469,7 @@ class CirclesService {
/**
+ * // TODO - check this on GS setup
* switchOlderAdminToOwner();
*
* @param Circle $circle
@@ -528,7 +531,7 @@ class CirclesService {
$ext = '.png';
}
- $urlGen = \OC::$server->getURLGenerator();
+ $urlGen = OC::$server->getURLGenerator();
switch ($type) {
case Circle::CIRCLES_PERSONAL:
return $urlGen->getAbsoluteURL(
@@ -580,7 +583,6 @@ class CirclesService {
* @throws MembersLimitException
*/
public function checkThatCircleIsNotFull(Circle $circle) {
-
$members = $this->membersRequest->forceGetMembers(
$circle->getUniqueId(), Member::LEVEL_MEMBER, true
);
@@ -604,7 +606,7 @@ class CirclesService {
/**
* @return bool
*/
- public function viewerIsAdmin() {
+ public function viewerIsAdmin(): bool {
if ($this->userId === '') {
return false;
}
diff --git a/lib/Service/ConfigService.php b/lib/Service/ConfigService.php
index 1b490cd6..7aee0684 100644
--- a/lib/Service/ConfigService.php
+++ b/lib/Service/ConfigService.php
@@ -26,6 +26,7 @@
namespace OCA\Circles\Service;
+use OCA\Circles\Exceptions\GSStatusException;
use OCA\Circles\Model\Circle;
use OCP\IConfig;
use OCP\IRequest;
@@ -39,6 +40,7 @@ class ConfigService {
const CIRCLES_STILL_FRONTEND = 'still_frontend';
const CIRCLES_SWAP_TO_TEAMS = 'swap_to_teams';
const CIRCLES_ALLOW_FEDERATED_CIRCLES = 'allow_federated';
+ const CIRCLES_GS_ENABLED = 'gs_enabled';
const CIRCLES_MEMBERS_LIMIT = 'members_limit';
const CIRCLES_ACCOUNTS_ONLY = 'accounts_only';
const CIRCLES_ALLOW_LINKED_GROUPS = 'allow_linked_groups';
@@ -52,6 +54,12 @@ class ConfigService {
const CIRCLES_TEST_ASYNC_HAND = 'test_async_hand';
const CIRCLES_TEST_ASYNC_COUNT = 'test_async_count';
+ const GS_ENABLED = 'enabled';
+ const GS_MODE = 'mode';
+ const GS_KEY = 'key';
+ const GS_LOOKUP = 'lookup';
+
+
private $defaults = [
self::CIRCLES_ALLOW_CIRCLES => Circle::CIRCLES_ALL,
self::CIRCLES_CONTACT_BACKEND => '0',
@@ -62,6 +70,7 @@ class ConfigService {
self::CIRCLES_MEMBERS_LIMIT => '50',
self::CIRCLES_ALLOW_LINKED_GROUPS => '0',
self::CIRCLES_ALLOW_FEDERATED_CIRCLES => '0',
+ self::CIRCLES_GS_ENABLED => '0',
self::CIRCLES_ALLOW_NON_SSL_LINKS => '0',
self::CIRCLES_NON_SSL_LOCAL => '0',
self::CIRCLES_SELF_SIGNED => '0',
@@ -428,8 +437,72 @@ class ConfigService {
}
+ /**
+ * @param string $type
+ *
+ * @throws GSStatusException
+ */
+ public function getGSStatus(string $type = '') {
+ $enabled = $this->config->getSystemValueBool('gs.enabled', false);
+ $lookup = $this->config->getSystemValue('lookup_server', '');
+
+ if ($lookup === '' || !$enabled) {
+ if ($type === self::GS_ENABLED) {
+ return false;
+ }
+
+ throw new GSStatusException('GS and lookup are not configured : ' . $lookup . ', ' . $enabled);
+ }
+
+ $clef = $this->config->getSystemValue('gss.jwt.key', '');
+ $mode = $this->config->getSystemValue('gss.mode', '');
+
+ switch ($type) {
+ case self::GS_ENABLED:
+ return $enabled;
+
+ case self::GS_MODE:
+ return $mode;
+
+ case self::GS_KEY:
+ return $clef;
+
+ case self::GS_LOOKUP:
+ return $lookup;
+ }
+
+ return [
+ self::GS_ENABLED => $enabled,
+ self::GS_LOOKUP => $lookup,
+ self::GS_MODE => $clef,
+ self::GS_KEY => $mode,
+ ];
+ }
+
+
+ /**
+ * @return array
+ */
+ public function getTrustedDomains(): array {
+ $domains = [];
+ foreach ($this->config->getSystemValue('trusted_domains', []) as $v) {
+ $domains[] = $v;
+ }
+
+ return $domains;
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getLocalCloudId(): string {
+ return $this->getTrustedDomains()[0];
+ }
+
public function getInstanceId() {
return $this->config->getSystemValue('instanceid');
}
}
+
diff --git a/lib/Service/DavService.php b/lib/Service/DavService.php
index 448bb221..54b19689 100644
--- a/lib/Service/DavService.php
+++ b/lib/Service/DavService.php
@@ -400,7 +400,7 @@ class DavService {
$circle->setContactGroupName($group);
try {
- $this->circlesRequest->createCircle($circle, $davCard->getOwner());
+ $this->circlesRequest->createCircle($circle);
$member = new Member($davCard->getOwner(), Member::TYPE_USER, $circle->getUniqueId());
$member->setLevel(Member::LEVEL_OWNER);
$member->setStatus(Member::STATUS_MEMBER);
diff --git a/lib/Service/GSDownstreamService.php b/lib/Service/GSDownstreamService.php
new file mode 100644
index 00000000..3b8cf7bc
--- /dev/null
+++ b/lib/Service/GSDownstreamService.php
@@ -0,0 +1,164 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Service;
+
+
+use Exception;
+use OCA\Circles\Db\CirclesRequest;
+use OCA\Circles\Db\GSEventsRequest;
+use OCA\Circles\Exceptions\CircleDoesNotExistException;
+use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
+use OCA\Circles\Exceptions\GlobalScaleDSyncException;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\GSKeyException;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCP\IURLGenerator;
+
+
+/**
+ * Class GSDownstreamService
+ *
+ * @package OCA\Circles\Service
+ */
+class GSDownstreamService {
+
+
+ /** @var string */
+ private $userId = '';
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var GSEventsRequest */
+ private $gsEventsRequest;
+
+ /** @var CirclesRequest */
+ private $circlesRequest;
+
+ /** @var GlobalScaleService */
+ private $globalScaleService;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * GSUpstreamService constructor.
+ *
+ * @param $userId
+ * @param IURLGenerator $urlGenerator
+ * @param GSEventsRequest $gsEventsRequest
+ * @param CirclesRequest $circlesRequest
+ * @param GlobalScaleService $globalScaleService
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ $userId,
+ IURLGenerator $urlGenerator,
+ GSEventsRequest $gsEventsRequest,
+ CirclesRequest $circlesRequest,
+ GlobalScaleService $globalScaleService,
+ ConfigService $configService,
+ MiscService $miscService
+ ) {
+ $this->userId = $userId;
+ $this->urlGenerator = $urlGenerator;
+ $this->gsEventsRequest = $gsEventsRequest;
+ $this->circlesRequest = $circlesRequest;
+ $this->globalScaleService = $globalScaleService;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws GSKeyException
+ * @throws GSStatusException
+ * @throws GlobalScaleEventException
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GlobalScaleDSyncException
+ */
+ public function requestedEvent(GSEvent $event) {
+ $this->globalScaleService->checkEvent($event);
+
+ $gs = $this->globalScaleService->getGlobalScaleEvent($event);
+ $gs->verify($event, true);
+
+ $this->miscService->log('&&&& 1 ' . json_encode($event));
+
+ $gs->manage($event);
+
+ $this->miscService->log('&&&& 2 ' . json_encode($event));
+
+ $this->globalScaleService->asyncBroadcast($event);
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws CircleDoesNotExistException
+ * @throws ConfigNoCircleAvailableException
+ * @throws GSKeyException
+ * @throws GlobalScaleDSyncException
+ * @throws GlobalScaleEventException
+ */
+ public function statusEvent(GSEvent $event) {
+ $this->globalScaleService->checkEvent($event);
+
+ $gs = $this->globalScaleService->getGlobalScaleEvent($event);
+ $gs->verify($event, false);
+ $gs->manage($event);
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ public function onNewEvent(GSEvent $event) {
+ try {
+ $this->globalScaleService->checkEvent($event);
+
+ $gs = $this->globalScaleService->getGlobalScaleEvent($event);
+ $gs->manage($event);
+ } catch (Exception $e) {
+ }
+ }
+
+}
+
diff --git a/lib/Service/GSUpstreamService.php b/lib/Service/GSUpstreamService.php
new file mode 100644
index 00000000..4fbd0091
--- /dev/null
+++ b/lib/Service/GSUpstreamService.php
@@ -0,0 +1,534 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Service;
+
+
+use daita\MySmallPhpTools\Exceptions\RequestContentException;
+use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
+use daita\MySmallPhpTools\Exceptions\RequestResultNotJsonException;
+use daita\MySmallPhpTools\Exceptions\RequestResultSizeException;
+use daita\MySmallPhpTools\Exceptions\RequestServerException;
+use daita\MySmallPhpTools\Model\Request;
+use daita\MySmallPhpTools\Model\SimpleDataStore;
+use daita\MySmallPhpTools\Traits\TArrayTools;
+use daita\MySmallPhpTools\Traits\TRequest;
+use Exception;
+use OCA\Circles\Db\CirclesRequest;
+use OCA\Circles\Db\GSEventsRequest;
+use OCA\Circles\Db\MembersRequest;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\Exceptions\JsonException;
+use OCA\Circles\Exceptions\ModelException;
+use OCA\Circles\GlobalScale\CircleStatus;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\GlobalScale\GSWrapper;
+use OCP\IURLGenerator;
+
+
+/**
+ * Class GSUpstreamService
+ *
+ * @package OCA\Circles\Service
+ */
+class GSUpstreamService {
+
+
+ use TRequest;
+ use TArrayTools;
+
+
+ /** @var string */
+ private $userId = '';
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var GSEventsRequest */
+ private $gsEventsRequest;
+
+ /** @var CirclesRequest */
+ private $circlesRequest;
+
+ /** @var MembersRequest */
+ private $membersRequest;
+
+ /** @var GlobalScaleService */
+ private $globalScaleService;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * GSUpstreamService constructor.
+ *
+ * @param $userId
+ * @param IURLGenerator $urlGenerator
+ * @param GSEventsRequest $gsEventsRequest
+ * @param CirclesRequest $circlesRequest
+ * @param MembersRequest $membersRequest
+ * @param GlobalScaleService $globalScaleService
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ $userId,
+ IURLGenerator $urlGenerator,
+ GSEventsRequest $gsEventsRequest,
+ CirclesRequest $circlesRequest,
+ MembersRequest $membersRequest,
+ GlobalScaleService $globalScaleService,
+ ConfigService $configService,
+ MiscService $miscService
+ ) {
+ $this->userId = $userId;
+ $this->urlGenerator = $urlGenerator;
+ $this->gsEventsRequest = $gsEventsRequest;
+ $this->circlesRequest = $circlesRequest;
+ $this->membersRequest = $membersRequest;
+ $this->globalScaleService = $globalScaleService;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws Exception
+ */
+ public function newEvent(GSEvent $event) {
+ try {
+ $gs = $this->globalScaleService->getGlobalScaleEvent($event);
+
+ $this->fillEvent($event);
+ if ($this->isLocalEvent($event)) {
+ $gs->verify($event, true);
+ $gs->manage($event);
+
+ $this->globalScaleService->asyncBroadcast($event);
+ } else {
+ $gs->verify($event); // needed ? as we check event on the 'master' of the circle
+ $this->confirmEvent($event);
+ $gs->manage($event);
+ }
+ } catch (Exception $e) {
+ $this->miscService->log(
+ get_class($e) . ' on new event: ' . $e->getMessage() . ' - ' . json_encode($event), 1
+ );
+ throw $e;
+ }
+ }
+
+
+ /**
+ * @param GSWrapper $wrapper
+ * @param string $protocol
+ */
+ public function broadcastWrapper(GSWrapper $wrapper, string $protocol): void {
+ $status = GSWrapper::STATUS_FAILED;
+
+ try {
+ $this->broadcastEvent($wrapper->getEvent(), $wrapper->getInstance(), $protocol);
+ $status = GSWrapper::STATUS_DONE;
+ } catch (RequestContentException | RequestNetworkException | RequestResultSizeException | RequestServerException | RequestResultNotJsonException $e) {
+ }
+
+ if ($wrapper->getSeverity() === GSEvent::SEVERITY_HIGH) {
+ $wrapper->setStatus($status);
+ } else {
+ $wrapper->setStatus(GSWrapper::STATUS_OVER);
+ }
+
+ $this->gsEventsRequest->update($wrapper);
+ }
+
+
+ /**
+ * @param GSEvent $event
+ * @param string $instance
+ * @param string $protocol
+ *
+ * @throws RequestContentException
+ * @throws RequestNetworkException
+ * @throws RequestResultNotJsonException
+ * @throws RequestResultSizeException
+ * @throws RequestServerException
+ */
+ public function broadcastEvent(GSEvent $event, string $instance, string $protocol = ''): void {
+ $this->signEvent($event);
+
+ $path = $this->urlGenerator->linkToRoute('circles.GlobalScale.broadcast');
+ $request = new Request($path, Request::TYPE_POST);
+
+ $protocols = ['https', 'http'];
+ if ($protocol !== '') {
+ $protocols = [$protocol];
+ }
+
+ $request->setProtocols($protocols);
+ $request->setDataSerialize($event);
+
+ $request->setAddress($instance);
+
+ $data = $this->retrieveJson($request);
+ $event->setResult(new SimpleDataStore($this->getArray('result', $data, [])));
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws RequestContentException
+ * @throws RequestNetworkException
+ * @throws RequestResultSizeException
+ * @throws RequestServerException
+ * @throws RequestResultNotJsonException
+ * @throws GlobalScaleEventException
+ */
+ public function confirmEvent(GSEvent $event): void {
+ $this->signEvent($event);
+
+ $circle = $event->getCircle();
+ $owner = $circle->getOwner();
+ $path = $this->urlGenerator->linkToRoute('circles.GlobalScale.event');
+
+ $request = new Request($path, Request::TYPE_POST);
+ if ($this->get('REQUEST_SCHEME', $_SERVER) !== '') {
+ $request->setProtocols([$_SERVER['REQUEST_SCHEME']]);
+ } else {
+ $request->setProtocols(['https', 'http']);
+ }
+ $request->setAddressFromUrl($owner->getInstance());
+ $request->setDataSerialize($event);
+
+ $result = $this->retrieveJson($request);
+ $this->miscService->log('result ' . json_encode($result));
+ if ($this->getInt('status', $result) === 0) {
+ throw new GlobalScaleEventException($this->get('error', $result));
+ }
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws GSStatusException
+ */
+ private function fillEvent(GSEvent $event): void {
+ if (!$this->configService->getGSStatus(ConfigService::GS_ENABLED)) {
+ return;
+ }
+
+ $event->setSource($this->configService->getLocalCloudId());
+ }
+
+
+ /**
+ * @param GSEvent $event
+ */
+ private function signEvent(GSEvent $event) {
+ $event->setKey($this->globalScaleService->getKey());
+ }
+
+
+ /**
+ * We check that the event can be managed/checked locally or if the owner of the circle belongs to
+ * an other instance of Nextcloud
+ *
+ * @param GSEvent $event
+ *asyncBroadcast
+ *
+ * @return bool
+ */
+ private function isLocalEvent(GSEvent $event): bool {
+ if ($event->isLocal()) {
+ return true;
+ }
+
+ $circle = $event->getCircle();
+ $owner = $circle->getOwner();
+ if ($owner->getInstance() === ''
+ || in_array(
+ $owner->getInstance(), $this->configService->getTrustedDomains()
+ )) {
+ return true;
+ }
+
+ return false;
+ }
+
+
+ /**
+ * @param string $token
+ *
+ * @return GSWrapper[]
+ * @throws JsonException
+ * @throws ModelException
+ */
+ public function getEventsByToken(string $token): array {
+ return $this->gsEventsRequest->getByToken($token);
+ }
+
+
+ /**
+ * Deprecated ?
+ * should be used to manage results from events, like sending mails on user creation
+ *
+ * @param string $token
+ */
+ public function manageResults(string $token): void {
+ try {
+ $wrappers = $this->gsEventsRequest->getByToken($token);
+ } catch (JsonException | ModelException $e) {
+ return;
+ }
+
+ $event = null;
+ $events = [];
+ foreach ($wrappers as $wrapper) {
+ if ($wrapper->getStatus() !== GSWrapper::STATUS_DONE) {
+ return;
+ }
+
+ $events[$wrapper->getInstance()] = $event = $wrapper->getEvent();
+ }
+
+ if ($event === null) {
+ return;
+ }
+
+ try {
+ $gs = $this->globalScaleService->getGlobalScaleEvent($event);
+ $gs->result($events);
+ } catch (GlobalScaleEventException $e) {
+ }
+ }
+
+
+ /**
+ * @throws GSStatusException
+ */
+ public function synchronize() {
+ $this->configService->getGSStatus();
+
+ $sync = $this->getCirclesToSync();
+ $this->synchronizeCircles($sync);
+ $this->removeDeprecatedCircles();
+
+ $this->removeDeprecatedEvents();
+ }
+
+
+ /**
+ * @param array $circles
+ *
+ * @throws GSStatusException
+ */
+ public function synchronizeCircles(array $circles): void {
+ $event = new GSEvent(GSEvent::GLOBAL_SYNC, true);
+ $event->setSource($this->configService->getLocalCloudId());
+ $event->setData(new SimpleDataStore($circles));
+
+ foreach ($this->globalScaleService->getInstances() as $instance) {
+ try {
+ $this->broadcastEvent($event, $instance);
+ } catch (RequestContentException | RequestNetworkException | RequestResultSizeException | RequestServerException | RequestResultNotJsonException $e) {
+ }
+ }
+ }
+
+
+ /**
+ * @return Circle[]
+ */
+ private function getCirclesToSync(): array {
+ $circles = $this->circlesRequest->forceGetCircles();
+
+ $sync = [];
+ foreach ($circles as $circle) {
+ if ($circle->getOwner()
+ ->getInstance() !== ''
+ || $circle->getType() === Circle::CIRCLES_PERSONAL) {
+ continue;
+ }
+
+ $members = $this->membersRequest->forceGetMembers($circle->getUniqueId());
+ $circle->setMembers($members);
+
+ $sync[] = $circle;
+ }
+
+ return $sync;
+ }
+
+
+ /**
+ *
+ */
+ private function removeDeprecatedCircles() {
+ $knownCircles = $this->circlesRequest->forceGetCircles();
+ foreach ($knownCircles as $knownItem) {
+ if ($knownItem->getOwner()
+ ->getInstance() === '') {
+ continue;
+ }
+
+ try {
+ $this->checkCircle($knownItem);
+ } catch (GSStatusException $e) {
+ }
+ }
+ }
+
+
+ /**
+ * @param Circle $circle
+ *
+ * @throws GSStatusException
+ */
+ private function checkCircle(Circle $circle): void {
+ $status = $this->confirmCircleStatus($circle);
+
+ if (!$status) {
+ $this->circlesRequest->destroyCircle($circle->getUniqueId());
+ $this->membersRequest->removeAllFromCircle($circle->getUniqueId());
+ }
+ }
+
+
+ /**
+ * @param Circle $circle
+ *
+ * @return bool
+ * @throws GSStatusException
+ */
+ public function confirmCircleStatus(Circle $circle): bool {
+ $event = new GSEvent(GSEvent::CIRCLE_STATUS, true);
+ $event->setSource($this->configService->getLocalCloudId());
+ $event->setCircle($circle);
+
+ $this->signEvent($event);
+
+ $path = $this->urlGenerator->linkToRoute('circles.GlobalScale.status');
+ $request = new Request($path, Request::TYPE_POST);
+
+ $request->setProtocols(['https', 'http']);
+ $request->setDataSerialize($event);
+
+ $requestIssue = false;
+ $notFound = false;
+ $foundWithNoOwner = false;
+ foreach ($this->globalScaleService->getInstances() as $instance) {
+ $request->setAddress($instance);
+
+ try {
+ $result = $this->retrieveJson($request);
+ $this->miscService->log('result: ' . json_encode($result));
+ if ($this->getInt('status', $result, 0) !== 1) {
+ throw new RequestContentException('result status is not good');
+ }
+
+ $status = $this->getInt('success.data.status', $result);
+
+ // if error, we assume the circle might still exist.
+ if ($status === CircleStatus::STATUS_ERROR) {
+ return true;
+ }
+
+ if ($status === CircleStatus::STATUS_OK) {
+ return true;
+ }
+
+ // TODO: check the data.supposedOwner entry.
+ if ($status === CircleStatus::STATUS_NOT_OWNER) {
+ $foundWithNoOwner = true;
+ }
+
+ if ($status === CircleStatus::STATUS_NOT_FOUND) {
+ $notFound = true;
+ }
+
+ } catch (RequestContentException
+ | RequestNetworkException
+ | RequestResultNotJsonException
+ | RequestResultSizeException
+ | RequestServerException $e) {
+ $requestIssue = true;
+ // TODO: log instances that have network issue, after too many tries (7d), remove this circle.
+ continue;
+ }
+ }
+
+ // if no request issue, we can imagine that the instance that owns the circle is down.
+ // We'll wait for more information (cf request exceptions management);
+ if ($requestIssue) {
+ return true;
+ }
+
+ // circle were not found in any other instances, we can easily says that the circle does not exists anymore
+ if ($notFound && !$foundWithNoOwner) {
+ return false;
+ }
+
+ // circle were found everywhere but with no owner on every instance. we need to assign a new owner.
+ // This should be done by checking admin rights. if no admin rights, let's assume that circle should be removed.
+ if (!$notFound && $foundWithNoOwner) {
+ // TODO: assign a new owner and check that when changing owner, we do check that the destination instance is updated FOR SURE!
+ return true;
+ }
+
+ // some instances returned notFound, some returned circle with no owner. let's assume the circle is deprecated.
+ return false;
+ }
+
+ /**
+ * @throws GSStatusException
+ */
+ public function syncEvents() {
+
+ }
+
+ /**
+ *
+ */
+ private function removeDeprecatedEvents() {
+// $this->deprecatedEvents();
+
+ }
+
+
+}
+
diff --git a/lib/Service/GlobalScaleService.php b/lib/Service/GlobalScaleService.php
new file mode 100644
index 00000000..4b5ddf07
--- /dev/null
+++ b/lib/Service/GlobalScaleService.php
@@ -0,0 +1,226 @@
+<?php declare(strict_types=1);
+
+
+/**
+ * Circles - Bring cloud-users closer together.
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later. See the COPYING file.
+ *
+ * @author Maxence Lange <maxence@artificial-owl.com>
+ * @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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+namespace OCA\Circles\Service;
+
+
+use daita\MySmallPhpTools\Exceptions\RequestContentException;
+use daita\MySmallPhpTools\Exceptions\RequestNetworkException;
+use daita\MySmallPhpTools\Exceptions\RequestResultNotJsonException;
+use daita\MySmallPhpTools\Exceptions\RequestResultSizeException;
+use daita\MySmallPhpTools\Exceptions\RequestServerException;
+use daita\MySmallPhpTools\Model\Request;
+use daita\MySmallPhpTools\Model\SimpleDataStore;
+use daita\MySmallPhpTools\Traits\TRequest;
+use daita\MySmallPhpTools\Traits\TStringTools;
+use OC;
+use OCA\Circles\Db\GSEventsRequest;
+use OCA\Circles\Exceptions\GlobalScaleEventException;
+use OCA\Circles\Exceptions\GSKeyException;
+use OCA\Circles\Exceptions\GSStatusException;
+use OCA\Circles\GlobalScale\AGlobalScaleEvent;
+use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
+use OCA\Circles\Model\GlobalScale\GSWrapper;
+use OCP\AppFramework\QueryException;
+use OCP\IURLGenerator;
+
+
+/**
+ * Class GlobalScaleService
+ *
+ * @package OCA\Circles\Service
+ */
+class GlobalScaleService {
+
+
+ use TRequest;
+ use TStringTools;
+
+
+ /** @var IURLGenerator */
+ private $urlGenerator;
+
+ /** @var GSEventsRequest */
+ private $gsEventsRequest;
+
+ /** @var ConfigService */
+ private $configService;
+
+ /** @var MiscService */
+ private $miscService;
+
+
+ /**
+ * GlobalScaleService constructor.
+ *
+ * @param IURLGenerator $urlGenerator
+ * @param GSEventsRequest $gsEventsRequest
+ * @param ConfigService $configService
+ * @param MiscService $miscService
+ */
+ public function __construct(
+ IURLGenerator $urlGenerator,
+ GSEventsRequest $gsEventsRequest,
+ ConfigService $configService,
+ MiscService $miscService
+ ) {
+ $this->urlGenerator = $urlGenerator;
+ $this->gsEventsRequest = $gsEventsRequest;
+ $this->configService = $configService;
+ $this->miscService = $miscService;
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws GSStatusException
+ */
+ public function asyncBroadcast(GSEvent $event): void {
+ if (!$this->configService->getGSStatus(ConfigService::GS_ENABLED)) {
+ return;
+ }
+
+ $wrapper = new GSWrapper();
+ $wrapper->setEvent($event);
+ $wrapper->setToken($this->uuid());
+ $wrapper->setCreation(time());
+ $wrapper->setSeverity($event->getSeverity());
+
+ foreach ($this->getInstances() as $instance) {
+ $wrapper->setInstance($instance);
+ $wrapper = $this->gsEventsRequest->create($wrapper);
+ }
+
+ $path = $this->urlGenerator->linkToRoute(
+ 'circles.GlobalScale.asyncBroadcast', ['token' => $wrapper->getToken()]
+ );
+
+ $request = new Request($path, Request::TYPE_PUT);
+
+ $baseUrl = $this->urlGenerator->getBaseUrl();
+ if (substr($baseUrl, 0, 16) === 'http://localhost') {
+ $request->setBaseUrl(substr($baseUrl, 16));
+ $request->setAddress($this->configService->getLocalCloudId());
+ $request->setProtocols(['https', 'http']);
+ } else {
+ $request->setAddressFromUrl($baseUrl);
+ }
+
+ try {
+ $this->doRequest($request);
+ } catch (RequestContentException | RequestNetworkException | RequestResultSizeException | RequestServerException $e) {
+ }
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @return AGlobalScaleEvent
+ * @throws GlobalScaleEventException
+ */
+ public function getGlobalScaleEvent(GSEvent $event): AGlobalScaleEvent {
+ $class = '\OCA\Circles\\' . $event->getType();
+ try {
+ $gs = OC::$server->query($class);
+ if (!$gs instanceof AGlobalScaleEvent) {
+ throw new GlobalScaleEventException($class . ' not an AGlobalScaleEvent');
+ }
+
+ return $gs;
+ } catch (QueryException $e) {
+ throw new GlobalScaleEventException('AGlobalScaleEvent ' . $class . ' not found');
+ }
+ }
+
+
+ /**
+ * @return string
+ */
+ public function getKey(): string {
+ // TODO: sign event with real and temp key.
+ return 'abcd';
+ }
+
+
+ /**
+ * @param string $key
+ *
+ * @throws GSKeyException
+ */
+ public function checkKey(string $key) {
+ if ($key !== $this->getKey()) {
+ throw new GSKeyException('invalid key');
+ }
+ }
+
+
+ /**
+ * @param GSEvent $event
+ *
+ * @throws GSKeyException
+ */
+ public function checkEvent(GSEvent $event): void {
+ $this->checkKey($event->getKey());
+ }
+
+
+ /**
+ * @param bool $all
+ *
+ * @return array
+ * @throws GSStatusException
+ */
+ public function getInstances(bool $all = false): array {
+ /** @var string $lookup */
+ $lookup = $this->configService->getGSStatus(ConfigService::GS_LOOKUP);
+
+ $request = new Request('/instances', Request::TYPE_GET);
+ $request->setAddressFromUrl($lookup);
+
+ try {
+ $instances = $this->retrieveJson($request);
+ } catch (RequestContentException | RequestNetworkException | RequestResultSizeException | RequestServerException | RequestResultNotJsonException $e) {
+ $this->miscService->log('Issue while retrieving instances from lookup: ' . $e->getMessage());
+
+ return [];
+ }
+
+ if ($all) {
+ return $instances;
+ }
+
+ return array_diff($instances, $this->configService->getTrustedDomains());
+ }
+
+
+
+}
diff --git a/lib/Service/MembersService.php b/lib/Service/MembersService.php
index d4246ad6..60b85c09 100644
--- a/lib/Service/MembersService.php
+++ b/lib/Service/MembersService.php
@@ -41,12 +41,11 @@ use OCA\Circles\Exceptions\ConfigNoCircleAvailableException;
use OCA\Circles\Exceptions\EmailAccountInvalidFormatException;
use OCA\Circles\Exceptions\GroupDoesNotExistException;
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
+use OCA\Circles\Exceptions\MemberCantJoinCircleException;
use OCA\Circles\Exceptions\MemberDoesNotExistException;
use OCA\Circles\Exceptions\MemberIsNotModeratorException;
-use OCA\Circles\Exceptions\MemberIsOwnerException;
-use OCA\Circles\Exceptions\MemberTypeCantEditLevelException;
-use OCA\Circles\Exceptions\ModeratorIsNotHighEnoughException;
use OCA\Circles\Model\Circle;
+use OCA\Circles\Model\GlobalScale\GSEvent;
use OCA\Circles\Model\Member;
use OCP\IL10N;
use OCP\IUserManager;
@@ -89,6 +88,9 @@ class MembersService {
/** @var EventsService */
private $eventsService;
+ /** @var GSUpstreamService */
+ private $gsUpstreamService;
+
/** @var FileSharingBroadcaster */
private $fileSharingBroadcaster;
@@ -115,7 +117,8 @@ class MembersService {
$userId, IL10N $l10n, IUserManager $userManager, ConfigService $configService,
CirclesRequest $circlesRequest, MembersRequest $membersRequest, SharesRequest $sharesRequest,
TokensRequest $tokensRequest, CirclesService $circlesService, EventsService $eventsService,
- FileSharingBroadcaster $fileSharingBroadcaster, MiscService $miscService
+ GSUpstreamService $gsUpstreamService, FileSharingBroadcaster $fileSharingBroadcaster,
+ MiscService $miscService
) {
$this->userId = $userId;
$this->l10n = $l10n;
@@ -127,6 +130,7 @@ class MembersService {
$this->tokensRequest = $tokensRequest;
$this->circlesService = $circlesService;
$this->eventsService = $eventsService;
+ $this->gsUpstreamService = $gsUpstreamService;
$this->fileSharingBroadcaster = $fileSharingBroadcaster;
$this->miscService = $miscService;
}
@@ -140,14 +144,14 @@ class MembersService {
* @param string $circleUniqueId
* @param $ident
* @param int $type
+ * @param string $instance
*
* @param bool $force
*
* @return array
* @throws Exception
*/
- public function addMember($circleUniqueId, $ident, $type, bool $force = false) {
-
+ public function addMember($circleUniqueId, $ident, $type, string $instance, bool $force = false) {
if ($force === true) {
$circle = $this->circlesRequest->forceGetCircle($circleUniqueId);
} else {
@@ -157,7 +161,7 @@ class MembersService {
}
if (!$this->addMassiveMembers($circle, $ident, $type)) {
- $this->addSingleMember($circle, $ident, $type);
+ $this->addSingleMember($circle, $ident, $type, $instance, $force);
}
return $this->membersRequest->getMembers($circle->getUniqueId(), $circle->getHigherViewer(), $force);
@@ -171,23 +175,24 @@ class MembersService {
* @param string $ident
* @param int $type
*
- * @throws MemberAlreadyExistsException
- * @throws Exception
+ * @param string $instance
+ * @param bool $force
+ *
+ * @throws EmailAccountInvalidFormatException
+ * @throws NoUserException
*/
- private function addSingleMember(Circle $circle, $ident, $type) {
- $this->verifyIdentBasedOnItsType($ident, $type);
-
- $member = $this->membersRequest->getFreshNewMember($circle->getUniqueId(), $ident, $type);
- $member->hasToBeInviteAble();
+ private function addSingleMember(Circle $circle, $ident, $type, $instance = '', bool $force = false) {
- $this->circlesService->checkThatCircleIsNotFull($circle);
+ $this->verifyIdentBasedOnItsType($ident, $type, $instance);
- $this->addMemberBasedOnItsType($circle, $member);
+ $member = $this->membersRequest->getFreshNewMember($circle->getUniqueId(), $ident, $type, $instance);
- $this->membersRequest->updateMember($member);
- $this->fileSharingBroadcaster->sendMailAboutExistingShares($circle, $member);
+ $event = new GSEvent(GSEvent::MEMBER_ADD, false, $force);
+ $event->setSeverity(GSEvent::SEVERITY_HIGH);
- $this->eventsService->onMemberNew($circle, $member);
+ $event->setCircle($circle);
+ $event->setMember($member);
+ $this->gsUpstreamService->newEvent($event);
}
@@ -202,7 +207,6 @@ class MembersService {
* @throws Exception
*/
private function addMassiveMembers(Circle $circle, $ident, $type) {
-
if ($type === Member::TYPE_GROUP) {
return $this->addGroupMembers($circle, $ident);
}
@@ -221,9 +225,10 @@ class MembersService {
* @param Circle $circle
* @param Member $member
*
- * @throws Exception
+ * @throws CircleTypeNotValidException
+ * @throws MemberCantJoinCircleException
*/
- private function addMemberBasedOnItsType(Circle $circle, Member &$member) {
+ public function addMemberBasedOnItsType(Circle $circle, Member &$member) {
$this->addLocalMember($circle, $member);
$this->addEmailAddress($member);
$this->addContact($member);
@@ -234,7 +239,8 @@ class MembersService {
* @param Circle $circle
* @param Member $member
*
- * @throws Exception
+ * @throws CircleTypeNotValidException
+ * @throws MemberCantJoinCircleException
*/
private function addLocalMember(Circle $circle, Member $member) {
@@ -254,8 +260,6 @@ class MembersService {
* add mail address as contact.
*
* @param Member $member
- *
- * @throws Exception
*/
private function addEmailAddress(Member $member) {
@@ -268,11 +272,10 @@ class MembersService {
/**
+ * // TODO - check this on GS setup
* Add contact as member.
*
* @param Member $member
- *
- * @throws Exception
*/
private function addContact(Member $member) {
@@ -285,15 +288,22 @@ class MembersService {
/**
+ * // TODO - check this on GS setup
* Verify the availability of an ident, based on its type.
*
* @param string $ident
* @param int $type
+ * @param string $instance
*
- * @throws Exception
+ * @throws EmailAccountInvalidFormatException
+ * @throws NoUserException
*/
- private function verifyIdentBasedOnItsType(&$ident, $type) {
- $this->verifyIdentLocalMember($ident, $type);
+ public function verifyIdentBasedOnItsType(&$ident, $type, string $instance = '') {
+ if ($instance === $this->configService->getLocalCloudId()) {
+ $instance = '';
+ }
+
+ $this->verifyIdentLocalMember($ident, $type, $instance);
$this->verifyIdentEmailAddress($ident, $type);
$this->verifyIdentContact($ident, $type);
}
@@ -305,17 +315,21 @@ class MembersService {
* @param $ident
* @param $type
*
+ * @param string $instance
+ *
* @throws NoUserException
*/
- private function verifyIdentLocalMember(&$ident, $type) {
+ private function verifyIdentLocalMember(&$ident, $type, string $instance = '') {
if ($type !== Member::TYPE_USER) {
return;
}
- try {
- $ident = $this->miscService->getRealUserId($ident);
- } catch (NoUserException $e) {
- throw new NoUserException($this->l10n->t("This user does not exist"));
+ if ($instance === '') {
+ try {
+ $ident = $this->miscService->getRealUserId($ident);
+ } catch (NoUserException $e) {
+ throw new NoUserException($this->l10n->t("This user does not exist"));
+ }
}
}
@@ -407,6 +421,7 @@ class MembersService {
/**
+ * // TODO - check this on GS setup
* @param Circle $circle
* @param string $mails
*
@@ -480,6 +495,7 @@ class MembersService {
* @param string $circleUniqueId
* @param string $name
* @param int $type
+ * @param string $instance
* @param int $level
* @param bool $force
*
@@ -488,11 +504,11 @@ class MembersService {
* @throws CircleTypeNotValidException
* @throws ConfigNoCircleAvailableException
* @throws MemberDoesNotExistException
- * @throws MemberTypeCantEditLevelException
* @throws Exception
*/
- public function levelMember($circleUniqueId, $name, $type, $level, bool $force = false) {
-
+ public function levelMember(
+ string $circleUniqueId, string $name, int $type, string $instance, int $level, bool $force = false
+ ) {
$level = (int)$level;
if ($force === false) {
$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
@@ -506,9 +522,16 @@ class MembersService {
);
}
- $member = $this->membersRequest->forceGetMember($circle->getUniqueId(), $name, $type);
- $member->levelHasToBeEditable();
- $this->updateMemberLevel($circle, $member, $level, $force);
+ $member = $this->membersRequest->forceGetMember($circle->getUniqueId(), $name, $type, $instance);
+ if ($member->getLevel() !== $level) {
+ $event = new GSEvent(GSEvent::MEMBER_LEVEL, false, $force);
+ $event->setCircle($circle);
+
+ $event->getData()
+ ->sInt('level', $level);
+ $event->setMember($member);
+ $this->gsUpstreamService->newEvent($event);
+ }
if ($force === false) {
return $this->membersRequest->getMembers(
@@ -522,95 +545,22 @@ class MembersService {
/**
- * @param Circle $circle
- * @param Member $member
- * @param $level
- * @param bool $force
- *
- * @throws Exception
- */
- private function updateMemberLevel(Circle $circle, Member $member, $level, bool $force = false) {
- if ($member->getLevel() === $level) {
- return;
- }
-
- if ($level === Member::LEVEL_OWNER) {
- $this->switchOwner($circle, $member, $force);
- } else {
- $this->editMemberLevel($circle, $member, $level, $force);
- }
-
- $this->eventsService->onMemberLevel($circle, $member);
- }
-
-
- /**
- * @param Circle $circle
- * @param Member $member
- * @param $level
- * @param bool $force
- *
- * @throws Exception
- */
- private function editMemberLevel(Circle $circle, Member &$member, $level, bool $force = false) {
- if ($force === false) {
- $isMod = $circle->getHigherViewer();
- $isMod->hasToBeModerator();
- $isMod->hasToBeHigherLevel($level);
-
- $member->hasToBeMember();
- $isMod->hasToBeHigherLevel($member->getLevel());
- }
-
- $member->cantBeOwner();
-
- $member->setLevel($level);
- $this->membersRequest->updateMember($member);
- }
-
- /**
- * @param Circle $circle
- * @param Member $member
- * @param bool $force
- *
- * @throws Exception
- */
- private function switchOwner(Circle $circle, Member &$member, bool $force = false) {
- if ($force === false) {
- $isMod = $circle->getHigherViewer();
-
- // should already be possible from an NCAdmin, but not enabled in the frontend.
- $this->circlesService->hasToBeOwner($isMod);
- } else {
- $isMod = $circle->getOwner();
- }
-
- $member->hasToBeMember();
- $member->cantBeOwner();
-
- $member->setLevel(Member::LEVEL_OWNER);
- $this->membersRequest->updateMember($member);
-
- $isMod->setLevel(Member::LEVEL_ADMIN);
- $this->membersRequest->updateMember($isMod);
- }
-
-
- /**
* @param string $circleUniqueId
* @param string $name
- * @param $type
+ * @param int $type
+ * @param string $instance
* @param bool $force
*
- * @return array
+ * @return Member[]
* @throws CircleDoesNotExistException
* @throws ConfigNoCircleAvailableException
* @throws MemberDoesNotExistException
* @throws MemberIsNotModeratorException
- * @throws MemberIsOwnerException
- * @throws ModeratorIsNotHighEnoughException
+ * @throws Exception
*/
- public function removeMember($circleUniqueId, $name, $type, bool $force = false) {
+ public function removeMember(
+ string $circleUniqueId, string $name, int $type, string $instance, bool $force = false
+ ): array {
if ($force === false) {
$circle = $this->circlesRequest->getCircle($circleUniqueId, $this->userId);
@@ -620,20 +570,12 @@ class MembersService {
$circle = $this->circlesRequest->forceGetCircle($circleUniqueId);
}
- $member = $this->membersRequest->forceGetMember($circleUniqueId, $name, $type);
- $member->hasToBeMemberOrAlmost();
- $member->cantBeOwner();
-
- if ($force === false) {
- $circle->getHigherViewer()
- ->hasToBeHigherLevel($member->getLevel());
- }
-
- $this->eventsService->onMemberLeaving($circle, $member);
+ $member = $this->membersRequest->forceGetMember($circleUniqueId, $name, $type, $instance);
- $this->membersRequest->removeMember($member);
- $this->sharesRequest->removeSharesFromMember($member);
- $this->tokensRequest->removeTokensFromMember($member);
+ $event = new GSEvent(GSEvent::MEMBER_REMOVE, false, $force);
+ $event->setCircle($circle);
+ $event->setMember($member);
+ $this->gsUpstreamService->newEvent($event);
if ($force === false) {
return $this->membersRequest->getMembers(
@@ -646,11 +588,13 @@ class MembersService {
/**
+ * // TODO - check this on GS setup
* When a user is removed, remove him from all Circles
*
* @param $userId
*/
public function onUserRemoved($userId) {
+ // TODO: broadcast the event to all instances
$this->membersRequest->removeAllMembershipsFromUser($userId);
}
diff --git a/lib/Service/SearchService.php b/lib/Service/SearchService.php
index 2fff3d30..96112d59 100644
--- a/lib/Service/SearchService.php
+++ b/lib/Service/SearchService.php
@@ -75,6 +75,7 @@ class SearchService {
public function loadSearch() {
$this->searchList = [
'OCA\Circles\Search\LocalUsers',
+ 'OCA\Circles\Search\GlobalScaleUsers',
'OCA\Circles\Search\LocalGroups',
'OCA\Circles\Search\Contacts'
];
@@ -82,7 +83,6 @@ class SearchService {
public function searchGlobal($str) {
-
$result = [];
foreach ($this->searchList as $container) {
$searcher = \OC::$server->query((string)$container);
@@ -98,4 +98,4 @@ class SearchService {
return $result;
}
-} \ No newline at end of file
+}
diff --git a/lib/Service/ShareService.php b/lib/Service/ShareService.php
index 5de9ecd8..fa41acf6 100644
--- a/lib/Service/ShareService.php
+++ b/lib/Service/ShareService.php
@@ -57,8 +57,6 @@ class ShareService {
$this->l10n = $l10n;
$this->configService = $configService;
$this->miscService = $miscService;
-
- $this->loadSearch();
}
@@ -72,4 +70,4 @@ class ShareService {
}
-} \ No newline at end of file
+}
diff --git a/lib/ShareByCircleProvider.php b/lib/ShareByCircleProvider.php
index ea38b82d..f4554a2b 100644
--- a/lib/ShareByCircleProvider.php
+++ b/lib/ShareByCircleProvider.php
@@ -167,7 +167,7 @@ class ShareByCircleProvider extends CircleProviderRequest implements IShareProvi
throw $this->errorShareAlreadyExist($share);
}
-// $share->setToken($this->miscService->uuid(15));
+ $share->setToken($this->token(15));
// if ($this->configService->enforcePasswordProtection()) {
// $share->setPassword($this->miscService->uuid(15));
// }
@@ -413,8 +413,8 @@ class ShareByCircleProvider extends CircleProviderRequest implements IShareProvi
$data['share_with'] =
sprintf(
'%s (%s, %s) [%s]', $data['circle_name'],
- $this->l10n->t(Circle::TypeLongString($data['circle_type'])),
- $this->miscService->getDisplayName($data['circle_owner']), $data['share_with']
+ Circle::TypeLongString($data['circle_type']),
+ $this->miscService->getDisplayName($data['circle_owner'], true), $data['share_with']
);
@@ -761,8 +761,8 @@ class ShareByCircleProvider extends CircleProviderRequest implements IShareProvi
->setSharedWithDisplayName(
sprintf(
'%s (%s, %s)', $data['circle_name'],
- $this->l10n->t(Circle::TypeLongString($data['circle_type'])),
- $this->miscService->getDisplayName($data['circle_owner'])
+ Circle::TypeLongString($data['circle_type']),
+ $this->miscService->getDisplayName($data['circle_owner'], true)
)
);
}
@@ -928,19 +928,44 @@ class ShareByCircleProvider extends CircleProviderRequest implements IShareProvi
$qb = $this->dbConnection->getQueryBuilder();
$qb->select('*')
- ->from('share')
- ->where(
- $qb->expr()->orX(
- $qb->expr()->eq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE))
- )
- );
+ ->from('share')
+ ->where(
+ $qb->expr()
+ ->orX(
+ $qb->expr()
+ ->eq('share_type', $qb->createNamedParameter(IShare::TYPE_CIRCLE))
+ )
+ );
$cursor = $qb->execute();
- while($data = $cursor->fetch()) {
+ while ($data = $cursor->fetch()) {
$share = $this->createShareObject($data);
yield $share;
}
$cursor->closeCursor();
}
+
+
+ /**
+ * @param int $length
+ *
+ * @return string
+ */
+ protected function token(int $length = 15): string {
+ $chars = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890';
+
+ $str = '';
+ $max = strlen($chars);
+ for ($i = 0; $i < $length; $i++) {
+ try {
+ $str .= $chars[random_int(0, $max - 1)];
+ } catch (Exception $e) {
+ }
+ }
+
+ return $str;
+ }
+
+
}