1027 lines
37 KiB
JavaScript
1027 lines
37 KiB
JavaScript
// Import necessary modules
|
|
const express = require('express');
|
|
const cors = require('cors');
|
|
const admin = require('firebase-admin');
|
|
const mysql = require('mysql');
|
|
const dotenv = require('dotenv');
|
|
const util = require('util');
|
|
|
|
// Load environment variables from .env file
|
|
dotenv.config();
|
|
|
|
// Firebase Admin SDK configuration
|
|
const serviceAccount = require('./config/serviceAccountKey.json'); // Update path if needed
|
|
admin.initializeApp({
|
|
credential: admin.credential.cert(serviceAccount)
|
|
});
|
|
|
|
// MySQL database connection setup
|
|
const db = mysql.createConnection({
|
|
host: process.env.MYSQL_HOST,
|
|
user: process.env.MYSQL_USER,
|
|
password: process.env.MYSQL_PASSWORD,
|
|
database: process.env.MYSQL_DATABASE,
|
|
});
|
|
|
|
// Alternative local config (commented)
|
|
// const db = mysql.createConnection({
|
|
// host: "localhost",
|
|
// user: "root",
|
|
// password: "",
|
|
// database:"iskalnik_dztps"
|
|
// });
|
|
|
|
db.connect((err) => {
|
|
if (err) {
|
|
console.error('MySQL connection failed:', err);
|
|
} else {
|
|
console.log('Connected to MySQL database');
|
|
}
|
|
});
|
|
|
|
// --- Promise helpers for mysql (node-mysql, not mysql2) ---
|
|
const query = util.promisify(db.query).bind(db);
|
|
const beginTransaction = util.promisify(db.beginTransaction).bind(db);
|
|
const commit = util.promisify(db.commit).bind(db);
|
|
const rollback = util.promisify(db.rollback).bind(db);
|
|
|
|
// Express application
|
|
const app = express();
|
|
|
|
// Middleware
|
|
app.use(cors());
|
|
app.use(express.json());
|
|
|
|
// Firebase authentication middleware
|
|
const authenticateFirebaseToken = async (req, res, next) => {
|
|
try {
|
|
const { authorization } = req.headers;
|
|
if (!authorization || !authorization.startsWith('Bearer ')) {
|
|
return res.status(401).json({ message: 'Unauthorized' });
|
|
}
|
|
|
|
const idToken = authorization.split('Bearer ')[1];
|
|
const decodedToken = await admin.auth().verifyIdToken(idToken);
|
|
req.uid = decodedToken.uid;
|
|
next();
|
|
} catch (error) {
|
|
console.error('Error authenticating Firebase token:', error);
|
|
return res.status(401).json({ message: 'Unauthorized' });
|
|
}
|
|
};
|
|
|
|
// Protected route example
|
|
app.get('/express', authenticateFirebaseToken, (req, res) => {
|
|
res.json({ message: 'Protected route accessed successfully' });
|
|
});
|
|
|
|
// Start the Express server
|
|
const PORT = process.env.PORT || 3000;
|
|
app.listen(PORT, () => {
|
|
console.log(`Server is running on port ${PORT}`);
|
|
});
|
|
|
|
|
|
/**********************************
|
|
* clan
|
|
*********************************/
|
|
|
|
function formClanStruct(from, id = null) {
|
|
if (!id) id = from.id;
|
|
return {
|
|
id,
|
|
id_izkaznica: from.id_izkaznica || "",
|
|
ime: from.ime || "",
|
|
priimek: from.priimek || "",
|
|
spol: from.spol || "",
|
|
datum_rojstva: from.datum_rojstva || "",
|
|
kraj_rojstva: from.kraj_rojstva || "",
|
|
drzavljanstvo: from.drzavljanstvo || "",
|
|
solska_izobrazba: from.solska_izobrazba || "",
|
|
telefondoma: from.telefondoma || "",
|
|
telefonsluzba: from.telefonsluzba || "",
|
|
telefonmobi: from.telefonmobi || "",
|
|
email: from.email || "",
|
|
spletnastran: from.spletnastran || "",
|
|
naslovbivalisca: from.naslovbivalisca || "",
|
|
ulica: from.ulica || "",
|
|
postna_stevilka: from.postna_stevilka || "",
|
|
posta: from.posta || "",
|
|
osnovni_poklic: from.osnovni_poklic || "",
|
|
sedanja_zaposlitev: from.sedanja_zaposlitev || "",
|
|
prevajalska_praksa: from.prevajalska_praksa || "",
|
|
nacin_pridobivanja_znanja_tujih_jezikov: from.nacin_pridobivanja_znanja_tujih_jezikov || "",
|
|
datum_vclanitve: from.datum_vclanitve || "",
|
|
materni_jezik: from.materni_jezik || "",
|
|
objava_v_iskalniku: from.objava_v_iskalniku || 0
|
|
}
|
|
}
|
|
|
|
function formClanValueArray(req) {
|
|
const body = req.body || {};
|
|
return [
|
|
body.id_izkaznica, body.ime, body.priimek, body.spol,
|
|
body.datum_rojstva ? new Date(body.datum_rojstva) : null,
|
|
body.kraj_rojstva, body.drzavljanstvo, body.solska_izobrazba, body.telefondoma,
|
|
body.telefonsluzba, body.telefonmobi, body.email, body.spletnastran, body.naslovbivalisca,
|
|
body.ulica, body.postna_stevilka, body.posta, body.osnovni_poklic, body.sedanja_zaposlitev,
|
|
body.prevajalska_praksa, body.nacin_pridobivanja_znanja_tujih_jezikov,
|
|
body.datum_vclanitve ? new Date(body.datum_vclanitve) : null,
|
|
body.materni_jezik, body.objava_v_iskalniku
|
|
];
|
|
}
|
|
|
|
app.get("/express/api/v1/clan/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT * FROM clan`, (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
const out = result.map(row => formClanStruct(row));
|
|
res.status(200).json(out);
|
|
});
|
|
});
|
|
|
|
app.get("/express/api/v1/clan/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT * FROM clan WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
if (!result.length) return res.sendStatus(404);
|
|
res.status(200).json(formClanStruct(result[0]));
|
|
});
|
|
});
|
|
|
|
app.post("/express/api/v1/clan/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(
|
|
`INSERT INTO clan (
|
|
id_izkaznica, ime, priimek, spol, datum_rojstva, kraj_rojstva,
|
|
drzavljanstvo, solska_izobrazba, telefondoma, telefonsluzba,
|
|
telefonmobi, email, spletnastran, naslovbivalisca, ulica,
|
|
postna_stevilka, posta, osnovni_poklic, sedanja_zaposlitev, prevajalska_praksa,
|
|
nacin_pridobivanja_znanja_tujih_jezikov, datum_vclanitve, materni_jezik, objava_v_iskalniku
|
|
)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
formClanValueArray(req),
|
|
(err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formClanStruct(req.body, result.insertId));
|
|
} else {
|
|
console.error("INSERT /clan error:", err);
|
|
res.sendStatus(400);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
app.put("/express/api/v1/clan/:id", authenticateFirebaseToken, (req, res) => {
|
|
const valueArr = formClanValueArray(req);
|
|
valueArr.push(req.params.id);
|
|
db.query(
|
|
`UPDATE clan
|
|
SET id_izkaznica=?, ime=?, priimek=?, spol=?, datum_rojstva=?, kraj_rojstva=?,
|
|
drzavljanstvo=?, solska_izobrazba=?, telefondoma=?, telefonsluzba=?,
|
|
telefonmobi=?, email=?, spletnastran=?, naslovbivalisca=?, ulica=?,
|
|
postna_stevilka=?, posta=?, osnovni_poklic=?, sedanja_zaposlitev=?, prevajalska_praksa=?,
|
|
nacin_pridobivanja_znanja_tujih_jezikov=?, datum_vclanitve=?,
|
|
materni_jezik=?, objava_v_iskalniku=?
|
|
WHERE id=?`,
|
|
valueArr,
|
|
(err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formClanStruct(req.body, req.params.id));
|
|
} else {
|
|
console.error("UPDATE /clan error:", err);
|
|
res.sendStatus(400);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
app.delete("/express/api/v1/clan/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`DELETE FROM clan WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.sendStatus(200);
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
/**********************************
|
|
* prevod (translations)
|
|
*********************************/
|
|
|
|
// Safe helpers that reject on error
|
|
function getVloge(prevodID) {
|
|
return new Promise((resolve, reject) => {
|
|
db.query(
|
|
`SELECT v.id AS id, v.vloga, v.izpis_zenska, v.izpis_moski
|
|
FROM prevod_vloga pv
|
|
JOIN vloga v ON pv.vloga_id = v.id
|
|
WHERE pv.prevod_id = ?`,
|
|
[prevodID],
|
|
(err, result) => {
|
|
if (err) return reject(err);
|
|
resolve(result.map(row => ({
|
|
id: row.id,
|
|
vloga: row.vloga,
|
|
izpis_zenska: row.izpis_zenska,
|
|
izpis_moski: row.izpis_moski
|
|
})));
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
function getPodrocja(prevodID) {
|
|
return new Promise((resolve, reject) => {
|
|
db.query(
|
|
`SELECT p.id AS id, p.podrocje
|
|
FROM prevod_podrocje pp
|
|
JOIN podrocje p ON pp.podrocje_id = p.id
|
|
WHERE pp.prevod_id = ?`,
|
|
[prevodID],
|
|
(err, result) => {
|
|
if (err) return reject(err);
|
|
resolve(result.map(row => ({ id: row.id, podrocje: row.podrocje })));
|
|
}
|
|
);
|
|
});
|
|
}
|
|
|
|
async function formPrevodStruct(from, id = null) {
|
|
const pid = id || from.id;
|
|
const out = {
|
|
id: pid,
|
|
id_clan: from.id_clan,
|
|
rang: from.rang,
|
|
iz: from.iz,
|
|
v: from.v,
|
|
licenca_DZTPS: from.licenca_DZTPS
|
|
};
|
|
out.podrocja = await getPodrocja(pid);
|
|
out.vloge = await getVloge(pid);
|
|
return out;
|
|
}
|
|
|
|
app.get("/express/api/v1/clan/:id/prevod/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(
|
|
`SELECT p.id AS id, p.id_clan, p.rang, iz.jezik AS iz, v.jezik AS v, p.licenca_DZTPS
|
|
FROM prevod p
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE p.id_clan = ?`,
|
|
[req.params.id],
|
|
async (err, result) => {
|
|
if (err) {
|
|
console.error("DB error (prevod list):", err);
|
|
return res.sendStatus(500);
|
|
}
|
|
try {
|
|
const out = await Promise.all(result.map(row => formPrevodStruct(row)));
|
|
res.status(200).json(out);
|
|
} catch (e) {
|
|
console.error("Error assembling prevod response:", e);
|
|
res.sendStatus(500);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
app.get("/express/api/v1/clan/:id/prevod/:pid", authenticateFirebaseToken, (req, res) => {
|
|
db.query(
|
|
`SELECT p.id AS id, p.id_clan, p.rang, iz.jezik AS iz, v.jezik AS v, p.licenca_DZTPS
|
|
FROM prevod p
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE p.id_clan = ? AND p.id = ?`,
|
|
[req.params.id, req.params.pid],
|
|
async (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
if (!result.length) return res.sendStatus(404);
|
|
try {
|
|
const out = await formPrevodStruct(result[0]);
|
|
res.status(200).json(out);
|
|
} catch (e) {
|
|
console.error("Error assembling single prevod:", e);
|
|
res.sendStatus(500);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
// Helpers to add/remove relations
|
|
async function addPrevodVloga(prevodID, vloga) {
|
|
await query(
|
|
`INSERT INTO prevod_vloga (prevod_id, vloga_id)
|
|
VALUES (?, (SELECT v.id FROM vloga v WHERE v.vloga = ?))`,
|
|
[prevodID, vloga]
|
|
);
|
|
}
|
|
async function removePrevodVloga(prevodID, vloga) {
|
|
await query(
|
|
`DELETE FROM prevod_vloga
|
|
WHERE prevod_id = ? AND vloga_id = (SELECT v.id FROM vloga v WHERE v.vloga = ?)`,
|
|
[prevodID, vloga]
|
|
);
|
|
}
|
|
async function addPrevodPodrocje(prevodID, podrocje) {
|
|
await query(
|
|
`INSERT INTO prevod_podrocje (prevod_id, podrocje_id)
|
|
VALUES (?, (SELECT p.id FROM podrocje p WHERE p.podrocje = ?))`,
|
|
[prevodID, podrocje]
|
|
);
|
|
}
|
|
async function removePrevodPodrocje(prevodID, podrocje) {
|
|
await query(
|
|
`DELETE FROM prevod_podrocje
|
|
WHERE prevod_id = ? AND podrocje_id = (SELECT p.id FROM podrocje p WHERE p.podrocje = ?)`,
|
|
[prevodID, podrocje]
|
|
);
|
|
}
|
|
|
|
function namesFromArray(arr, key) {
|
|
if (!Array.isArray(arr)) return [];
|
|
return arr.map(x => (typeof x === 'string' ? x : (x?.[key] ?? ''))).filter(Boolean);
|
|
}
|
|
|
|
// Create translation
|
|
app.post("/express/api/v1/clan/:id/prevod/", authenticateFirebaseToken, async (req, res) => {
|
|
const { id: pathId } = req.params;
|
|
const { id_clan, rang, iz, v, licenca_DZTPS, podrocja = [], vloge = [] } = req.body || {};
|
|
|
|
if (String(pathId) !== String(id_clan)) {
|
|
return res.status(400).json({ message: "id_clan in body must match :id in path" });
|
|
}
|
|
if (!rang || !iz || !v) {
|
|
return res.status(400).json({ message: "Missing required fields: rang, iz, v" });
|
|
}
|
|
|
|
try {
|
|
await beginTransaction();
|
|
|
|
// Resolve language IDs
|
|
const langs = await query(`SELECT id, jezik FROM jezik WHERE jezik IN (?, ?)`, [iz, v]);
|
|
const izRow = langs.find(r => r.jezik === iz);
|
|
const vRow = langs.find(r => r.jezik === v);
|
|
if (!izRow || !vRow) {
|
|
await rollback();
|
|
return res.status(400).json({ message: "Unknown language in iz or v" });
|
|
}
|
|
|
|
const insert = await query(
|
|
`INSERT INTO prevod (id_clan, rang, iz_id, v_id, licenca_DZTPS)
|
|
VALUES (?, ?, ?, ?, ?)`,
|
|
[id_clan, rang, izRow.id, vRow.id, licenca_DZTPS ?? 0]
|
|
);
|
|
const prevodID = insert.insertId;
|
|
|
|
// Podrocja
|
|
const podNames = namesFromArray(podrocja, 'podrocje');
|
|
if (podNames.length) {
|
|
const rows = await query(
|
|
`SELECT id, podrocje FROM podrocje WHERE podrocje IN (${podNames.map(() => '?').join(',')})`,
|
|
podNames
|
|
);
|
|
const mapIds = new Map(rows.map(r => [r.podrocje, r.id]));
|
|
const missing = podNames.filter(n => !mapIds.has(n));
|
|
if (missing.length) {
|
|
await rollback();
|
|
return res.status(400).json({ message: "Unknown podrocje", details: missing });
|
|
}
|
|
const values = podNames.map(n => [prevodID, mapIds.get(n)]);
|
|
await query(
|
|
`INSERT INTO prevod_podrocje (prevod_id, podrocje_id)
|
|
VALUES ${values.map(() => '(?, ?)').join(',')}`,
|
|
values.flat()
|
|
);
|
|
}
|
|
|
|
// Vloge
|
|
const vlogaNames = namesFromArray(vloge, 'vloga');
|
|
if (vlogaNames.length) {
|
|
const rows = await query(
|
|
`SELECT id, vloga FROM vloga WHERE vloga IN (${vlogaNames.map(() => '?').join(',')})`,
|
|
vlogaNames
|
|
);
|
|
const mapIds = new Map(rows.map(r => [r.vloga, r.id]));
|
|
const missing = vlogaNames.filter(n => !mapIds.has(n));
|
|
if (missing.length) {
|
|
await rollback();
|
|
return res.status(400).json({ message: "Unknown vloga", details: missing });
|
|
}
|
|
const values = vlogaNames.map(n => [prevodID, mapIds.get(n)]);
|
|
await query(
|
|
`INSERT INTO prevod_vloga (prevod_id, vloga_id)
|
|
VALUES ${values.map(() => '(?, ?)').join(',')}`,
|
|
values.flat()
|
|
);
|
|
}
|
|
|
|
await commit();
|
|
|
|
const [row] = await query(
|
|
`SELECT p.id AS id, p.id_clan, p.rang, iz.jezik AS iz, v.jezik AS v, p.licenca_DZTPS
|
|
FROM prevod p
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE p.id = ?`,
|
|
[prevodID]
|
|
);
|
|
const payload = await formPrevodStruct(row);
|
|
return res.status(200).json(payload);
|
|
|
|
} catch (e) {
|
|
try { await rollback(); } catch {}
|
|
console.error("POST /clan/:id/prevod error:", e);
|
|
return res.status(400).json({ message: "Failed to create prevod", error: e && e.message });
|
|
}
|
|
});
|
|
|
|
// Update translation
|
|
app.put("/express/api/v1/clan/:id/prevod/:pid", authenticateFirebaseToken, async (req, res) => {
|
|
const { id: pathId, pid } = req.params;
|
|
const { id_clan, rang, iz, v, licenca_DZTPS, podrocja = [], vloge = [] } = req.body || {};
|
|
|
|
if (String(pathId) !== String(id_clan)) {
|
|
return res.status(400).json({ message: "id_clan in body must match :id in path" });
|
|
}
|
|
|
|
try {
|
|
await beginTransaction();
|
|
|
|
// Resolve language IDs if provided strings
|
|
const langsNeeded = [];
|
|
if (iz) langsNeeded.push(iz);
|
|
if (v) langsNeeded.push(v);
|
|
|
|
let izId = null, vId = null;
|
|
if (langsNeeded.length) {
|
|
const langRows = await query(
|
|
`SELECT id, jezik FROM jezik WHERE jezik IN (${langsNeeded.map(() => '?').join(',')})`,
|
|
langsNeeded
|
|
);
|
|
const map = new Map(langRows.map(r => [r.jezik, r.id]));
|
|
if (iz && !map.has(iz)) { await rollback(); return res.status(400).json({ message: "Unknown language (iz)" }); }
|
|
if (v && !map.has(v)) { await rollback(); return res.status(400).json({ message: "Unknown language (v)" }); }
|
|
if (iz) izId = map.get(iz);
|
|
if (v) vId = map.get(v);
|
|
}
|
|
|
|
// Build dynamic UPDATE (keep current values if not provided)
|
|
const sets = [];
|
|
const params = [];
|
|
if (id_clan != null) { sets.push(`id_clan = ?`); params.push(id_clan); }
|
|
if (rang != null) { sets.push(`rang = ?`); params.push(rang); }
|
|
if (izId != null) { sets.push(`iz_id = ?`); params.push(izId); }
|
|
if (vId != null) { sets.push(`v_id = ?`); params.push(vId); }
|
|
if (licenca_DZTPS != null) { sets.push(`licenca_DZTPS = ?`); params.push(licenca_DZTPS); }
|
|
|
|
if (sets.length) {
|
|
params.push(pathId, pid);
|
|
const sql = `UPDATE prevod SET ${sets.join(', ')} WHERE id_clan = ? AND id = ?`;
|
|
const upd = await query(sql, params);
|
|
if (upd.affectedRows === 0) {
|
|
await rollback();
|
|
return res.sendStatus(404);
|
|
}
|
|
}
|
|
|
|
// Fetch old relations BEFORE syncing
|
|
const oldPodrocja = await getPodrocja(pid);
|
|
const oldVloge = await getVloge(pid);
|
|
|
|
// Sync Podrocja
|
|
const newPodrocjaNames = namesFromArray(podrocja, 'podrocje');
|
|
if (newPodrocjaNames.length) {
|
|
// Map names -> ids
|
|
const rows = await query(
|
|
`SELECT id, podrocje FROM podrocje WHERE podrocje IN (${newPodrocjaNames.map(() => '?').join(',')})`,
|
|
newPodrocjaNames
|
|
);
|
|
const mapIds = new Map(rows.map(r => [r.podrocje, r.id]));
|
|
const missing = newPodrocjaNames.filter(n => !mapIds.has(n));
|
|
if (missing.length) {
|
|
await rollback();
|
|
return res.status(400).json({ message: "Unknown podrocje", details: missing });
|
|
}
|
|
|
|
// Compute deltas by name
|
|
const oldNames = new Set(oldPodrocja.map(p => p.podrocje));
|
|
const newNames = new Set(newPodrocjaNames);
|
|
|
|
// Deletes
|
|
for (const name of oldNames) {
|
|
if (!newNames.has(name)) {
|
|
await removePrevodPodrocje(pid, name);
|
|
}
|
|
}
|
|
// Adds
|
|
for (const name of newNames) {
|
|
if (!oldNames.has(name)) {
|
|
await addPrevodPodrocje(pid, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sync Vloge
|
|
const newVlogaNames = namesFromArray(vloge, 'vloga');
|
|
if (newVlogaNames.length) {
|
|
const rows = await query(
|
|
`SELECT id, vloga FROM vloga WHERE vloga IN (${newVlogaNames.map(() => '?').join(',')})`,
|
|
newVlogaNames
|
|
);
|
|
const mapIds = new Map(rows.map(r => [r.vloga, r.id]));
|
|
const missing = newVlogaNames.filter(n => !mapIds.has(n));
|
|
if (missing.length) {
|
|
await rollback();
|
|
return res.status(400).json({ message: "Unknown vloga", details: missing });
|
|
}
|
|
|
|
const oldNames = new Set(oldVloge.map(v => v.vloga));
|
|
const newNames = new Set(newVlogaNames);
|
|
|
|
for (const name of oldNames) {
|
|
if (!newNames.has(name)) {
|
|
await removePrevodVloga(pid, name);
|
|
}
|
|
}
|
|
for (const name of newNames) {
|
|
if (!oldNames.has(name)) {
|
|
await addPrevodVloga(pid, name);
|
|
}
|
|
}
|
|
}
|
|
|
|
await commit();
|
|
|
|
// Return the updated record
|
|
const [row] = await query(
|
|
`SELECT p.id AS id, p.id_clan, p.rang, iz.jezik AS iz, v.jezik AS v, p.licenca_DZTPS
|
|
FROM prevod p
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE p.id = ?`,
|
|
[pid]
|
|
);
|
|
if (!row) return res.sendStatus(404);
|
|
const payload = await formPrevodStruct(row);
|
|
res.status(200).json(payload);
|
|
|
|
} catch (e) {
|
|
try { await rollback(); } catch {}
|
|
console.error("PUT /clan/:id/prevod/:pid error:", e);
|
|
res.status(400).json({ message: "Failed to update prevod", error: e && e.message });
|
|
}
|
|
});
|
|
|
|
app.delete("/express/api/v1/clan/:id/prevod/:pid", authenticateFirebaseToken, async (req, res) => {
|
|
try {
|
|
await beginTransaction();
|
|
await query(`DELETE FROM prevod_podrocje WHERE prevod_id = ?`, [req.params.pid]);
|
|
await query(`DELETE FROM prevod_vloga WHERE prevod_id = ?`, [req.params.pid]);
|
|
const del = await query(`DELETE FROM prevod WHERE id_clan = ? AND id = ?`, [req.params.id, req.params.pid]);
|
|
if (!del.affectedRows) { await rollback(); return res.sendStatus(404); }
|
|
await commit();
|
|
res.sendStatus(200);
|
|
} catch (e) {
|
|
try { await rollback(); } catch {}
|
|
console.error("DELETE /clan/:id/prevod/:pid error:", e);
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
|
|
|
|
/**********************************
|
|
* jezik
|
|
*********************************/
|
|
|
|
function formJezikStruct(from, id = null) {
|
|
if (!id) id = from.id;
|
|
return { id, jezik: from.jezik };
|
|
}
|
|
|
|
app.get("/express/api/v1/jezik/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT id, jezik FROM jezik`, (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
res.status(200).json(result.map(row => formJezikStruct(row)));
|
|
});
|
|
});
|
|
|
|
app.get("/express/api/v1/jezik/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT id, jezik FROM jezik WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
if (!result.length) return res.sendStatus(404);
|
|
res.status(200).json(formJezikStruct(result[0]));
|
|
});
|
|
});
|
|
|
|
app.post("/express/api/v1/jezik/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`INSERT INTO jezik (jezik) VALUES (?)`, [req.body.jezik], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formJezikStruct(req.body, result.insertId));
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
app.put("/express/api/v1/jezik/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`UPDATE jezik SET jezik = ? WHERE id = ?`, [req.body.jezik, req.params.id], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formJezikStruct(req.body, req.params.id));
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
app.delete("/express/api/v1/jezik/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`DELETE FROM jezik WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.sendStatus(200);
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
/**********************************
|
|
* vloga
|
|
*********************************/
|
|
|
|
function formVlogaStruct(from, id = null) {
|
|
if (!id) id = from.id;
|
|
return {
|
|
id,
|
|
vloga: from.vloga,
|
|
izpis_zenska: from.izpis_zenska,
|
|
izpis_moski: from.izpis_moski
|
|
};
|
|
}
|
|
|
|
app.get("/express/api/v1/vloga/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT id, vloga, izpis_zenska, izpis_moski FROM vloga`, (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
res.status(200).json(result.map(row => formVlogaStruct(row)));
|
|
});
|
|
});
|
|
|
|
app.get("/express/api/v1/vloga/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT id, vloga, izpis_zenska, izpis_moski FROM vloga WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
if (!result.length) return res.sendStatus(404);
|
|
res.status(200).json(formVlogaStruct(result[0]));
|
|
});
|
|
});
|
|
|
|
app.post("/express/api/v1/vloga/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(
|
|
`INSERT INTO vloga (vloga, izpis_zenska, izpis_moski) VALUES (?, ?, ?)`,
|
|
[req.body.vloga, req.body.izpis_zenska, req.body.izpis_moski],
|
|
(err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formVlogaStruct(req.body, result.insertId));
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
app.put("/express/api/v1/vloga/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(
|
|
`UPDATE vloga SET vloga = ?, izpis_zenska = ?, izpis_moski = ? WHERE id = ?`,
|
|
[req.body.vloga, req.body.izpis_zenska, req.body.izpis_moski, req.params.id],
|
|
(err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formVlogaStruct(req.body, req.params.id));
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
app.delete("/express/api/v1/vloga/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`DELETE FROM vloga WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.sendStatus(200);
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
/**********************************
|
|
* podrocje
|
|
*********************************/
|
|
|
|
function formPodrocjeStruct(from, id = null) {
|
|
if (!id) id = from.id;
|
|
return { id, podrocje: from.podrocje };
|
|
}
|
|
|
|
app.get("/express/api/v1/podrocje", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT id, podrocje FROM podrocje`, (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
res.status(200).json(result.map(row => formPodrocjeStruct(row)));
|
|
});
|
|
});
|
|
|
|
app.get("/express/api/v1/podrocje/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`SELECT id, podrocje FROM podrocje WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (err) return res.sendStatus(500);
|
|
if (!result.length) return res.sendStatus(404);
|
|
res.status(200).json(formPodrocjeStruct(result[0]));
|
|
});
|
|
});
|
|
|
|
app.post("/express/api/v1/podrocje/", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`INSERT INTO podrocje (podrocje) VALUES (?)`, [req.body.podrocje], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formPodrocjeStruct(req.body, result.insertId));
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
app.put("/express/api/v1/podrocje/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(
|
|
`UPDATE podrocje SET podrocje = ? WHERE id = ?`,
|
|
[req.body.podrocje, req.params.id],
|
|
(err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.status(200).json(formPodrocjeStruct(req.body, req.params.id));
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
}
|
|
);
|
|
});
|
|
|
|
app.delete("/express/api/v1/podrocje/:id", authenticateFirebaseToken, (req, res) => {
|
|
db.query(`DELETE FROM podrocje WHERE id = ?`, [req.params.id], (err, result) => {
|
|
if (!err && result.affectedRows === 1) {
|
|
res.sendStatus(200);
|
|
} else {
|
|
res.sendStatus(400);
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
/**********************************
|
|
* ISKALNIK (search)
|
|
*********************************/
|
|
|
|
app.get('/express_backend', (req, res) => {
|
|
res.send({ express: `YOUR BACKEND IS CONNECTED` });
|
|
});
|
|
|
|
app.post('/express_backend/api/v1/iskanje', (req, res) => {
|
|
const iskanjeIme = req.body.iskanjeNiz;
|
|
const iskanjeCrka = req.body.iskanjeCrkaPriimek;
|
|
const iskanjeIz = req.body.iskanjeIzvirniJezik;
|
|
const iskanjeV = req.body.iskanjeCiljniJezik;
|
|
const iskanjeRangi = req.body.iskanjeRang;
|
|
const iskanjePodrocja = new Set(req.body.iskanjeStrokovnoPodrocje);
|
|
const iskanjeVloge = new Set(req.body.iskanjeVloga);
|
|
const iskanjeLicenca = req.body.iskanjeLicenca;
|
|
|
|
// Build query
|
|
const params = [];
|
|
const queryConditions = [];
|
|
|
|
if (iskanjeIme) {
|
|
queryConditions.push("(LOWER(CONCAT(c.ime, ' ', c.priimek)) LIKE LOWER(?))");
|
|
params.push(`%${iskanjeIme}%`);
|
|
}
|
|
if (iskanjeCrka) {
|
|
queryConditions.push("(c.priimek LIKE (?))");
|
|
params.push(`${iskanjeCrka}%`);
|
|
}
|
|
if (iskanjeIz) {
|
|
queryConditions.push("(iz.jezik = (?))");
|
|
params.push(iskanjeIz);
|
|
}
|
|
if (iskanjeV) {
|
|
queryConditions.push("(v.jezik = (?))");
|
|
params.push(iskanjeV);
|
|
}
|
|
const generateQuestionMarks = (n) => Array.from({ length: n }, () => '?').join(',');
|
|
if (Array.isArray(iskanjeRangi) && iskanjeRangi.length) {
|
|
queryConditions.push(`(p.rang IN (${generateQuestionMarks(iskanjeRangi.length)}))`);
|
|
params.push(...iskanjeRangi);
|
|
}
|
|
if (iskanjeLicenca != null) {
|
|
queryConditions.push("(p.licenca_DZTPS = ?)");
|
|
params.push(iskanjeLicenca);
|
|
}
|
|
|
|
const where = [
|
|
"c.objava_v_iskalniku = 1",
|
|
...(queryConditions.length ? queryConditions : [])
|
|
].join(" AND ");
|
|
|
|
db.query(
|
|
`SELECT
|
|
c.id AS id, c.ime AS ime, c.priimek AS priimek, c.spol AS spol,
|
|
c.telefondoma AS telefondoma, c.telefonsluzba AS telefonsluzba,
|
|
c.telefonmobi AS telefonmobi, c.email AS email, c.spletnastran AS spletnastran,
|
|
p.rang AS rang, iz.jezik AS iz, v.jezik AS v, p.licenca_DZTPS AS licenca,
|
|
(
|
|
SELECT GROUP_CONCAT(po.podrocje SEPARATOR ';')
|
|
FROM prevod_podrocje pp
|
|
JOIN podrocje po ON pp.podrocje_id = po.id
|
|
WHERE pp.prevod_id = p.id
|
|
GROUP BY pp.prevod_id
|
|
) AS podrocja,
|
|
(
|
|
SELECT GROUP_CONCAT(vl.vloga SEPARATOR ';')
|
|
FROM prevod_vloga pv
|
|
JOIN vloga vl ON pv.vloga_id = vl.id
|
|
WHERE pv.prevod_id = p.id
|
|
GROUP BY pv.prevod_id
|
|
) AS vloge
|
|
FROM clan c
|
|
JOIN prevod p ON c.id = p.id_clan
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE ${where}`,
|
|
params,
|
|
(err, rows) => {
|
|
if (err) {
|
|
console.error("Search error:", err);
|
|
return res.sendStatus(500);
|
|
}
|
|
if (!rows.length) return res.send({});
|
|
|
|
let out = [];
|
|
for (let row of rows) {
|
|
if (out.length <= 0 || out[out.length - 1].id !== row.id) {
|
|
out.push({
|
|
id: row.id,
|
|
ime: row.ime,
|
|
priimek: row.priimek,
|
|
spol: row.spol,
|
|
telefondoma: row.telefondoma,
|
|
telefonmobi: row.telefonmobi,
|
|
telefonsluzba: row.telefonsluzba,
|
|
email: row.email,
|
|
spletnastran: row.spletnastran,
|
|
prevodi: [],
|
|
});
|
|
}
|
|
let podrocja = row.podrocja?.split(';') || [];
|
|
let vloge = row.vloge?.split(';') || [];
|
|
|
|
if (iskanjePodrocja.size) {
|
|
podrocja = podrocja.filter(el => iskanjePodrocja.has(el));
|
|
if (!podrocja.length) continue;
|
|
}
|
|
if (iskanjeVloge.size) {
|
|
vloge = vloge.filter(el => iskanjeVloge.has(el));
|
|
if (!vloge.length) continue;
|
|
}
|
|
|
|
out[out.length - 1].prevodi.push({
|
|
rang: row.rang,
|
|
iz: row.iz,
|
|
v: row.v,
|
|
strokovnopodrocje: row.podrocja?.split(';') || [],
|
|
vloga: row.vloge?.split(';') || [],
|
|
});
|
|
}
|
|
out = out.filter(row => row.prevodi.length > 0);
|
|
res.send(JSON.stringify(out, null, 4));
|
|
}
|
|
);
|
|
});
|
|
|
|
app.get("/express_backend/api/get/user/:user_id", (req, res) => {
|
|
db.query(
|
|
`SELECT
|
|
c.id AS id, c.ime AS ime, c.priimek AS priimek, c.spol AS spol,
|
|
c.telefondoma AS telefondoma, c.telefonsluzba AS telefonsluzba,
|
|
c.telefonmobi AS telefonmobi, c.email AS email, c.spletnastran AS spletnastran,
|
|
p.id AS id_prevod, p.rang AS rang, iz.jezik AS iz, v.jezik AS v,
|
|
(
|
|
SELECT GROUP_CONCAT(po.podrocje SEPARATOR ';')
|
|
FROM prevod_podrocje pp
|
|
JOIN podrocje po ON pp.podrocje_id = po.id
|
|
WHERE pp.prevod_id = p.id
|
|
GROUP BY pp.prevod_id
|
|
) AS podrocja,
|
|
(
|
|
SELECT GROUP_CONCAT(vl.vloga SEPARATOR ';')
|
|
FROM prevod_vloga pv
|
|
JOIN vloga vl ON pv.vloga_id = vl.id
|
|
WHERE pv.prevod_id = p.id
|
|
GROUP BY pv.prevod_id
|
|
) AS vloge
|
|
FROM clan c
|
|
JOIN prevod p ON c.id = p.id_clan
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE c.id = ? AND c.objava_v_iskalniku = 1
|
|
ORDER BY p.rang`,
|
|
[req.params.user_id],
|
|
(err, rows) => {
|
|
if (err) {
|
|
console.error("get/user error:", err);
|
|
return res.sendStatus(500);
|
|
}
|
|
if (!rows.length) return res.send({});
|
|
|
|
const first = rows[0];
|
|
const out = {
|
|
id: first.id,
|
|
ime: first.ime,
|
|
priimek: first.priimek,
|
|
telefondoma: first.telefondoma,
|
|
telefonmobi: first.telefonmobi,
|
|
telefonsluzba: first.telefonsluzba,
|
|
email: first.email,
|
|
spletnastran: first.spletnastran,
|
|
prevodi: [],
|
|
};
|
|
for (let row of rows) {
|
|
out.prevodi.push({
|
|
id: row.id_prevod,
|
|
rang: row.rang,
|
|
iz: row.iz,
|
|
v: row.v,
|
|
strokovnopodrocje: row.podrocja?.split(';') || [],
|
|
vloga: row.vloge?.split(';') || [],
|
|
});
|
|
}
|
|
res.send(JSON.stringify(out, null, 4));
|
|
}
|
|
);
|
|
});
|
|
|
|
app.get("/express_backend/api/getAll", (req, res) => {
|
|
db.query(
|
|
`SELECT
|
|
c.id AS id, c.ime AS ime, c.priimek AS priimek, c.spol AS spol,
|
|
c.telefondoma AS telefondoma, c.telefonsluzba AS telefonsluzba,
|
|
c.telefonmobi AS telefonmobi, c.email AS email, c.spletnastran AS spletnastran,
|
|
p.rang AS rang, iz.jezik AS iz, v.jezik AS v,
|
|
(
|
|
SELECT GROUP_CONCAT(po.podrocje SEPARATOR ';')
|
|
FROM prevod_podrocje pp
|
|
JOIN podrocje po ON pp.podrocje_id = po.id
|
|
WHERE pp.prevod_id = p.id
|
|
GROUP BY pp.prevod_id
|
|
) AS podrocja,
|
|
(
|
|
SELECT GROUP_CONCAT(vl.vloga SEPARATOR ';')
|
|
FROM prevod_vloga pv
|
|
JOIN vloga vl ON pv.vloga_id = vl.id
|
|
WHERE pv.prevod_id = p.id
|
|
GROUP BY pv.prevod_id
|
|
) AS vloge
|
|
FROM clan c
|
|
JOIN prevod p ON c.id = p.id_clan
|
|
JOIN jezik iz ON p.iz_id = iz.id
|
|
JOIN jezik v ON p.v_id = v.id
|
|
WHERE c.objava_v_iskalniku = 1`,
|
|
(err, rows) => {
|
|
if (err) {
|
|
console.error("getAll error:", err);
|
|
return res.sendStatus(500);
|
|
}
|
|
|
|
// Group prevodi per user
|
|
let out = [];
|
|
for (let row of rows) {
|
|
if (out.length <= 0 || out[out.length - 1].id !== row.id) {
|
|
out.push({
|
|
id: row.id,
|
|
ime: row.ime,
|
|
priimek: row.priimek,
|
|
spol: row.spol,
|
|
telefondoma: row.telefondoma,
|
|
telefonmobi: row.telefonmobi,
|
|
telefonsluzba: row.telefonsluzba,
|
|
email: row.email,
|
|
spletnastran: row.spletnastran,
|
|
prevodi: [],
|
|
});
|
|
}
|
|
out[out.length - 1].prevodi.push({
|
|
rang: row.rang,
|
|
iz: row.iz,
|
|
v: row.v,
|
|
strokovnopodrocje: row.podrocja?.split(';') || [],
|
|
vloga: row.vloge?.split(';') || [],
|
|
});
|
|
}
|
|
res.send(JSON.stringify(out, null, 4));
|
|
}
|
|
);
|
|
});
|
|
|
|
// app.listen(PORT, () => { console.log(`Server listening on port ${PORT}`); });
|