Skip to content

Commit 84269cd

Browse files
Cyperghostdtdesign
andauthored
Commands/endpoints for moderation-related actions (#6418)
* Implement command and endpoint to mark a moderation queue or all as read * Do not use the clipboard for moderation entries anymore. This has already been removed for moderation entries. * Implement command to mark a moderation queue entry as done * Implement API Endpoint to retrieve the user menu items for moderation queue items * Mark the `ModerationQueue…Action` methods as deprecated that have already been migrated to an API endpoint. * Use `StandaloneInteractionContextMenuComponent` to show actions for moderation queue entries * Use form builder to report content * Remove unused type `ResponseGetData` * Make members private * Fix a few inconsistencies * Improve the naming of classes and functions * Improves comments, fix class naming * Settle on a naming scheme for endpoints and commands * Mark the specialized DBOActions as deprecated Those only existed as a helper for the legacy AJAX API and all their methods have been deprecated. The `ModerationQueueAction` itself is not deprecated. * Use a `NamedUserException` to handle custom validation errors * Unify the naming of the RPC calls These are now in sync with the PHP implementation. * Fix a refactoring issue * Remove JS artifacts of deleted files --------- Co-authored-by: Alexander Ebert <[email protected]>
1 parent e3cf697 commit 84269cd

File tree

54 files changed

+879
-1200
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+879
-1200
lines changed

com.woltlab.wcf/templates/headIncludeJavaScript.tpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ window.addEventListener('pageshow', function(event) {
107107
{foreach from=$__wcf->getMessageQuoteManager()->getUsedQuotes() key=editorID item=uuids}['{unsafe:$editorID|encodeJS}', [{implode from=$uuids item=uuid}'{unsafe:$uuid|encodeJS}'{/implode}]]{/foreach}
108108
]),
109109
{/if}
110+
reportEndpoint: '{link controller="Report"}{/link}',
110111
});
111112
});
112113
</script>

com.woltlab.wcf/templates/moderationActivation.tpl

Lines changed: 4 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,7 @@
22

33
{capture assign='contentHeader'}
44
<header class="contentHeader">
5-
<div class="contentHeaderTitle">
6-
<h1 class="contentTitle">{$__wcf->getActivePage()->getTitle()}: {$queue->getTitle()}</h1>
7-
<ul class="inlineList contentHeaderMetaData">
8-
{event name='beforeMetaData'}
9-
10-
{if $queue->lastChangeTime}
11-
<li title="{lang}wcf.moderation.lastChangeTime{/lang}">
12-
{icon name='clock'}
13-
{time time=$queue->lastChangeTime}
14-
</li>
15-
{/if}
16-
17-
<li title="{lang}wcf.moderation.assignedUser{/lang}">
18-
{icon name='user'}
19-
<span id="moderationAssignedUser">
20-
{if $queue->assignedUserID}
21-
<a href="{link controller='User' id=$assignedUserID}{/link}" class="userLink" data-object-id="{$assignedUserID}">{$queue->assignedUsername}</a>
22-
{else}
23-
{lang}wcf.moderation.assignedUser.nobody{/lang}
24-
{/if}
25-
</span>
26-
</li>
27-
28-
<li title="{lang}wcf.moderation.status{/lang}">
29-
{icon name='arrows-rotate'}
30-
<span id="moderationQueueStatus">{$queue->getStatus()}</span>
31-
</li>
32-
33-
{event name='afterMetaData'}
34-
</ul>
35-
</div>
5+
{include file='moderationContentHeader' title=$__wcf->getActivePage()->getTitle() queue=$queue sandbox=true}
366

377
{hascontent}
388
<nav class="contentHeaderNavigation">
@@ -48,40 +18,9 @@
4818
{/capture}
4919

5020
{capture assign='contentInteractionButtons'}
51-
<button
52-
type="button"
53-
id="moderationAssignUser"
54-
class="contentInteractionButton button small jsOnly"
55-
data-url="{$queue->endpointAssignUser()}"
56-
>
57-
{icon name='user-plus' type='solid'}
58-
<span>{lang}wcf.moderation.assignedUser.change{/lang}</span>
59-
</button>
60-
{if !$queue->isDone()}
61-
<button
62-
type="button"
63-
id="enableContent"
64-
class="contentInteractionButton button small jsOnly"
65-
data-object-id="{$queue->queueID}"
66-
data-redirect-url="{link controller='ModerationList'}{/link}"
67-
>
68-
{icon name='check'}
69-
<span>{lang}wcf.moderation.activation.enableContent{/lang}</span>
70-
</button>
71-
{if $queueManager->canRemoveContent($queue->getDecoratedObject())}
72-
<button
73-
type="button"
74-
id="removeContent"
75-
class="contentInteractionButton button small jsOnly"
76-
data-object-id="{$queue->queueID}"
77-
data-object-name="{$queue->getTitle()}"
78-
data-redirect-url="{link controller='ModerationList'}{/link}"
79-
>
80-
{icon name='xmark'}
81-
<span>{lang}wcf.moderation.activation.removeContent{/lang}</span>
82-
</button>
83-
{/if}
84-
{/if}
21+
<div class="contentInteractionButton">
22+
{unsafe:$interactionContextMenu->render()}
23+
</div>
8524
{/capture}
8625

8726
{include file='header'}
@@ -106,23 +45,4 @@
10645
{include file='comments' commentContainerID='moderationQueueCommentList' commentObjectID=$queueID}
10746
</section>
10847

109-
<script data-relocate="true">
110-
require(['WoltLabSuite/Core/Controller/Moderation/AssignUser'], ({ setup }) => {
111-
{jsphrase name='wcf.moderation.assignedUser.nobody'}
112-
113-
setup(document.getElementById('moderationAssignUser'));
114-
});
115-
116-
{if !$queue->isDone()}
117-
require(['WoltLabSuite/Core/Controller/Moderation/Activation'], ({ setup }) => {
118-
{jsphrase name='wcf.moderation.activation.enableContent.confirmMessage'}
119-
120-
setup(
121-
document.getElementById('enableContent'),
122-
document.getElementById('removeContent'),
123-
);
124-
});
125-
{/if}
126-
</script>
127-
12848
{include file='footer'}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<div class="contentHeaderTitle">
2+
<h1 class="contentTitle">{$title}: {$queue->getTitle()}</h1>
3+
<ul class="inlineList contentHeaderMetaData">
4+
{event name='beforeMetaData'}
5+
6+
{if $queue->lastChangeTime}
7+
<li title="{lang}wcf.moderation.lastChangeTime{/lang}">
8+
{icon name='clock'}
9+
{time time=$queue->lastChangeTime}
10+
</li>
11+
{/if}
12+
13+
<li title="{lang}wcf.moderation.assignedUser{/lang}">
14+
{icon name='user'}
15+
{if $queue->assignedUserID}
16+
<a href="{link controller='User' id=$queue->assignedUserID}{/link}" class="userLink" data-object-id="{$queue->assignedUserID}">{$queue->assignedUsername}</a>
17+
{else}
18+
{lang}wcf.moderation.assignedUser.nobody{/lang}
19+
{/if}
20+
</li>
21+
22+
<li title="{lang}wcf.moderation.status{/lang}">
23+
{icon name='arrows-rotate'}
24+
{$queue->getStatus()}
25+
</li>
26+
27+
{event name='afterMetaData'}
28+
</ul>
29+
</div>

com.woltlab.wcf/templates/moderationReport.tpl

Lines changed: 4 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,7 @@
22

33
{capture assign='contentHeader'}
44
<header class="contentHeader">
5-
<div class="contentHeaderTitle">
6-
<h1 class="contentTitle">{$__wcf->getActivePage()->getTitle()}: {$queue->getTitle()}</h1>
7-
<ul class="inlineList contentHeaderMetaData">
8-
{event name='beforeMetaData'}
9-
10-
{if $queue->lastChangeTime}
11-
<li title="{lang}wcf.moderation.lastChangeTime{/lang}">
12-
{icon name='clock'}
13-
{time time=$queue->lastChangeTime}
14-
</li>
15-
{/if}
16-
17-
<li title="{lang}wcf.moderation.assignedUser{/lang}">
18-
{icon name='user'}
19-
<span id="moderationAssignedUser">
20-
{if $queue->assignedUserID}
21-
<a href="{link controller='User' id=$assignedUserID}{/link}" class="userLink" data-object-id="{$assignedUserID}">{$queue->assignedUsername}</a>
22-
{else}
23-
{lang}wcf.moderation.assignedUser.nobody{/lang}
24-
{/if}
25-
</span>
26-
</li>
27-
28-
<li title="{lang}wcf.moderation.status{/lang}">
29-
{icon name='arrows-rotate'}
30-
<span id="moderationQueueStatus">{$queue->getStatus()}</span>
31-
</li>
32-
33-
{event name='afterMetaData'}
34-
</ul>
35-
</div>
5+
{include file='moderationContentHeader' title=$__wcf->getActivePage()->getTitle() queue=$queue sandbox=true}
366

377
{hascontent}
388
<nav class="contentHeaderNavigation">
@@ -48,44 +18,9 @@
4818
{/capture}
4919

5020
{capture assign='contentInteractionButtons'}
51-
<button
52-
type="button"
53-
id="moderationAssignUser"
54-
class="contentInteractionButton button small jsOnly"
55-
data-url="{$queue->endpointAssignUser()}"
56-
>
57-
{icon name='user-plus' type='solid'}
58-
<span>{lang}wcf.moderation.assignedUser.change{/lang}</span>
59-
</button>
60-
{if !$queue->isDone()}
61-
{if $queueManager->canRemoveContent($queue->getDecoratedObject())}
62-
<button
63-
type="button"
64-
id="removeContent"
65-
class="contentInteractionButton button small jsOnly"
66-
data-object-id="{$queue->queueID}"
67-
data-object-name="{$queue->getTitle()}"
68-
data-redirect-url="{link controller='ModerationList'}{/link}"
69-
>{icon name='xmark'} <span>{lang}wcf.moderation.activation.removeContent{/lang}</span></button>
70-
{/if}
71-
<button
72-
type="button"
73-
id="removeReport"
74-
class="contentInteractionButton button small jsOnly"
75-
data-object-id="{$queue->queueID}"
76-
data-redirect-url="{link controller='ModerationList'}{/link}"
77-
>{icon name='square-check'} <span>{lang}wcf.moderation.report.removeReport{/lang}</span></button>
78-
{/if}
79-
{if $queue->canChangeJustifiedStatus()}
80-
<button
81-
type="button"
82-
id="changeJustifiedStatus"
83-
class="contentInteractionButton button small jsOnly"
84-
data-object-id="{$queue->queueID}"
85-
data-redirect-url="{link controller='ModerationReport' object=$queue}{/link}"
86-
data-justified="{if $queue->markAsJustified}true{else}false{/if}"
87-
>{icon name='arrows-rotate'} <span>{lang}wcf.moderation.report.changeJustifiedStatus{/lang}</span></button>
88-
{/if}
21+
<div class="contentInteractionButton">
22+
{unsafe:$interactionContextMenu->render()}
23+
</div>
8924
{/capture}
9025

9126
{include file='header'}
@@ -133,25 +68,4 @@
13368
{include file='comments' commentContainerID='moderationQueueCommentList' commentObjectID=$queueID}
13469
</section>
13570

136-
<script data-relocate="true">
137-
require(['WoltLabSuite/Core/Controller/Moderation/AssignUser'], ({ setup }) => {
138-
{jsphrase name='wcf.moderation.assignedUser.nobody'}
139-
140-
setup(document.getElementById('moderationAssignUser'));
141-
});
142-
143-
require(['WoltLabSuite/Core/Controller/Moderation/Report'], ({ setup }) => {
144-
{jsphrase name='wcf.moderation.report.removeReport.confirmMessage'}
145-
{jsphrase name='wcf.moderation.report.removeReport.markAsJustified'}
146-
{jsphrase name='wcf.moderation.report.changeJustifiedStatus.confirmMessage'}
147-
{jsphrase name='wcf.moderation.report.changeJustifiedStatus.markAsJustified'}
148-
149-
setup(
150-
document.getElementById('removeContent'),
151-
document.getElementById('removeReport'),
152-
document.getElementById('changeJustifiedStatus')
153-
);
154-
});
155-
</script>
156-
15771
{include file='footer'}

phpstan-baseline.neon

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
parameters:
22
ignoreErrors:
3-
-
4-
message: '#^Variable \$this might not be defined\.$#'
5-
identifier: variable.undefined
6-
count: 1
7-
path: wcfsetup/install/files/acp/update_com.woltlab.wcf_6.1_spider_step1.php
8-
93
-
104
message: '#^Property wcf\\acp\\form\\AbstractCategoryAddForm\:\:\$categoryNodeTree \(wcf\\data\\category\\UncachedCategoryNodeTree\) does not accept wcf\\data\\category\\CategoryNodeTree\.$#'
115
identifier: assign.propertyType

ts/WoltLabSuite/Core/Api/ModerationQueues/DeleteContent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Deletes the content associated with a moderation queue entry.
2+
* Deletes the content associated with a moderation queue.
33
*
44
* @author Marcel Werk
55
* @copyright 2001-2024 WoltLab GmbH

ts/WoltLabSuite/Core/Api/ModerationQueues/EnableContent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Enables the content associated with a moderation queue entry.
2+
* Enables the content associated with a moderation queue.
33
*
44
* @author Marcel Werk
55
* @copyright 2001-2024 WoltLab GmbH
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/**
2+
* Retrieves the user menu items for the moderation queues.
3+
*
4+
* @author Olaf Braun
5+
* @copyright 2001-2025 WoltLab GmbH
6+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7+
* @since 6.3
8+
* @woltlabExcludeBundle tiny
9+
*/
10+
11+
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
12+
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
13+
import { UserMenuData } from "WoltLabSuite/Core/Ui/User/Menu/Data/Provider";
14+
15+
type Response = {
16+
unreadModerationCount: number;
17+
items: UserMenuData[];
18+
};
19+
20+
export async function getUserMenuItems(): Promise<ApiResult<Response>> {
21+
let response: Response;
22+
23+
try {
24+
response = (await prepareRequest(`${window.WSC_RPC_API_URL}core/moderation-queues/user-menu-items`)
25+
.get()
26+
.fetchAsJson()) as Response;
27+
} catch (e) {
28+
return apiResultFromError(e);
29+
}
30+
31+
return apiResultFromValue(response);
32+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
/**
2+
* Marks all moderation queues as read.
3+
*
4+
* @author Olaf Braun
5+
* @copyright 2001-2025 WoltLab GmbH
6+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7+
* @since 6.3
8+
* @woltlabExcludeBundle tiny
9+
*/
10+
11+
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
12+
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
13+
14+
export async function markAllModerationQueuesAsRead(): Promise<ApiResult<[]>> {
15+
try {
16+
await prepareRequest(`${window.WSC_RPC_API_URL}core/moderation-queues/mark-all-as-read`).post().fetchAsJson();
17+
} catch (e) {
18+
return apiResultFromError(e);
19+
}
20+
21+
return apiResultFromValue([]);
22+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* Marks a moderation queue as read.
3+
*
4+
* @author Olaf Braun
5+
* @copyright 2001-2025 WoltLab GmbH
6+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7+
* @since 6.3
8+
* @woltlabExcludeBundle tiny
9+
*/
10+
11+
import { prepareRequest } from "WoltLabSuite/Core/Ajax/Backend";
12+
import { ApiResult, apiResultFromError, apiResultFromValue } from "../Result";
13+
14+
type Response = {
15+
unreadModerationItems: number;
16+
};
17+
18+
export async function markModerationQueueAsRead(queueId: number): Promise<ApiResult<Response>> {
19+
let response: Response;
20+
21+
try {
22+
response = (await prepareRequest(`${window.WSC_RPC_API_URL}core/moderation-queues/${queueId}/mark-as-read`)
23+
.post()
24+
.fetchAsJson()) as Response;
25+
} catch (e) {
26+
return apiResultFromError(e);
27+
}
28+
29+
return apiResultFromValue(response);
30+
}

0 commit comments

Comments
 (0)