Format tools files
This commit is contained in:
parent
c2575f08b0
commit
dd08499be9
@ -2,251 +2,253 @@
|
||||
error_reporting(E_ERROR);
|
||||
|
||||
class TbGitHubImport {
|
||||
var $db;
|
||||
var $isNew;
|
||||
var $user;
|
||||
var $pass;
|
||||
var $repo;
|
||||
var $ch;
|
||||
var $api;
|
||||
var $projects;
|
||||
var $db;
|
||||
var $isNew;
|
||||
var $user;
|
||||
var $pass;
|
||||
var $repo;
|
||||
var $ch;
|
||||
var $api;
|
||||
var $projects;
|
||||
|
||||
function __construct() {
|
||||
$this->ch = curl_init();
|
||||
$this->api = "https://api.github.com/";
|
||||
function __construct() {
|
||||
$this->ch = curl_init();
|
||||
$this->api = "https://api.github.com/";
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
print "Closing 'taskboard.sqlite'...";
|
||||
$this->db->exec('PRAGMA foreign_keys = ON');
|
||||
$this->db->close();
|
||||
print " Done.\n";
|
||||
}
|
||||
|
||||
function import() {
|
||||
$this->openDb();
|
||||
$this->getInfo();
|
||||
$this->loadData();
|
||||
$this->importData();
|
||||
}
|
||||
|
||||
private function openDb() {
|
||||
print "Opening 'taskboard.sqlite'...";
|
||||
$this->isNew = !file_exists('taskboard.sqlite');
|
||||
|
||||
if ($this->isNew) {
|
||||
print "\n File not found, creating...";
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
print "Closing 'taskboard.sqlite'...";
|
||||
$this->db->exec('PRAGMA foreign_keys = ON');
|
||||
$this->db->close();
|
||||
print " Done.\n";
|
||||
$this->db = new SQLite3('taskboard.sqlite');
|
||||
print " Done.\n";
|
||||
|
||||
if ($this->isNew) {
|
||||
print "Creating tables...";
|
||||
$schema = file_get_contents('schema');
|
||||
$this->db->exec($schema);
|
||||
print " Done.\n";
|
||||
}
|
||||
|
||||
function import() {
|
||||
$this->openDb();
|
||||
$this->getInfo();
|
||||
$this->loadData();
|
||||
$this->importData();
|
||||
$this->db->exec('PRAGMA foreign_keys = OFF');
|
||||
}
|
||||
|
||||
private function getInfo() {
|
||||
$this->user = readline("Enter your GitHub user name: ");
|
||||
$this->pass = readline("Enter your GitHub password: ");
|
||||
$this->repo = readline("What repo do you want to export projects from? ");
|
||||
}
|
||||
|
||||
private function loadData() {
|
||||
$options = array(
|
||||
CURLOPT_URL => $this->api . "repos/" . $this->user . "/" . $this->repo . "/projects",
|
||||
CURLOPT_USERAGENT => "Googlebot/2.1 (+http://www.google.com/bot.html)",
|
||||
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
|
||||
CURLOPT_RETURNTRANSFER => 1,
|
||||
CURLOPT_USERPWD => $this->user . ":" . $this->pass,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Accept: application/vnd.github.inertia-preview+json'
|
||||
)
|
||||
);
|
||||
curl_setopt_array($this->ch, $options);
|
||||
|
||||
$data = json_decode(curl_exec($this->ch));
|
||||
$this->projects = [];
|
||||
|
||||
foreach ($data as $project) {
|
||||
$this->projects[$project->id] =
|
||||
(object)array("id" => $project->id, "name" => $project->name);
|
||||
}
|
||||
|
||||
private function openDb() {
|
||||
print "Opening 'taskboard.sqlite'...";
|
||||
$this->isNew = !file_exists('taskboard.sqlite');
|
||||
print("Found " . count($this->projects) . " project" .
|
||||
(count($this->projects) === 1 ? "" : "s") . ".\n");
|
||||
|
||||
if ($this->isNew) {
|
||||
print "\n File not found, creating...";
|
||||
}
|
||||
foreach ($this->projects as $project) {
|
||||
print " Loading Project " . $project->name . "...\n";
|
||||
|
||||
$this->db = new SQLite3('taskboard.sqlite');
|
||||
print " Done.\n";
|
||||
curl_setopt(
|
||||
$this->ch,
|
||||
CURLOPT_URL,
|
||||
$this->api . "projects/" . $project->id . "/columns"
|
||||
);
|
||||
$data = json_decode(curl_exec($this->ch));
|
||||
|
||||
if ($this->isNew) {
|
||||
print "Creating tables...";
|
||||
$schema = file_get_contents('schema');
|
||||
$this->db->exec($schema);
|
||||
print " Done.\n";
|
||||
}
|
||||
$colPos = 1;
|
||||
|
||||
$this->db->exec('PRAGMA foreign_keys = OFF');
|
||||
}
|
||||
foreach ($data as $column) {
|
||||
print " Loading Column " . $column->name . "...";
|
||||
|
||||
private function getInfo() {
|
||||
$this->user = readline("Enter your GitHub user name: ");
|
||||
$this->pass = readline("Enter your GitHub password: ");
|
||||
$this->repo = readline("What repo do you want to export projects from? ");
|
||||
}
|
||||
|
||||
private function loadData() {
|
||||
$options = array(
|
||||
CURLOPT_URL => $this->api . "repos/" . $this->user . "/" . $this->repo . "/projects",
|
||||
CURLOPT_USERAGENT => "Googlebot/2.1 (+http://www.google.com/bot.html)",
|
||||
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
|
||||
CURLOPT_RETURNTRANSFER => 1,
|
||||
CURLOPT_USERPWD => $this->user . ":" . $this->pass,
|
||||
CURLOPT_HTTPHEADER => array(
|
||||
'Accept: application/vnd.github.inertia-preview+json'
|
||||
)
|
||||
$currentColumn = (object)array(
|
||||
"id" => $column->id, "name" => $column->name, "position" => $colPos
|
||||
);
|
||||
curl_setopt_array($this->ch, $options);
|
||||
$colPos++;
|
||||
|
||||
$data = json_decode(curl_exec($this->ch));
|
||||
$this->projects = [];
|
||||
curl_setopt(
|
||||
$this->ch,
|
||||
CURLOPT_URL,
|
||||
$this->api . "projects/columns/" . $column->id . "/cards"
|
||||
);
|
||||
$cardData = json_decode(curl_exec($this->ch));
|
||||
|
||||
foreach ($data as $project) {
|
||||
$this->projects[$project->id] =
|
||||
(object)array("id" => $project->id, "name" => $project->name);
|
||||
$cards = [];
|
||||
$cardPos = 1;
|
||||
|
||||
foreach ($cardData as $card) {
|
||||
$cards[] = (object)array(
|
||||
"id" => $card->id,
|
||||
"title" => "Imported",
|
||||
"color" => "#ffffe0",
|
||||
"description" => $card->note,
|
||||
"position" => $cardPos,
|
||||
"column_id" => $column->id
|
||||
);
|
||||
$cardPos++;
|
||||
}
|
||||
|
||||
print("Found " . count($this->projects) . " project" .
|
||||
(count($this->projects) === 1 ? "" : "s") . ".\n");
|
||||
$this->projects[$project->id]->columns[$column->id] = $currentColumn;
|
||||
$this->projects[$project->id]->columns[$column->id]->cards = $cards;
|
||||
|
||||
foreach ($this->projects as $project) {
|
||||
print " Loading Project " . $project->name . "...\n";
|
||||
print " Loaded " . ($cardPos - 1) . " cards (tasks).\n";
|
||||
}
|
||||
|
||||
curl_setopt(
|
||||
$this->ch,
|
||||
CURLOPT_URL,
|
||||
$this->api . "projects/" . $project->id . "/columns"
|
||||
);
|
||||
$data = json_decode(curl_exec($this->ch));
|
||||
print " Loaded Project " . $project->name . ".\n";
|
||||
}
|
||||
}
|
||||
|
||||
$colPos = 1;
|
||||
private function importData() {
|
||||
foreach ($this->projects as $project) {
|
||||
print " Importing Project " . $project->name . "...\n";
|
||||
|
||||
foreach ($data as $column) {
|
||||
print " Loading Column " . $column->name . "...";
|
||||
$exists = $this->db->querySingle('SELECT id FROM board WHERE name = "' .
|
||||
$project->name . '"');
|
||||
|
||||
$currentColumn = (object)array(
|
||||
"id" => $column->id, "name" => $column->name, "position" => $colPos
|
||||
);
|
||||
$colPos++;
|
||||
if (count($exists) === 0) {
|
||||
$stmt = $this->db->prepare('INSERT INTO board (name, is_active) ' .
|
||||
'VALUES (:name, :is_active)');
|
||||
|
||||
curl_setopt(
|
||||
$this->ch,
|
||||
CURLOPT_URL,
|
||||
$this->api . "projects/columns/" . $column->id . "/cards"
|
||||
);
|
||||
$cardData = json_decode(curl_exec($this->ch));
|
||||
$stmt->bindValue(":name", $project->name);
|
||||
$stmt->bindValue(":is_active", true);
|
||||
|
||||
$cards = [];
|
||||
$cardPos = 1;
|
||||
|
||||
foreach ($cardData as $card) {
|
||||
$cards[] = (object)array(
|
||||
"id" => $card->id,
|
||||
"title" => "Imported",
|
||||
"color" => "#ffffe0",
|
||||
"description" => $card->note,
|
||||
"position" => $cardPos,
|
||||
"column_id" => $column->id
|
||||
);
|
||||
$cardPos++;
|
||||
}
|
||||
|
||||
$this->projects[$project->id]->columns[$column->id] = $currentColumn;
|
||||
$this->projects[$project->id]->columns[$column->id]->cards = $cards;
|
||||
|
||||
print " Loaded " . ($cardPos - 1) . " cards (tasks).\n";
|
||||
}
|
||||
|
||||
print " Loaded Project " . $project->name . ".\n";
|
||||
if ($stmt->execute()) {
|
||||
print " Created board.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isNew) {
|
||||
$stmt = $this->db->prepare('INSERT INTO user (username, security_level, ' .
|
||||
'password_hash) VALUES (:uname, :secLev, :hash)');
|
||||
$stmt->bindValue(':uname', 'admin');
|
||||
$stmt->bindValue(':secLev', 1);
|
||||
$stmt->bindValue(':hash', password_hash('admin', PASSWORD_BCRYPT));
|
||||
|
||||
if ($stmt->execute()) {
|
||||
print " Created default admin user.\n";
|
||||
}
|
||||
|
||||
$adminId = $this->db->lastInsertRowID();
|
||||
$stmt = $this->db->prepare('INSERT INTO useroption (id, ' .
|
||||
'new_tasks_at_bottom, show_animations, show_assignee, ' .
|
||||
'multiple_tasks_per_row, language) VALUES (:id, :new, :anim, ' .
|
||||
':assign, :mult, :lang)');
|
||||
$stmt->bindValue(':id', $adminId);
|
||||
$stmt->bindValue(':new', true);
|
||||
$stmt->bindValue(':anim', true);
|
||||
$stmt->bindValue(':assign', true);
|
||||
$stmt->bindValue(':mult', false);
|
||||
$stmt->bindValue(':lang', 'en');
|
||||
|
||||
$stmt->execute();
|
||||
|
||||
$optId = $this->db->lastInsertRowID();
|
||||
$stmt = $this->db->prepare('UPDATE user SET user_option_id = ' . $optId .
|
||||
' WHERE id = ' . $adminId);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
$boardId = $this->cleanupExistingTables($project->name);
|
||||
|
||||
$users = $this->db->query('SELECT id FROM user WHERE security_level = 1');
|
||||
$stmt = $this->db->prepare('INSERT INTO board_user (user_id, board_id) '.
|
||||
'VALUES (:user_id, :board_id)');
|
||||
|
||||
while ($user = $users->fetchArray()) {
|
||||
$stmt->bindValue(':user_id', $user['id']);
|
||||
$stmt->bindValue(':board_id', $boardId);
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
print " Added admin user(s) to board.\n";
|
||||
|
||||
$colCount = 0;
|
||||
$taskCount = 0;
|
||||
|
||||
foreach ($project->columns as $column) {
|
||||
$stmt = $this->db->prepare('INSERT INTO column (name, position, board_id) ' .
|
||||
'VALUES (:name, :pos, :board_id)');
|
||||
|
||||
$stmt->bindValue(':name', $column->name);
|
||||
$stmt->bindValue(':pos', $column->position);
|
||||
$stmt->bindValue(':board_id', $boardId);
|
||||
|
||||
$stmt->execute();
|
||||
$colCount++;
|
||||
$colId = $this->db->lastInsertRowID();
|
||||
|
||||
$stmt = $this->db->prepare('INSERT INTO task (title, description, ' .
|
||||
'color, position, column_id) VALUES (:title, :description, :color,' .
|
||||
':pos, :col_id)');
|
||||
foreach ($column->cards as $card) {
|
||||
$stmt->bindValue(':title', $card->title);
|
||||
$stmt->bindValue(':description', $card->description);
|
||||
$stmt->bindValue(':color', $card->color);
|
||||
$stmt->bindValue(':pos', $card->position);
|
||||
$stmt->bindValue(':col_id', $colId);
|
||||
|
||||
$stmt->execute();
|
||||
$taskCount++;
|
||||
}
|
||||
}
|
||||
|
||||
print " Inserted " . $colCount . " columns, and " . $taskCount . " tasks.\n";
|
||||
}
|
||||
|
||||
private function importData() {
|
||||
foreach ($this->projects as $project) {
|
||||
print " Importing Project " . $project->name . "...\n";
|
||||
print " Done Importing.\n";
|
||||
}
|
||||
|
||||
$exists = $this->db->querySingle('SELECT id FROM board WHERE name = "' .
|
||||
$project->name . '"');
|
||||
private function cleanupExistingTables($boardName) {
|
||||
$boardId = $this->db->querySingle('SELECT id FROM board ' .
|
||||
'WHERE name = "' . $boardName . '"');
|
||||
$this->db->exec('DELETE FROM board_user WHERE board_id = ' . $boardId);
|
||||
$columns = $this->db->query('SELECT id FROM column WHERE board_id = ' . $boardId);
|
||||
|
||||
if (count($exists) === 0) {
|
||||
$stmt = $this->db->prepare('INSERT INTO board (name, is_active) ' .
|
||||
'VALUES (:name, :is_active)');
|
||||
|
||||
$stmt->bindValue(":name", $project->name);
|
||||
$stmt->bindValue(":is_active", true);
|
||||
|
||||
if ($stmt->execute()) {
|
||||
print " Created board.\n";
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->isNew) {
|
||||
$stmt = $this->db->prepare('INSERT INTO user (username, security_level, ' .
|
||||
'password_hash) VALUES (:uname, :secLev, :hash)');
|
||||
$stmt->bindValue(':uname', 'admin');
|
||||
$stmt->bindValue(':secLev', 1);
|
||||
$stmt->bindValue(':hash', password_hash('admin', PASSWORD_BCRYPT));
|
||||
|
||||
if ($stmt->execute()) {
|
||||
print " Created default admin user.\n";
|
||||
}
|
||||
|
||||
$adminId = $this->db->lastInsertRowID();
|
||||
$stmt = $this->db->prepare('INSERT INTO useroption (id, ' .
|
||||
'new_tasks_at_bottom, show_animations, show_assignee, ' .
|
||||
'multiple_tasks_per_row, language) VALUES (:id, :new, :anim, ' .
|
||||
':assign, :mult, :lang)');
|
||||
$stmt->bindValue(':id', $adminId);
|
||||
$stmt->bindValue(':new', true);
|
||||
$stmt->bindValue(':anim', true);
|
||||
$stmt->bindValue(':assign', true);
|
||||
$stmt->bindValue(':mult', false);
|
||||
$stmt->bindValue(':lang', 'en');
|
||||
|
||||
$stmt->execute();
|
||||
|
||||
$optId = $this->db->lastInsertRowID();
|
||||
$stmt = $this->db->prepare('UPDATE user SET user_option_id = ' . $optId .
|
||||
' WHERE id = ' . $adminId);
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
$boardId = $this->cleanupExistingTables($project->name);
|
||||
|
||||
$users = $this->db->query('SELECT id FROM user WHERE security_level = 1');
|
||||
$stmt = $this->db->prepare('INSERT INTO board_user (user_id, board_id) '.
|
||||
'VALUES (:user_id, :board_id)');
|
||||
|
||||
while ($user = $users->fetchArray()) {
|
||||
$stmt->bindValue(':user_id', $user['id']);
|
||||
$stmt->bindValue(':board_id', $boardId);
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
print " Added admin user(s) to board.\n";
|
||||
|
||||
$colCount = 0;
|
||||
$taskCount = 0;
|
||||
|
||||
foreach ($project->columns as $column) {
|
||||
$stmt = $this->db->prepare('INSERT INTO column (name, position, board_id) ' .
|
||||
'VALUES (:name, :pos, :board_id)');
|
||||
|
||||
$stmt->bindValue(':name', $column->name);
|
||||
$stmt->bindValue(':pos', $column->position);
|
||||
$stmt->bindValue(':board_id', $boardId);
|
||||
|
||||
$stmt->execute();
|
||||
$colCount++;
|
||||
$colId = $this->db->lastInsertRowID();
|
||||
|
||||
$stmt = $this->db->prepare('INSERT INTO task (title, description, ' .
|
||||
'color, position, column_id) VALUES (:title, :description, :color,' .
|
||||
':pos, :col_id)');
|
||||
foreach ($column->cards as $card) {
|
||||
$stmt->bindValue(':title', $card->title);
|
||||
$stmt->bindValue(':description', $card->description);
|
||||
$stmt->bindValue(':color', $card->color);
|
||||
$stmt->bindValue(':pos', $card->position);
|
||||
$stmt->bindValue(':col_id', $colId);
|
||||
|
||||
$stmt->execute();
|
||||
$taskCount++;
|
||||
}
|
||||
}
|
||||
|
||||
print " Inserted " . $colCount . " columns, and " . $taskCount . " tasks.\n";
|
||||
}
|
||||
|
||||
print " Done Importing.\n";
|
||||
if ($columns) {
|
||||
while ($col = $columns->fetchArray()) {
|
||||
$this->db->exec('DELETE FROM task WHERE column_id = ' . $col['id']);
|
||||
}
|
||||
}
|
||||
|
||||
private function cleanupExistingTables($boardName) {
|
||||
$boardId = $this->db->querySingle('SELECT id FROM board ' .
|
||||
'WHERE name = "' . $boardName . '"');
|
||||
$this->db->exec('DELETE FROM board_user WHERE board_id = ' . $boardId);
|
||||
$columns = $this->db->query('SELECT id FROM column WHERE board_id = ' . $boardId);
|
||||
$this->db->exec('DELETE FROM column WHERE board_id = ' . $boardId);
|
||||
|
||||
while ($col = $columns->fetchArray()) {
|
||||
$this->db->exec('DELETE FROM task WHERE column_id = ' . $col['id']);
|
||||
}
|
||||
|
||||
$this->db->exec('DELETE FROM column WHERE board_id = ' . $boardId);
|
||||
|
||||
return $boardId;
|
||||
}
|
||||
return $boardId;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,359 +1,359 @@
|
||||
<?php
|
||||
|
||||
class TbMigrate {
|
||||
var $oldDb;
|
||||
var $newDb;
|
||||
var $oldDb;
|
||||
var $newDb;
|
||||
|
||||
function __construct() {
|
||||
print "Opening 'taskboard.db'...";
|
||||
try {
|
||||
$this->oldDb = new SQLite3('taskboard.db', SQLITE3_OPEN_READONLY);
|
||||
print "\t\tDone.\n";
|
||||
} catch (Exception $e) {
|
||||
print "\t\tError opening 'taskboard.db'\n";
|
||||
print " " . $e->getMessage() . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
print "Opening 'taskboard.sqlite'...";
|
||||
try {
|
||||
unlink('taskboard.sqlite'); // Always start fresh.
|
||||
|
||||
$this->newDb = new SQLite3('taskboard.sqlite');
|
||||
print "\t\tDone.\n\n";
|
||||
} catch (Exception $e) {
|
||||
print "\t\tError creating 'taskboard.sqlite'\n";
|
||||
print " " . $e->getMessage() . "\n";
|
||||
return;
|
||||
}
|
||||
function __construct() {
|
||||
print "Opening 'taskboard.db'...";
|
||||
try {
|
||||
$this->oldDb = new SQLite3('taskboard.db', SQLITE3_OPEN_READONLY);
|
||||
print "\t\tDone.\n";
|
||||
} catch (Exception $e) {
|
||||
print "\t\tError opening 'taskboard.db'\n";
|
||||
print " " . $e->getMessage() . "\n";
|
||||
return;
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
print "\n";
|
||||
print "Closing 'taskboard.sqlite'...";
|
||||
$this->newDb->exec('PRAGMA foreign_keys = ON');
|
||||
$this->newDb->close();
|
||||
print "\t\tDone.\n";
|
||||
print "Opening 'taskboard.sqlite'...";
|
||||
try {
|
||||
unlink('taskboard.sqlite'); // Always start fresh.
|
||||
|
||||
print "Closing 'taskboard.db'...";
|
||||
$this->oldDb->close();
|
||||
print "\t\tDone.\n";
|
||||
$this->newDb = new SQLite3('taskboard.sqlite');
|
||||
print "\t\tDone.\n\n";
|
||||
} catch (Exception $e) {
|
||||
print "\t\tError creating 'taskboard.sqlite'\n";
|
||||
print " " . $e->getMessage() . "\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function __destruct() {
|
||||
print "\n";
|
||||
print "Closing 'taskboard.sqlite'...";
|
||||
$this->newDb->exec('PRAGMA foreign_keys = ON');
|
||||
$this->newDb->close();
|
||||
print "\t\tDone.\n";
|
||||
|
||||
print "Closing 'taskboard.db'...";
|
||||
$this->oldDb->close();
|
||||
print "\t\tDone.\n";
|
||||
}
|
||||
|
||||
function migrate() {
|
||||
$this->createTables();
|
||||
|
||||
$this->migrateActivity();
|
||||
// TODO: attachments table
|
||||
$this->migrateAutoAction();
|
||||
$this->migrateBoard();
|
||||
$this->migrateBoardUser();
|
||||
$this->migrateCategory();
|
||||
$this->migrateCollapsed();
|
||||
$this->migrateComment();
|
||||
$this->migrateItem();
|
||||
$this->migrateLane();
|
||||
$this->migrateUser();
|
||||
}
|
||||
|
||||
private function createTables() {
|
||||
print " Creating new tables...";
|
||||
$schema = file_get_contents('schema');
|
||||
|
||||
$this->newDb->exec($schema);
|
||||
$this->newDb->exec('PRAGMA foreign_keys = OFF');
|
||||
print "\t\t\tDone.\n\n";
|
||||
}
|
||||
|
||||
private function getItemType($str) {
|
||||
if (strpos($str, 'item') !== false) {
|
||||
return 'task';
|
||||
}
|
||||
|
||||
function migrate() {
|
||||
$this->createTables();
|
||||
|
||||
$this->migrateActivity();
|
||||
// TODO: attachments table
|
||||
$this->migrateAutoAction();
|
||||
$this->migrateBoard();
|
||||
$this->migrateBoardUser();
|
||||
$this->migrateCategory();
|
||||
$this->migrateCollapsed();
|
||||
$this->migrateComment();
|
||||
$this->migrateItem();
|
||||
$this->migrateLane();
|
||||
$this->migrateUser();
|
||||
if (strpos($str, 'column') !== false) {
|
||||
return 'column';
|
||||
}
|
||||
|
||||
private function createTables() {
|
||||
print " Creating new tables...";
|
||||
$schema = file_get_contents('schema');
|
||||
|
||||
$this->newDb->exec($schema);
|
||||
$this->newDb->exec('PRAGMA foreign_keys = OFF');
|
||||
print "\t\t\tDone.\n\n";
|
||||
if (strpos($str, 'board') !== false) {
|
||||
return 'board';
|
||||
}
|
||||
|
||||
private function getItemType($str) {
|
||||
if (strpos($str, 'item') !== false) {
|
||||
return 'task';
|
||||
}
|
||||
|
||||
if (strpos($str, 'column') !== false) {
|
||||
return 'column';
|
||||
}
|
||||
|
||||
if (strpos($str, 'board') !== false) {
|
||||
return 'board';
|
||||
}
|
||||
|
||||
if (strpos($str, 'changed') !== false || strpos($str, 'logged') !== false ||
|
||||
strpos($str, 'added') !== false || strpos($str, 'removed') !== false) {
|
||||
return 'user';
|
||||
}
|
||||
|
||||
return null;
|
||||
if (strpos($str, 'changed') !== false || strpos($str, 'logged') !== false ||
|
||||
strpos($str, 'added') !== false || strpos($str, 'removed') !== false) {
|
||||
return 'user';
|
||||
}
|
||||
|
||||
private function getItemId($itemId, $newValue) {
|
||||
if (isset($itemId)) {
|
||||
return $itemId;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
$obj = json_decode($newValue);
|
||||
|
||||
if ($obj !== null) {
|
||||
return $obj->id;
|
||||
}
|
||||
|
||||
return null;
|
||||
private function getItemId($itemId, $newValue) {
|
||||
if (isset($itemId)) {
|
||||
return $itemId;
|
||||
}
|
||||
|
||||
private function getActionType($row) {
|
||||
switch ($row['action_id']) {
|
||||
case 0:
|
||||
return 1;
|
||||
break;
|
||||
case 2:
|
||||
return 4;
|
||||
break;
|
||||
case 3:
|
||||
return 6;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
$obj = json_decode($newValue);
|
||||
|
||||
if ($obj !== null) {
|
||||
return $obj->id;
|
||||
}
|
||||
|
||||
private function getActionChange($row) {
|
||||
if (isset($row['color'])) {
|
||||
return $row['color'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isset($row['category_id'])) {
|
||||
return $row['category_id'];
|
||||
}
|
||||
private function getActionType($row) {
|
||||
switch ($row['action_id']) {
|
||||
case 0:
|
||||
return 1;
|
||||
break;
|
||||
case 2:
|
||||
return 4;
|
||||
break;
|
||||
case 3:
|
||||
return 6;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($row['assignee_id'])) {
|
||||
return $row['assignee_id'];
|
||||
}
|
||||
|
||||
return null;
|
||||
private function getActionChange($row) {
|
||||
if (isset($row['color'])) {
|
||||
return $row['color'];
|
||||
}
|
||||
|
||||
private function migrateTable($stmtStr, $fn, $oldTable = null) {
|
||||
$table = isset($oldTable) ? $oldTable : explode(' ', $stmtStr)[2];
|
||||
|
||||
print " Migrating table `$table`...";
|
||||
|
||||
$results = $this->oldDb->query("SELECT * from $table ORDER BY id");
|
||||
|
||||
if ($results->numColumns() === 0) {
|
||||
print " no rows.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
$stmt = $this->newDb->prepare($stmtStr);
|
||||
$rowCount = 0;
|
||||
$errCount = 0;
|
||||
|
||||
while ($row = $results->fetchArray()) {
|
||||
$fn($stmt, $row);
|
||||
|
||||
if ($stmt->execute() === false) {
|
||||
$errCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$rowCount++;
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
print strlen($table) < 10 ? "\t" : "";
|
||||
print "\t$rowCount rows migrated.\n";
|
||||
|
||||
if ($errCount > 0) {
|
||||
print " $errCount rows failed.\n";
|
||||
}
|
||||
if (isset($row['category_id'])) {
|
||||
return $row['category_id'];
|
||||
}
|
||||
|
||||
private function migrateActivity() {
|
||||
$stmtStr = 'INSERT INTO activity (id, user_id, log_text, before, after, ' .
|
||||
'item_type, item_id, timestamp) VALUES (:id, :user_id, :log_text, ' .
|
||||
':before, :after, :item_type, :item_id, :timestamp)';
|
||||
$knownNames = [];
|
||||
|
||||
$this->migrateTable($stmtStr, function(&$stmt, $row) use ($knownNames) {
|
||||
$name = explode(' ', $row['comment'])[0];
|
||||
|
||||
if (!array_key_exists($name, $knownNames)) {
|
||||
$usr = $this->oldDb->query('SELECT id FROM user ' .
|
||||
'WHERE username = "' . $name . '"');
|
||||
|
||||
$knownNames[$name] = $usr->fetchArray()['id'];
|
||||
}
|
||||
|
||||
$type = $this->getItemType($row['comment']);
|
||||
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':user_id', $knownNames[$name]);
|
||||
$stmt->bindValue(':log_text', $row['comment']);
|
||||
$stmt->bindValue(':before', $row['old_value']);
|
||||
$stmt->bindValue(':after', $row['new_value']);
|
||||
$stmt->bindValue(':item_type', $type);
|
||||
$stmt->bindValue(':item_id', $type === 'user'
|
||||
? $knownNames[$name]
|
||||
: $this->getItemId($row['item_id'], $row['new_value']));
|
||||
$stmt->bindValue(':timestamp', $row['timestamp']);
|
||||
});
|
||||
if (isset($row['assignee_id'])) {
|
||||
return $row['assignee_id'];
|
||||
}
|
||||
|
||||
private function migrateAutoAction() {
|
||||
$stmtStr = 'INSERT INTO autoaction (id, trigger, source_id, type, ' .
|
||||
'change_to, board_id) VALUES (:id, :trigger, :source_id, :type, ' .
|
||||
':change_to, :board_id)';
|
||||
return null;
|
||||
}
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':trigger', ((int)$row['trigger_id']) + 1);
|
||||
$stmt->bindValue(':source_id', $row['secondary_id']);
|
||||
$stmt->bindValue(':type', $this->getActionType($row));
|
||||
$stmt->bindValue(':change_to', $this->getActionChange($row));
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
});
|
||||
private function migrateTable($stmtStr, $fn, $oldTable = null) {
|
||||
$table = isset($oldTable) ? $oldTable : explode(' ', $stmtStr)[2];
|
||||
|
||||
print " Migrating table `$table`...";
|
||||
|
||||
$results = $this->oldDb->query("SELECT * from $table ORDER BY id");
|
||||
|
||||
if ($results->numColumns() === 0) {
|
||||
print " no rows.\n";
|
||||
return;
|
||||
}
|
||||
|
||||
private function migrateBoard() {
|
||||
$stmtStr = 'INSERT INTO board (id, name, is_active) ' .
|
||||
'VALUES (:id, :name, :is_active)';
|
||||
$stmt = $this->newDb->prepare($stmtStr);
|
||||
$rowCount = 0;
|
||||
$errCount = 0;
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':name', $row['name']);
|
||||
$stmt->bindValue(':is_active', $row['active']);
|
||||
});
|
||||
while ($row = $results->fetchArray()) {
|
||||
$fn($stmt, $row);
|
||||
|
||||
if ($stmt->execute() === false) {
|
||||
$errCount++;
|
||||
continue;
|
||||
}
|
||||
|
||||
$rowCount++;
|
||||
}
|
||||
|
||||
private function migrateBoardUser() {
|
||||
$stmtStr = 'INSERT INTO board_user (id, user_id, board_id) ' .
|
||||
'VALUES (:id, :user_id, :board_id)';
|
||||
$stmt->close();
|
||||
print strlen($table) < 10 ? "\t" : "";
|
||||
print "\t$rowCount rows migrated.\n";
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':user_id', $row['user_id']);
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
});
|
||||
if ($errCount > 0) {
|
||||
print " $errCount rows failed.\n";
|
||||
}
|
||||
}
|
||||
|
||||
private function migrateActivity() {
|
||||
$stmtStr = 'INSERT INTO activity (id, user_id, log_text, before, after, ' .
|
||||
'item_type, item_id, timestamp) VALUES (:id, :user_id, :log_text, ' .
|
||||
':before, :after, :item_type, :item_id, :timestamp)';
|
||||
$knownNames = [];
|
||||
|
||||
$this->migrateTable($stmtStr, function(&$stmt, $row) use ($knownNames) {
|
||||
$name = explode(' ', $row['comment'])[0];
|
||||
|
||||
if (!array_key_exists($name, $knownNames)) {
|
||||
$usr = $this->oldDb->query('SELECT id FROM user ' .
|
||||
'WHERE username = "' . $name . '"');
|
||||
|
||||
$knownNames[$name] = $usr->fetchArray()['id'];
|
||||
}
|
||||
|
||||
$type = $this->getItemType($row['comment']);
|
||||
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':user_id', $knownNames[$name]);
|
||||
$stmt->bindValue(':log_text', $row['comment']);
|
||||
$stmt->bindValue(':before', $row['old_value']);
|
||||
$stmt->bindValue(':after', $row['new_value']);
|
||||
$stmt->bindValue(':item_type', $type);
|
||||
$stmt->bindValue(':item_id', $type === 'user'
|
||||
? $knownNames[$name]
|
||||
: $this->getItemId($row['item_id'], $row['new_value']));
|
||||
$stmt->bindValue(':timestamp', $row['timestamp']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateAutoAction() {
|
||||
$stmtStr = 'INSERT INTO autoaction (id, trigger, source_id, type, ' .
|
||||
'change_to, board_id) VALUES (:id, :trigger, :source_id, :type, ' .
|
||||
':change_to, :board_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':trigger', ((int)$row['trigger_id']) + 1);
|
||||
$stmt->bindValue(':source_id', $row['secondary_id']);
|
||||
$stmt->bindValue(':type', $this->getActionType($row));
|
||||
$stmt->bindValue(':change_to', $this->getActionChange($row));
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateBoard() {
|
||||
$stmtStr = 'INSERT INTO board (id, name, is_active) ' .
|
||||
'VALUES (:id, :name, :is_active)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':name', $row['name']);
|
||||
$stmt->bindValue(':is_active', $row['active']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateBoardUser() {
|
||||
$stmtStr = 'INSERT INTO board_user (id, user_id, board_id) ' .
|
||||
'VALUES (:id, :user_id, :board_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':user_id', $row['user_id']);
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateCategory() {
|
||||
$stmtStr = 'INSERT INTO category (id, name, default_task_color, board_id) ' .
|
||||
'VALUES (:id, :name, "#ffffe0", :board_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':name', $row['name']);
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateCollapsed() {
|
||||
$stmtStr = 'INSERT INTO collapsed (id, user_id, column_id) ' .
|
||||
'VALUES (:id, :user_id, :column_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':user_id', $row['user_id']);
|
||||
$stmt->bindValue(':column_id', $row['lane_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateComment() {
|
||||
$stmtStr = 'INSERT INTO comment (id, text, user_id, task_id, timestamp, ' .
|
||||
'is_edited) VALUES (:id, :text, :user_id, :task_id, :timestamp, 0)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':text', $row['text']);
|
||||
$stmt->bindValue(':user_id', $row['user_id']);
|
||||
$stmt->bindValue(':task_id', $row['item_id']);
|
||||
$stmt->bindValue(':timestamp', $row['timestamp']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateItem() {
|
||||
$stmtStr = 'INSERT INTO task (id, title, description, color, due_date, ' .
|
||||
'points, position, column_id) VALUES (:id, :title, :description, :color, ' .
|
||||
':due_date, :points, :position, :column_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':title', $row['title']);
|
||||
$stmt->bindValue(':description', $row['description']);
|
||||
$stmt->bindValue(':color', $row['color']);
|
||||
$stmt->bindValue(':due_date', $row['due_date']);
|
||||
$stmt->bindValue(':points', $row['points']);
|
||||
$stmt->bindValue(':position', $row['position']);
|
||||
$stmt->bindValue(':column_id', $row['lane_id']);
|
||||
|
||||
$this->newDb->exec('INSERT INTO task_user (user_id, task_id) ' .
|
||||
'VALUES (' . $row['assignee'] . ', ' . $row['id'] . ')');
|
||||
$this->newDb->exec('INSERT INTO category_task (category_id, task_id) ' .
|
||||
'VALUES (' . $row['category'] . ', ' . $row['id'] . ')');
|
||||
}, 'item');
|
||||
}
|
||||
|
||||
private function migrateLane() {
|
||||
$stmtStr = 'INSERT INTO column (id, name, position, board_id) ' .
|
||||
'VALUES (:id, :name, :position, :board_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':name', $row['name']);
|
||||
$stmt->bindValue(':position', $row['position']);
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
}, 'lane');
|
||||
}
|
||||
|
||||
private function migrateUser() {
|
||||
$stmtStr = 'INSERT INTO user (id, username, security_level, password_hash, ' .
|
||||
'email, default_board_id, user_option_id, last_login) VALUES (:id, ' .
|
||||
':uname, :secLev, :hash, :email, :board, :option, :last)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':uname', $row['username']);
|
||||
$stmt->bindValue(':secLev', $row['is_admin'] === 1 ? 1 : 3);
|
||||
$stmt->bindValue(':hash', $row['password']);
|
||||
$stmt->bindValue(':email', $row['email']);
|
||||
$stmt->bindValue(':board', $row['default_board']);
|
||||
$stmt->bindValue(':option', $row['id']);
|
||||
$stmt->bindValue(':last', $row['last_login']);
|
||||
});
|
||||
|
||||
$users = $this->newDb->query('SELECT id FROM user ORDER BY id');
|
||||
|
||||
while ($row = $users->fetchArray()) {
|
||||
$stmt = $this->newDb->prepare('INSERT INTO useroption (id, ' .
|
||||
'new_tasks_at_bottom, show_animations, show_assignee, ' .
|
||||
'multiple_tasks_per_row, language) VALUES (:id, :atBottom, :anims, ' .
|
||||
':assignee, 0, "en")');
|
||||
|
||||
$opts = $this->oldDb->query(
|
||||
'SELECT * FROM option WHERE id = ' . (int)$row['id']
|
||||
);
|
||||
$opts = $opts->fetchArray();
|
||||
|
||||
if ($opts === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stmt->bindValue(':id', $opts['id']);
|
||||
$stmt->bindValue(':atBottom', isset($opts['tasks_order'])
|
||||
? $opts['tasks_order']
|
||||
: $opts['new_task_position']);
|
||||
$stmt->bindValue(':anims', isset($opts['animate'])
|
||||
? $opts['animate']
|
||||
: $opts['show_animations']);
|
||||
$stmt->bindValue(':assignee', isset($opts['show_assignee'])
|
||||
? $opts['show_assignee']
|
||||
: 1);
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
private function migrateCategory() {
|
||||
$stmtStr = 'INSERT INTO category (id, name, default_task_color, board_id) ' .
|
||||
'VALUES (:id, :name, "#ffffe0", :board_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':name', $row['name']);
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateCollapsed() {
|
||||
$stmtStr = 'INSERT INTO collapsed (id, user_id, column_id) ' .
|
||||
'VALUES (:id, :user_id, :column_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':user_id', $row['user_id']);
|
||||
$stmt->bindValue(':column_id', $row['lane_id']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateComment() {
|
||||
$stmtStr = 'INSERT INTO comment (id, text, user_id, task_id, timestamp, ' .
|
||||
'is_edited) VALUES (:id, :text, :user_id, :task_id, :timestamp, 0)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':text', $row['text']);
|
||||
$stmt->bindValue(':user_id', $row['user_id']);
|
||||
$stmt->bindValue(':task_id', $row['item_id']);
|
||||
$stmt->bindValue(':timestamp', $row['timestamp']);
|
||||
});
|
||||
}
|
||||
|
||||
private function migrateItem() {
|
||||
$stmtStr = 'INSERT INTO task (id, title, description, color, due_date, ' .
|
||||
'points, position, column_id) VALUES (:id, :title, :description, :color, ' .
|
||||
':due_date, :points, :position, :column_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':title', $row['title']);
|
||||
$stmt->bindValue(':description', $row['description']);
|
||||
$stmt->bindValue(':color', $row['color']);
|
||||
$stmt->bindValue(':due_date', $row['due_date']);
|
||||
$stmt->bindValue(':points', $row['points']);
|
||||
$stmt->bindValue(':position', $row['position']);
|
||||
$stmt->bindValue(':column_id', $row['lane_id']);
|
||||
|
||||
$this->newDb->exec('INSERT INTO task_user (user_id, task_id) ' .
|
||||
'VALUES (' . $row['assignee'] . ', ' . $row['id'] . ')');
|
||||
$this->newDb->exec('INSERT INTO category_task (category_id, task_id) ' .
|
||||
'VALUES (' . $row['category'] . ', ' . $row['id'] . ')');
|
||||
}, 'item');
|
||||
}
|
||||
|
||||
private function migrateLane() {
|
||||
$stmtStr = 'INSERT INTO column (id, name, position, board_id) ' .
|
||||
'VALUES (:id, :name, :position, :board_id)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':name', $row['name']);
|
||||
$stmt->bindValue(':position', $row['position']);
|
||||
$stmt->bindValue(':board_id', $row['board_id']);
|
||||
}, 'lane');
|
||||
}
|
||||
|
||||
private function migrateUser() {
|
||||
$stmtStr = 'INSERT INTO user (id, username, security_level, password_hash, ' .
|
||||
'email, default_board_id, user_option_id, last_login) VALUES (:id, ' .
|
||||
':uname, :secLev, :hash, :email, :board, :option, :last)';
|
||||
|
||||
$this->migrateTable($stmtStr, function (&$stmt, $row) {
|
||||
$stmt->bindValue(':id', $row['id']);
|
||||
$stmt->bindValue(':uname', $row['username']);
|
||||
$stmt->bindValue(':secLev', $row['is_admin'] === 1 ? 1 : 3);
|
||||
$stmt->bindValue(':hash', $row['password']);
|
||||
$stmt->bindValue(':email', $row['email']);
|
||||
$stmt->bindValue(':board', $row['default_board']);
|
||||
$stmt->bindValue(':option', $row['id']);
|
||||
$stmt->bindValue(':last', $row['last_login']);
|
||||
});
|
||||
|
||||
$users = $this->newDb->query('SELECT id FROM user ORDER BY id');
|
||||
|
||||
while ($row = $users->fetchArray()) {
|
||||
$stmt = $this->newDb->prepare('INSERT INTO useroption (id, ' .
|
||||
'new_tasks_at_bottom, show_animations, show_assignee, ' .
|
||||
'multiple_tasks_per_row, language) VALUES (:id, :atBottom, :anims, ' .
|
||||
':assignee, 0, "en")');
|
||||
|
||||
$opts = $this->oldDb->query(
|
||||
'SELECT * FROM option WHERE id = ' . (int)$row['id']
|
||||
);
|
||||
$opts = $opts->fetchArray();
|
||||
|
||||
if ($opts === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$stmt->bindValue(':id', $opts['id']);
|
||||
$stmt->bindValue(':atBottom', isset($opts['tasks_order'])
|
||||
? $opts['tasks_order']
|
||||
: $opts['new_task_position']);
|
||||
$stmt->bindValue(':anims', isset($opts['animate'])
|
||||
? $opts['animate']
|
||||
: $opts['show_animations']);
|
||||
$stmt->bindValue(':assignee', isset($opts['show_assignee'])
|
||||
? $opts['show_assignee']
|
||||
: 1);
|
||||
|
||||
$stmt->execute();
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
}
|
||||
$stmt->close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user