Migrate to local PG & Update Solana Checkout
This commit is contained in:
56
app/api/auth/login/route.ts
Normal file
56
app/api/auth/login/route.ts
Normal file
@@ -0,0 +1,56 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { db } from '@/lib/db';
|
||||
import bcrypt from 'bcryptjs';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'super-secret-key-12345';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const { email, password } = await request.json();
|
||||
|
||||
if (!email || !password) {
|
||||
return NextResponse.json({ error: 'Email ve şifre zorunludur.' }, { status: 400 });
|
||||
}
|
||||
|
||||
const res = await db.query('SELECT * FROM admin_users WHERE email = $1', [email]);
|
||||
const user = res.rows[0];
|
||||
|
||||
if (!user || (!user.password_hash && password !== 'password123')) {
|
||||
return NextResponse.json({ error: 'Geçersiz email veya şifre.' }, { status: 401 });
|
||||
}
|
||||
|
||||
// Verify password
|
||||
let isValid = false;
|
||||
if (user.password_hash) {
|
||||
isValid = await bcrypt.compare(password, user.password_hash);
|
||||
} else if (password === 'password123') { // Fallback if someone forgot to run the init script
|
||||
isValid = true;
|
||||
}
|
||||
|
||||
if (!isValid) {
|
||||
return NextResponse.json({ error: 'Geçersiz email veya şifre.' }, { status: 401 });
|
||||
}
|
||||
|
||||
// Generate token
|
||||
const token = jwt.sign({ id: user.id, email: user.email }, JWT_SECRET, {
|
||||
expiresIn: '1d',
|
||||
});
|
||||
|
||||
// Set cookie
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.set('admin_session', token, {
|
||||
httpOnly: true,
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'lax',
|
||||
path: '/',
|
||||
maxAge: 60 * 60 * 24, // 1 day
|
||||
});
|
||||
|
||||
return NextResponse.json({ success: true, user: { id: user.id, email: user.email } });
|
||||
} catch (error: any) {
|
||||
console.error('Login error:', error);
|
||||
return NextResponse.json({ error: 'Giriş sırasında bir hata oluştu.' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
8
app/api/auth/logout/route.ts
Normal file
8
app/api/auth/logout/route.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { cookies } from 'next/headers';
|
||||
|
||||
export async function POST() {
|
||||
const cookieStore = await cookies();
|
||||
cookieStore.delete('admin_session');
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
@@ -1,36 +1,40 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { stripe } from '@/lib/stripe';
|
||||
import { supabaseAdmin } from '@/lib/supabase-admin';
|
||||
import { db } from '@/lib/db';
|
||||
import { PaymentProviderFactory } from '@/lib/payment-providers';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const { amount, currency, ref_id, callback_url, customer_name, customer_phone, merchant_id } = await req.json();
|
||||
|
||||
if (!amount || !currency || !merchant_id) {
|
||||
if (!amount || !currency) {
|
||||
return NextResponse.json(
|
||||
{ error: 'Tutar, para birimi ve firma ID zorunludur.' },
|
||||
{ error: 'Tutar ve para birimi zorunludur.' },
|
||||
{ status: 400 }
|
||||
);
|
||||
}
|
||||
|
||||
let merchant;
|
||||
// 1. Fetch Merchant to check provider (Support both UUID and Short ID)
|
||||
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(merchant_id);
|
||||
|
||||
const query = supabaseAdmin
|
||||
.from('merchants')
|
||||
.select('*');
|
||||
|
||||
if (isUUID) {
|
||||
query.eq('id', merchant_id);
|
||||
if (merchant_id) {
|
||||
const isUUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(merchant_id);
|
||||
let result;
|
||||
if (isUUID) {
|
||||
result = await db.query('SELECT * FROM merchants WHERE id = $1', [merchant_id]);
|
||||
} else {
|
||||
result = await db.query('SELECT * FROM merchants WHERE short_id = $1', [merchant_id]);
|
||||
}
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return NextResponse.json({ error: 'Firma bulunamadı.' }, { status: 404 });
|
||||
}
|
||||
merchant = result.rows[0];
|
||||
} else {
|
||||
query.eq('short_id', merchant_id);
|
||||
}
|
||||
|
||||
const { data: merchant, error: merchantError } = await query.single();
|
||||
|
||||
if (merchantError || !merchant) {
|
||||
return NextResponse.json({ error: 'Firma bulunamadı.' }, { status: 404 });
|
||||
// For demo purposes on the landing page, fetch any existing merchant
|
||||
const result = await db.query('SELECT * FROM merchants LIMIT 1');
|
||||
if (result.rows.length === 0) {
|
||||
return NextResponse.json({ error: 'Sistemde kayıtlı firma bulunamadı (Önce admin panelinden firma ekleyin).' }, { status: 404 });
|
||||
}
|
||||
merchant = result.rows[0];
|
||||
}
|
||||
|
||||
// Use the actual UUID for DB operations
|
||||
@@ -67,26 +71,19 @@ export async function POST(req: NextRequest) {
|
||||
}
|
||||
|
||||
// 3. Log transaction in Supabase
|
||||
const { error: dbError } = await supabaseAdmin
|
||||
.from('transactions')
|
||||
.insert({
|
||||
amount,
|
||||
currency,
|
||||
status: 'pending',
|
||||
stripe_pi_id: providerTxId, // We keep using this column for now or we could use provider_tx_id if we updated schema
|
||||
source_ref_id: ref_id,
|
||||
customer_name,
|
||||
customer_phone,
|
||||
callback_url,
|
||||
merchant_id: resolvedMerchantId,
|
||||
provider: provider,
|
||||
metadata: {
|
||||
nextAction,
|
||||
redirectUrl
|
||||
}
|
||||
});
|
||||
|
||||
if (dbError) {
|
||||
try {
|
||||
await db.query(`
|
||||
INSERT INTO transactions (
|
||||
amount, currency, status, stripe_pi_id, source_ref_id,
|
||||
customer_name, customer_phone, callback_url, merchant_id,
|
||||
provider, metadata
|
||||
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
||||
`, [
|
||||
amount, currency, 'pending', providerTxId, ref_id,
|
||||
customer_name, customer_phone, callback_url, resolvedMerchantId,
|
||||
provider, JSON.stringify({ nextAction, redirectUrl })
|
||||
]);
|
||||
} catch (dbError) {
|
||||
console.error('Database log error:', dbError);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,27 +1,66 @@
|
||||
import { NextResponse } from 'next/server';
|
||||
import { CryptoEngine } from '@/lib/crypto-engine';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { txId, merchantAddress } = body;
|
||||
const { txId, merchantAddress, amount, currency } = body;
|
||||
|
||||
// In a real app, you would fetch the private key for this txId from a secure DB/Vault
|
||||
// For demo: We just simulate the result of a sweep
|
||||
|
||||
console.log(`[API] Checking and Sweeping for Transaction: ${txId}`);
|
||||
|
||||
// Mock success response
|
||||
// This is a demo integration. In a real application:
|
||||
// 1. We would look up the transaction ID from the DB
|
||||
// 2. Fetch the temporary wallet private key created for that specific TX
|
||||
// 3. We use the platform address defined in our .env or settings
|
||||
|
||||
// For this demo, we'll use the user's devnet wallet as both the source (temp wallet) and platform
|
||||
const demoTempWalletPrivKey = "3Ab6AyfDDWquPJ6ySjHmQmiW3USg7CuDxJSNtrNQySsXj5v4KfBKcw9vnK1Rrfwm6RYq43PdKjiNZekgtNzGsNm2";
|
||||
const platformAddress = "5pLH1tqZhx8p8WpZ18yr28N42KXB3FXVPzZ9ceCtpBVe";
|
||||
|
||||
// Ensure we have a merchant address or use a fallback for testing
|
||||
const targetMerchant = merchantAddress || "5pLH1tqZhx8p8WpZ18yr28N42KXB3FXVPzZ9ceCtpBVe"; // using same for demo
|
||||
|
||||
// Initialize Crypto Engine for Solana
|
||||
const cryptoEngine = new CryptoEngine('SOLANA');
|
||||
|
||||
console.log("Starting Sweep Process on SOLANA DEVNET...");
|
||||
|
||||
// Attempt the sweep (this will do a real devnet transaction if uncommented in engine)
|
||||
const sweepResult = await cryptoEngine.sweepFunds(
|
||||
demoTempWalletPrivKey,
|
||||
targetMerchant,
|
||||
platformAddress,
|
||||
'SOL' // Using native SOL for demo
|
||||
);
|
||||
|
||||
if (!sweepResult.success) {
|
||||
throw new Error("Süpürme işlemi başarısız oldu.");
|
||||
}
|
||||
|
||||
// --- UPDATE DATABASE STATUS ---
|
||||
// Marks the transaction as succeeded so it updates in the Admin dashboard
|
||||
try {
|
||||
await db.query(
|
||||
`UPDATE transactions
|
||||
SET status = 'succeeded'
|
||||
WHERE stripe_pi_id = $1`,
|
||||
[txId]
|
||||
);
|
||||
} catch (dbError) {
|
||||
console.error('[API] Failed to update transaction status in DB:', dbError);
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
success: true,
|
||||
message: "Ödeme başarıyla doğrulandı ve dağıtıldı.",
|
||||
message: "Ödeme başarıyla doğrulandı ve dağıtıldı (Solana Devnet).",
|
||||
split: {
|
||||
platform: "1.00 USDT (%1)",
|
||||
merchant: "99.00 USDT (%99)"
|
||||
platform: "%1",
|
||||
merchant: "%99"
|
||||
},
|
||||
hashes: {
|
||||
platform: "0x" + Math.random().toString(16).slice(2, 66),
|
||||
merchant: "0x" + Math.random().toString(16).slice(2, 66)
|
||||
platform: sweepResult.platformTx,
|
||||
merchant: sweepResult.merchantTx
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { supabaseAdmin } from '@/lib/supabase-admin';
|
||||
import { db } from '@/lib/db';
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
@@ -22,24 +22,21 @@ export async function POST(req: NextRequest) {
|
||||
return result;
|
||||
};
|
||||
|
||||
const { data, error } = await supabaseAdmin
|
||||
.from('merchants')
|
||||
.insert([{
|
||||
name,
|
||||
webhook_url,
|
||||
short_id: generateShortId(),
|
||||
payment_provider: payment_provider || 'stripe',
|
||||
provider_config: provider_config || {}
|
||||
}])
|
||||
.select()
|
||||
.single();
|
||||
const shortId = generateShortId();
|
||||
const provider = payment_provider || 'stripe';
|
||||
const configStr = provider_config ? JSON.stringify(provider_config) : '{}';
|
||||
|
||||
if (error) {
|
||||
console.error('Merchant creation error:', error);
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
const result = await db.query(
|
||||
`INSERT INTO merchants (name, webhook_url, short_id, payment_provider, provider_config)
|
||||
VALUES ($1, $2, $3, $4, $5) RETURNING *`,
|
||||
[name, webhook_url, shortId, provider, configStr]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
throw new Error('Could not insert merchant');
|
||||
}
|
||||
|
||||
return NextResponse.json(data);
|
||||
return NextResponse.json(result.rows[0]);
|
||||
} catch (err: any) {
|
||||
console.error('Internal Error:', err);
|
||||
return NextResponse.json(
|
||||
@@ -51,16 +48,8 @@ export async function POST(req: NextRequest) {
|
||||
|
||||
export async function GET() {
|
||||
try {
|
||||
const { data, error } = await supabaseAdmin
|
||||
.from('merchants')
|
||||
.select('*')
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
if (error) {
|
||||
return NextResponse.json({ error: error.message }, { status: 500 });
|
||||
}
|
||||
|
||||
return NextResponse.json(data);
|
||||
const result = await db.query('SELECT * FROM merchants ORDER BY created_at DESC');
|
||||
return NextResponse.json(result.rows);
|
||||
} catch (err: any) {
|
||||
return NextResponse.json(
|
||||
{ error: `Internal Server Error: ${err.message}` },
|
||||
|
||||
Reference in New Issue
Block a user