Skip to content

Commit

Permalink
fixup! Augment the category menu by system tags and already used cate…
Browse files Browse the repository at this point in the history
…gories.

Signed-off-by: Christoph Wurst <[email protected]>
  • Loading branch information
ChristophWurst committed Jun 28, 2023
1 parent 121feef commit 287342d
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 28 deletions.
2 changes: 1 addition & 1 deletion lib/Controller/ViewController.php
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ public function index():TemplateResponse {
$this->initialStateService->provideInitialState('appointmentConfigs', $this->appointmentConfigService->getAllAppointmentConfigurations($this->userId));
$this->initialStateService->provideInitialState('disable_appointments', $disableAppointments);
$this->initialStateService->provideInitialState('can_subscribe_link', $canSubscribeLink);
$this->initialStateService->provideInitialState('categories', $this->categoriesService->getCategories());
$this->initialStateService->provideInitialState('categories', $this->categoriesService->getCategories($this->userId));

return new TemplateResponse($this->appName, 'main');
}
Expand Down
39 changes: 13 additions & 26 deletions lib/Service/CategoriesService.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<?php

declare(strict_types=1);

/**
* Calendar App
*
Expand All @@ -25,57 +26,43 @@

namespace OCA\Calendar\Service;

use OCP\Calendar\ICalendar;
use OCP\Calendar\ICalendarQuery;
use OCP\Calendar\IManager as ICalendarManager;
use OCP\IL10N;
use OCP\SystemTag\ISystemTag;
use OCP\SystemTag\ISystemTagManager;
use Psr\Log\LoggerInterface;

/**
* @psalm-type Category = array{label: string, value: string}
* @psalm-type CategoryGroup = array{group: string, options: array<int, Category>}
*/
class CategoriesService {
/** @var null|string */
private $userId;

/** @var ICalendarManager */
private $calendarManager;

/** @var ISystemTagManager */
private $systemTagManager;

/** @var LoggerInterface */
private $logger;

/** @var IL10N */
private $l;

private const CALENDAR_OBJECT_PROPERTIES_TABLE = 'calendarobjects_props';

public function __construct(?string $userId,
ICalendarManager $calendarManager,
public function __construct(ICalendarManager $calendarManager,
ISystemTagManager $systemTagManager,
LoggerInterface $logger,
IL10N $l10n) {
$this->userId = $userId;
$this->calendarManager = $calendarManager;
$this->systemTagManager = $systemTagManager;
$this->logger = $logger;
$this->l = $l10n;
}

/**
* This is a simplistic brute-force extraction of all already used
* categories from all events accessible to the currently logged in user.
* categories from all events accessible to the given user.
*
* @return array
*/
private function getUsedCategories(): array {
if (empty($this->userId)) {
return [];
}

private function getUsedCategories(string $userId): array {
$categories = [];
$principalUri = 'principals/users/' . $this->userId;
$principalUri = 'principals/users/' . $userId;
$query = $this->calendarManager->newQuery($principalUri);
$query->addSearchProperty(ICalendarQuery::SEARCH_PROPERTY_CATEGORIES);
$calendarObjects = $this->calendarManager->searchForPrincipal($query);
Expand All @@ -96,11 +83,11 @@ private function getUsedCategories(): array {

/**
* Return a grouped array with all previously used categories, all system
* tags and all categories found the the iCalendar RFC.
* tags and all categories found in the iCalendar RFC.
*
* @return array
* @return CategoryGroup[]
*/
public function getCategories(): array {
public function getCategories(string $userId): array {
$systemTags = $this->systemTagManager->getAllTags(true);

$systemTagCategoryLabels = [];
Expand Down Expand Up @@ -135,7 +122,7 @@ public function getCategories(): array {
$rfcCategoryLabels = array_values(array_filter(array_unique($rfcCategoryLabels)));

$standardCategories = array_merge($systemTagCategoryLabels, $rfcCategoryLabels);
$customCategoryLabels = array_values(array_filter($this->getUsedCategories(), fn ($label) => !in_array($label, $standardCategories)));
$customCategoryLabels = array_values(array_filter($this->getUsedCategories($userId), fn ($label) => !in_array($label, $standardCategories)));

$categories = [
[
Expand Down
24 changes: 23 additions & 1 deletion tests/php/unit/Controller/ViewControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,18 @@ public function testIndex(): void {
->method('getAllAppointmentConfigurations')
->with($this->userId)
->willReturn([new AppointmentConfig()]);

$this->categoriesService->expects(self::once())
->method('getCategories')
->with('user123')
->willReturn([
[
'group' => 'Test',
'options' => [
'label' => 'hawaii',
'value' => 'pizza',
],
],
]);
$this->initialStateService
->method('provideInitialState')
->withConsecutive(
Expand All @@ -161,6 +172,17 @@ public function testIndex(): void {
['hide_event_export', true],
['force_event_alarm_type', null],
['appointmentConfigs', [new AppointmentConfig()]],
['disable_appointments', false],
['can_subscribe_link', false],
['categories', [
[
'group' => 'Test',
'options' => [
'label' => 'hawaii',
'value' => 'pizza',
],
],
]],
);

$response = $this->controller->index();
Expand Down
146 changes: 146 additions & 0 deletions tests/php/unit/Service/CategoriesServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
<?php

declare(strict_types=1);

/*
* @copyright 2023 Christoph Wurst <[email protected]>
*
* @author 2023 Christoph Wurst <[email protected]>
*
* @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\Calendar\Tests\Unit\Service;

use ChristophWurst\Nextcloud\Testing\ServiceMockObject;
use ChristophWurst\Nextcloud\Testing\TestCase;
use OCA\Calendar\Service\CategoriesService;
use OCP\SystemTag\ISystemTag;
use function array_column;

class CategoriesServiceTest extends TestCase {
private ServiceMockObject $serviceMock;
private CategoriesService $service;

protected function setUp(): void {
parent::setUp();

$this->serviceMock = $this->createServiceMock(CategoriesService::class);
$this->service = $this->serviceMock->getService();

$this->serviceMock->getParameter('l10n')
->method('t')
->willReturnArgument(0);
}

public function testGetCategoriesDefaultsOnly(): void {
$categories = $this->service->getCategories('user123');

self::assertCount(3, $categories);
self::assertEquals(
[
'Custom Categories',
'Collaborative Tags',
'Standard Categories',
],
array_column($categories, 'group')
);
self::assertCount(0, $categories[0]['options']);
self::assertCount(0, $categories[1]['options']);
self::assertCount(15, $categories[2]['options']);
}

public function testGetUsedCategories(): void {
$this->serviceMock->getParameter('calendarManager')
->expects(self::once())
->method('searchForPrincipal')
->willReturn([
[
'objects' => [],
],
[
'objects' => [
[
'CATEGORIES' => [
[
'',
[],
]
],
],
],
],
[
'objects' => [
[
'CATEGORIES' => [
[
'pizza,party',
[],
]
],
],
],
],
[
'objects' => [
[
'CATEGORIES' => [
[
'pizza,hawaii',
[],
]
],
],
],
],
]);

$categories = $this->service->getCategories('user123');

self::assertArrayHasKey(0, $categories);
self::assertCount(3, $categories[0]['options']);
self::assertEquals(['pizza', 'party', 'hawaii'], array_column($categories[0]['options'], 'label'));
}

public function testGetSystemTagsAsCategories(): void {
$tag1 = $this->createMock(ISystemTag::class);
$tag1->method('isUserAssignable')->willReturn(false);
$tag1->method('isUserVisible')->willReturn(true);
$tag2 = $this->createMock(ISystemTag::class);
$tag2->method('isUserAssignable')->willReturn(false);
$tag2->method('isUserVisible')->willReturn(false);
$tag3 = $this->createMock(ISystemTag::class);
$tag3->method('isUserAssignable')->willReturn(true);
$tag3->method('isUserVisible')->willReturn(true);
$tag3->method('getName')->willReturn('fun');
$this->serviceMock->getParameter('systemTagManager')
->expects(self::once())
->method('getAllTags')
->with(true)
->willReturn([
$tag1,
$tag2,
$tag3,
]);

$categories = $this->service->getCategories('user123');

self::assertArrayHasKey(1, $categories);
self::assertCount(1, $categories[1]['options']);
self::assertEquals(['fun'], array_column($categories[1]['options'], 'label'));
}
}

0 comments on commit 287342d

Please sign in to comment.