Update files
This commit is contained in:
parent
aeae68b39e
commit
d85ebdfe01
|
|
@ -56,6 +56,10 @@ const PostSchema = new mongoose.Schema({
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
},
|
},
|
||||||
|
isArt: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
|
},
|
||||||
likes: [{
|
likes: [{
|
||||||
type: mongoose.Schema.Types.ObjectId,
|
type: mongoose.Schema.Types.ObjectId,
|
||||||
ref: 'User'
|
ref: 'User'
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,7 @@ const TicketActivitySchema = new mongoose.Schema({
|
||||||
type: mongoose.Schema.Types.Mixed,
|
type: mongoose.Schema.Types.Mixed,
|
||||||
default: {}
|
default: {}
|
||||||
},
|
},
|
||||||
|
artsModerated: { type: Number, default: 0 }, // Количество артов, прошедших модерацию
|
||||||
createdAt: {
|
createdAt: {
|
||||||
type: Date,
|
type: Date,
|
||||||
default: Date.now
|
default: Date.now
|
||||||
|
|
|
||||||
|
|
@ -173,6 +173,7 @@ router.get('/posts', authenticateModeration, requireModerationAccess, async (req
|
||||||
commentsCount: post.comments?.length || 0,
|
commentsCount: post.comments?.length || 0,
|
||||||
likesCount: post.likes?.length || 0,
|
likesCount: post.likes?.length || 0,
|
||||||
isNSFW: post.isNSFW,
|
isNSFW: post.isNSFW,
|
||||||
|
isArt: post.isArt,
|
||||||
publishedToChannel: post.publishedToChannel,
|
publishedToChannel: post.publishedToChannel,
|
||||||
adminNumber: post.adminNumber,
|
adminNumber: post.adminNumber,
|
||||||
editedAt: post.editedAt,
|
editedAt: post.editedAt,
|
||||||
|
|
@ -245,7 +246,7 @@ router.delete('/posts/:postId/comments/:commentId', authenticateModeration, requ
|
||||||
});
|
});
|
||||||
|
|
||||||
router.put('/posts/:id', authenticateModeration, requireModerationAccess, async (req, res) => {
|
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');
|
const post = await Post.findById(req.params.id).populate('author');
|
||||||
if (!post) {
|
if (!post) {
|
||||||
|
|
@ -285,6 +286,18 @@ router.put('/posts/:id', authenticateModeration, requireModerationAccess, async
|
||||||
post.isNSFW = !!isNSFW;
|
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();
|
post.editedAt = new Date();
|
||||||
await post.save();
|
await post.save();
|
||||||
|
|
||||||
|
|
@ -312,6 +325,7 @@ router.put('/posts/:id', authenticateModeration, requireModerationAccess, async
|
||||||
tags: post.tags,
|
tags: post.tags,
|
||||||
images: post.images,
|
images: post.images,
|
||||||
isNSFW: post.isNSFW,
|
isNSFW: post.isNSFW,
|
||||||
|
isArt: post.isArt,
|
||||||
publishedToChannel: post.publishedToChannel,
|
publishedToChannel: post.publishedToChannel,
|
||||||
adminNumber: post.adminNumber,
|
adminNumber: post.adminNumber,
|
||||||
editedAt: post.editedAt,
|
editedAt: post.editedAt,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
awardReferral,
|
||||||
awardArtLike,
|
awardArtLike,
|
||||||
awardArtComment,
|
awardArtComment,
|
||||||
|
awardArtModeration,
|
||||||
deductPostCreation,
|
deductPostCreation,
|
||||||
deductPostDeletion,
|
deductPostDeletion,
|
||||||
deductAction,
|
deductAction,
|
||||||
|
|
|
||||||
|
|
@ -422,6 +422,12 @@ export default function App() {
|
||||||
loadUsers();
|
loadUsers();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleToggleArt = async (post) => {
|
||||||
|
const newIsArt = !post.isArt;
|
||||||
|
await updatePost(post.id, { isArt: newIsArt });
|
||||||
|
loadPosts();
|
||||||
|
};
|
||||||
|
|
||||||
const handleOpenComments = async (postId) => {
|
const handleOpenComments = async (postId) => {
|
||||||
setCommentsLoading(true);
|
setCommentsLoading(true);
|
||||||
try {
|
try {
|
||||||
|
|
@ -631,6 +637,13 @@ export default function App() {
|
||||||
<Edit size={16} />
|
<Edit size={16} />
|
||||||
Редактировать
|
Редактировать
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className={`btn ${post.isArt ? 'active' : ''}`}
|
||||||
|
onClick={() => handleToggleArt(post)}
|
||||||
|
style={post.isArt ? { backgroundColor: '#4CAF50', color: 'white' } : {}}
|
||||||
|
>
|
||||||
|
🎨 Арт
|
||||||
|
</button>
|
||||||
<button className="btn danger" onClick={() => handlePostDelete(post.id)}>
|
<button className="btn danger" onClick={() => handlePostDelete(post.id)}>
|
||||||
<Trash2 size={16} />
|
<Trash2 size={16} />
|
||||||
Удалить
|
Удалить
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue