const express = require('express'); const path = require('path'); const fs = require('fs').promises; const session = require('express-session'); const cookieParser = require('cookie-parser'); const app = express(); const PORT = process.env.PORT || 3000; // Middleware app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser()); app.use(session({ secret: 'jawara88-lucky-spin-secret-key', resave: false, saveUninitialized: false, cookie: { maxAge: 24 * 60 * 60 * 1000 } // 24 jam })); // Serve static files app.use(express.static('public_html/Luckyspin_jawara88')); // Data paths const DATA_DIR = path.join(__dirname, 'data'); const HISTORY_FILE = path.join(DATA_DIR, 'history.json'); const COUPONS_FILE = path.join(DATA_DIR, 'coupons.json'); // Initialize data files async function initializeDataFiles() { try { await fs.access(DATA_DIR); } catch { await fs.mkdir(DATA_DIR, { recursive: true }); } try { await fs.access(HISTORY_FILE); } catch { await fs.writeFile(HISTORY_FILE, JSON.stringify([])); } try { await fs.access(COUPONS_FILE); } catch { await fs.writeFile(COUPONS_FILE, JSON.stringify([])); } } // Helper functions async function readJSON(filePath) { try { const data = await fs.readFile(filePath, 'utf8'); return JSON.parse(data); } catch { return []; } } async function writeJSON(filePath, data) { await fs.writeFile(filePath, JSON.stringify(data, null, 2)); } // Admin authentication middleware function isAdmin(req, res, next) { if (req.session.isAdmin) { next(); } else { res.status(401).json({ error: 'Unauthorized' }); } } // Routes // Admin login app.post('/api/admin/login', (req, res) => { const { username, password } = req.body; // Credentials (ganti sesuai kebutuhan) if (username === 'admin' && password === 'jawara88admin') { req.session.isAdmin = true; res.json({ success: true }); } else { res.status(401).json({ error: 'Invalid credentials' }); } }); // Admin logout app.post('/api/admin/logout', (req, res) => { req.session.destroy(); res.json({ success: true }); }); // Check admin status app.get('/api/admin/check', (req, res) => { res.json({ isAdmin: !!req.session.isAdmin }); }); // Get spin prizes configuration app.get('/api/prizes', (req, res) => { const prizes = [ { id: 1, name: 'Freespin 10x', color: '#FF6B6B', probability: 15 }, { id: 2, name: 'Bonus 50K', color: '#4ECDC4', probability: 10 }, { id: 3, name: 'Freespin 5x', color: '#FFE66D', probability: 20 }, { id: 4, name: 'Cashback 10%', color: '#95E1D3', probability: 15 }, { id: 5, name: 'Freespin 20x', color: '#F38181', probability: 8 }, { id: 6, name: 'Bonus 100K', color: '#AA96DA', probability: 5 }, { id: 7, name: 'Freespin 3x', color: '#FCBAD3', probability: 20 }, { id: 8, name: 'Try Again', color: '#A8D8EA', probability: 7 } ]; res.json(prizes); }); // Spin the wheel app.post('/api/spin', async (req, res) => { const { username, phone } = req.body; if (!username || !phone) { return res.status(400).json({ error: 'Username dan nomor telepon harus diisi' }); } try { // Get prizes const prizes = [ { id: 1, name: 'Freespin 10x', probability: 15 }, { id: 2, name: 'Bonus 50K', probability: 10 }, { id: 3, name: 'Freespin 5x', probability: 20 }, { id: 4, name: 'Cashback 10%', probability: 15 }, { id: 5, name: 'Freespin 20x', probability: 8 }, { id: 6, name: 'Bonus 100K', probability: 5 }, { id: 7, name: 'Freespin 3x', probability: 20 }, { id: 8, name: 'Try Again', probability: 7 } ]; // Select prize based on probability const totalProbability = prizes.reduce((sum, p) => sum + p.probability, 0); let random = Math.random() * totalProbability; let selectedPrize = prizes[0]; for (const prize of prizes) { random -= prize.probability; if (random <= 0) { selectedPrize = prize; break; } } // Generate coupon code const couponCode = 'JWR' + Math.random().toString(36).substr(2, 9).toUpperCase(); // Save to history const history = await readJSON(HISTORY_FILE); const spinRecord = { id: Date.now(), username, phone, prize: selectedPrize.name, couponCode, timestamp: new Date().toISOString(), claimed: false }; history.unshift(spinRecord); await writeJSON(HISTORY_FILE, history); // Save coupon if (selectedPrize.name !== 'Try Again') { const coupons = await readJSON(COUPONS_FILE); coupons.unshift({ code: couponCode, prize: selectedPrize.name, username, phone, createdAt: new Date().toISOString(), used: false }); await writeJSON(COUPONS_FILE, coupons); } res.json({ success: true, prize: selectedPrize.name, prizeId: selectedPrize.id, couponCode: selectedPrize.name !== 'Try Again' ? couponCode : null }); } catch (error) { console.error('Spin error:', error); res.status(500).json({ error: 'Terjadi kesalahan server' }); } }); // Get spin history (Admin only) app.get('/api/admin/history', isAdmin, async (req, res) => { try { const history = await readJSON(HISTORY_FILE); res.json(history); } catch (error) { res.status(500).json({ error: 'Failed to load history' }); } }); // Get coupons (Admin only) app.get('/api/admin/coupons', isAdmin, async (req, res) => { try { const coupons = await readJSON(COUPONS_FILE); res.json(coupons); } catch (error) { res.status(500).json({ error: 'Failed to load coupons' }); } }); // Mark coupon as used (Admin only) app.post('/api/admin/coupon/use', isAdmin, async (req, res) => { try { const { code } = req.body; const coupons = await readJSON(COUPONS_FILE); const coupon = coupons.find(c => c.code === code); if (coupon) { coupon.used = true; coupon.usedAt = new Date().toISOString(); await writeJSON(COUPONS_FILE, coupons); res.json({ success: true }); } else { res.status(404).json({ error: 'Coupon not found' }); } } catch (error) { res.status(500).json({ error: 'Failed to update coupon' }); } }); // Delete history record (Admin only) app.delete('/api/admin/history/:id', isAdmin, async (req, res) => { try { const id = parseInt(req.params.id); let history = await readJSON(HISTORY_FILE); history = history.filter(h => h.id !== id); await writeJSON(HISTORY_FILE, history); res.json({ success: true }); } catch (error) { res.status(500).json({ error: 'Failed to delete record' }); } }); // Start server initializeDataFiles().then(() => { app.listen(PORT, () => { console.log(`Lucky Spin server running on port ${PORT}`); }); });