nanobot özel sürüm v1

This commit is contained in:
hpibot
2026-03-01 20:26:44 +03:00
parent 34c5eb0a23
commit 3ea10e9c78
16 changed files with 248 additions and 659 deletions

View File

@@ -1,5 +1,4 @@
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
@@ -32,67 +31,71 @@ passport.deserializeUser(async (id, done) => {
}
});
// Google OAuth Strategy
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL || "/api/auth/google/callback"
}, async (accessToken, refreshToken, profile, done) => {
try {
// Önce Google ID ile kullanıcı ara
let user = await prisma.user.findUnique({
where: { googleId: profile.id }
});
if (user) {
// Kullanıcı zaten var, son giriş tarihini güncelle
user = await prisma.user.update({
where: { id: user.id },
data: { lastLoginAt: new Date() }
// Google OAuth Strategy - Sadece credentials varsa yükle
if (process.env.GOOGLE_CLIENT_ID && process.env.GOOGLE_CLIENT_SECRET) {
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: process.env.GOOGLE_CALLBACK_URL || "/api/auth/google/callback"
}, async (accessToken, refreshToken, profile, done) => {
try {
// Önce Google ID ile kullanıcı ara
let user = await prisma.user.findUnique({
where: { googleId: profile.id }
});
return done(null, user);
}
// Email ile kullanıcı ara (mevcut hesap varsa bağla)
user = await prisma.user.findUnique({
where: { email: profile.emails[0].value }
});
if (user) {
// Kullanıcı zaten var, son giriş tarihini güncelle
user = await prisma.user.update({
where: { id: user.id },
data: { lastLoginAt: new Date() }
});
return done(null, user);
}
if (user) {
// Mevcut hesabı Google ile bağla
user = await prisma.user.update({
where: { id: user.id },
// Email ile kullanıcı ara (mevcut hesap varsa bağla)
user = await prisma.user.findUnique({
where: { email: profile.emails[0].value }
});
if (user) {
// Mevcut hesabı Google ile bağla
user = await prisma.user.update({
where: { id: user.id },
data: {
googleId: profile.id,
authProvider: 'google',
avatar: profile.photos[0]?.value || user.avatar,
lastLoginAt: new Date()
}
});
return done(null, user);
}
// Yeni kullanıcı oluştur
const username = profile.emails[0].value.split('@')[0] + '_' + Math.random().toString(36).substr(2, 4);
user = await prisma.user.create({
data: {
email: profile.emails[0].value,
username: username,
firstName: profile.name.givenName || '',
lastName: profile.name.familyName || '',
googleId: profile.id,
authProvider: 'google',
avatar: profile.photos[0]?.value || user.avatar,
avatar: profile.photos[0]?.value,
lastLoginAt: new Date()
}
});
return done(null, user);
} catch (error) {
console.error('Google OAuth Error:', error);
return done(error, null);
}
// Yeni kullanıcı oluştur
const username = profile.emails[0].value.split('@')[0] + '_' + Math.random().toString(36).substr(2, 4);
user = await prisma.user.create({
data: {
email: profile.emails[0].value,
username: username,
firstName: profile.name.givenName || '',
lastName: profile.name.familyName || '',
googleId: profile.id,
authProvider: 'google',
avatar: profile.photos[0]?.value,
lastLoginAt: new Date()
}
});
return done(null, user);
} catch (error) {
console.error('Google OAuth Error:', error);
return done(error, null);
}
}));
}));
}
module.exports = passport;

View File

@@ -1,5 +1,4 @@
const express = require('express');
const { PrismaClient } = require('@prisma/client');
const { authenticateToken, checkListMembership, requireListEditPermission } = require('../middleware/auth');
const { asyncHandler } = require('../middleware/errorHandler');
const {
@@ -15,7 +14,6 @@ const { successResponse, errorResponse, calculatePagination, createPaginationMet
const notificationService = require('../services/notificationService');
const router = express.Router();
const prisma = new PrismaClient();
/**
* Liste öğelerini getir
@@ -68,8 +66,8 @@ router.get('/:listId',
// Toplam sayı ve öğeleri getir
const [total, items] = await Promise.all([
prisma.listItem.count({ where }),
prisma.listItem.findMany({
req.prisma.listItem.count({ where }),
req.prisma.listItem.findMany({
where,
skip,
take,
@@ -116,7 +114,7 @@ router.get('/:listId/:itemId',
const { listId, itemId } = req.params;
const item = await prisma.listItem.findFirst({
const item = await req.prisma.listItem.findFirst({
where: {
id: itemId,
listId
@@ -179,7 +177,7 @@ router.post('/:listId',
// Eğer productId verilmişse, ürünün var olduğunu kontrol et
let product = null;
if (productId) {
product = await prisma.product.findUnique({
product = await req.prisma.product.findUnique({
where: { id: productId }
});
@@ -189,7 +187,7 @@ router.post('/:listId',
}
// Aynı öğenin listede zaten var olup olmadığını kontrol et
const existingItem = await prisma.listItem.findFirst({
const existingItem = await req.prisma.listItem.findFirst({
where: {
listId,
OR: [
@@ -204,7 +202,7 @@ router.post('/:listId',
}
// Yeni öğe oluştur
const newItem = await prisma.listItem.create({
const newItem = await req.prisma.listItem.create({
data: {
customName: productId ? product.name : name,
quantity,
@@ -226,26 +224,26 @@ router.post('/:listId',
// Ürün kullanım sayısını artır (Product modelinde usageCount alanı yok, bu özellik kaldırıldı)
// Liste güncelleme tarihini güncelle
await prisma.shoppingList.update({
await req.prisma.shoppingList.update({
where: { id: listId },
data: { updatedAt: new Date() }
});
// Aktivite kaydı oluştur
await prisma.activity.create({
data: {
action: 'item_added',
details: {
itemId: newItem.id,
itemName: newItem.customName || newItem.product?.name || 'Öğe',
userName: `${req.user.firstName} ${req.user.lastName}`
},
userId,
listId
}
});
// Aktivite kaydı oluştur (geçici olarak devre dışı)
// await req.prisma.activity.create({
// data: {
// action: 'item_added',
// details: {
// itemId: newItem.id,
// itemName: newItem.customName || newItem.product?.name || 'Öğe',
// userName: `${req.user.firstName} ${req.user.lastName}`
// },
// userId,
// listId
// }
// });
// Liste üyelerine bildirim gönder (geçici olarak devre dışı - notifyListMembers fonksiyonu mevcut değil)
// Liste üyelerine bildirim gönder (geçici olarak devre dışı)
// await notificationService.notifyListMembers(
// listId,
// userId,
@@ -254,14 +252,14 @@ router.post('/:listId',
// { itemId: newItem.id, itemName: newItem.customName || newItem.product?.name }
// );
// Socket.IO ile gerçek zamanlı güncelleme
const io = req.app.get('io');
if (io) {
io.to(`list_${listId}`).emit('itemAdded', {
item: newItem,
addedBy: req.user
});
}
// Socket.IO ile gerçek zamanlı güncelleme (geçici olarak devre dışı)
// const io = req.app.get('io');
// if (io) {
// io.to(`list_${listId}`).emit('itemAdded', {
// item: newItem,
// addedBy: req.user
// });
// }
// Priority değerini string'e çevir
const newItemWithStringPriority = {
@@ -321,7 +319,7 @@ router.put('/:listId/:itemId',
// Öğenin var olduğunu kontrol et
console.log('🔍 Öğe aranıyor:', { itemId, listId });
const existingItem = await prisma.listItem.findFirst({
const existingItem = await req.prisma.listItem.findFirst({
where: {
id: itemId,
listId
@@ -364,7 +362,7 @@ router.put('/:listId/:itemId',
}
// Öğeyi güncelle
const updatedItem = await prisma.listItem.update({
const updatedItem = await req.prisma.listItem.update({
where: { id: itemId },
data: updateData,
include: {
@@ -378,7 +376,7 @@ router.put('/:listId/:itemId',
// Fiyat geçmişi ekle (eğer fiyat girilmişse ve ürün varsa)
if (price && existingItem.productId && isPurchased) {
await prisma.priceHistory.create({
await req.prisma.priceHistory.create({
data: {
price: price,
productId: existingItem.productId,
@@ -389,7 +387,7 @@ router.put('/:listId/:itemId',
}
// Liste güncelleme tarihini güncelle
await prisma.shoppingList.update({
await req.prisma.shoppingList.update({
where: { id: listId },
data: { updatedAt: new Date() }
});
@@ -402,7 +400,7 @@ router.put('/:listId/:itemId',
: `${req.user.firstName} ${req.user.lastName} "${updatedItem.name}" öğesinin satın alma durumunu iptal etti`;
}
await prisma.activity.create({
await req.prisma.activity.create({
data: {
action: isPurchased !== undefined ? (isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED') : 'ITEM_UPDATED',
details: {
@@ -467,7 +465,7 @@ router.delete('/:listId/:itemId',
const userId = req.user.id;
// Öğenin var olduğunu kontrol et
const existingItem = await prisma.listItem.findFirst({
const existingItem = await req.prisma.listItem.findFirst({
where: {
id: itemId,
listId
@@ -479,19 +477,19 @@ router.delete('/:listId/:itemId',
}
// Öğeyi sil
await prisma.listItem.delete({
await req.prisma.listItem.delete({
where: { id: itemId }
});
// Liste güncelleme tarihini güncelle
await prisma.shoppingList.update({
await req.prisma.shoppingList.update({
where: { id: listId },
data: { updatedAt: new Date() }
});
// Aktivite kaydı oluştur (Prisma şemasına uygun)
const itemName = existingItem.customName || existingItem.product?.name || 'Öğe';
await prisma.activity.create({
await req.prisma.activity.create({
data: {
action: 'ITEM_REMOVED',
details: {
@@ -551,7 +549,7 @@ router.patch('/:listId/bulk',
}
// Öğelerin var olduğunu kontrol et
const existingItems = await prisma.listItem.findMany({
const existingItems = await req.prisma.listItem.findMany({
where: {
id: { in: items },
listId
@@ -593,14 +591,14 @@ router.patch('/:listId/bulk',
// Toplu güncelleme veya silme
if (action === 'delete') {
await prisma.listItem.deleteMany({
await req.prisma.listItem.deleteMany({
where: {
id: { in: items },
listId
}
});
} else {
await prisma.listItem.updateMany({
await req.prisma.listItem.updateMany({
where: {
id: { in: items },
listId
@@ -610,13 +608,13 @@ router.patch('/:listId/bulk',
}
// Liste güncelleme tarihini güncelle
await prisma.shoppingList.update({
await req.prisma.shoppingList.update({
where: { id: listId },
data: { updatedAt: new Date() }
});
// Aktivite kaydı oluştur
await prisma.activity.create({
await req.prisma.activity.create({
data: {
type: activityType,
description: activityDescription,

View File

@@ -198,23 +198,25 @@ router.post('/', authenticateToken, [
}
});
// Aktivite kaydı oluştur
await req.prisma.activity.create({
data: {
listId: list.id,
userId: req.user.id,
action: 'list_created',
details: {
listName: list.name
}
}
});
// Aktivite kaydı oluştur (geçici olarak devre dışı)
// await req.prisma.activity.create({
// data: {
// listId: list.id,
// userId: req.user.id,
// action: 'list_created',
// details: {
// listName: list.name
// }
// }
// });
// Socket.IO ile gerçek zamanlı bildirim gönder
req.io.emit('list_created', {
list: { ...list, userRole: 'owner' },
user: req.user
});
// Socket.IO ile gerçek zamanlı bildirim gönder (geçici olarak devre dışı)
// if (req.io) {
// req.io.emit('list_created', {
// list: { ...list, userRole: 'owner' },
// user: req.user
// });
// }
res.status(201).json({
success: true,

View File

@@ -148,7 +148,7 @@ process.on('SIGINT', async () => {
});
// Sunucuyu başlat
const PORT = process.env.PORT || 5000;
const PORT = process.env.PORT || 7001;
server.listen(PORT, () => {
console.log(`🚀 Server ${PORT} portunda çalışıyor - port 7001`);

View File

@@ -9,6 +9,16 @@ class NotificationService {
initializeFirebase() {
try {
// Firebase credentials kontrolü
const hasCredentials = process.env.FIREBASE_PROJECT_ID &&
process.env.FIREBASE_PRIVATE_KEY &&
process.env.FIREBASE_CLIENT_EMAIL;
if (!hasCredentials) {
console.log('⚠️ Firebase credentials not configured. Push notifications disabled.');
return;
}
if (!admin.apps.length) {
const serviceAccount = {
type: process.env.FIREBASE_TYPE,
@@ -27,10 +37,11 @@ class NotificationService {
credential: admin.credential.cert(serviceAccount)
});
console.log('Firebase Admin SDK initialized successfully');
console.log('Firebase Admin SDK initialized successfully');
}
} catch (error) {
console.error('Firebase initialization error:', error);
console.error('Firebase initialization error:', error.message);
console.warn('Push notifications will be disabled.');
}
}

View File

@@ -16,13 +16,20 @@ function getDatabaseName(databaseUrl) {
async function setupUtf8mb4(prisma) {
const databaseUrl = process.env.DATABASE_URL || '';
// SQLite için bu fonksiyonu atla
if (databaseUrl.includes('sqlite') || databaseUrl.includes('.db')) {
console.log(' SQLite kullanılıyor. UTF8MB4 kurulumu atlandı.');
return;
}
const dbName = getDatabaseName(databaseUrl);
if (!dbName) {
console.warn('⚠️ DATABASE_URL bulunamadı veya veritabanı adı çözümlenemedi. UTF8MB4 kurulumu atlandı.');
return;
}
// Try altering database charset/collation
// Only run for MySQL/MariaDB
try {
await prisma.$executeRawUnsafe(`ALTER DATABASE \`${dbName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
console.log('✅ Veritabanı varsayılan karakter seti/collation utf8mb4 olarak ayarlandı.');
@@ -30,7 +37,6 @@ async function setupUtf8mb4(prisma) {
console.warn('⚠️ Veritabanı charset ayarlanırken hata oluştu:', err?.message || err);
}
// Try converting categories table
try {
await prisma.$executeRawUnsafe('ALTER TABLE `categories` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
console.log('✅ `categories` tablosu utf8mb4 olarak dönüştürüldü.');