From 3ea10e9c784737ffe3f46a42bffc318c6f841994 Mon Sep 17 00:00:00 2001 From: hpibot Date: Sun, 1 Mar 2026 20:26:44 +0300 Subject: [PATCH] =?UTF-8?q?nanobot=20=C3=B6zel=20s=C3=BCr=C3=BCm=20v1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backend/package-lock.json | 1 - backend/prisma/dev.db | Bin 0 -> 147456 bytes backend/prisma/schema.prisma | 10 +- backend/prisma/seed.js | 460 +++++--------------- backend/src/config/passport.js | 107 ++--- backend/src/routes/items.js | 88 ++-- backend/src/routes/lists.js | 34 +- backend/src/server.js | 2 +- backend/src/services/notificationService.js | 15 +- backend/src/utils/dbCharsetSetup.js | 10 +- frontend/package-lock.json | 13 - generate_logo.py | 63 --- generate_logo_orange.py | 60 --- login.json | 1 - logo_temp.html | 39 -- test-login.json | 4 - 16 files changed, 248 insertions(+), 659 deletions(-) create mode 100644 backend/prisma/dev.db delete mode 100644 generate_logo.py delete mode 100644 generate_logo_orange.py delete mode 100644 login.json delete mode 100644 logo_temp.html delete mode 100644 test-login.json diff --git a/backend/package-lock.json b/backend/package-lock.json index 33b974f..d9f549b 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -3075,7 +3075,6 @@ "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, "hasInstallScript": true, "optional": true, "os": [ diff --git a/backend/prisma/dev.db b/backend/prisma/dev.db new file mode 100644 index 0000000000000000000000000000000000000000..f463731649d43a13a46c5f5408ced9c0569bd52c GIT binary patch literal 147456 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 { - console.error('❌ Seed işlemi sırasında hata:', e); - process.exit(1); + console.error(e) + process.exit(1) }) .finally(async () => { - await prisma.$disconnect(); - }); \ No newline at end of file + await prisma.$disconnect() + }) diff --git a/backend/src/config/passport.js b/backend/src/config/passport.js index c7144c7..d40cebd 100644 --- a/backend/src/config/passport.js +++ b/backend/src/config/passport.js @@ -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; \ No newline at end of file diff --git a/backend/src/routes/items.js b/backend/src/routes/items.js index 265c4e0..c540412 100644 --- a/backend/src/routes/items.js +++ b/backend/src/routes/items.js @@ -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, diff --git a/backend/src/routes/lists.js b/backend/src/routes/lists.js index 7d1f9ba..5d9cdba 100644 --- a/backend/src/routes/lists.js +++ b/backend/src/routes/lists.js @@ -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, diff --git a/backend/src/server.js b/backend/src/server.js index 2b2dc32..e930aba 100644 --- a/backend/src/server.js +++ b/backend/src/server.js @@ -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`); diff --git a/backend/src/services/notificationService.js b/backend/src/services/notificationService.js index 054c039..19cb1d3 100644 --- a/backend/src/services/notificationService.js +++ b/backend/src/services/notificationService.js @@ -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.'); } } diff --git a/backend/src/utils/dbCharsetSetup.js b/backend/src/utils/dbCharsetSetup.js index 0fa78dc..d68618b 100644 --- a/backend/src/utils/dbCharsetSetup.js +++ b/backend/src/utils/dbCharsetSetup.js @@ -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ü.'); diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 34e7ccc..20c5a62 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -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": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.0.tgz", diff --git a/generate_logo.py b/generate_logo.py deleted file mode 100644 index a30ff15..0000000 --- a/generate_logo.py +++ /dev/null @@ -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.") diff --git a/generate_logo_orange.py b/generate_logo_orange.py deleted file mode 100644 index e9a4462..0000000 --- a/generate_logo_orange.py +++ /dev/null @@ -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.") diff --git a/login.json b/login.json deleted file mode 100644 index c930974..0000000 --- a/login.json +++ /dev/null @@ -1 +0,0 @@ -{"email":"admin@hmarket.com","password":"admin123"} \ No newline at end of file diff --git a/logo_temp.html b/logo_temp.html deleted file mode 100644 index 36a31a0..0000000 --- a/logo_temp.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - -
- - - -
- - diff --git a/test-login.json b/test-login.json deleted file mode 100644 index 8ab1bc2..0000000 --- a/test-login.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "login": "ahmet@test.com", - "password": "test123" -} \ No newline at end of file