feat(Moderation): enhance moderation reporting and user feedback
All checks were successful
Deploy to production / deploy (push) Successful in 1m55s

- Added user blocking checks in authentication and reporting processes, returning appropriate error responses.
- Expanded moderation report functionality to include new target types and optional fields for reports.
- Implemented a new API endpoint to retrieve the count of open moderation reports.
- Enhanced frontend components to allow users to report profiles, images, and guestbook entries, with corresponding UI updates.
- Updated internationalization files to include new strings for reporting features in both German and English.
This commit is contained in:
Torsten Schulz (local)
2026-04-27 15:57:02 +02:00
parent e94ae4350d
commit 530855e26e
16 changed files with 417 additions and 20 deletions

View File

@@ -48,7 +48,17 @@
:style="`background-image:url('/images/icons/${subitem.icon}')`"
class="submenu-icon"
>&nbsp;</span>
<span>{{ subitem?.label || $t(`navigation.m-${key}.${subkey}`) }}</span>
<span class="submenu-label-row">
<span>{{ subitem?.label || $t(`navigation.m-${key}.${subkey}`) }}</span>
<span
v-if="key === 'administration' && subkey === 'moderationReports' && moderationOpenCount > 0"
class="moderation-alert-badge"
:title="$t('navigation.m-administration.moderationBadgeTitle')"
>
<span class="moderation-alert-icon"></span>
<span class="moderation-alert-count">{{ moderationOpenCount }}</span>
</span>
</span>
<span v-if="subitem.disabled" class="menu-lock-badge">18+</span>
<span
v-if="hasSecondLevelSubmenu(subitem, subkey)"
@@ -203,7 +213,10 @@ export default {
_forumsChangedHandler: null,
_friendLoginChangedHandler: null,
_reloadMenuHandler: null,
_adultVerificationChangedHandler: null
_adultVerificationChangedHandler: null,
_moderationReportChangedHandler: null,
_userAccessChangedHandler: null,
moderationOpenCount: 0
};
},
computed: {
@@ -213,6 +226,12 @@ export default {
menuNeedsUpdate(newVal) {
if (newVal) this.loadMenu();
},
menu: {
deep: true,
handler() {
this.fetchModerationOpenCount();
}
},
$route() {
this.collapseMenus();
},
@@ -229,6 +248,7 @@ export default {
this.fetchForums();
this.fetchFriends();
this.fetchVocabLanguages();
this.fetchModerationOpenCount();
}
this.updateViewportState();
window.addEventListener('resize', this.updateViewportState);
@@ -263,10 +283,25 @@ export default {
showInfo(this, this.$t('socialnetwork.erotic.notifications.rejected'));
}
};
this._moderationReportChangedHandler = async (payload = {}) => {
if (Number.isFinite(Number(payload.openCount))) {
this.moderationOpenCount = Number(payload.openCount);
return;
}
await this.fetchModerationOpenCount();
};
this._userAccessChangedHandler = async (payload = {}) => {
if (payload.active === false) {
this.$root?.$refs?.messageDialog?.open?.('Dein Account wurde gesperrt.');
await this.logout();
}
};
sock.on('forumschanged', this._forumsChangedHandler);
sock.on('friendloginchanged', this._friendLoginChangedHandler);
sock.on('reloadmenu', this._reloadMenuHandler);
sock.on('adultVerificationChanged', this._adultVerificationChangedHandler);
sock.on('moderationReportChanged', this._moderationReportChangedHandler);
sock.on('userAccessChanged', this._userAccessChangedHandler);
},
unregisterSocketListeners() {
@@ -276,10 +311,14 @@ export default {
if (this._friendLoginChangedHandler) sock.off('friendloginchanged', this._friendLoginChangedHandler);
if (this._reloadMenuHandler) sock.off('reloadmenu', this._reloadMenuHandler);
if (this._adultVerificationChangedHandler) sock.off('adultVerificationChanged', this._adultVerificationChangedHandler);
if (this._moderationReportChangedHandler) sock.off('moderationReportChanged', this._moderationReportChangedHandler);
if (this._userAccessChangedHandler) sock.off('userAccessChanged', this._userAccessChangedHandler);
this._forumsChangedHandler = null;
this._friendLoginChangedHandler = null;
this._reloadMenuHandler = null;
this._adultVerificationChangedHandler = null;
this._moderationReportChangedHandler = null;
this._userAccessChangedHandler = null;
},
updateViewportState() {
@@ -461,6 +500,19 @@ export default {
this.vocabLanguagesList = [];
}
},
async fetchModerationOpenCount() {
try {
const adminChildren = this.menu?.administration?.children || {};
if (!adminChildren.moderationReports) {
this.moderationOpenCount = 0;
return;
}
const res = await apiClient.get('/api/admin/moderation/reports/open-count');
this.moderationOpenCount = Number(res?.data?.openCount || 0);
} catch (_) {
this.moderationOpenCount = 0;
}
},
openForum(forumId) {
this.$router.push({ name: 'Forum', params: { id: forumId } });
@@ -800,6 +852,29 @@ a {
border-radius: 14px;
}
.submenu-label-row {
display: inline-flex;
align-items: center;
gap: 8px;
}
.moderation-alert-badge {
display: inline-flex;
align-items: center;
gap: 4px;
background: #d32f2f;
color: #fff;
border-radius: 999px;
padding: 2px 7px;
font-weight: 800;
font-size: 0.72rem;
line-height: 1;
}
.moderation-alert-icon {
font-size: 0.78rem;
}
.submenu1 > li:hover {
color: var(--color-text-primary);
background-color: rgba(248, 162, 43, 0.12);