Database fixes

This commit is contained in:
Roman Hergenreder 2020-04-02 16:16:58 +02:00
parent 5c7875c1ba
commit cc334eb62d
7 changed files with 132 additions and 109 deletions

@ -249,11 +249,7 @@ class MySQL extends SQL {
$columns = array(); $columns = array();
foreach($select->getColumns() as $col) { foreach($select->getColumns() as $col) {
if ($col instanceof Keyword) { $columns[] = $this->columnName($col);
$columns[] = $col->getValue();
} else {
$columns[] = "`$col`";
}
} }
$columns = implode(",", $columns); $columns = implode(",", $columns);
@ -429,22 +425,32 @@ class MySQL extends SQL {
} }
protected function columnName($col) { protected function columnName($col) {
if ($col instanceof KeyWord) { if ($col instanceof Keyword) {
return $col->getValue(); return $col->getValue();
} else { } else {
return "`$col`"; if (($index = strrpos($col, ".")) !== FALSE) {
$tableName = $this->tableName(substr($col, 0, $index));
$columnName = $this->columnName(substr($col, $index + 1));
return "$tableName.$columnName";
} else if(($index = stripos($col, " as ")) !== FALSE) {
$columnName = $this->columnName(trim(substr($col, 0, $index)));
$alias = trim(substr($col, $index + 4));
return "$columnName as $alias";
} else {
return "`$col`";
}
} }
} }
public function currentTimestamp() { public function currentTimestamp() {
return new KeyWord("NOW()"); return new Keyword("NOW()");
} }
public function count($col = NULL) { public function count($col = NULL) {
if (is_null($col)) { if (is_null($col)) {
return new Keyword("COUNT(*)"); return new Keyword("COUNT(*) AS count");
} else { } else {
return new Keyword("COUNT($col)"); return new Keyword("COUNT($col) AS count");
} }
} }

@ -174,14 +174,8 @@ class PostgreSQL extends SQL {
if (is_null($columns) || empty($columns)) { if (is_null($columns) || empty($columns)) {
$columnStr = ""; $columnStr = "";
$numColumns = count($rows[0]);
} else { } else {
$numColumns = count($columns); $columnStr = " (" . $this->columnName($columns) . ")";
$columnStr = array();
foreach($columns as $col) {
$columnStr[] = $this->columnName($col);
}
$columnStr = " (" . implode(",", $columnStr) . ")";
} }
$numRows = count($rows); $numRows = count($rows);
@ -235,23 +229,14 @@ class PostgreSQL extends SQL {
public function executeSelect($select) { public function executeSelect($select) {
$columns = array(); $columns = $this->columnName($select->getColumns());
foreach($select->getColumns() as $col) {
$columns[] = $this->columnName($col);
}
$columns = implode(",", $columns);
$tables = $select->getTables(); $tables = $select->getTables();
$params = array(); $params = array();
if (is_null($tables) || empty($tables)) { if (is_null($tables) || empty($tables)) {
return "SELECT $columns"; return "SELECT $columns";
} else { } else {
$tableStr = array(); $tableStr = $this->tableName($tables);
foreach($tables as $table) {
$tableStr[] = $this->tableName($table);
}
$tableStr = implode(",", $tableStr);
} }
$conditions = $select->getConditions(); $conditions = $select->getConditions();
@ -346,7 +331,7 @@ class PostgreSQL extends SQL {
} }
protected function getColumnDefinition($column) { protected function getColumnDefinition($column) {
$columnName = $column->getName(); $columnName = $this->columnName($column->getName());
if ($column instanceof StringColumn) { if ($column instanceof StringColumn) {
$maxSize = $column->getMaxSize(); $maxSize = $column->getMaxSize();
@ -378,22 +363,20 @@ class PostgreSQL extends SQL {
$defaultValue = " DEFAULT " . $this->getValueDefinition($column->getDefaultValue()); $defaultValue = " DEFAULT " . $this->getValueDefinition($column->getDefaultValue());
} }
return "\"$columnName\" $type$notNull$defaultValue"; return "$columnName $type$notNull$defaultValue";
} }
protected function getConstraintDefinition($constraint) { protected function getConstraintDefinition($constraint) {
$columnName = $constraint->getColumnName(); $columnName = $this->columnName($constraint->getColumnName());
if ($constraint instanceof PrimaryKey) { if ($constraint instanceof PrimaryKey) {
if (is_array($columnName)) $columnName = implode('","', $columnName); return "PRIMARY KEY ($columnName)";
return "PRIMARY KEY (\"$columnName\")";
} else if ($constraint instanceof Unique) { } else if ($constraint instanceof Unique) {
if (is_array($columnName)) $columnName = implode('","', $columnName); return "UNIQUE ($columnName)";
return "UNIQUE (\"$columnName\")";
} else if ($constraint instanceof ForeignKey) { } else if ($constraint instanceof ForeignKey) {
$refTable = $constraint->getReferencedTable(); $refTable = $this->tableName($constraint->getReferencedTable());
$refColumn = $constraint->getReferencedColumn(); $refColumn = $this->columnName($constraint->getReferencedColumn());
$strategy = $constraint->onDelete(); $strategy = $constraint->onDelete();
$code = "FOREIGN KEY (\"$columnName\") REFERENCES \"$refTable\" (\"$refColumn\")"; $code = "FOREIGN KEY ($columnName) REFERENCES $refTable ($refColumn)";
if ($strategy instanceof SetDefaultStrategy) { if ($strategy instanceof SetDefaultStrategy) {
$code .= " ON DELETE SET DEFAULT"; $code .= " ON DELETE SET DEFAULT";
} else if($strategy instanceof SetNullStrategy) { } else if($strategy instanceof SetNullStrategy) {
@ -431,20 +414,33 @@ class PostgreSQL extends SQL {
} }
protected function tableName($table) { protected function tableName($table) {
return "\"$table\""; if (is_array($table)) {
$tables = array();
foreach($table as $t) $tables[] = $this->tableName($t);
return implode(",", $tables);
} else {
return "\"$table\"";
}
} }
protected function columnName($col) { protected function columnName($col) {
if ($col instanceof KeyWord) { if ($col instanceof KeyWord) {
return $col->getValue(); return $col->getValue();
} elseif(is_array($col)) {
$columns = array();
foreach($col as $c) $columns[] = $this->columnName($c);
return implode(",", $columns);
} else { } else {
$index = strrpos($col, "."); if (($index = strrpos($col, ".")) !== FALSE) {
if ($index === FALSE) {
return "\"$col\"";
} else {
$tableName = $this->tableName(substr($col, 0, $index)); $tableName = $this->tableName(substr($col, 0, $index));
$columnName = $this->columnName(substr($col, $index + 1)); $columnName = $this->columnName(substr($col, $index + 1));
return "$tableName.$columnName"; return "$tableName.$columnName";
} else if(($index = stripos($col, " as ")) !== FALSE) {
$columnName = $this->columnName(trim(substr($col, 0, $index)));
$alias = $this->columnName(trim(substr($col, $index + 4)));
return "$columnName as $alias";
} else {
return "\"$col\"";
} }
} }
} }
@ -456,9 +452,9 @@ class PostgreSQL extends SQL {
public function count($col = NULL) { public function count($col = NULL) {
if (is_null($col)) { if (is_null($col)) {
return new Keyword("COUNT(*)"); return new Keyword("COUNT(*) AS count");
} else { } else {
return new Keyword("COUNT(\"$col\")"); return new Keyword("COUNT(" . $this->columnName($col) . ") AS count");
} }
} }
} }

@ -128,7 +128,6 @@ class User extends ApiObject {
$this->session->stayLoggedIn($row["stay_logged_in"]); $this->session->stayLoggedIn($row["stay_logged_in"]);
if($sessionUpdate) $this->session->update(); if($sessionUpdate) $this->session->update();
$this->loggedIn = true; $this->loggedIn = true;
if(!is_null($row['langId'])) { if(!is_null($row['langId'])) {
$this->setLangauge(Language::newInstance($row['langId'], $row['langCode'], $row['langName'])); $this->setLangauge(Language::newInstance($row['langId'], $row['langCode'], $row['langName']));
} }

@ -1,21 +1,28 @@
import requests
import json
from phpTest import PhpTest from phpTest import PhpTest
class ApiTestCase(PhpTest): class ApiTestCase(PhpTest):
def __init__(self): def __init__(self):
super().__init__("test_api") super().__init__({
self.session = requests.Session() "Testing login…": self.test_login,
"Testing already logged in…": self.test_already_logged_in,
"Testing get api keys empty…": self.test_get_api_keys,
})
def api(self, method): def api(self, method):
return "%s/api/%s" % (self.url, method) return "/api/%s" % method
def test_api(self): def test_login(self):
obj = self.httpPost(self.api("login"), data={ "username": PhpTest.ADMIN_USERNAME, "password": PhpTest.ADMIN_PASSWORD })
res = self.session.post(self.api("login"), data={ "username": PhpTest.ADMIN_USERNAME, "password": PhpTest.ADMIN_PASSWORD })
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
obj = json.loads(res.text)
self.assertEquals(True, obj["success"], obj["msg"]) self.assertEquals(True, obj["success"], obj["msg"])
return obj
def test_already_logged_in(self):
obj = self.test_login()
self.assertEquals("You are already logged in", obj["msg"])
def test_get_api_keys(self):
obj = self.httpPost(self.api("getApiKeys"))
self.assertEquals(True, obj["success"], obj["msg"])
self.assertEquals([], obj["api_keys"])
return obj

@ -1,68 +1,53 @@
import requests
from phpTest import PhpTest from phpTest import PhpTest
import sys
class InstallTestCase(PhpTest): class InstallTestCase(PhpTest):
def __init__(self, args): def __init__(self, args):
super().__init__("test_install") super().__init__({
"Testing connection…": self.test_connection,
"Testing database setup…": self.test_database_setup,
"Testing invalid usernames…": self.test_invalid_usernames,
"Testing invalid password…": self.test_invalid_password,
"Testing not matching password…": self.test_not_matching_passwords,
"Testing user creation…": self.test_create_user,
"Testing skip mail configuration…": self.test_skil_mail_config,
"Testing complete setup…": self.test_complete_setup,
})
self.args = args self.args = args
self.session = requests.Session()
def test_install(self): def test_connection(self):
self.httpGet()
# Test Connection def test_database_setup(self):
res = self.session.get(self.url) obj = self.httpPost(data=vars(self.args))
self.assertEquals(200, res.status_code, self.httpError(res)) self.assertEquals(True, obj["success"], obj["msg"])
self.assertEquals([], self.getPhpErrors(res))
# Database Setup def test_invalid_usernames(self):
res = self.session.post(self.url, data=vars(self.args))
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
# Create User
# 1. Invalid username
for username in ["a", "a"*33]: for username in ["a", "a"*33]:
res = self.session.post(self.url, data={ "username": username, "password": "123456", "confirmPassword": "123456" }) obj = self.httpPost(data={ "username": username, "password": "123456", "confirmPassword": "123456" })
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
obj = self.getJson(res)
self.assertEquals(False, obj["success"]) self.assertEquals(False, obj["success"])
self.assertEquals("The username should be between 5 and 32 characters long", obj["msg"]) self.assertEquals("The username should be between 5 and 32 characters long", obj["msg"])
# 2. Invalid password def test_invalid_password(self):
res = self.session.post(self.url, data={ "username": PhpTest.ADMIN_USERNAME, "password": "1", "confirmPassword": "1" }) obj = self.httpPost(data={ "username": PhpTest.ADMIN_USERNAME, "password": "1", "confirmPassword": "1" })
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
obj = self.getJson(res)
self.assertEquals(False, obj["success"]) self.assertEquals(False, obj["success"])
self.assertEquals("The password should be at least 6 characters long", obj["msg"]) self.assertEquals("The password should be at least 6 characters long", obj["msg"])
# 3. Passwords do not match def test_not_matching_passwords(self):
res = self.session.post(self.url, data={ "username": PhpTest.ADMIN_USERNAME, "password": "1", "confirmPassword": "2" }) obj = self.httpPost(data={ "username": PhpTest.ADMIN_USERNAME, "password": "1", "confirmPassword": "2" })
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
obj = self.getJson(res)
self.assertEquals(False, obj["success"]) self.assertEquals(False, obj["success"])
self.assertEquals("The given passwords do not match", obj["msg"]) self.assertEquals("The given passwords do not match", obj["msg"])
# 4. User creation OK def test_create_user(self):
res = self.session.post(self.url, data={ "username": PhpTest.ADMIN_USERNAME, "password": PhpTest.ADMIN_PASSWORD, "confirmPassword": PhpTest.ADMIN_PASSWORD }) obj = self.httpPost(data={ "username": PhpTest.ADMIN_USERNAME, "password": PhpTest.ADMIN_PASSWORD, "confirmPassword": PhpTest.ADMIN_PASSWORD })
self.assertEquals(200, res.status_code, self.httpError(res)) self.assertEquals(True, obj["success"], obj["msg"])
self.assertEquals([], self.getPhpErrors(res))
obj = self.getJson(res)
self.assertEquals(True, obj["success"])
# Mail: SKIP def test_skil_mail_config(self):
res = self.session.post(self.url, data={ "skip": "true" }) obj = self.httpPost(data={ "skip": "true" })
self.assertEquals(200, res.status_code, self.httpError(res)) self.assertEquals(True, obj["success"], obj["msg"])
self.assertEquals([], self.getPhpErrors(res))
obj = self.getJson(res)
self.assertEquals(True, obj["success"])
# Creation successful: def test_complete_setup(self):
res = self.session.get(self.url) res = self.httpGet()
self.assertEquals(200, res.status_code, self.httpError(res)) self.assertTrue("Installation finished" in res.text)
self.assertEquals([], self.getPhpErrors(res))

@ -1,8 +1,10 @@
import unittest import unittest
import string import string
import random import random
import requests
import re import re
import json import json
import sys
class PhpTest(unittest.TestCase): class PhpTest(unittest.TestCase):
@ -13,11 +15,13 @@ class PhpTest(unittest.TestCase):
ADMIN_USERNAME = "Administrator" ADMIN_USERNAME = "Administrator"
ADMIN_PASSWORD = randomString(16) ADMIN_PASSWORD = randomString(16)
def __init__(self, test_method): def __init__(self, methods):
super().__init__(test_method) super().__init__("test_methods")
keywords = ["Fatal error", "Warning", "Notice", "Parse error", "Deprecated"] keywords = ["Fatal error", "Warning", "Notice", "Parse error", "Deprecated"]
self.methods = methods
self.phpPattern = re.compile("<b>(%s)</b>:" % ("|".join(keywords))) self.phpPattern = re.compile("<b>(%s)</b>:" % ("|".join(keywords)))
self.url = "http://localhost/" self.url = "http://localhost"
self.session = requests.Session()
def httpError(self, res): def httpError(self, res):
return "Server returned: %d %s" % (res.status_code, res.reason) return "Server returned: %d %s" % (res.status_code, res.reason)
@ -25,6 +29,21 @@ class PhpTest(unittest.TestCase):
def getPhpErrors(self, res): def getPhpErrors(self, res):
return [line for line in res.text.split("\n") if self.phpPattern.search(line)] return [line for line in res.text.split("\n") if self.phpPattern.search(line)]
def httpGet(self, target="/"):
url = self.url + target
res = self.session.get(url)
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
return res
def httpPost(self, target="/", data={}):
url = self.url + target
res = self.session.post(url, data=data)
self.assertEquals(200, res.status_code, self.httpError(res))
self.assertEquals([], self.getPhpErrors(res))
obj = self.getJson(res)
return obj
def getJson(self, res): def getJson(self, res):
obj = None obj = None
try: try:
@ -34,3 +53,15 @@ class PhpTest(unittest.TestCase):
finally: finally:
self.assertTrue(isinstance(obj, dict), res.text) self.assertTrue(isinstance(obj, dict), res.text)
return obj return obj
def test_methods(self):
print()
print("Running Tests in %s" % self.__class__.__name__)
for msg, method in self.methods.items():
self.test_method(msg, method)
def test_method(self, msg, method):
sys.stdout.write("[ ] %s" % msg)
method()
sys.stdout.write("\r[+] %s\n" % msg)
sys.stdout.flush()

@ -44,7 +44,6 @@ def testMysql(args):
cursor = connection.cursor() cursor = connection.cursor()
print("[ ] Creating temporary databse %s" % args.database) print("[ ] Creating temporary databse %s" % args.database)
cursor.execute("CREATE DATABASE %s" % args.database) cursor.execute("CREATE DATABASE %s" % args.database)
cursor.commit()
print("[+] Success") print("[+] Success")
# perform test # perform test