1
1
Fork 0
mirror of https://code.mensbeam.com/MensBeam/Arsse.git synced 2024-12-23 06:44:57 +00:00
This commit is contained in:
J. King 2017-09-28 09:01:43 -04:00
parent 5ebf6cb689
commit 96ebf936e4
9 changed files with 27 additions and 21 deletions

View file

@ -322,7 +322,7 @@ class Database {
protected function folderValidateId(string $user, $id = null, bool $subject = false): array { protected function folderValidateId(string $user, $id = null, bool $subject = false): array {
// if the specified ID is not a non-negative integer (or null), this will always fail // if the specified ID is not a non-negative integer (or null), this will always fail
if(!ValueInfo::id($id, true)) { if (!ValueInfo::id($id, true)) {
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "folder", 'type' => "int >= 0"]); throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "folder", 'type' => "int >= 0"]);
} }
// if a null or zero ID is specified this is a no-op // if a null or zero ID is specified this is a no-op
@ -358,7 +358,9 @@ class Database {
if ($id==$parent) { if ($id==$parent) {
throw new Db\ExceptionInput("circularDependence", $errData); throw new Db\ExceptionInput("circularDependence", $errData);
} }
// make sure both that the prospective parent exists, and that the it is not one of its children (a circular dependence) // make sure both that the prospective parent exists, and that the it is not one of its children (a circular dependence);
// also make sure that a folder with the same prospective name and parent does not already exist: if the parent is null,
// SQL will happily accept duplicates (null is not unique), so we must do this check ourselves
$p = $this->db->prepare( $p = $this->db->prepare(
"WITH RECURSIVE "WITH RECURSIVE
target as (select ? as user, ? as source, ? as dest, ? as rename), target as (select ? as user, ? as source, ? as dest, ? as rename),
@ -368,7 +370,7 @@ class Database {
((select dest from target) is null or exists(select id from arsse_folders join target on owner is user and id is dest)) as extant, ((select dest from target) is null or exists(select id from arsse_folders join target on owner is user and id is dest)) as extant,
not exists(select id from folders where id is (select dest from target)) as valid, not exists(select id from folders where id is (select dest from target)) as valid,
not exists(select id from arsse_folders join target on parent is dest and name is coalesce((select rename from target),(select name from arsse_folders join target on id is source))) as available not exists(select id from arsse_folders join target on parent is dest and name is coalesce((select rename from target),(select name from arsse_folders join target on id is source))) as available
", "str", "int", "int","str" ", "str", "int", "int", "str"
)->run($user, $id, $parent, $name)->getRow(); )->run($user, $id, $parent, $name)->getRow();
if (!$p['extant']) { if (!$p['extant']) {
// if the parent doesn't exist or doesn't below to the user, throw an exception // if the parent doesn't exist or doesn't below to the user, throw an exception
@ -377,6 +379,7 @@ class Database {
// if using the desired parent would create a circular dependence, throw a different exception // if using the desired parent would create a circular dependence, throw a different exception
throw new Db\ExceptionInput("circularDependence", $errData); throw new Db\ExceptionInput("circularDependence", $errData);
} elseif (!$p['available']) { } elseif (!$p['available']) {
// if a folder with the same parent and name already exists, throw another different exception
throw new Db\ExceptionInput("constraintViolation", ["action" => $this->caller(), "field" => (is_null($name) ? "parent" : "name")]); throw new Db\ExceptionInput("constraintViolation", ["action" => $this->caller(), "field" => (is_null($name) ? "parent" : "name")]);
} }
return $parent; return $parent;
@ -390,7 +393,10 @@ class Database {
throw new Db\ExceptionInput("whitespace", ["action" => $this->caller(), "field" => "name"]); throw new Db\ExceptionInput("whitespace", ["action" => $this->caller(), "field" => "name"]);
} elseif (!($info & ValueInfo::VALID)) { } elseif (!($info & ValueInfo::VALID)) {
throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "name", 'type' => "string"]); throw new Db\ExceptionInput("typeViolation", ["action" => $this->caller(), "field" => "name", 'type' => "string"]);
} elseif($checkDuplicates) { } elseif ($checkDuplicates) {
// make sure that a folder with the same prospective name and parent does not already exist: if the parent is null,
// SQL will happily accept duplicates (null is not unique), so we must do this check ourselves
$parent = $parent ? $parent : null;
if ($this->db->prepare("SELECT exists(select id from arsse_folders where parent is ? and name is ?)", "int", "str")->run($parent, $name)->getValue()) { if ($this->db->prepare("SELECT exists(select id from arsse_folders where parent is ? and name is ?)", "int", "str")->run($parent, $name)->getValue()) {
throw new Db\ExceptionInput("constraintViolation", ["action" => $this->caller(), "field" => "name"]); throw new Db\ExceptionInput("constraintViolation", ["action" => $this->caller(), "field" => "name"]);
} }

View file

@ -20,7 +20,7 @@ class Driver extends \JKingWeb\Arsse\Db\AbstractDriver {
// check to make sure required extension is loaded // check to make sure required extension is loaded
if (!class_exists("SQLite3")) { if (!class_exists("SQLite3")) {
throw new Exception("extMissing", self::driverName()); // @codeCoverageIgnore throw new Exception("extMissing", self::driverName()); // @codeCoverageIgnore
} }
// if no database file is specified in the configuration, use a suitable default // if no database file is specified in the configuration, use a suitable default
$dbFile = Arsse::$conf->dbSQLite3File ?? \JKingWeb\Arsse\BASE."arsse.db"; $dbFile = Arsse::$conf->dbSQLite3File ?? \JKingWeb\Arsse\BASE."arsse.db";
$mode = \SQLITE3_OPEN_READWRITE | \SQLITE3_OPEN_CREATE; $mode = \SQLITE3_OPEN_READWRITE | \SQLITE3_OPEN_CREATE;

View file

@ -37,7 +37,7 @@ class Context {
protected function cleanArray(array $spec): array { protected function cleanArray(array $spec): array {
$spec = array_values($spec); $spec = array_values($spec);
for ($a = 0; $a < sizeof($spec); $a++) { for ($a = 0; $a < sizeof($spec); $a++) {
if(ValueInfo::id($spec[$a])) { if (ValueInfo::id($spec[$a])) {
$spec[$a] = (int) $spec[$a]; $spec[$a] = (int) $spec[$a];
} else { } else {
$spec[$a] = 0; $spec[$a] = 0;

View file

@ -13,7 +13,7 @@ class ValueInfo {
const EMPTY = 1 << 2; const EMPTY = 1 << 2;
const WHITE = 1 << 3; const WHITE = 1 << 3;
static public function int($value): int { public static function int($value): int {
$out = 0; $out = 0;
if (is_null($value)) { if (is_null($value)) {
// check if the input is null // check if the input is null
@ -40,7 +40,7 @@ class ValueInfo {
// mark validity // mark validity
$out += self::VALID; $out += self::VALID;
// mark zeroness // mark zeroness
if($value==0) { if ($value==0) {
$out += self::ZERO; $out += self::ZERO;
} }
// mark negativeness // mark negativeness
@ -50,7 +50,7 @@ class ValueInfo {
return $out; return $out;
} }
static public function str($value): int { public static function str($value): int {
$out = 0; $out = 0;
// check if the input is null // check if the input is null
if (is_null($value)) { if (is_null($value)) {
@ -75,7 +75,7 @@ class ValueInfo {
return $out; return $out;
} }
static public function id($value, bool $allowNull = false): bool { public static function id($value, bool $allowNull = false): bool {
$info = self::int($value); $info = self::int($value);
if ($allowNull && ($info & self::NULL)) { // null (and allowed) if ($allowNull && ($info & self::NULL)) { // null (and allowed)
return true; return true;

View file

@ -50,7 +50,7 @@ abstract class AbstractHandler implements Handler {
} }
break; break;
case "string": case "string":
if(is_bool($value)) { if (is_bool($value)) {
$out[$key] = var_export($value, true); $out[$key] = var_export($value, true);
} elseif (!is_scalar($value)) { } elseif (!is_scalar($value)) {
break; break;

View file

@ -79,7 +79,7 @@ class V1_2 extends \JKingWeb\Arsse\REST\AbstractHandler {
// dispatch // dispatch
try { try {
return $this->$func($req->paths, $data); return $this->$func($req->paths, $data);
// @codeCoverageIgnoreStart // @codeCoverageIgnoreStart
} catch (Exception $e) { } catch (Exception $e) {
// if there was a REST exception return 400 // if there was a REST exception return 400
return new Response(400); return new Response(400);

View file

@ -197,7 +197,7 @@ class TestValueInfo extends Test\AbstractTest {
]; ];
foreach ($tests as $test) { foreach ($tests as $test) {
list($value, $exp, $expNull) = $test; list($value, $exp, $expNull) = $test;
$this->assertSame($exp, I::id($value), "Non-null test failed for value: ".var_export($value, true)); $this->assertSame($exp, I::id($value), "Non-null test failed for value: ".var_export($value, true));
$this->assertSame($expNull, I::id($value, true), "Null test failed for value: ".var_export($value, true)); $this->assertSame($expNull, I::id($value, true), "Null test failed for value: ".var_export($value, true));
} }
} }

View file

@ -500,14 +500,14 @@ class TestNCNV1_2 extends Test\AbstractTest {
Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.com/news.atom")->thenReturn(2112)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.com/news.atom")->thenReturn(2112)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.org/news.atom")->thenReturn(42)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.org/news.atom")->thenReturn(42)->thenThrow(new ExceptionInput("constraintViolation")); // error on the second call
Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 2112)->thenReturn($this->feeds['db'][0]); Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 2112)->thenReturn($this->feeds['db'][0]);
Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 42)->thenReturn($this->feeds['db'][1]); Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 42)->thenReturn($this->feeds['db'][1]);
Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 47)->thenReturn($this->feeds['db'][2]); Phake::when(Arsse::$db)->subscriptionPropertiesGet(Arsse::$user->id, 47)->thenReturn($this->feeds['db'][2]);
Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(2112))->thenReturn(0); Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(2112))->thenReturn(0);
Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(42))->thenReturn(4758915); Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(42))->thenReturn(4758915);
Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(47))->thenReturn(2112); Phake::when(Arsse::$db)->editionLatest(Arsse::$user->id, (new Context)->subscription(47))->thenReturn(2112);
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 2112, ['folder' => 3])->thenThrow(new ExceptionInput("idMissing")); // folder ID 3 does not exist Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 2112, ['folder' => 3])->thenThrow(new ExceptionInput("idMissing")); // folder ID 3 does not exist
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, ['folder' => 8])->thenReturn(true); Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 42, ['folder' => 8])->thenReturn(true);
Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 47, ['folder' => -1])->thenThrow(new ExceptionInput("typeViolation")); // folder ID -1 is invalid Phake::when(Arsse::$db)->subscriptionPropertiesSet(Arsse::$user->id, 47, ['folder' => -1])->thenThrow(new ExceptionInput("typeViolation")); // folder ID -1 is invalid
// set up a mock for a bad feed which succeeds the second time // set up a mock for a bad feed which succeeds the second time
Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException()))->thenReturn(47); Phake::when(Arsse::$db)->subscriptionAdd(Arsse::$user->id, "http://example.net/news.atom")->thenThrow(new \JKingWeb\Arsse\Feed\Exception("http://example.net/news.atom", new \PicoFeed\Client\InvalidUrlException()))->thenReturn(47);
// add the subscriptions // add the subscriptions