mirror of
https://github.com/itsnaveenk/bazar3.git
synced 2025-12-19 19:37:06 +00:00
1
This commit is contained in:
commit
c1433aa070
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
node_modules/
|
||||
.env
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
.DS_Store
|
||||
.idea/
|
||||
dist/
|
||||
coverage/
|
||||
39
server/auth.js
Normal file
39
server/auth.js
Normal file
@ -0,0 +1,39 @@
|
||||
const argon2 = require('argon2');
|
||||
const speakeasy = require('speakeasy');
|
||||
|
||||
// Generate Admin Credentials
|
||||
const createAdmin = async (password) => {
|
||||
const accessKey = crypto.randomBytes(16).toString('hex');
|
||||
const hash = await argon2.hash(password);
|
||||
const totpSecret = speakeasy.generateSecret({ length: 20 });
|
||||
|
||||
return {
|
||||
accessKey,
|
||||
hash,
|
||||
totpSecret: totpSecret.base32
|
||||
};
|
||||
};
|
||||
|
||||
// Verify Admin Login
|
||||
const verifyAdmin = async (accessKey, password, token) => {
|
||||
// 1. Fetch admin from DB
|
||||
const { rows: [admin] } = await db.query(
|
||||
'SELECT * FROM admins WHERE access_key = $1',
|
||||
[accessKey]
|
||||
);
|
||||
|
||||
// 2. Verify password
|
||||
if (!admin || !await argon2.verify(admin.argon2_hash, password)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 3. Verify TOTP
|
||||
return speakeasy.totp.verify({
|
||||
secret: admin.totp_secret,
|
||||
encoding: 'base32',
|
||||
token,
|
||||
window: 1
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { createAdmin, verifyAdmin };
|
||||
31
server/cache.js
Normal file
31
server/cache.js
Normal file
@ -0,0 +1,31 @@
|
||||
class SattaCache {
|
||||
constructor() {
|
||||
this.store = new Map();
|
||||
this.ttl = 300000;
|
||||
}
|
||||
|
||||
set(key, value) {
|
||||
this.store.set(key, { data: value, expires: Date.now() + this.ttl });
|
||||
}
|
||||
|
||||
get(key) {
|
||||
const entry = this.store.get(key);
|
||||
if (entry && Date.now() < entry.expires) return entry.data;
|
||||
this.store.delete(key);
|
||||
return null;
|
||||
}
|
||||
|
||||
has(key) {
|
||||
return this.store.has(key) && Date.now() < this.store.get(key).expires;
|
||||
}
|
||||
|
||||
delete(key) {
|
||||
this.store.delete(key);
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.store.clear();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new SattaCache();
|
||||
37
server/controllers/adminController.js
Normal file
37
server/controllers/adminController.js
Normal file
@ -0,0 +1,37 @@
|
||||
const db = require('../db');
|
||||
const crypto = require('crypto');
|
||||
const argon2 = require('argon2');
|
||||
|
||||
exports.login = async (accessKey, password) => {
|
||||
const [admin] = await db.query(
|
||||
'SELECT * FROM admins WHERE access_key = ? AND is_active = 1',
|
||||
[accessKey]
|
||||
);
|
||||
|
||||
if (!admin) throw { status: 401, message: 'Invalid credentials' };
|
||||
|
||||
const validPass = await argon2.verify(admin.argon2_hash, password);
|
||||
if (!validPass) throw { status: 401, message: 'Invalid password' };
|
||||
|
||||
const sessionToken = crypto.randomBytes(32).toString('hex');
|
||||
await db.query(
|
||||
'UPDATE admins SET session_token = ?, last_access = NOW() WHERE id = ?',
|
||||
[sessionToken, admin.id]
|
||||
);
|
||||
|
||||
return sessionToken;
|
||||
};
|
||||
|
||||
exports.publishResult = async (data, authorization) => {
|
||||
const token = authorization?.split(' ')[1];
|
||||
const [admin] = await db.query('SELECT id FROM admins WHERE session_token = ?', [token]);
|
||||
|
||||
if (!admin) throw { status: 401, message: 'Unauthorized' };
|
||||
|
||||
const { team, date, result } = data;
|
||||
await db.query(`
|
||||
INSERT INTO results (team_id, result_date, result)
|
||||
SELECT id, ?, ? FROM teams WHERE name = ?
|
||||
ON DUPLICATE KEY UPDATE result = VALUES(result)
|
||||
`, [date, result, team.toUpperCase()]);
|
||||
};
|
||||
81
server/controllers/teamController.js
Normal file
81
server/controllers/teamController.js
Normal file
@ -0,0 +1,81 @@
|
||||
const db = require('../db');
|
||||
|
||||
// Get all teams
|
||||
exports.getAllTeams = async (req, res) => {
|
||||
try {
|
||||
const teams = await db.query('SELECT * FROM teams');
|
||||
res.json(teams);
|
||||
} catch (error) {
|
||||
console.error('Error fetching teams:', error);
|
||||
res.status(500).json({ error: 'Failed to fetch teams' });
|
||||
}
|
||||
};
|
||||
|
||||
// Create a new team
|
||||
exports.createTeam = async (req, res) => {
|
||||
try {
|
||||
const { name, announcement_time } = req.body;
|
||||
|
||||
if (!name || !announcement_time) {
|
||||
return res.status(400).json({ error: 'Name and announcement time are required' });
|
||||
}
|
||||
|
||||
await db.query(
|
||||
'INSERT INTO teams (name, announcement_time) VALUES (?, ?)',
|
||||
[name.toUpperCase(), announcement_time]
|
||||
);
|
||||
|
||||
res.status(201).json({ success: true, message: 'Team created successfully' });
|
||||
} catch (error) {
|
||||
console.error('Error creating team:', error);
|
||||
res.status(500).json({ error: 'Failed to create team' });
|
||||
}
|
||||
};
|
||||
|
||||
// Update a team
|
||||
exports.updateTeam = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, announcement_time } = req.body;
|
||||
|
||||
if (!name && !announcement_time) {
|
||||
return res.status(400).json({ error: 'At least one field (name or announcement time) is required' });
|
||||
}
|
||||
|
||||
const fields = [];
|
||||
const values = [];
|
||||
|
||||
if (name) {
|
||||
fields.push('name = ?');
|
||||
values.push(name.toUpperCase());
|
||||
}
|
||||
|
||||
if (announcement_time) {
|
||||
fields.push('announcement_time = ?');
|
||||
values.push(announcement_time);
|
||||
}
|
||||
|
||||
values.push(id);
|
||||
|
||||
await db.query(`UPDATE teams SET ${fields.join(', ')} WHERE id = ?`, values);
|
||||
|
||||
res.json({ success: true, message: 'Team updated successfully' });
|
||||
} catch (error) {
|
||||
console.error('Error updating team:', error);
|
||||
res.status(500).json({ error: 'Failed to update team' });
|
||||
}
|
||||
};
|
||||
|
||||
// Delete a team
|
||||
exports.deleteTeam = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
await db.query('DELETE FROM teams WHERE id = ?', [id]);
|
||||
|
||||
res.json({ success: true, message: 'Team deleted successfully' });
|
||||
} catch (error) {
|
||||
console.error('Error deleting team:', error);
|
||||
res.status(500).json({ error: 'Failed to delete team' });
|
||||
}
|
||||
};
|
||||
19
server/db.js
Normal file
19
server/db.js
Normal file
@ -0,0 +1,19 @@
|
||||
const mysql = require('mysql2/promise');
|
||||
|
||||
const pool = mysql.createPool({
|
||||
host: process.env.DB_HOST,
|
||||
user: process.env.DB_USER,
|
||||
password: process.env.DB_PASS,
|
||||
database: process.env.DB_NAME,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 20,
|
||||
queueLimit: 0,
|
||||
timezone: '+00:00'
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
query: async (sql, params) => {
|
||||
const [rows] = await pool.execute(sql, params);
|
||||
return rows;
|
||||
}
|
||||
};
|
||||
14
server/middlewares/rateLimit.js
Normal file
14
server/middlewares/rateLimit.js
Normal file
@ -0,0 +1,14 @@
|
||||
const { RateLimiterMemory } = require('rate-limiter-flexible');
|
||||
|
||||
const publicLimiter = new RateLimiterMemory({
|
||||
points: 100,
|
||||
duration: 60
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
publicLimiter: (req, res, next) => {
|
||||
publicLimiter.consume(req.anonymizedIP)
|
||||
.then(() => next())
|
||||
.catch(() => res.status(429).json({ error: 'Too many requests' }));
|
||||
}
|
||||
};
|
||||
17
server/middlewares/security.js
Normal file
17
server/middlewares/security.js
Normal file
@ -0,0 +1,17 @@
|
||||
const crypto = require('crypto');
|
||||
|
||||
module.exports = {
|
||||
// IP Anonymization
|
||||
anonymizeIP: (req, res, next) => {
|
||||
const ip = req.ip || '127.0.0.1';
|
||||
const salt = Math.floor(Date.now() / 3600000); // Hourly salt
|
||||
req.anonymizedIP = crypto.createHash('sha3-256')
|
||||
.update(ip + salt + process.env.IP_PEPPER)
|
||||
.digest('hex');
|
||||
next();
|
||||
},
|
||||
sanitizeInput: (req, res, next) => {
|
||||
// ...implement input sanitization if needed...
|
||||
next();
|
||||
}
|
||||
};
|
||||
28
server/middlewares/validation.js
Normal file
28
server/middlewares/validation.js
Normal file
@ -0,0 +1,28 @@
|
||||
const Joi = require('joi');
|
||||
|
||||
exports.validateTeam = (req, res, next) => {
|
||||
const schema = Joi.object({
|
||||
name: Joi.string().max(100).required(),
|
||||
announcement_time: Joi.string().pattern(/^([01]\d|2[0-3]):([0-5]\d):([0-5]\d)$/).required()
|
||||
});
|
||||
|
||||
const { error } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).json({ error: error.details[0].message });
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
exports.validateResult = (req, res, next) => {
|
||||
const schema = Joi.object({
|
||||
team: Joi.string().max(100).required(),
|
||||
date: Joi.string().pattern(/^\d{4}-\d{2}-\d{2}$/).required(),
|
||||
result: Joi.string().max(10).required()
|
||||
});
|
||||
|
||||
const { error } = schema.validate(req.body);
|
||||
if (error) {
|
||||
return res.status(400).json({ error: error.details[0].message });
|
||||
}
|
||||
next();
|
||||
};
|
||||
1788
server/package-lock.json
generated
Normal file
1788
server/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
server/package.json
Normal file
20
server/package.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"name": "satta-backend",
|
||||
"version": "1.0.0",
|
||||
"main": "server.js",
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"create-admin": "node scripts/create-admin.js",
|
||||
"test-api": "node scripts/test-api.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"argon2": "^0.31.0",
|
||||
"axios": "^1.8.3",
|
||||
"cors": "^2.8.5",
|
||||
"dotenv": "^16.3.1",
|
||||
"express": "^4.18.2",
|
||||
"joi": "^17.9.2",
|
||||
"mysql2": "^3.6.5",
|
||||
"rate-limiter-flexible": "^2.4.2"
|
||||
}
|
||||
}
|
||||
161
server/postman_collection.json
Normal file
161
server/postman_collection.json
Normal file
@ -0,0 +1,161 @@
|
||||
{
|
||||
"info": {
|
||||
"_postman_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
"name": "Satta Backend API",
|
||||
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
|
||||
},
|
||||
"item": [
|
||||
{
|
||||
"name": "Admin Login",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"accessKey\": \"<ACCESS_KEY>\",\n \"password\": \"<PASSWORD>\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/admin/login",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["admin", "login"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Publish Result",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
},
|
||||
{
|
||||
"key": "Authorization",
|
||||
"value": "Bearer <SESSION_TOKEN>"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"team\": \"BIKANER SUPER\",\n \"date\": \"2025-03-12\",\n \"result\": \"45\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/admin/results",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["admin", "results"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get All Teams",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/api/teams",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["api", "teams"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Create Team",
|
||||
"request": {
|
||||
"method": "POST",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"NEW TEAM\",\n \"announcement_time\": \"02:30:00\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/api/teams",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["api", "teams"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Update Team",
|
||||
"request": {
|
||||
"method": "PUT",
|
||||
"header": [
|
||||
{
|
||||
"key": "Content-Type",
|
||||
"value": "application/json"
|
||||
}
|
||||
],
|
||||
"body": {
|
||||
"mode": "raw",
|
||||
"raw": "{\n \"name\": \"UPDATED TEAM\",\n \"announcement_time\": \"03:00:00\"\n}"
|
||||
},
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/api/teams/1",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["api", "teams", "1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Delete Team",
|
||||
"request": {
|
||||
"method": "DELETE",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/api/teams/1",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["api", "teams", "1"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Get Today's Results",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/api/today",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["api", "today"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Health Check",
|
||||
"request": {
|
||||
"method": "GET",
|
||||
"header": [],
|
||||
"url": {
|
||||
"raw": "http://localhost:3000/api/health",
|
||||
"protocol": "http",
|
||||
"host": ["localhost"],
|
||||
"port": "3000",
|
||||
"path": ["api", "health"]
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
25
server/routes/admin.js
Normal file
25
server/routes/admin.js
Normal file
@ -0,0 +1,25 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const adminController = require('../controllers/adminController');
|
||||
const { validateResult } = require('../middlewares/validation');
|
||||
|
||||
router.post('/login', async (req, res, next) => {
|
||||
try {
|
||||
const { accessKey, password } = req.body;
|
||||
const token = await adminController.login(accessKey, password);
|
||||
res.json({ token });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
router.post('/results', validateResult, async (req, res, next) => {
|
||||
try {
|
||||
await adminController.publishResult(req.body, req.headers.authorization);
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
66
server/routes/public.js
Normal file
66
server/routes/public.js
Normal file
@ -0,0 +1,66 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const db = require('../db');
|
||||
const cache = require('../cache');
|
||||
|
||||
// Get specific result
|
||||
router.get('/results', async (req, res) => {
|
||||
try {
|
||||
const { team, date } = req.query;
|
||||
const cacheKey = `${team}:${date}`;
|
||||
|
||||
if (cache.has(cacheKey)) {
|
||||
return res.json(cache.get(cacheKey));
|
||||
}
|
||||
|
||||
const [result] = await db.query(`
|
||||
SELECT r.result, r.result_date, t.name AS team
|
||||
FROM results r
|
||||
JOIN teams t ON r.team_id = t.id
|
||||
WHERE t.name = ? AND r.result_date = ?
|
||||
`, [team.toUpperCase(), date]);
|
||||
|
||||
if (!result) return res.status(404).json({ error: 'Result not found' });
|
||||
|
||||
cache.set(cacheKey, result);
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Get all today's results
|
||||
router.get('/today', async (req, res) => {
|
||||
try {
|
||||
const today = new Date().toISOString().split('T')[0];
|
||||
const cacheKey = `today:${today}`;
|
||||
|
||||
if (cache.has(cacheKey)) {
|
||||
return res.json(cache.get(cacheKey));
|
||||
}
|
||||
|
||||
const results = await db.query(`
|
||||
SELECT t.name AS team, r.result, r.result_date
|
||||
FROM results r
|
||||
JOIN teams t ON r.team_id = t.id
|
||||
WHERE r.result_date = ?
|
||||
`, [today]);
|
||||
|
||||
cache.set(cacheKey, results);
|
||||
res.json(results);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: 'Server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// health check
|
||||
router.get('/health', async (req, res) => {
|
||||
try {
|
||||
await db.query('SELECT 1'); // Simple query to check DB connection
|
||||
res.json({ status: 'healthy' });
|
||||
} catch (error) {
|
||||
res.status(500).json({ status: 'unhealthy', error: error.message });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
18
server/routes/team.js
Normal file
18
server/routes/team.js
Normal file
@ -0,0 +1,18 @@
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const teamController = require('../controllers/teamController');
|
||||
const { validateTeam } = require('../middlewares/validation');
|
||||
|
||||
// Get all teams
|
||||
router.get('/', teamController.getAllTeams);
|
||||
|
||||
// Create a new team
|
||||
router.post('/', validateTeam, teamController.createTeam);
|
||||
|
||||
// Update a team
|
||||
router.put('/:id', validateTeam, teamController.updateTeam);
|
||||
|
||||
// Delete a team
|
||||
router.delete('/:id', teamController.deleteTeam);
|
||||
|
||||
module.exports = router;
|
||||
27
server/schema.sql
Normal file
27
server/schema.sql
Normal file
@ -0,0 +1,27 @@
|
||||
CREATE DATABASE IF NOT EXISTS satta_prod;
|
||||
USE satta_prod;
|
||||
|
||||
CREATE TABLE teams (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
name VARCHAR(100) NOT NULL UNIQUE,
|
||||
announcement_time TIME NOT NULL,
|
||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
);
|
||||
|
||||
CREATE TABLE results (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
team_id INT NOT NULL,
|
||||
result_date DATE NOT NULL,
|
||||
result VARCHAR(10) NOT NULL,
|
||||
FOREIGN KEY (team_id) REFERENCES teams(id) ON DELETE CASCADE,
|
||||
UNIQUE KEY uniq_team_date (team_id, result_date)
|
||||
);
|
||||
|
||||
CREATE TABLE admins (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
access_key CHAR(64) UNIQUE NOT NULL,
|
||||
argon2_hash TEXT NOT NULL,
|
||||
session_token CHAR(64),
|
||||
is_active BOOLEAN DEFAULT TRUE,
|
||||
last_access TIMESTAMP
|
||||
);
|
||||
28
server/scripts/create-admin.js
Normal file
28
server/scripts/create-admin.js
Normal file
@ -0,0 +1,28 @@
|
||||
require('dotenv').config();
|
||||
const crypto = require('crypto');
|
||||
const argon2 = require('argon2');
|
||||
const db = require('../db');
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
const accessKey = crypto.randomBytes(16).toString('hex');
|
||||
const password = process.argv[2];
|
||||
if (!password) {
|
||||
console.error('Usage: node scripts/create-admin.js <password>');
|
||||
process.exit(1);
|
||||
}
|
||||
const hash = await argon2.hash(password);
|
||||
|
||||
await db.query(
|
||||
`INSERT INTO admins (access_key, argon2_hash) VALUES (?, ?)`,
|
||||
[accessKey, hash]
|
||||
);
|
||||
|
||||
console.log('Admin created successfully!');
|
||||
console.log(`Access Key: ${accessKey}`);
|
||||
} catch (error) {
|
||||
console.error('Error creating admin:', error);
|
||||
} finally {
|
||||
process.exit();
|
||||
}
|
||||
})();
|
||||
73
server/scripts/test-api.js
Normal file
73
server/scripts/test-api.js
Normal file
@ -0,0 +1,73 @@
|
||||
const axios = require('axios');
|
||||
|
||||
const BASE_URL = 'http://localhost:3000';
|
||||
|
||||
(async () => {
|
||||
try {
|
||||
// Admin Login
|
||||
console.log('Logging in as admin...');
|
||||
const loginResponse = await axios.post(`${BASE_URL}/admin/login`, {
|
||||
accessKey: '<ACCESS_KEY>',
|
||||
password: '<PASSWORD>'
|
||||
});
|
||||
const sessionToken = loginResponse.data.token;
|
||||
console.log('Login successful. Session Token:', sessionToken);
|
||||
|
||||
// Create a Team
|
||||
console.log('Creating a new team...');
|
||||
const createTeamResponse = await axios.post(
|
||||
`${BASE_URL}/api/teams`,
|
||||
{
|
||||
name: 'NEW TEAM',
|
||||
announcement_time: '02:30:00'
|
||||
},
|
||||
{
|
||||
headers: { Authorization: `Bearer ${sessionToken}` }
|
||||
}
|
||||
);
|
||||
console.log('Team created:', createTeamResponse.data);
|
||||
|
||||
// Get All Teams
|
||||
console.log('Fetching all teams...');
|
||||
const teamsResponse = await axios.get(`${BASE_URL}/api/teams`);
|
||||
console.log('Teams:', teamsResponse.data);
|
||||
|
||||
// Update a Team
|
||||
console.log('Updating a team...');
|
||||
const updateTeamResponse = await axios.put(
|
||||
`${BASE_URL}/api/teams/1`,
|
||||
{
|
||||
name: 'UPDATED TEAM',
|
||||
announcement_time: '03:00:00'
|
||||
},
|
||||
{
|
||||
headers: { Authorization: `Bearer ${sessionToken}` }
|
||||
}
|
||||
);
|
||||
console.log('Team updated:', updateTeamResponse.data);
|
||||
|
||||
// Delete a Team
|
||||
console.log('Deleting a team...');
|
||||
const deleteTeamResponse = await axios.delete(`${BASE_URL}/api/teams/1`, {
|
||||
headers: { Authorization: `Bearer ${sessionToken}` }
|
||||
});
|
||||
console.log('Team deleted:', deleteTeamResponse.data);
|
||||
|
||||
// Publish a Result
|
||||
console.log('Publishing a result...');
|
||||
const publishResultResponse = await axios.post(
|
||||
`${BASE_URL}/admin/results`,
|
||||
{
|
||||
team: 'NEW TEAM',
|
||||
date: '2025-03-12',
|
||||
result: '45'
|
||||
},
|
||||
{
|
||||
headers: { Authorization: `Bearer ${sessionToken}` }
|
||||
}
|
||||
);
|
||||
console.log('Result published:', publishResultResponse.data);
|
||||
} catch (error) {
|
||||
console.error('Error:', error.response?.data || error.message);
|
||||
}
|
||||
})();
|
||||
38
server/server.js
Normal file
38
server/server.js
Normal file
@ -0,0 +1,38 @@
|
||||
require('dotenv').config();
|
||||
const express = require('express');
|
||||
const cors = require('cors');
|
||||
const security = require('./middlewares/security');
|
||||
const rateLimit = require('./middlewares/rateLimit');
|
||||
const cache = require('./cache');
|
||||
const publicRoutes = require('./routes/public');
|
||||
const adminRoutes = require('./routes/admin');
|
||||
const teamRoutes = require('./routes/team');
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(cors({ origin: ['http://localhost:3000', 'https://your-production-domain.com'] }));
|
||||
app.use(express.json({ limit: '10kb' }));
|
||||
app.use(security.anonymizeIP);
|
||||
app.use(security.sanitizeInput);
|
||||
app.use(rateLimit.publicLimiter);
|
||||
|
||||
app.use('/api', publicRoutes);
|
||||
app.use('/admin', adminRoutes);
|
||||
app.use('/api/teams', teamRoutes);
|
||||
|
||||
app.use((req, res, next) => {
|
||||
if (['POST', 'PUT', 'DELETE'].includes(req.method)) {
|
||||
cache.store.clear();
|
||||
}
|
||||
next();
|
||||
});
|
||||
|
||||
app.use((err, req, res, next) => {
|
||||
console.error(err.stack);
|
||||
res.status(err.status || 500).json({ error: err.message || 'Internal Server Error' });
|
||||
});
|
||||
|
||||
const PORT = process.env.PORT || 3000;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user