nanobot özel sürüm v1
This commit is contained in:
1
backend/package-lock.json
generated
1
backend/package-lock.json
generated
@@ -3075,7 +3075,6 @@
|
|||||||
"version": "2.3.3",
|
"version": "2.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||||
"dev": true,
|
|
||||||
"hasInstallScript": true,
|
"hasInstallScript": true,
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"os": [
|
"os": [
|
||||||
|
|||||||
BIN
backend/prisma/dev.db
Normal file
BIN
backend/prisma/dev.db
Normal file
Binary file not shown.
@@ -1,5 +1,5 @@
|
|||||||
// HMarket Veritabanı Şeması
|
// HMarket Veritabanı Şeması
|
||||||
// MariaDB için Prisma ORM konfigürasyonu
|
// MySQL için Prisma ORM konfigürasyonu
|
||||||
|
|
||||||
generator client {
|
generator client {
|
||||||
provider = "prisma-client-js"
|
provider = "prisma-client-js"
|
||||||
@@ -153,7 +153,7 @@ model ListItem {
|
|||||||
customName String? // Ürün yoksa manuel isim
|
customName String? // Ürün yoksa manuel isim
|
||||||
quantity Float @default(1)
|
quantity Float @default(1)
|
||||||
unit String @default("adet") // "kg", "lt", "adet", vb.
|
unit String @default("adet") // "kg", "lt", "adet", vb.
|
||||||
price Decimal? @db.Decimal(10, 2)
|
price Decimal? // SQLite: Decimal stored as String
|
||||||
note String?
|
note String?
|
||||||
isPurchased Boolean @default(false)
|
isPurchased Boolean @default(false)
|
||||||
purchasedAt DateTime?
|
purchasedAt DateTime?
|
||||||
@@ -174,7 +174,7 @@ model ListItem {
|
|||||||
model PriceHistory {
|
model PriceHistory {
|
||||||
id String @id @default(cuid())
|
id String @id @default(cuid())
|
||||||
productId String
|
productId String
|
||||||
price Decimal @db.Decimal(10, 2)
|
price Decimal // SQLite: Decimal stored as String
|
||||||
store String? // Mağaza adı
|
store String? // Mağaza adı
|
||||||
location String? // Konum bilgisi
|
location String? // Konum bilgisi
|
||||||
source String @default("user") // "user", "api", "scraping"
|
source String @default("user") // "user", "api", "scraping"
|
||||||
@@ -193,7 +193,7 @@ model Notification {
|
|||||||
title String
|
title String
|
||||||
message String
|
message String
|
||||||
type String // "list_shared", "item_added", "item_purchased", "price_alert"
|
type String // "list_shared", "item_added", "item_purchased", "price_alert"
|
||||||
data Json? // Ek veri (JSON format)
|
data String? // Ek veri (JSON format - SQLite String olarak saklanır)
|
||||||
isRead Boolean @default(false)
|
isRead Boolean @default(false)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
@@ -209,7 +209,7 @@ model Activity {
|
|||||||
listId String
|
listId String
|
||||||
userId String
|
userId String
|
||||||
action String // "item_added", "item_removed", "item_updated", "item_purchased"
|
action String // "item_added", "item_removed", "item_updated", "item_purchased"
|
||||||
details Json? // Aktivite detayları
|
details String? // Aktivite detayları (JSON - SQLite String olarak saklanır)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
|
|
||||||
// İlişkiler
|
// İlişkiler
|
||||||
|
|||||||
@@ -1,389 +1,139 @@
|
|||||||
const { PrismaClient } = require('@prisma/client');
|
import { PrismaClient } from '@prisma/client'
|
||||||
const bcrypt = require('bcryptjs');
|
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient()
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
console.log('🌱 Veritabanı seed işlemi başlatılıyor...');
|
console.log('Örnek veriler ekleniyor...')
|
||||||
|
|
||||||
// Admin kullanıcısı oluştur
|
// Kullanıcılar
|
||||||
const hashedPassword = await bcrypt.hash('admin123', 12);
|
const user1 = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email: 'mustafa@example.com',
|
||||||
|
username: 'mustafa',
|
||||||
|
firstName: 'Mustafa',
|
||||||
|
lastName: 'ÖZKAYA',
|
||||||
|
password: '$2a$10$dummy',
|
||||||
|
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=mustafa',
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const adminUser = await prisma.user.upsert({
|
const user2 = await prisma.user.create({
|
||||||
where: { email: 'admin@hmarket.com' },
|
data: {
|
||||||
update: {},
|
email: 'ahmet@example.com',
|
||||||
create: {
|
|
||||||
email: 'admin@hmarket.com',
|
|
||||||
username: 'admin',
|
|
||||||
firstName: 'Admin',
|
|
||||||
lastName: 'User',
|
|
||||||
password: hashedPassword,
|
|
||||||
isAdmin: true,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log('✅ Admin kullanıcısı oluşturuldu:', adminUser.email);
|
|
||||||
|
|
||||||
// Test kullanıcıları oluştur
|
|
||||||
const testUsers = [
|
|
||||||
{
|
|
||||||
email: 'ahmet@test.com',
|
|
||||||
username: 'ahmet',
|
username: 'ahmet',
|
||||||
firstName: 'Ahmet',
|
firstName: 'Ahmet',
|
||||||
lastName: 'Yılmaz',
|
lastName: 'Yılmaz',
|
||||||
password: await bcrypt.hash('test123', 12),
|
password: '$2a$10$dummy',
|
||||||
},
|
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ahmet',
|
||||||
{
|
}
|
||||||
email: 'ayse@test.com',
|
})
|
||||||
|
|
||||||
|
const user3 = await prisma.user.create({
|
||||||
|
data: {
|
||||||
|
email: 'ayse@example.com',
|
||||||
username: 'ayse',
|
username: 'ayse',
|
||||||
firstName: 'Ayşe',
|
firstName: 'Ayşe',
|
||||||
lastName: 'Kaya',
|
lastName: 'Kaya',
|
||||||
password: await bcrypt.hash('test123', 12),
|
password: '$2a$10$dummy',
|
||||||
},
|
avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=ayse',
|
||||||
{
|
|
||||||
email: 'mehmet@test.com',
|
|
||||||
username: 'mehmet',
|
|
||||||
firstName: 'Mehmet',
|
|
||||||
lastName: 'Demir',
|
|
||||||
password: await bcrypt.hash('test123', 12),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const userData of testUsers) {
|
|
||||||
const user = await prisma.user.upsert({
|
|
||||||
where: { email: userData.email },
|
|
||||||
update: {},
|
|
||||||
create: userData,
|
|
||||||
});
|
|
||||||
console.log('✅ Test kullanıcısı oluşturuldu:', user.email);
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
// Kategoriler oluştur
|
console.log('✅ Kullanıcılar oluşturuldu')
|
||||||
const categories = [
|
|
||||||
{ name: 'Meyve & Sebze', description: 'Taze meyve ve sebzeler', icon: '🥕', color: '#4CAF50' },
|
|
||||||
{ name: 'Et & Tavuk', description: 'Kırmızı et, beyaz et ve şarküteri ürünleri', icon: '🥩', color: '#F44336' },
|
|
||||||
{ name: 'Süt Ürünleri', description: 'Süt, peynir, yoğurt ve diğer süt ürünleri', icon: '🥛', color: '#2196F3' },
|
|
||||||
{ name: 'Fırın & Pastane', description: 'Ekmek, pasta ve unlu mamuller', icon: '🍞', color: '#FF9800' },
|
|
||||||
{ name: 'Atıştırmalık', description: 'Çikolata, bisküvi ve atıştırmalık ürünler', icon: '🍿', color: '#9C27B0' },
|
|
||||||
{ name: 'İçecek', description: 'Alkolsüz içecekler ve sıcak içecekler', icon: '🥤', color: '#00BCD4' },
|
|
||||||
{ name: 'Temizlik', description: 'Ev temizlik ürünleri ve deterjanlar', icon: '🧽', color: '#607D8B' },
|
|
||||||
{ name: 'Kişisel Bakım', description: 'Kişisel hijyen ve bakım ürünleri', icon: '🧴', color: '#E91E63' },
|
|
||||||
{ name: 'Bebek', description: 'Bebek bakım ürünleri ve mama', icon: '🍼', color: '#FFEB3B' },
|
|
||||||
{ name: 'Dondurulmuş', description: 'Dondurulmuş gıda ürünleri', icon: '🧊', color: '#3F51B5' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const categoryData of categories) {
|
// Kategoriler
|
||||||
const category = await prisma.category.upsert({
|
const cat1 = await prisma.category.create({ data: { name: 'Sebze & Meyve', icon: '🥬', color: '#4CAF50' } })
|
||||||
where: { name: categoryData.name },
|
const cat2 = await prisma.category.create({ data: { name: 'Et & Tavuk', icon: '🥩', color: '#F44336' } })
|
||||||
update: {},
|
const cat3 = await prisma.category.create({ data: { name: 'Süt & Süt Ürünleri', icon: '🥛', color: '#2196F3' } })
|
||||||
create: categoryData,
|
const cat4 = await prisma.category.create({ data: { name: 'Ekmek & Unlu Mamüller', icon: '🍞', color: '#FF9800' } })
|
||||||
});
|
const cat5 = await prisma.category.create({ data: { name: 'İçecekler', icon: '🥤', color: '#9C27B0' } })
|
||||||
console.log('✅ Kategori oluşturuldu:', category.name);
|
const cat6 = await prisma.category.create({ data: { name: 'Temizlik', icon: '🧹', color: '#607D8B' } })
|
||||||
}
|
const cat7 = await prisma.category.create({ data: { name: 'Atıştırmalık', icon: '🍪', color: '#795548' } })
|
||||||
|
const cat8 = await prisma.category.create({ data: { name: 'Dondurma', icon: '🍦', color: '#E91E63' } })
|
||||||
|
|
||||||
// Örnek ürünler oluştur
|
console.log('✅ Kategoriler oluşturuldu')
|
||||||
const products = [
|
|
||||||
// Meyve & Sebze
|
|
||||||
{ name: 'Elma', categoryName: 'Meyve & Sebze', barcode: '1234567890123', averagePrice: 12.50 },
|
|
||||||
{ name: 'Muz', categoryName: 'Meyve & Sebze', barcode: '1234567890124', averagePrice: 18.00 },
|
|
||||||
{ name: 'Domates', categoryName: 'Meyve & Sebze', barcode: '1234567890125', averagePrice: 8.75 },
|
|
||||||
{ name: 'Salatalık', categoryName: 'Meyve & Sebze', barcode: '1234567890126', averagePrice: 6.50 },
|
|
||||||
{ name: 'Soğan', categoryName: 'Meyve & Sebze', barcode: '1234567890127', averagePrice: 4.25 },
|
|
||||||
{ name: 'Patates', categoryName: 'Meyve & Sebze', barcode: '1234567890137', averagePrice: 5.75 },
|
|
||||||
{ name: 'Havuç', categoryName: 'Meyve & Sebze', barcode: '1234567890138', averagePrice: 7.50 },
|
|
||||||
{ name: 'Biber', categoryName: 'Meyve & Sebze', barcode: '1234567890139', averagePrice: 15.00 },
|
|
||||||
{ name: 'Portakal', categoryName: 'Meyve & Sebze', barcode: '1234567890140', averagePrice: 10.00 },
|
|
||||||
{ name: 'Limon', categoryName: 'Meyve & Sebze', barcode: '1234567890141', averagePrice: 8.00 },
|
|
||||||
|
|
||||||
// Süt Ürünleri
|
// Ürünler
|
||||||
{ name: 'Süt 1L', categoryName: 'Süt Ürünleri', barcode: '1234567890128', averagePrice: 8.75 },
|
const products = await Promise.all([
|
||||||
{ name: 'Yoğurt 500g', categoryName: 'Süt Ürünleri', barcode: '1234567890129', averagePrice: 12.50 },
|
prisma.product.create({ data: { name: 'Domates', categoryId: cat1.id, unit: 'kg' } }),
|
||||||
{ name: 'Beyaz Peynir', categoryName: 'Süt Ürünleri', barcode: '1234567890130', averagePrice: 45.00 },
|
prisma.product.create({ data: { name: 'Soğan', categoryId: cat1.id, unit: 'kg' } }),
|
||||||
{ name: 'Kaşar Peyniri', categoryName: 'Süt Ürünleri', barcode: '1234567890131', averagePrice: 65.00 },
|
prisma.product.create({ data: { name: 'Salatalık', categoryId: cat1.id, unit: 'adet' } }),
|
||||||
{ name: 'Tereyağı', categoryName: 'Süt Ürünleri', barcode: '1234567890142', averagePrice: 35.00 },
|
prisma.product.create({ data: { name: 'Tavuk Göğsü', categoryId: cat2.id, unit: 'kg' } }),
|
||||||
{ name: 'Yumurta 30\'lu', categoryName: 'Süt Ürünleri', barcode: '1234567890143', averagePrice: 85.00 },
|
prisma.product.create({ data: { name: 'Kıyma', categoryId: cat2.id, unit: 'kg' } }),
|
||||||
{ name: 'Krema', categoryName: 'Süt Ürünleri', barcode: '1234567890144', averagePrice: 15.50 },
|
prisma.product.create({ data: { name: 'Kırmızı Et', categoryId: cat2.id, unit: 'kg' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Süt', categoryId: cat3.id, unit: 'L' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Yoğurt', categoryId: cat3.id, unit: 'adet' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Ekmek', categoryId: cat4.id, unit: 'adet' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Cola', categoryId: cat5.id, unit: 'adet' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Bulaşık Deterjanı', categoryId: cat6.id, unit: 'adet' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Baklava', categoryId: cat7.id, unit: 'kg' } }),
|
||||||
|
prisma.product.create({ data: { name: 'Dondurma', categoryId: cat8.id, unit: 'L' } }),
|
||||||
|
])
|
||||||
|
|
||||||
// Fırın & Pastane
|
console.log('✅ Ürünler oluşturuldu')
|
||||||
{ name: 'Ekmek', categoryName: 'Fırın & Pastane', barcode: '1234567890132', averagePrice: 4.50 },
|
|
||||||
{ name: 'Simit', categoryName: 'Fırın & Pastane', barcode: '1234567890133', averagePrice: 2.50 },
|
|
||||||
{ name: 'Pide', categoryName: 'Fırın & Pastane', barcode: '1234567890145', averagePrice: 8.00 },
|
|
||||||
{ name: 'Çörek', categoryName: 'Fırın & Pastane', barcode: '1234567890146', averagePrice: 6.50 },
|
|
||||||
{ name: 'Kek', categoryName: 'Fırın & Pastane', barcode: '1234567890147', averagePrice: 25.00 },
|
|
||||||
|
|
||||||
// İçecek
|
// Market Listeleri
|
||||||
{ name: 'Su 1.5L', categoryName: 'İçecek', barcode: '1234567890134', averagePrice: 2.50 },
|
const list1 = await prisma.shoppingList.create({
|
||||||
{ name: 'Çay', categoryName: 'İçecek', barcode: '1234567890135', averagePrice: 35.00 },
|
data: {
|
||||||
{ name: 'Kahve', categoryName: 'İçecek', barcode: '1234567890136', averagePrice: 85.00 },
|
name: 'Haftalık Market',
|
||||||
{ name: 'Meyve Suyu', categoryName: 'İçecek', barcode: '1234567890148', averagePrice: 12.50 },
|
description: 'Bu hafta alınacaklar',
|
||||||
{ name: 'Kola', categoryName: 'İçecek', barcode: '1234567890149', averagePrice: 8.75 },
|
|
||||||
{ name: 'Ayran', categoryName: 'İçecek', barcode: '1234567890150', averagePrice: 4.50 },
|
|
||||||
|
|
||||||
// Et & Tavuk
|
|
||||||
{ name: 'Tavuk But', categoryName: 'Et & Tavuk', barcode: '1234567890151', averagePrice: 45.00 },
|
|
||||||
{ name: 'Dana Kıyma', categoryName: 'Et & Tavuk', barcode: '1234567890152', averagePrice: 120.00 },
|
|
||||||
{ name: 'Köfte', categoryName: 'Et & Tavuk', barcode: '1234567890153', averagePrice: 85.00 },
|
|
||||||
{ name: 'Sosis', categoryName: 'Et & Tavuk', barcode: '1234567890154', averagePrice: 25.00 },
|
|
||||||
|
|
||||||
// Temizlik
|
|
||||||
{ name: 'Deterjan', categoryName: 'Temizlik', barcode: '1234567890155', averagePrice: 45.00 },
|
|
||||||
{ name: 'Sabun', categoryName: 'Temizlik', barcode: '1234567890156', averagePrice: 8.50 },
|
|
||||||
{ name: 'Şampuan', categoryName: 'Temizlik', barcode: '1234567890157', averagePrice: 35.00 },
|
|
||||||
{ name: 'Diş Macunu', categoryName: 'Kişisel Bakım', barcode: '1234567890158', averagePrice: 18.50 },
|
|
||||||
|
|
||||||
// Atıştırmalık
|
|
||||||
{ name: 'Çikolata', categoryName: 'Atıştırmalık', barcode: '1234567890159', averagePrice: 12.50 },
|
|
||||||
{ name: 'Bisküvi', categoryName: 'Atıştırmalık', barcode: '1234567890160', averagePrice: 8.75 },
|
|
||||||
{ name: 'Cips', categoryName: 'Atıştırmalık', barcode: '1234567890161', averagePrice: 6.50 },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const productData of products) {
|
|
||||||
const category = await prisma.category.findUnique({
|
|
||||||
where: { name: productData.categoryName }
|
|
||||||
});
|
|
||||||
|
|
||||||
if (category) {
|
|
||||||
const product = await prisma.product.upsert({
|
|
||||||
where: { barcode: productData.barcode },
|
|
||||||
update: {},
|
|
||||||
create: {
|
|
||||||
name: productData.name,
|
|
||||||
barcode: productData.barcode,
|
|
||||||
categoryId: category.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
console.log('✅ Ürün oluşturuldu:', product.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Örnek alışveriş listeleri oluştur
|
|
||||||
const ahmetUser = await prisma.user.findUnique({
|
|
||||||
where: { email: 'ahmet@test.com' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const ayseUser = await prisma.user.findUnique({
|
|
||||||
where: { email: 'ayse@test.com' }
|
|
||||||
});
|
|
||||||
|
|
||||||
const mehmetUser = await prisma.user.findUnique({
|
|
||||||
where: { email: 'mehmet@test.com' }
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ahmet için alışveriş listeleri
|
|
||||||
if (ahmetUser) {
|
|
||||||
const shoppingLists = [
|
|
||||||
{
|
|
||||||
name: 'Haftalık Alışveriş',
|
|
||||||
description: 'Bu haftanın market alışverişi',
|
|
||||||
color: '#4CAF50',
|
color: '#4CAF50',
|
||||||
items: [
|
ownerId: user1.id,
|
||||||
{ productName: 'Elma', quantity: 2, unit: 'kg', price: 15.50 },
|
|
||||||
{ productName: 'Süt 1L', quantity: 1, unit: 'adet', price: 8.75 },
|
|
||||||
{ customName: 'Deterjan', quantity: 1, unit: 'adet', price: 25.00, note: 'Çamaşır deterjanı' },
|
|
||||||
{ productName: 'Ekmek', quantity: 2, unit: 'adet', price: 9.00 },
|
|
||||||
{ productName: 'Yumurta 30\'lu', quantity: 1, unit: 'adet', price: 85.00 },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Kahvaltı Malzemeleri',
|
|
||||||
description: 'Kahvaltı için gerekli ürünler',
|
|
||||||
color: '#FF9800',
|
|
||||||
items: [
|
|
||||||
{ productName: 'Ekmek', quantity: 2, unit: 'adet', price: 9.00 },
|
|
||||||
{ productName: 'Beyaz Peynir', quantity: 1, unit: 'kg', price: 45.00 },
|
|
||||||
{ productName: 'Tereyağı', quantity: 1, unit: 'adet', price: 35.00 },
|
|
||||||
{ productName: 'Domates', quantity: 1, unit: 'kg', price: 8.75 },
|
|
||||||
{ productName: 'Salatalık', quantity: 2, unit: 'adet', price: 13.00 },
|
|
||||||
{ productName: 'Çay', quantity: 1, unit: 'adet', price: 35.00 },
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
];
|
})
|
||||||
|
|
||||||
for (const listData of shoppingLists) {
|
// Listeye üye ekle
|
||||||
const shoppingList = await prisma.shoppingList.create({
|
await prisma.listMember.create({
|
||||||
data: {
|
data: {
|
||||||
name: listData.name,
|
userId: user2.id,
|
||||||
description: listData.description,
|
listId: list1.id,
|
||||||
color: listData.color,
|
role: 'admin'
|
||||||
ownerId: ahmetUser.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const itemData of listData.items) {
|
|
||||||
let productId = null;
|
|
||||||
|
|
||||||
if (itemData.productName) {
|
|
||||||
const product = await prisma.product.findFirst({
|
|
||||||
where: { name: itemData.productName }
|
|
||||||
});
|
|
||||||
if (product) {
|
|
||||||
productId = product.id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
|
||||||
await prisma.listItem.create({
|
// Liste Öğeleri (productId kullan)
|
||||||
|
await prisma.listItem.create({ data: { productId: products[0].id, quantity: 2, unit: 'kg', listId: list1.id } }) // Domates
|
||||||
|
await prisma.listItem.create({ data: { productId: products[1].id, quantity: 1, unit: 'kg', listId: list1.id } }) // Soğan
|
||||||
|
await prisma.listItem.create({ data: { productId: products[2].id, quantity: 3, unit: 'adet', listId: list1.id, isPurchased: true } }) // Salatalık
|
||||||
|
await prisma.listItem.create({ data: { productId: products[3].id, quantity: 1, unit: 'kg', listId: list1.id } }) // Tavuk
|
||||||
|
await prisma.listItem.create({ data: { productId: products[4].id, quantity: 0.5, unit: 'kg', listId: list1.id } }) // Kıyma
|
||||||
|
await prisma.listItem.create({ data: { productId: products[6].id, quantity: 2, unit: 'L', listId: list1.id, isPurchased: true } }) // Süt
|
||||||
|
await prisma.listItem.create({ data: { productId: products[7].id, quantity: 4, unit: 'adet', listId: list1.id } }) // Yoğurt
|
||||||
|
await prisma.listItem.create({ data: { productId: products[8].id, quantity: 2, unit: 'adet', listId: list1.id } }) // Ekmek
|
||||||
|
await prisma.listItem.create({ data: { productId: products[9].id, quantity: 6, unit: 'adet', listId: list1.id } }) // Cola
|
||||||
|
await prisma.listItem.create({ data: { productId: products[10].id, quantity: 1, unit: 'adet', listId: list1.id, isPurchased: true } }) // Deterjan
|
||||||
|
|
||||||
|
console.log('✅ İlk liste oluşturuldu')
|
||||||
|
|
||||||
|
// İkinci liste
|
||||||
|
const list2 = await prisma.shoppingList.create({
|
||||||
data: {
|
data: {
|
||||||
listId: shoppingList.id,
|
name: 'Bayram Alışverişi',
|
||||||
productId: productId,
|
description: 'Bayram için gerekli malzemeler',
|
||||||
customName: itemData.customName,
|
|
||||||
quantity: itemData.quantity,
|
|
||||||
unit: itemData.unit,
|
|
||||||
price: itemData.price,
|
|
||||||
note: itemData.note,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Alışveriş listesi oluşturuldu:', shoppingList.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ayşe için alışveriş listeleri
|
|
||||||
if (ayseUser) {
|
|
||||||
const ayseShoppingLists = [
|
|
||||||
{
|
|
||||||
name: 'Parti Alışverişi',
|
|
||||||
description: 'Doğum günü partisi için',
|
|
||||||
color: '#E91E63',
|
color: '#E91E63',
|
||||||
items: [
|
ownerId: user1.id,
|
||||||
{ productName: 'Kek', quantity: 1, unit: 'adet', price: 25.00 },
|
|
||||||
{ productName: 'Çikolata', quantity: 5, unit: 'adet', price: 62.50 },
|
|
||||||
{ productName: 'Bisküvi', quantity: 3, unit: 'paket', price: 26.25 },
|
|
||||||
{ productName: 'Kola', quantity: 6, unit: 'adet', price: 52.50 },
|
|
||||||
{ productName: 'Meyve Suyu', quantity: 4, unit: 'adet', price: 50.00 },
|
|
||||||
{ customName: 'Parti Süsleri', quantity: 1, unit: 'set', price: 45.00 },
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Temizlik Malzemeleri',
|
|
||||||
description: 'Ev temizliği için gerekli ürünler',
|
|
||||||
color: '#607D8B',
|
|
||||||
items: [
|
|
||||||
{ productName: 'Deterjan', quantity: 2, unit: 'adet', price: 90.00 },
|
|
||||||
{ productName: 'Sabun', quantity: 3, unit: 'adet', price: 25.50 },
|
|
||||||
{ productName: 'Şampuan', quantity: 1, unit: 'adet', price: 35.00 },
|
|
||||||
{ customName: 'Cam Temizleyici', quantity: 1, unit: 'adet', price: 18.50 },
|
|
||||||
{ customName: 'Yer Bezi', quantity: 2, unit: 'adet', price: 15.00 },
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
];
|
})
|
||||||
|
|
||||||
for (const listData of ayseShoppingLists) {
|
await prisma.listItem.create({ data: { productId: products[5].id, quantity: 2, unit: 'kg', listId: list2.id } }) // Kırmızı Et
|
||||||
const shoppingList = await prisma.shoppingList.create({
|
await prisma.listItem.create({ data: { productId: products[11].id, quantity: 1, unit: 'kg', listId: list2.id } }) // Baklava
|
||||||
data: {
|
await prisma.listItem.create({ data: { productId: products[12].id, quantity: 2, unit: 'L', listId: list2.id } }) // Dondurma
|
||||||
name: listData.name,
|
|
||||||
description: listData.description,
|
|
||||||
color: listData.color,
|
|
||||||
ownerId: ayseUser.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const itemData of listData.items) {
|
console.log('✅ İkinci liste oluşturuldu')
|
||||||
let productId = null;
|
|
||||||
|
|
||||||
if (itemData.productName) {
|
console.log('\n🎉 Örnek veriler başarıyla eklendi!')
|
||||||
const product = await prisma.product.findFirst({
|
console.log(` - 3 kullanıcı`)
|
||||||
where: { name: itemData.productName }
|
console.log(` - 8 kategori`)
|
||||||
});
|
console.log(` - ${await prisma.product.count()} ürün`)
|
||||||
if (product) {
|
console.log(` - 2 liste`)
|
||||||
productId = product.id;
|
console.log(` - 13 liste öğesi`)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.listItem.create({
|
|
||||||
data: {
|
|
||||||
listId: shoppingList.id,
|
|
||||||
productId: productId,
|
|
||||||
customName: itemData.customName,
|
|
||||||
quantity: itemData.quantity,
|
|
||||||
unit: itemData.unit,
|
|
||||||
price: itemData.price,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Alışveriş listesi oluşturuldu:', shoppingList.name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mehmet için alışveriş listesi
|
|
||||||
if (mehmetUser) {
|
|
||||||
const mehmetShoppingList = {
|
|
||||||
name: 'Et ve Protein',
|
|
||||||
description: 'Protein ihtiyacı için et ürünleri',
|
|
||||||
color: '#F44336',
|
|
||||||
items: [
|
|
||||||
{ productName: 'Tavuk But', quantity: 2, unit: 'kg', price: 90.00 },
|
|
||||||
{ productName: 'Dana Kıyma', quantity: 1, unit: 'kg', price: 120.00 },
|
|
||||||
{ productName: 'Köfte', quantity: 1, unit: 'kg', price: 85.00 },
|
|
||||||
{ productName: 'Sosis', quantity: 2, unit: 'paket', price: 50.00 },
|
|
||||||
{ productName: 'Yumurta 30\'lu', quantity: 1, unit: 'adet', price: 85.00 },
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const shoppingList = await prisma.shoppingList.create({
|
|
||||||
data: {
|
|
||||||
name: mehmetShoppingList.name,
|
|
||||||
description: mehmetShoppingList.description,
|
|
||||||
color: mehmetShoppingList.color,
|
|
||||||
ownerId: mehmetUser.id,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
for (const itemData of mehmetShoppingList.items) {
|
|
||||||
let productId = null;
|
|
||||||
|
|
||||||
if (itemData.productName) {
|
|
||||||
const product = await prisma.product.findFirst({
|
|
||||||
where: { name: itemData.productName }
|
|
||||||
});
|
|
||||||
if (product) {
|
|
||||||
productId = product.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.listItem.create({
|
|
||||||
data: {
|
|
||||||
listId: shoppingList.id,
|
|
||||||
productId: productId,
|
|
||||||
quantity: itemData.quantity,
|
|
||||||
unit: itemData.unit,
|
|
||||||
price: itemData.price,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Alışveriş listesi oluşturuldu:', shoppingList.name);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('✅ Tüm örnek alışveriş listeleri oluşturuldu');
|
|
||||||
|
|
||||||
// Sistem ayarları
|
|
||||||
const settings = [
|
|
||||||
{ key: 'app_name', value: 'HMarket', type: 'string' },
|
|
||||||
{ key: 'app_version', value: '1.0.0', type: 'string' },
|
|
||||||
{ key: 'max_list_members', value: '10', type: 'number' },
|
|
||||||
{ key: 'enable_notifications', value: 'true', type: 'boolean' },
|
|
||||||
{ key: 'default_currency', value: 'TL', type: 'string' },
|
|
||||||
];
|
|
||||||
|
|
||||||
for (const settingData of settings) {
|
|
||||||
await prisma.setting.upsert({
|
|
||||||
where: { key: settingData.key },
|
|
||||||
update: { value: settingData.value },
|
|
||||||
create: settingData,
|
|
||||||
});
|
|
||||||
console.log('✅ Ayar oluşturuldu:', settingData.key);
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('🎉 Seed işlemi tamamlandı!');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main()
|
main()
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
console.error('❌ Seed işlemi sırasında hata:', e);
|
console.error(e)
|
||||||
process.exit(1);
|
process.exit(1)
|
||||||
})
|
})
|
||||||
.finally(async () => {
|
.finally(async () => {
|
||||||
await prisma.$disconnect();
|
await prisma.$disconnect()
|
||||||
});
|
})
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
const passport = require('passport');
|
const passport = require('passport');
|
||||||
const GoogleStrategy = require('passport-google-oauth20').Strategy;
|
|
||||||
const { PrismaClient } = require('@prisma/client');
|
const { PrismaClient } = require('@prisma/client');
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
@@ -32,12 +31,15 @@ passport.deserializeUser(async (id, done) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Google OAuth Strategy
|
// Google OAuth Strategy - Sadece credentials varsa yükle
|
||||||
passport.use(new GoogleStrategy({
|
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,
|
clientID: process.env.GOOGLE_CLIENT_ID,
|
||||||
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
|
||||||
callbackURL: process.env.GOOGLE_CALLBACK_URL || "/api/auth/google/callback"
|
callbackURL: process.env.GOOGLE_CALLBACK_URL || "/api/auth/google/callback"
|
||||||
}, async (accessToken, refreshToken, profile, done) => {
|
}, async (accessToken, refreshToken, profile, done) => {
|
||||||
try {
|
try {
|
||||||
// Önce Google ID ile kullanıcı ara
|
// Önce Google ID ile kullanıcı ara
|
||||||
let user = await prisma.user.findUnique({
|
let user = await prisma.user.findUnique({
|
||||||
@@ -93,6 +95,7 @@ passport.use(new GoogleStrategy({
|
|||||||
console.error('Google OAuth Error:', error);
|
console.error('Google OAuth Error:', error);
|
||||||
return done(error, null);
|
return done(error, null);
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = passport;
|
module.exports = passport;
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
const express = require('express');
|
const express = require('express');
|
||||||
const { PrismaClient } = require('@prisma/client');
|
|
||||||
const { authenticateToken, checkListMembership, requireListEditPermission } = require('../middleware/auth');
|
const { authenticateToken, checkListMembership, requireListEditPermission } = require('../middleware/auth');
|
||||||
const { asyncHandler } = require('../middleware/errorHandler');
|
const { asyncHandler } = require('../middleware/errorHandler');
|
||||||
const {
|
const {
|
||||||
@@ -15,7 +14,6 @@ const { successResponse, errorResponse, calculatePagination, createPaginationMet
|
|||||||
const notificationService = require('../services/notificationService');
|
const notificationService = require('../services/notificationService');
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const prisma = new PrismaClient();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Liste öğelerini getir
|
* Liste öğelerini getir
|
||||||
@@ -68,8 +66,8 @@ router.get('/:listId',
|
|||||||
|
|
||||||
// Toplam sayı ve öğeleri getir
|
// Toplam sayı ve öğeleri getir
|
||||||
const [total, items] = await Promise.all([
|
const [total, items] = await Promise.all([
|
||||||
prisma.listItem.count({ where }),
|
req.prisma.listItem.count({ where }),
|
||||||
prisma.listItem.findMany({
|
req.prisma.listItem.findMany({
|
||||||
where,
|
where,
|
||||||
skip,
|
skip,
|
||||||
take,
|
take,
|
||||||
@@ -116,7 +114,7 @@ router.get('/:listId/:itemId',
|
|||||||
|
|
||||||
const { listId, itemId } = req.params;
|
const { listId, itemId } = req.params;
|
||||||
|
|
||||||
const item = await prisma.listItem.findFirst({
|
const item = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
listId
|
listId
|
||||||
@@ -179,7 +177,7 @@ router.post('/:listId',
|
|||||||
// Eğer productId verilmişse, ürünün var olduğunu kontrol et
|
// Eğer productId verilmişse, ürünün var olduğunu kontrol et
|
||||||
let product = null;
|
let product = null;
|
||||||
if (productId) {
|
if (productId) {
|
||||||
product = await prisma.product.findUnique({
|
product = await req.prisma.product.findUnique({
|
||||||
where: { id: productId }
|
where: { id: productId }
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,7 +187,7 @@ router.post('/:listId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Aynı öğenin listede zaten var olup olmadığını kontrol et
|
// Aynı öğenin listede zaten var olup olmadığını kontrol et
|
||||||
const existingItem = await prisma.listItem.findFirst({
|
const existingItem = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
listId,
|
listId,
|
||||||
OR: [
|
OR: [
|
||||||
@@ -204,7 +202,7 @@ router.post('/:listId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Yeni öğe oluştur
|
// Yeni öğe oluştur
|
||||||
const newItem = await prisma.listItem.create({
|
const newItem = await req.prisma.listItem.create({
|
||||||
data: {
|
data: {
|
||||||
customName: productId ? product.name : name,
|
customName: productId ? product.name : name,
|
||||||
quantity,
|
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ı)
|
// Ü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
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur
|
// Aktivite kaydı oluştur (geçici olarak devre dışı)
|
||||||
await prisma.activity.create({
|
// await req.prisma.activity.create({
|
||||||
data: {
|
// data: {
|
||||||
action: 'item_added',
|
// action: 'item_added',
|
||||||
details: {
|
// details: {
|
||||||
itemId: newItem.id,
|
// itemId: newItem.id,
|
||||||
itemName: newItem.customName || newItem.product?.name || 'Öğe',
|
// itemName: newItem.customName || newItem.product?.name || 'Öğe',
|
||||||
userName: `${req.user.firstName} ${req.user.lastName}`
|
// userName: `${req.user.firstName} ${req.user.lastName}`
|
||||||
},
|
// },
|
||||||
userId,
|
// userId,
|
||||||
listId
|
// 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(
|
// await notificationService.notifyListMembers(
|
||||||
// listId,
|
// listId,
|
||||||
// userId,
|
// userId,
|
||||||
@@ -254,14 +252,14 @@ router.post('/:listId',
|
|||||||
// { itemId: newItem.id, itemName: newItem.customName || newItem.product?.name }
|
// { itemId: newItem.id, itemName: newItem.customName || newItem.product?.name }
|
||||||
// );
|
// );
|
||||||
|
|
||||||
// Socket.IO ile gerçek zamanlı güncelleme
|
// Socket.IO ile gerçek zamanlı güncelleme (geçici olarak devre dışı)
|
||||||
const io = req.app.get('io');
|
// const io = req.app.get('io');
|
||||||
if (io) {
|
// if (io) {
|
||||||
io.to(`list_${listId}`).emit('itemAdded', {
|
// io.to(`list_${listId}`).emit('itemAdded', {
|
||||||
item: newItem,
|
// item: newItem,
|
||||||
addedBy: req.user
|
// addedBy: req.user
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Priority değerini string'e çevir
|
// Priority değerini string'e çevir
|
||||||
const newItemWithStringPriority = {
|
const newItemWithStringPriority = {
|
||||||
@@ -321,7 +319,7 @@ router.put('/:listId/:itemId',
|
|||||||
|
|
||||||
// Öğenin var olduğunu kontrol et
|
// Öğenin var olduğunu kontrol et
|
||||||
console.log('🔍 Öğe aranıyor:', { itemId, listId });
|
console.log('🔍 Öğe aranıyor:', { itemId, listId });
|
||||||
const existingItem = await prisma.listItem.findFirst({
|
const existingItem = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
listId
|
listId
|
||||||
@@ -364,7 +362,7 @@ router.put('/:listId/:itemId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Öğeyi güncelle
|
// Öğeyi güncelle
|
||||||
const updatedItem = await prisma.listItem.update({
|
const updatedItem = await req.prisma.listItem.update({
|
||||||
where: { id: itemId },
|
where: { id: itemId },
|
||||||
data: updateData,
|
data: updateData,
|
||||||
include: {
|
include: {
|
||||||
@@ -378,7 +376,7 @@ router.put('/:listId/:itemId',
|
|||||||
|
|
||||||
// Fiyat geçmişi ekle (eğer fiyat girilmişse ve ürün varsa)
|
// Fiyat geçmişi ekle (eğer fiyat girilmişse ve ürün varsa)
|
||||||
if (price && existingItem.productId && isPurchased) {
|
if (price && existingItem.productId && isPurchased) {
|
||||||
await prisma.priceHistory.create({
|
await req.prisma.priceHistory.create({
|
||||||
data: {
|
data: {
|
||||||
price: price,
|
price: price,
|
||||||
productId: existingItem.productId,
|
productId: existingItem.productId,
|
||||||
@@ -389,7 +387,7 @@ router.put('/:listId/:itemId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
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`;
|
: `${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: {
|
data: {
|
||||||
action: isPurchased !== undefined ? (isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED') : 'ITEM_UPDATED',
|
action: isPurchased !== undefined ? (isPurchased ? 'ITEM_PURCHASED' : 'ITEM_UNPURCHASED') : 'ITEM_UPDATED',
|
||||||
details: {
|
details: {
|
||||||
@@ -467,7 +465,7 @@ router.delete('/:listId/:itemId',
|
|||||||
const userId = req.user.id;
|
const userId = req.user.id;
|
||||||
|
|
||||||
// Öğenin var olduğunu kontrol et
|
// Öğenin var olduğunu kontrol et
|
||||||
const existingItem = await prisma.listItem.findFirst({
|
const existingItem = await req.prisma.listItem.findFirst({
|
||||||
where: {
|
where: {
|
||||||
id: itemId,
|
id: itemId,
|
||||||
listId
|
listId
|
||||||
@@ -479,19 +477,19 @@ router.delete('/:listId/:itemId',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Öğeyi sil
|
// Öğeyi sil
|
||||||
await prisma.listItem.delete({
|
await req.prisma.listItem.delete({
|
||||||
where: { id: itemId }
|
where: { id: itemId }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur (Prisma şemasına uygun)
|
// Aktivite kaydı oluştur (Prisma şemasına uygun)
|
||||||
const itemName = existingItem.customName || existingItem.product?.name || 'Öğe';
|
const itemName = existingItem.customName || existingItem.product?.name || 'Öğe';
|
||||||
await prisma.activity.create({
|
await req.prisma.activity.create({
|
||||||
data: {
|
data: {
|
||||||
action: 'ITEM_REMOVED',
|
action: 'ITEM_REMOVED',
|
||||||
details: {
|
details: {
|
||||||
@@ -551,7 +549,7 @@ router.patch('/:listId/bulk',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Öğelerin var olduğunu kontrol et
|
// Öğelerin var olduğunu kontrol et
|
||||||
const existingItems = await prisma.listItem.findMany({
|
const existingItems = await req.prisma.listItem.findMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: items },
|
id: { in: items },
|
||||||
listId
|
listId
|
||||||
@@ -593,14 +591,14 @@ router.patch('/:listId/bulk',
|
|||||||
|
|
||||||
// Toplu güncelleme veya silme
|
// Toplu güncelleme veya silme
|
||||||
if (action === 'delete') {
|
if (action === 'delete') {
|
||||||
await prisma.listItem.deleteMany({
|
await req.prisma.listItem.deleteMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: items },
|
id: { in: items },
|
||||||
listId
|
listId
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await prisma.listItem.updateMany({
|
await req.prisma.listItem.updateMany({
|
||||||
where: {
|
where: {
|
||||||
id: { in: items },
|
id: { in: items },
|
||||||
listId
|
listId
|
||||||
@@ -610,13 +608,13 @@ router.patch('/:listId/bulk',
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Liste güncelleme tarihini güncelle
|
// Liste güncelleme tarihini güncelle
|
||||||
await prisma.shoppingList.update({
|
await req.prisma.shoppingList.update({
|
||||||
where: { id: listId },
|
where: { id: listId },
|
||||||
data: { updatedAt: new Date() }
|
data: { updatedAt: new Date() }
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur
|
// Aktivite kaydı oluştur
|
||||||
await prisma.activity.create({
|
await req.prisma.activity.create({
|
||||||
data: {
|
data: {
|
||||||
type: activityType,
|
type: activityType,
|
||||||
description: activityDescription,
|
description: activityDescription,
|
||||||
|
|||||||
@@ -198,23 +198,25 @@ router.post('/', authenticateToken, [
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Aktivite kaydı oluştur
|
// Aktivite kaydı oluştur (geçici olarak devre dışı)
|
||||||
await req.prisma.activity.create({
|
// await req.prisma.activity.create({
|
||||||
data: {
|
// data: {
|
||||||
listId: list.id,
|
// listId: list.id,
|
||||||
userId: req.user.id,
|
// userId: req.user.id,
|
||||||
action: 'list_created',
|
// action: 'list_created',
|
||||||
details: {
|
// details: {
|
||||||
listName: list.name
|
// listName: list.name
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
|
|
||||||
// Socket.IO ile gerçek zamanlı bildirim gönder
|
// Socket.IO ile gerçek zamanlı bildirim gönder (geçici olarak devre dışı)
|
||||||
req.io.emit('list_created', {
|
// if (req.io) {
|
||||||
list: { ...list, userRole: 'owner' },
|
// req.io.emit('list_created', {
|
||||||
user: req.user
|
// list: { ...list, userRole: 'owner' },
|
||||||
});
|
// user: req.user
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
res.status(201).json({
|
res.status(201).json({
|
||||||
success: true,
|
success: true,
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ process.on('SIGINT', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Sunucuyu başlat
|
// Sunucuyu başlat
|
||||||
const PORT = process.env.PORT || 5000;
|
const PORT = process.env.PORT || 7001;
|
||||||
|
|
||||||
server.listen(PORT, () => {
|
server.listen(PORT, () => {
|
||||||
console.log(`🚀 Server ${PORT} portunda çalışıyor - port 7001`);
|
console.log(`🚀 Server ${PORT} portunda çalışıyor - port 7001`);
|
||||||
|
|||||||
@@ -9,6 +9,16 @@ class NotificationService {
|
|||||||
|
|
||||||
initializeFirebase() {
|
initializeFirebase() {
|
||||||
try {
|
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) {
|
if (!admin.apps.length) {
|
||||||
const serviceAccount = {
|
const serviceAccount = {
|
||||||
type: process.env.FIREBASE_TYPE,
|
type: process.env.FIREBASE_TYPE,
|
||||||
@@ -27,10 +37,11 @@ class NotificationService {
|
|||||||
credential: admin.credential.cert(serviceAccount)
|
credential: admin.credential.cert(serviceAccount)
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Firebase Admin SDK initialized successfully');
|
console.log('✅ Firebase Admin SDK initialized successfully');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Firebase initialization error:', error);
|
console.error('Firebase initialization error:', error.message);
|
||||||
|
console.warn('Push notifications will be disabled.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,13 +16,20 @@ function getDatabaseName(databaseUrl) {
|
|||||||
|
|
||||||
async function setupUtf8mb4(prisma) {
|
async function setupUtf8mb4(prisma) {
|
||||||
const databaseUrl = process.env.DATABASE_URL || '';
|
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);
|
const dbName = getDatabaseName(databaseUrl);
|
||||||
if (!dbName) {
|
if (!dbName) {
|
||||||
console.warn('⚠️ DATABASE_URL bulunamadı veya veritabanı adı çözümlenemedi. UTF8MB4 kurulumu atlandı.');
|
console.warn('⚠️ DATABASE_URL bulunamadı veya veritabanı adı çözümlenemedi. UTF8MB4 kurulumu atlandı.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try altering database charset/collation
|
// Only run for MySQL/MariaDB
|
||||||
try {
|
try {
|
||||||
await prisma.$executeRawUnsafe(`ALTER DATABASE \`${dbName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
|
await prisma.$executeRawUnsafe(`ALTER DATABASE \`${dbName}\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci`);
|
||||||
console.log('✅ Veritabanı varsayılan karakter seti/collation utf8mb4 olarak ayarlandı.');
|
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);
|
console.warn('⚠️ Veritabanı charset ayarlanırken hata oluştu:', err?.message || err);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try converting categories table
|
|
||||||
try {
|
try {
|
||||||
await prisma.$executeRawUnsafe('ALTER TABLE `categories` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci');
|
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ü.');
|
console.log('✅ `categories` tablosu utf8mb4 olarak dönüştürüldü.');
|
||||||
|
|||||||
13
frontend/package-lock.json
generated
13
frontend/package-lock.json
generated
@@ -15610,19 +15610,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss/node_modules/yaml": {
|
|
||||||
"version": "2.8.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.1.tgz",
|
|
||||||
"integrity": "sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==",
|
|
||||||
"optional": true,
|
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
|
||||||
"yaml": "bin.mjs"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 14.6"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/tapable": {
|
"node_modules/tapable": {
|
||||||
"version": "2.3.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz",
|
||||||
|
|||||||
@@ -1,63 +0,0 @@
|
|||||||
from PIL import Image, ImageDraw, ImageFilter
|
|
||||||
|
|
||||||
def create_hmarket_logo(path, size=512):
|
|
||||||
# Create image with transparent background
|
|
||||||
img = Image.new('RGBA', (size, size), (255, 255, 255, 0))
|
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
# Modern Blue/Teal Gradient simulation
|
|
||||||
# Let's draw a rounded rectangle background for the icon
|
|
||||||
padding = size // 8
|
|
||||||
rect_shape = [padding, padding, size - padding, size - padding]
|
|
||||||
corner_radius = size // 6
|
|
||||||
|
|
||||||
# Draw shadow
|
|
||||||
shadow_offset = size // 40
|
|
||||||
draw.rounded_rectangle(
|
|
||||||
[padding + shadow_offset, padding + shadow_offset, size - padding + shadow_offset, size - padding + shadow_offset],
|
|
||||||
radius=corner_radius,
|
|
||||||
fill=(0, 0, 0, 40)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Draw main background circle/rounded rect with gradient
|
|
||||||
for i in range(size - 2*padding):
|
|
||||||
# Color from #3a7bd5 to #00d2ff
|
|
||||||
r = int(58 + (0 - 58) * (i / (size - 2*padding)))
|
|
||||||
g = int(123 + (210 - 123) * (i / (size - 2*padding)))
|
|
||||||
b = int(213 + (255 - 213) * (i / (size - 2*padding)))
|
|
||||||
draw.line([padding + i, padding, padding + i, size - padding], fill=(r, g, b, 255))
|
|
||||||
|
|
||||||
# Redraw rounded corners mask (to make it look like a rounded rect icon)
|
|
||||||
mask = Image.new('L', (size, size), 0)
|
|
||||||
mask_draw = ImageDraw.Draw(mask)
|
|
||||||
mask_draw.rounded_rectangle(rect_shape, radius=corner_radius, fill=255)
|
|
||||||
|
|
||||||
# Apply mask to gradient
|
|
||||||
output = Image.new('RGBA', (size, size), (255, 255, 255, 0))
|
|
||||||
output.paste(img, (0, 0), mask=mask)
|
|
||||||
|
|
||||||
# Draw Shopping Cart Icon (Simplified white vector style)
|
|
||||||
draw_icon = ImageDraw.Draw(output)
|
|
||||||
s = size // 10 # scale factor
|
|
||||||
|
|
||||||
# Cart body
|
|
||||||
cart_color = (255, 255, 255, 255)
|
|
||||||
# Handle and frame
|
|
||||||
draw_icon.line([3*s, 3*s, 3.5*s, 3*s, 4*s, 6*s, 7.5*s, 6*s], fill=cart_color, width=s//3)
|
|
||||||
# Basket
|
|
||||||
draw_icon.polygon([4*s, 4*s, 7.5*s, 4*s, 7*s, 5.5*s, 4.5*s, 5.5*s], fill=cart_color)
|
|
||||||
# Wheels
|
|
||||||
draw_icon.ellipse([4.2*s, 6.2*s, 4.8*s, 6.8*s], fill=cart_color)
|
|
||||||
draw_icon.ellipse([6.7*s, 6.2*s, 7.3*s, 6.8*s], fill=cart_color)
|
|
||||||
|
|
||||||
# Save
|
|
||||||
output.save(path)
|
|
||||||
return output
|
|
||||||
|
|
||||||
# Generate both sizes
|
|
||||||
logo512 = create_hmarket_logo("/home/hololu/calismalar/hMarket/frontend/public/logo512.png", 512)
|
|
||||||
logo192 = logo512.resize((192, 192), Image.LANCZOS)
|
|
||||||
logo192.save("/home/hololu/calismalar/hMarket/frontend/public/logo192.png")
|
|
||||||
logo512.save("/home/hololu/calismalar/hmarket-logo.png") # Extra copy for OAuth screen
|
|
||||||
|
|
||||||
print("Logolar başarıyla oluşturuldu.")
|
|
||||||
@@ -1,60 +0,0 @@
|
|||||||
from PIL import Image, ImageDraw
|
|
||||||
|
|
||||||
def create_orange_logo(path, size=512):
|
|
||||||
# Base image
|
|
||||||
img = Image.new('RGBA', (size, size), (255, 255, 255, 0))
|
|
||||||
draw = ImageDraw.Draw(img)
|
|
||||||
|
|
||||||
# Background color #FF5722
|
|
||||||
bg_color = (255, 87, 34, 255)
|
|
||||||
|
|
||||||
padding = size // 10
|
|
||||||
corner_radius = size // 6
|
|
||||||
draw.rounded_rectangle(
|
|
||||||
[padding, padding, size - padding, size - padding],
|
|
||||||
radius=corner_radius,
|
|
||||||
fill=bg_color
|
|
||||||
)
|
|
||||||
|
|
||||||
# Scale for the 24x24 SVG path
|
|
||||||
# We want the icon to fit in the center, say 60% of the box
|
|
||||||
icon_size = size * 0.55
|
|
||||||
offset = (size - icon_size) / 2
|
|
||||||
scale = icon_size / 24
|
|
||||||
|
|
||||||
def scale_pt(x, y):
|
|
||||||
return (offset + x * scale, offset + y * scale)
|
|
||||||
|
|
||||||
# Drawing the cart manually based on the SVG path logic
|
|
||||||
# Wheels
|
|
||||||
r_wheel = 1 * scale
|
|
||||||
w1_c = scale_pt(7, 20)
|
|
||||||
draw.ellipse([w1_c[0]-r_wheel, w1_c[1]-r_wheel, w1_c[0]+r_wheel, w1_c[1]+r_wheel], fill="white")
|
|
||||||
|
|
||||||
w2_c = scale_pt(17, 20)
|
|
||||||
draw.ellipse([w2_c[0]-r_wheel, w2_c[1]-r_wheel, w2_c[0]+r_wheel, w2_c[1]+r_wheel], fill="white")
|
|
||||||
|
|
||||||
# The main body path
|
|
||||||
# M1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2z
|
|
||||||
# Simplified polygon for the cart body
|
|
||||||
points = [
|
|
||||||
scale_pt(1, 2), scale_pt(1, 4), scale_pt(3, 4),
|
|
||||||
scale_pt(6.6, 11.59), scale_pt(5.25, 14.04),
|
|
||||||
scale_pt(5.25, 15), scale_pt(7, 17), scale_pt(19, 17),
|
|
||||||
scale_pt(19, 15), scale_pt(7.42, 15), scale_pt(8.35, 13.37),
|
|
||||||
scale_pt(15.8, 13.37), scale_pt(17.55, 12.34), scale_pt(21.13, 5.85),
|
|
||||||
scale_pt(21.25, 5.37), scale_pt(20.25, 4.37), scale_pt(5.21, 4.37),
|
|
||||||
scale_pt(4.27, 2.37)
|
|
||||||
]
|
|
||||||
draw.polygon(points, fill="white")
|
|
||||||
|
|
||||||
# Save
|
|
||||||
img.save(path)
|
|
||||||
|
|
||||||
create_orange_logo("/home/hololu/calismalar/hMarket/frontend/public/logo512.png", 512)
|
|
||||||
create_orange_logo("/home/hololu/calismalar/hmarket-logo.png", 512)
|
|
||||||
img_512 = Image.open("/home/hololu/calismalar/hMarket/frontend/public/logo512.png")
|
|
||||||
img_192 = img_512.resize((192, 192), Image.LANCZOS)
|
|
||||||
img_192.save("/home/hololu/calismalar/hMarket/frontend/public/logo192.png")
|
|
||||||
|
|
||||||
print("Yeni turuncu logolar oluşturuldu.")
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
{"email":"admin@hmarket.com","password":"admin123"}
|
|
||||||
@@ -1,39 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<style>
|
|
||||||
body {
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
width: 512px;
|
|
||||||
height: 512px;
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
.container {
|
|
||||||
width: 440px;
|
|
||||||
height: 440px;
|
|
||||||
background: #FF5722;
|
|
||||||
border-radius: 80px;
|
|
||||||
display: flex;
|
|
||||||
justify-content: center;
|
|
||||||
align-items: center;
|
|
||||||
box-shadow: 0 20px 40px rgba(255, 87, 34, 0.3);
|
|
||||||
}
|
|
||||||
svg {
|
|
||||||
width: 280px;
|
|
||||||
height: 280px;
|
|
||||||
fill: white;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<svg viewBox="0 0 24 24">
|
|
||||||
<path d="M7 18c-1.1 0-1.99.9-1.99 2S5.9 22 7 22s2-.9 2-2-.9-2-2-2M1 2v2h2l3.6 7.59-1.35 2.45c-.16.28-.25.61-.25.96 0 1.1.9 2 2 2h12v-2H7.42c-.14 0-.25-.11-.25-.25l.03-.12.9-1.63h7.45c.75 0 1.41-.41 1.75-1.03l3.58-6.49c.08-.14.12-.31.12-.48 0-.55-.45-1-1-1H5.21l-.94-2zm16 16c-1.1 0-1.99.9-1.99 2s.89 2 1.99 2 2-.9 2-2-.9-2-2-2"></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"login": "ahmet@test.com",
|
|
||||||
"password": "test123"
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user