Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions lib/Activity/Provider.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

use OCA\Absence\Service\ActivityPublisher;
use OCA\Absence\Service\ConfigService;
use OCP\Activity\Exceptions\UnknownActivityException;
use OCP\Activity\IEvent;
use OCP\Activity\IProvider;
use OCP\IURLGenerator;
Expand All @@ -27,7 +28,7 @@ public function __construct(
#[\Override]
public function parse($language, IEvent $event, ?IEvent $previousEvent = null): IEvent {
if ($event->getApp() !== ConfigService::APP_ID) {
throw new \InvalidArgumentException('Not an Absence event');
throw new UnknownActivityException('Not an Absence event');
}
$l = $this->l10nFactory->get(ConfigService::APP_ID, $language);
$params = $event->getSubjectParameters();
Expand All @@ -42,7 +43,7 @@ public function parse($language, IEvent $event, ?IEvent $previousEvent = null):
ActivityPublisher::SUBJECT_ESCALATED => $l->t('Leave for %1$s (%2$s) was escalated to HR', [$employee, $range]),
ActivityPublisher::SUBJECT_WITHDRAWAL => $l->t('%1$s requested to withdraw leave for %2$s', [$employee, $range]),
ActivityPublisher::SUBJECT_BALANCE_ADJUSTED => $l->t('Leave balance of %s was adjusted', [$employee]),
default => throw new \InvalidArgumentException('Unknown subject'),
default => throw new UnknownActivityException('Unknown subject'),
};

$event->setParsedSubject($subject);
Expand Down
6 changes: 3 additions & 3 deletions lib/Service/PersonalDefaultsService.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use OCA\DAV\CalDAV\Schedule\Plugin;
use OCA\DAV\Db\PropertyMapper;
use OCP\Accounts\IAccountManager;
use OCP\IConfig;
use OCP\Config\IUserConfig;
use OCP\IUserManager;
use Psr\Log\LoggerInterface;
use Sabre\VObject\Reader;
Expand Down Expand Up @@ -49,7 +49,7 @@ class PersonalDefaultsService {
];

public function __construct(
private IConfig $config,
private IUserConfig $userConfig,
private ConfigService $appConfig,
private IAccountManager $accountManager,
private IUserManager $userManager,
Expand Down Expand Up @@ -139,7 +139,7 @@ public function detectWorkingWeekdays(string $uid): ?array {

/** Suggested ISO country code from the user's locale, then phone; null if unknown. */
public function detectCountry(string $uid): ?string {
$locale = $this->config->getUserValue($uid, 'core', 'locale', '');
$locale = $this->userConfig->getValueString($uid, 'core', 'locale');
if (str_contains($locale, '_')) {
$region = strtoupper(substr($locale, strpos($locale, '_') + 1));
if (preg_match('/^[A-Z]{2}$/', $region)) {
Expand Down
91 changes: 91 additions & 0 deletions tests/Unit/Activity/ProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Absence\Tests\Unit\Activity;

use OCA\Absence\Activity\Provider;
use OCA\Absence\Service\ActivityPublisher;
use OCA\Absence\Service\ConfigService;
use OCP\Activity\Exceptions\UnknownActivityException;
use OCP\Activity\IEvent;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
use OCP\L10N\IFactory;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

class ProviderTest extends TestCase {
private IURLGenerator&MockObject $urlGenerator;
private IUserManager&MockObject $userManager;
private Provider $provider;

protected function setUp(): void {
parent::setUp();
$l10n = $this->createMock(IL10N::class);
$l10n->method('t')->willReturnCallback(
static fn (string $text, array $parameters = []): string => vsprintf($text, $parameters)
);
$l10nFactory = $this->createMock(IFactory::class);
$l10nFactory->method('get')->willReturn($l10n);
$this->urlGenerator = $this->createMock(IURLGenerator::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->provider = new Provider($l10nFactory, $this->urlGenerator, $this->userManager);
}

public function testParseThrowsUnknownActivityForForeignApp(): void {
$event = $this->createMock(IEvent::class);
$event->method('getApp')->willReturn('files');

$this->expectException(UnknownActivityException::class);
$this->provider->parse('en', $event);
}

public function testParseThrowsUnknownActivityForUnknownSubject(): void {
$event = $this->createMock(IEvent::class);
$event->method('getApp')->willReturn(ConfigService::APP_ID);
$event->method('getSubject')->willReturn('something_else');
$event->method('getSubjectParameters')->willReturn([]);

$this->expectException(UnknownActivityException::class);
$this->provider->parse('en', $event);
}

public function testParseSetsSubjectIconAndLink(): void {
$user = $this->createMock(IUser::class);
$user->method('getDisplayName')->willReturn('Alice Doe');
$this->userManager->method('get')->with('alice')->willReturn($user);

$this->urlGenerator->method('imagePath')->willReturn('/img/app-dark.svg');
$this->urlGenerator->method('getAbsoluteURL')->willReturn('https://cloud.example.com/img/app-dark.svg');
$this->urlGenerator->method('linkToRouteAbsolute')->willReturn('https://cloud.example.com/apps/absence/');

$event = $this->createMock(IEvent::class);
$event->method('getApp')->willReturn(ConfigService::APP_ID);
$event->method('getSubject')->willReturn(ActivityPublisher::SUBJECT_APPROVED);
$event->method('getSubjectParameters')->willReturn([
'employee' => 'alice',
'start' => '2026-08-03',
'end' => '2026-08-07',
]);
$event->method('getObjectId')->willReturn(42);

$event->expects($this->once())
->method('setParsedSubject')
->with('Leave for Alice Doe (2026-08-03 – 2026-08-07) was approved');
$event->expects($this->once())
->method('setIcon')
->with('https://cloud.example.com/img/app-dark.svg');
$event->expects($this->once())
->method('setLink')
->with('https://cloud.example.com/apps/absence/#/requests/42');

$this->assertSame($event, $this->provider->parse('en', $event));
}
}
63 changes: 63 additions & 0 deletions tests/Unit/Service/PersonalDefaultsServiceTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

declare(strict_types=1);
/**
* SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCA\Absence\Tests\Unit\Service;

use OCA\Absence\Service\ConfigService;
use OCA\Absence\Service\PersonalDefaultsService;
use OCA\DAV\Db\PropertyMapper;
use OCP\Accounts\IAccountManager;
use OCP\Config\IUserConfig;
use OCP\IUserManager;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;

class PersonalDefaultsServiceTest extends TestCase {
private IUserConfig&MockObject $userConfig;
private IUserManager&MockObject $userManager;
private PersonalDefaultsService $service;

protected function setUp(): void {
parent::setUp();
$this->userConfig = $this->createMock(IUserConfig::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->service = new PersonalDefaultsService(
$this->userConfig,
$this->createMock(ConfigService::class),
$this->createMock(IAccountManager::class),
$this->userManager,
$this->createMock(PropertyMapper::class),
$this->createMock(LoggerInterface::class),
);
}

public function testDetectCountryReadsLocaleFromUserConfig(): void {
$this->userConfig->expects($this->once())
->method('getValueString')
->with('alice', 'core', 'locale')
->willReturn('de_AT');

$this->assertSame('AT', $this->service->detectCountry('alice'));
}

public function testDetectCountryFallsBackToPhoneWhenLocaleHasNoRegion(): void {
$this->userConfig->method('getValueString')->willReturn('de');
// No user -> phone lookup yields nothing, so the result is null rather than a guess.
$this->userManager->method('get')->with('alice')->willReturn(null);

$this->assertNull($this->service->detectCountry('alice'));
}

public function testDetectCountryFallsBackToPhoneWhenLocaleUnset(): void {
$this->userConfig->method('getValueString')->willReturn('');
$this->userManager->method('get')->with('alice')->willReturn(null);

$this->assertNull($this->service->detectCountry('alice'));
}
}
Loading