Alap API
Az alap api implementációja, ami kiszolgálja a kéréseket
This commit is contained in:
247
api.js
Normal file
247
api.js
Normal file
@@ -0,0 +1,247 @@
|
||||
import express from 'express';
|
||||
import dotenv from 'dotenv';
|
||||
import crypto from 'crypto';
|
||||
import mysql from 'mysql2/promise';
|
||||
|
||||
dotenv.config();
|
||||
|
||||
const {
|
||||
APP_PORT = 3000,
|
||||
DB_HOST = 'localhost',
|
||||
DB_PORT = 3306,
|
||||
DB_NAME = 'telefonkonyv',
|
||||
DB_USER = 'appuser',
|
||||
DB_PASSWORD = 'apppass',
|
||||
} = process.env;
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
|
||||
// --- DB pool ---
|
||||
const pool = mysql.createPool({
|
||||
host: DB_HOST,
|
||||
port: Number(DB_PORT),
|
||||
user: DB_USER,
|
||||
password: DB_PASSWORD,
|
||||
database: DB_NAME,
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
queueLimit: 0,
|
||||
});
|
||||
|
||||
// --- Helper: SHA-256 hash ---
|
||||
function sha256(text) {
|
||||
return crypto.createHash('sha256').update(String(text)).digest('hex');
|
||||
}
|
||||
|
||||
// --- Middleware: auth ---
|
||||
// A body-ban jön: { uname, pw }
|
||||
async function auth(req, res, next) {
|
||||
try {
|
||||
const { authUname, authPw } = req.body || {};
|
||||
if (!authUname || !authPw) {
|
||||
return res.status(401).json({ ok: false, error: 'Missing authUname or authPw' });
|
||||
}
|
||||
const hashed = sha256(authPw);
|
||||
const [rows] = await pool.query(
|
||||
'SELECT id, uname, admin FROM users WHERE uname = ? AND pw = ? LIMIT 1',
|
||||
[authUname, hashed]
|
||||
);
|
||||
if (!rows.length) return res.status(401).json({ ok: false, error: 'Invalid credentials' });
|
||||
req.user = rows[0];
|
||||
next();
|
||||
} catch (e) {
|
||||
console.error('auth error:', e);
|
||||
res.status(500).json({ ok: false, error: 'Auth failed' });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --- Middleware: adminCheck ---
|
||||
function adminCheck(req, res, next) {
|
||||
if (!req.user?.admin) {
|
||||
return res.status(403).json({ ok: false, error: 'Admin required' });
|
||||
}
|
||||
next();
|
||||
}
|
||||
|
||||
// --- Root ---
|
||||
app.get('/', (req, res) => {
|
||||
res.json({ status: 'ok' });
|
||||
});
|
||||
|
||||
// --- /auth ---
|
||||
// POST { uname, pw } -> { ok, admin, userId }
|
||||
app.post('/auth', async (req, res) => {
|
||||
try {
|
||||
const { authUname, authPw } = req.body || {};
|
||||
if (!authUname || !authPw) {
|
||||
return res.status(400).json({ ok: false, error: 'Missing authUname or authPw' });
|
||||
}
|
||||
const hashed = sha256(authPw);
|
||||
const [rows] = await pool.query(
|
||||
'SELECT id, admin FROM users WHERE uname = ? AND pw = ? LIMIT 1',
|
||||
[authUname, hashed]
|
||||
);
|
||||
if (!rows.length) return res.json({ ok: false, admin: false });
|
||||
res.json({ ok: true, admin: !!rows[0].admin, userId: rows[0].id });
|
||||
} catch (e) {
|
||||
console.error('/auth error:', e);
|
||||
res.status(500).json({ ok: false, error: 'Auth error' });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// --- /users (admin only) ---
|
||||
app.get('/users', auth, adminCheck, async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(
|
||||
'SELECT id, uname, admin, note FROM users ORDER BY id ASC'
|
||||
);
|
||||
res.json({ ok: true, users: rows });
|
||||
} catch (err) {
|
||||
console.error('GET /users error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// POST: { uname, pw, admin?, note? }
|
||||
app.post('/users', auth, adminCheck, async (req, res) => {
|
||||
try {
|
||||
const { uname, pw, admin = false, note = null } = req.body || {};
|
||||
if (!uname || !pw) {
|
||||
return res.status(400).json({ ok: false, error: 'uname and pw required' });
|
||||
}
|
||||
const hashed = sha256(pw);
|
||||
const [result] = await pool.query(
|
||||
'INSERT INTO users (uname, pw, admin, note) VALUES (?, ?, ?, ?)',
|
||||
[uname, hashed, !!admin, note]
|
||||
);
|
||||
res.status(201).json({ ok: true, id: result.insertId });
|
||||
} catch (err) {
|
||||
console.error('POST /users error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// PATCH: body tartalmazza az id-t és a módosítandó mezőket
|
||||
// Pl.: { id, uname?, pw?(plain), admin?, note? }
|
||||
app.patch('/users', auth, adminCheck, async (req, res) => {
|
||||
try {
|
||||
const { id, uname, pw, admin, note } = req.body || {};
|
||||
if (!id) return res.status(400).json({ ok: false, error: 'id required' });
|
||||
|
||||
// Olvassuk ki az aktuális rekordot
|
||||
const [rows] = await pool.query('SELECT * FROM users WHERE id = ? LIMIT 1', [id]);
|
||||
if (!rows.length) return res.status(404).json({ ok: false, error: 'User not found' });
|
||||
|
||||
const current = rows[0];
|
||||
const newUname = uname ?? current.uname;
|
||||
const newPw = pw ? sha256(pw) : current.pw;
|
||||
const newAdmin = (admin === undefined ? current.admin : !!admin);
|
||||
const newNote = (note === undefined ? current.note : note);
|
||||
|
||||
await pool.query(
|
||||
'UPDATE users SET uname = ?, pw = ?, admin = ?, note = ? WHERE id = ?',
|
||||
[newUname, newPw, newAdmin, newNote, id]
|
||||
);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
console.error('PATCH /users error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE: { id }
|
||||
app.delete('/users', auth, adminCheck, async (req, res) => {
|
||||
try {
|
||||
const { id } = req.body || {};
|
||||
if (!id) return res.status(400).json({ ok: false, error: 'id required' });
|
||||
|
||||
const [result] = await pool.query('DELETE FROM users WHERE id = ?', [id]);
|
||||
res.json({ ok: true, deleted: result.affectedRows });
|
||||
} catch (err) {
|
||||
console.error('DELETE /users error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// --- /contacts (auth required) ---
|
||||
|
||||
// GET: listázás
|
||||
app.get('/contacts', auth, async (req, res) => {
|
||||
try {
|
||||
const [rows] = await pool.query(
|
||||
'SELECT id, name, phone, address, note FROM contacts ORDER BY id ASC'
|
||||
);
|
||||
res.json({ ok: true, contacts: rows });
|
||||
} catch (err) {
|
||||
console.error('GET /contacts error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// POST: { name, phone, address?, note? } — elfogadja a "phome"-ot is
|
||||
app.post('/contacts', auth, async (req, res) => {
|
||||
try {
|
||||
const { name, phone: rawPhone, phome, address = null, note = null } = req.body || {};
|
||||
const phone = rawPhone ?? phome; // ha véletlen "phome" érkezik
|
||||
if (!name || !phone) {
|
||||
return res.status(400).json({ ok: false, error: 'name and phone required' });
|
||||
}
|
||||
const [result] = await pool.query(
|
||||
'INSERT INTO contacts (name, phone, address, note) VALUES (?, ?, ?, ?)',
|
||||
[name, phone, address, note]
|
||||
);
|
||||
res.status(201).json({ ok: true, id: result.insertId });
|
||||
} catch (err) {
|
||||
console.error('POST /contacts error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// PATCH: { id, name?, phone?/phome?, address?, note? }
|
||||
app.patch('/contacts', auth, async (req, res) => {
|
||||
try {
|
||||
const { id, name, phone: rawPhone, phome, address, note } = req.body || {};
|
||||
if (!id) return res.status(400).json({ ok: false, error: 'id required' });
|
||||
|
||||
const [rows] = await pool.query('SELECT * FROM contacts WHERE id = ? LIMIT 1', [id]);
|
||||
if (!rows.length) return res.status(404).json({ ok: false, error: 'Contact not found' });
|
||||
|
||||
const current = rows[0];
|
||||
const phone = (rawPhone ?? phome);
|
||||
const newName = name ?? current.name;
|
||||
const newPhone = (phone === undefined ? current.phone : phone);
|
||||
const newAddress = (address === undefined ? current.address : address);
|
||||
const newNote = (note === undefined ? current.note : note);
|
||||
|
||||
await pool.query(
|
||||
'UPDATE contacts SET name = ?, phone = ?, address = ?, note = ? WHERE id = ?',
|
||||
[newName, newPhone, newAddress, newNote, id]
|
||||
);
|
||||
res.json({ ok: true });
|
||||
} catch (err) {
|
||||
console.error('PATCH /contacts error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE: { id }
|
||||
app.delete('/contacts', auth, async (req, res) => {
|
||||
try {
|
||||
const { id } = req.body || {};
|
||||
if (!id) return res.status(400).json({ ok: false, error: 'id required' });
|
||||
|
||||
const [result] = await pool.query('DELETE FROM contacts WHERE id = ?', [id]);
|
||||
res.json({ ok: true, deleted: result.affectedRows });
|
||||
} catch (err) {
|
||||
console.error('DELETE /contacts error:', err);
|
||||
res.status(500).json({ ok: false, error: 'DB error' });
|
||||
}
|
||||
});
|
||||
|
||||
// --- Start ---
|
||||
app.listen(APP_PORT, () => {
|
||||
console.log(`API listening on port ${APP_PORT}`);
|
||||
});
|
||||
Reference in New Issue
Block a user