This commit is contained in:
2025-07-19 12:21:46 +02:00
parent 12822dfdbf
commit 2e7957d0a0
86 changed files with 25573 additions and 0 deletions

86
scripts/addTeams.js Normal file
View File

@@ -0,0 +1,86 @@
const fetch = require('node-fetch');
// Get number of teams from command line argument, default to 10
const numTeams = parseInt(process.argv[2]) || 10;
// Generate team names dynamically
const teamNames = [
'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa',
'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron', 'Pi', 'Rho', 'Sigma', 'Tau', 'Upsilon',
'Phi', 'Chi', 'Psi', 'Omega'
];
// Generate SVG logo based on team name
function generateSVGLogo(teamName, size = 40) {
// Use team name to generate consistent colors and patterns
let hash = 0;
for (let i = 0; i < teamName.length; i++) {
hash = teamName.charCodeAt(i) + ((hash << 5) - hash);
}
const hue = hash % 360;
const saturation = 60 + (hash % 30);
const lightness = 40 + (hash % 30);
const color = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
// Generate secondary color
const secondaryHue = (hue + 180) % 360;
const secondaryColor = `hsl(${secondaryHue}, ${saturation}%, ${lightness}%)`;
// Choose a logo pattern based on hash
const pattern = hash % 4;
const initials = teamName.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2);
let svgContent = '';
switch (pattern) {
case 0: // Circle with initials
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><circle cx="${size/2}" cy="${size/2}" r="${size/2}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 1: // Square with diagonal
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><rect x="2" y="2" width="${size-4}" height="${size-4}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><line x1="0" y1="0" x2="${size}" y2="${size}" stroke="${secondaryColor}" stroke-width="3"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 2: // Triangle
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><polygon points="${size/2},5 ${size-5},${size-5} 5,${size-5}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="60%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 3: // Diamond
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><polygon points="${size/2},5 ${size-5},${size/2} ${size/2},${size-5} 5,${size/2}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
}
return svgContent;
}
const teams = [];
for (let i = 0; i < numTeams; i++) {
const teamName = `Team ${teamNames[i]}`;
teams.push({
name: teamName,
logo: generateSVGLogo(teamName)
});
}
async function addTeams() {
for (const team of teams) {
try {
const res = await fetch('http://localhost:4000/api/teams', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name: team.name, logo: team.logo })
});
const data = await res.json();
if (res.ok) {
console.log(`Added: ${team.name} with SVG logo`);
} else {
console.log(`Failed to add ${team.name}: ${data.error}`);
}
} catch (err) {
console.log(`Error adding ${team.name}:`, err.message);
}
}
}
addTeams();

16
scripts/checkAdmin.js Normal file
View File

@@ -0,0 +1,16 @@
const { PrismaClient } = require('../generated/prisma');
const prisma = new PrismaClient();
async function checkAdmin() {
try {
const admins = await prisma.adminUser.findMany();
console.log('Admin users in database:', admins);
} catch (err) {
console.error('Error:', err);
} finally {
await prisma.$disconnect();
}
}
checkAdmin();

13
scripts/clearMatches.js Normal file
View File

@@ -0,0 +1,13 @@
const { PrismaClient } = require('../generated/prisma');
async function main() {
const prisma = new PrismaClient();
// Delete all results first (if results depend on matches)
const deletedResults = await prisma.result.deleteMany();
// Delete all matches
const deletedMatches = await prisma.match.deleteMany();
console.log(`Deleted ${deletedResults.count} results and ${deletedMatches.count} matches.`);
await prisma.$disconnect();
}
main().catch(e => { console.error(e); process.exit(1); });

14
scripts/clearPlayers.js Normal file
View File

@@ -0,0 +1,14 @@
const { PrismaClient } = require('../generated/prisma');
async function main() {
const prisma = new PrismaClient();
const deletedResults = await prisma.result.deleteMany();
const deletedMatches = await prisma.match.deleteMany();
const deletedStages = await prisma.tournamentStage.deleteMany();
const deletedTeams = await prisma.team.deleteMany();
const deletedPlayers = await prisma.player.deleteMany();
console.log(`Deleted ${deletedResults.count} results, ${deletedMatches.count} matches, ${deletedStages.count} tournament stages, ${deletedTeams.count} teams, and ${deletedPlayers.count} players.`);
await prisma.$disconnect();
}
main().catch(e => { console.error(e); process.exit(1); });

31
scripts/clearStages.js Normal file
View File

@@ -0,0 +1,31 @@
const { PrismaClient } = require('../generated/prisma');
async function main() {
const prisma = new PrismaClient();
// Find all single elimination stages
const singleElimStages = await prisma.tournamentStage.findMany({ where: { type: 'SINGLE_ELIM' } });
if (!singleElimStages.length) {
console.log('No single elimination stages found.');
await prisma.$disconnect();
return;
}
let totalDeletedMatches = 0;
let totalDeletedResults = 0;
for (const stage of singleElimStages) {
// Find all matches for this stage
const matches = await prisma.match.findMany({ where: { stageId: stage.id } });
const matchIds = matches.map(m => m.id);
// Delete all results for these matches
const deletedResults = await prisma.result.deleteMany({ where: { matchId: { in: matchIds } } });
// Delete all matches for this stage
const deletedMatches = await prisma.match.deleteMany({ where: { stageId: stage.id } });
// Delete the stage itself
await prisma.tournamentStage.delete({ where: { id: stage.id } });
totalDeletedMatches += deletedMatches.count;
totalDeletedResults += deletedResults.count;
}
console.log(`Deleted ${singleElimStages.length} SINGLE_ELIM stages, ${totalDeletedMatches} matches, and ${totalDeletedResults} results.`);
await prisma.$disconnect();
}
main().catch(e => { console.error(e); process.exit(1); });

28
scripts/createAdmin.js Normal file
View File

@@ -0,0 +1,28 @@
const { PrismaClient } = require('../generated/prisma');
const bcrypt = require('bcryptjs');
const prisma = new PrismaClient();
async function createAdmin() {
try {
const username = 'admin';
const password = 'admin123';
const hash = await bcrypt.hash(password, 10);
const admin = await prisma.adminUser.create({
data: { username, passwordHash: hash },
});
console.log('Admin created successfully:', { id: admin.id, username: admin.username });
} catch (err) {
if (err.code === 'P2002') {
console.log('Admin already exists');
} else {
console.error('Error creating admin:', err);
}
} finally {
await prisma.$disconnect();
}
}
createAdmin();

17
scripts/deleteAdmins.js Normal file
View File

@@ -0,0 +1,17 @@
const { PrismaClient } = require('../generated/prisma');
const prisma = new PrismaClient();
async function deleteAdmins() {
try {
console.log('Deleting all admin users...');
const result = await prisma.adminUser.deleteMany();
console.log(`Deleted ${result.count} admin users`);
} catch (err) {
console.error('Error:', err);
} finally {
await prisma.$disconnect();
}
}
deleteAdmins();

View File

@@ -0,0 +1,12 @@
const { PrismaClient } = require('../generated/prisma');
async function main() {
const prisma = new PrismaClient();
const deletedResults = await prisma.result.deleteMany();
const deletedMatches = await prisma.match.deleteMany();
const deletedStages = await prisma.tournamentStage.deleteMany();
console.log(`Deleted ${deletedResults.count} results, ${deletedMatches.count} matches, and ${deletedStages.count} tournament stages.`);
await prisma.$disconnect();
}
main().catch(e => { console.error(e); process.exit(1); });

View File

@@ -0,0 +1,73 @@
const { PrismaClient } = require('../generated/prisma');
const prisma = new PrismaClient();
// Generate random SVG logo based on team name
function generateSVGLogo(teamName, size = 40) {
// Use team name to generate consistent colors and patterns
let hash = 0;
for (let i = 0; i < teamName.length; i++) {
hash = teamName.charCodeAt(i) + ((hash << 5) - hash);
}
const hue = hash % 360;
const saturation = 60 + (hash % 30);
const lightness = 40 + (hash % 30);
const color = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
// Generate secondary color
const secondaryHue = (hue + 180) % 360;
const secondaryColor = `hsl(${secondaryHue}, ${saturation}%, ${lightness}%)`;
// Choose a logo pattern based on hash
const pattern = hash % 4;
const initials = teamName.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2);
let svgContent = '';
switch (pattern) {
case 0: // Circle with initials
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><circle cx="${size/2}" cy="${size/2}" r="${size/2}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 1: // Square with diagonal
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><rect x="2" y="2" width="${size-4}" height="${size-4}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><line x1="0" y1="0" x2="${size}" y2="${size}" stroke="${secondaryColor}" stroke-width="3"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 2: // Triangle
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><polygon points="${size/2},5 ${size-5},${size-5} 5,${size-5}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="60%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 3: // Diamond
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><polygon points="${size/2},5 ${size-5},${size/2} ${size/2},${size-5} 5,${size/2}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
}
return svgContent;
}
async function updateTeamLogos() {
try {
const teams = await prisma.team.findMany();
console.log(`Found ${teams.length} teams to update`);
for (const team of teams) {
const svgLogo = generateSVGLogo(team.name);
await prisma.team.update({
where: { id: team.id },
data: { logo: svgLogo }
});
console.log(`Updated ${team.name} with SVG logo`);
}
console.log('✅ All team logos updated successfully!');
} catch (err) {
console.error('Error updating team logos:', err);
} finally {
await prisma.$disconnect();
}
}
updateTeamLogos();

101
scripts/resetTournament.js Normal file
View File

@@ -0,0 +1,101 @@
const { PrismaClient } = require('../generated/prisma');
const fetch = require('node-fetch');
const prisma = new PrismaClient();
// Generate SVG logo based on team name
function generateSVGLogo(teamName, size = 40) {
let hash = 0;
for (let i = 0; i < teamName.length; i++) {
hash = teamName.charCodeAt(i) + ((hash << 5) - hash);
}
const hue = Math.abs(hash) % 360;
const saturation = 60 + (Math.abs(hash) % 30);
const lightness = 40 + (Math.abs(hash) % 30);
const color = `hsl(${hue}, ${saturation}%, ${lightness}%)`;
const secondaryHue = (hue + 180) % 360;
const secondaryColor = `hsl(${secondaryHue}, ${saturation}%, ${lightness}%)`;
const pattern = Math.abs(hash) % 4;
const initials = teamName.split(' ').map(w => w[0]).join('').toUpperCase().slice(0, 2);
let svgContent = '';
switch (pattern) {
case 0: // Circle with initials
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><circle cx="${size/2}" cy="${size/2}" r="${size/2}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 1: // Square with diagonal
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><rect x="2" y="2" width="${size-4}" height="${size-4}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><line x1="0" y1="0" x2="${size}" y2="${size}" stroke="${secondaryColor}" stroke-width="3"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 2: // Triangle
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><polygon points="${size/2},5 ${size-5},${size-5} 5,${size-5}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="60%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
case 3: // Diamond
svgContent = `<svg width="${size}" height="${size}" viewBox="0 0 ${size} ${size}"><polygon points="${size/2},5 ${size-5},${size/2} ${size/2},${size-5} 5,${size/2}" fill="${color}" stroke="${secondaryColor}" stroke-width="2"/><text x="50%" y="55%" text-anchor="middle" font-size="${size/3}" fill="white" font-family="Arial, sans-serif" font-weight="bold">${initials}</text></svg>`;
break;
}
return svgContent;
}
async function resetTournament() {
try {
console.log('🗑️ Deleting all existing data...');
// Delete all data in the correct order (due to foreign key constraints)
await prisma.result.deleteMany();
await prisma.match.deleteMany();
await prisma.tournamentStage.deleteMany();
await prisma.tournament.deleteMany();
await prisma.team.deleteMany();
console.log('✅ All existing data deleted');
// Create new tournament
console.log('🏆 Creating new tournament...');
const tournament = await prisma.tournament.create({
data: {
name: 'Championship Tournament',
date: new Date(),
location: 'Main Arena'
}
});
console.log(`✅ Tournament created: ${tournament.name}`);
// Create 15 teams
console.log('👥 Creating 15 teams...');
const teamNames = [
'Alpha', 'Beta', 'Gamma', 'Delta', 'Epsilon', 'Zeta', 'Eta', 'Theta', 'Iota', 'Kappa',
'Lambda', 'Mu', 'Nu', 'Xi', 'Omicron'
];
const teams = [];
for (let i = 0; i < 15; i++) {
const teamName = `Team ${teamNames[i]}`;
const team = await prisma.team.create({
data: {
name: teamName,
logo: generateSVGLogo(teamName)
}
});
teams.push(team);
console.log(`✅ Created ${team.name} with SVG logo`);
}
console.log(`\n🎉 Tournament reset complete!`);
console.log(`📊 Tournament: ${tournament.name}`);
console.log(`👥 Teams: ${teams.length}`);
console.log(`📅 Date: ${tournament.date.toLocaleDateString()}`);
console.log(`📍 Location: ${tournament.location}`);
} catch (err) {
console.error('❌ Error resetting tournament:', err);
} finally {
await prisma.$disconnect();
}
}
resetTournament();

View File

@@ -0,0 +1,60 @@
const fetch = require('node-fetch');
const readline = require('readline');
async function prompt(question) {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans); }));
}
function getRandomScore() {
// No draws allowed, so scores must be different
let a = Math.floor(Math.random() * 10);
let b = Math.floor(Math.random() * 10);
while (a === b) {
b = Math.floor(Math.random() * 10);
}
return [a, b];
}
async function main() {
const username = process.env.ADMIN_USERNAME || await prompt('Admin username: ');
const password = process.env.ADMIN_PASSWORD || await prompt('Admin password: ');
// Login as admin
const loginRes = await fetch('http://localhost:4000/api/admin/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const loginData = await loginRes.json();
if (!loginRes.ok || !loginData.token) {
console.error('Admin login failed:', loginData.error || loginRes.statusText);
process.exit(1);
}
const token = loginData.token;
console.log('Admin login successful. Filling in match results...');
// Fetch all matches
const matchesRes = await fetch('http://localhost:4000/api/matches');
const matches = await matchesRes.json();
for (const match of matches) {
if (match.result) continue; // Skip if result already exists
const [team1Score, team2Score] = getRandomScore();
const resultRes = await fetch(`http://localhost:4000/api/admin/matches/${match.id}/result`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${token}`
},
body: JSON.stringify({ team1Score, team2Score })
});
if (resultRes.ok) {
console.log(`Filled result for match ${match.id}: ${team1Score} - ${team2Score}`);
} else {
const err = await resultRes.json();
console.log(`Failed to fill result for match ${match.id}:`, err.error || resultRes.statusText);
}
}
}
main();

View File

@@ -0,0 +1,49 @@
const fetch = require('node-fetch');
const readline = require('readline');
async function prompt(question) {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans); }));
}
async function main() {
const username = process.env.ADMIN_USERNAME || await prompt('Admin username: ');
const password = process.env.ADMIN_PASSWORD || await prompt('Admin password: ');
let minTeamsPerPool = 3;
const minTeamsInput = await prompt('Minimum teams per pool (default 3): ');
if (minTeamsInput && !isNaN(parseInt(minTeamsInput))) {
minTeamsPerPool = parseInt(minTeamsInput);
}
// Login as admin
const loginRes = await fetch('http://localhost:4000/api/admin/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const loginData = await loginRes.json();
if (!loginRes.ok || !loginData.token) {
console.error('Admin login failed:', loginData.error || loginRes.statusText);
process.exit(1);
}
const token = loginData.token;
console.log('Admin login successful. Scheduling round robin matches...');
// Call schedule round robin endpoint
const scheduleRes = await fetch('http://localhost:4000/api/admin/schedule/roundrobin', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ minTeamsPerPool })
});
const scheduleData = await scheduleRes.json();
if (scheduleRes.ok) {
console.log('Round robin scheduled:', scheduleData);
} else {
console.error('Failed to schedule round robin:', scheduleData.error || scheduleRes.statusText);
}
}
main();

View File

@@ -0,0 +1,40 @@
const fetch = require('node-fetch');
const readline = require('readline');
async function prompt(question) {
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
return new Promise(resolve => rl.question(question, ans => { rl.close(); resolve(ans); }));
}
async function main() {
const username = process.env.ADMIN_USERNAME || await prompt('Admin username: ');
const password = process.env.ADMIN_PASSWORD || await prompt('Admin password: ');
// Login as admin
const loginRes = await fetch('http://localhost:4000/api/admin/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username, password })
});
const loginData = await loginRes.json();
if (!loginRes.ok || !loginData.token) {
console.error('Admin login failed:', loginData.error || loginRes.statusText);
process.exit(1);
}
const token = loginData.token;
console.log('Admin login successful. Scheduling single elimination bracket...');
// Call schedule single elimination endpoint
const scheduleRes = await fetch('http://localhost:4000/api/admin/schedule/singleelim', {
method: 'POST',
headers: { 'Authorization': `Bearer ${token}` }
});
const scheduleData = await scheduleRes.json();
if (scheduleRes.ok) {
console.log('Single elimination scheduled:', scheduleData);
} else {
console.error('Failed to schedule single elimination:', scheduleData.error || scheduleRes.statusText);
}
}
main();

View File

@@ -0,0 +1,24 @@
const { PrismaClient } = require('../generated/prisma');
async function main() {
const prisma = new PrismaClient();
const players = await prisma.player.findMany();
const usedUsernames = new Set();
for (const player of players) {
let base = player.email.split('@')[0];
let username = base;
let i = 1;
// Ensure uniqueness
while (usedUsernames.has(username) || await prisma.player.findUnique({ where: { username } })) {
username = `${base}${i}`;
i++;
}
usedUsernames.add(username);
await prisma.player.update({ where: { id: player.id }, data: { username } });
console.log(`Set username for ${player.email}: ${username}`);
}
await prisma.$disconnect();
}
main().catch(e => { console.error(e); process.exit(1); });

View File

@@ -0,0 +1,57 @@
const fetch = require('node-fetch');
async function startTournament() {
try {
// 1. Login as admin with .env credentials
console.log('Logging in as admin...');
const loginRes = await fetch('http://localhost:4000/api/admin/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'admin',
password: '0000'
})
});
if (!loginRes.ok) {
const error = await loginRes.json();
console.error('Login failed:', error);
return;
}
const { token } = await loginRes.json();
console.log('✅ Login successful!');
// 2. Start round robin
console.log('Starting round robin...');
const scheduleRes = await fetch('http://localhost:4000/api/admin/schedule/roundrobin', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json'
}
});
if (scheduleRes.ok) {
const data = await scheduleRes.json();
console.log('✅ Round robin started successfully!');
console.log('Pools created:', data.pools);
console.log('Matches created:', data.matchesCreated);
// 3. Check the created matches
console.log('Checking created matches...');
const matchesRes = await fetch('http://localhost:4000/api/matches');
if (matchesRes.ok) {
const matches = await matchesRes.json();
console.log(`✅ Found ${matches.length} matches created`);
}
} else {
const error = await scheduleRes.json();
console.error('❌ Failed to start round robin:', error);
}
} catch (err) {
console.error('Error:', err.message);
}
}
startTournament();

44
scripts/testEnvLogin.js Normal file
View File

@@ -0,0 +1,44 @@
const fetch = require('node-fetch');
async function testEnvLogin() {
try {
console.log('Testing admin login with .env credentials...');
console.log('Username: admin, Password: 0000');
const loginRes = await fetch('http://localhost:4000/api/admin/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'admin',
password: '0000'
})
});
console.log('Response status:', loginRes.status);
const data = await loginRes.json();
console.log('Response data:', data);
if (loginRes.ok) {
console.log('✅ Login successful! Token received');
// Test the token by calling a protected endpoint
console.log('Testing protected endpoint...');
const teamsRes = await fetch('http://localhost:4000/api/teams', {
headers: { 'Authorization': `Bearer ${data.token}` }
});
if (teamsRes.ok) {
const teams = await teamsRes.json();
console.log(`✅ Token works! Found ${teams.length} teams`);
} else {
console.log('❌ Token validation failed');
}
} else {
console.log('❌ Login failed:', data.error);
}
} catch (err) {
console.error('Error:', err.message);
}
}
testEnvLogin();

30
scripts/testLogin.js Normal file
View File

@@ -0,0 +1,30 @@
const fetch = require('node-fetch');
const bcrypt = require('bcryptjs');
async function testLogin() {
try {
console.log('Testing admin login...');
const loginRes = await fetch('http://localhost:4000/api/admin/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'admin',
password: 'admin123'
})
});
console.log('Response status:', loginRes.status);
const data = await loginRes.json();
console.log('Response data:', data);
if (loginRes.ok) {
console.log('Login successful! Token:', data.token);
} else {
console.log('Login failed:', data.error);
}
} catch (err) {
console.error('Error:', err.message);
}
}
testLogin();

34
scripts/verifyPassword.js Normal file
View File

@@ -0,0 +1,34 @@
const { PrismaClient } = require('../generated/prisma');
const bcrypt = require('bcryptjs');
const prisma = new PrismaClient();
async function verifyPassword() {
try {
const admin = await prisma.adminUser.findUnique({ where: { username: 'admin' } });
if (!admin) {
console.log('Admin not found');
return;
}
console.log('Admin found:', { id: admin.id, username: admin.username });
console.log('Password hash:', admin.passwordHash);
const password = 'admin123';
const isValid = await bcrypt.compare(password, admin.passwordHash);
console.log('Password valid:', isValid);
// Test with a new hash
const newHash = await bcrypt.hash(password, 10);
console.log('New hash for same password:', newHash);
const isValidNew = await bcrypt.compare(password, newHash);
console.log('New hash valid:', isValidNew);
} catch (err) {
console.error('Error:', err);
} finally {
await prisma.$disconnect();
}
}
verifyPassword();