Update files
This commit is contained in:
parent
ca7c508e57
commit
d0ae307cd8
|
|
@ -257,43 +257,49 @@ const authenticate = async (req, res, next) => {
|
|||
user.loginDates = [];
|
||||
}
|
||||
|
||||
const { getMoscowStartOfDay, getMoscowDate } = require('../utils/moscowTime');
|
||||
const today = getMoscowDate();
|
||||
const todayTime = today.getTime();
|
||||
|
||||
// Получить уникальные даты из существующего массива (только даты, без времени по московскому времени)
|
||||
const { getMoscowStartOfDay } = require('../utils/moscowTime');
|
||||
const uniqueDates = new Set();
|
||||
user.loginDates.forEach(date => {
|
||||
const dateObj = getMoscowStartOfDay(new Date(date));
|
||||
uniqueDates.add(dateObj.getTime());
|
||||
});
|
||||
|
||||
// Если уже есть 2 уникальные даты, сразу засчитать реферал без добавления новой даты
|
||||
// Добавить сегодняшнюю дату, если её еще нет
|
||||
const todayExists = uniqueDates.has(todayTime);
|
||||
if (!todayExists) {
|
||||
user.loginDates.push(today);
|
||||
uniqueDates.add(todayTime);
|
||||
}
|
||||
|
||||
// Если уже есть 2 или более уникальные даты, засчитать реферала
|
||||
if (uniqueDates.size >= 2) {
|
||||
const User = require('../models/User');
|
||||
await User.findByIdAndUpdate(user.referredBy, {
|
||||
$inc: { referralsCount: 1 }
|
||||
});
|
||||
const referrer = await User.findById(user.referredBy);
|
||||
|
||||
if (referrer) {
|
||||
// Увеличить счетчик рефералов
|
||||
referrer.referralsCount = (referrer.referralsCount || 0) + 1;
|
||||
await referrer.save();
|
||||
|
||||
console.log(`✅ Реферал засчитан: пользователь ${user.username} (${user._id}) засчитан для ${referrer.username} (${referrer._id}). Всего рефералов: ${referrer.referralsCount}`);
|
||||
|
||||
// Начислить баллы за реферала
|
||||
const { awardReferral } = require('../utils/tickets');
|
||||
await awardReferral(user.referredBy);
|
||||
}
|
||||
|
||||
user.referralCounted = true;
|
||||
// Очистить loginDates после засчета, чтобы не хранить лишние данные
|
||||
user.loginDates = [];
|
||||
await user.save();
|
||||
} else {
|
||||
// Если еще нет 2 уникальных дат, добавить сегодняшнюю дату по московскому времени (если её нет)
|
||||
const { getMoscowDate } = require('../utils/moscowTime');
|
||||
const today = getMoscowDate();
|
||||
const todayTime = today.getTime();
|
||||
|
||||
// Проверить, есть ли уже сегодняшняя дата
|
||||
const todayExists = uniqueDates.has(todayTime);
|
||||
|
||||
// Если сегодняшней даты нет, добавить её
|
||||
if (!todayExists) {
|
||||
user.loginDates.push(today);
|
||||
// Если еще нет 2 уникальных дат, сохранить обновленный массив loginDates
|
||||
await user.save();
|
||||
}
|
||||
console.log(`📅 Реферал ${user.username} (${user._id}): добавлена дата входа. Уникальных дат: ${uniqueDates.size}/2`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,14 +28,31 @@ const multerConfig = {
|
|||
return cb(new Error('Запрещенный тип файла'));
|
||||
}
|
||||
|
||||
// Разрешенные типы изображений и видео
|
||||
// Разрешенные типы изображений и видео (расширенный список)
|
||||
const allowedMimes = [
|
||||
// Основные форматы изображений
|
||||
'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp',
|
||||
'video/mp4', 'video/quicktime', 'video/x-msvideo'
|
||||
// Дополнительные форматы изображений
|
||||
'image/bmp', 'image/x-ms-bmp', 'image/tiff', 'image/tif',
|
||||
'image/heic', 'image/heif', 'image/avif', 'image/x-icon',
|
||||
// Видео форматы
|
||||
'video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/webm',
|
||||
'video/x-matroska', 'video/avi'
|
||||
];
|
||||
|
||||
if (!allowedMimes.includes(file.mimetype)) {
|
||||
return cb(new Error('Только изображения и видео разрешены'));
|
||||
// Также проверяем по расширению файла (на случай неправильного MIME типа)
|
||||
const allowedExts = [
|
||||
'.jpg', '.jpeg', '.png', '.gif', '.webp', '.bmp', '.tiff', '.tif',
|
||||
'.heic', '.heif', '.avif', '.ico',
|
||||
'.mp4', '.mov', '.avi', '.webm', '.mkv'
|
||||
];
|
||||
|
||||
const fileExt = ext.toLowerCase();
|
||||
const isValidMime = allowedMimes.includes(file.mimetype);
|
||||
const isValidExt = allowedExts.includes(fileExt);
|
||||
|
||||
if (!isValidMime && !isValidExt) {
|
||||
return cb(new Error(`Неподдерживаемый формат файла. Разрешены: JPEG, PNG, GIF, WebP, BMP, HEIC, MP4, MOV, AVI, WebM. Получен: ${file.mimetype || 'неизвестно'}`));
|
||||
}
|
||||
|
||||
cb(null, true);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,99 @@
|
|||
const mongoose = require('mongoose');
|
||||
const dotenv = require('dotenv');
|
||||
const path = require('path');
|
||||
|
||||
// Загрузить переменные окружения
|
||||
dotenv.config({ path: path.join(__dirname, '../.env') });
|
||||
|
||||
const User = require('../models/User');
|
||||
const { getMoscowStartOfDay } = require('../utils/moscowTime');
|
||||
const { awardReferral } = require('../utils/tickets');
|
||||
|
||||
async function fixReferrals() {
|
||||
try {
|
||||
const mongoUri = process.env.MONGO_URI || 'mongodb://localhost:27017/nakama';
|
||||
await mongoose.connect(mongoUri);
|
||||
console.log('✅ Подключено к MongoDB');
|
||||
|
||||
// Найти всех пользователей, у которых есть referredBy, но они еще не засчитаны
|
||||
const usersWithReferrals = await User.find({
|
||||
referredBy: { $exists: true, $ne: null },
|
||||
referralCounted: { $ne: true }
|
||||
}).populate('referredBy', 'username referralCode referralsCount');
|
||||
|
||||
console.log(`\n📊 Найдено ${usersWithReferrals.length} пользователей с незасчитанными рефералами\n`);
|
||||
|
||||
let fixed = 0;
|
||||
let needMoreDays = 0;
|
||||
|
||||
for (const user of usersWithReferrals) {
|
||||
if (!user.referredBy) {
|
||||
console.log(`⚠️ Пользователь ${user.username} (${user._id}) имеет referredBy, но реферер не найден`);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Инициализировать loginDates если его нет
|
||||
if (!user.loginDates || user.loginDates.length === 0) {
|
||||
console.log(`📅 Пользователь ${user.username} (${user._id}) не имеет дат входа. Пропускаем.`);
|
||||
needMoreDays++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Получить уникальные даты из массива loginDates
|
||||
const uniqueDates = new Set();
|
||||
user.loginDates.forEach(date => {
|
||||
const dateObj = getMoscowStartOfDay(new Date(date));
|
||||
uniqueDates.add(dateObj.getTime());
|
||||
});
|
||||
|
||||
console.log(`👤 ${user.username} (${user._id})`);
|
||||
console.log(` Реферер: ${user.referredBy.username} (${user.referredBy._id})`);
|
||||
console.log(` Уникальных дат входа: ${uniqueDates.size}`);
|
||||
console.log(` Даты: ${Array.from(uniqueDates).map(t => new Date(t).toLocaleDateString('ru-RU')).join(', ')}`);
|
||||
|
||||
// Если есть 2 или более уникальные даты, засчитать реферала
|
||||
if (uniqueDates.size >= 2) {
|
||||
const referrer = user.referredBy;
|
||||
|
||||
// Увеличить счетчик рефералов
|
||||
referrer.referralsCount = (referrer.referralsCount || 0) + 1;
|
||||
await referrer.save();
|
||||
|
||||
console.log(` ✅ РЕФЕРАЛ ЗАСЧИТАН! Новый счетчик: ${referrer.referralsCount}`);
|
||||
|
||||
// Начислить баллы за реферала
|
||||
try {
|
||||
await awardReferral(referrer._id);
|
||||
console.log(` ✅ Баллы начислены`);
|
||||
} catch (error) {
|
||||
console.error(` ⚠️ Ошибка начисления баллов:`, error.message);
|
||||
}
|
||||
|
||||
// Пометить как засчитанный
|
||||
user.referralCounted = true;
|
||||
user.loginDates = [];
|
||||
await user.save();
|
||||
|
||||
fixed++;
|
||||
} else {
|
||||
console.log(` ⏳ Нужно еще ${2 - uniqueDates.size} уникальных дат входа`);
|
||||
needMoreDays++;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
}
|
||||
|
||||
console.log(`\n📊 Итого:`);
|
||||
console.log(` ✅ Засчитано рефералов: ${fixed}`);
|
||||
console.log(` ⏳ Требуется больше дней: ${needMoreDays}`);
|
||||
|
||||
await mongoose.connection.close();
|
||||
console.log('✅ Готово!');
|
||||
} catch (error) {
|
||||
console.error('❌ Ошибка:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
fixReferrals();
|
||||
|
||||
|
|
@ -72,32 +72,103 @@ export default function CreatePostModal({ user, onClose, onPostCreated, initialI
|
|||
}, [])
|
||||
|
||||
const handleImageSelect = (e) => {
|
||||
const files = Array.from(e.target.files)
|
||||
if (files.length === 0) return
|
||||
const files = Array.from(e.target.files || [])
|
||||
if (files.length === 0) {
|
||||
console.warn('No files selected')
|
||||
return
|
||||
}
|
||||
|
||||
// Валидация файлов на фронтенде
|
||||
const validFiles = files.filter(file => {
|
||||
// Проверка типа файла
|
||||
const validTypes = [
|
||||
'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp',
|
||||
'image/bmp', 'image/tiff', 'image/heic', 'image/heif', 'image/avif',
|
||||
'video/mp4', 'video/quicktime', 'video/x-msvideo', 'video/webm'
|
||||
]
|
||||
|
||||
if (!validTypes.includes(file.type)) {
|
||||
console.warn('Invalid file type:', file.type, file.name)
|
||||
alert(`Файл "${file.name}" имеет неподдерживаемый формат. Разрешены: JPEG, PNG, GIF, WebP, BMP, HEIC, MP4, MOV, AVI, WebM`)
|
||||
return false
|
||||
}
|
||||
|
||||
// Проверка размера (10MB)
|
||||
const maxSize = 10 * 1024 * 1024
|
||||
if (file.size > maxSize) {
|
||||
console.warn('File too large:', file.name, file.size)
|
||||
alert(`Файл "${file.name}" слишком большой. Максимальный размер: 10MB`)
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if (validFiles.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const remainingSlots = 5 - images.length
|
||||
const filesToAdd = files.slice(0, remainingSlots)
|
||||
const filesToAdd = validFiles.slice(0, remainingSlots)
|
||||
|
||||
filesToAdd.forEach(file => {
|
||||
if (filesToAdd.length < validFiles.length) {
|
||||
alert(`Можно добавить максимум 5 изображений. Добавлено ${filesToAdd.length} из ${validFiles.length}`)
|
||||
}
|
||||
|
||||
// Создаем превью для каждого файла
|
||||
const previewPromises = filesToAdd.map((file, index) => {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader()
|
||||
reader.onloadend = () => {
|
||||
setImagePreviews(prev => [...prev, reader.result])
|
||||
resolve({ index, result: reader.result })
|
||||
}
|
||||
reader.onerror = (error) => {
|
||||
console.error('Error reading file:', error, file.name)
|
||||
reject(new Error(`Ошибка чтения файла "${file.name}"`))
|
||||
}
|
||||
reader.readAsDataURL(file)
|
||||
})
|
||||
})
|
||||
|
||||
// Ждем загрузки всех превью, затем обновляем состояние
|
||||
Promise.all(previewPromises)
|
||||
.then((previewResults) => {
|
||||
// Сортируем результаты по индексу
|
||||
previewResults.sort((a, b) => a.index - b.index)
|
||||
const newPreviews = previewResults.map(r => r.result)
|
||||
|
||||
setImagePreviews(prev => [...prev, ...newPreviews])
|
||||
|
||||
// Добавляем файлы в массив после успешной загрузки превью
|
||||
setImages(prev => {
|
||||
const newImages = [...prev, ...filesToAdd]
|
||||
console.log('Images after add:', newImages.length, newImages.map(f => ({ name: f.name, type: f.type, size: f.size })))
|
||||
return newImages
|
||||
})
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error loading previews:', error)
|
||||
alert(error.message || 'Ошибка загрузки превью изображений')
|
||||
})
|
||||
|
||||
setImages(prev => [...prev, ...filesToAdd])
|
||||
hapticFeedback('light')
|
||||
|
||||
// Очищаем input для возможности повторного выбора того же файла
|
||||
if (fileInputRef.current) {
|
||||
fileInputRef.current.value = ''
|
||||
}
|
||||
}
|
||||
|
||||
const handleRemoveImage = (index) => {
|
||||
setImages(prev => prev.filter((_, i) => i !== index))
|
||||
console.log('Removing image at index:', index, 'Total images:', images.length)
|
||||
setImages(prev => {
|
||||
const newImages = prev.filter((_, i) => i !== index)
|
||||
console.log('Images after remove:', newImages.length)
|
||||
return newImages
|
||||
})
|
||||
setImagePreviews(prev => prev.filter((_, i) => i !== index))
|
||||
setExternalImages(prev => prev.filter((_, i) => i !== index))
|
||||
hapticFeedback('light')
|
||||
}
|
||||
|
||||
const handleTagInputChange = (e) => {
|
||||
|
|
@ -216,12 +287,22 @@ export default function CreatePostModal({ user, onClose, onPostCreated, initialI
|
|||
formData.append('isNSFW', isNSFW)
|
||||
formData.append('isHomo', isHomo)
|
||||
|
||||
images.forEach((image, index) => {
|
||||
if (image instanceof File) {
|
||||
formData.append('images', image)
|
||||
// Отправляем все файлы, которые являются File объектами
|
||||
const fileImages = images.filter(img => img instanceof File)
|
||||
|
||||
if (fileImages.length === 0 && images.length > 0) {
|
||||
console.warn('No File objects found in images array:', images.map(img => typeof img))
|
||||
}
|
||||
|
||||
fileImages.forEach((image, index) => {
|
||||
formData.append('images', image, image.name)
|
||||
console.log(`Appending image ${index}:`, image.name, image.type, image.size)
|
||||
})
|
||||
|
||||
console.log('FormData images count:', fileImages.length, 'Total images:', images.length)
|
||||
|
||||
// Если есть externalImages (из поиска), добавляем их отдельно
|
||||
|
||||
if (externalImages.length > 0) {
|
||||
formData.append('externalImages', JSON.stringify(externalImages))
|
||||
}
|
||||
|
|
@ -408,7 +489,7 @@ export default function CreatePostModal({ user, onClose, onPostCreated, initialI
|
|||
<input
|
||||
ref={fileInputRef}
|
||||
type="file"
|
||||
accept="image/*"
|
||||
accept="image/*,video/*,.heic,.heif,.avif"
|
||||
multiple
|
||||
onChange={handleImageSelect}
|
||||
style={{ display: 'none' }}
|
||||
|
|
|
|||
Loading…
Reference in New Issue