Files
Projectkiln/ProjectKiln/install/install_db.php

496 lines
21 KiB
PHP

<?php
declare(strict_types=1);
require_once __DIR__ . '/../db.php';
$pdo = db();
function quoteIdentifier(string $identifier): string {
if (!preg_match('/^[A-Za-z0-9_]+$/', $identifier)) {
throw new InvalidArgumentException('Invalid identifier: ' . $identifier);
}
return '`' . $identifier . '`';
}
function tableExists(PDO $pdo, string $table): bool {
$stmt = $pdo->prepare(
'SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ?'
);
$stmt->execute([$table]);
return (int) $stmt->fetchColumn() > 0;
}
function indexExists(PDO $pdo, string $table, string $index): bool {
$stmt = $pdo->prepare(
'SELECT COUNT(*) FROM information_schema.STATISTICS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = ? AND INDEX_NAME = ?'
);
$stmt->execute([$table, $index]);
return (int) $stmt->fetchColumn() > 0;
}
function foreignKeyExists(PDO $pdo, string $constraint): bool {
$stmt = $pdo->prepare(
"SELECT COUNT(*) FROM information_schema.TABLE_CONSTRAINTS
WHERE CONSTRAINT_SCHEMA = DATABASE()
AND CONSTRAINT_NAME = ?
AND CONSTRAINT_TYPE = 'FOREIGN KEY'"
);
$stmt->execute([$constraint]);
return (int) $stmt->fetchColumn() > 0;
}
function addIndexIfMissing(PDO $pdo, string $table, string $index, string $definition): void {
if (indexExists($pdo, $table, $index)) {
return;
}
$pdo->exec('ALTER TABLE ' . quoteIdentifier($table) . ' ADD ' . $definition);
}
function addForeignKeyIfMissing(PDO $pdo, string $constraint, string $definition): void {
if (foreignKeyExists($pdo, $constraint)) {
return;
}
$pdo->exec($definition);
}
function assetBlob(string $relativePath): ?string {
$path = __DIR__ . '/../../raw-resources/' . ltrim($relativePath, '/');
if (!is_file($path)) {
return null;
}
return file_get_contents($path) ?: null;
}
function upsert(PDO $pdo, string $sql, array $params): void {
$stmt = $pdo->prepare($sql);
$stmt->execute($params);
}
try {
$pdo->exec('SET FOREIGN_KEY_CHECKS = 0');
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `task_states` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`color` varchar(7) COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `task_priorities` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) COLLATE utf8mb4_0900_bin NOT NULL,
`logo` blob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `task_types` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(20) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
`logo` blob,
`default_state` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `users` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`email` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`passwd` varchar(255) COLLATE utf8mb4_0900_bin NOT NULL,
`picture` mediumblob,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `projects` (
`id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
`name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`owner` int NOT NULL,
`created_date` date NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `versions` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin,
`created_date` date NOT NULL,
`due_date` date DEFAULT NULL,
`released_date` date DEFAULT NULL,
`project` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `tasks` (
`id` varchar(26) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
`title` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
`description` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin,
`project` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
`created_date` date NOT NULL,
`last_changed` date NOT NULL,
`reporter` int NOT NULL,
`assignee` int DEFAULT NULL,
`fix_version` int DEFAULT NULL,
`type` int NOT NULL,
`priority` int NOT NULL,
`status` int DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `assigned_task_states` (
`id` int NOT NULL AUTO_INCREMENT,
`state` int NOT NULL,
`task_type` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `auth_tokens` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`token_hash` char(64) COLLATE utf8mb4_0900_bin NOT NULL,
`expires_at` datetime NOT NULL,
`revoked_at` datetime DEFAULT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_used_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `comments` (
`id` int NOT NULL AUTO_INCREMENT,
`response_to` int DEFAULT NULL,
`task_id` varchar(26) COLLATE utf8mb4_0900_bin NOT NULL,
`commenter` int NOT NULL,
`comment` text COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `custom_task_fields` (
`id` int NOT NULL AUTO_INCREMENT,
`task_type` int NOT NULL,
`name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`type` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`default_value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `custom_field_values` (
`id` int NOT NULL AUTO_INCREMENT,
`field_id` int NOT NULL,
`task_id` varchar(26) COLLATE utf8mb4_0900_bin NOT NULL,
`value` text CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `remember_tokens` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`selector` char(32) COLLATE utf8mb4_0900_bin NOT NULL,
`token_hash` char(64) COLLATE utf8mb4_0900_bin NOT NULL,
`expires_at` datetime NOT NULL,
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
`last_used_at` datetime DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `rights` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `settings` (
`id` int NOT NULL AUTO_INCREMENT,
`setting_name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`setting_value` varchar(256) COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `task_state_transitions` (
`id` int NOT NULL AUTO_INCREMENT,
`from_id` int NOT NULL,
`to_id` int NOT NULL,
`action_name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `user_access` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`project_id` varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `user_rights` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`right_id` int NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$pdo->exec(<<<'SQL'
CREATE TABLE IF NOT EXISTS `user_settings` (
`id` int NOT NULL AUTO_INCREMENT,
`user_id` int NOT NULL,
`setting_name` varchar(128) COLLATE utf8mb4_0900_bin NOT NULL,
`setting_value` varchar(256) COLLATE utf8mb4_0900_bin NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_bin
SQL);
$indexes = [
['assigned_task_states', 'state', 'KEY `state` (`state`)'],
['assigned_task_states', 'task_type', 'KEY `task_type` (`task_type`)'],
['auth_tokens', 'unique_token_hash', 'UNIQUE KEY `unique_token_hash` (`token_hash`)'],
['auth_tokens', 'user_id', 'KEY `user_id` (`user_id`)'],
['comments', 'response_to', 'KEY `response_to` (`response_to`)'],
['comments', 'task_id', 'KEY `task_id` (`task_id`)'],
['comments', 'commenter', 'KEY `commenter` (`commenter`)'],
['custom_field_values', 'field_id', 'KEY `field_id` (`field_id`)'],
['custom_field_values', 'task_id', 'KEY `task_id` (`task_id`)'],
['custom_task_fields', 'task_type', 'KEY `task_type` (`task_type`)'],
['projects', 'owner', 'KEY `owner` (`owner`)'],
['remember_tokens', 'unique_selector', 'UNIQUE KEY `unique_selector` (`selector`)'],
['remember_tokens', 'user_id', 'KEY `user_id` (`user_id`)'],
['tasks', 'project', 'KEY `project` (`project`)'],
['tasks', 'reporter', 'KEY `reporter` (`reporter`,`assignee`,`fix_version`,`type`,`priority`)'],
['tasks', 'type', 'KEY `type` (`type`)'],
['tasks', 'priority', 'KEY `priority` (`priority`)'],
['tasks', 'assignee', 'KEY `assignee` (`assignee`)'],
['tasks', 'fix_version', 'KEY `fix_version` (`fix_version`)'],
['tasks', 'status', 'KEY `status` (`status`)'],
['task_state_transitions', 'from_id', 'KEY `from_id` (`from_id`)'],
['task_state_transitions', 'to_id', 'KEY `to_id` (`to_id`)'],
['task_types', 'default_state', 'KEY `default_state` (`default_state`)'],
['users', 'unique_email', 'UNIQUE KEY `unique_email` (`email`)'],
['user_access', 'user_id', 'KEY `user_id` (`user_id`)'],
['user_access', 'project_id', 'KEY `project_id` (`project_id`)'],
['user_rights', 'user_id', 'KEY `user_id` (`user_id`)'],
['user_rights', 'right_id', 'KEY `right_id` (`right_id`)'],
['user_settings', 'user_id', 'KEY `user_id` (`user_id`)'],
['versions', 'project', 'KEY `project` (`project`)'],
];
foreach ($indexes as [$table, $index, $definition]) {
addIndexIfMissing($pdo, $table, $index, $definition);
}
upsert(
$pdo,
"INSERT INTO `settings` (`id`, `setting_name`, `setting_value`)
VALUES (1, 'version', '0.0.1')
ON DUPLICATE KEY UPDATE `setting_name` = VALUES(`setting_name`), `setting_value` = VALUES(`setting_value`)",
[]
);
$states = [
[1, 'Open', '#858e99'],
[2, 'In Progress', '#3384e1'],
[3, 'Resolved', '#1a7f21'],
[4, 'Reopened', '#8693a2'],
[5, 'Closed', '#3c810e'],
];
foreach ($states as $state) {
upsert(
$pdo,
"INSERT INTO `task_states` (`id`, `name`, `color`)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `color` = VALUES(`color`)",
$state
);
}
$priorities = [
[1, 'Critical', 'images_task_priority/1_critical.svg'],
[2, 'Heigh', 'images_task_priority/2_heigh.svg'],
[3, 'Medium', 'images_task_priority/3_medium.svg'],
[4, 'Low', 'images_task_priority/4_low.svg'],
[5, 'Trivial', 'images_task_priority/5_trivial.svg'],
];
foreach ($priorities as [$id, $name, $asset]) {
upsert(
$pdo,
"INSERT INTO `task_priorities` (`id`, `name`, `logo`)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `logo` = VALUES(`logo`)",
[$id, $name, assetBlob($asset)]
);
}
$types = [
[1, 'Unknown', 'images_task_types/unknown.svg', 1],
[2, 'Bug', 'images_task_types/bug.svg', 1],
[3, 'New Feature', 'images_task_types/new_feature.svg', 1],
[4, 'Improvement', 'images_task_types/improvement.svg', 1],
[5, 'Task', 'images_task_types/task.svg', 1],
];
foreach ($types as [$id, $name, $asset, $defaultState]) {
upsert(
$pdo,
"INSERT INTO `task_types` (`id`, `name`, `logo`, `default_state`)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`), `logo` = VALUES(`logo`), `default_state` = VALUES(`default_state`)",
[$id, $name, assetBlob($asset), $defaultState]
);
}
$transitions = [
[1, 1, 2, 'Start Work'],
[2, 2, 3, 'Resolve Issue'],
[3, 3, 4, 'Reopen Issue'],
[4, 4, 2, 'Start Work'],
[5, 1, 5, 'Close'],
[6, 2, 5, 'Close'],
[7, 2, 1, 'Stop Work'],
[8, 5, 4, 'Reopen Issue'],
];
foreach ($transitions as $transition) {
upsert(
$pdo,
"INSERT INTO `task_state_transitions` (`id`, `from_id`, `to_id`, `action_name`)
VALUES (?, ?, ?, ?)
ON DUPLICATE KEY UPDATE `from_id` = VALUES(`from_id`), `to_id` = VALUES(`to_id`), `action_name` = VALUES(`action_name`)",
$transition
);
}
$assignedStates = [
[1, 1, 5], [2, 2, 5], [3, 3, 5], [4, 5, 5], [5, 4, 5],
[6, 1, 1],
[7, 1, 2], [8, 2, 2], [9, 3, 2], [10, 4, 2], [11, 5, 2],
[12, 1, 3], [13, 2, 3], [14, 3, 3], [15, 4, 3], [16, 5, 3],
[17, 1, 4], [18, 2, 4], [19, 3, 4], [20, 4, 4], [21, 5, 4],
];
foreach ($assignedStates as $assignedState) {
upsert(
$pdo,
"INSERT INTO `assigned_task_states` (`id`, `state`, `task_type`)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE `state` = VALUES(`state`), `task_type` = VALUES(`task_type`)",
$assignedState
);
}
$rights = [
[1, 'Admin'],
[2, 'Create Tasks'],
[3, 'Edit Tasks'],
[4, 'Create Versions'],
[5, 'Edit Versions'],
[6, 'Create Projects'],
[7, 'Edit Projects'],
];
foreach ($rights as $right) {
upsert(
$pdo,
"INSERT INTO `rights` (`id`, `name`)
VALUES (?, ?)
ON DUPLICATE KEY UPDATE `name` = VALUES(`name`)",
$right
);
}
$pdo->exec('SET FOREIGN_KEY_CHECKS = 1');
$foreignKeys = [
['assigned_task_states_ibfk_1', 'ALTER TABLE `assigned_task_states` ADD CONSTRAINT `assigned_task_states_ibfk_1` FOREIGN KEY (`task_type`) REFERENCES `task_types` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['assigned_task_states_ibfk_2', 'ALTER TABLE `assigned_task_states` ADD CONSTRAINT `assigned_task_states_ibfk_2` FOREIGN KEY (`state`) REFERENCES `task_states` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['auth_tokens_ibfk_1', 'ALTER TABLE `auth_tokens` ADD CONSTRAINT `auth_tokens_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE'],
['comments_ibfk_1', 'ALTER TABLE `comments` ADD CONSTRAINT `comments_ibfk_1` FOREIGN KEY (`commenter`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['comments_ibfk_2', 'ALTER TABLE `comments` ADD CONSTRAINT `comments_ibfk_2` FOREIGN KEY (`task_id`) REFERENCES `tasks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['comments_ibfk_3', 'ALTER TABLE `comments` ADD CONSTRAINT `comments_ibfk_3` FOREIGN KEY (`response_to`) REFERENCES `comments` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['custom_field_values_ibfk_1', 'ALTER TABLE `custom_field_values` ADD CONSTRAINT `custom_field_values_ibfk_1` FOREIGN KEY (`field_id`) REFERENCES `custom_task_fields` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['custom_field_values_ibfk_2', 'ALTER TABLE `custom_field_values` ADD CONSTRAINT `custom_field_values_ibfk_2` FOREIGN KEY (`task_id`) REFERENCES `tasks` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['custom_task_fields_ibfk_1', 'ALTER TABLE `custom_task_fields` ADD CONSTRAINT `custom_task_fields_ibfk_1` FOREIGN KEY (`task_type`) REFERENCES `task_types` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['projects_ibfk_1', 'ALTER TABLE `projects` ADD CONSTRAINT `projects_ibfk_1` FOREIGN KEY (`owner`) REFERENCES `users` (`id`) ON UPDATE CASCADE'],
['remember_tokens_ibfk_1', 'ALTER TABLE `remember_tokens` ADD CONSTRAINT `remember_tokens_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE'],
['tasks_ibfk_1', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_1` FOREIGN KEY (`type`) REFERENCES `task_types` (`id`) ON UPDATE CASCADE'],
['tasks_ibfk_2', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_2` FOREIGN KEY (`priority`) REFERENCES `task_priorities` (`id`) ON UPDATE CASCADE'],
['tasks_ibfk_3', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_3` FOREIGN KEY (`reporter`) REFERENCES `users` (`id`) ON UPDATE CASCADE'],
['tasks_ibfk_4', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_4` FOREIGN KEY (`assignee`) REFERENCES `users` (`id`) ON UPDATE CASCADE'],
['tasks_ibfk_5', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_5` FOREIGN KEY (`project`) REFERENCES `projects` (`id`) ON UPDATE CASCADE'],
['tasks_ibfk_6', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_6` FOREIGN KEY (`fix_version`) REFERENCES `versions` (`id`) ON UPDATE CASCADE'],
['tasks_ibfk_7', 'ALTER TABLE `tasks` ADD CONSTRAINT `tasks_ibfk_7` FOREIGN KEY (`status`) REFERENCES `task_states` (`id`) ON DELETE SET NULL ON UPDATE CASCADE'],
['task_state_transitions_ibfk_1', 'ALTER TABLE `task_state_transitions` ADD CONSTRAINT `task_state_transitions_ibfk_1` FOREIGN KEY (`to_id`) REFERENCES `task_states` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['task_state_transitions_ibfk_2', 'ALTER TABLE `task_state_transitions` ADD CONSTRAINT `task_state_transitions_ibfk_2` FOREIGN KEY (`from_id`) REFERENCES `task_states` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['task_types_ibfk_1', 'ALTER TABLE `task_types` ADD CONSTRAINT `task_types_ibfk_1` FOREIGN KEY (`default_state`) REFERENCES `task_states` (`id`) ON DELETE SET NULL ON UPDATE CASCADE'],
['user_access_ibfk_1', 'ALTER TABLE `user_access` ADD CONSTRAINT `user_access_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['user_access_ibfk_2', 'ALTER TABLE `user_access` ADD CONSTRAINT `user_access_ibfk_2` FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['user_rights_ibfk_1', 'ALTER TABLE `user_rights` ADD CONSTRAINT `user_rights_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['user_rights_ibfk_2', 'ALTER TABLE `user_rights` ADD CONSTRAINT `user_rights_ibfk_2` FOREIGN KEY (`right_id`) REFERENCES `rights` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['user_settings_ibfk_1', 'ALTER TABLE `user_settings` ADD CONSTRAINT `user_settings_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE'],
['versions_ibfk_1', 'ALTER TABLE `versions` ADD CONSTRAINT `versions_ibfk_1` FOREIGN KEY (`project`) REFERENCES `projects` (`id`) ON UPDATE CASCADE'],
];
foreach ($foreignKeys as [$constraint, $definition]) {
addForeignKeyIfMissing($pdo, $constraint, $definition);
}
if (realpath($_SERVER['SCRIPT_FILENAME'] ?? '') === __FILE__) {
header('Location: install.php');
exit;
}
} catch (Throwable $exception) {
try {
$pdo->exec('SET FOREIGN_KEY_CHECKS = 1');
} catch (Throwable) {
}
if (realpath($_SERVER['SCRIPT_FILENAME'] ?? '') !== __FILE__) {
throw $exception;
}
http_response_code(500);
echo '<!doctype html><meta charset="utf-8"><title>ProjectKiln install failed</title>';
echo '<h1>Database install failed</h1>';
echo '<pre>' . htmlspecialchars($exception->getMessage(), ENT_QUOTES, 'UTF-8') . '</pre>';
}