Skip to content

Commit

Permalink
use proper types in API (fossar#879)
Browse files Browse the repository at this point in the history
  • Loading branch information
niol authored and jtojnar committed Apr 23, 2018
1 parent 43da7f6 commit 42d12bd
Show file tree
Hide file tree
Showing 14 changed files with 89 additions and 33 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
### Bug fixes
- Reddit spout allows wider range of URLs, including absolute URLs and searches ([#1033](https://github.com/SSilence/selfoss/pull/1033))

### API changes
- `tags` attribute is now consistently array of strings, numbers are numbers and booleans are booleans.

### Other changes
- Removed broken instapaper scraping from Reddit spout ([#1033](https://github.com/SSilence/selfoss/pull/1033))

Expand Down
3 changes: 1 addition & 2 deletions controllers/Index.php
Original file line number Diff line number Diff line change
Expand Up @@ -217,8 +217,7 @@ private function loadItems($options, $tags) {
$tagsController = new \controllers\Tags();
foreach ($itemDao->get($options) as $item) {
// parse tags and assign tag colors
$itemTags = explode(',', $item['tags']);
$item['tags'] = $tagsController->tagsAddColors($itemTags, $tags);
$item['tags'] = $tagsController->tagsAddColors($item['tags'], $tags);

$this->view->item = $item;
$itemsHtml .= $this->view->render('templates/item.phtml');
Expand Down
4 changes: 2 additions & 2 deletions controllers/Sources.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ public function write() {

// clean up title and tag data to prevent XSS
$title = htmlspecialchars($data['title']);
$tags = htmlspecialchars($data['tags']);
$tags = htmlspecialchars(implode(',', $data['tags']));
$spout = $data['spout'];
$filter = $data['filter'];
$isAjax = isset($data['ajax']);
Expand Down Expand Up @@ -209,7 +209,7 @@ public function write() {

$return = [
'success' => true,
'id' => $id,
'id' => (int) $id,
'title' => $title
];

Expand Down
4 changes: 4 additions & 0 deletions daos/Database.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

namespace daos;

const PARAM_INT = 1;
const PARAM_BOOL = 2;
const PARAM_CSV = 3;

/**
* Base class for database access
*
Expand Down
6 changes: 2 additions & 4 deletions daos/Items.php
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,7 @@ public function get($options = []) {
// remove private posts with private tags
if (!\F3::get('auth')->showPrivateTags()) {
foreach ($items as $idx => $item) {
$tags = explode(',', $item['tags']);
foreach ($tags as $tag) {
foreach ($item['tags'] as $tag) {
if (strpos(trim($tag), '@') === 0) {
unset($items[$idx]);
break;
Expand All @@ -94,8 +93,7 @@ public function get($options = []) {
// remove posts with hidden tags
if (!isset($options['tag']) || strlen($options['tag']) === 0) {
foreach ($items as $idx => $item) {
$tags = explode(',', $item['tags']);
foreach ($tags as $tag) {
foreach ($item['tags'] as $tag) {
if (strpos(trim($tag), '#') === 0) {
unset($items[$idx]);
break;
Expand Down
3 changes: 1 addition & 2 deletions daos/Sources.php
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,7 @@ public function get($id = null) {
// remove items with private tags
if (!\F3::get('auth')->showPrivateTags()) {
foreach ($sources as $idx => $source) {
$tags = explode(',', $source['tags']);
foreach ($tags as $tag) {
foreach ($source['tags'] as $tag) {
if (strpos(trim($tag), '@') === 0) {
unset($sources[$idx]);
break;
Expand Down
20 changes: 13 additions & 7 deletions daos/mysql/Items.php
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,13 @@ public function get($options = []) {
$query = "$select $where_sql $order_sql LIMIT " . $options['items'] . ' OFFSET ' . $options['offset'];
}

return \F3::get('db')->exec($query, $params);
return $this->stmt->ensureRowTypes(\F3::get('db')->exec($query, $params), [
'id' => \daos\PARAM_INT,
'unread' => \daos\PARAM_BOOL,
'starred' => \daos\PARAM_BOOL,
'source' => \daos\PARAM_INT,
'tags' => \daos\PARAM_CSV
]);
}

/**
Expand Down Expand Up @@ -503,9 +509,9 @@ public function stats() {
' . $this->stmt->sumBool('starred') . ' AS starred
FROM ' . \F3::get('db_prefix') . 'items;');
$res = $this->stmt->ensureRowTypes($res, [
'total' => \PDO::PARAM_INT,
'unread' => \PDO::PARAM_INT,
'starred' => \PDO::PARAM_INT
'total' => \daos\PARAM_INT,
'unread' => \daos\PARAM_INT,
'starred' => \daos\PARAM_INT
]);

return $res[0];
Expand Down Expand Up @@ -537,9 +543,9 @@ public function statuses($since) {
WHERE ' . \F3::get('db_prefix') . 'items.updatetime > :since;',
[':since' => [$since, \PDO::PARAM_STR]]);
$res = $this->stmt->ensureRowTypes($res, [
'id' => \PDO::PARAM_INT,
'unread' => \PDO::PARAM_BOOL,
'starred' => \PDO::PARAM_BOOL
'id' => \daos\PARAM_INT,
'unread' => \daos\PARAM_BOOL,
'starred' => \daos\PARAM_BOOL
]);

return $res;
Expand Down
17 changes: 15 additions & 2 deletions daos/mysql/Sources.php
Original file line number Diff line number Diff line change
Expand Up @@ -144,13 +144,18 @@ public function get($id = null) {
// select source by id if specified or return all sources
if (isset($id)) {
$ret = \F3::get('db')->exec('SELECT id, title, tags, spout, params, filter, error FROM ' . \F3::get('db_prefix') . 'sources WHERE id=:id', [':id' => $id]);
$ret = $this->stmt->ensureRowTypes($ret, ['id' => \daos\PARAM_INT]);
if (isset($ret[0])) {
$ret = $ret[0];
} else {
$ret = false;
}
} else {
$ret = \F3::get('db')->exec('SELECT id, title, tags, spout, params, filter, error FROM ' . \F3::get('db_prefix') . 'sources ORDER BY error DESC, lower(title) ASC');
$ret = $this->stmt->ensureRowTypes($ret, [
'id' => \daos\PARAM_INT,
'tags' => \daos\PARAM_CSV
]);
}

return $ret;
Expand All @@ -162,13 +167,18 @@ public function get($id = null) {
* @return mixed all sources
*/
public function getWithUnread() {
return \F3::get('db')->exec('SELECT
$ret = \F3::get('db')->exec('SELECT
sources.id, sources.title, COUNT(items.id) AS unread
FROM ' . \F3::get('db_prefix') . 'sources AS sources
LEFT OUTER JOIN ' . \F3::get('db_prefix') . 'items AS items
ON (items.source=sources.id AND ' . $this->stmt->isTrue('items.unread') . ')
GROUP BY sources.id, sources.title
ORDER BY lower(sources.title) ASC');

return $this->stmt->ensureRowTypes($ret, [
'id' => \daos\PARAM_INT,
'unread' => \daos\PARAM_INT
]);
}

/**
Expand All @@ -194,7 +204,10 @@ public function getWithIcon() {
ON sources.id=sourceicons.source
ORDER BY ' . $this->stmt->nullFirst('sources.error', 'DESC') . ', lower(sources.title)');

return $ret;
return $this->stmt->ensureRowTypes($ret, [
'id' => \daos\PARAM_INT,
'tags' => \daos\PARAM_CSV
]);
}

/**
Expand Down
17 changes: 12 additions & 5 deletions daos/mysql/Statements.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function insert($query, array $params) {
\F3::get('db')->exec($query, $params);
$res = \F3::get('db')->exec('SELECT LAST_INSERT_ID() as lastid');

return $res[0]['lastid'];
return (int) $res[0]['lastid'];
}

/**
Expand Down Expand Up @@ -152,18 +152,25 @@ public function ensureRowTypes(array $rows, array $expectedRowTypes) {
foreach ($expectedRowTypes as $columnIndex => $type) {
if (array_key_exists($columnIndex, $row)) {
switch ($type) {
case \PDO::PARAM_INT:
$value = intval($row[$columnIndex]);
case \daos\PARAM_INT:
$value = (int) $row[$columnIndex];
break;
case \PDO::PARAM_BOOL:
case \daos\PARAM_BOOL:
if ($row[$columnIndex] == '1') {
$value = true;
} else {
$value = false;
}
break;
case \daos\PARAM_CSV:
$value = explode(',', $row[$columnIndex]);
break;
default:
$value = null;
}
if ($value !== null) {
$rows[$rowIndex][$columnIndex] = $value;
}
$rows[$rowIndex][$columnIndex] = $value;
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion daos/mysql/Tags.php
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ public function getWithUnread() {
GROUP BY tags.tag, tags.color
ORDER BY LOWER(tags.tag);';

return \F3::get('db')->exec($select);
return $this->stmt->ensureRowTypes(\F3::get('db')->exec($select), ['unread' => \daos\PARAM_INT]);
}

/**
Expand Down
20 changes: 19 additions & 1 deletion daos/pgsql/Statements.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,24 @@ public static function csvRowMatches($column, $value) {
* expected types
*/
public function ensureRowTypes(array $rows, array $expectedRowTypes) {
return $rows; // pgsql returns correct PHP types
foreach ($rows as $rowIndex => $row) {
foreach ($expectedRowTypes as $columnIndex => $type) {
if (array_key_exists($columnIndex, $row)) {
switch ($type) {
// pgsql returns correct PHP types for INT and BOOL
case \daos\PARAM_CSV:
$value = explode(',', $row[$columnIndex]);
break;
default:
$value = null;
}
if ($value !== null) {
$rows[$rowIndex][$columnIndex] = $value;
}
}
}
}

return $rows;
}
}
2 changes: 1 addition & 1 deletion daos/sqlite/Statements.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function insert($query, array $params) {
\F3::get('db')->exec($query, $params);
$res = \F3::get('db')->exec('SELECT last_insert_rowid() as lastid');

return $res[0]['lastid'];
return (int) $res[0]['lastid'];
}

/**
Expand Down
19 changes: 14 additions & 5 deletions docs/api-description.json
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,7 @@
{
"id": "2",
"title": "devart",
"tags": "da",
"tags": ["da"],
"spout": "spouts\\deviantart\\dailydeviations",
"params": [],
"error": "",
Expand All @@ -471,7 +471,7 @@
{
"id": "1",
"title": "Tobis Blog",
"tags": "blog",
"tags": ["blog"],
"spout": "spouts\\rss\\feed",
"params": {
"url": "http://blog.aditu.de/feed"
Expand Down Expand Up @@ -925,7 +925,10 @@
},
"tags": {
"description": "all tags of the source of this article",
"type": "string"
"type": "array",
"items": {
"type": "string"
}
}
}
},
Expand All @@ -942,7 +945,10 @@
},
"tags": {
"description": "user given tags",
"type": "string"
"type": "array",
"items": {
"type": "string"
}
},
"spout": {
"description": "the spout type. You can also get all available spout types by using the json api",
Expand Down Expand Up @@ -980,7 +986,10 @@
},
"tags": {
"description": "tags for this source",
"type": "string"
"type": "array",
"items": {
"type": "string"
}
},
"username": {
"description": "Username in “deviantART - user”, “deviantART - favs of a user”, Tumblr, Reddit anf “Twitter - User timeline” spouts",
Expand Down
2 changes: 1 addition & 1 deletion templates/source.phtml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@

<!-- tags -->
<li><label for="tags-<?= $idAttr ?>"><?= \F3::get('lang_source_tags'); ?></label>
<input id="tags-<?= $idAttr ?>" type="text" name="tags" value="<?= isset($this->source) ? $this->source['tags'] : ''; ?>" /> <span class="source-edit-form-help"> <?= \F3::get('lang_source_comma')?></span>
<input id="tags-<?= $idAttr ?>" type="text" name="tags" value="<?= isset($this->source) ? implode(',', $this->source['tags']) : ''; ?>" /> <span class="source-edit-form-help"> <?= \F3::get('lang_source_comma')?></span>
</li>

<!-- filter -->
Expand Down

0 comments on commit 42d12bd

Please sign in to comment.