migrate therinaldos.com data
Build & Deploy to DigitalOcean Space / build (push) Failing after 2m38s

This commit is contained in:
2024-05-05 15:50:45 -04:00
commit ef1ff240d4
23182 changed files with 3801898 additions and 0 deletions
@@ -0,0 +1,79 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@pontapreta.net>
* @copyright 2022
* @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\RelatedResources\AppInfo;
use OCA\Files\Event\LoadSidebar;
use OCA\RelatedResources\Listener\FileShareUpdate;
use OCA\RelatedResources\Listener\LoadSidebarScript;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
use OCP\AppFramework\Bootstrap\IBootstrap;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\Share\Events\ShareCreatedEvent;
use OCP\Share\Events\ShareDeletedEvent;
use Throwable;
/**
* Class Application
*
* @package OCA\RelatedResources\AppInfo
*/
class Application extends App implements IBootstrap {
public const APP_ID = 'related_resources';
/**
* @param array $params
*/
public function __construct(array $params = array()) {
parent::__construct(self::APP_ID, $params);
}
/**
* @param IRegistrationContext $context
*/
public function register(IRegistrationContext $context): void {
$context->registerEventListener(LoadSidebar::class, LoadSidebarScript::class);
$context->registerEventListener(ShareCreatedEvent::class, FileShareUpdate::class);
$context->registerEventListener(ShareDeletedEvent::class, FileShareUpdate::class);
}
/**
* @param IBootContext $context
*
* @throws Throwable
*/
public function boot(IBootContext $context): void {
}
}
@@ -0,0 +1,191 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Command;
use Exception;
use OC\Core\Command\Base;
use OCA\Circles\CirclesManager;
use OCA\RelatedResources\Exceptions\RelatedResourceProviderNotFound;
use OCA\RelatedResources\Service\RelatedService;
use OCA\RelatedResources\Tools\Traits\TStringTools;
use OCP\AutoloadNotAllowedException;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IConfig;
use OCP\IUserManager;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Symfony\Component\Console\Exception\InvalidArgumentException;
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\ConsoleOutput;
use Symfony\Component\Console\Output\OutputInterface;
/**
* Class Create
*
* @package OCA\RelatedResources\Command
*/
class Test extends Base {
use TStringTools;
private IUserManager $userManager;
private IConfig $config;
private ICache $cache;
private OutputInterface $output;
private RelatedService $relatedService;
public function __construct(
IUserManager $userManager,
IConfig $config,
RelatedService $relatedService,
ICacheFactory $cacheFactory
) {
$this->config = $config;
parent::__construct();
$this->userManager = $userManager;
$this->cache = $cacheFactory->createDistributed(RelatedService::CACHE_RELATED);
$this->relatedService = $relatedService;
}
/**
* @return void
*/
protected function configure() {
parent::configure();
$this->setName('related:test')
->setHidden(!$this->config->getSystemValueBool('debug'))
->setDescription('returns related resource to a share')
->addArgument('userId', InputArgument::REQUIRED, 'user\'s point of view')
->addArgument('providerId', InputArgument::REQUIRED, 'Provider Id (ie. files)')
->addOption('clear-cache', '', InputOption::VALUE_NONE, 'clear cache')
->addOption('resource-type', '', InputOption::VALUE_REQUIRED, 'limit to a type of resources', '')
->addArgument('itemId', InputArgument::REQUIRED, 'Item Id');
}
/**
* @param InputInterface $input
* @param OutputInterface $output
*
* @return int
* @throws RelatedResourceProviderNotFound
*/
protected function execute(InputInterface $input, OutputInterface $output): int {
$userId = $input->getArgument('userId');
$providerId = $input->getArgument('providerId');
$itemId = $input->getArgument('itemId');
if ($input->getOption('clear-cache')) {
$this->cache->clear();
}
$user = $this->userManager->get($userId);
if (is_null($user)) {
throw new InvalidArgumentException('must specify a valid local user');
}
$userId = $user->getUID();
try {
/** @var CirclesManager $circleManager */
$circleManager = Server::get(CirclesManager::class);
} catch (ContainerExceptionInterface | AutoloadNotAllowedException $e) {
throw new Exception('Circles needs to be enabled');
}
$circleManager->startSession($circleManager->getLocalFederatedUser($userId));
$this->displayRecipients($providerId, $itemId);
$this->displayRelated($providerId, $itemId, $input->getOption('resource-type'), ($input->getOption('output') === 'json'));
return 0;
}
private function displayRecipients(string $providerId, string $itemId): void {
$result = $this->relatedService->getRelatedFromItem($providerId, $itemId);
$output = new ConsoleOutput();
$output->writeln('<info>Title</info>: ' . $result->getTitle());
$output->writeln('<info>Group Shared</info>: ' . ($result->isGroupShared() ? 'true' : 'false'));
$output->writeln('<info>Virtual Group</info>: ' . json_encode($result->getVirtualGroup()));
$output->writeln('<info>Recipients</info>: ' . json_encode($result->getRecipients()));
$output->writeln('');
}
private function displayRelated(string $providerId, string $itemId, string $resourceType, bool $json): void {
$result = $this->relatedService->getRelatedToItem($providerId, $itemId, -1, $resourceType);
$output = new ConsoleOutput();
if ($json) {
$output->writeln(json_encode($result, JSON_PRETTY_PRINT));
return;
}
$output = $output->section();
$table = new Table($output);
$table->setHeaders(
[
'Provider Id',
'Item Id',
'Title',
'Description',
'Score',
'Link'
]
);
$table->render();
foreach ($result as $entry) {
$table->appendRow(
[
$entry->getProviderId(),
$entry->getItemId(),
$entry->getTitle(),
$entry->getSubtitle(),
$entry->getScore(),
$entry->getUrl()
]
);
}
$output->writeln('');
}
}
@@ -0,0 +1,129 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022, Maxence Lange <maxence@artificial-owl.com>
* @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\RelatedResources\Controller;
use Exception;
use OCA\Circles\CirclesManager;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Service\ConfigService;
use OCA\RelatedResources\Service\RelatedService;
use OCA\RelatedResources\Tools\Traits\TDeserialize;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\DataResponse;
use OCP\AppFramework\OCS\OCSException;
use OCP\AppFramework\OCSController;
use OCP\AutoloadNotAllowedException;
use OCP\IRequest;
use OCP\IUserSession;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Log\LoggerInterface;
class ApiController extends OcsController {
use TDeserialize;
private LoggerInterface $logger;
private IUserSession $userSession;
private RelatedService $relatedService;
private ConfigService $configService;
private ?CirclesManager $circlesManager = null;
public function __construct(
string $appName,
IRequest $request,
LoggerInterface $logger,
IUserSession $userSession,
RelatedService $relatedService,
ConfigService $configService
) {
parent::__construct($appName, $request);
$this->logger = $logger;
$this->userSession = $userSession;
$this->relatedService = $relatedService;
$this->configService = $configService;
try {
$this->circlesManager = Server::get(CirclesManager::class);
} catch (ContainerExceptionInterface | AutoloadNotAllowedException $e) {
}
}
/**
* @NoAdminRequired
*
* @param string $providerId
* @param string $itemId
* @param string $resourceType
* @return DataResponse
* @throws OCSException
*/
public function getRelatedResources(
string $providerId,
string $itemId,
int $limit = 0,
string $resourceType = ''
): DataResponse {
if (is_null($this->circlesManager)) {
$this->logger->info('RelatedResources require Circles');
return new DataResponse([]);
}
$limit = ($limit > 0) ? $limit : $this->configService->getAppValueInt(ConfigService::RESULT_MAX);
try {
$this->circlesManager->startSession();
$result = $this->relatedService->getRelatedToItem(
$providerId,
$itemId,
$limit,
$resourceType
);
// cleanData on result, to not send useless data.
$new = [];
foreach ($result as $related) {
$new[] = RelatedResource::cleanData($this->serialize($related));
}
return new DataResponse($new);
} catch (Exception $e) {
$this->logger->error($e->getMessage(), ['exception' => $e]);
throw new OCSException(
($e->getMessage() === '') ? get_class($e) : $e->getMessage(),
Http::STATUS_BAD_REQUEST
);
}
}
}
@@ -0,0 +1,124 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\CalendarDataNotFoundException;
use OCA\RelatedResources\Model\Calendar;
use OCA\RelatedResources\Model\CalendarShare;
class CalendarShareRequest extends CalendarShareRequestBuilder {
/**
* @param string $principalUri
* @param string $uri
*
* @return Calendar
* @throws CalendarDataNotFoundException
*/
public function getCalendarByUri(string $principalUri, string $uri): Calendar {
$qb = $this->getCalendarSelectSql();
$qb->limit('principaluri', $principalUri);
$qb->limit('uri', $uri);
return $this->getCalendarFromRequest($qb);
}
/**
* @param int $calendarId
*
* @return CalendarShare[]
*/
public function getSharesByCalendarId(int $calendarId): array {
$qb = $this->getCalendarShareSelectSql();
$qb->limit('type', 'calendar');
$qb->limitInt('resourceid', $calendarId);
return $this->getSharesFromRequest($qb);
}
/**
* @param string $singleId
*
* @return Calendar[]
*/
public function getCalendarAvailableToCircle(string $singleId): array {
$qb = $this->getCalendarSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_DAV_SHARE, 'ds',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ds.resourceid')
);
$qb->limit('type', 'calendar', 'ds');
$qb->limit('principaluri', 'principals/circles/' . $singleId, 'ds');
return $this->getCalendarsFromRequest($qb);
}
/**
* @param string $groupName
*
* @return Calendar[]
*/
public function getCalendarAvailableToGroup(string $groupName): array {
$qb = $this->getCalendarSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_DAV_SHARE, 'ds',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ds.resourceid')
);
$qb->limit('type', 'calendar', 'ds');
$qb->limit('principaluri', 'principals/groups/' . $groupName, 'ds');
return $this->getCalendarsFromRequest($qb);
}
/**
* @param string $userName
*
* @return Calendar[]
*/
public function getCalendarAvailableToUser(string $userName): array {
$qb = $this->getCalendarSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_DAV_SHARE, 'ds',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ds.resourceid')
);
$qb->limit('type', 'calendar', 'ds');
$qb->limit('principaluri', 'principals/users/' . $userName, 'ds');
return $this->getCalendarsFromRequest($qb);
}
}
@@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\CalendarDataNotFoundException;
use OCA\RelatedResources\Model\Calendar;
use OCA\RelatedResources\Model\CalendarShare;
use OCA\RelatedResources\Tools\Exceptions\InvalidItemException;
use OCA\RelatedResources\Tools\Exceptions\RowNotFoundException;
class CalendarShareRequestBuilder extends CoreQueryBuilder {
/**
* @return CoreRequestBuilder
*/
protected function getCalendarSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_CALENDARS, self::$externalTables[self::TABLE_CALENDARS]);
return $qb;
}
/**
* @return CoreRequestBuilder
*/
protected function getCalendarShareSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_DAV_SHARE, self::$externalTables[self::TABLE_DAV_SHARE]);
return $qb;
}
/**
* @param CoreRequestBuilder $qb
*
* @return Calendar
* @throws CalendarDataNotFoundException
*/
public function getCalendarFromRequest(CoreRequestBuilder $qb): Calendar {
/** @var Calendar $calendar */
try {
$calendar = $qb->asItem(Calendar::class);
} catch (InvalidItemException | RowNotFoundException $e) {
throw new CalendarDataNotFoundException();
}
return $calendar;
}
/**
* @param CoreRequestBuilder $qb
*
* @return Calendar[]
*/
public function getCalendarsFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(Calendar::class);
}
/**
* @param CoreRequestBuilder $qb
*
* @return CalendarShare[]
*/
public function getSharesFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(CalendarShare::class);
}
}
@@ -0,0 +1,120 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Service\ConfigService;
/**
*
*/
class CoreQueryBuilder {
public const TABLE_FILES_SHARE = 'share';
public const TABLE_DECK_SHARE = 'deck_board_acl';
public const TABLE_DECK_BOARD = 'deck_boards';
public const TABLE_TALK_ATTENDEE = 'talk_attendees';
public const TABLE_TALK_ROOM = 'talk_rooms';
public const TABLE_DAV_SHARE = 'dav_shares';
public const TABLE_CALENDARS = 'calendars';
public const TABLE_CAL_OBJECTS = 'calendarobjects';
public const TABLE_CAL_OBJ_PROPS = 'calendarobjects_props';
protected ConfigService $configService;
public static array $externalTables = [
self::TABLE_FILES_SHARE => [
'share_type',
'share_with',
'uid_owner',
'uid_initiator',
'file_source',
'file_target',
'stime'
],
self::TABLE_DECK_SHARE => [
'board_id',
'type',
'participant'
],
self::TABLE_DECK_BOARD => [
'id',
'title',
'owner',
'last_modified'
],
self::TABLE_TALK_ATTENDEE => [
'room_id',
'actor_type',
'actor_id'
],
self::TABLE_TALK_ROOM => [
'name',
'type',
'token'
],
self::TABLE_DAV_SHARE => [
'principaluri',
'resourceid'
],
self::TABLE_CALENDARS => [
'id',
'principaluri',
'uri',
'displayname'
],
self::TABLE_CAL_OBJECTS => [
'firstoccurence',
'lastoccurence'
],
self::TABLE_CAL_OBJ_PROPS => [
'value'
]
];
/**
* @param ConfigService $configService
*/
public function __construct(ConfigService $configService) {
$this->configService = $configService;
}
/**
* @return CoreRequestBuilder
*/
public function getQueryBuilder(): CoreRequestBuilder {
return new CoreRequestBuilder();
}
}
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@pontapreta.net>
* @copyright 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Tools\Db\ExtendedQueryBuilder;
class CoreRequestBuilder extends ExtendedQueryBuilder {
public function __construct() {
parent::__construct();
}
}
@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\DeckDataNotFoundException;
use OCA\RelatedResources\Model\DeckBoard;
use OCA\RelatedResources\Model\DeckShare;
use OCP\Share\IShare;
class DeckRequest extends DeckRequestBuilder {
/**
* @param int $itemId
*
* @return DeckBoard
* @throws DeckDataNotFoundException
*/
public function getBoardById(int $itemId): DeckBoard {
$qb = $this->getDeckBoardSelectSql();
$qb->limitInt('id', $itemId);
return $this->getDeckFromRequest($qb);
}
/**
* @param int $boardId
*
* @return DeckShare[]
*/
public function getSharesByBoardId(int $boardId): array {
$qb = $this->getDeckShareSelectSql();
$qb->limitInt('board_id', $boardId);
return $this->getSharesFromRequest($qb);
}
/**
* @param string $singleId
*
* @return DeckBoard[]
*/
public function getDeckAvailableToCircle(string $singleId): array {
$qb = $this->getDeckBoardSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_DECK_SHARE, 'ds',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ds.board_id')
);
$qb->limitInt('type', IShare::TYPE_CIRCLE, 'ds');
$qb->limit('participant', $singleId, 'ds');
return $this->getDecksFromRequest($qb);
}
/**
* @param string $groupName
*
* @return DeckBoard[]
*/
public function getDeckAvailableToGroup(string $groupName): array {
$qb = $this->getDeckBoardSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_DECK_SHARE, 'ds',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ds.board_id')
);
$qb->limitInt('type', IShare::TYPE_GROUP, 'ds');
$qb->limit('participant', $groupName, 'ds');
return $this->getDecksFromRequest($qb);
}
/**
* @param string $userName
*
* @return DeckBoard[]
*/
public function getDeckAvailableToUser(string $userName): array {
$qb = $this->getDeckBoardSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_DECK_SHARE, 'ds',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ds.board_id')
);
$qb->limitInt('type', IShare::TYPE_USER, 'ds');
$qb->limit('participant', $userName, 'ds');
return $this->getDecksFromRequest($qb);
}
}
@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\DeckDataNotFoundException;
use OCA\RelatedResources\Model\DeckBoard;
use OCA\RelatedResources\Model\DeckShare;
use OCA\RelatedResources\Tools\Exceptions\InvalidItemException;
use OCA\RelatedResources\Tools\Exceptions\RowNotFoundException;
class DeckRequestBuilder extends CoreQueryBuilder {
/**
* @return CoreRequestBuilder
*/
protected function getDeckBoardSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_DECK_BOARD, self::$externalTables[self::TABLE_DECK_BOARD]);
return $qb;
}
protected function getDeckShareSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_DECK_SHARE, self::$externalTables[self::TABLE_DECK_SHARE]);
return $qb;
}
/**
* @param CoreRequestBuilder $qb
*
* @return DeckBoard
* @throws DeckDataNotFoundException
*/
public function getDeckFromRequest(CoreRequestBuilder $qb): DeckBoard {
/** @var DeckBoard $deck */
try {
$deck = $qb->asItem(DeckBoard::class);
} catch (InvalidItemException | RowNotFoundException $e) {
throw new DeckDataNotFoundException();
}
return $deck;
}
/**
* @param CoreRequestBuilder $qb
*
* @return DeckBoard[]
*/
public function getDecksFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(DeckBoard::class);
}
/**
* @param CoreRequestBuilder $qb
*
* @return DeckShare[]
*/
public function getSharesFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(DeckShare::class);
}
}
@@ -0,0 +1,103 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Model\FilesShare;
use OCP\Share\IShare;
class FilesShareRequest extends FilesShareRequestBuilder {
/**
* @param int $itemId
*
* @return FilesShare[]
*/
public function getSharesByItemId(int $itemId): array {
$qb = $this->getFilesShareSelectSql();
$qb->limitInt('file_source', $itemId);
return $this->getItemsFromRequest($qb);
}
/**
* @param array $itemIds
*
* @return FilesShare[]
*/
public function getSharesByItemIds(array $itemIds): array {
$qb = $this->getFilesShareSelectSql();
$qb->limitInArray('file_source', $itemIds);
return $this->getItemsFromRequest($qb);
}
/**
* @param string $singleId
*
* @return FilesShare[]
*/
public function getSharesToCircle(string $singleId): array {
$qb = $this->getFilesShareSelectSql();
$qb->limitInt('share_type', IShare::TYPE_CIRCLE);
$qb->limit('share_with', $singleId);
return $this->getItemsFromRequest($qb);
}
/**
* @param string $groupName
*
* @return FilesShare[]
*/
public function getSharesToGroup(string $groupName): array {
$qb = $this->getFilesShareSelectSql();
$qb->limitInt('share_type', IShare::TYPE_GROUP);
$qb->limit('share_with', $groupName);
return $this->getItemsFromRequest($qb);
}
/**
* @param string $userId
*
* @return FilesShare[]
*/
public function getSharesToUser(string $userId): array {
$qb = $this->getFilesShareSelectSql();
$qb->limitInt('share_type', IShare::TYPE_USER);
$qb->limit('share_with', $userId);
return $this->getItemsFromRequest($qb);
}
}
@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\FilesShareNotFoundException;
use OCA\RelatedResources\Model\FilesShare;
use OCA\RelatedResources\Tools\Exceptions\InvalidItemException;
use OCA\RelatedResources\Tools\Exceptions\RowNotFoundException;
class FilesShareRequestBuilder extends CoreQueryBuilder {
/**
* @return CoreRequestBuilder
*/
protected function getFilesShareSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_FILES_SHARE, self::$externalTables[self::TABLE_FILES_SHARE]);
return $qb;
}
/**
* @param CoreRequestBuilder $qb
*
* @return FilesShare
* @throws FilesShareNotFoundException
*/
public function getItemFromRequest(CoreRequestBuilder $qb): FilesShare {
/** @var FilesShare $share */
try {
$share = $qb->asItem(FilesShare::class);
} catch (InvalidItemException | RowNotFoundException $e) {
throw new FilesShareNotFoundException();
}
return $share;
}
/**
* @param CoreRequestBuilder $qb
*
* @return FilesShare[]
*/
public function getItemsFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(FilesShare::class);
}
}
@@ -0,0 +1,125 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\TalkDataNotFoundException;
use OCA\RelatedResources\Model\TalkActor;
use OCA\RelatedResources\Model\TalkRoom;
class TalkRoomRequest extends TalkRoomRequestBuilder {
/**
* @param string $token
*
* @return TalkRoom
* @throws TalkDataNotFoundException
*/
public function getRoomByToken(string $token): TalkRoom {
$qb = $this->getTalkRoomSelectSql();
$qb->limit('token', $token);
return $this->getRoomFromRequest($qb);
}
/**
* @param string $token
*
* @return TalkActor[]
*/
public function getActorsByToken(string $token): array {
$qb = $this->getActorSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_TALK_ROOM, 'tr',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.room_id', 'tr.id')
);
$qb->limit('token', $token, 'tr');
return $this->getActorsFromRequest($qb);
}
/**
* @param string $singleId
*
* @return TalkRoom[]
*/
public function getRoomsAvailableToCircle(string $singleId): array {
$qb = $this->getTalkRoomSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_TALK_ATTENDEE, 'ta',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ta.room_id')
);
$qb->limit('actor_type', 'circles', 'ta');
$qb->limit('actor_id', $singleId, 'ta');
return $this->getRoomsFromRequest($qb);
}
/**
* @param string $groupName
*
* @return TalkRoom[]
*/
public function getRoomsAvailableToGroup(string $groupName): array {
$qb = $this->getTalkRoomSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_TALK_ATTENDEE, 'ta',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ta.room_id')
);
$qb->limit('actor_type', 'groups', 'ta');
$qb->limit('actor_id', $groupName, 'ta');
return $this->getRoomsFromRequest($qb);
}
/**
* @param string $userName
*
* @return TalkRoom[]
*/
public function getRoomsAvailableToUser(string $userName): array {
$qb = $this->getTalkRoomSelectSql();
$qb->innerJoin(
$qb->getDefaultSelectAlias(), self::TABLE_TALK_ATTENDEE, 'ta',
$qb->expr()->eq($qb->getDefaultSelectAlias() . '.id', 'ta.room_id')
);
$qb->limit('actor_type', 'users', 'ta');
$qb->limit('actor_id', $userName, 'ta');
return $this->getRoomsFromRequest($qb);
}
}
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Db;
use OCA\RelatedResources\Exceptions\TalkDataNotFoundException;
use OCA\RelatedResources\Model\TalkActor;
use OCA\RelatedResources\Model\TalkRoom;
use OCA\RelatedResources\Tools\Exceptions\InvalidItemException;
use OCA\RelatedResources\Tools\Exceptions\RowNotFoundException;
class TalkRoomRequestBuilder extends CoreQueryBuilder {
/**
* @return CoreRequestBuilder
*/
protected function getTalkRoomSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_TALK_ROOM, self::$externalTables[self::TABLE_TALK_ROOM]);
return $qb;
}
protected function getActorSelectSql(): CoreRequestBuilder {
$qb = $this->getQueryBuilder();
$qb->generateSelect(self::TABLE_TALK_ATTENDEE, self::$externalTables[self::TABLE_TALK_ATTENDEE]);
return $qb;
}
/**
* @param CoreRequestBuilder $qb
*
* @return TalkRoom
* @throws TalkDataNotFoundException
*/
public function getRoomFromRequest(CoreRequestBuilder $qb): TalkRoom {
/** @var TalkRoom $room */
try {
$room = $qb->asItem(TalkRoom::class);
} catch (InvalidItemException | RowNotFoundException $e) {
throw new TalkDataNotFoundException();
}
return $room;
}
/**
* @param CoreRequestBuilder $qb
*
* @return TalkRoom[]
*/
public function getRoomsFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(TalkRoom::class);
}
/**
* @param CoreRequestBuilder $qb
*
* @return TalkActor[]
*/
public function getActorsFromRequest(CoreRequestBuilder $qb): array {
return $qb->asItems(TalkActor::class);
}
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class CacheNotFoundException extends Exception {
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class CalendarDataNotFoundException extends Exception {
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class DeckDataNotFoundException extends Exception {
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class FilesShareNotFoundException extends Exception {
}
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2023
* @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\RelatedResources\Exceptions;
use Exception;
class GroupFolderNotFoundException extends Exception {
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class RelatedResourceNotFound extends Exception {
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class RelatedResourceProviderNotFound extends Exception {
}
@@ -0,0 +1,37 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Exceptions;
use Exception;
class TalkDataNotFoundException extends Exception {
}
@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@pontapreta.net>
* @copyright 2022
* @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\RelatedResources;
interface ILinkWeightCalculator {
/**
* @param IRelatedResource $current
* @param IRelatedResource[] $result
*/
public function weight(IRelatedResource $current, array &$result): void;
}
@@ -0,0 +1,106 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@pontapreta.net>
* @copyright 2022
* @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\RelatedResources;
interface IRelatedResource {
public function getProviderId(): string;
public function getItemId(): string;
public function setTitle(string $title): self;
public function getTitle(): string;
public function setSubtitle(string $subtitle): self;
public function getSubtitle(): string;
public function setTooltip(string $tooltip): self;
public function getTooltip(): string;
public function setIcon(string $icon): self;
public function getIcon(): string;
public function setPreview(string $preview): self;
public function getPreview(): string;
public function setUrl(string $url): self;
public function getUrl(): string;
public function improve(float $quality, string $type, bool $diminishingReturn = true): self;
public function getImprovements(): array;
public function getScore(): float;
public function setVirtualGroup(array $virtualGroup): self;
public function getVirtualGroup(): array;
public function addToVirtualGroup(string $singleId): self;
public function mergeVirtualGroup(array $virtualGroup): self;
public function setRecipients(array $recipients): self;
public function getRecipients(): array;
public function addRecipient(string $singleId): self;
public function mergeRecipients(array $recipients): self;
public function setAsGroupShared(bool $groupShared = true): self;
public function isGroupShared(): bool;
public function setMeta(string $k, string $v): self;
public function setMetaInt(string $k, int $v): self;
public function setMetaArray(string $k, array $v): self;
public function setMetas(array $metas): self;
public function hasMeta(string $k): bool;
public function getMeta(string $k): string;
public function getMetaInt(string $k): int;
public function getMetaArray(string $k): array;
public function getMetas(): array;
}
@@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* This file is licensed under the Affero General Public License version 3 or
* later. See the COPYING file.
*
* @author Maxence Lange <maxence@pontapreta.net>
* @copyright 2022
* @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\RelatedResources;
use OCA\Circles\CirclesManager;
use OCA\Circles\Model\FederatedUser;
interface IRelatedResourceProvider {
public function getProviderId(): string;
/**
* returns the list of ILinkWeightCalculator provided by this app
*
* @return string[]
*/
public function loadWeightCalculator(): array;
/**
* convert item to IRelatedResource, based on available shares
*
* @param CirclesManager $circlesManager
* @param string $itemId
*
* @return IRelatedResource|null
*/
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource;
/**
* returns itemIds (as string) the entity have access to
*
* @param FederatedUser $entity
*
* @return string[]
*/
public function getItemsAvailableToEntity(FederatedUser $entity): array;
/**
* improve a related resource before sending result to front-end.
*
* @param CirclesManager $circlesManager
* @param IRelatedResource $entry
*
* @return void
*/
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void;
}
@@ -0,0 +1,84 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\LinkWeightCalculators;
use OCA\RelatedResources\ILinkWeightCalculator;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class AncienShareWeightCalculator implements ILinkWeightCalculator {
use TArrayTools;
private static float $RATIO_5Y = 0.4;
private static float $RATIO_3Y = 0.7;
private static float $RATIO_1Y = 0.85;
/**
* @inheritDoc
*/
public function weight(IRelatedResource $current, array &$result): void {
if (!$current->hasMeta(RelatedResource::LINK_CREATION)) {
return;
}
foreach ($result as $entry) {
if (!$entry->hasMeta(RelatedResource::LINK_CREATION)) {
continue;
}
$now = time();
$entryCreation = $entry->getMetaInt(RelatedResource::LINK_CREATION);
if ($entryCreation < $now - (5 * 360 * 24 * 3600)) { // 5y
$entry->improve(self::$RATIO_5Y, 'ancien_5y');
} elseif ($entryCreation < $now - (3 * 360 * 24 * 3600)) { // 3y
$entry->improve(self::$RATIO_3Y, 'ancien_3y');
} elseif ($entryCreation < $now - (360 * 24 * 3600)) { // 1y
$entry->improve(self::$RATIO_1Y, 'ancien_1y');
}
$diff = abs(
$current->getMetaInt(RelatedResource::LINK_CREATION)
- $entry->getMetaInt(RelatedResource::LINK_CREATION)
);
// calculate an improvement base on 0.75 up to 1.2, based on difference of time between 2 shares
// with 1.0 score for a 3 month period
$neutral = 90 * 24 * 3600;
$ratio = $diff - $neutral;
$impr = 1 - ($ratio * 0.2 / $neutral);
$impr = max($impr, 0.75);
$entry->improve($impr, 'ancien_3m');
}
}
}
@@ -0,0 +1,65 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\LinkWeightCalculators;
use OCA\RelatedResources\ILinkWeightCalculator;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class KeywordWeightCalculator implements ILinkWeightCalculator {
use TArrayTools;
/**
* @inheritDoc
*/
public function weight(IRelatedResource $current, array &$result): void {
if (!$current->hasMeta(RelatedResource::ITEM_KEYWORDS)) {
return;
}
foreach ($result as $entry) {
if (!$entry->hasMeta(RelatedResource::ITEM_KEYWORDS)) {
continue;
}
foreach ($entry->getMetaArray(RelatedResource::ITEM_KEYWORDS) as $kw) {
if (strlen($kw) <= 3) {
continue;
}
if (in_array($kw, $current->getMetaArray(RelatedResource::ITEM_KEYWORDS))) {
$entry->improve(RelatedResource::$IMPROVE_HIGH_LINK, 'keyword');
}
}
}
}
}
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\LinkWeightCalculators;
use OCA\RelatedResources\ILinkWeightCalculator;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class TimeWeightCalculator implements ILinkWeightCalculator {
use TArrayTools;
private const DELAY_1 = 120;
private const DELAY_2 = 900;
private const DELAY_3 = 7200;
/**
* @inheritDoc
*/
public function weight(IRelatedResource $current, array &$result): void {
if (!$current->hasMeta(RelatedResource::LINK_CREATION)
|| !$current->hasMeta(RelatedResource::LINK_CREATOR)
|| !$current->hasMeta(RelatedResource::LINK_RECIPIENT)) {
return;
}
foreach ($result as $entry) {
if (!$entry->hasMeta(RelatedResource::LINK_CREATION)
|| !$entry->hasMeta(RelatedResource::LINK_CREATOR)
|| !$entry->hasMeta(RelatedResource::LINK_RECIPIENT)) {
continue;
}
// check if link is initiated from same entity
if ($entry->getMeta(RelatedResource::LINK_CREATOR)
!== $current->getMeta(RelatedResource::LINK_CREATOR)) {
continue;
}
if ($entry->getMetaInt(RelatedResource::LINK_CREATION)
< $current->getMetaInt(RelatedResource::LINK_CREATION) + self::DELAY_1
&& $entry->getMetaInt(RelatedResource::LINK_CREATION)
> $current->getMetaInt(RelatedResource::LINK_CREATION) - self::DELAY_1) {
$entry->improve(RelatedResource::$IMPROVE_HIGH_LINK, 'time_delay_1');
continue;
}
if ($entry->getMetaInt(RelatedResource::LINK_CREATION)
< $current->getMetaInt(RelatedResource::LINK_CREATION) + self::DELAY_2
&& $entry->getMetaInt(RelatedResource::LINK_CREATION)
> $current->getMetaInt(RelatedResource::LINK_CREATION) - self::DELAY_2) {
$entry->improve(RelatedResource::$IMPROVE_MEDIUM_LINK, 'time_delay_2');
continue;
}
if ($entry->getMetaInt(RelatedResource::LINK_CREATION)
< $current->getMetaInt(RelatedResource::LINK_CREATION) + self::DELAY_3
&& $entry->getMetaInt(RelatedResource::LINK_CREATION)
> $current->getMetaInt(RelatedResource::LINK_CREATION) - self::DELAY_3) {
$entry->improve(RelatedResource::$IMPROVE_LOW_LINK, 'time_delay_3');
continue;
}
}
}
}
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Listener;
use Exception;
use OCA\RelatedResources\Service\RelatedService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Share\Events\ShareCreatedEvent;
use OCP\Share\Events\ShareDeletedEvent;
/**
* @template-implements IEventListener<Event>
*/
class FileShareUpdate implements IEventListener {
private RelatedService $relatedService;
public function __construct(
RelatedService $relatedService
) {
$this->relatedService = $relatedService;
}
public function handle(Event $event): void {
if (!($event instanceof ShareCreatedEvent)
&& !($event instanceof ShareDeletedEvent)) {
return;
}
try {
$this->relatedService->flushCache();
} catch (Exception $e) {
}
}
}
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019, John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @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\RelatedResources\Listener;
use OCA\Files\Event\LoadSidebar;
use OCA\RelatedResources\AppInfo\Application;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\Util;
/**
* @template-implements IEventListener<Event>
*/
class LoadSidebarScript implements IEventListener {
public function handle(Event $event): void {
if (!($event instanceof LoadSidebar)) {
return;
}
Util::addScript(Application::APP_ID, 'related_resources');
}
}
@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class Calendar implements IQueryRow, JsonSerializable {
use TArrayTools;
private int $calendarId = 0;
private string $calendarName = '';
private string $calendarPrincipalUri = '';
private string $calendarUri = '';
public function __construct() {
}
public function getId(): string {
return $this->getCalendarPrincipalUri() . ':' . $this->getCalendarUri();
}
public function setCalendarId(int $calendarId): self {
$this->calendarId = $calendarId;
return $this;
}
public function getCalendarId(): int {
return $this->calendarId;
}
public function setCalendarName(string $calendarName): self {
$this->calendarName = $calendarName;
return $this;
}
public function getCalendarName(): string {
return $this->calendarName;
}
public function setCalendarPrincipalUri(string $calendarPrincipalUri): self {
$this->calendarPrincipalUri = $calendarPrincipalUri;
return $this;
}
public function getCalendarPrincipalUri(): string {
return $this->calendarPrincipalUri;
}
public function setCalendarUri(string $calendarUri): self {
$this->calendarUri = $calendarUri;
return $this;
}
public function getCalendarUri(): string {
return $this->calendarUri;
}
public function importFromDatabase(array $data): IQueryRow {
$this->setCalendarId($this->getInt('id', $data))
->setCalendarName($this->get('displayname', $data))
->setCalendarPrincipalUri($this->get('principaluri', $data))
->setCalendarUri($this->get('uri', $data));
return $this;
}
public function jsonSerialize(): array {
return [
'calendarName' => $this->getCalendarName(),
'calendarPrincipalUri' => $this->getCalendarPrincipalUri(),
'calendarUri' => $this->getCalendarUri()
];
}
}
@@ -0,0 +1,122 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class CalendarShare implements IQueryRow, JsonSerializable {
use TArrayTools;
private int $calendarId = 0;
private string $sharePrincipalUri = '';
private int $type = 0;
private string $user = '';
public function __construct() {
}
public function setCalendarId(int $calendarId): self {
$this->calendarId = $calendarId;
return $this;
}
public function getCalendarId(): int {
return $this->calendarId;
}
public function setSharePrincipalUri(string $sharePrincipalUri): self {
$this->sharePrincipalUri = $sharePrincipalUri;
return $this;
}
public function getSharePrincipalUri(): string {
return $this->sharePrincipalUri;
}
/**
* @param int $type
*
* @return CalendarShare
*/
public function setType(int $type): self {
$this->type = $type;
return $this;
}
/**
* @return int
*/
public function getType(): int {
return $this->type;
}
/**
* @param string $user
*
* @return CalendarShare
*/
public function setUser(string $user): self {
$this->user = $user;
return $this;
}
/**
* @return string
*/
public function getUser(): string {
return $this->user;
}
public function importFromDatabase(array $data): IQueryRow {
$this->setCalendarId($this->getInt('resourceid', $data))
->setSharePrincipalUri($this->get('principaluri', $data));
return $this;
}
public function jsonSerialize(): array {
return [
'id' => $this->getCalendarId(),
'sharePrincipalUri' => $this->getSharePrincipalUri(),
'type' => $this->getType(),
'user' => $this->getUser()
];
}
}
@@ -0,0 +1,149 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class DeckBoard implements IQueryRow, JsonSerializable {
use TArrayTools;
private int $boardId = 0;
private string $boardName = '';
private string $owner = '';
private int $lastModified = 0;
public function __construct() {
}
/**
* @param int $boardId
*
* @return DeckBoard
*/
public function setBoardId(int $boardId): self {
$this->boardId = $boardId;
return $this;
}
/**
* @return int
*/
public function getBoardId(): int {
return $this->boardId;
}
/**
* @param string $boardName
*
* @return DeckBoard
*/
public function setBoardName(string $boardName): self {
$this->boardName = $boardName;
return $this;
}
/**
* @return string
*/
public function getBoardName(): string {
return $this->boardName;
}
/**
* @param string $owner
*
* @return DeckBoard
*/
public function setOwner(string $owner): self {
$this->owner = $owner;
return $this;
}
/**
* @return string
*/
public function getOwner(): string {
return $this->owner;
}
/**
* @param int $lastModified
*
* @return DeckBoard
*/
public function setLastModified(int $lastModified): self {
$this->lastModified = $lastModified;
return $this;
}
/**
* @return int
*/
public function getLastModified(): int {
return $this->lastModified;
}
/**
* @param array $data
*
* @return IQueryRow
*/
public function importFromDatabase(array $data): IQueryRow {
$this->setBoardId($this->getInt('id', $data))
->setBoardName($this->get('title', $data))
->setOwner($this->get('owner', $data))
->setLastModified($this->getInt('last_modified', $data));
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'boardId' => $this->getBoardId(),
'boardName' => $this->getBoardName(),
'owner' => $this->getOwner(),
'last_modified' => $this->getLastModified()
];
}
}
@@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class DeckShare implements IQueryRow, JsonSerializable {
use TArrayTools;
private int $boardId = 0;
private int $recipientType = 0;
private string $recipientId = '';
public function __construct() {
}
/**
* @param int $boardId
*
* @return DeckShare
*/
public function setBoardId(int $boardId): self {
$this->boardId = $boardId;
return $this;
}
/**
* @return int
*/
public function getBoardId(): int {
return $this->boardId;
}
/**
* @param int $recipientType
*
* @return DeckShare
*/
public function setRecipientType(int $recipientType): self {
$this->recipientType = $recipientType;
return $this;
}
/**
* @return int
*/
public function getRecipientType(): int {
return $this->recipientType;
}
/**
* @param string $recipientId
*
* @return DeckShare
*/
public function setRecipientId(string $recipientId): self {
$this->recipientId = $recipientId;
return $this;
}
/**
* @return string
*/
public function getRecipientId(): string {
return $this->recipientId;
}
/**
* @param array $data
*
* @return IQueryRow
*/
public function importFromDatabase(array $data): IQueryRow {
$this->setBoardId($this->getInt('board_id', $data))
->setRecipientType($this->getInt('type', $data))
->setRecipientId($this->get('participant', $data));
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'boardId' => $this->getBoardId(),
'recipientType' => $this->getRecipientType(),
'recipientId' => $this->getRecipientId()
];
}
}
@@ -0,0 +1,170 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\Circles\Model\FederatedUser;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class FilesShare implements IQueryRow, JsonSerializable {
use TArrayTools;
private string $sharedWith = '';
private int $shareType = 0;
private ?FederatedUser $entity = null;
private int $fileId = 0;
private string $fileTarget = '';
private string $fileOwner = '';
private int $fileLastUpdate = 0;
private int $shareTime = 0;
private string $shareCreator = '';
public function __construct() {
}
public function setSharedWith(string $sharedWith): self {
$this->sharedWith = $sharedWith;
return $this;
}
public function getSharedWith(): string {
return $this->sharedWith;
}
public function setShareType(int $shareType): self {
$this->shareType = $shareType;
return $this;
}
public function getShareType(): int {
return $this->shareType;
}
public function setFileId(int $fileId): self {
$this->fileId = $fileId;
return $this;
}
public function getFileId(): int {
return $this->fileId;
}
public function setEntity(FederatedUser $entity): self {
$this->entity = $entity;
return $this;
}
public function getEntity(): ?FederatedUser {
return $this->entity;
}
public function setFileTarget(string $fileTarget): self {
$this->fileTarget = $fileTarget;
return $this;
}
public function getFileTarget(): string {
return $this->fileTarget;
}
public function setFileOwner(string $fileOwner): self {
$this->fileOwner = $fileOwner;
return $this;
}
public function getFileOwner(): string {
return $this->fileOwner;
}
public function setFileLastUpdate(int $fileLastUpdate): self {
$this->fileLastUpdate = $fileLastUpdate;
return $this;
}
public function getFileLastUpdate(): int {
return $this->fileLastUpdate;
}
public function setShareTime(int $shareTime): self {
$this->shareTime = $shareTime;
return $this;
}
public function getShareTime(): int {
return $this->shareTime;
}
public function setShareCreator(string $shareCreator): self {
$this->shareCreator = $shareCreator;
return $this;
}
public function getShareCreator(): string {
return $this->shareCreator;
}
public function importFromDatabase(array $data): IQueryRow {
$this->setShareType($this->getInt('share_type', $data))
->setSharedWith($this->get('share_with', $data))
->setShareCreator($this->get('uid_initiator', $data))
->setFileId($this->getInt('file_source', $data))
->setFileOwner($this->get('uid_owner', $data))
->setFileTarget($this->get('file_target', $data))
->setShareTime($this->getInt('stime', $data));
return $this;
}
public function jsonSerialize(): array {
return [
'shareType' => $this->getShareType(),
'sharedWith' => $this->getSharedWith(),
'shareCreator' => $this->getShareCreator(),
'fileId' => $this->getFileId(),
'fileTarget' => $this->getFileTarget(),
'fileLastUpdate' => $this->getFileLastUpdate(),
'shareTime' => $this->getShareTime(),
'entity' => $this->getEntity()
];
}
}
@@ -0,0 +1,376 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\Tools\IDeserializable;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
/**
* Class RelatedResource
*
* @package OCA\RelatedResources\Model
*/
class RelatedResource implements IRelatedResource, IDeserializable, JsonSerializable {
use TArrayTools;
public static float $IMPROVE_LOW_LINK = 1.1;
public static float $IMPROVE_MEDIUM_LINK = 1.3;
public static float $IMPROVE_HIGH_LINK = 1.8;
private static float $DIMINISHING_RETURN = 0.6;
public const ITEM_OWNER = 'itemOwner';
public const ITEM_CREATION = 'itemCreation';
public const ITEM_LAST_UPDATE = 'itemLastUpdate';
public const ITEM_KEYWORDS = 'itemKeywords';
public const LINK_CREATOR = 'linkCreator';
public const LINK_CREATION = 'linkCreation';
public const LINK_RECIPIENT = 'linkRecipient';
private string $providerId;
private string $itemId;
private string $title = '';
private string $subtitle = '';
private string $tooltip = '';
private string $icon = '';
private string $preview = '';
private string $url = '';
private int $range = 0;
private array $virtualGroup = [];
private array $recipients = [];
private bool $groupShared = false;
private float $score = 1;
private array $improvements = [];
private array $currentQuality = [];
private array $metas = [];
public function __construct(string $providerId = '', string $itemId = '') {
$this->providerId = $providerId;
$this->itemId = $itemId;
}
public function getProviderId(): string {
return $this->providerId;
}
public function setProviderId(string $providerId): self {
$this->providerId = $providerId;
return $this;
}
public function getItemId(): string {
return $this->itemId;
}
public function setItemId(string $itemId): self {
$this->itemId = $itemId;
return $this;
}
public function setTitle(string $title): IRelatedResource {
$this->title = $title;
return $this;
}
public function getTitle(): string {
return $this->title;
}
public function setSubtitle(string $subtitle): IRelatedResource {
$this->subtitle = $subtitle;
return $this;
}
public function getSubtitle(): string {
return $this->subtitle;
}
public function setTooltip(string $tooltip): self {
$this->tooltip = $tooltip;
return $this;
}
public function getTooltip(): string {
return $this->tooltip;
}
public function setIcon(string $icon): self {
$this->icon = $icon;
return $this;
}
public function getIcon(): string {
return $this->icon;
}
public function setPreview(string $preview): self {
$this->preview = $preview;
return $this;
}
public function getPreview(): string {
return $this->preview;
}
public function setUrl(string $url): IRelatedResource {
$this->url = $url;
return $this;
}
public function getUrl(): string {
return $this->url;
}
public function improve(
float $quality,
string $type,
bool $diminishingReturn = true
): IRelatedResource {
$quality = ($this->currentQuality[$type] ?? $quality);
$this->score = $this->score * $quality;
$this->improvements[] = [
'type' => $type,
'quality' => $quality
];
if ($diminishingReturn) {
$quality = 1 + (($quality - 1) * self::$DIMINISHING_RETURN);
}
$this->currentQuality[$type] = $quality;
return $this;
}
public function getScore(): float {
return $this->score;
}
public function setScore(int $score): self {
$this->score = $score;
return $this;
}
public function setVirtualGroup(array $virtualGroup): self {
$this->virtualGroup = $virtualGroup;
return $this;
}
public function getVirtualGroup(): array {
return $this->virtualGroup;
}
public function addToVirtualGroup(string $singleId): self {
if (!in_array($singleId, $this->virtualGroup)) {
$this->virtualGroup[] = $singleId;
}
return $this;
}
public function mergeVirtualGroup(array $virtualGroup): self {
$this->virtualGroup = array_values(array_unique(array_merge($this->virtualGroup, $virtualGroup)));
return $this;
}
public function setRecipients(array $recipients): self {
$this->recipients = $recipients;
return $this;
}
public function getRecipients(): array {
return $this->recipients;
}
public function addRecipient(string $singleId): self {
if (!in_array($singleId, $this->recipients)) {
$this->recipients[] = $singleId;
}
return $this;
}
public function mergeRecipients(array $recipients): self {
$this->recipients = array_values(array_unique(array_merge($this->recipients, $recipients)));
return $this;
}
public function setAsGroupShared(bool $groupShared = true): self {
$this->groupShared = $groupShared;
return $this;
}
public function isGroupShared(): bool {
return $this->groupShared;
}
public function getImprovements(): array {
return $this->improvements;
}
public function setImprovements(array $improvements): self {
$this->improvements = $improvements;
return $this;
}
public function setCurrentQuality(array $currentQuality): self {
$this->currentQuality = $currentQuality;
return $this;
}
public function getCurrentQuality(): array {
return $this->currentQuality;
}
public function import(array $data): IDeserializable {
$this->setProviderId($this->get('providerId', $data));
$this->setItemId($this->get('itemId', $data));
$this->setTitle($this->get('title', $data));
$this->setSubtitle($this->get('subtitle', $data));
$this->setTooltip($this->get('tooltip', $data));
$this->setIcon($this->get('icon', $data));
$this->setPreview($this->get('preview', $data));
$this->setUrl($this->get('url', $data));
$this->setScore($this->getInt('score', $data));
$this->setAsGroupShared($this->getBool('groupShared', $data));
$this->setRecipients($this->getArray('recipients', $data));
$this->setVirtualGroup($this->getArray('virtualGroup', $data));
$this->setImprovements($this->getArray('improvements', $data));
$this->setCurrentQuality($this->getArray('currentQuality', $data));
$this->setMetas($this->getArray('meta', $data));
return $this;
}
public function jsonSerialize(): array {
return [
'providerId' => $this->getProviderId(),
'itemId' => $this->getItemId(),
'title' => $this->getTitle(),
'subtitle' => $this->getSubtitle(),
'tooltip' => $this->getTooltip(),
'icon' => $this->getIcon(),
'preview' => $this->getPreview(),
'url' => $this->getUrl(),
'score' => $this->getScore(),
'groupShared' => $this->isGroupShared(),
'virtualGroup' => $this->getVirtualGroup(),
'recipients' => $this->getRecipients(),
'improvements' => $this->getImprovements(),
'currentQuality' => $this->getCurrentQuality(),
'meta' => $this->getMetas()
];
}
public static function cleanData(array $arr): array {
static $acceptedKeys = [
'providerId', 'itemId', 'title', 'subtitle', 'tooltip', 'url',
'icon', 'preview', 'score', 'improvements'
];
$new = [];
foreach (array_keys($arr) as $k) {
if (in_array($k, $acceptedKeys)) {
$new[$k] = $arr[$k];
}
}
return $new;
}
public function setMeta(string $k, string $v): IRelatedResource {
$this->metas[$k] = $v;
return $this;
}
public function setMetaInt(string $k, int $v): IRelatedResource {
$this->metas[$k] = $v;
return $this;
}
public function setMetaArray(string $k, array $v): IRelatedResource {
$this->metas[$k] = $v;
return $this;
}
public function setMetas(array $metas): IRelatedResource {
$this->metas = array_merge($this->metas, $metas);
return $this;
}
public function hasMeta(string $k): bool {
return $this->validKey($k, $this->metas);
}
public function getMeta(string $k): string {
return $this->get($k, $this->metas);
}
public function getMetaInt(string $k): int {
return $this->getInt($k, $this->metas);
}
public function getMetaArray(string $k): array {
return $this->getArray($k, $this->metas);
}
public function getMetas(): array {
return $this->metas;
}
}
@@ -0,0 +1,105 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class TalkActor implements IQueryRow, JsonSerializable {
use TArrayTools;
private string $actorType = '';
private string $actorId = '';
public function __construct() {
}
/**
* @param string $actorType
*
* @return TalkActor
*/
public function setActorType(string $actorType): self {
$this->actorType = $actorType;
return $this;
}
/**
* @return string
*/
public function getActorType(): string {
return $this->actorType;
}
/**
* @param string $actorId
*
* @return TalkActor
*/
public function setActorId(string $actorId): self {
$this->actorId = $actorId;
return $this;
}
/**
* @return string
*/
public function getActorId(): string {
return $this->actorId;
}
/**
* @param array $data
*
* @return IQueryRow
*/
public function importFromDatabase(array $data): IQueryRow {
$this->setActorType($this->get('actor_type', $data))
->setActorId($this->get('actor_id', $data));
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'actorType' => $this->getActorType(),
'actorId' => $this->getActorId()
];
}
}
@@ -0,0 +1,148 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Model;
use JsonSerializable;
use OCA\RelatedResources\Tools\Db\IQueryRow;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
class TalkRoom implements IQueryRow, JsonSerializable {
use TArrayTools;
private int $roomId = 0;
private string $roomName = '';
private int $roomType = 0;
private string $token = '';
public function __construct() {
}
/**
* @param int $roomId
*
* @return TalkRoom
*/
public function setRoomId(int $roomId): self {
$this->roomId = $roomId;
return $this;
}
/**
* @return int
*/
public function getRoomId(): int {
return $this->roomId;
}
/**
* @param string $roomName
*
* @return TalkRoom
*/
public function setRoomName(string $roomName): self {
$this->roomName = $roomName;
return $this;
}
/**
* @return string
*/
public function getRoomName(): string {
return $this->roomName;
}
/**
* @param int $roomType
*
* @return TalkRoom
*/
public function setRoomType(int $roomType): self {
$this->roomType = $roomType;
return $this;
}
/**
* @return int
*/
public function getRoomType(): int {
return $this->roomType;
}
/**
* @param string $token
*/
public function setToken(string $token): self {
$this->token = $token;
return $this;
}
/**
* @return string
*/
public function getToken(): string {
return $this->token;
}
/**
* @param array $data
*
* @return IQueryRow
*/
public function importFromDatabase(array $data): IQueryRow {
$this->setRoomId($this->getInt('id', $data))
->setRoomName($this->get('name', $data))
->setRoomType($this->getInt('type', $data))
->setToken($this->get('token', $data));
return $this;
}
/**
* @return array
*/
public function jsonSerialize(): array {
return [
'roomId' => $this->getRoomId(),
'roomName' => $this->getRoomName(),
'roomType' => $this->getRoomType(),
'token' => $this->getToken()
];
}
}
@@ -0,0 +1,76 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2023
* @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\RelatedResources\RelatedResourceProviders;
use OCA\Circles\CirclesManager;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\Model\RelatedResource;
class AccountRelatedResourceProvider implements IRelatedResourceProvider {
private const PROVIDER_ID = 'account';
public function __construct() {
}
public function getProviderId(): string {
return self::PROVIDER_ID;
}
public function loadWeightCalculator(): array {
return [];
}
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource {
$related = new RelatedResource(self::PROVIDER_ID, $itemId);
$related->setTitle('Account ' . $itemId);
$card = $circlesManager->getFederatedUser($itemId, Member::TYPE_USER);
$curr = $circlesManager->getCurrentFederatedUser();
$related->mergeVirtualGroup(
[
$curr->getSingleId(),
$card->getSingleId()
]
);
return $related;
}
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void {
}
public function getItemsAvailableToEntity(FederatedUser $entity): array {
return [];
}
}
@@ -0,0 +1,225 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\RelatedResourceProviders;
use Exception;
use OCA\Circles\CirclesManager;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\RelatedResources\Db\CalendarShareRequest;
use OCA\RelatedResources\Exceptions\CalendarDataNotFoundException;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\Model\Calendar;
use OCA\RelatedResources\Model\CalendarShare;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
use OCP\IL10N;
use OCP\IURLGenerator;
class CalendarRelatedResourceProvider implements IRelatedResourceProvider {
use TArrayTools;
private const PROVIDER_ID = 'calendar';
private IURLGenerator $urlGenerator;
private IL10N $l10n;
private CalendarShareRequest $calendarShareRequest;
public function __construct(
IURLGenerator $urlGenerator,
IL10N $l10n,
CalendarShareRequest $calendarShareRequest
) {
$this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
$this->calendarShareRequest = $calendarShareRequest;
}
public function getProviderId(): string {
return self::PROVIDER_ID;
}
public function loadWeightCalculator(): array {
return [];
}
/**
* @param string $itemId
*
* @return IRelatedResource|null
*/
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource {
[$principalUri, $uri] = explode(':', $itemId, 2);
$itemId = (int)$itemId;
/** @var Calendar $calendar */
try {
$calendar = $this->calendarShareRequest->getCalendarByUri($principalUri, $uri);
} catch (CalendarDataNotFoundException $e) {
return null;
}
$related = $this->convertToRelatedResource($calendar);
if (strtolower(substr($calendar->getCalendarPrincipalUri(), 0, 17)) === 'principals/users/') {
$calendarOwner = substr($calendar->getCalendarPrincipalUri(), 17);
$owner = $circlesManager->getFederatedUser($calendarOwner, Member::TYPE_USER);
$related->addToVirtualGroup($owner->getSingleId());
}
foreach ($this->calendarShareRequest->getSharesByCalendarId($calendar->getCalendarId()) as $share) {
try {
$this->completeShareDetails($share);
} catch (Exception $e) {
continue;
}
$this->processCalendarShare($circlesManager, $related, $share);
}
return $related;
}
public function getItemsAvailableToEntity(FederatedUser $entity): array {
switch ($entity->getBasedOn()->getSource()) {
case Member::TYPE_USER:
$shares = $this->calendarShareRequest->getCalendarAvailableToUser($entity->getUserId());
break;
case Member::TYPE_GROUP:
$shares = $this->calendarShareRequest->getCalendarAvailableToGroup($entity->getUserId());
break;
case Member::TYPE_CIRCLE:
$shares = $this->calendarShareRequest->getCalendarAvailableToCircle($entity->getSingleId());
break;
default:
return [];
}
return array_map(function (Calendar $calendar): string {
return $calendar->getId();
}, $shares);
}
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void {
}
private function convertToRelatedResource(Calendar $calendar): IRelatedResource {
$related = new RelatedResource(self::PROVIDER_ID, $calendar->getId());
$url = '';
try {
$url = $this->urlGenerator->linkToRouteAbsolute(
'calendar.view.indexview.timerange',
[
'view' => 'dayGridMonth',
'timeRange' => date('Y-m-d', time())
]
);
} catch (Exception $e) {
}
$related->setTitle($calendar->getCalendarName())
->setSubtitle($this->l10n->t('Calendar'))
->setTooltip($this->l10n->t('Calendar "%s"', $calendar->getCalendarName()))
->setIcon(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(
'calendar',
'calendar.svg'
)
)
)
->setUrl($url);
$keywords = preg_split(
'/[\/_\-. ]/',
ltrim(strtolower($calendar->getCalendarName()), '/')
);
if (is_array($keywords)) {
$related->setMetaArray(RelatedResource::ITEM_KEYWORDS, $keywords);
}
return $related;
}
/**
* @param RelatedResource $related
* @param CalendarShare $share
*/
private function processCalendarShare(
CirclesManager $circlesManager,
RelatedResource $related,
CalendarShare $share) {
try {
$participant = $circlesManager->getFederatedUser($share->getUser(), $share->getType());
if ($share->getType() === Member::TYPE_USER) {
$related->addToVirtualGroup($participant->getSingleId());
} else {
$related->addRecipient($participant->getSingleId())
->setAsGroupShared();
}
} catch (Exception $e) {
}
}
private function completeShareDetails(CalendarShare $share): void {
[$type, $user] = explode('/', substr($share->getSharePrincipalUri(), 11), 2);
switch ($type) {
case 'users':
$type = Member::TYPE_USER;
break;
case 'groups':
$type = Member::TYPE_GROUP;
break;
case 'circles': // not supported yet by Calendar
$type = Member::TYPE_SINGLE;
break;
default:
throw new Exception();
}
$share->setType($type)
->setUser($user);
}
}
@@ -0,0 +1,205 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\RelatedResourceProviders;
use Exception;
use OCA\Circles\CirclesManager;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\RelatedResources\Db\DeckRequest;
use OCA\RelatedResources\Exceptions\DeckDataNotFoundException;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\Model\DeckBoard;
use OCA\RelatedResources\Model\DeckShare;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Share\IShare;
class DeckRelatedResourceProvider implements IRelatedResourceProvider {
use TArrayTools;
private const PROVIDER_ID = 'deck';
private IUrlGenerator $urlGenerator;
private IL10N $l10n;
private DeckRequest $deckSharesRequest;
public function __construct(
IUrlGenerator $urlGenerator,
IL10N $l10n,
DeckRequest $deckSharesRequest
) {
$this->urlGenerator = $urlGenerator;
$this->l10n = $l10n;
$this->deckSharesRequest = $deckSharesRequest;
}
public function getProviderId(): string {
return self::PROVIDER_ID;
}
public function loadWeightCalculator(): array {
return [];
}
/**
* @param string $itemId
*
* @return IRelatedResource|null
*/
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource {
$itemId = (int)$itemId;
/** @var DeckBoard $board */
try {
$board = $this->deckSharesRequest->getBoardById($itemId);
} catch (DeckDataNotFoundException $e) {
return null;
}
$related = $this->convertToRelatedResource($board);
$owner = $circlesManager->getFederatedUser($board->getOwner(), Member::TYPE_USER);
$related->addToVirtualGroup($owner->getSingleId());
foreach ($this->deckSharesRequest->getSharesByBoardId($itemId) as $share) {
$this->processDeckShare($circlesManager, $related, $share);
}
return $related;
}
public function getItemsAvailableToEntity(FederatedUser $entity): array {
switch ($entity->getBasedOn()->getSource()) {
case Member::TYPE_USER:
$shares = $this->deckSharesRequest->getDeckAvailableToUser($entity->getUserId());
break;
case Member::TYPE_GROUP:
$shares = $this->deckSharesRequest->getDeckAvailableToGroup($entity->getUserId());
break;
case Member::TYPE_CIRCLE:
$shares = $this->deckSharesRequest->getDeckAvailableToCircle($entity->getSingleId());
break;
default:
return [];
}
return array_map(function (DeckBoard $board): string {
return (string)$board->getBoardId();
}, $shares);
}
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void {
}
private function convertToRelatedResource(DeckBoard $board): IRelatedResource {
$url = '';
try {
$url =
$this->urlGenerator->linkToRouteAbsolute('deck.page.index')
. '#/board/' . $board->getBoardId();
} catch (Exception $e) {
}
$related = new RelatedResource(self::PROVIDER_ID, (string)$board->getBoardId());
$related->setTitle($board->getBoardName())
->setSubtitle($this->l10n->t('Deck'))
->setTooltip($this->l10n->t('Deck board "%s"', $board->getBoardName()))
->setIcon(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(
'deck',
'deck.svg'
)
)
)
->setUrl($url);
$related->setMetaInt(RelatedResource::ITEM_LAST_UPDATE, $board->getLastModified());
$keywords = preg_split('/[\/_\-. ]/', ltrim(strtolower($board->getBoardName()), '/'));
if (is_array($keywords)) {
$related->setMetaArray(RelatedResource::ITEM_KEYWORDS, $keywords);
}
return $related;
}
/**
* @param RelatedResource $related
* @param DeckShare $share
*/
private function processDeckShare(
CirclesManager $circlesManager,
RelatedResource $related,
DeckShare $share
) {
try {
$participant = $this->convertDeckShare($circlesManager, $share);
if ($share->getRecipientType() === IShare::TYPE_USER) {
$related->addToVirtualGroup($participant->getSingleId());
} else {
$related->addRecipient($participant->getSingleId())
->setAsGroupShared();
}
} catch (Exception $e) {
}
}
/**
* @param CirclesManager $circlesManager
* @param DeckShare $share
*
* @return FederatedUser
* @throws Exception
*/
public function convertDeckShare(CirclesManager $circlesManager, DeckShare $share): FederatedUser {
$type = match ($share->getRecipientType()) {
IShare::TYPE_USER => Member::TYPE_USER,
IShare::TYPE_GROUP => Member::TYPE_GROUP,
IShare::TYPE_CIRCLE => Member::TYPE_SINGLE,
default => throw new Exception('unknown deck share type (' . $share->getRecipientType() . ')'),
};
return $circlesManager->getFederatedUser($share->getRecipientId(), $type);
}
}
@@ -0,0 +1,331 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\RelatedResourceProviders;
use Exception;
use OC\User\NoUserException;
use OCA\Circles\CirclesManager;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\GroupFolders\Mount\GroupMountPoint;
use OCA\RelatedResources\Db\FilesShareRequest;
use OCA\RelatedResources\Exceptions\GroupFolderNotFoundException;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\Model\FilesShare;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
use OCP\Files\InvalidPathException;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Share\IShare;
class FilesRelatedResourceProvider implements IRelatedResourceProvider {
use TArrayTools;
private const PROVIDER_ID = 'files';
public function __construct(
private IRootFolder $rootFolder,
private IURLGenerator $urlGenerator,
private IL10N $l10n,
private FilesShareRequest $filesShareRequest,
private GroupFoldersRelatedResourceProvider $groupFoldersRRProvider,
) {
}
public function getProviderId(): string {
return self::PROVIDER_ID;
}
public function loadWeightCalculator(): array {
return [];
}
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource {
$itemId = (int)$itemId;
if ($itemId <= 1) {
return null;
}
$related = null;
try {
$itemEntries = $this->getItemIdsFromParentPath($circlesManager, $itemId);
} catch (Exception $e) {
$itemEntries = [['id' => $itemId]];
}
// TODO: create related item first, apply share recipient then.
// cleaner way ?
// should be already available in the current app
$itemIds = array_values(
array_filter(
array_map(function (array $entry): int {
return (($entry['type'] ?? 'files') === 'files') ? (int)$entry['id'] : 0;
}, $itemEntries)
)
);
foreach ($this->filesShareRequest->getSharesByItemIds($itemIds) as $share) {
if ($related === null) {
$related = $this->convertToRelatedResource($share);
}
$this->processShareRecipient($circlesManager, $related, $share);
}
$related = $this->managerGroupFolders($circlesManager, $related, $itemEntries);
return $related;
}
public function getItemsAvailableToEntity(FederatedUser $entity): array {
switch ($entity->getBasedOn()->getSource()) {
case Member::TYPE_USER:
$shares = $this->filesShareRequest->getSharesToUser($entity->getUserId());
break;
case Member::TYPE_GROUP:
$shares = $this->filesShareRequest->getSharesToGroup($entity->getUserId());
break;
case Member::TYPE_CIRCLE:
$shares = $this->filesShareRequest->getSharesToCircle($entity->getSingleId());
break;
default:
return [];
}
return array_map(function (FilesShare $share): string {
return (string)$share->getFileId();
}, $shares);
}
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void {
$current = $circlesManager->getCurrentFederatedUser();
if (!$current->isLocal() || $current->getUserType() !== Member::TYPE_USER) {
return;
}
$paths = $this->rootFolder->getUserFolder($current->getUserId())
->getById((int)$entry->getItemId());
if (sizeof($paths) > 0) {
$entry->setTitle($paths[0]->getName());
}
}
private function convertToRelatedResource(FilesShare $share): IRelatedResource {
$related = new RelatedResource(self::PROVIDER_ID, (string)$share->getFileId());
$related->setTitle(trim($share->getFileTarget(), '/'));
$related->setSubtitle($this->l10n->t('Files'));
$related->setTooltip($this->l10n->t('File "%s"', $share->getFileTarget()));
$related->setIcon(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(
'files',
'app.svg'
)
)
);
$related->setPreview(
$this->urlGenerator->linkToRouteAbsolute(
'core.Preview.getPreviewByFileId',
['x' => 64, 'y' => 64, 'fileId' => $share->getFileId()]
)
);
$related->setUrl(
$this->urlGenerator->linkToRouteAbsolute('files.View.showFile', ['fileid' => $share->getFileId()])
);
$related->setMetas(
[
RelatedResource::ITEM_LAST_UPDATE => $share->getFileLastUpdate(),
RelatedResource::ITEM_OWNER => $share->getFileOwner(),
// RelatedResource::LINK_CREATOR => $share->getShareCreator(),
RelatedResource::LINK_CREATION => $share->getShareTime()
]
);
$keywords = preg_split('/[\/_\-. ]/', ltrim(strtolower($share->getFileTarget()), '/'));
if (is_array($keywords)) {
$related->setMetaArray(RelatedResource::ITEM_KEYWORDS, $keywords);
}
return $related;
}
/**
* @param list<array{id:int,type?:string}> $itemEntries
*/
private function managerGroupFolders(
CirclesManager $circlesManager,
?IRelatedResource $related,
array $itemEntries
): ?IRelatedResource {
foreach ($itemEntries as $entry) {
if (($entry['type'] ?? '') !== 'groupfolder') {
continue;
}
try {
$folder = $this->groupFoldersRRProvider->getFolder($entry['id']);
} catch (GroupFolderNotFoundException $e) {
continue;
}
if ($related === null) {
$related = $this->groupFoldersRRProvider->convertToRelatedResource($folder);
}
$this->groupFoldersRRProvider->processApplicableMap(
$circlesManager,
$related,
$folder['groups'] ?? []
);
}
return $related;
}
/**
* @param int $itemId
*
* @return list<array{id:int,type?:string}>
* @throws InvalidPathException
* @throws NotFoundException
* @throws NotPermittedException
* @throws NoUserException
*/
private function getItemIdsFromParentPath(CirclesManager $circlesManager, int $itemId): array {
$current = $circlesManager->getCurrentFederatedUser();
if (!$current->isLocal() || $current->getUserType() !== Member::TYPE_USER) {
return [['id' => $itemId]];
}
$paths = $this->rootFolder->getUserFolder($current->getUserId())
->getById($itemId);
$itemEntries = [];
foreach ($paths as $path) {
while (true) {
$mountPoint = $path->getMountPoint();
if ($mountPoint instanceof GroupMountPoint) {
$itemEntries[] = [
'id' => $mountPoint->getFolderId(),
'type' => 'groupfolder'
];
}
if ($path->getId() === 0) {
break;
}
$itemEntries[] = ['id' => $path->getId()];
$path = $path->getParent();
}
}
return $itemEntries;
}
/**
* @param RelatedResource $related
* @param FilesShare $share
*/
private function processShareRecipient(
CirclesManager $circlesManager,
RelatedResource $related,
FilesShare $share
) {
try {
$sharedWith = $this->convertShareRecipient(
$circlesManager,
$share->getShareType(),
$share->getSharedWith()
);
if ($share->getShareType() === IShare::TYPE_USER) {
$shareCreator = $this->convertShareRecipient(
$circlesManager,
IShare::TYPE_USER,
$share->getShareCreator()
);
$related->mergeVirtualGroup(
[
$sharedWith->getSingleId(),
$shareCreator->getSingleId()
]
);
} else {
$related->addRecipient($sharedWith->getSingleId())
->setAsGroupShared();
}
} catch (Exception $e) {
}
}
/**
* @param int $shareType
* @param string $sharedWith
*
* @return FederatedUser
* @throws Exception
*/
private function convertShareRecipient(
CirclesManager $circlesManager,
int $shareType,
string $sharedWith
): FederatedUser {
$type = match ($shareType) {
IShare::TYPE_USER => Member::TYPE_USER,
IShare::TYPE_GROUP => Member::TYPE_GROUP,
IShare::TYPE_CIRCLE => Member::TYPE_SINGLE,
default => throw new Exception('unknown share type (' . $shareType . ')'),
};
return $circlesManager->getFederatedUser($sharedWith, $type);
}
}
@@ -0,0 +1,199 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2023
* @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\RelatedResources\RelatedResourceProviders;
use OCA\Circles\CirclesManager;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\GroupFolders\Folder\FolderManager;
use OCA\RelatedResources\Db\FilesShareRequest;
use OCA\RelatedResources\Exceptions\GroupFolderNotFoundException;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
use OCP\AutoloadNotAllowedException;
use OCP\Files\IRootFolder;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
class GroupFoldersRelatedResourceProvider implements IRelatedResourceProvider {
use TArrayTools;
private const PROVIDER_ID = 'groupfolders';
private ?FolderManager $folderManager = null;
/**
* @var array<int, array{acl: bool, groups: array<array-key, array<array-key, int|string>>, id: int, mount_point: mixed, quota: int, size: 0}>
*/
private array $folders = [];
public function __construct(
private IRootFolder $rootFolder,
private IURLGenerator $urlGenerator,
private IL10N $l10n,
private FilesShareRequest $filesShareRequest,
) {
try {
$this->folderManager = Server::get(FolderManager::class);
$this->folders = $this->folderManager->getAllFolders();
} catch (ContainerExceptionInterface|AutoloadNotAllowedException $e) {
}
}
public function getProviderId(): string {
return self::PROVIDER_ID;
}
public function loadWeightCalculator(): array {
return [];
}
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource {
$itemId = (int)$itemId;
if ($itemId < 1) {
return null;
}
// need to get the groupfolders parent, based on itemId
try {
$folder = $this->getFolder($itemId);
} catch (GroupFolderNotFoundException $e) {
return null;
}
$related = $this->convertToRelatedResource($folder);
$this->processApplicableMap($circlesManager, $related, $folder['groups'] ?? []);
return $related;
}
public function getItemsAvailableToEntity(FederatedUser $entity): array {
$items = [];
foreach ($this->folders as $folder) {
foreach ($folder['groups'] as $k => $entry) {
if ($entity->getBasedOn()->getSource() === Member::TYPE_GROUP
&& $entry['type'] === 'group'
&& $k === $entity->getUserId()) {
$items[] = (string)$folder['id'];
}
if ($entity->getBasedOn()->getSource() === Member::TYPE_CIRCLE
&& $entry['type'] === 'circle'
&& $k === $entity->getSingleId()) {
$items[] = (string)$folder['id'];
}
}
}
return $items;
}
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void {
}
/**
* @param array{acl: bool, groups: array<array-key, array<array-key, int|string>>, id: int, mount_point: mixed, quota: int, size: 0} $folderData
*/
public function convertToRelatedResource(array $folderData): IRelatedResource {
$related = new RelatedResource(self::PROVIDER_ID, (string)($folderData['id'] ?? 0));
$folderName = $folderData['mount_point'] ?? 'groupfolder';
$related->setTitle($folderName);
$related->setSubtitle($this->l10n->t('Group Folder'));
$related->setTooltip($this->l10n->t('Group Folder "%s"', '/' . $folderName . '/'));
try {
$related->setIcon(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(
'groupfolders',
'app.svg'
)
)
);
} catch (\Exception $e) {
// try/catch can be removed once groupfolders is released for nc27
}
$related->setUrl(
$this->urlGenerator->linkToRouteAbsolute(
'files.view.index',
['dir' => '/' . $folderName]
)
);
$related->setMetaArray(RelatedResource::ITEM_KEYWORDS, [$folderName]);
return $related;
}
/**
* @param RelatedResource $related
* @param array<array-key, array<array-key, int|string>> $applicableMap
*/
public function processApplicableMap(
CirclesManager $circlesManager,
RelatedResource $related,
array $applicableMap
): void {
foreach ($applicableMap as $k => $entry) {
$entityId = '';
if ($entry['type'] === 'circle') {
$entityId = (string)$k;
} elseif ($entry['type'] === 'group') {
$federatedGroup = $circlesManager->getFederatedUser($k, Member::TYPE_GROUP);
$entityId = $federatedGroup->getSingleId();
}
$related->addRecipient($entityId)
->setAsGroupShared();
}
}
/**
* @param int $folderId
*
* @return array{acl: bool, groups: array<array-key, array<array-key, int|string>>, id: int, mount_point: mixed, quota: int, size: 0}
* @throws GroupFolderNotFoundException
*/
public function getFolder(int $folderId): array {
foreach ($this->folders as $folder) {
if ($folder['id'] === $folderId) {
return $folder;
}
}
throw new GroupFolderNotFoundException();
}
}
@@ -0,0 +1,247 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\RelatedResourceProviders;
use Exception;
use OCA\Circles\CirclesManager;
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\RelatedResources\Db\TalkRoomRequest;
use OCA\RelatedResources\Exceptions\TalkDataNotFoundException;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\Model\TalkActor;
use OCA\RelatedResources\Model\TalkRoom;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
use OCP\IL10N;
use OCP\IURLGenerator;
use Psr\Log\LoggerInterface;
class TalkRelatedResourceProvider implements IRelatedResourceProvider {
use TArrayTools;
private const PROVIDER_ID = 'talk';
public function __construct(
private IURLGenerator $urlGenerator,
private IL10N $l10n,
private TalkRoomRequest $talkRoomRequest,
private LoggerInterface $logger
) {
}
public function getProviderId(): string {
return self::PROVIDER_ID;
}
public function loadWeightCalculator(): array {
return [];
}
/**
* @param string $itemId
*
* @return IRelatedResource|null
*/
public function getRelatedFromItem(CirclesManager $circlesManager, string $itemId): ?IRelatedResource {
/** @var TalkRoom $room */
try {
$room = $this->talkRoomRequest->getRoomByToken($itemId);
} catch (TalkDataNotFoundException $e) {
return null;
}
$related = $this->convertToRelatedResource($room);
foreach ($this->talkRoomRequest->getActorsByToken($room->getToken()) as $actor) {
$this->processRoomParticipant($circlesManager, $related, $actor);
}
if (!$related->isGroupShared()) {
$countActor = count($related->getVirtualGroup());
if ($countActor === 1) { // room is still in preparation
return null;
}
if ($countActor === 2 && $room->getRoomType() === \OCA\Talk\Room::TYPE_ONE_TO_ONE) {
$related->setTitle($this->l10n->t('Talk conversation'))
->setMetaArray('1on1', json_decode($room->getRoomName()));
}
}
return $related;
}
public function improveRelatedResource(CirclesManager $circlesManager, IRelatedResource $entry): void {
if (!$entry->hasMeta('1on1')) {
return;
}
try {
$current = $circlesManager->getCurrentFederatedUser();
} catch (FederatedUserNotFoundException $e) {
$circlesManager->startSession(); // enforce new session if not available
$current = $circlesManager->getCurrentFederatedUser();
$this->logger->info('session restarted', ['current' => $current]);
}
if (!$current->isLocal() || $current->getUserType() !== Member::TYPE_USER) {
return;
}
foreach ($entry->getMetaArray('1on1') as $actor) {
if ($actor !== $current->getUserId()) {
$entry->setTitle($this->l10n->t('Conversation with %s', $actor));
return;
}
}
}
public function getItemsAvailableToEntity(FederatedUser $entity): array {
switch ($entity->getBasedOn()->getSource()) {
case Member::TYPE_USER:
$shares = $this->talkRoomRequest->getRoomsAvailableToUser($entity->getUserId());
break;
case Member::TYPE_GROUP:
$shares = $this->talkRoomRequest->getRoomsAvailableToGroup($entity->getUserId());
break;
case Member::TYPE_CIRCLE:
$shares = $this->talkRoomRequest->getRoomsAvailableToCircle($entity->getSingleId());
break;
default:
return [];
}
return array_map(function (TalkRoom $room): string {
return $room->getToken();
}, $shares);
}
private function convertToRelatedResource(TalkRoom $share): IRelatedResource {
$url = '';
try {
$url = $this->urlGenerator->linkToRouteAbsolute(
'spreed.Page.showCall',
[
'token' => $share->getToken()
]
);
} catch (Exception $e) {
}
$related = new RelatedResource(self::PROVIDER_ID, $share->getToken());
$related->setTitle($share->getRoomName())
->setSubtitle($this->l10n->t('Talk'))
->setTooltip($this->l10n->t('Talk conversation "%s"', $share->getRoomName()))
->setIcon(
$this->urlGenerator->getAbsoluteURL(
$this->urlGenerator->imagePath(
'spreed',
'app.svg'
)
)
)
->setPreview(
$this->urlGenerator->linkToOCSRouteAbsolute(
'spreed.Avatar.getAvatar',
['token' => $share->getToken(), 'apiVersion' => 'v1']
)
)
->setUrl($url);
$keywords = preg_split('/[\/_\-. ]/', ltrim(strtolower($share->getRoomName()), '/'));
if (is_array($keywords)) {
$related->setMetaArray(RelatedResource::ITEM_KEYWORDS, $keywords);
}
return $related;
}
/**
* @param RelatedResource $related
* @param TalkActor $actor
*/
private function processRoomParticipant(
CirclesManager $circlesManager,
RelatedResource $related,
TalkActor $actor
) {
try {
$participant = $this->convertRoomParticipant($circlesManager, $actor);
if ($actor->getActorType() === 'users') {
$related->addToVirtualGroup($participant->getSingleId());
} else {
$related->addRecipient($participant->getSingleId())
->setAsGroupShared();
}
} catch (Exception $e) {
}
}
/**
* @param TalkActor $actor
*
* @return FederatedUser
* @throws Exception
*/
public function convertRoomParticipant(CirclesManager $circlesManager, TalkActor $actor): FederatedUser {
switch ($actor->getActorType()) {
case 'users':
$type = Member::TYPE_USER;
break;
case 'groups':
$type = Member::TYPE_GROUP;
break;
case 'circles':
$type = Member::TYPE_SINGLE;
break;
default:
throw new Exception('unknown actor type (' . $actor->getActorType() . ')');
}
return $circlesManager->getFederatedUser($actor->getActorId(), $type);
}
}
@@ -0,0 +1,90 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Service;
use OCA\RelatedResources\AppInfo\Application;
use OCA\RelatedResources\Tools\Traits\TArrayTools;
use OCP\IConfig;
class ConfigService {
use TArrayTools;
private IConfig $config;
public const RESULT_MAX = 'result_max';
private static $defaults = [
self::RESULT_MAX => 7
];
public function __construct(IConfig $config) {
$this->config = $config;
}
public function unsetAppConfig(): void {
$this->config->deleteAppValues(Application::APP_ID);
}
public function setAppValue(string $key, string $value): void {
$this->config->setAppValue(Application::APP_ID, $key, $value);
}
public function getAppValue(string $key): string {
if (($value = $this->config->getAppValue(Application::APP_ID, $key, '')) !== '') {
return $value;
}
if (($value = $this->config->getSystemValue(Application::APP_ID . '.' . $key, '')) !== '') {
return $value;
}
return $this->get($key, self::$defaults);
}
/**
* @param string $key
*
* @return int
*/
public function getAppValueInt(string $key): int {
return (int)$this->getAppValue($key);
}
/**
* @param string $key
*
* @return bool
*/
public function getAppValueBool(string $key): bool {
return ($this->getAppValueInt($key) === 1);
}
}
@@ -0,0 +1,625 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Service;
use Exception;
use OCA\Circles\CirclesManager;
use OCA\Circles\Exceptions\FederatedUserNotFoundException;
use OCA\Circles\Model\FederatedUser;
use OCA\Circles\Model\Member;
use OCA\RelatedResources\Exceptions\CacheNotFoundException;
use OCA\RelatedResources\Exceptions\RelatedResourceNotFound;
use OCA\RelatedResources\Exceptions\RelatedResourceProviderNotFound;
use OCA\RelatedResources\ILinkWeightCalculator;
use OCA\RelatedResources\IRelatedResource;
use OCA\RelatedResources\IRelatedResourceProvider;
use OCA\RelatedResources\LinkWeightCalculators\AncienShareWeightCalculator;
use OCA\RelatedResources\LinkWeightCalculators\KeywordWeightCalculator;
use OCA\RelatedResources\LinkWeightCalculators\TimeWeightCalculator;
use OCA\RelatedResources\Model\RelatedResource;
use OCA\RelatedResources\RelatedResourceProviders\AccountRelatedResourceProvider;
use OCA\RelatedResources\RelatedResourceProviders\CalendarRelatedResourceProvider;
use OCA\RelatedResources\RelatedResourceProviders\DeckRelatedResourceProvider;
use OCA\RelatedResources\RelatedResourceProviders\FilesRelatedResourceProvider;
use OCA\RelatedResources\RelatedResourceProviders\GroupFoldersRelatedResourceProvider;
use OCA\RelatedResources\RelatedResourceProviders\TalkRelatedResourceProvider;
use OCA\RelatedResources\Tools\Exceptions\InvalidItemException;
use OCA\RelatedResources\Tools\Traits\TDeserialize;
use OCP\App\IAppManager;
use OCP\AutoloadNotAllowedException;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\Server;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface;
use Psr\Log\LoggerInterface;
use ReflectionClass;
use ReflectionException;
class RelatedService {
use TDeserialize;
public const CACHE_RELATED = 'related/related';
public const CACHE_RELATED_TTL = 600;
public const CACHE_ITEMS_TTL = 600;
private IAppManager $appManager;
private ICache $cache;
private LoggerInterface $logger;
private ?CirclesManager $circlesManager = null;
private ConfigService $configService;
/** @var ILinkWeightCalculator[] */
private array $weightCalculators = [];
/** @var string[] */
private static array $weightCalculators_ = [
TimeWeightCalculator::class,
KeywordWeightCalculator::class,
AncienShareWeightCalculator::class
];
public function __construct(
IAppManager $appManager,
ICacheFactory $cacheFactory,
LoggerInterface $logger,
ConfigService $configService
) {
$this->appManager = $appManager;
$this->cache = $cacheFactory->createDistributed(self::CACHE_RELATED);
$this->logger = $logger;
$this->configService = $configService;
try {
$this->circlesManager = Server::get(CirclesManager::class);
} catch (ContainerExceptionInterface | AutoloadNotAllowedException $e) {
$this->logger->notice($e->getMessage());
}
}
/**
* @param string $providerId
* @param string $itemId
* @param int $chunk
*
* @return IRelatedResource[]
* @throws RelatedResourceProviderNotFound
*/
public function getRelatedToItem(
string $providerId,
string $itemId,
int $chunk = -1,
string $resourceType = ''
): array {
if ($this->circlesManager === null) {
return [];
}
$result = $this->retrieveRelatedToItem($providerId, $itemId, $resourceType);
usort($result, function (IRelatedResource $r1, IRelatedResource $r2): int {
$a = $r1->getScore();
$b = $r2->getScore();
return ($a === $b) ? 0 : (($a > $b) ? -1 : 1);
});
return ($chunk > -1) ? array_slice($result, 0, $chunk) : $result;
}
/**
* Main method that will return resource related an item (identified by providerId and itemId)
*
* @param string $providerId
* @param string $itemId
*
* @return IRelatedResource[]
* @throws RelatedResourceProviderNotFound
*/
private function retrieveRelatedToItem(
string $providerId,
string $itemId,
string $resourceType = ''
): array {
$this->logger->debug('retrieving related to item ' . $providerId . '.' . $itemId);
try {
// we generate a related resource for current item, including a full
// list of recipients and virtual group
$current = $this->getRelatedFromItem($providerId, $itemId);
} catch (Exception $e) {
return [];
}
if ($current->isGroupShared()) {
$recipients = $current->getRecipients();
} else {
$recipients = $current->getVirtualGroup();
}
if ($resourceType === '') {
$providers = $this->getRelatedResourceProviders();
} else {
$providers = [$this->getRelatedResourceProvider($resourceType)];
}
$result = [];
foreach ($providers as $provider) {
$known = [];
if ($provider->getProviderId() === $providerId) {
$known[] = $current->getItemId();
}
foreach ($recipients as $recipient) {
// foreach provider, we get a list of items available to each recipient of the 'current' item
// we only needs itemIds because, at this point, the full list of recipient each
// item is shared to is not important
// However, if 'current' item contains a group share, we do not need to waste resource to get
// details about items available to single users as they are ignored in current scope of the app.
try {
$entity = $this->circlesManager->getFederatedUser($recipient);
} catch (Exception $e) {
continue;
}
if ($current->isGroupShared() && $entity->getBasedOn()->getSource() === Member::TYPE_USER) {
continue;
}
foreach ($this->getItemsAvailableToEntity($provider, $entity) as $itemId) {
if (in_array($itemId, $known)) {
continue; // we don't want duplicate details
}
$known[] = $itemId;
// foreach itemId, we get full details about it
try {
// cast to string is mandatory in here !
$related = $this->getRelatedFromItem($provider->getProviderId(), (string)$itemId);
} catch (RelatedResourceNotFound $e) {
continue;
}
$result[] = $related;
}
}
}
$result = $this->strictMatching($current, $result);
$result = $this->filterUnavailableResults($result);
$result = $this->improveResult($result);
$this->weightResult($current, $result);
return $result;
}
/**
* get the RelatedResource from an item. including all recipient/virtual groups
*
* @param string $providerId
* @param string $itemId
*
* @return RelatedResource
* @throws RelatedResourceNotFound
* @throws RelatedResourceProviderNotFound
*/
public function getRelatedFromItem(string $providerId, string $itemId): RelatedResource {
try {
return $this->getCachedRelatedFromItem($providerId, $itemId);
} catch (CacheNotFoundException $e) {
}
$result = $this->getRelatedResourceProvider($providerId)
->getRelatedFromItem($this->circlesManager, $itemId);
$this->logger->debug('get related to ' . $providerId . '.' . $itemId . ' - ' . json_encode($result));
if ($result === null) {
throw new RelatedResourceNotFound();
}
$this->cacheRelatedFromItem($providerId, $itemId, $result);
return $result;
}
/**
* @param string $providerId
* @param string $itemId
*
* @return RelatedResource
* @throws CacheNotFoundException
*/
private function getCachedRelatedFromItem(
string $providerId,
string $itemId
): RelatedResource {
$key = $this->generateRelatedFromItemCacheKey($providerId, $itemId);
$cachedData = $this->cache->get($key);
if (!is_string($cachedData) || empty($cachedData)) {
throw new CacheNotFoundException();
}
/** @var RelatedResource $result */
try {
$result = $this->deserializeJson($cachedData, RelatedResource::class);
} catch (InvalidItemException $e) {
throw new CacheNotFoundException();
}
$this->logger->debug(
'existing cache on related from ' . $providerId . '.' . $itemId . ' - ' . json_encode($result)
);
return $result;
}
/**
* @param string $providerId
* @param string $itemId
* @param RelatedResource $related
*/
private function cacheRelatedFromItem(
string $providerId,
string $itemId,
RelatedResource $related
): void {
$this->logger->debug(
'caching related from ' . $providerId . '.' . $itemId . ' - ' . json_encode($related)
);
$key = $this->generateRelatedFromItemCacheKey($providerId, $itemId);
$this->cache->set($key, json_encode($related), self::CACHE_RELATED_TTL);
}
/**
* @param string $providerId
* @param string $itemId
*
* @return string
*/
private function generateRelatedFromItemCacheKey(
string $providerId,
string $itemId
): string {
return 'relatedFromItem/' . $providerId . '::' . $itemId;
}
/**
* @param IRelatedResourceProvider $provider
* @param FederatedUser $entity
*
* @return string[]
*/
private function getItemsAvailableToEntity(
IRelatedResourceProvider $provider,
FederatedUser $entity
): array {
try {
return $this->getCachedItemsAvailableToEntity($provider->getProviderId(), $entity->getSingleId());
} catch (CacheNotFoundException $e) {
}
$result = $provider->getItemsAvailableToEntity($entity);
$this->logger->debug(
'get available items to ' . $entity->getSingleId() . ' from ' . $provider->getProviderId() . ' - '
. json_encode($result)
);
$this->cacheItemsAvailableToEntity($provider->getProviderId(), $entity->getSingleId(), $result);
return $result;
}
/**
* @param string $providerId
* @param string $singleId
*
* @return string[]
* @throws CacheNotFoundException
*/
private function getCachedItemsAvailableToEntity(
string $providerId,
string $singleId
): array {
$key = $this->generateItemsAvailableToEntityCacheKey($providerId, $singleId);
$cachedData = $this->cache->get($key);
if (!is_string($cachedData) || empty($cachedData)) {
throw new CacheNotFoundException();
}
$result = json_decode($cachedData, true);
if (!is_array($result)) {
throw new CacheNotFoundException();
}
$this->logger->debug(
'existing cache on available items to ' . $singleId . ' from ' . $providerId . ' - '
. json_encode($result)
);
return $result;
}
/**
* @param string $providerId
* @param string $singleId
* @param array $result
*/
private function cacheItemsAvailableToEntity(
string $providerId,
string $singleId,
array $result
): void {
$this->logger->debug(
'caching available items to ' . $singleId . ' from ' . $providerId . ' - ' . json_encode($result)
);
$key = $this->generateItemsAvailableToEntityCacheKey($providerId, $singleId);
$this->cache->set($key, json_encode($result), self::CACHE_ITEMS_TTL);
}
/**
* @param string $providerId
* @param string $singleId
*
* @return string
*/
private function generateItemsAvailableToEntityCacheKey(
string $providerId,
string $singleId
): string {
return 'availableItem/' . $providerId . '::' . $singleId;
}
/**
* @param RelatedResource $current
* @param RelatedResource[] $result
*
* @return RelatedResource[]
*/
private function strictMatching(RelatedResource $current, array $result): array {
return array_filter($result, function (IRelatedResource $res) use ($current): bool {
if ($current->isGroupShared()) {
if (!$res->isGroupShared()) {
return false;
}
if ($this->isStrict($current->getRecipients(), $res->getRecipients())) {
return true;
}
} else {
if ($res->isGroupShared()) {
return false;
}
if ($this->isStrict($current->getVirtualGroup(), $res->getVirtualGroup())) {
return true;
}
}
return false;
});
}
/**
* @param IRelatedResource[] $result
*
* @return IRelatedResource[]
*/
private function filterUnavailableResults(array $result): array {
try {
$current = $this->circlesManager->getCurrentFederatedUser();
} catch (FederatedUserNotFoundException $e) {
$this->circlesManager->startSession(); // in case session is lost, restart fresh one
$current = $this->circlesManager->getCurrentFederatedUser();
}
return array_filter($result, function (IRelatedResource $res) use ($current): bool {
$all = array_values(array_unique(array_merge($res->getVirtualGroup(), $res->getRecipients())));
// is current user in the list already ?
if (in_array($current->getSingleId(), $all)) {
return true;
}
// or a member of an entity from the list ?
foreach ($res->getRecipients() as $circleId) {
try {
$this->circlesManager->getLink($circleId, $current->getSingleId());
return true;
} catch (Exception $e) {
}
}
return false;
});
}
/**
* @param IRelatedResource[] $result
*
* @return array
* @throws RelatedResourceProviderNotFound
*/
private function improveResult(array $result): array {
foreach ($result as $entry) {
$this->getRelatedResourceProvider($entry->getProviderId())
->improveRelatedResource($this->circlesManager, $entry);
}
return $result;
}
/**
* @param IRelatedResource $current
* @param IRelatedResource[] $result
*
* @return void
*/
private function weightResult(IRelatedResource $current, array &$result): void {
foreach ($this->getWeightCalculators() as $weightCalculator) {
$weightCalculator->weight($current, $result);
}
}
/**
* @return ILinkWeightCalculator[]
*/
private function getWeightCalculators(): array {
if (empty($this->weightCalculators)) {
$classes = self::$weightCalculators_;
foreach ($this->getRelatedResourceProviders() as $provider) {
foreach ($provider->loadWeightCalculator() as $class) {
$classes[] = $class;
}
}
foreach ($classes as $class) {
try {
$test = new ReflectionClass($class);
if (!in_array(ILinkWeightCalculator::class, $test->getInterfaceNames())) {
throw new ReflectionException(
$class . ' does not implements ILinkWeightCalculator'
);
}
$this->weightCalculators[] = Server::get($class);
} catch (NotFoundExceptionInterface | ContainerExceptionInterface | ReflectionException $e) {
$this->logger->notice($e->getMessage());
}
}
}
return $this->weightCalculators;
}
/**
* @return IRelatedResourceProvider[]
*/
private function getRelatedResourceProviders(): array {
$providers = [];
try {
$providers[] = Server::get(FilesRelatedResourceProvider::class);
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
$this->logger->notice($e->getMessage());
}
try {
$providers[] = Server::get(AccountRelatedResourceProvider::class);
} catch (NotFoundExceptionInterface|ContainerExceptionInterface $e) {
$this->logger->notice($e->getMessage());
}
if ($this->appManager->isInstalled('deck')) {
try {
$providers[] = Server::get(DeckRelatedResourceProvider::class);
} catch (NotFoundExceptionInterface | ContainerExceptionInterface $e) {
$this->logger->notice($e->getMessage());
}
}
if ($this->appManager->isInstalled('calendar')) {
try {
$providers[] = Server::get(CalendarRelatedResourceProvider::class);
} catch (NotFoundExceptionInterface | ContainerExceptionInterface $e) {
$this->logger->notice($e->getMessage());
}
}
if ($this->appManager->isInstalled('spreed')) {
try {
$providers[] = Server::get(TalkRelatedResourceProvider::class);
} catch (NotFoundExceptionInterface | ContainerExceptionInterface $e) {
$this->logger->notice($e->getMessage());
}
}
if ($this->appManager->isInstalled('groupfolders')) {
try {
$providers[] = Server::get(GroupFoldersRelatedResourceProvider::class);
} catch (NotFoundExceptionInterface | ContainerExceptionInterface $e) {
$this->logger->notice($e->getMessage());
}
}
return $providers;
}
/**
* @param string $relatedProviderId
*
* @return IRelatedResourceProvider
* @throws RelatedResourceProviderNotFound
*/
public function getRelatedResourceProvider(string $relatedProviderId): IRelatedResourceProvider {
foreach ($this->getRelatedResourceProviders() as $provider) {
if ($provider->getProviderId() === $relatedProviderId) {
return $provider;
}
}
throw new RelatedResourceProviderNotFound();
}
/**
* @param array $arr1
* @param array $arr2
*
* @return bool
*/
private function isStrict(array $arr1, array $arr2): bool {
return empty(array_merge(array_diff($arr1, $arr2), array_diff($arr2, $arr1)));
}
/**
* when a share is created/deleted, flush all
*/
public function flushCache(): void {
$this->logger->debug('flush cache');
$this->cache->clear();
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Db;
/**
* Interface IQueryRow
*
* @package OCA\RelatedResources\Tools\Db
*/
interface IQueryRow {
/**
* import data to feed the model.
*
* @param array $data
*
* @return IQueryRow
*/
public function importFromDatabase(array $data): self;
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class ArrayNotFoundException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class ArrayNotFoundException extends Exception {
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class DateTimeException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class DateTimeException extends Exception {
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class InvalidItemException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class InvalidItemException extends Exception {
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class ItemNotFoundException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class ItemNotFoundException extends Exception {
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class MalformedArrayException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class MalformedArrayException extends Exception {
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class RowNotFoundException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class RowNotFoundException extends Exception {
}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Exceptions;
use Exception;
/**
* Class UnknownTypeException
*
* @package OCA\RelatedResources\Tools\Exceptions
*/
class UnknownTypeException extends Exception {
}
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools;
interface IDeserializable {
/**
* @param array $data
*
* @return self
*/
public function import(array $data): self;
}
@@ -0,0 +1,432 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Traits;
use Exception;
use JsonSerializable;
use OCA\RelatedResources\Tools\Exceptions\ArrayNotFoundException;
use OCA\RelatedResources\Tools\Exceptions\ItemNotFoundException;
use OCA\RelatedResources\Tools\Exceptions\MalformedArrayException;
use OCA\RelatedResources\Tools\Exceptions\UnknownTypeException;
trait TArrayTools {
public static $TYPE_NULL = 'Null';
public static $TYPE_STRING = 'String';
public static $TYPE_ARRAY = 'Array';
public static $TYPE_BOOLEAN = 'Boolean';
public static $TYPE_INTEGER = 'Integer';
public static $TYPE_SERIALIZABLE = 'Serializable';
/**
* @param string $k
* @param array $arr
* @param string $default
*
* @return string
*/
protected function get(string $k, array $arr, string $default = ''): string {
if (!array_key_exists($k, $arr)) {
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return $default;
}
$r = $arr[$subs[0]];
if (!is_array($r)) {
return $default;
}
return $this->get($subs[1], $r, $default);
} else {
return $default;
}
}
if ($arr[$k] === null || !is_string($arr[$k]) && (!is_int($arr[$k]))) {
return $default;
}
return (string)$arr[$k];
}
/**
* @param string $k
* @param array $arr
* @param int $default
*
* @return int
*/
protected function getInt(string $k, array $arr, int $default = 0): int {
if (!array_key_exists($k, $arr)) {
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return $default;
}
$r = $arr[$subs[0]];
if (!is_array($r)) {
return $default;
}
return $this->getInt($subs[1], $r, $default);
} else {
return $default;
}
}
if ($arr[$k] === null) {
return $default;
}
return intval($arr[$k]);
}
/**
* @param string $k
* @param array $arr
* @param float $default
*
* @return float
*/
protected function getFloat(string $k, array $arr, float $default = 0): float {
if (!array_key_exists($k, $arr)) {
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return $default;
}
$r = $arr[$subs[0]];
if (!is_array($r)) {
return $default;
}
return $this->getFloat($subs[1], $r, $default);
} else {
return $default;
}
}
if ($arr[$k] === null) {
return $default;
}
return intval($arr[$k]);
}
/**
* @param string $k
* @param array $arr
* @param bool $default
*
* @return bool
*/
protected function getBool(string $k, array $arr, bool $default = false): bool {
if (!array_key_exists($k, $arr)) {
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return $default;
}
return $this->getBool($subs[1], $arr[$subs[0]], $default);
} else {
return $default;
}
}
if ($arr[$k] === null) {
return $default;
}
if (is_bool($arr[$k])) {
return $arr[$k];
}
$sk = (string)$arr[$k];
if ($sk === '1' || strtolower($sk) === 'true') {
return true;
}
if ($sk === '0' || strtolower($sk) === 'false') {
return false;
}
return $default;
}
/**
* @param string $k
* @param array $arr
* @param JsonSerializable|null $default
*
* @return mixed
*/
protected function getObj(string $k, array $arr, ?JsonSerializable $default = null): ?JsonSerializable {
if (!array_key_exists($k, $arr)) {
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return $default;
}
return $this->getObj($subs[1], $arr[$subs[0]], $default);
} else {
return $default;
}
}
return $arr[$k];
}
/**
* @param string $k
* @param array $arr
* @param array $default
*
* @return array
*/
protected function getArray(string $k, array $arr, array $default = []): array {
if (!array_key_exists($k, $arr)) {
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return $default;
}
$r = $arr[$subs[0]];
if (!is_array($r)) {
return $default;
}
return $this->getArray($subs[1], $r, $default);
} else {
return $default;
}
}
$r = $arr[$k];
if (!is_array($r) && !is_string($r)) {
return $default;
}
if (is_string($r)) {
$r = json_decode($r, true);
}
if (!is_array($r)) {
return $default;
}
return $r;
}
/**
* @param string $k
* @param array $arr
*
* @return bool
*/
public function validKey(string $k, array $arr): bool {
if (array_key_exists($k, $arr)) {
return true;
}
$subs = explode('.', $k, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
return false;
}
$r = $arr[$subs[0]];
if (!is_array($r)) {
return false;
}
return $this->validKey($subs[1], $r);
}
return false;
}
/**
* @param string $k
* @param array $arr
* @param array $import
* @param array $default
*
* @return array
*/
protected function getList(string $k, array $arr, array $import, array $default = []): array {
$list = $this->getArray($k, $arr, $default);
$r = [];
[$obj, $method] = $import;
foreach ($list as $item) {
try {
$o = new $obj();
$o->$method($item);
$r[] = $o;
} catch (Exception $e) {
}
}
return $r;
}
/**
* @param string $k
* @param string $value
* @param array $list
*
* @return mixed
* @throws ArrayNotFoundException
*/
protected function extractArray(string $k, string $value, array $list) {
foreach ($list as $arr) {
if (!array_key_exists($k, $arr)) {
continue;
}
if ($arr[$k] === $value) {
return $arr;
}
}
throw new ArrayNotFoundException();
}
/**
* @param string $key
* @param array $arr
* @param bool $root
*
* @return string
* @throws ItemNotFoundException
* @throws UnknownTypeException
*/
public function typeOf(string $key, array $arr, bool $root = true): string {
if (array_key_exists($key, $arr)) {
$item = $arr[$key];
if (is_null($item)) {
return self::$TYPE_NULL;
}
if (is_string($item)) {
return self::$TYPE_STRING;
}
if (is_array($item)) {
return self::$TYPE_ARRAY;
}
if (is_bool($item)) {
return self::$TYPE_BOOLEAN;
}
if (is_int($item)) {
return self::$TYPE_INTEGER;
}
if ($item instanceof JsonSerializable) {
return self::$TYPE_SERIALIZABLE;
}
throw new UnknownTypeException();
}
$subs = explode('.', $key, 2);
if (sizeof($subs) > 1) {
if (!array_key_exists($subs[0], $arr)) {
throw new ItemNotFoundException();
}
$r = $arr[$subs[0]];
if (is_array($r)) {
return $this->typeOf($subs[1], $r);
}
}
throw new ItemNotFoundException();
}
/**
* @param array $keys
* @param array $arr
*
* @throws MalformedArrayException
*/
protected function mustContains(array $keys, array $arr): void {
foreach ($keys as $key) {
if (!array_key_exists($key, $arr)) {
throw new MalformedArrayException(
'source: ' . json_encode($arr) . ' - missing key: ' . $key
);
}
}
}
/**
* @param array $arr
*/
protected function cleanArray(array &$arr): void {
$arr = array_filter(
$arr,
function ($v) {
if (is_string($v)) {
return ($v !== '');
}
if (is_array($v)) {
return !empty($v);
}
return true;
}
);
}
}
@@ -0,0 +1,159 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Traits;
use Exception;
use JsonSerializable;
use OCA\RelatedResources\Tools\Exceptions\InvalidItemException;
use OCA\RelatedResources\Tools\IDeserializable;
use ReflectionClass;
trait TDeserialize {
/**
* @param JsonSerializable $model
*
* @return array
*/
public function serialize(JsonSerializable $model): array {
return json_decode(json_encode($model), true);
}
/**
* @param array $data
*
* @return array
*/
public function serializeArray(array $data): array {
return json_decode(json_encode($data), true);
}
/**
* @param array $data
* @param string $class
*
* @return IDeserializable
* @throws InvalidItemException
*/
public function deserialize(array $data, string $class): IDeserializable {
try {
$test = new ReflectionClass($class);
} catch (\ReflectionException $e) {
throw new InvalidItemException('cannot ReflectionClass ' . $class);
}
if (!in_array(IDeserializable::class, $test->getInterfaceNames())) {
throw new InvalidItemException($class . ' does not implement IDeserializable');
}
/** @var IDeserializable $item */
$item = new $class;
$item->import($data);
return $item;
}
/**
* force deserialize without checking for implementation of IDeserializable.
* quickest solution to deserialize model from other apps.
*
* @param string $json
* @param string $class
*
* @return array
*/
public function forceDeserializeArrayFromJson(string $json, string $class): array {
$data = json_decode($json, true);
if (!is_array($data)) {
return [];
}
$arr = [];
foreach ($data as $entry) {
try {
$item = new $class;
$arr[] = $item->import($entry);
} catch (Exception $e) {
}
}
return $arr;
}
/**
* @param string $json
* @param string $class
*
* @return IDeserializable[]
*/
public function deserializeArrayFromJson(string $json, string $class): array {
$data = json_decode($json, true);
if (!is_array($data)) {
return [];
}
return $this->deserializeArray($data, $class);
}
/**
* @param array $data
* @param string $class
*
* @return array
*/
public function deserializeArray(array $data, string $class): array {
$arr = [];
foreach ($data as $entry) {
try {
$arr[] = $this->deserialize($entry, $class);
} catch (InvalidItemException $e) {
}
}
return $arr;
}
/**
* @param string $json
* @param string $class
*
* @return IDeserializable
* @throws InvalidItemException
*/
public function deserializeJson(string $json, string $class): IDeserializable {
$data = json_decode($json, true);
return $this->deserialize($data, $class);
}
}
@@ -0,0 +1,258 @@
<?php
declare(strict_types=1);
/**
* Nextcloud - Related Resources
*
* 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 2022
* @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\RelatedResources\Tools\Traits;
use DateTime;
use Exception;
trait TStringTools {
use TArrayTools;
/**
* @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 - 2)];
} catch (Exception $e) {
}
}
return $str;
}
/**
* Generate uuid: 2b5a7a87-8db1-445f-a17b-405790f91c80
*
* @param int $length
*
* @return string
*/
protected function uuid(int $length = 0): string {
$uuid = sprintf(
'%04x%04x-%04x-%04x-%04x-%04x%04x%04x', mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff), mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
);
if ($length > 0) {
if ($length <= 16) {
$uuid = str_replace('-', '', $uuid);
}
$uuid = substr($uuid, 0, $length);
}
return $uuid;
}
/**
* @param string $line
* @param int $length
*
* @return string
*/
protected function cut(string $line, int $length): string {
if (strlen($line) < $length) {
return $line;
}
return substr($line, 0, $length - 5) . ' (..)';
}
/**
* @param string $str1
* @param string $str2
* @param bool $cs case sensitive ?
*
* @return string
*/
protected function commonPart(string $str1, string $str2, bool $cs = true): string {
for ($i = 0; $i < strlen($str1) && $i < strlen($str2); $i++) {
$chr1 = $str1[$i];
$chr2 = $str2[$i];
if (!$cs) {
$chr1 = strtolower($chr1);
$chr2 = strtolower($chr2);
}
if ($chr1 !== $chr2) {
break;
}
}
return substr($str1, 0, $i);
}
/**
* @param string $line
* @param array $params
*
* @return string
*/
protected function feedStringWithParams(string $line, array $params): string {
$ak = array_keys($params);
foreach ($ak as $k) {
$line = str_replace('{' . $k . '}', (string)$params[$k], $line);
}
return $line;
}
/**
* @param int $words
*
* @return string
*/
public function generateRandomSentence(int $words = 5): string {
$sentence = [];
for ($i = 0; $i < $words; $i++) {
$sentence[] = $this->generateRandomWord(rand(2, 12));
}
return implode(' ', $sentence);
}
/**
* @param int $length
*
* @return string
*/
public function generateRandomWord(int $length = 8): string {
$c = ['b', 'c', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'm', 'n', 'p', 'r', 's', 't', 'v'];
$v = ['a', 'e', 'i', 'o', 'u', 'y'];
$word = [];
for ($i = 0; $i <= ($length / 2); $i++) {
$word[] = $c[array_rand($c)];
$word[] = $v[array_rand($v)];
}
return implode('', $word);
}
/**
* @param int $bytes
*
* @return string
*/
public function humanReadable(int $bytes): string {
if ($bytes == 0) {
return '0.00 B';
}
$s = ['B', 'KB', 'MB', 'GB', 'TB', 'PB'];
$e = floor(log($bytes, 1024));
return round($bytes / pow(1024, $e), 2) . ' ' . $s[$e];
}
/**
* @param int $first
* @param int $second
* @param bool $short
*
* @return string
* @throws Exception
*/
public function getDateDiff(
int $first,
int $second = 0,
bool $short = false,
array $words = []
): string {
if ($second === 0) {
$first = time() - $first;
$second = time();
}
$f = new DateTime('@' . $first);
$s = new DateTime('@' . $second);
$duration = $second - $first;
if ($short) {
$minutes = $this->get('minutes', $words, 'M');
$hours = $this->get('hours', $words, 'H');
$days = $this->get('days', $words, 'D');
if ($duration < 60) {
return $f->diff($s)->format('<1' . $minutes);
}
if ($duration < 3600) {
return $f->diff($s)->format('%i' . $minutes);
}
if ($duration < 86400) {
return $f->diff($s)->format('%h' . $hours . ', %i' . $minutes);
}
return $f->diff($s)->format('%a' . $days . ', %h' . $hours . ', %i' . $minutes);
}
$seconds = $this->get('seconds', $words, 'seconds');
$minutes = $this->get('minutes', $words, 'minutes');
$hours = $this->get('hours', $words, 'hours');
$days = $this->get('days', $words, 'days');
if ($duration < 60) {
return $f->diff($s)->format('%s ' . $seconds);
}
if ($duration < 3600) {
return $f->diff($s)->format('%i ' . $minutes . ' and %s ' . $seconds);
}
if ($duration < 86400) {
return $f->diff($s)->format('%h ' . $hours . ', %i ' . $minutes . ' and %s ' . $seconds);
}
return $f->diff($s)->format(
'%a ' . $days .
', %h ' . $hours .
', %i ' . $minutes .
' and %s ' . $seconds
);
}
}