feat(Moderation): implement moderation reports feature
All checks were successful
Deploy to production / deploy (push) Successful in 2m1s

- Added moderationRouter to handle moderation-related API routes.
- Introduced new methods in AdminController for fetching all regions, region types, and creating regions.
- Enhanced adminRouter with routes for moderation reports and status updates.
- Updated navigationController to include moderation reports in the admin menu.
- Implemented frontend components for reporting messages in the forum and managing moderation reports.
- Added internationalization support for moderation-related texts in multiple languages.
This commit is contained in:
Torsten Schulz (local)
2026-04-27 14:52:19 +02:00
parent 7fc9b55b59
commit a02fe1f008
36 changed files with 1162 additions and 17 deletions

View File

@@ -13,8 +13,13 @@
<li v-for="message in messages" :key="message.id" class="surface-card">
<div v-html="sanitizedMessage(message)"></div>
<div class="footer">
<span class="link" @click="openProfile(message.lastMessageUser.hashedId)">
{{ message.lastMessageUser.username }}
<span class="footer-left">
<span class="link" @click="openProfile(message.lastMessageUser.hashedId)">
{{ message.lastMessageUser.username }}
</span>
<button type="button" class="report-btn" @click="reportMessage(message)">
{{ $t('socialnetwork.forum.reportAction') }}
</button>
</span>
<span>{{ new Date(message.createdAt).toLocaleString() }}</span>
</div>
@@ -103,6 +108,36 @@ export default {
},
sanitizedMessage(message) {
return DOMPurify.sanitize(message.text);
},
async reportMessage(message) {
const reason = window.prompt(this.$t('socialnetwork.forum.reportPrompt'));
if (reason == null) return;
const trimmed = String(reason || '').trim();
if (trimmed.length < 3) {
this.$root.$refs.messageDialog?.open(
this.$t('socialnetwork.forum.reportReasonTooShort'),
this.$t('error.title')
);
return;
}
try {
await apiClient.post('/api/moderation/reports', {
targetType: 'forum_message',
targetId: message.id,
reason: trimmed,
details: '',
});
this.$root.$refs.messageDialog?.open(
this.$t('socialnetwork.forum.reportSubmitted'),
this.$t('message.title')
);
} catch (error) {
console.error('Error creating moderation report:', error);
this.$root.$refs.messageDialog?.open(
this.$t('socialnetwork.forum.reportError'),
this.$t('error.title')
);
}
}
}
}
@@ -145,16 +180,29 @@ export default {
font-size: 0.8em;
margin-top: 0.5em;
display: flex;
align-items: center;
gap: 8px;
}
.messages > li > .footer > span:first-child {
.footer-left {
flex: 1;
display: inline-flex;
align-items: center;
gap: 10px;
}
.messages > li > .footer > span:last-child {
text-align: right;
}
.report-btn {
min-height: auto;
padding: 2px 8px;
font-size: 0.75rem;
border-radius: 999px;
background: rgba(255, 255, 255, 0.78);
}
.editor-container {
margin-top: 1rem;
padding: 0;