feat: rewrite db.php from PDO to MySQLi
PDO extension was not available on CloudLinux/alt-php84 server. MySQLi is available, so rewrote entire database layer to use it. Added helper functions (_dbRun, _dbFetchAll, _dbFetchOne, etc.) that handle named parameter conversion and type binding automatically. All public db*() function signatures remain identical. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
445
db.php
445
db.php
@@ -1,6 +1,6 @@
|
|||||||
<?php
|
<?php
|
||||||
/**
|
/**
|
||||||
* Noxus Intra — Tietokantakerros (PDO/MySQL)
|
* Noxus Intra — Tietokantakerros (MySQLi)
|
||||||
*
|
*
|
||||||
* Korvaa kaikki JSON-tiedosto-operaatiot MySQL-kutsuilla.
|
* Korvaa kaikki JSON-tiedosto-operaatiot MySQL-kutsuilla.
|
||||||
* Funktiot palauttavat samat tietorakenteet kuin vanhat JSON-funktiot.
|
* Funktiot palauttavat samat tietorakenteet kuin vanhat JSON-funktiot.
|
||||||
@@ -8,22 +8,102 @@
|
|||||||
|
|
||||||
// ==================== YHTEYS ====================
|
// ==================== YHTEYS ====================
|
||||||
|
|
||||||
function getDb(): PDO {
|
function getDb(): mysqli {
|
||||||
static $pdo = null;
|
static $db = null;
|
||||||
if ($pdo === null) {
|
if ($db === null) {
|
||||||
$configFile = __DIR__ . '/db_config.php';
|
$configFile = __DIR__ . '/db_config.php';
|
||||||
if (!file_exists($configFile)) {
|
if (!file_exists($configFile)) {
|
||||||
throw new RuntimeException('db_config.php puuttuu! Kopioi db_config.php.example ja täytä tiedot.');
|
throw new RuntimeException('db_config.php puuttuu! Kopioi db_config.php.example ja täytä tiedot.');
|
||||||
}
|
}
|
||||||
$cfg = require $configFile;
|
$cfg = require $configFile;
|
||||||
$dsn = "mysql:host={$cfg['host']};dbname={$cfg['dbname']};charset={$cfg['charset']}";
|
|
||||||
$pdo = new PDO($dsn, $cfg['username'], $cfg['password'], [
|
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
|
||||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
|
$db = new mysqli($cfg['host'], $cfg['username'], $cfg['password'], $cfg['dbname']);
|
||||||
PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
|
$db->set_charset($cfg['charset'] ?? 'utf8mb4');
|
||||||
PDO::ATTR_EMULATE_PREPARES => false,
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
return $pdo;
|
return $db;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==================== HELPER-FUNKTIOT ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Valmistele ja suorita kysely. Tukee sekä nimettyja (:name) että positiivisia (?) parametreja.
|
||||||
|
*/
|
||||||
|
function _dbRun(string $sql, array $params = []): mysqli_stmt {
|
||||||
|
$db = getDb();
|
||||||
|
|
||||||
|
// Muunna nimetyt parametrit (:name) positiivisiksi (?)
|
||||||
|
if (!empty($params) && !array_is_list($params)) {
|
||||||
|
$ordered = [];
|
||||||
|
$sql = preg_replace_callback('/:(\w+)/', function($m) use ($params, &$ordered) {
|
||||||
|
$key = $m[1];
|
||||||
|
$ordered[] = array_key_exists($key, $params) ? $params[$key] : null;
|
||||||
|
return '?';
|
||||||
|
}, $sql);
|
||||||
|
$params = $ordered;
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $db->prepare($sql);
|
||||||
|
if ($stmt === false) {
|
||||||
|
throw new RuntimeException("MySQL prepare failed: " . $db->error);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!empty($params)) {
|
||||||
|
$types = '';
|
||||||
|
foreach ($params as $p) {
|
||||||
|
if (is_int($p)) $types .= 'i';
|
||||||
|
elseif (is_float($p)) $types .= 'd';
|
||||||
|
elseif (is_bool($p)) $types .= 'i';
|
||||||
|
else $types .= 's';
|
||||||
|
}
|
||||||
|
// Booleanit → int
|
||||||
|
$vals = array_map(fn($v) => is_bool($v) ? (int)$v : $v, array_values($params));
|
||||||
|
$stmt->bind_param($types, ...$vals);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt->execute();
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** SELECT — kaikki rivit */
|
||||||
|
function _dbFetchAll(string $sql, array $params = []): array {
|
||||||
|
$stmt = _dbRun($sql, $params);
|
||||||
|
$result = $stmt->get_result();
|
||||||
|
return $result ? $result->fetch_all(MYSQLI_ASSOC) : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** SELECT — yksi rivi */
|
||||||
|
function _dbFetchOne(string $sql, array $params = []): ?array {
|
||||||
|
$stmt = _dbRun($sql, $params);
|
||||||
|
$result = $stmt->get_result();
|
||||||
|
$row = $result ? $result->fetch_assoc() : null;
|
||||||
|
return $row ?: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** SELECT — yhden sarakkeen arvot */
|
||||||
|
function _dbFetchColumn(string $sql, array $params = []): array {
|
||||||
|
$stmt = _dbRun($sql, $params);
|
||||||
|
$result = $stmt->get_result();
|
||||||
|
if (!$result) return [];
|
||||||
|
$col = [];
|
||||||
|
while ($row = $result->fetch_row()) {
|
||||||
|
$col[] = $row[0];
|
||||||
|
}
|
||||||
|
return $col;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** SELECT — yksittäinen skalaariarvo */
|
||||||
|
function _dbFetchScalar(string $sql, array $params = []) {
|
||||||
|
$stmt = _dbRun($sql, $params);
|
||||||
|
$result = $stmt->get_result();
|
||||||
|
$row = $result ? $result->fetch_row() : null;
|
||||||
|
return $row ? $row[0] : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** INSERT/UPDATE/DELETE — suorita, palauta affected_rows */
|
||||||
|
function _dbExecute(string $sql, array $params = []): int {
|
||||||
|
$stmt = _dbRun($sql, $params);
|
||||||
|
return $stmt->affected_rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== TAULUJEN LUONTI ====================
|
// ==================== TAULUJEN LUONTI ====================
|
||||||
@@ -31,7 +111,6 @@ function getDb(): PDO {
|
|||||||
function initDatabase(): void {
|
function initDatabase(): void {
|
||||||
$db = getDb();
|
$db = getDb();
|
||||||
|
|
||||||
// Jokainen CREATE TABLE omana exec()-kutsuna — MySQL/PDO ei tue useaa lausetta kerralla
|
|
||||||
$tables = [
|
$tables = [
|
||||||
"CREATE TABLE IF NOT EXISTS companies (
|
"CREATE TABLE IF NOT EXISTS companies (
|
||||||
id VARCHAR(50) PRIMARY KEY,
|
id VARCHAR(50) PRIMARY KEY,
|
||||||
@@ -264,10 +343,8 @@ function initDatabase(): void {
|
|||||||
];
|
];
|
||||||
|
|
||||||
foreach ($tables as $i => $sql) {
|
foreach ($tables as $i => $sql) {
|
||||||
try {
|
if ($db->query($sql) === false) {
|
||||||
$db->exec($sql);
|
throw new RuntimeException("Taulun luonti epäonnistui (taulu #" . ($i+1) . "): " . $db->error);
|
||||||
} catch (PDOException $e) {
|
|
||||||
throw new RuntimeException("Taulun luonti epäonnistui (taulu #" . ($i+1) . "): " . $e->getMessage());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -275,14 +352,10 @@ function initDatabase(): void {
|
|||||||
// ==================== YRITYKSET ====================
|
// ==================== YRITYKSET ====================
|
||||||
|
|
||||||
function dbLoadCompanies(): array {
|
function dbLoadCompanies(): array {
|
||||||
$db = getDb();
|
$companies = _dbFetchAll("SELECT * FROM companies ORDER BY nimi");
|
||||||
$companies = $db->query("SELECT * FROM companies ORDER BY nimi")->fetchAll();
|
|
||||||
|
|
||||||
// Liitä domainit
|
|
||||||
foreach ($companies as &$c) {
|
foreach ($companies as &$c) {
|
||||||
$stmt = $db->prepare("SELECT domain FROM company_domains WHERE company_id = ?");
|
$c['domains'] = _dbFetchColumn("SELECT domain FROM company_domains WHERE company_id = ?", [$c['id']]);
|
||||||
$stmt->execute([$c['id']]);
|
|
||||||
$c['domains'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
$c['aktiivinen'] = (bool)$c['aktiivinen'];
|
$c['aktiivinen'] = (bool)$c['aktiivinen'];
|
||||||
}
|
}
|
||||||
return $companies;
|
return $companies;
|
||||||
@@ -290,17 +363,16 @@ function dbLoadCompanies(): array {
|
|||||||
|
|
||||||
function dbSaveCompany(array $company): void {
|
function dbSaveCompany(array $company): void {
|
||||||
$db = getDb();
|
$db = getDb();
|
||||||
$db->beginTransaction();
|
$db->begin_transaction();
|
||||||
try {
|
try {
|
||||||
$stmt = $db->prepare("
|
_dbExecute("
|
||||||
INSERT INTO companies (id, nimi, luotu, aktiivinen, primary_color, subtitle, logo_file, api_key, cors_origins)
|
INSERT INTO companies (id, nimi, luotu, aktiivinen, primary_color, subtitle, logo_file, api_key, cors_origins)
|
||||||
VALUES (:id, :nimi, :luotu, :aktiivinen, :primary_color, :subtitle, :logo_file, :api_key, :cors_origins)
|
VALUES (:id, :nimi, :luotu, :aktiivinen, :primary_color, :subtitle, :logo_file, :api_key, :cors_origins)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
nimi = VALUES(nimi), aktiivinen = VALUES(aktiivinen),
|
nimi = VALUES(nimi), aktiivinen = VALUES(aktiivinen),
|
||||||
primary_color = VALUES(primary_color), subtitle = VALUES(subtitle),
|
primary_color = VALUES(primary_color), subtitle = VALUES(subtitle),
|
||||||
logo_file = VALUES(logo_file), api_key = VALUES(api_key), cors_origins = VALUES(cors_origins)
|
logo_file = VALUES(logo_file), api_key = VALUES(api_key), cors_origins = VALUES(cors_origins)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $company['id'],
|
'id' => $company['id'],
|
||||||
'nimi' => $company['nimi'],
|
'nimi' => $company['nimi'],
|
||||||
'luotu' => $company['luotu'] ?? date('Y-m-d H:i:s'),
|
'luotu' => $company['luotu'] ?? date('Y-m-d H:i:s'),
|
||||||
@@ -313,38 +385,35 @@ function dbSaveCompany(array $company): void {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Päivitä domainit
|
// Päivitä domainit
|
||||||
$db->prepare("DELETE FROM company_domains WHERE company_id = ?")->execute([$company['id']]);
|
_dbExecute("DELETE FROM company_domains WHERE company_id = ?", [$company['id']]);
|
||||||
if (!empty($company['domains'])) {
|
if (!empty($company['domains'])) {
|
||||||
$ins = $db->prepare("INSERT INTO company_domains (company_id, domain) VALUES (?, ?)");
|
|
||||||
foreach ($company['domains'] as $domain) {
|
foreach ($company['domains'] as $domain) {
|
||||||
$domain = trim($domain);
|
$domain = trim($domain);
|
||||||
if ($domain) $ins->execute([$company['id'], $domain]);
|
if ($domain) {
|
||||||
|
_dbExecute("INSERT INTO company_domains (company_id, domain) VALUES (?, ?)", [$company['id'], $domain]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$db->commit();
|
$db->commit();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$db->rollBack();
|
$db->rollback();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteCompany(string $companyId): void {
|
function dbDeleteCompany(string $companyId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM companies WHERE id = ?", [$companyId]);
|
||||||
$db->prepare("DELETE FROM companies WHERE id = ?")->execute([$companyId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbGetBranding(string $host): array {
|
function dbGetBranding(string $host): array {
|
||||||
$db = getDb();
|
|
||||||
$host = strtolower(trim($host));
|
$host = strtolower(trim($host));
|
||||||
|
|
||||||
$stmt = $db->prepare("
|
$company = _dbFetchOne("
|
||||||
SELECT c.* FROM companies c
|
SELECT c.* FROM companies c
|
||||||
JOIN company_domains cd ON c.id = cd.company_id
|
JOIN company_domains cd ON c.id = cd.company_id
|
||||||
WHERE LOWER(cd.domain) = ?
|
WHERE LOWER(cd.domain) = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
");
|
", [$host]);
|
||||||
$stmt->execute([$host]);
|
|
||||||
$company = $stmt->fetch();
|
|
||||||
|
|
||||||
if ($company) {
|
if ($company) {
|
||||||
$logoUrl = !empty($company['logo_file'])
|
$logoUrl = !empty($company['logo_file'])
|
||||||
@@ -371,41 +440,29 @@ function dbGetBranding(string $host): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbGetCompanyByDomain(string $host): ?array {
|
function dbGetCompanyByDomain(string $host): ?array {
|
||||||
$db = getDb();
|
return _dbFetchOne("
|
||||||
$stmt = $db->prepare("
|
|
||||||
SELECT c.* FROM companies c
|
SELECT c.* FROM companies c
|
||||||
JOIN company_domains cd ON c.id = cd.company_id
|
JOIN company_domains cd ON c.id = cd.company_id
|
||||||
WHERE LOWER(cd.domain) = ?
|
WHERE LOWER(cd.domain) = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
");
|
", [strtolower(trim($host))]);
|
||||||
$stmt->execute([strtolower(trim($host))]);
|
|
||||||
return $stmt->fetch() ?: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbGetCompanyByApiKey(string $apiKey): ?array {
|
function dbGetCompanyByApiKey(string $apiKey): ?array {
|
||||||
$db = getDb();
|
return _dbFetchOne("SELECT * FROM companies WHERE api_key = ? AND api_key != '' LIMIT 1", [$apiKey]);
|
||||||
$stmt = $db->prepare("SELECT * FROM companies WHERE api_key = ? AND api_key != '' LIMIT 1");
|
|
||||||
$stmt->execute([$apiKey]);
|
|
||||||
return $stmt->fetch() ?: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== KÄYTTÄJÄT ====================
|
// ==================== KÄYTTÄJÄT ====================
|
||||||
|
|
||||||
function dbLoadUsers(): array {
|
function dbLoadUsers(): array {
|
||||||
$db = getDb();
|
$users = _dbFetchAll("SELECT * FROM users ORDER BY luotu");
|
||||||
$users = $db->query("SELECT * FROM users ORDER BY luotu")->fetchAll();
|
|
||||||
|
|
||||||
foreach ($users as &$u) {
|
foreach ($users as &$u) {
|
||||||
// Yritykset
|
$u['companies'] = _dbFetchColumn("SELECT company_id FROM user_companies WHERE user_id = ?", [$u['id']]);
|
||||||
$stmt = $db->prepare("SELECT company_id FROM user_companies WHERE user_id = ?");
|
|
||||||
$stmt->execute([$u['id']]);
|
|
||||||
$u['companies'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
|
|
||||||
// Allekirjoitukset
|
$sigRows = _dbFetchAll("SELECT mailbox_id, signature FROM user_signatures WHERE user_id = ?", [$u['id']]);
|
||||||
$stmt = $db->prepare("SELECT mailbox_id, signature FROM user_signatures WHERE user_id = ?");
|
|
||||||
$stmt->execute([$u['id']]);
|
|
||||||
$sigs = [];
|
$sigs = [];
|
||||||
foreach ($stmt->fetchAll() as $row) {
|
foreach ($sigRows as $row) {
|
||||||
$sigs[$row['mailbox_id']] = $row['signature'];
|
$sigs[$row['mailbox_id']] = $row['signature'];
|
||||||
}
|
}
|
||||||
$u['signatures'] = $sigs;
|
$u['signatures'] = $sigs;
|
||||||
@@ -414,20 +471,14 @@ function dbLoadUsers(): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbGetUser(string $id): ?array {
|
function dbGetUser(string $id): ?array {
|
||||||
$db = getDb();
|
$u = _dbFetchOne("SELECT * FROM users WHERE id = ?", [$id]);
|
||||||
$stmt = $db->prepare("SELECT * FROM users WHERE id = ?");
|
|
||||||
$stmt->execute([$id]);
|
|
||||||
$u = $stmt->fetch();
|
|
||||||
if (!$u) return null;
|
if (!$u) return null;
|
||||||
|
|
||||||
$stmt = $db->prepare("SELECT company_id FROM user_companies WHERE user_id = ?");
|
$u['companies'] = _dbFetchColumn("SELECT company_id FROM user_companies WHERE user_id = ?", [$id]);
|
||||||
$stmt->execute([$id]);
|
|
||||||
$u['companies'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
|
|
||||||
$stmt = $db->prepare("SELECT mailbox_id, signature FROM user_signatures WHERE user_id = ?");
|
$sigRows = _dbFetchAll("SELECT mailbox_id, signature FROM user_signatures WHERE user_id = ?", [$id]);
|
||||||
$stmt->execute([$id]);
|
|
||||||
$sigs = [];
|
$sigs = [];
|
||||||
foreach ($stmt->fetchAll() as $row) {
|
foreach ($sigRows as $row) {
|
||||||
$sigs[$row['mailbox_id']] = $row['signature'];
|
$sigs[$row['mailbox_id']] = $row['signature'];
|
||||||
}
|
}
|
||||||
$u['signatures'] = $sigs;
|
$u['signatures'] = $sigs;
|
||||||
@@ -436,20 +487,14 @@ function dbGetUser(string $id): ?array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbGetUserByUsername(string $username): ?array {
|
function dbGetUserByUsername(string $username): ?array {
|
||||||
$db = getDb();
|
$u = _dbFetchOne("SELECT * FROM users WHERE username = ?", [$username]);
|
||||||
$stmt = $db->prepare("SELECT * FROM users WHERE username = ?");
|
|
||||||
$stmt->execute([$username]);
|
|
||||||
$u = $stmt->fetch();
|
|
||||||
if (!$u) return null;
|
if (!$u) return null;
|
||||||
|
|
||||||
$stmt = $db->prepare("SELECT company_id FROM user_companies WHERE user_id = ?");
|
$u['companies'] = _dbFetchColumn("SELECT company_id FROM user_companies WHERE user_id = ?", [$u['id']]);
|
||||||
$stmt->execute([$u['id']]);
|
|
||||||
$u['companies'] = $stmt->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
|
|
||||||
$stmt = $db->prepare("SELECT mailbox_id, signature FROM user_signatures WHERE user_id = ?");
|
$sigRows = _dbFetchAll("SELECT mailbox_id, signature FROM user_signatures WHERE user_id = ?", [$u['id']]);
|
||||||
$stmt->execute([$u['id']]);
|
|
||||||
$sigs = [];
|
$sigs = [];
|
||||||
foreach ($stmt->fetchAll() as $row) {
|
foreach ($sigRows as $row) {
|
||||||
$sigs[$row['mailbox_id']] = $row['signature'];
|
$sigs[$row['mailbox_id']] = $row['signature'];
|
||||||
}
|
}
|
||||||
$u['signatures'] = $sigs;
|
$u['signatures'] = $sigs;
|
||||||
@@ -459,16 +504,15 @@ function dbGetUserByUsername(string $username): ?array {
|
|||||||
|
|
||||||
function dbSaveUser(array $user): void {
|
function dbSaveUser(array $user): void {
|
||||||
$db = getDb();
|
$db = getDb();
|
||||||
$db->beginTransaction();
|
$db->begin_transaction();
|
||||||
try {
|
try {
|
||||||
$stmt = $db->prepare("
|
_dbExecute("
|
||||||
INSERT INTO users (id, username, password_hash, nimi, role, email, luotu)
|
INSERT INTO users (id, username, password_hash, nimi, role, email, luotu)
|
||||||
VALUES (:id, :username, :password_hash, :nimi, :role, :email, :luotu)
|
VALUES (:id, :username, :password_hash, :nimi, :role, :email, :luotu)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
username = VALUES(username), password_hash = VALUES(password_hash),
|
username = VALUES(username), password_hash = VALUES(password_hash),
|
||||||
nimi = VALUES(nimi), role = VALUES(role), email = VALUES(email)
|
nimi = VALUES(nimi), role = VALUES(role), email = VALUES(email)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $user['id'],
|
'id' => $user['id'],
|
||||||
'username' => $user['username'],
|
'username' => $user['username'],
|
||||||
'password_hash' => $user['password_hash'],
|
'password_hash' => $user['password_hash'],
|
||||||
@@ -479,40 +523,36 @@ function dbSaveUser(array $user): void {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Yritykset
|
// Yritykset
|
||||||
$db->prepare("DELETE FROM user_companies WHERE user_id = ?")->execute([$user['id']]);
|
_dbExecute("DELETE FROM user_companies WHERE user_id = ?", [$user['id']]);
|
||||||
if (!empty($user['companies'])) {
|
if (!empty($user['companies'])) {
|
||||||
$ins = $db->prepare("INSERT IGNORE INTO user_companies (user_id, company_id) VALUES (?, ?)");
|
|
||||||
foreach ($user['companies'] as $cid) {
|
foreach ($user['companies'] as $cid) {
|
||||||
$ins->execute([$user['id'], $cid]);
|
_dbExecute("INSERT IGNORE INTO user_companies (user_id, company_id) VALUES (?, ?)", [$user['id'], $cid]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allekirjoitukset
|
// Allekirjoitukset
|
||||||
$db->prepare("DELETE FROM user_signatures WHERE user_id = ?")->execute([$user['id']]);
|
_dbExecute("DELETE FROM user_signatures WHERE user_id = ?", [$user['id']]);
|
||||||
if (!empty($user['signatures'])) {
|
if (!empty($user['signatures'])) {
|
||||||
$ins = $db->prepare("INSERT INTO user_signatures (user_id, mailbox_id, signature) VALUES (?, ?, ?)");
|
|
||||||
foreach ($user['signatures'] as $mbId => $sig) {
|
foreach ($user['signatures'] as $mbId => $sig) {
|
||||||
$ins->execute([$user['id'], $mbId, $sig]);
|
_dbExecute("INSERT INTO user_signatures (user_id, mailbox_id, signature) VALUES (?, ?, ?)", [$user['id'], $mbId, $sig]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$db->commit();
|
$db->commit();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$db->rollBack();
|
$db->rollback();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteUser(string $userId): void {
|
function dbDeleteUser(string $userId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM users WHERE id = ?", [$userId]);
|
||||||
$db->prepare("DELETE FROM users WHERE id = ?")->execute([$userId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== ASETUKSET (global) ====================
|
// ==================== ASETUKSET (global) ====================
|
||||||
|
|
||||||
function dbLoadConfig(): array {
|
function dbLoadConfig(): array {
|
||||||
$db = getDb();
|
$rows = _dbFetchAll("SELECT config_key, config_value FROM config");
|
||||||
$rows = $db->query("SELECT config_key, config_value FROM config")->fetchAll();
|
|
||||||
$config = [];
|
$config = [];
|
||||||
foreach ($rows as $row) {
|
foreach ($rows as $row) {
|
||||||
$decoded = json_decode($row['config_value'], true);
|
$decoded = json_decode($row['config_value'], true);
|
||||||
@@ -522,69 +562,52 @@ function dbLoadConfig(): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbSaveConfig(array $config): void {
|
function dbSaveConfig(array $config): void {
|
||||||
$db = getDb();
|
|
||||||
$stmt = $db->prepare("
|
|
||||||
INSERT INTO config (config_key, config_value) VALUES (?, ?)
|
|
||||||
ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)
|
|
||||||
");
|
|
||||||
foreach ($config as $key => $value) {
|
foreach ($config as $key => $value) {
|
||||||
$stmt->execute([$key, is_array($value) ? json_encode($value) : $value]);
|
_dbExecute(
|
||||||
|
"INSERT INTO config (config_key, config_value) VALUES (?, ?) ON DUPLICATE KEY UPDATE config_value = VALUES(config_value)",
|
||||||
|
[$key, is_array($value) ? json_encode($value) : (string)$value]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== SALASANAN PALAUTUS ====================
|
// ==================== SALASANAN PALAUTUS ====================
|
||||||
|
|
||||||
function dbSaveToken(string $userId, string $token): void {
|
function dbSaveToken(string $userId, string $token): void {
|
||||||
$db = getDb();
|
_dbExecute("INSERT INTO reset_tokens (user_id, token, created_at) VALUES (?, ?, NOW())", [$userId, hash('sha256', $token)]);
|
||||||
$stmt = $db->prepare("INSERT INTO reset_tokens (user_id, token, created_at) VALUES (?, ?, NOW())");
|
|
||||||
$stmt->execute([$userId, hash('sha256', $token)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbValidateToken(string $token): ?string {
|
function dbValidateToken(string $token): ?string {
|
||||||
$db = getDb();
|
|
||||||
$hash = hash('sha256', $token);
|
$hash = hash('sha256', $token);
|
||||||
$stmt = $db->prepare("SELECT user_id FROM reset_tokens WHERE token = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)");
|
$row = _dbFetchOne("SELECT user_id FROM reset_tokens WHERE token = ? AND created_at > DATE_SUB(NOW(), INTERVAL 1 HOUR)", [$hash]);
|
||||||
$stmt->execute([$hash]);
|
|
||||||
$row = $stmt->fetch();
|
|
||||||
return $row ? $row['user_id'] : null;
|
return $row ? $row['user_id'] : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbRemoveToken(string $token): void {
|
function dbRemoveToken(string $token): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM reset_tokens WHERE token = ?", [hash('sha256', $token)]);
|
||||||
$db->prepare("DELETE FROM reset_tokens WHERE token = ?")->execute([hash('sha256', $token)]);
|
|
||||||
// Siivoa vanhentuneet
|
// Siivoa vanhentuneet
|
||||||
$db->exec("DELETE FROM reset_tokens WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 HOUR)");
|
getDb()->query("DELETE FROM reset_tokens WHERE created_at < DATE_SUB(NOW(), INTERVAL 1 HOUR)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== RATE LIMITING ====================
|
// ==================== RATE LIMITING ====================
|
||||||
|
|
||||||
function dbCheckRateLimit(string $ip): bool {
|
function dbCheckRateLimit(string $ip): bool {
|
||||||
$db = getDb();
|
$count = _dbFetchScalar("SELECT COUNT(*) FROM login_attempts WHERE ip = ? AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)", [$ip]);
|
||||||
$stmt = $db->prepare("SELECT COUNT(*) FROM login_attempts WHERE ip = ? AND attempted_at > DATE_SUB(NOW(), INTERVAL 15 MINUTE)");
|
return (int)$count < 10;
|
||||||
$stmt->execute([$ip]);
|
|
||||||
return $stmt->fetchColumn() < 10;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbRecordLoginAttempt(string $ip): void {
|
function dbRecordLoginAttempt(string $ip): void {
|
||||||
$db = getDb();
|
_dbExecute("INSERT INTO login_attempts (ip, attempted_at) VALUES (?, NOW())", [$ip]);
|
||||||
$db->prepare("INSERT INTO login_attempts (ip, attempted_at) VALUES (?, NOW())")->execute([$ip]);
|
|
||||||
// Siivoa vanhat (yli 1h)
|
// Siivoa vanhat (yli 1h)
|
||||||
$db->exec("DELETE FROM login_attempts WHERE attempted_at < DATE_SUB(NOW(), INTERVAL 1 HOUR)");
|
getDb()->query("DELETE FROM login_attempts WHERE attempted_at < DATE_SUB(NOW(), INTERVAL 1 HOUR)");
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== ASIAKKAAT ====================
|
// ==================== ASIAKKAAT ====================
|
||||||
|
|
||||||
function dbLoadCustomers(string $companyId): array {
|
function dbLoadCustomers(string $companyId): array {
|
||||||
$db = getDb();
|
$customers = _dbFetchAll("SELECT * FROM customers WHERE company_id = ? ORDER BY yritys", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM customers WHERE company_id = ? ORDER BY yritys");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$customers = $stmt->fetchAll();
|
|
||||||
|
|
||||||
// Liitä liittymät
|
|
||||||
$connStmt = $db->prepare("SELECT * FROM customer_connections WHERE customer_id = ?");
|
|
||||||
foreach ($customers as &$c) {
|
foreach ($customers as &$c) {
|
||||||
$connStmt->execute([$c['id']]);
|
$conns = _dbFetchAll("SELECT * FROM customer_connections WHERE customer_id = ?", [$c['id']]);
|
||||||
$conns = $connStmt->fetchAll();
|
|
||||||
$c['liittymat'] = array_map(function($conn) {
|
$c['liittymat'] = array_map(function($conn) {
|
||||||
return [
|
return [
|
||||||
'asennusosoite' => $conn['asennusosoite'] ?? '',
|
'asennusosoite' => $conn['asennusosoite'] ?? '',
|
||||||
@@ -596,7 +619,6 @@ function dbLoadCustomers(string $companyId): array {
|
|||||||
'alkupvm' => $conn['alkupvm'] ?? '',
|
'alkupvm' => $conn['alkupvm'] ?? '',
|
||||||
];
|
];
|
||||||
}, $conns);
|
}, $conns);
|
||||||
// Poista company_id vastauksesta (ei tarvita frontissa)
|
|
||||||
unset($c['company_id']);
|
unset($c['company_id']);
|
||||||
}
|
}
|
||||||
return $customers;
|
return $customers;
|
||||||
@@ -604,9 +626,9 @@ function dbLoadCustomers(string $companyId): array {
|
|||||||
|
|
||||||
function dbSaveCustomer(string $companyId, array $customer): void {
|
function dbSaveCustomer(string $companyId, array $customer): void {
|
||||||
$db = getDb();
|
$db = getDb();
|
||||||
$db->beginTransaction();
|
$db->begin_transaction();
|
||||||
try {
|
try {
|
||||||
$stmt = $db->prepare("
|
_dbExecute("
|
||||||
INSERT INTO customers (id, company_id, yritys, yhteyshenkilö, puhelin, sahkoposti,
|
INSERT INTO customers (id, company_id, yritys, yhteyshenkilö, puhelin, sahkoposti,
|
||||||
laskutusosoite, laskutuspostinumero, laskutuskaupunki, laskutussahkoposti,
|
laskutusosoite, laskutuspostinumero, laskutuskaupunki, laskutussahkoposti,
|
||||||
elaskuosoite, elaskuvalittaja, ytunnus, lisatiedot, luotu, muokattu, muokkaaja)
|
elaskuosoite, elaskuvalittaja, ytunnus, lisatiedot, luotu, muokattu, muokkaaja)
|
||||||
@@ -621,8 +643,7 @@ function dbSaveCustomer(string $companyId, array $customer): void {
|
|||||||
elaskuosoite = VALUES(elaskuosoite), elaskuvalittaja = VALUES(elaskuvalittaja),
|
elaskuosoite = VALUES(elaskuosoite), elaskuvalittaja = VALUES(elaskuvalittaja),
|
||||||
ytunnus = VALUES(ytunnus), lisatiedot = VALUES(lisatiedot),
|
ytunnus = VALUES(ytunnus), lisatiedot = VALUES(lisatiedot),
|
||||||
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $customer['id'],
|
'id' => $customer['id'],
|
||||||
'company_id' => $companyId,
|
'company_id' => $companyId,
|
||||||
'yritys' => $customer['yritys'] ?? '',
|
'yritys' => $customer['yritys'] ?? '',
|
||||||
@@ -643,14 +664,13 @@ function dbSaveCustomer(string $companyId, array $customer): void {
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Päivitä liittymät
|
// Päivitä liittymät
|
||||||
$db->prepare("DELETE FROM customer_connections WHERE customer_id = ?")->execute([$customer['id']]);
|
_dbExecute("DELETE FROM customer_connections WHERE customer_id = ?", [$customer['id']]);
|
||||||
if (!empty($customer['liittymat'])) {
|
if (!empty($customer['liittymat'])) {
|
||||||
$ins = $db->prepare("
|
foreach ($customer['liittymat'] as $l) {
|
||||||
|
_dbExecute("
|
||||||
INSERT INTO customer_connections (customer_id, asennusosoite, postinumero, kaupunki, liittymanopeus, hinta, sopimuskausi, alkupvm)
|
INSERT INTO customer_connections (customer_id, asennusosoite, postinumero, kaupunki, liittymanopeus, hinta, sopimuskausi, alkupvm)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
");
|
", [
|
||||||
foreach ($customer['liittymat'] as $l) {
|
|
||||||
$ins->execute([
|
|
||||||
$customer['id'],
|
$customer['id'],
|
||||||
$l['asennusosoite'] ?? '',
|
$l['asennusosoite'] ?? '',
|
||||||
$l['postinumero'] ?? '',
|
$l['postinumero'] ?? '',
|
||||||
@@ -664,23 +684,19 @@ function dbSaveCustomer(string $companyId, array $customer): void {
|
|||||||
}
|
}
|
||||||
$db->commit();
|
$db->commit();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$db->rollBack();
|
$db->rollback();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteCustomer(string $customerId): void {
|
function dbDeleteCustomer(string $customerId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM customers WHERE id = ?", [$customerId]);
|
||||||
$db->prepare("DELETE FROM customers WHERE id = ?")->execute([$customerId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== LIIDIT ====================
|
// ==================== LIIDIT ====================
|
||||||
|
|
||||||
function dbLoadLeads(string $companyId): array {
|
function dbLoadLeads(string $companyId): array {
|
||||||
$db = getDb();
|
$leads = _dbFetchAll("SELECT * FROM leads WHERE company_id = ? ORDER BY luotu DESC", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM leads WHERE company_id = ? ORDER BY luotu DESC");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$leads = $stmt->fetchAll();
|
|
||||||
foreach ($leads as &$l) {
|
foreach ($leads as &$l) {
|
||||||
unset($l['company_id']);
|
unset($l['company_id']);
|
||||||
}
|
}
|
||||||
@@ -688,8 +704,7 @@ function dbLoadLeads(string $companyId): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbSaveLead(string $companyId, array $lead): void {
|
function dbSaveLead(string $companyId, array $lead): void {
|
||||||
$db = getDb();
|
_dbExecute("
|
||||||
$stmt = $db->prepare("
|
|
||||||
INSERT INTO leads (id, company_id, yritys, yhteyshenkilo, puhelin, sahkoposti, osoite, kaupunki, tila, muistiinpanot, luotu, luoja, muokattu, muokkaaja)
|
INSERT INTO leads (id, company_id, yritys, yhteyshenkilo, puhelin, sahkoposti, osoite, kaupunki, tila, muistiinpanot, luotu, luoja, muokattu, muokkaaja)
|
||||||
VALUES (:id, :company_id, :yritys, :yhteyshenkilo, :puhelin, :sahkoposti, :osoite, :kaupunki, :tila, :muistiinpanot, :luotu, :luoja, :muokattu, :muokkaaja)
|
VALUES (:id, :company_id, :yritys, :yhteyshenkilo, :puhelin, :sahkoposti, :osoite, :kaupunki, :tila, :muistiinpanot, :luotu, :luoja, :muokattu, :muokkaaja)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
@@ -698,8 +713,7 @@ function dbSaveLead(string $companyId, array $lead): void {
|
|||||||
osoite = VALUES(osoite), kaupunki = VALUES(kaupunki),
|
osoite = VALUES(osoite), kaupunki = VALUES(kaupunki),
|
||||||
tila = VALUES(tila), muistiinpanot = VALUES(muistiinpanot),
|
tila = VALUES(tila), muistiinpanot = VALUES(muistiinpanot),
|
||||||
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
muokattu = VALUES(muokattu), muokkaaja = VALUES(muokkaaja)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $lead['id'],
|
'id' => $lead['id'],
|
||||||
'company_id' => $companyId,
|
'company_id' => $companyId,
|
||||||
'yritys' => $lead['yritys'] ?? '',
|
'yritys' => $lead['yritys'] ?? '',
|
||||||
@@ -718,24 +732,17 @@ function dbSaveLead(string $companyId, array $lead): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteLead(string $leadId): void {
|
function dbDeleteLead(string $leadId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM leads WHERE id = ?", [$leadId]);
|
||||||
$db->prepare("DELETE FROM leads WHERE id = ?")->execute([$leadId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== TIKETIT ====================
|
// ==================== TIKETIT ====================
|
||||||
|
|
||||||
function dbLoadTickets(string $companyId): array {
|
function dbLoadTickets(string $companyId): array {
|
||||||
$db = getDb();
|
$tickets = _dbFetchAll("SELECT * FROM tickets WHERE company_id = ? ORDER BY updated DESC", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM tickets WHERE company_id = ? ORDER BY updated DESC");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$tickets = $stmt->fetchAll();
|
|
||||||
|
|
||||||
$msgStmt = $db->prepare("SELECT * FROM ticket_messages WHERE ticket_id = ? ORDER BY timestamp");
|
|
||||||
$tagStmt = $db->prepare("SELECT tag FROM ticket_tags WHERE ticket_id = ?");
|
|
||||||
|
|
||||||
foreach ($tickets as &$t) {
|
foreach ($tickets as &$t) {
|
||||||
// Viestit
|
// Viestit
|
||||||
$msgStmt->execute([$t['id']]);
|
$msgs = _dbFetchAll("SELECT * FROM ticket_messages WHERE ticket_id = ? ORDER BY timestamp", [$t['id']]);
|
||||||
$t['messages'] = array_map(function($m) {
|
$t['messages'] = array_map(function($m) {
|
||||||
return [
|
return [
|
||||||
'id' => $m['id'],
|
'id' => $m['id'],
|
||||||
@@ -746,11 +753,10 @@ function dbLoadTickets(string $companyId): array {
|
|||||||
'timestamp' => $m['timestamp'],
|
'timestamp' => $m['timestamp'],
|
||||||
'message_id' => $m['message_id'] ?? '',
|
'message_id' => $m['message_id'] ?? '',
|
||||||
];
|
];
|
||||||
}, $msgStmt->fetchAll());
|
}, $msgs);
|
||||||
|
|
||||||
// Tagit
|
// Tagit
|
||||||
$tagStmt->execute([$t['id']]);
|
$t['tags'] = _dbFetchColumn("SELECT tag FROM ticket_tags WHERE ticket_id = ?", [$t['id']]);
|
||||||
$t['tags'] = $tagStmt->fetchAll(PDO::FETCH_COLUMN);
|
|
||||||
|
|
||||||
unset($t['company_id']);
|
unset($t['company_id']);
|
||||||
}
|
}
|
||||||
@@ -759,9 +765,9 @@ function dbLoadTickets(string $companyId): array {
|
|||||||
|
|
||||||
function dbSaveTicket(string $companyId, array $ticket): void {
|
function dbSaveTicket(string $companyId, array $ticket): void {
|
||||||
$db = getDb();
|
$db = getDb();
|
||||||
$db->beginTransaction();
|
$db->begin_transaction();
|
||||||
try {
|
try {
|
||||||
$stmt = $db->prepare("
|
_dbExecute("
|
||||||
INSERT INTO tickets (id, company_id, subject, from_email, from_name, status, type,
|
INSERT INTO tickets (id, company_id, subject, from_email, from_name, status, type,
|
||||||
assigned_to, customer_id, customer_name, message_id, mailbox_id, auto_close_at, created, updated)
|
assigned_to, customer_id, customer_name, message_id, mailbox_id, auto_close_at, created, updated)
|
||||||
VALUES (:id, :company_id, :subject, :from_email, :from_name, :status, :type,
|
VALUES (:id, :company_id, :subject, :from_email, :from_name, :status, :type,
|
||||||
@@ -772,8 +778,7 @@ function dbSaveTicket(string $companyId, array $ticket): void {
|
|||||||
customer_id = VALUES(customer_id), customer_name = VALUES(customer_name),
|
customer_id = VALUES(customer_id), customer_name = VALUES(customer_name),
|
||||||
message_id = VALUES(message_id), mailbox_id = VALUES(mailbox_id),
|
message_id = VALUES(message_id), mailbox_id = VALUES(mailbox_id),
|
||||||
auto_close_at = VALUES(auto_close_at), updated = VALUES(updated)
|
auto_close_at = VALUES(auto_close_at), updated = VALUES(updated)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $ticket['id'],
|
'id' => $ticket['id'],
|
||||||
'company_id' => $companyId,
|
'company_id' => $companyId,
|
||||||
'subject' => $ticket['subject'] ?? '',
|
'subject' => $ticket['subject'] ?? '',
|
||||||
@@ -793,12 +798,11 @@ function dbSaveTicket(string $companyId, array $ticket): void {
|
|||||||
|
|
||||||
// Viestit — lisää vain uudet (ei poista vanhoja)
|
// Viestit — lisää vain uudet (ei poista vanhoja)
|
||||||
if (!empty($ticket['messages'])) {
|
if (!empty($ticket['messages'])) {
|
||||||
$ins = $db->prepare("
|
foreach ($ticket['messages'] as $m) {
|
||||||
|
_dbExecute("
|
||||||
INSERT IGNORE INTO ticket_messages (id, ticket_id, type, from_email, from_name, body, timestamp, message_id)
|
INSERT IGNORE INTO ticket_messages (id, ticket_id, type, from_email, from_name, body, timestamp, message_id)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||||
");
|
", [
|
||||||
foreach ($ticket['messages'] as $m) {
|
|
||||||
$ins->execute([
|
|
||||||
$m['id'],
|
$m['id'],
|
||||||
$ticket['id'],
|
$ticket['id'],
|
||||||
$m['type'],
|
$m['type'],
|
||||||
@@ -812,52 +816,44 @@ function dbSaveTicket(string $companyId, array $ticket): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tagit — korvaa kaikki
|
// Tagit — korvaa kaikki
|
||||||
$db->prepare("DELETE FROM ticket_tags WHERE ticket_id = ?")->execute([$ticket['id']]);
|
_dbExecute("DELETE FROM ticket_tags WHERE ticket_id = ?", [$ticket['id']]);
|
||||||
if (!empty($ticket['tags'])) {
|
if (!empty($ticket['tags'])) {
|
||||||
$ins = $db->prepare("INSERT INTO ticket_tags (ticket_id, tag) VALUES (?, ?)");
|
|
||||||
foreach ($ticket['tags'] as $tag) {
|
foreach ($ticket['tags'] as $tag) {
|
||||||
if ($tag) $ins->execute([$ticket['id'], $tag]);
|
if ($tag) {
|
||||||
|
_dbExecute("INSERT INTO ticket_tags (ticket_id, tag) VALUES (?, ?)", [$ticket['id'], $tag]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$db->commit();
|
$db->commit();
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
$db->rollBack();
|
$db->rollback();
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteTicket(string $ticketId): void {
|
function dbDeleteTicket(string $ticketId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM tickets WHERE id = ?", [$ticketId]);
|
||||||
$db->prepare("DELETE FROM tickets WHERE id = ?")->execute([$ticketId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbFindTicketByMessageId(string $companyId, string $messageId): ?array {
|
function dbFindTicketByMessageId(string $companyId, string $messageId): ?array {
|
||||||
$db = getDb();
|
|
||||||
// Ensin tikettitasolla
|
// Ensin tikettitasolla
|
||||||
$stmt = $db->prepare("SELECT * FROM tickets WHERE company_id = ? AND message_id = ? LIMIT 1");
|
$t = _dbFetchOne("SELECT * FROM tickets WHERE company_id = ? AND message_id = ? LIMIT 1", [$companyId, $messageId]);
|
||||||
$stmt->execute([$companyId, $messageId]);
|
|
||||||
$t = $stmt->fetch();
|
|
||||||
if ($t) return $t;
|
if ($t) return $t;
|
||||||
|
|
||||||
// Sitten viestien message_id:stä
|
// Sitten viestien message_id:stä
|
||||||
$stmt = $db->prepare("
|
return _dbFetchOne("
|
||||||
SELECT t.* FROM tickets t
|
SELECT t.* FROM tickets t
|
||||||
JOIN ticket_messages tm ON t.id = tm.ticket_id
|
JOIN ticket_messages tm ON t.id = tm.ticket_id
|
||||||
WHERE t.company_id = ? AND tm.message_id = ?
|
WHERE t.company_id = ? AND tm.message_id = ?
|
||||||
LIMIT 1
|
LIMIT 1
|
||||||
");
|
", [$companyId, $messageId]);
|
||||||
$stmt->execute([$companyId, $messageId]);
|
|
||||||
return $stmt->fetch() ?: null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== ARKISTO ====================
|
// ==================== ARKISTO ====================
|
||||||
|
|
||||||
function dbLoadArchive(string $companyId): array {
|
function dbLoadArchive(string $companyId): array {
|
||||||
$db = getDb();
|
$rows = _dbFetchAll("SELECT * FROM archives WHERE company_id = ? ORDER BY archived_at DESC", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM archives WHERE company_id = ? ORDER BY archived_at DESC");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$rows = $stmt->fetchAll();
|
|
||||||
return array_map(function($row) {
|
return array_map(function($row) {
|
||||||
$data = json_decode($row['data'], true) ?? [];
|
$data = json_decode($row['data'], true) ?? [];
|
||||||
$data['id'] = $row['id'];
|
$data['id'] = $row['id'];
|
||||||
@@ -867,61 +863,46 @@ function dbLoadArchive(string $companyId): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbArchiveCustomer(string $companyId, array $customerData): void {
|
function dbArchiveCustomer(string $companyId, array $customerData): void {
|
||||||
$db = getDb();
|
_dbExecute("INSERT INTO archives (id, company_id, data, archived_at) VALUES (?, ?, ?, NOW())",
|
||||||
$stmt = $db->prepare("INSERT INTO archives (id, company_id, data, archived_at) VALUES (?, ?, ?, NOW())");
|
[$customerData['id'], $companyId, json_encode($customerData, JSON_UNESCAPED_UNICODE)]);
|
||||||
$stmt->execute([$customerData['id'], $companyId, json_encode($customerData, JSON_UNESCAPED_UNICODE)]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbRestoreArchive(string $archiveId): ?array {
|
function dbRestoreArchive(string $archiveId): ?array {
|
||||||
$db = getDb();
|
$row = _dbFetchOne("SELECT * FROM archives WHERE id = ?", [$archiveId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM archives WHERE id = ?");
|
|
||||||
$stmt->execute([$archiveId]);
|
|
||||||
$row = $stmt->fetch();
|
|
||||||
if (!$row) return null;
|
if (!$row) return null;
|
||||||
$db->prepare("DELETE FROM archives WHERE id = ?")->execute([$archiveId]);
|
_dbExecute("DELETE FROM archives WHERE id = ?", [$archiveId]);
|
||||||
return json_decode($row['data'], true);
|
return json_decode($row['data'], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteArchive(string $archiveId): void {
|
function dbDeleteArchive(string $archiveId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM archives WHERE id = ?", [$archiveId]);
|
||||||
$db->prepare("DELETE FROM archives WHERE id = ?")->execute([$archiveId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== CHANGELOG ====================
|
// ==================== CHANGELOG ====================
|
||||||
|
|
||||||
function dbAddLog(string $companyId, string $user, string $action, string $customerId = '', string $customerName = '', string $details = ''): void {
|
function dbAddLog(string $companyId, string $user, string $action, string $customerId = '', string $customerName = '', string $details = ''): void {
|
||||||
if (empty($companyId)) return;
|
if (empty($companyId)) return;
|
||||||
$db = getDb();
|
|
||||||
|
|
||||||
$id = bin2hex(random_bytes(8));
|
$id = bin2hex(random_bytes(8));
|
||||||
$stmt = $db->prepare("
|
_dbExecute("
|
||||||
INSERT INTO changelog (id, company_id, timestamp, user, action, customer_id, customer_name, details)
|
INSERT INTO changelog (id, company_id, timestamp, user, action, customer_id, customer_name, details)
|
||||||
VALUES (?, ?, NOW(), ?, ?, ?, ?, ?)
|
VALUES (?, ?, NOW(), ?, ?, ?, ?, ?)
|
||||||
");
|
", [$id, $companyId, $user, $action, $customerId, $customerName, $details]);
|
||||||
$stmt->execute([$id, $companyId, $user, $action, $customerId, $customerName, $details]);
|
|
||||||
|
|
||||||
// Pidä max 500 per yritys
|
// Pidä max 500 per yritys
|
||||||
$db->prepare("
|
getDb()->query("DELETE FROM changelog WHERE company_id = '" . getDb()->real_escape_string($companyId) . "' AND id NOT IN (
|
||||||
DELETE FROM changelog WHERE company_id = ? AND id NOT IN (
|
SELECT id FROM (SELECT id FROM changelog WHERE company_id = '" . getDb()->real_escape_string($companyId) . "' ORDER BY timestamp DESC LIMIT 500) tmp
|
||||||
SELECT id FROM (SELECT id FROM changelog WHERE company_id = ? ORDER BY timestamp DESC LIMIT 500) tmp
|
)");
|
||||||
)
|
|
||||||
")->execute([$companyId, $companyId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbLoadChangelog(string $companyId, int $limit = 100): array {
|
function dbLoadChangelog(string $companyId, int $limit = 100): array {
|
||||||
$db = getDb();
|
return _dbFetchAll("SELECT * FROM changelog WHERE company_id = ? ORDER BY timestamp DESC LIMIT ?", [$companyId, $limit]);
|
||||||
$stmt = $db->prepare("SELECT * FROM changelog WHERE company_id = ? ORDER BY timestamp DESC LIMIT ?");
|
|
||||||
$stmt->execute([$companyId, $limit]);
|
|
||||||
return $stmt->fetchAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== POSTILAATIKOT ====================
|
// ==================== POSTILAATIKOT ====================
|
||||||
|
|
||||||
function dbLoadMailboxes(string $companyId): array {
|
function dbLoadMailboxes(string $companyId): array {
|
||||||
$db = getDb();
|
$boxes = _dbFetchAll("SELECT * FROM mailboxes WHERE company_id = ?", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM mailboxes WHERE company_id = ?");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$boxes = $stmt->fetchAll();
|
|
||||||
foreach ($boxes as &$b) {
|
foreach ($boxes as &$b) {
|
||||||
$b['aktiivinen'] = (bool)$b['aktiivinen'];
|
$b['aktiivinen'] = (bool)$b['aktiivinen'];
|
||||||
$b['imap_port'] = (int)$b['imap_port'];
|
$b['imap_port'] = (int)$b['imap_port'];
|
||||||
@@ -931,8 +912,7 @@ function dbLoadMailboxes(string $companyId): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbSaveMailbox(string $companyId, array $mailbox): void {
|
function dbSaveMailbox(string $companyId, array $mailbox): void {
|
||||||
$db = getDb();
|
_dbExecute("
|
||||||
$stmt = $db->prepare("
|
|
||||||
INSERT INTO mailboxes (id, company_id, nimi, imap_host, imap_port, imap_user, imap_encryption, imap_password, smtp_from_email, smtp_from_name, aktiivinen)
|
INSERT INTO mailboxes (id, company_id, nimi, imap_host, imap_port, imap_user, imap_encryption, imap_password, smtp_from_email, smtp_from_name, aktiivinen)
|
||||||
VALUES (:id, :company_id, :nimi, :imap_host, :imap_port, :imap_user, :imap_encryption, :imap_password, :smtp_from_email, :smtp_from_name, :aktiivinen)
|
VALUES (:id, :company_id, :nimi, :imap_host, :imap_port, :imap_user, :imap_encryption, :imap_password, :smtp_from_email, :smtp_from_name, :aktiivinen)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
@@ -940,8 +920,7 @@ function dbSaveMailbox(string $companyId, array $mailbox): void {
|
|||||||
imap_user = VALUES(imap_user), imap_encryption = VALUES(imap_encryption),
|
imap_user = VALUES(imap_user), imap_encryption = VALUES(imap_encryption),
|
||||||
imap_password = VALUES(imap_password), smtp_from_email = VALUES(smtp_from_email),
|
imap_password = VALUES(imap_password), smtp_from_email = VALUES(smtp_from_email),
|
||||||
smtp_from_name = VALUES(smtp_from_name), aktiivinen = VALUES(aktiivinen)
|
smtp_from_name = VALUES(smtp_from_name), aktiivinen = VALUES(aktiivinen)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $mailbox['id'],
|
'id' => $mailbox['id'],
|
||||||
'company_id' => $companyId,
|
'company_id' => $companyId,
|
||||||
'nimi' => $mailbox['nimi'] ?? '',
|
'nimi' => $mailbox['nimi'] ?? '',
|
||||||
@@ -957,29 +936,22 @@ function dbSaveMailbox(string $companyId, array $mailbox): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteMailbox(string $mailboxId): void {
|
function dbDeleteMailbox(string $mailboxId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM mailboxes WHERE id = ?", [$mailboxId]);
|
||||||
$db->prepare("DELETE FROM mailboxes WHERE id = ?")->execute([$mailboxId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbGetMailbox(string $mailboxId): ?array {
|
function dbGetMailbox(string $mailboxId): ?array {
|
||||||
$db = getDb();
|
$b = _dbFetchOne("SELECT * FROM mailboxes WHERE id = ?", [$mailboxId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM mailboxes WHERE id = ?");
|
|
||||||
$stmt->execute([$mailboxId]);
|
|
||||||
$b = $stmt->fetch();
|
|
||||||
if ($b) {
|
if ($b) {
|
||||||
$b['aktiivinen'] = (bool)$b['aktiivinen'];
|
$b['aktiivinen'] = (bool)$b['aktiivinen'];
|
||||||
$b['imap_port'] = (int)$b['imap_port'];
|
$b['imap_port'] = (int)$b['imap_port'];
|
||||||
}
|
}
|
||||||
return $b ?: null;
|
return $b;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== TIKETTISÄÄNNÖT ====================
|
// ==================== TIKETTISÄÄNNÖT ====================
|
||||||
|
|
||||||
function dbLoadTicketRules(string $companyId): array {
|
function dbLoadTicketRules(string $companyId): array {
|
||||||
$db = getDb();
|
$rules = _dbFetchAll("SELECT * FROM ticket_rules WHERE company_id = ? ORDER BY priority", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT * FROM ticket_rules WHERE company_id = ? ORDER BY priority");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$rules = $stmt->fetchAll();
|
|
||||||
foreach ($rules as &$r) {
|
foreach ($rules as &$r) {
|
||||||
$r['priority'] = (int)$r['priority'];
|
$r['priority'] = (int)$r['priority'];
|
||||||
$r['auto_close_days'] = (int)$r['auto_close_days'];
|
$r['auto_close_days'] = (int)$r['auto_close_days'];
|
||||||
@@ -989,16 +961,14 @@ function dbLoadTicketRules(string $companyId): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbSaveTicketRule(string $companyId, array $rule): void {
|
function dbSaveTicketRule(string $companyId, array $rule): void {
|
||||||
$db = getDb();
|
_dbExecute("
|
||||||
$stmt = $db->prepare("
|
|
||||||
INSERT INTO ticket_rules (id, company_id, name, from_contains, priority, tag, assign_to, status_set, type_set, auto_close_days)
|
INSERT INTO ticket_rules (id, company_id, name, from_contains, priority, tag, assign_to, status_set, type_set, auto_close_days)
|
||||||
VALUES (:id, :company_id, :name, :from_contains, :priority, :tag, :assign_to, :status_set, :type_set, :auto_close_days)
|
VALUES (:id, :company_id, :name, :from_contains, :priority, :tag, :assign_to, :status_set, :type_set, :auto_close_days)
|
||||||
ON DUPLICATE KEY UPDATE
|
ON DUPLICATE KEY UPDATE
|
||||||
name = VALUES(name), from_contains = VALUES(from_contains), priority = VALUES(priority),
|
name = VALUES(name), from_contains = VALUES(from_contains), priority = VALUES(priority),
|
||||||
tag = VALUES(tag), assign_to = VALUES(assign_to), status_set = VALUES(status_set),
|
tag = VALUES(tag), assign_to = VALUES(assign_to), status_set = VALUES(status_set),
|
||||||
type_set = VALUES(type_set), auto_close_days = VALUES(auto_close_days)
|
type_set = VALUES(type_set), auto_close_days = VALUES(auto_close_days)
|
||||||
");
|
", [
|
||||||
$stmt->execute([
|
|
||||||
'id' => $rule['id'],
|
'id' => $rule['id'],
|
||||||
'company_id' => $companyId,
|
'company_id' => $companyId,
|
||||||
'name' => $rule['name'] ?? '',
|
'name' => $rule['name'] ?? '',
|
||||||
@@ -1013,8 +983,7 @@ function dbSaveTicketRule(string $companyId, array $rule): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbDeleteTicketRule(string $ruleId): void {
|
function dbDeleteTicketRule(string $ruleId): void {
|
||||||
$db = getDb();
|
_dbExecute("DELETE FROM ticket_rules WHERE id = ?", [$ruleId]);
|
||||||
$db->prepare("DELETE FROM ticket_rules WHERE id = ?")->execute([$ruleId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== YRITYKSEN API-ASETUKSET ====================
|
// ==================== YRITYKSEN API-ASETUKSET ====================
|
||||||
@@ -1029,28 +998,20 @@ function dbGetCompanyConfig(string $companyId): array {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function dbGetCompanyApiKey(string $companyId): string {
|
function dbGetCompanyApiKey(string $companyId): string {
|
||||||
$db = getDb();
|
return _dbFetchScalar("SELECT api_key FROM companies WHERE id = ?", [$companyId]) ?: '';
|
||||||
$stmt = $db->prepare("SELECT api_key FROM companies WHERE id = ?");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
return $stmt->fetchColumn() ?: '';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbGetCompanyCorsOrigins(string $companyId): array {
|
function dbGetCompanyCorsOrigins(string $companyId): array {
|
||||||
$db = getDb();
|
$val = _dbFetchScalar("SELECT cors_origins FROM companies WHERE id = ?", [$companyId]);
|
||||||
$stmt = $db->prepare("SELECT cors_origins FROM companies WHERE id = ?");
|
|
||||||
$stmt->execute([$companyId]);
|
|
||||||
$val = $stmt->fetchColumn();
|
|
||||||
if (!$val) return [];
|
if (!$val) return [];
|
||||||
$decoded = json_decode($val, true);
|
$decoded = json_decode($val, true);
|
||||||
return is_array($decoded) ? $decoded : [];
|
return is_array($decoded) ? $decoded : [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbSetCompanyApiKey(string $companyId, string $apiKey): void {
|
function dbSetCompanyApiKey(string $companyId, string $apiKey): void {
|
||||||
$db = getDb();
|
_dbExecute("UPDATE companies SET api_key = ? WHERE id = ?", [$apiKey, $companyId]);
|
||||||
$db->prepare("UPDATE companies SET api_key = ? WHERE id = ?")->execute([$apiKey, $companyId]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function dbSetCompanyCorsOrigins(string $companyId, array $origins): void {
|
function dbSetCompanyCorsOrigins(string $companyId, array $origins): void {
|
||||||
$db = getDb();
|
_dbExecute("UPDATE companies SET cors_origins = ? WHERE id = ?", [json_encode($origins), $companyId]);
|
||||||
$db->prepare("UPDATE companies SET cors_origins = ? WHERE id = ?")->execute([json_encode($origins), $companyId]);
|
|
||||||
}
|
}
|
||||||
|
|||||||
10
phpcheck.php
10
phpcheck.php
@@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
echo "<h2>PHP Info</h2>";
|
|
||||||
echo "<p>PHP versio: " . PHP_VERSION . "</p>";
|
|
||||||
echo "<p>SAPI: " . php_sapi_name() . "</p>";
|
|
||||||
echo "<p>PDO loaded: " . (extension_loaded('pdo') ? 'KYLLÄ ✅' : 'EI ❌') . "</p>";
|
|
||||||
echo "<p>PDO MySQL: " . (extension_loaded('pdo_mysql') ? 'KYLLÄ ✅' : 'EI ❌') . "</p>";
|
|
||||||
echo "<p>MySQLi: " . (extension_loaded('mysqli') ? 'KYLLÄ ✅' : 'EI ❌') . "</p>";
|
|
||||||
echo "<p>php.ini sijainti: " . php_ini_loaded_file() . "</p>";
|
|
||||||
echo "<h3>Kaikki laajennukset:</h3>";
|
|
||||||
echo "<p>" . implode(', ', get_loaded_extensions()) . "</p>";
|
|
||||||
Reference in New Issue
Block a user