Skip to content

feat: Add OCP interface to format richtext into string #48137

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Sep 18, 2024
Merged
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
27 changes: 3 additions & 24 deletions core/Command/SetupChecks.php
Original file line number Diff line number Diff line change
@@ -9,13 +9,15 @@

namespace OC\Core\Command;

use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\SetupCheck\ISetupCheckManager;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class SetupChecks extends Base {
public function __construct(
private ISetupCheckManager $setupCheckManager,
private IRichTextFormatter $richTextFormatter,
) {
parent::__construct();
}
@@ -29,29 +31,6 @@ protected function configure(): void {
;
}

/**
* @TODO move this method to a common service used by notifications, activity and this command
* @throws \InvalidArgumentException if a parameter has no name or no type
*/
private function richToParsed(string $message, array $parameters): string {
$placeholders = [];
$replacements = [];
foreach ($parameters as $placeholder => $parameter) {
$placeholders[] = '{' . $placeholder . '}';
foreach (['name','type'] as $requiredField) {
if (!isset($parameter[$requiredField]) || !is_string($parameter[$requiredField])) {
throw new \InvalidArgumentException("Invalid rich object, {$requiredField} field is missing");
}
}
$replacements[] = match($parameter['type']) {
'user' => '@' . $parameter['name'],
'file' => $parameter['path'] ?? $parameter['name'],
default => $parameter['name'],
};
}
return str_replace($placeholders, $replacements, $message);
}

protected function execute(InputInterface $input, OutputInterface $output): int {
$results = $this->setupCheckManager->runAll();
switch ($input->getOption('output')) {
@@ -79,7 +58,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int
$description = $check->getDescription();
$descriptionParameters = $check->getDescriptionParameters();
if ($description !== null && $descriptionParameters !== null) {
$description = $this->richToParsed($description, $descriptionParameters);
$description = $this->richTextFormatter->richToParsed($description, $descriptionParameters);
}
$output->writeln(
"\t\t".
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_classmap.php
Original file line number Diff line number Diff line change
@@ -646,6 +646,7 @@
'OCP\\Remote\\IInstanceFactory' => $baseDir . '/lib/public/Remote/IInstanceFactory.php',
'OCP\\Remote\\IUser' => $baseDir . '/lib/public/Remote/IUser.php',
'OCP\\RichObjectStrings\\Definitions' => $baseDir . '/lib/public/RichObjectStrings/Definitions.php',
'OCP\\RichObjectStrings\\IRichTextFormatter' => $baseDir . '/lib/public/RichObjectStrings/IRichTextFormatter.php',
'OCP\\RichObjectStrings\\IValidator' => $baseDir . '/lib/public/RichObjectStrings/IValidator.php',
'OCP\\RichObjectStrings\\InvalidObjectExeption' => $baseDir . '/lib/public/RichObjectStrings/InvalidObjectExeption.php',
'OCP\\Route\\IRoute' => $baseDir . '/lib/public/Route/IRoute.php',
@@ -1839,6 +1840,7 @@
'OC\\Repair\\RepairInvalidShares' => $baseDir . '/lib/private/Repair/RepairInvalidShares.php',
'OC\\Repair\\RepairLogoDimension' => $baseDir . '/lib/private/Repair/RepairLogoDimension.php',
'OC\\Repair\\RepairMimeTypes' => $baseDir . '/lib/private/Repair/RepairMimeTypes.php',
'OC\\RichObjectStrings\\RichTextFormatter' => $baseDir . '/lib/private/RichObjectStrings/RichTextFormatter.php',
'OC\\RichObjectStrings\\Validator' => $baseDir . '/lib/private/RichObjectStrings/Validator.php',
'OC\\Route\\CachingRouter' => $baseDir . '/lib/private/Route/CachingRouter.php',
'OC\\Route\\Route' => $baseDir . '/lib/private/Route/Route.php',
2 changes: 2 additions & 0 deletions lib/composer/composer/autoload_static.php
Original file line number Diff line number Diff line change
@@ -679,6 +679,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OCP\\Remote\\IInstanceFactory' => __DIR__ . '/../../..' . '/lib/public/Remote/IInstanceFactory.php',
'OCP\\Remote\\IUser' => __DIR__ . '/../../..' . '/lib/public/Remote/IUser.php',
'OCP\\RichObjectStrings\\Definitions' => __DIR__ . '/../../..' . '/lib/public/RichObjectStrings/Definitions.php',
'OCP\\RichObjectStrings\\IRichTextFormatter' => __DIR__ . '/../../..' . '/lib/public/RichObjectStrings/IRichTextFormatter.php',
'OCP\\RichObjectStrings\\IValidator' => __DIR__ . '/../../..' . '/lib/public/RichObjectStrings/IValidator.php',
'OCP\\RichObjectStrings\\InvalidObjectExeption' => __DIR__ . '/../../..' . '/lib/public/RichObjectStrings/InvalidObjectExeption.php',
'OCP\\Route\\IRoute' => __DIR__ . '/../../..' . '/lib/public/Route/IRoute.php',
@@ -1872,6 +1873,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2
'OC\\Repair\\RepairInvalidShares' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairInvalidShares.php',
'OC\\Repair\\RepairLogoDimension' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairLogoDimension.php',
'OC\\Repair\\RepairMimeTypes' => __DIR__ . '/../../..' . '/lib/private/Repair/RepairMimeTypes.php',
'OC\\RichObjectStrings\\RichTextFormatter' => __DIR__ . '/../../..' . '/lib/private/RichObjectStrings/RichTextFormatter.php',
'OC\\RichObjectStrings\\Validator' => __DIR__ . '/../../..' . '/lib/private/RichObjectStrings/Validator.php',
'OC\\Route\\CachingRouter' => __DIR__ . '/../../..' . '/lib/private/Route/CachingRouter.php',
'OC\\Route\\Route' => __DIR__ . '/../../..' . '/lib/private/Route/Route.php',
40 changes: 7 additions & 33 deletions lib/private/Activity/Event.php
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
use OCP\Activity\Exceptions\InvalidValueException;
use OCP\Activity\IEvent;
use OCP\RichObjectStrings\InvalidObjectExeption;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;

class Event implements IEvent {
@@ -60,14 +61,11 @@ class Event implements IEvent {

/** @var IEvent|null */
protected $child;
/** @var IValidator */
protected $richValidator;

/**
* @param IValidator $richValidator
*/
public function __construct(IValidator $richValidator) {
$this->richValidator = $richValidator;
public function __construct(
protected IValidator $richValidator,
protected IRichTextFormatter $richTextFormatter,
) {
}

/**
@@ -217,7 +215,7 @@ public function setRichSubject(string $subject, array $parameters = []): IEvent

if ($this->subjectParsed === '') {
try {
$this->subjectParsed = $this->richToParsed($subject, $parameters);
$this->subjectParsed = $this->richTextFormatter->richToParsed($subject, $parameters);
} catch (\InvalidArgumentException $e) {
throw new InvalidValueException('richSubjectParameters', $e);
}
@@ -226,30 +224,6 @@ public function setRichSubject(string $subject, array $parameters = []): IEvent
return $this;
}

/**
* @throws \InvalidArgumentException if a parameter has no name or no type
*/
private function richToParsed(string $message, array $parameters): string {
$placeholders = [];
$replacements = [];
foreach ($parameters as $placeholder => $parameter) {
$placeholders[] = '{' . $placeholder . '}';
foreach (['name','type'] as $requiredField) {
if (!isset($parameter[$requiredField]) || !is_string($parameter[$requiredField])) {
throw new \InvalidArgumentException("Invalid rich object, {$requiredField} field is missing");
}
}
if ($parameter['type'] === 'user') {
$replacements[] = '@' . $parameter['name'];
} elseif ($parameter['type'] === 'file') {
$replacements[] = $parameter['path'] ?? $parameter['name'];
} else {
$replacements[] = $parameter['name'];
}
}
return str_replace($placeholders, $replacements, $message);
}

/**
* @return string
* @since 11.0.0
@@ -317,7 +291,7 @@ public function setRichMessage(string $message, array $parameters = []): IEvent

if ($this->messageParsed === '') {
try {
$this->messageParsed = $this->richToParsed($message, $parameters);
$this->messageParsed = $this->richTextFormatter->richToParsed($message, $parameters);
} catch (\InvalidArgumentException $e) {
throw new InvalidValueException('richMessageParameters', $e);
}
32 changes: 8 additions & 24 deletions lib/private/Activity/Manager.php
Original file line number Diff line number Diff line change
@@ -21,20 +21,10 @@
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;

class Manager implements IManager {
/** @var IRequest */
protected $request;

/** @var IUserSession */
protected $session;

/** @var IConfig */
protected $config;

/** @var IValidator */
protected $validator;

/** @var string */
protected $formattingObjectType;
@@ -48,20 +38,14 @@ class Manager implements IManager {
/** @var string */
protected $currentUserId;

protected $l10n;

public function __construct(
IRequest $request,
IUserSession $session,
IConfig $config,
IValidator $validator,
IL10N $l10n
protected IRequest $request,
protected IUserSession $session,
protected IConfig $config,
protected IValidator $validator,
protected IRichTextFormatter $richTextFormatter,
protected IL10N $l10n,
) {
$this->request = $request;
$this->session = $session;
$this->config = $config;
$this->validator = $validator;
$this->l10n = $l10n;
}

/** @var \Closure[] */
@@ -104,7 +88,7 @@ protected function getConsumers(): array {
* @return IEvent
*/
public function generateEvent(): IEvent {
return new Event($this->validator);
return new Event($this->validator, $this->richTextFormatter);
}

/**
4 changes: 3 additions & 1 deletion lib/private/Notification/Manager.php
Original file line number Diff line number Diff line change
@@ -22,6 +22,7 @@
use OCP\Notification\INotification;
use OCP\Notification\INotifier;
use OCP\Notification\UnknownNotificationException;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;
use OCP\Support\Subscription\IRegistry;
use Psr\Container\ContainerExceptionInterface;
@@ -55,6 +56,7 @@ public function __construct(
protected IRegistry $subscription,
protected LoggerInterface $logger,
private Coordinator $coordinator,
private IRichTextFormatter $richTextFormatter,
) {
$this->cache = $cacheFactory->createDistributed('notifications');

@@ -199,7 +201,7 @@ public function getNotifiers(): array {
* @since 8.2.0
*/
public function createNotification(): INotification {
return new Notification($this->validator);
return new Notification($this->validator, $this->richTextFormatter);
}

/**
30 changes: 4 additions & 26 deletions lib/private/Notification/Notification.php
Original file line number Diff line number Diff line change
@@ -12,6 +12,7 @@
use OCP\Notification\INotification;
use OCP\Notification\InvalidValueException;
use OCP\RichObjectStrings\InvalidObjectExeption;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;

class Notification implements INotification {
@@ -39,6 +40,7 @@ class Notification implements INotification {

public function __construct(
protected IValidator $richValidator,
protected IRichTextFormatter $richTextFormatter,
) {
$this->dateTime = new \DateTime();
$this->dateTime->setTimestamp(0);
@@ -187,7 +189,7 @@ public function setRichSubject(string $subject, array $parameters = []): INotifi

if ($this->subjectParsed === '') {
try {
$this->subjectParsed = $this->richToParsed($subject, $parameters);
$this->subjectParsed = $this->richTextFormatter->richToParsed($subject, $parameters);
} catch (\InvalidArgumentException $e) {
throw new InvalidValueException('richSubjectParameters', $e);
}
@@ -196,30 +198,6 @@ public function setRichSubject(string $subject, array $parameters = []): INotifi
return $this;
}

/**
* @throws \InvalidArgumentException if a parameter has no name or no type
*/
private function richToParsed(string $message, array $parameters): string {
$placeholders = [];
$replacements = [];
foreach ($parameters as $placeholder => $parameter) {
$placeholders[] = '{' . $placeholder . '}';
foreach (['name','type'] as $requiredField) {
if (!isset($parameter[$requiredField]) || !is_string($parameter[$requiredField])) {
throw new \InvalidArgumentException("Invalid rich object, {$requiredField} field is missing");
}
}
if ($parameter['type'] === 'user') {
$replacements[] = '@' . $parameter['name'];
} elseif ($parameter['type'] === 'file') {
$replacements[] = $parameter['path'] ?? $parameter['name'];
} else {
$replacements[] = $parameter['name'];
}
}
return str_replace($placeholders, $replacements, $message);
}

/**
* {@inheritDoc}
*/
@@ -293,7 +271,7 @@ public function setRichMessage(string $message, array $parameters = []): INotifi

if ($this->messageParsed === '') {
try {
$this->messageParsed = $this->richToParsed($message, $parameters);
$this->messageParsed = $this->richTextFormatter->richToParsed($message, $parameters);
} catch (\InvalidArgumentException $e) {
throw new InvalidValueException('richMessageParameters', $e);
}
36 changes: 36 additions & 0 deletions lib/private/RichObjectStrings/RichTextFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OC\RichObjectStrings;

use OCP\RichObjectStrings\IRichTextFormatter;

class RichTextFormatter implements IRichTextFormatter {
/**
* @throws \InvalidArgumentException if a parameter has no name or no type
*/
public function richToParsed(string $message, array $parameters): string {
$placeholders = [];
$replacements = [];
foreach ($parameters as $placeholder => $parameter) {
$placeholders[] = '{' . $placeholder . '}';
foreach (['name','type'] as $requiredField) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
foreach (['name','type'] as $requiredField) {
foreach (['name', 'type'] as $requiredField) {

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this not covered by cs-fixed? 👀

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why would it be broken?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because this change is not flagged an cs error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But do we have a rule for this?
The code @nickvergessen mentioned is only there to ignore git-ignored files.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an array, not a function call so a space is not expected there I think

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I agree that we should have a rule for it.

if (!isset($parameter[$requiredField]) || !is_string($parameter[$requiredField])) {
throw new \InvalidArgumentException("Invalid rich object, {$requiredField} field is missing");
}
}
$replacements[] = match($parameter['type']) {
'user' => '@' . $parameter['name'],
'file' => $parameter['path'] ?? $parameter['name'],
default => $parameter['name'],
};
}
return str_replace($placeholders, $replacements, $message);
}
}
4 changes: 4 additions & 0 deletions lib/private/Server.php
Original file line number Diff line number Diff line change
@@ -204,6 +204,7 @@
use OCP\Profiler\IProfiler;
use OCP\Remote\Api\IApiFactory;
use OCP\Remote\IInstanceFactory;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;
use OCP\Route\IRouter;
use OCP\Security\Bruteforce\IThrottler;
@@ -648,6 +649,7 @@ public function __construct($webRoot, \OC\Config $config) {
$c->get(IUserSession::class),
$c->get(\OCP\IConfig::class),
$c->get(IValidator::class),
$c->get(IRichTextFormatter::class),
$l10n
);
});
@@ -1285,6 +1287,8 @@ public function __construct($webRoot, \OC\Config $config) {

$this->registerAlias(\OCP\Security\Ip\IFactory::class, \OC\Security\Ip\Factory::class);

$this->registerAlias(IRichTextFormatter::class, \OC\RichObjectStrings\RichTextFormatter::class);

$this->connectDispatcher();
}

25 changes: 25 additions & 0 deletions lib/public/RichObjectStrings/IRichTextFormatter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<?php

declare(strict_types=1);

/**
* SPDX-FileCopyrightText: 2024 Nextcloud GmbH and Nextcloud contributors
* SPDX-License-Identifier: AGPL-3.0-or-later
*/

namespace OCP\RichObjectStrings;

/**
* Parse rich text and format it with the richobjects
*
* @since 31.0.0
*/
interface IRichTextFormatter {
/**
* @since 31.0.0
* @param string $message
* @param array<string,array<string,string>> $parameters
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* @param array<string,array<string,string>> $parameters
* @param array<string, array<string, string>> $parameters

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’m always afraid to break tools by doing that because the type and the name of the parameter is space separated to adding space in the type looks wrong.

* @throws \InvalidArgumentException if a parameter has no name or no type
*/
public function richToParsed(string $message, array $parameters): string;
}
17 changes: 9 additions & 8 deletions tests/lib/Activity/ManagerTest.php
Original file line number Diff line number Diff line change
@@ -14,21 +14,20 @@
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;

class ManagerTest extends TestCase {
/** @var \OC\Activity\Manager */
private $activityManager;

/** @var IRequest|\PHPUnit\Framework\MockObject\MockObject */
protected $request;
/** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */
protected $session;
/** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */
protected $config;
/** @var IValidator|\PHPUnit\Framework\MockObject\MockObject */
protected $validator;
protected IRequest&MockObject $request;
protected IUserSession&MockObject $session;
protected IConfig&MockObject $config;
protected IValidator&MockObject $validator;
protected IRichTextFormatter&MockObject $richTextFormatter;

protected function setUp(): void {
parent::setUp();
@@ -37,12 +36,14 @@ protected function setUp(): void {
$this->session = $this->createMock(IUserSession::class);
$this->config = $this->createMock(IConfig::class);
$this->validator = $this->createMock(IValidator::class);
$this->richTextFormatter = $this->createMock(IRichTextFormatter::class);

$this->activityManager = new \OC\Activity\Manager(
$this->request,
$this->session,
$this->config,
$this->validator,
$this->richTextFormatter,
$this->createMock(IL10N::class)
);

20 changes: 17 additions & 3 deletions tests/lib/Notification/ManagerTest.php
Original file line number Diff line number Diff line change
@@ -18,6 +18,7 @@
use OCP\IUserManager;
use OCP\Notification\IManager;
use OCP\Notification\INotification;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;
use OCP\Support\Subscription\IRegistry;
use PHPUnit\Framework\MockObject\MockObject;
@@ -28,8 +29,8 @@ class ManagerTest extends TestCase {
/** @var IManager */
protected $manager;

/** @var IValidator|MockObject */
protected $validator;
protected IValidator&MockObject $validator;
protected IRichTextFormatter&MockObject $richTextFormatter;
/** @var IUserManager|MockObject */
protected $userManager;
/** @var ICacheFactory|MockObject */
@@ -49,6 +50,7 @@ protected function setUp(): void {
parent::setUp();

$this->validator = $this->createMock(IValidator::class);
$this->richTextFormatter = $this->createMock(IRichTextFormatter::class);
$this->userManager = $this->createMock(IUserManager::class);
$this->cache = $this->createMock(ICache::class);
$this->subscriptionRegistry = $this->createMock(IRegistry::class);
@@ -64,7 +66,15 @@ protected function setUp(): void {
$this->coordinator->method('getRegistrationContext')
->willReturn($this->registrationContext);

$this->manager = new Manager($this->validator, $this->userManager, $this->cacheFactory, $this->subscriptionRegistry, $this->logger, $this->coordinator);
$this->manager = new Manager(
$this->validator,
$this->userManager,
$this->cacheFactory,
$this->subscriptionRegistry,
$this->logger,
$this->coordinator,
$this->richTextFormatter,
);
}

public function testRegisterApp(): void {
@@ -141,6 +151,7 @@ public function testNotify(): void {
$this->subscriptionRegistry,
$this->logger,
$this->coordinator,
$this->richTextFormatter,
])
->setMethods(['getApps'])
->getMock();
@@ -172,6 +183,7 @@ public function testNotifyInvalid(): void {
$this->subscriptionRegistry,
$this->logger,
$this->coordinator,
$this->richTextFormatter,
])
->setMethods(['getApps'])
->getMock();
@@ -196,6 +208,7 @@ public function testMarkProcessed(): void {
$this->subscriptionRegistry,
$this->logger,
$this->coordinator,
$this->richTextFormatter,
])
->setMethods(['getApps'])
->getMock();
@@ -221,6 +234,7 @@ public function testGetCount(): void {
$this->subscriptionRegistry,
$this->logger,
$this->coordinator,
$this->richTextFormatter,
])
->setMethods(['getApps'])
->getMock();
15 changes: 9 additions & 6 deletions tests/lib/Notification/NotificationTest.php
Original file line number Diff line number Diff line change
@@ -12,19 +12,22 @@
use OC\Notification\Notification;
use OCP\Notification\IAction;
use OCP\Notification\INotification;
use OCP\RichObjectStrings\IRichTextFormatter;
use OCP\RichObjectStrings\IValidator;
use PHPUnit\Framework\MockObject\MockObject;
use Test\TestCase;

class NotificationTest extends TestCase {
/** @var INotification */
protected $notification;
/** @var IValidator|\PHPUnit\Framework\MockObject\MockObject */
protected $validator;
protected IValidator&MockObject $validator;
protected IRichTextFormatter&MockObject $richTextFormatter;

protected function setUp(): void {
parent::setUp();
$this->validator = $this->createMock(IValidator::class);
$this->notification = new Notification($this->validator);
$this->richTextFormatter = $this->createMock(IRichTextFormatter::class);
$this->notification = new Notification($this->validator, $this->richTextFormatter);
}

protected function dataValidString($maxLength) {
@@ -529,7 +532,7 @@ public function testIsValid($isValidCommon, $subject, $expected): void {
'getSubject',
'getParsedSubject',
])
->setConstructorArgs([$this->validator])
->setConstructorArgs([$this->validator, $this->richTextFormatter])
->getMock();

$notification->expects($this->once())
@@ -562,7 +565,7 @@ public function testIsParsedValid($isValidCommon, $subject, $expected): void {
'getParsedSubject',
'getSubject',
])
->setConstructorArgs([$this->validator])
->setConstructorArgs([$this->validator, $this->richTextFormatter])
->getMock();

$notification->expects($this->once())
@@ -611,7 +614,7 @@ public function testIsValidCommon($app, $user, $timestamp, $objectType, $objectI
'getObjectType',
'getObjectId',
])
->setConstructorArgs([$this->validator])
->setConstructorArgs([$this->validator, $this->richTextFormatter])
->getMock();

$notification->expects($this->any())

Unchanged files with check annotations Beta

$this->logger->critical(
sprintf(
'$params["'.$element.'"] was missing. Transferred value: %s',
print_r($params, true)

Check failure on line 42 in apps/admin_audit/lib/Actions/Action.php

GitHub Actions / static-code-analysis-security

TaintedHtml

apps/admin_audit/lib/Actions/Action.php:42:16: TaintedHtml: Detected tainted HTML (see https://psalm.dev/245)
),
['app' => 'admin_audit']
);
if (!is_subclass_of($objectClass, IObjectStore::class)) {
throw new \InvalidArgumentException('Invalid object store');
}
$storage->setBackendOption('objectstore', new $objectClass($objectStore));

Check failure on line 51 in apps/files_external/lib/Config/ConfigAdapter.php

GitHub Actions / static-code-analysis-security

TaintedCallable

apps/files_external/lib/Config/ConfigAdapter.php:51:50: TaintedCallable: Detected tainted text (see https://psalm.dev/243)
}
$storage->getAuthMechanism()->manipulateStorageConfig($storage, $user);
case 'c':
case 'c+':
$context = stream_context_create(['sftp' => ['session' => $connection]]);
$handle = fopen($this->constructUrl($path), $mode, false, $context);

Check failure on line 384 in apps/files_external/lib/Lib/Storage/SFTP.php

GitHub Actions / static-code-analysis-security

TaintedFile

apps/files_external/lib/Lib/Storage/SFTP.php:384:22: TaintedFile: Detected tainted file handling (see https://psalm.dev/255)
return RetryWrapper::wrap($handle);
}
} catch (\Exception $e) {
&& !isset($downloadStartSecret[32])
&& preg_match('!^[a-zA-Z0-9]+$!', $downloadStartSecret) === 1) {
// FIXME: set on the response once we use an actual app framework response
setcookie('ocDownloadStarted', $downloadStartSecret, time() + 20, '/');

Check failure on line 431 in apps/files_sharing/lib/Controller/ShareController.php

GitHub Actions / static-code-analysis-security

TaintedCookie

apps/files_sharing/lib/Controller/ShareController.php:431:35: TaintedCookie: Detected tainted cookie (see https://psalm.dev/257)
}
$this->emitAccessShareHook($share);
$appIconContent = $appIcon->getContent();
$mime = $appIcon->getMimeType();
} else {
$appIconContent = file_get_contents($appIcon);

Check failure on line 116 in apps/theming/lib/IconBuilder.php

GitHub Actions / static-code-analysis-security

TaintedFile

apps/theming/lib/IconBuilder.php:116:40: TaintedFile: Detected tainted file handling (see https://psalm.dev/255)
$mime = mime_content_type($appIcon);
}
if ($imageFile === false || $imageFile === '') {
return false;
}
$svg = file_get_contents($imageFile);

Check failure on line 209 in apps/theming/lib/IconBuilder.php

GitHub Actions / static-code-analysis-security

TaintedFile

apps/theming/lib/IconBuilder.php:209:28: TaintedFile: Detected tainted file handling (see https://psalm.dev/255)
if ($svg !== false && $svg !== '') {
$color = $this->util->elementColor($this->themingDefaults->getColorPrimary());
$svg = $this->util->colorizeSvg($svg, $color);
// slash which is required by URL generation.
if (isset($_SERVER['REQUEST_URI']) && $_SERVER['REQUEST_URI'] === \OC::$WEBROOT &&
substr($_SERVER['REQUEST_URI'], -1) !== '/') {
header('Location: '.\OC::$WEBROOT.'/');

Check failure on line 144 in lib/base.php

GitHub Actions / static-code-analysis-security

TaintedHeader

lib/base.php:144:12: TaintedHeader: Detected tainted header (see https://psalm.dev/256)
exit();
}
}
throw new Exception('Not installed');
} else {
$url = OC::$WEBROOT . '/index.php';
header('Location: ' . $url);

Check failure on line 226 in lib/base.php

GitHub Actions / static-code-analysis-security

TaintedHeader

lib/base.php:226:12: TaintedHeader: Detected tainted header (see https://psalm.dev/256)
}
exit();
}
}
libxml_use_internal_errors(true);
$xml = simplexml_load_string(file_get_contents($file));

Check failure on line 38 in lib/private/App/InfoParser.php

GitHub Actions / static-code-analysis-security

TaintedFile

lib/private/App/InfoParser.php:38:50: TaintedFile: Detected tainted file handling (see https://psalm.dev/255)
if ($xml === false) {
libxml_clear_errors();
public function resolve($name) {
$baseMsg = 'Could not resolve ' . $name . '!';
try {
$class = new ReflectionClass($name);

Check failure on line 104 in lib/private/AppFramework/Utility/SimpleContainer.php

GitHub Actions / static-code-analysis-security

TaintedCallable

lib/private/AppFramework/Utility/SimpleContainer.php:104:33: TaintedCallable: Detected tainted text (see https://psalm.dev/243)
if ($class->isInstantiable()) {
return $this->buildClass($class);
} else {