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
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
<?php

namespace wcf\action;

use Laminas\Diactoros\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
use wcf\command\article\AssignLabelsToArticles;
use wcf\data\article\Article;
use wcf\data\article\ArticleList;
use wcf\data\label\group\ViewableLabelGroup;
use wcf\http\Helper;
use wcf\system\exception\IllegalLinkException;
use wcf\system\exception\PermissionDeniedException;
use wcf\system\form\builder\field\label\LabelFormField;
use wcf\system\form\builder\Psr15DialogForm;
use wcf\system\WCF;

/**
* Shows the dialog for assigning labels to multiple articles.
*
* @author Marcel Werk
* @copyright 2001-2026 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @since 6.3
*/
final class ArticleBulkAssignLabelDialogAction implements RequestHandlerInterface
{
#[\Override]
public function handle(ServerRequestInterface $request): ResponseInterface
{
$parameters = Helper::mapQueryParameters(
$request->getQueryParams(),
<<<'EOT'
array {
ids: non-empty-list<positive-int>
}
EOT
);

$articleList = new ArticleList();
$articleList->setObjectIDs($parameters['ids']);
$articleList->readObjects();
if ($articleList->getObjects() === []) {
throw new IllegalLinkException();
}

$articles = \array_values(\array_filter(
$articleList->getObjects(),
static fn(Article $article): bool => $article->canEdit()
));
if ($articles === []) {
throw new PermissionDeniedException();
}

$labelGroups = $this->getCommonLabelGroups($articles);
if ($labelGroups === []) {
throw new IllegalLinkException();
}

$form = $this->getForm($labelGroups);

if ($request->getMethod() === 'GET') {
return $form->toResponse();
} elseif ($request->getMethod() === 'POST') {
$response = $form->validateRequest($request);
if ($response !== null) {
return $response;
}

new AssignLabelsToArticles(
$articles,
\array_keys($labelGroups),
$form->getData()['labelIDs'] ?? []
)();

return new JsonResponse([]);
} else {
throw new \LogicException('Unreachable');
}
}

/**
* Returns the label groups that are available in the categories of all given articles
* and that the active user is allowed to set.
*
* @param list<Article> $articles
* @return array<int, ViewableLabelGroup>
*/
private function getCommonLabelGroups(array $articles): array
{
$labelGroups = null;
foreach ($articles as $article) {
$categoryLabelGroups = $article->getCategory()?->getLabelGroups() ?? [];
$labelGroups = $labelGroups === null
? $categoryLabelGroups
: \array_intersect_key($labelGroups, $categoryLabelGroups);

if ($labelGroups === []) {
return [];
}
}

return \array_filter(
$labelGroups,
static fn(ViewableLabelGroup $labelGroup): bool => \count($labelGroup) !== 0
);
}

/**
* @param array<int, ViewableLabelGroup> $labelGroups
*/
private function getForm(array $labelGroups): Psr15DialogForm
{
$form = new Psr15DialogForm(
static::class,
WCF::getLanguage()->get('wcf.article.button.assignLabel')
);

foreach ($labelGroups as $labelGroup) {
$form->appendChild(
LabelFormField::create('labelIDs' . $labelGroup->groupID)
->objectProperty('labelIDs')
->objectType('com.woltlab.wcf.article')
->required($labelGroup->forceSelection !== 0)
->labelGroup($labelGroup)
);
}
$form->build();

return $form;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

namespace wcf\command\article;

use wcf\data\article\Article;
use wcf\data\article\ArticleBuilder;
use wcf\system\label\LabelHandler;

/**
* Assigns labels to articles. Existing labels of the given label groups are replaced.
*
* @author Marcel Werk
* @copyright 2001-2026 WoltLab GmbH
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
* @since 6.3
*/
final class AssignLabelsToArticles
{
/**
* @param list<Article> $articles
* @param list<int> $labelGroupIDs
* @param array<int, int> $labelIDs
*/
public function __construct(
private readonly array $articles,
private readonly array $labelGroupIDs,
private readonly array $labelIDs
) {}

public function __invoke(): void
{
if ($this->articles === [] || $this->labelGroupIDs === []) {
return;
}

$objectTypeID = LabelHandler::getInstance()->getObjectType('com.woltlab.wcf.article')->objectTypeID;
$articleIDs = [];
foreach ($this->articles as $article) {
$articleIDs[] = $article->articleID;
}

foreach ($this->articles as $article) {
LabelHandler::getInstance()->replaceLabels(
$this->labelGroupIDs,
$this->labelIDs,
'com.woltlab.wcf.article',
$article->articleID
);
}

// Do not validate permissions for the hasLabels flag.
$assignedLabels = LabelHandler::getInstance()->getAssignedLabels($objectTypeID, $articleIDs, false);

// update `hasLabels` flag
foreach ($this->articles as $article) {
ArticleBuilder::forUpdate($article)
->setHasLabels(($assignedLabels[$article->articleID] ?? []) !== [])
->update();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace wcf\system\interaction\bulk\admin;

use wcf\acp\action\ArticleCategoryAction;
use wcf\action\ArticleBulkAssignLabelDialogAction;
use wcf\data\article\AccessibleArticleList;
use wcf\data\article\Article;
use wcf\event\interaction\bulk\admin\ArticleBulkInteractionCollecting;
Expand Down Expand Up @@ -121,7 +122,19 @@ function (Article $article): bool {
'setCategory',
ArticleCategoryAction::class,
'wcf.article.button.setCategory'
)
),
new BulkFormBuilderDialogInteraction(
'assign-label',
ArticleBulkAssignLabelDialogAction::class,
'wcf.article.button.assignLabel',
static function (Article $article): bool {
if (!$article->canEdit()) {
return false;
}

return ($article->getCategory()?->getLabelGroups() ?? []) !== [];
}
),
]);

EventHandler::getInstance()->fire(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

namespace wcf\system\interaction\bulk\user;

use wcf\action\ArticleBulkAssignLabelDialogAction;
use wcf\data\article\AccessibleArticleList;
use wcf\data\article\Article;
use wcf\event\interaction\bulk\user\ArticleBulkInteractionCollecting;
use wcf\system\event\EventHandler;
use wcf\system\interaction\bulk\AbstractBulkInteractionProvider;
use wcf\system\interaction\bulk\BulkDeleteInteraction;
use wcf\system\interaction\bulk\BulkFormBuilderDialogInteraction;
use wcf\system\interaction\bulk\BulkRestoreInteraction;
use wcf\system\interaction\bulk\BulkRpcInteraction;
use wcf\system\interaction\bulk\BulkSoftDeleteInteraction;
Expand Down Expand Up @@ -113,6 +115,18 @@ function (Article $article): bool {
return $article->isFeatured !== 0;
}
),
new BulkFormBuilderDialogInteraction(
'assign-label',
ArticleBulkAssignLabelDialogAction::class,
'wcf.article.button.assignLabel',
static function (Article $article): bool {
if (!$article->canEdit()) {
return false;
}

return ($article->getCategory()?->getLabelGroups() ?? []) !== [];
}
),
]
);
}
Expand Down
1 change: 1 addition & 0 deletions wcfsetup/install/lang/de.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3319,6 +3319,7 @@ freigeschaltet. {if LANGUAGE_USE_INFORMAL_VARIANT}Du kannst{else}Sie können{/if
<item name="wcf.article.button.unsetAsFeatured"><![CDATA[„Empfohlen“-Markierung entfernen]]></item>
<item name="wcf.article.featured"><![CDATA[Empfohlen]]></item>
<item name="wcf.article.condition.isFeatured"><![CDATA[Nur empfohlene Artikel]]></item>
<item name="wcf.article.button.assignLabel"><![CDATA[Label zuweisen]]></item>
<item name="wcf.article.unreadArticles"><![CDATA[Ungelesene Artikel]]></item>
<item name="wcf.article.userArticles"><![CDATA[Artikel von {$user->username}]]></item>
<item name="wcf.article.watchedArticles"><![CDATA[Abonnierte Artikel]]></item>
Expand Down
1 change: 1 addition & 0 deletions wcfsetup/install/lang/en.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3244,6 +3244,7 @@ Your account on {@PAGE_TITLE|phrase} [URL:{link isEmail=true}{/link}] has been a
<item name="wcf.article.button.unsetAsFeatured"><![CDATA[Remove Featured Marking]]></item>
<item name="wcf.article.featured"><![CDATA[Featured]]></item>
<item name="wcf.article.condition.isFeatured"><![CDATA[Featured articles only]]></item>
<item name="wcf.article.button.assignLabel"><![CDATA[Assign Labels]]></item>
<item name="wcf.article.unreadArticles"><![CDATA[Unread Articles]]></item>
<item name="wcf.article.userArticles"><![CDATA[Articles by {$user->username}]]></item>
<item name="wcf.article.watchedArticles"><![CDATA[Subscribed Articles]]></item>
Expand Down
Loading