From d85ebdfe01d768b78f62e59d21adc17c00e4a4b4 Mon Sep 17 00:00:00 2001 From: glpshchn <464976@niuitmo.ru> Date: Sun, 7 Dec 2025 06:14:27 +0300 Subject: [PATCH] Update files --- backend/models/Post.js | 4 +++ backend/models/TicketActivity.js | 1 + backend/routes/modApp.js | 16 +++++++++- backend/utils/tickets.js | 50 ++++++++++++++++++++++++++++++++ moderation/frontend/src/App.jsx | 13 +++++++++ 5 files changed, 83 insertions(+), 1 deletion(-) diff --git a/backend/models/Post.js b/backend/models/Post.js index bbf42df..4c64452 100644 --- a/backend/models/Post.js +++ b/backend/models/Post.js @@ -56,6 +56,10 @@ const PostSchema = new mongoose.Schema({ type: Boolean, default: false }, + isArt: { + type: Boolean, + default: false + }, likes: [{ type: mongoose.Schema.Types.ObjectId, ref: 'User' diff --git a/backend/models/TicketActivity.js b/backend/models/TicketActivity.js index 99c1340..74b20c4 100644 --- a/backend/models/TicketActivity.js +++ b/backend/models/TicketActivity.js @@ -43,6 +43,7 @@ const TicketActivitySchema = new mongoose.Schema({ type: mongoose.Schema.Types.Mixed, default: {} }, + artsModerated: { type: Number, default: 0 }, // Количество артов, прошедших модерацию createdAt: { type: Date, default: Date.now diff --git a/backend/routes/modApp.js b/backend/routes/modApp.js index 4b6ca51..3c6fa50 100644 --- a/backend/routes/modApp.js +++ b/backend/routes/modApp.js @@ -173,6 +173,7 @@ router.get('/posts', authenticateModeration, requireModerationAccess, async (req commentsCount: post.comments?.length || 0, likesCount: post.likes?.length || 0, isNSFW: post.isNSFW, + isArt: post.isArt, publishedToChannel: post.publishedToChannel, adminNumber: post.adminNumber, editedAt: post.editedAt, @@ -245,7 +246,7 @@ router.delete('/posts/:postId/comments/:commentId', authenticateModeration, requ }); router.put('/posts/:id', authenticateModeration, requireModerationAccess, async (req, res) => { - const { content, hashtags, tags, isNSFW } = req.body; + const { content, hashtags, tags, isNSFW, isArt } = req.body; const post = await Post.findById(req.params.id).populate('author'); if (!post) { @@ -285,6 +286,18 @@ router.put('/posts/:id', authenticateModeration, requireModerationAccess, async post.isNSFW = !!isNSFW; } + // Обработка метки "арт" + const wasArt = post.isArt || false; + if (isArt !== undefined) { + post.isArt = !!isArt; + + // Если арт только что помечен (было false, стало true), начислить билеты + if (!wasArt && post.isArt && post.author) { + const { awardArtModeration } = require('../utils/tickets'); + await awardArtModeration(post.author._id); + } + } + post.editedAt = new Date(); await post.save(); @@ -312,6 +325,7 @@ router.put('/posts/:id', authenticateModeration, requireModerationAccess, async tags: post.tags, images: post.images, isNSFW: post.isNSFW, + isArt: post.isArt, publishedToChannel: post.publishedToChannel, adminNumber: post.adminNumber, editedAt: post.editedAt, diff --git a/backend/utils/tickets.js b/backend/utils/tickets.js index 1e132c0..3b02e25 100644 --- a/backend/utils/tickets.js +++ b/backend/utils/tickets.js @@ -205,6 +205,55 @@ async function awardArtComment(authorId, commenterId, postId) { }); } +/** + * Начисляет билеты за арт, прошедший модерацию + */ +async function awardArtModeration(userId) { + // Проверяем лимиты: 1 арт в день / 5 в неделю + const { getMoscowStartOfDay } = require('./moscowTime'); + const today = getMoscowStartOfDay(); + const weekAgo = new Date(today.getTime() - 7 * 24 * 60 * 60 * 1000); + + const activity = await TicketActivity.getOrCreateToday(userId); + + // Проверка лимита: 1 арт в день + const todayArts = activity.artsModerated || 0; + if (todayArts >= 1) { + console.log(`[Tickets ${formatMoscowTime()}] Лимит артов на сегодня достигнут для пользователя ${userId}`); + return { success: false, reason: 'daily_limit_reached' }; + } + + // Проверка лимита: 5 артов в неделю + const TicketActivityModel = require('../models/TicketActivity'); + const weekActivities = await TicketActivityModel.find({ + user: userId, + date: { $gte: weekAgo } + }); + + const weekArtsCount = weekActivities.reduce((sum, act) => { + return sum + (act.artsModerated || 0); + }, 0); + + if (weekArtsCount >= 5) { + console.log(`[Tickets ${formatMoscowTime()}] Лимит артов на неделю достигнут для пользователя ${userId}`); + return { success: false, reason: 'weekly_limit_reached' }; + } + + // Начислить билеты + if (!activity.artsModerated) { + activity.artsModerated = 0; + } + activity.artsModerated += 1; + await activity.save(); + + await User.findByIdAndUpdate(userId, { + $inc: { tickets: 40 } + }); + + console.log(`[Tickets ${formatMoscowTime()}] Начислено 40 билетов пользователю ${userId} за арт, прошедший модерацию`); + return { success: true, points: 40 }; +} + /** * Списывает билеты за действие (лайк/комментарий) с удаленным постом */ @@ -373,6 +422,7 @@ module.exports = { awardReferral, awardArtLike, awardArtComment, + awardArtModeration, deductPostCreation, deductPostDeletion, deductAction, diff --git a/moderation/frontend/src/App.jsx b/moderation/frontend/src/App.jsx index 00d7315..e2be27d 100644 --- a/moderation/frontend/src/App.jsx +++ b/moderation/frontend/src/App.jsx @@ -422,6 +422,12 @@ export default function App() { loadUsers(); }; + const handleToggleArt = async (post) => { + const newIsArt = !post.isArt; + await updatePost(post.id, { isArt: newIsArt }); + loadPosts(); + }; + const handleOpenComments = async (postId) => { setCommentsLoading(true); try { @@ -631,6 +637,13 @@ export default function App() { Редактировать +