Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions backend/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
node_modules
# Keep environment variables out of version control
.env

/generated/prisma
73 changes: 7 additions & 66 deletions backend/config/db.js
Original file line number Diff line number Diff line change
@@ -1,69 +1,10 @@
// const { Pool } = require('pg');
import { Pool } from 'pg';
import dotenv from 'dotenv';
dotenv.config();
import "dotenv/config";
import { PrismaPg } from '@prisma/adapter-pg'
import { PrismaClient } from '../generated/prisma/client.js';

const pool = new Pool({
user: process.env.DB_USER,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: process.env.DB_PORT,
});
const connectionString = `${process.env.DATABASE_URL}`

const initDB = async () => {
const client = await pool.connect();

try {
await client.query(`
CREATE TABLE IF NOT EXISTS users (
id SERIAL PRIMARY KEY,
email VARCHAR(255) UNIQUE NOT NULL,
password VARCHAR(255) NOT NULL,
role VARCHAR(50) DEFAULT 'user',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
await client.query(`
CREATE TABLE IF NOT EXISTS events (
id SERIAL PRIMARY KEY,
title VARCHAR(255) NOT NULL,
description TEXT,
date DATE,
max_team_size INTEGER DEFAULT 1,
registration_fee DECIMAL(10, 2),
qr_code_image VARCHAR(255),
status VARCHAR(50) DEFAULT 'active',
created_by INTEGER REFERENCES users(id),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);
const adapter = new PrismaPg({ connectionString })
const prisma = new PrismaClient({ adapter })

await client.query(`
CREATE TABLE IF NOT EXISTS registrations (
id SERIAL PRIMARY KEY,
event_id INTEGER REFERENCES events(id) ON DELETE CASCADE,
user_id INTEGER REFERENCES users(id),
team_size INTEGER NOT NULL,
team_leader_name VARCHAR(255) NOT NULL,
team_leader_email VARCHAR(255) NOT NULL,
team_leader_contact VARCHAR(20) NOT NULL,
team_members JSONB,
payment_screenshot VARCHAR(255),
transaction_id VARCHAR(255),
status VARCHAR(50) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`);

console.log('Database tables created successfully');
} catch (error) {
console.error('Database initialization error:', error);
throw error;
} finally {
client.release();
}
};

// module.exports = { pool, initDB };
export { pool, initDB };
export { prisma }
176 changes: 95 additions & 81 deletions backend/controllers/adminController.js
Original file line number Diff line number Diff line change
@@ -1,36 +1,47 @@
import { pool } from '../config/db.js';
import { prisma } from '../config/db.js';
import bcrypt from 'bcryptjs';

const getDashboardStats = async (req, res) => {
try {
const usersCount = await pool.query('SELECT COUNT(*) FROM users WHERE role = $1', ['user']);
const eventsCount = await pool.query('SELECT COUNT(*) FROM events');
const registrationsCount = await pool.query('SELECT COUNT(*) FROM registrations');
const pendingCount = await pool.query(
'SELECT COUNT(*) FROM registrations WHERE status = $1',
['pending']
);

res.json({
stats: {
totalUsers: parseInt(usersCount.rows[0].count),
totalEvents: parseInt(eventsCount.rows[0].count),
totalRegistrations: parseInt(registrationsCount.rows[0].count),
pendingRegistrations: parseInt(pendingCount.rows[0].count)
}
});
const [usersCount, eventsCount, registrationsCount, pendingCount] = await Promise.all([
prisma.user.count({
where: { role: 'user' }
}),
prisma.event.count(),
prisma.registration.count(),
prisma.registration.count({
where: { status: 'pending' }
})
]);

res.json({
stats: {
totalUsers: usersCount,
totalEvents: eventsCount,
totalRegistrations: registrationsCount,
pendingRegistrations: pendingCount
}
});
} catch (error) {
console.error('Get dashboard stats error:', error);
res.status(500).json({ message: 'Server error' });
}
};
const getAllUsers = async (req, res) => {
try {
const result = await pool.query(
'SELECT id, email, role, created_at FROM users ORDER BY created_at DESC'
);
const result = await prisma.user.findMany({
select: {
id: true,
email: true,
role: true,
createdAt: true
},
orderBy: {
createdAt: 'desc'
}
});

res.json({ users: result.rows });
res.json({ users: result });
} catch (error) {
console.error('Get all users error:', error);
res.status(500).json({ message: 'Server error' });
Expand All @@ -42,27 +53,26 @@ const updateUser = async (req, res) => {
const { id } = req.params;
const { email, role, password } = req.body;

let query = 'UPDATE users SET email = $1, role = $2';
let params = [email, role];

const updateData = {
email,
role,
};
if (password) {
const hashedPassword = await bcrypt.hash(password, 10);
query += ', password = $3';
params.push(hashedPassword);
}

query += ` WHERE id = $${params.length + 1} RETURNING id, email, role, created_at`;
params.push(id);

const result = await pool.query(query, params);

if (result.rows.length === 0) {
return res.status(404).json({ message: 'User not found' });
}

updateData.password = await bcrypt.hash(password, 10);
}
const updatedUser = await prisma.user.update({
where: { id: parseInt(id) },
data: updateData,
select: {
id: true,
email: true,
role: true,
createdAt: true,
},
});
res.json({
message: 'User updated successfully',
user: result.rows[0]
user: updatedUser
});
} catch (error) {
console.error('Update user error:', error);
Expand All @@ -74,14 +84,18 @@ const deleteUser = async (req, res) => {
try {
const { id } = req.params;

const user = await pool.query('SELECT role FROM users WHERE id = $1', [id]);
if (user.rows.length > 0 && user.rows[0].role === 'admin') {
const user = await prisma.user.findUnique({
where: { id: parseInt(id) },
select: { role: true }
});
if (user && user.role === 'admin') {
return res.status(403).json({ message: 'Cannot delete admin account' });
}

const result = await pool.query('DELETE FROM users WHERE id = $1 RETURNING *', [id]);

if (result.rows.length === 0) {
const result = await prisma.user.delete({
where: { id: parseInt(id) }
});
if (!result) {
return res.status(404).json({ message: 'User not found' });
}

Expand All @@ -96,25 +110,20 @@ const getAllRegistrations = async (req, res) => {
try {
const { eventId } = req.query;

let query = `
SELECT r.*, e.title as event_title, e.date as event_date,
u.email as user_email
FROM registrations r
JOIN events e ON r.event_id = e.id
JOIN users u ON r.user_id = u.id
`;

const params = [];
if (eventId) {
query += ' WHERE r.event_id = $1';
params.push(eventId);
}

query += ' ORDER BY r.created_at DESC';

const result = await pool.query(query, params);
const registrations = await prisma.registration.findMany({
where: eventId ? { eventId: Number(eventId) } : {},
orderBy: { createdAt: 'desc' },
include: {
event: {
select: { title: true, date: true }
},
user: {
select: { email: true }
}
}
});

res.json({ registrations: result.rows });
res.json({ registrations: registrations });
} catch (error) {
console.error('Get all registrations error:', error);
res.status(500).json({ message: 'Server error' });
Expand All @@ -130,18 +139,18 @@ const updateRegistrationStatus = async (req, res) => {
return res.status(400).json({ message: 'Invalid status' });
}

const result = await pool.query(
'UPDATE registrations SET status = $1 WHERE id = $2 RETURNING *',
[status, id]
);
const updatedRegistration = await prisma.registration.update({
where: { id: parseInt(id) },
data: { status: status }
});

if (result.rows.length === 0) {
if (!updatedRegistration) {
return res.status(404).json({ message: 'Registration not found' });
}

res.json({
message: 'Registration status updated successfully',
registration: result.rows[0]
registration: updatedRegistration
});
} catch (error) {
console.error('Update registration status error:', error);
Expand All @@ -162,22 +171,26 @@ const updateRegistration = async (req, res) => {
status
} = req.body;

const result = await pool.query(
`UPDATE registrations
SET team_size = $1, team_leader_name = $2, team_leader_email = $3,
team_leader_contact = $4, team_members = $5, transaction_id = $6, status = $7
WHERE id = $8 RETURNING *`,
[teamSize, teamLeaderName, teamLeaderEmail, teamLeaderContact,
teamMembers, transactionId, status, id]
);
const updatedRegistration = await prisma.registration.update({
where: { id: parseInt(id) },
data: {
teamSize,
teamLeaderName,
teamLeaderEmail,
teamLeaderContact,
teamMembers,
transactionId,
status
}
});

if (result.rows.length === 0) {
if (!updatedRegistration) {
return res.status(404).json({ message: 'Registration not found' });
}

res.json({
message: 'Registration updated successfully',
registration: result.rows[0]
registration: updatedRegistration
});
} catch (error) {
console.error('Update registration error:', error);
Expand All @@ -189,9 +202,10 @@ const deleteRegistration = async (req, res) => {
try {
const { id } = req.params;

const result = await pool.query('DELETE FROM registrations WHERE id = $1 RETURNING *', [id]);

if (result.rows.length === 0) {
const deletedRegistration = await prisma.registration.delete({
where: { id: parseInt(id) }
});
if (!deletedRegistration) {
return res.status(404).json({ message: 'Registration not found' });
}

Expand Down
Loading