Merge pull request #1 from shish/develop

MERGE ALL THE THINGS
This commit is contained in:
Daniel Løvbrøtte Olsen 2015-12-17 11:26:51 +01:00
commit de87bdbb0d
115 changed files with 2789 additions and 2063 deletions

2
.gitignore vendored
View File

@ -3,6 +3,8 @@ data
images
thumbs
!lib/images
*.phar
*.sqlite
# Created by http://www.gitignore.io

View File

@ -3,7 +3,12 @@
</IfModule>
<FilesMatch "\.(sqlite|sdb|s3db|db)$">
Deny from all
<IfModule mod_authz_host.c>
Require all denied
</IfModule>
<IfModule !mod_authz_host.c>
Deny from all
</IfModule>
</FilesMatch>
<IfModule mod_rewrite.c>

View File

@ -1,6 +1,9 @@
imports:
- javascript
- php
- javascript
- php
filter:
excluded_paths: [lib/*,ext/tagger/script.js,ext/chatbox/*]
excluded_paths: [lib/*,ext/tagger/script.js,ext/chatbox/*]
tools:
external_code_coverage: true

View File

@ -2,47 +2,42 @@ language: php
sudo: false
php:
# Here is where we can list the versions of PHP you want to test against
# using major version aliases
- 5.4
- 5.5
- 5.6
- nightly
- 5.4
- 5.5
- 5.6
- nightly
# optionally specify a list of environments, for example to test different RDBMS
env:
matrix:
- DB=mysql
- DB=pgsql
- DB=sqlite
install:
# Enable logging of all queries (for debugging) and create the database schema for shimmie.
- mkdir -p data/config
- if [[ "$DB" == "pgsql" ]]; then psql -c "SELECT set_config('log_statement', 'all', false);" -U postgres; fi
- if [[ "$DB" == "pgsql" ]]; then psql -c "CREATE DATABASE shimmie;" -U postgres; fi
- if [[ "$DB" == "pgsql" ]]; then echo '<?php define("DATABASE_DSN", "pgsql:user=postgres;password=;host=;dbname=shimmie");' > data/config/auto_install.conf.php ; fi
- if [[ "$DB" == "mysql" ]]; then mysql -e "SET GLOBAL general_log = 'ON';" -uroot; fi
- if [[ "$DB" == "mysql" ]]; then mysql -e "CREATE DATABASE shimmie;" -uroot; fi
- if [[ "$DB" == "mysql" ]]; then echo '<?php define("DATABASE_DSN", "mysql:user=root;password=;host=localhost;dbname=shimmie");' > data/config/auto_install.conf.php ; fi
- if [[ "$DB" == "sqlite" ]]; then echo '<?php define("DATABASE_DSN", "sqlite:shimmie.sqlite");' > data/config/auto_install.conf.php ; fi
- mkdir -p data/config
- if [[ "$DB" == "pgsql" ]]; then psql -c "SELECT set_config('log_statement', 'all', false);" -U postgres; fi
- if [[ "$DB" == "pgsql" ]]; then psql -c "CREATE DATABASE shimmie;" -U postgres; fi
- if [[ "$DB" == "pgsql" ]]; then echo '<?php define("DATABASE_DSN", "pgsql:user=postgres;password=;host=;dbname=shimmie");' > data/config/auto_install.conf.php ; fi
- if [[ "$DB" == "mysql" ]]; then mysql -e "SET GLOBAL general_log = 'ON';" -uroot; fi
- if [[ "$DB" == "mysql" ]]; then mysql -e "CREATE DATABASE shimmie;" -uroot; fi
- if [[ "$DB" == "mysql" ]]; then echo '<?php define("DATABASE_DSN", "mysql:user=root;password=;host=localhost;dbname=shimmie");' > data/config/auto_install.conf.php ; fi
- if [[ "$DB" == "sqlite" ]]; then echo '<?php define("DATABASE_DSN", "sqlite:shimmie.sqlite");' > data/config/auto_install.conf.php ; fi
- wget https://scrutinizer-ci.com/ocular.phar
script:
- php install.php
- phpunit --configuration tests/phpunit.xml
- php install.php
- phpunit --configuration tests/phpunit.xml --coverage-clover=data/coverage.clover
# If a failure occured then dump out a bunch of logs for debugging purposes.
after_failure:
- head -n 100 data/config/*
- ls /var/run/mysql*
- ls /var/log/*mysql*
- cat /var/log/mysql.err
- cat /var/log/mysql.log
- cat /var/log/mysql/error.log
- cat /var/log/mysql/slow.log
- ls /var/log/postgresql
- cat /var/log/postgresql/postgresql*
- head -n 100 data/config/*
- ls /var/run/mysql*
- ls /var/log/*mysql*
- cat /var/log/mysql.err
- cat /var/log/mysql.log
- cat /var/log/mysql/error.log
- cat /var/log/mysql/slow.log
- ls /var/log/postgresql
- cat /var/log/postgresql/postgresql*
# configure notifications (email, IRC, campfire etc)
#notifications:
# irc: "irc.freenode.org#shimmie"
#
after_script:
- php ocular.phar code-coverage:upload --format=php-clover data/coverage.clover

View File

@ -96,7 +96,7 @@ class BaseThemelet {
*
* @param string $base_url
* @param string $query
* @param int|string $page
* @param string $page
* @param string $name
* @return string
*/
@ -108,8 +108,8 @@ class BaseThemelet {
/**
* @param string $base_url
* @param string $query
* @param int|string $page
* @param int|string $current_page
* @param string $page
* @param int $current_page
* @param string $name
* @return string
*/

View File

@ -20,7 +20,7 @@ class Block {
*/
public $body;
/**
/**
* Where the block should be placed. The default theme supports
* "main" and "left", other themes can add their own areas.
*
@ -58,7 +58,7 @@ class Block {
$this->body = $body;
$this->section = $section;
$this->position = $position;
$this->id = str_replace(' ', '_', is_null($id) ? (is_null($header) ? md5($body) : $header) . $section : $id);
$this->id = preg_replace('/[^\w]/', '',str_replace(' ', '_', is_null($id) ? (is_null($header) ? md5($body) : $header) . $section : $id));
}
/**
@ -94,4 +94,3 @@ class NavBlock extends Block {
parent::__construct("Navigation", "<a href='".make_link()."'>Index</a>", "left", 0);
}
}

View File

@ -639,7 +639,7 @@ class Database {
*
* @param string $query
* @param array $args
* @return mixed|null
* @return array|null
*/
public function get_row($query, $args=array()) {
$_start = microtime(true);
@ -702,7 +702,7 @@ class Database {
* Get the ID of the last inserted row.
*
* @param string|null $seq
* @return string
* @return int
*/
public function get_last_insert_id($seq) {
if($this->engine->name == "pgsql") {

View File

@ -282,7 +282,7 @@ abstract class DataHandlerExtension extends Extension {
abstract protected function supported_ext($ext);
/**
* @param $tmpname
* @param string $tmpname
* @return bool
*/
abstract protected function check_contents($tmpname);

View File

@ -63,7 +63,7 @@ class Image {
public $tag_array;
public $owner_id, $owner_ip;
public $posted, $posted_timestamp;
public $posted;
public $source;
public $locked;
@ -82,7 +82,6 @@ class Image {
$name = str_replace("images.", "", $name);
$this->$name = $value; // hax, this is likely the cause of much scrutinizer-ci complaints.
}
$this->posted_timestamp = strtotime($this->posted); // pray
$this->locked = bool_escape($this->locked);
assert(is_numeric($this->id));
@ -192,6 +191,13 @@ class Image {
return ($yays > 1 || $nays > 0);
}
/**
* @param string[] $tags
* @param int $offset
* @param int $limit
* @return null|PDOStatement
* @throws SCoreException
*/
public function get_accelerated_result($tags, $offset, $limit) {
global $database;
@ -244,7 +250,7 @@ class Image {
* Count the number of image results for a given search
*
* @param string[] $tags
* @return mixed
* @return int
*/
public static function count_images($tags=array()) {
assert('is_array($tags)');
@ -284,7 +290,6 @@ class Image {
return ceil(Image::count_images($tags) / $config->get_int('index_images'));
}
/*
* Accessors & mutators
*/
@ -401,9 +406,9 @@ class Image {
/**
* Check configured template for a link, then try nice URL, then plain URL
*
* @param $template
* @param $nice
* @param $plain
* @param string $template
* @param string $nice
* @param string $plain
* @return string
*/
private function get_link($template, $nice, $plain) {
@ -532,6 +537,10 @@ class Image {
return $this->locked;
}
/**
* @param bool $tf
* @throws SCoreException
*/
public function set_locked($tf) {
global $database;
$ln = $tf ? "Y" : "N";
@ -551,9 +560,22 @@ class Image {
*/
public function delete_tags_from_image() {
global $database;
$database->execute(
"UPDATE tags SET count = count - 1 WHERE id IN ".
"(SELECT tag_id FROM image_tags WHERE image_id = :id)", array("id"=>$this->id));
if($database->get_driver_name() == "mysql") {
//mysql < 5.6 has terrible subquery optimization, using EXISTS / JOIN fixes this
$database->execute("
UPDATE tags t
INNER JOIN image_tags it ON t.id = it.tag_id
SET count = count - 1
WHERE it.image_id = :id",
array("id"=>$this->id)
);
} else {
$database->execute("
UPDATE tags
SET count = count - 1
WHERE id IN (SELECT tag_id FROM image_tags WHERE image_id = :id)", array("id"=>$this->id)
);
}
$database->execute("DELETE FROM image_tags WHERE image_id=:id", array("id"=>$this->id));
}
@ -567,9 +589,6 @@ class Image {
assert('is_array($tags) && count($tags) > 0', var_export($tags, true));
global $database;
$tags = array_map(array('Tag', 'sanitise'), $tags);
$tags = Tag::resolve_aliases($tags);
if(count($tags) <= 0) {
throw new SCoreException('Tried to set zero tags');
}
@ -579,12 +598,6 @@ class Image {
$this->delete_tags_from_image();
// insert each new tags
foreach($tags as $tag) {
$ttpe = new TagTermParseEvent($tag, $this->id);
send_event($ttpe);
if($ttpe->is_metatag()) {
continue;
}
if(mb_strlen($tag, 'UTF-8') > 255){
flash_message("The tag below is longer than 255 characters, please use a shorter tag.\n$tag\n");
continue;
@ -623,6 +636,19 @@ class Image {
}
}
/**
* Send list of metatags to be parsed.
*
* @param [] $metatags
* @param int $image_id
*/
public function parse_metatags($metatags, $image_id) {
foreach($metatags as $tag) {
$ttpe = new TagTermParseEvent($tag, $image_id, TRUE);
send_event($ttpe);
}
}
/**
* Delete this image from the database and disk
*/
@ -736,9 +762,58 @@ class Image {
return Image::build_accurate_search_querylet($terms);
}
/**
* @param string[] $terms
* @return ImgQuerylet[]
*/
private static function parse_meta_terms($terms) {
$img_querylets = array();
$stpe = new SearchTermParseEvent(null, $terms);
send_event($stpe);
if ($stpe->is_querylet_set()) {
foreach ($stpe->get_querylets() as $querylet) {
$img_querylets[] = new ImgQuerylet($querylet, true);
}
}
return $img_querylets;
}
/**
* @param ImgQuerylet[] $img_querylets
* @return Querylet
*/
private static function build_img_search($img_querylets) {
// merge all the image metadata searches into one generic querylet
$n = 0;
$sql = "";
$terms = array();
foreach ($img_querylets as $iq) {
if ($n++ > 0) $sql .= " AND";
if (!$iq->positive) $sql .= " NOT";
$sql .= " (" . $iq->qlet->sql . ")";
$terms = array_merge($terms, $iq->qlet->variables);
}
return new Querylet($sql, $terms);
}
/**
* @param Querylet $img_search
* @return Querylet
*/
private static function build_simple_query($img_search) {
$query = new Querylet("SELECT images.* FROM images ");
if (!empty($img_search->sql)) {
$query->append_sql(" WHERE ");
$query->append($img_search);
return $query;
}
return $query;
}
/**
* WARNING: this description is no longer accurate, though it does get across
* the general idea - the actual method has a few extra optimisiations
* the general idea - the actual method has a few extra optimisations
*
* "foo bar -baz user=foo" becomes
*
@ -752,7 +827,7 @@ class Image {
* A) Incredibly simple:
* Each search term maps to a list of image IDs
* B) Runs really fast on a good database:
* These lists are calucalted once, and the set intersection taken
* These lists are calculated once, and the set intersection taken
* C) Runs really slow on bad databases:
* All the subqueries are executed every time for every row in the
* images table. Yes, MySQL does suck this much.
@ -764,21 +839,12 @@ class Image {
global $database;
$tag_querylets = array();
$img_querylets = array();
$img_querylets = self::parse_meta_terms($terms);
$positive_tag_count = 0;
$stpe = new SearchTermParseEvent(null, $terms);
send_event($stpe);
if($stpe->is_querylet_set()) {
foreach($stpe->get_querylets() as $querylet) {
$img_querylets[] = new ImgQuerylet($querylet, true);
}
}
$terms = Tag::resolve_aliases($terms);
// parse the words that are searched for into
// various types of querylet
$terms = Tag::resolve_aliases($terms);
foreach($terms as $term) {
$positive = true;
if(is_string($term) && !empty($term) && ($term[0] == '-')) {
@ -804,41 +870,25 @@ class Image {
}
}
}
// merge all the image metadata searches into one generic querylet
$n = 0;
$sql = "";
$terms = array();
foreach($img_querylets as $iq) {
if($n++ > 0) $sql .= " AND";
if(!$iq->positive) $sql .= " NOT";
$sql .= " (" . $iq->qlet->sql . ")";
$terms = array_merge($terms, $iq->qlet->variables);
}
$img_search = new Querylet($sql, $terms);
$img_search = self::build_img_search($img_querylets);
// How many tag querylets are there?
$count_tag_querylets = count($tag_querylets);
// no tags, do a simple search (+image metadata if we have any)
if($count_tag_querylets === 0) {
$query = new Querylet("SELECT images.* FROM images ");
if(!empty($img_search->sql)) {
$query->append_sql(" WHERE ");
$query->append($img_search);
}
$query = self::build_simple_query($img_search);
}
// one positive tag (a common case), do an optimised search
else if($count_tag_querylets === 1 && $tag_querylets[0]->positive) {
$query = new Querylet($database->scoreql_to_sql("
SELECT images.* FROM images
SELECT images.*
FROM images
JOIN image_tags ON images.id=image_tags.image_id
JOIN tags ON image_tags.tag_id=tags.id
WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)
"), array("tag"=>$tag_querylets[0]->tag));
"), array("tag"=>$tag_querylets[0]->tag));
if(!empty($img_search->sql)) {
$query->append_sql(" AND ");
@ -854,10 +904,12 @@ class Image {
foreach($tag_querylets as $tq) {
$tag_ids = $database->get_col(
$database->scoreql_to_sql(
"SELECT id FROM tags WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)"
),
array("tag"=>$tq->tag));
$database->scoreql_to_sql("
SELECT id
FROM tags
WHERE SCORE_STRNORM(tag) = SCORE_STRNORM(:tag)
"), array("tag"=>$tq->tag)
);
if($tq->positive) {
$positive_tag_id_array = array_merge($positive_tag_id_array, $tag_ids);
$tags_ok = count($tag_ids) > 0;
@ -872,7 +924,7 @@ class Image {
$have_pos = count($positive_tag_id_array) > 0;
$have_neg = count($negative_tag_id_array) > 0;
$sql = "SELECT images.* FROM images WHERE images.id IN (";
$sql = "";
if($have_pos) {
$positive_tag_id_list = join(', ', $positive_tag_id_array);
$sql .= "
@ -894,8 +946,11 @@ class Image {
WHERE tag_id IN ($negative_tag_id_list)
";
}
$sql .= ")";
$query = new Querylet($sql);
$query = new Querylet("
SELECT images.*
FROM images
WHERE images.id IN ($sql)
");
if(strlen($img_search->sql) > 0) {
$query->append_sql(" AND ");
@ -921,23 +976,16 @@ class Image {
* build_accurate_search_querylet() for a full explanation
*
* @param array $terms
* @return Querylet
*/
private static function build_ugly_search_querylet($terms) {
global $database;
$tag_querylets = array();
$img_querylets = array();
$img_querylets = self::parse_meta_terms($terms);
$positive_tag_count = 0;
$negative_tag_count = 0;
$stpe = new SearchTermParseEvent(null, $terms);
send_event($stpe);
if($stpe->is_querylet_set()) {
foreach($stpe->get_querylets() as $querylet) {
$img_querylets[] = new ImgQuerylet($querylet, true);
}
}
$terms = Tag::resolve_aliases($terms);
reset($terms); // rewind to first element in array.
@ -979,44 +1027,24 @@ class Image {
else $negative_tag_count++;
}
$tag_search = new Querylet($sql, $terms);
// merge all the image metadata searches into one generic querylet
$n = 0;
$sql = "";
$terms = array();
foreach($img_querylets as $iq) {
if($n++ > 0) $sql .= " AND";
if(!$iq->positive) $sql .= " NOT";
$sql .= " (" . $iq->qlet->sql . ")";
$terms = array_merge($terms, $iq->qlet->variables);
}
$img_search = new Querylet($sql, $terms);
$img_search = self::build_img_search($img_querylets);
// no tags, do a simple search (+image metadata if we have any)
if($positive_tag_count + $negative_tag_count == 0) {
$query = new Querylet("SELECT images.*,UNIX_TIMESTAMP(posted) AS posted_timestamp FROM images ");
if(!empty($img_search->sql)) {
$query->append_sql(" WHERE ");
$query->append($img_search);
}
$query = self::build_simple_query($img_search);
}
// one positive tag (a common case), do an optimised search
else if($positive_tag_count === 1 && $negative_tag_count === 0) {
$query = new Querylet(
// MySQL is braindead, and does a full table scan on images, running the subquery once for each row -_-
// "{$this->get_images} WHERE images.id IN (SELECT image_id FROM tags WHERE tag LIKE ?) ",
"
SELECT images.*, UNIX_TIMESTAMP(posted) AS posted_timestamp
FROM tags, image_tags, images
WHERE
tag LIKE :tag0
AND tags.id = image_tags.tag_id
AND image_tags.image_id = images.id
",
$tag_search->variables);
// MySQL is braindead, and does a full table scan on images, running the subquery once for each row -_-
// "{$this->get_images} WHERE images.id IN (SELECT image_id FROM tags WHERE tag LIKE ?) ",
$query = new Querylet("
SELECT images.*
FROM images
JOIN image_tags ON images.id=image_tags.image_id
JOIN tags ON image_tags.tag_id=tags.id
WHERE tag LIKE :tag0
", $tag_search->variables);
if(!empty($img_search->sql)) {
$query->append_sql(" AND ");
@ -1031,7 +1059,10 @@ class Image {
$x = 0;
foreach($tag_search->variables as $tag) {
$tag_ids = $database->get_col("SELECT id FROM tags WHERE tag LIKE :tag", array("tag"=>$tag));
$tag_ids = $database->get_col(
"SELECT id FROM tags WHERE tag LIKE :tag",
array("tag"=>$tag)
);
$tag_id_array = array_merge($tag_id_array, $tag_ids);
$tags_ok = count($tag_ids) > 0 || !$tag_querylets[$x]->positive;
@ -1057,7 +1088,7 @@ class Image {
)
);
$query = new Querylet('
SELECT *, UNIX_TIMESTAMP(posted) AS posted_timestamp
SELECT *
FROM ('.$subquery->sql.') AS images ', $subquery->variables);
if(!empty($img_search->sql)) {
@ -1102,7 +1133,7 @@ class Tag {
* Remove any excess fluff from a user-input tag
*
* @param string $tag
* @return mixed
* @return string
*/
public static function sanitise($tag) {
assert('is_string($tag)');
@ -1118,7 +1149,7 @@ class Tag {
*
* @param string|string[] $tags
* @param bool $tagme
* @return array
* @return string[]
*/
public static function explode($tags, $tagme=true) {
assert('is_string($tags) || is_array($tags)');
@ -1142,6 +1173,8 @@ class Tag {
$tag_array = array("tagme");
}
$tag_array = array_iunique($tag_array); //remove duplicate tags
sort($tag_array);
return $tag_array;
@ -1213,7 +1246,10 @@ class Tag {
global $database;
$db_wild_tag = str_replace("%", "\%", $tag);
$db_wild_tag = str_replace("*", "%", $db_wild_tag);
$newtags = $database->get_col($database->scoreql_to_sql("SELECT tag FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(?)"), array($db_wild_tag));
$newtags = $database->get_col(
$database->scoreql_to_sql("SELECT tag FROM tags WHERE SCORE_STRNORM(tag) LIKE SCORE_STRNORM(?)"),
array($db_wild_tag)
);
if(count($newtags) > 0) {
$resolved = $newtags;
} else {
@ -1237,7 +1273,7 @@ class Tag {
$i = 0;
$tag_count = count($tags);
while($i<$tag_count) {
$aliases = explode(' ', Tag::resolve_alias($tags[$i]));
$aliases = Tag::explode(Tag::resolve_alias($tags[$i]), FALSE);
foreach($aliases as $alias){
if(!in_array($alias, $new)){
if($tags[$i] == $alias){
@ -1284,7 +1320,7 @@ function move_upload_to_archive(DataUploadEvent $event) {
* @param $base string
* @return array
*/
function add_dir(/*string*/ $base) {
function add_dir($base) {
$results = array();
foreach(list_files($base) as $full_path) {
@ -1307,12 +1343,12 @@ function add_dir(/*string*/ $base) {
}
/**
* @param $tmpname
* @param $filename
* @param $tags
* @param string $tmpname
* @param string $filename
* @param string $tags
* @throws UploadException
*/
function add_image(/*string*/ $tmpname, /*string*/ $filename, /*string*/ $tags) {
function add_image($tmpname, $filename, $tags) {
assert(file_exists($tmpname));
$pathinfo = pathinfo($filename);
@ -1337,7 +1373,7 @@ function add_image(/*string*/ $tmpname, /*string*/ $filename, /*string*/ $tags)
*
* @param int $orig_width
* @param int $orig_height
* @return array
* @return int[]
*/
function get_thumbnail_size(/*int*/ $orig_width, /*int*/ $orig_height) {
global $config;
@ -1363,4 +1399,3 @@ function get_thumbnail_size(/*int*/ $orig_width, /*int*/ $orig_height) {
}
}

View File

@ -205,6 +205,10 @@ class Page {
$this->cookies[] = array($full_name, $value, $time, $path);
}
/**
* @param string $name
* @return string|null
*/
public function get_cookie(/*string*/ $name) {
$full_name = COOKIE_PREFIX."_".$name;
if(isset($_COOKIE[$full_name])) {

View File

@ -36,7 +36,7 @@ _d("COMPILE_ELS", false); // boolean pre-build the list of event listeners
_d("NICE_URLS", false); // boolean force niceurl mode
_d("SEARCH_ACCEL", false); // boolean use search accelerator
_d("WH_SPLITS", 1); // int how many levels of subfolders to put in the warehouse
_d("VERSION", '2.5.4+'); // string shimmie version
_d("VERSION", '2.5.5+'); // string shimmie version
_d("TIMEZONE", null); // string timezone
_d("CORE_EXTS", "bbcode,user,mail,upload,image,view,handle_pixel,ext_manager,setup,upgrade,handle_404,comment,tag_list,index,tag_edit,alias_editor"); // extensions to always enable
_d("EXTRA_EXTS", ""); // optional extra extensions

View File

@ -124,6 +124,25 @@ function no_escape($input) {
return $input;
}
/**
* @param int $val
* @param int|null $min
* @param int|null $max
* @return int
*/
function clamp($val, $min, $max) {
if(!is_numeric($val) || (!is_null($min) && $val < $min)) {
$val = $min;
}
if(!is_null($max) && $val > $max) {
$val = $max;
}
if(!is_null($min) && !is_null($max)) {
assert('$val >= $min && $val <= $max', "$min <= $val <= $max");
}
return $val;
}
/**
* @param string $name
* @param array $attrs
@ -268,17 +287,22 @@ function validate_input($inputs) {
foreach($inputs as $key => $validations) {
$flags = explode(',', $validations);
if(in_array('bool', $flags) && !isset($_POST[$key])) {
$_POST[$key] = 'off';
}
if(in_array('optional', $flags)) {
if(!isset($_POST[$key])) {
if(!isset($_POST[$key]) || trim($_POST[$key]) == "") {
$outputs[$key] = null;
continue;
}
}
if(!isset($_POST[$key])) {
if(!isset($_POST[$key]) || trim($_POST[$key]) == "") {
throw new InvalidInput("Input '$key' not set");
}
$value = $_POST[$key];
$value = trim($_POST[$key]);
if(in_array('user_id', $flags)) {
$id = int_escape($value);
@ -308,11 +332,36 @@ function validate_input($inputs) {
$outputs[$key] = $value;
}
else if(in_array('email', $flags)) {
$outputs[$key] = $value;
$outputs[$key] = trim($value);
}
else if(in_array('password', $flags)) {
$outputs[$key] = $value;
}
else if(in_array('int', $flags)) {
$value = trim($value);
if(empty($value) || !is_numeric($value)) {
throw new InvalidInput("Invalid int: ".html_escape($value));
}
$outputs[$key] = (int)$value;
}
else if(in_array('bool', $flags)) {
$outputs[$key] = bool_escape($value);
}
else if(in_array('string', $flags)) {
if(in_array('trim', $flags)) {
$value = trim($value);
}
if(in_array('lower', $flags)) {
$value = strtolower($value);
}
if(in_array('not-empty', $flags)) {
throw new InvalidInput("$key must not be blank");
}
if(in_array('nullify', $flags)) {
if(empty($value)) $value = null;
}
$outputs[$key] = $value;
}
else {
throw new InvalidInput("Unknown validation '$validations'");
}
@ -910,21 +959,19 @@ function transload($url, $mfile) {
}
if($config->get_string("transload_engine") === "fopen") {
$fp = @fopen($url, "r");
if(!$fp) {
$fp_in = @fopen($url, "r");
$fp_out = fopen($mfile, "w");
if(!$fp_in || !$fp_out) {
return false;
}
$data = "";
$length = 0;
while(!feof($fp) && $length <= $config->get_int('upload_size')) {
$data .= fread($fp, 8192);
$length = strlen($data);
while(!feof($fp_in) && $length <= $config->get_int('upload_size')) {
$data = fread($fp_in, 8192);
$length += strlen($data);
fwrite($fp_out, $data);
}
fclose($fp);
$fp = fopen($mfile, "w");
fwrite($fp, $data);
fclose($fp);
fclose($fp_in);
fclose($fp_out);
$headers = http_parse_headers(implode("\n", $http_response_header));

View File

@ -1,6 +1,6 @@
<?php
class AdminPageTest extends ShimmiePHPUnitTestCase {
function testAuth() {
public function testAuth() {
$this->get_page('admin');
$this->assert_response(403);
$this->assert_title("Permission Denied");
@ -16,7 +16,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase {
$this->assert_title("Admin Tools");
}
function testLowercase() {
public function testLowercase() {
$ts = time(); // we need a tag that hasn't been used before
$this->log_in_as_admin();
@ -37,7 +37,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase {
}
# FIXME: make sure the admin tools actually work
function testRecount() {
public function testRecount() {
$this->log_in_as_admin();
$this->get_page('admin');
$this->assert_title("Admin Tools");
@ -46,7 +46,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase {
send_event(new AdminActionEvent('recount_tag_use'));
}
function testDump() {
public function testDump() {
$this->log_in_as_admin();
$this->get_page('admin');
$this->assert_title("Admin Tools");
@ -57,7 +57,7 @@ class AdminPageTest extends ShimmiePHPUnitTestCase {
//$this->assert_response(200);
}
function testDBQ() {
public function testDBQ() {
$this->log_in_as_user();
$image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test");
$image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2");

View File

@ -1,12 +1,12 @@
<?php
class AliasEditorTest extends ShimmiePHPUnitTestCase {
function testAliasList() {
public function testAliasList() {
$this->get_page('alias/list');
$this->assert_response(200);
$this->assert_title("Alias List");
}
function testAliasListReadOnly() {
public function testAliasListReadOnly() {
// Check that normal users can't add aliases.
$this->log_in_as_user();
$this->get_page('alias/list');
@ -14,7 +14,7 @@ class AliasEditorTest extends ShimmiePHPUnitTestCase {
$this->assert_no_text("Add");
}
function testAliasEditor() {
public function testAliasEditor() {
/*
**********************************************************************
* FIXME: TODO:
@ -26,6 +26,8 @@ class AliasEditorTest extends ShimmiePHPUnitTestCase {
* dig into this and determine exactly what is happening.
*
*********************************************************************
*/
$this->markTestIncomplete();
$this->log_in_as_admin();
@ -97,8 +99,6 @@ class AliasEditorTest extends ShimmiePHPUnitTestCase {
$this->get_page('alias/list');
$this->assert_title("Alias List");
$this->assert_no_text("Add");
*/
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
<?php
class ArtistTest extends ShimmiePHPUnitTestCase {
function testSearch() {
public function testSearch() {
# FIXME: check that the results are there
$this->get_page("post/list/author=bob/1");
#$this->assert_response(200);

View File

@ -23,7 +23,7 @@ class ArtistsTheme extends Themelet {
* @param null|int $artistID
* @param bool $is_admin
*/
public function sidebar_options(/*string*/ $mode, $artistID=NULL, $is_admin=FALSE){
public function sidebar_options(/*string*/ $mode, $artistID=NULL, $is_admin=FALSE) {
global $page, $user;
$html = "";
@ -77,49 +77,44 @@ class ArtistsTheme extends Themelet {
if($html) $page->add_block(new Block("Manage Artists", $html, "left", 10));
}
public function show_artist_editor($artist, $aliases, $members, $urls)
{
global $user;
public function show_artist_editor($artist, $aliases, $members, $urls) {
global $user;
$artistName = $artist['name'];
$artistNotes = $artist['notes'];
$artistID = $artist['id'];
$artistName = $artist['name'];
$artistNotes = $artist['notes'];
$artistID = $artist['id'];
// aliases
$aliasesString = "";
$aliasesIDsString = "";
foreach ($aliases as $alias)
{
$aliasesString .= $alias["alias_name"]." ";
$aliasesIDsString .= $alias["alias_id"]." ";
}
$aliasesString = rtrim($aliasesString);
$aliasesIDsString = rtrim($aliasesIDsString);
// aliases
$aliasesString = "";
$aliasesIDsString = "";
foreach ($aliases as $alias) {
$aliasesString .= $alias["alias_name"]." ";
$aliasesIDsString .= $alias["alias_id"]." ";
}
$aliasesString = rtrim($aliasesString);
$aliasesIDsString = rtrim($aliasesIDsString);
// members
$membersString = "";
$membersIDsString = "";
foreach ($members as $member)
{
$membersString .= $member["name"]." ";
$membersIDsString .= $member["id"]." ";
}
$membersString = rtrim($membersString);
$membersIDsString = rtrim($membersIDsString);
// members
$membersString = "";
$membersIDsString = "";
foreach ($members as $member) {
$membersString .= $member["name"]." ";
$membersIDsString .= $member["id"]." ";
}
$membersString = rtrim($membersString);
$membersIDsString = rtrim($membersIDsString);
// urls
$urlsString = "";
$urlsIDsString = "";
foreach ($urls as $url)
{
$urlsString .= $url["url"]."\n";
$urlsIDsString .= $url["id"]." ";
}
$urlsString = substr($urlsString, 0, strlen($urlsString) -1);
$urlsIDsString = rtrim($urlsIDsString);
// urls
$urlsString = "";
$urlsIDsString = "";
foreach ($urls as $url) {
$urlsString .= $url["url"]."\n";
$urlsIDsString .= $url["id"]." ";
}
$urlsString = substr($urlsString, 0, strlen($urlsString) -1);
$urlsIDsString = rtrim($urlsIDsString);
$html =
'
$html = '
<form method="POST" action="'.make_link("artist/edited/".$artist['id']).'">
'.$user->get_auth_html().'
<table>
@ -135,113 +130,108 @@ class ArtistsTheme extends Themelet {
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
';
';
global $page;
$page->add_block(new Block("Edit artist", $html, "main", 10));
}
public function new_artist_composer()
{
global $page, $user;
$html = "<form action=".make_link("artist/create")." method='POST'>
".$user->get_auth_html()."
<table>
<tr><td>Name:</td><td><input type='text' name='name' /></td></tr>
<tr><td>Aliases:</td><td><input type='text' name='aliases' /></td></tr>
<tr><td>Members:</td><td><input type='text' name='members' /></td></tr>
<tr><td>URLs:</td><td><textarea name='urls'></textarea></td></tr>
<tr><td>Notes:</td><td><textarea name='notes'></textarea></td></tr>
<tr><td colspan='2'><input type='submit' value='Submit' /></td></tr>
</table>
";
$page->set_title("Artists");
$page->set_heading("Artists");
$page->add_block(new Block("Artists", $html, "main", 10));
global $page;
$page->add_block(new Block("Edit artist", $html, "main", 10));
}
public function list_artists($artists, $pageNumber, $totalPages)
{
global $user, $page;
public function new_artist_composer() {
global $page, $user;
$html = "<table id='poolsList' class='zebra'>".
"<thead><tr>".
"<th>Name</th>".
"<th>Type</th>".
"<th>Last updater</th>".
"<th>Posts</th>";
$html = "<form action=".make_link("artist/create")." method='POST'>
".$user->get_auth_html()."
<table>
<tr><td>Name:</td><td><input type='text' name='name' /></td></tr>
<tr><td>Aliases:</td><td><input type='text' name='aliases' /></td></tr>
<tr><td>Members:</td><td><input type='text' name='members' /></td></tr>
<tr><td>URLs:</td><td><textarea name='urls'></textarea></td></tr>
<tr><td>Notes:</td><td><textarea name='notes'></textarea></td></tr>
<tr><td colspan='2'><input type='submit' value='Submit' /></td></tr>
</table>
";
$page->set_title("Artists");
$page->set_heading("Artists");
$page->add_block(new Block("Artists", $html, "main", 10));
}
public function list_artists($artists, $pageNumber, $totalPages) {
global $user, $page;
if(!$user->is_anonymous()) $html .= "<th colspan='2'>Action</th>"; // space for edit link
$html = "<table id='poolsList' class='zebra'>".
"<thead><tr>".
"<th>Name</th>".
"<th>Type</th>".
"<th>Last updater</th>".
"<th>Posts</th>";
if(!$user->is_anonymous()) $html .= "<th colspan='2'>Action</th>"; // space for edit link
$html .= "</tr></thead>";
$html .= "</tr></thead>";
$deletionLinkActionArray =
array('artist' => 'artist/nuke/'
, 'alias' => 'artist/alias/delete/'
, 'member' => 'artist/member/delete/'
);
$deletionLinkActionArray = array(
'artist' => 'artist/nuke/',
'alias' => 'artist/alias/delete/',
'member' => 'artist/member/delete/',
);
$editionLinkActionArray =
array('artist' => 'artist/edit/'
, 'alias' => 'artist/alias/edit/'
, 'member' => 'artist/member/edit/'
);
$editionLinkActionArray = array(
'artist' => 'artist/edit/',
'alias' => 'artist/alias/edit/',
'member' => 'artist/member/edit/',
);
$typeTextArray =
array('artist' => 'Artist'
, 'alias' => 'Alias'
, 'member' => 'Member'
);
$typeTextArray = array(
'artist' => 'Artist',
'alias' => 'Alias',
'member' => 'Member',
);
foreach ($artists as $artist) {
if ($artist['type'] != 'artist')
$artist['name'] = str_replace("_", " ", $artist['name']);
foreach ($artists as $artist) {
if ($artist['type'] != 'artist')
$artist['name'] = str_replace("_", " ", $artist['name']);
$elementLink = "<a href='".make_link("artist/view/".$artist['artist_id'])."'>".str_replace("_", " ", $artist['name'])."</a>";
//$artist_link = "<a href='".make_link("artist/view/".$artist['artist_id'])."'>".str_replace("_", " ", $artist['artist_name'])."</a>";
$user_link = "<a href='".make_link("user/".$artist['user_name'])."'>".$artist['user_name']."</a>";
$edit_link = "<a href='".make_link($editionLinkActionArray[$artist['type']].$artist['id'])."'>Edit</a>";
$del_link = "<a href='".make_link($deletionLinkActionArray[$artist['type']].$artist['id'])."'>Delete</a>";
$elementLink = "<a href='".make_link("artist/view/".$artist['artist_id'])."'>".str_replace("_", " ", $artist['name'])."</a>";
//$artist_link = "<a href='".make_link("artist/view/".$artist['artist_id'])."'>".str_replace("_", " ", $artist['artist_name'])."</a>";
$user_link = "<a href='".make_link("user/".$artist['user_name'])."'>".$artist['user_name']."</a>";
$edit_link = "<a href='".make_link($editionLinkActionArray[$artist['type']].$artist['id'])."'>Edit</a>";
$del_link = "<a href='".make_link($deletionLinkActionArray[$artist['type']].$artist['id'])."'>Delete</a>";
$html .= "<tr>".
"<td class='left'>".$elementLink;
$html .= "<tr>".
"<td class='left'>".$elementLink;
//if ($artist['type'] == 'member')
// $html .= " (member of ".$artist_link.")";
//if ($artist['type'] == 'member')
// $html .= " (member of ".$artist_link.")";
//if ($artist['type'] == 'alias')
// $html .= " (alias for ".$artist_link.")";
//if ($artist['type'] == 'alias')
// $html .= " (alias for ".$artist_link.")";
$html .= "</td>".
"<td>".$typeTextArray[$artist['type']]."</td>".
"<td>".$user_link."</td>".
"<td>".$artist['posts']."</td>";
$html .= "</td>".
"<td>".$typeTextArray[$artist['type']]."</td>".
"<td>".$user_link."</td>".
"<td>".$artist['posts']."</td>";
if(!$user->is_anonymous()) $html .= "<td>".$edit_link."</td>";
if($user->is_admin()) $html .= "<td>".$del_link."</td>";
if(!$user->is_anonymous()) $html .= "<td>".$edit_link."</td>";
if($user->is_admin()) $html .= "<td>".$del_link."</td>";
$html .= "</tr>";
}
$html .= "</tr>";
}
$html .= "</tbody></table>";
$html .= "</tbody></table>";
$page->set_title("Artists");
$page->set_heading("Artists");
$page->add_block(new Block("Artists", $html, "main", 10));
$page->set_title("Artists");
$page->set_heading("Artists");
$page->add_block(new Block("Artists", $html, "main", 10));
$this->display_paginator($page, "artist/list", null, $pageNumber, $totalPages);
$this->display_paginator($page, "artist/list", null, $pageNumber, $totalPages);
}
public function show_new_alias_composer($artistID)
{
global $user;
public function show_new_alias_composer($artistID) {
global $user;
$html =
'<form method="POST" action='.make_link("artist/alias/add").'>
$html = '
<form method="POST" action='.make_link("artist/alias/add").'>
'.$user->get_auth_html().'
<table>
<tr><td>Alias:</td><td><input type="text" name="aliases" />
@ -249,277 +239,290 @@ class ArtistsTheme extends Themelet {
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
';
';
global $page;
$page->add_block(new Block("Artist Aliases", $html, "main", 20));
}
public function show_new_member_composer($artistID)
{
global $user;
global $page;
$page->add_block(new Block("Artist Aliases", $html, "main", 20));
}
$html =
' <form method="POST" action='.make_link("artist/member/add").'>
public function show_new_member_composer($artistID) {
global $user;
$html = '
<form method="POST" action='.make_link("artist/member/add").'>
'.$user->get_auth_html().'
<table>
<tr><td>Members:</td><td><input type="text" name="members" />
<input type="hidden" name="artistID" value='.$artistID.' /></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
';
<table>
<tr><td>Members:</td><td><input type="text" name="members" />
<input type="hidden" name="artistID" value='.$artistID.' /></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
';
global $page;
$page->add_block(new Block("Artist members", $html, "main", 30));
}
global $page;
$page->add_block(new Block("Artist members", $html, "main", 30));
}
public function show_new_url_composer($artistID)
{
global $user;
public function show_new_url_composer($artistID) {
global $user;
$html =
' <form method="POST" action='.make_link("artist/url/add").'>
$html = '
<form method="POST" action='.make_link("artist/url/add").'>
'.$user->get_auth_html().'
<table>
<tr><td>URL:</td><td><textarea name="urls"></textarea>
<input type="hidden" name="artistID" value='.$artistID.' /></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
';
<table>
<tr><td>URL:</td><td><textarea name="urls"></textarea>
<input type="hidden" name="artistID" value='.$artistID.' /></td></tr>
<tr><td colspan="2"><input type="submit" value="Submit" /></td></tr>
</table>
</form>
';
global $page;
$page->add_block(new Block("Artist URLs", $html, "main", 40));
}
global $page;
$page->add_block(new Block("Artist URLs", $html, "main", 40));
}
public function show_alias_editor($alias)
{
global $user;
public function show_alias_editor($alias) {
global $user;
$html =
'
<form method="POST" action="'.make_link("artist/alias/edited/".$alias['id']).'">
'.$user->get_auth_html().'
<label for="alias">Alias:</label>
<input type="text" name="alias" value="'.$alias['alias'].'" />
<input type="hidden" name="aliasID" value="'.$alias['id'].'" />
<input type="submit" value="Submit" />
</form>
';
$html = '
<form method="POST" action="'.make_link("artist/alias/edited/".$alias['id']).'">
'.$user->get_auth_html().'
<label for="alias">Alias:</label>
<input type="text" name="alias" value="'.$alias['alias'].'" />
<input type="hidden" name="aliasID" value="'.$alias['id'].'" />
<input type="submit" value="Submit" />
</form>
';
global $page;
$page->add_block(new Block("Edit Alias", $html, "main", 10));
}
global $page;
$page->add_block(new Block("Edit Alias", $html, "main", 10));
}
public function show_url_editor($url)
{
global $user;
public function show_url_editor($url) {
global $user;
$html =
'
<form method="POST" action="'.make_link("artist/url/edited/".$url['id']).'">
'.$user->get_auth_html().'
<label for="url">URL:</label>
<input type="text" name="url" value="'.$url['url'].'" />
<input type="hidden" name="urlID" value="'.$url['id'].'" />
<input type="submit" value="Submit" />
</form>
';
$html = '
<form method="POST" action="'.make_link("artist/url/edited/".$url['id']).'">
'.$user->get_auth_html().'
<label for="url">URL:</label>
<input type="text" name="url" value="'.$url['url'].'" />
<input type="hidden" name="urlID" value="'.$url['id'].'" />
<input type="submit" value="Submit" />
</form>
';
global $page;
$page->add_block(new Block("Edit URL", $html, "main", 10));
}
global $page;
$page->add_block(new Block("Edit URL", $html, "main", 10));
}
public function show_member_editor($member)
{
global $user;
public function show_member_editor($member) {
global $user;
$html =
'
<form method="POST" action="'.make_link("artist/member/edited/".$member['id']).'">
'.$user->get_auth_html().'
<label for="member">Member name:</label>
<input type="text" name="name" value="'.$member['name'].'" />
<input type="hidden" name="memberID" value="'.$member['id'].'" />
<input type="submit" value="Submit" />
</form>
';
$html = '
<form method="POST" action="'.make_link("artist/member/edited/".$member['id']).'">
'.$user->get_auth_html().'
<label for="member">Member name:</label>
<input type="text" name="name" value="'.$member['name'].'" />
<input type="hidden" name="memberID" value="'.$member['id'].'" />
<input type="submit" value="Submit" />
</form>
';
global $page;
$page->add_block(new Block("Edit Member", $html, "main", 10));
}
global $page;
$page->add_block(new Block("Edit Member", $html, "main", 10));
}
public function show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin)
{
global $page;
public function show_artist($artist, $aliases, $members, $urls, $images, $userIsLogged, $userIsAdmin) {
global $page;
$artist_link = "<a href='".make_link("post/list/".$artist['name']."/1")."'>".str_replace("_", " ", $artist['name'])."</a>";
$artist_link = "<a href='".make_link("post/list/".$artist['name']."/1")."'>".str_replace("_", " ", $artist['name'])."</a>";
$html = "<table id='poolsList' class='zebra'>
$html = "<table id='poolsList' class='zebra'>
<thead>
<tr>
<th></th>
<th></th>";
if ($userIsLogged)
$html .= "<th></th>";
if ($userIsLogged) $html .= "<th></th>";
if ($userIsAdmin) $html .= "<th></th>";
if ($userIsAdmin)
$html .= "<th></th>";
$html .= " <tr>
$html .= " <tr>
</thead>
<tr>
<td class='left'>Name:</td>
<td class='left'>".$artist_link."</td>";
if ($userIsLogged) $html .= "<td></td>";
if ($userIsAdmin) $html .= "<td></td>";
$html .= "</tr>";
if ($userIsLogged) $html .= "<td></td>";
if ($userIsAdmin) $html .= "<td></td>";
$html .= "</tr>";
if (count($aliases) > 0)
{
$aliasViewLink = str_replace("_", " ", $aliases[0]['alias_name']); // no link anymore
$aliasEditLink = "<a href='".make_link("artist/alias/edit/".$aliases[0]['alias_id'])."'>Edit</a>";
$aliasDeleteLink = "<a href='".make_link("artist/alias/delete/".$aliases[0]['alias_id'])."'>Delete</a>";
$html .= "<tr>
<td class='left'>Aliases:</td>
<td class='left'>".$aliasViewLink."</td>";
if ($userIsLogged)
$html .= "<td class='left'>".$aliasEditLink."</td>";
$html .= $this->render_aliases($aliases, $userIsLogged, $userIsAdmin);
$html .= $this->render_members($members, $userIsLogged, $userIsAdmin);
$html .= $this->render_urls($urls, $userIsLogged, $userIsAdmin);
if ($userIsAdmin)
$html .= "<td class='left'>".$aliasDeleteLink."</td>";
$html .= "</tr>";
if (count($aliases) > 1)
{
for ($i = 1; $i < count($aliases); $i++)
{
$aliasViewLink = str_replace("_", " ", $aliases[$i]['alias_name']); // no link anymore
$aliasEditLink = "<a href='".make_link("artist/alias/edit/".$aliases[$i]['alias_id'])."'>Edit</a>";
$aliasDeleteLink = "<a href='".make_link("artist/alias/delete/".$aliases[$i]['alias_id'])."'>Delete</a>";
$html .= "<tr>
<td class='left'>&nbsp;</td>
<td class='left'>".$aliasViewLink."</td>";
if ($userIsLogged)
$html .= "<td class='left'>".$aliasEditLink."</td>";
if ($userIsAdmin)
$html .= "<td class='left'>".$aliasDeleteLink."</td>";
$html .= "</tr>";
}
}
}
if (count($members) > 0)
{
$memberViewLink = str_replace("_", " ", $members[0]['name']); // no link anymore
$memberEditLink = "<a href='".make_link("artist/member/edit/".$members[0]['id'])."'>Edit</a>";
$memberDeleteLink = "<a href='".make_link("artist/member/delete/".$members[0]['id'])."'>Delete</a>";
$html .= "<tr>
<td class='left'>Members:</td>
<td class='left'>".$memberViewLink."</td>";
if ($userIsLogged)
$html .= "<td class='left'>".$memberEditLink."</td>";
if ($userIsAdmin)
$html .= "<td class='left'>".$memberDeleteLink."</td>";
$html .= "</tr>";
if (count($members) > 1)
{
for ($i = 1; $i < count($members); $i++)
{
$memberViewLink = str_replace("_", " ", $members[$i]['name']); // no link anymore
$memberEditLink = "<a href='".make_link("artist/member/edit/".$members[$i]['id'])."'>Edit</a>";
$memberDeleteLink = "<a href='".make_link("artist/member/delete/".$members[$i]['id'])."'>Delete</a>";
$html .= "<tr>
<td class='left'>&nbsp;</td>
<td class='left'>".$memberViewLink."</td>";
if ($userIsLogged)
$html .= "<td class='left'>".$memberEditLink."</td>";
if ($userIsAdmin)
$html .= "<td class='left'>".$memberDeleteLink."</td>";
$html .= "</tr>";
}
}
}
if (count($urls) > 0)
{
$urlViewLink = "<a href='".str_replace("_", " ", $urls[0]['url'])."' target='_blank'>".str_replace("_", " ", $urls[0]['url'])."</a>";
$urlEditLink = "<a href='".make_link("artist/url/edit/".$urls[0]['id'])."'>Edit</a>";
$urlDeleteLink = "<a href='".make_link("artist/url/delete/".$urls[0]['id'])."'>Delete</a>";
$html .= "<tr>
<td class='left'>URLs:</td>
<td class='left'>".$urlViewLink."</td>";
if ($userIsLogged)
$html .= "<td class='left'>".$urlEditLink."</td>";
if ($userIsAdmin)
$html .= "<td class='left'>".$urlDeleteLink."</td>";
$html .= "</tr>";
if (count($urls) > 1)
{
for ($i = 1; $i < count($urls); $i++)
{
$urlViewLink = "<a href='".str_replace("_", " ", $urls[$i]['url'])."' target='_blank'>".str_replace("_", " ", $urls[$i]['url'])."</a>";
$urlEditLink = "<a href='".make_link("artist/url/edit/".$urls[$i]['id'])."'>Edit</a>";
$urlDeleteLink = "<a href='".make_link("artist/url/delete/".$urls[$i]['id'])."'>Delete</a>";
$html .= "<tr>
<td class='left'>&nbsp;</td>
<td class='left'>".$urlViewLink."</td>";
if ($userIsLogged)
$html .= "<td class='left'>".$urlEditLink."</td>";
if ($userIsAdmin)
$html .= "<td class='left'>".$urlDeleteLink."</td>";
$html .= "</tr>";
}
}
}
$html .=
"<tr>
$html .= "<tr>
<td class='left'>Notes:</td>
<td class='left'>".$artist["notes"]."</td>";
if ($userIsLogged) $html .= "<td></td>";
if ($userIsAdmin) $html .= "<td></td>";
//TODO how will notes be edited? On edit artist? (should there be an editartist?) or on a editnotes?
//same question for deletion
$html .= "</tr>
</table>";
if ($userIsLogged) $html .= "<td></td>";
if ($userIsAdmin) $html .= "<td></td>";
//TODO how will notes be edited? On edit artist? (should there be an editartist?) or on a editnotes?
//same question for deletion
$html .= "</tr>
</table>";
$page->set_title("Artist");
$page->set_heading("Artist");
$page->add_block(new Block("Artist", $html, "main", 10));
$page->set_title("Artist");
$page->set_heading("Artist");
$page->add_block(new Block("Artist", $html, "main", 10));
//we show the images for the artist
$artist_images = "";
foreach($images as $image) {
$thumb_html = $this->build_thumb_html($image);
//we show the images for the artist
$artist_images = "";
foreach($images as $image) {
$thumb_html = $this->build_thumb_html($image);
$artist_images .= '<span class="thumb">'.
'<a href="$image_link">'.$thumb_html.'</a>'.
'</span>';
}
$artist_images .= '<span class="thumb">'.
'<a href="$image_link">'.$thumb_html.'</a>'.
'</span>';
}
$page->add_block(new Block("Artist Images", $artist_images, "main", 20));
$page->add_block(new Block("Artist Images", $artist_images, "main", 20));
}
/**
* @param $aliases
* @param $userIsLogged
* @param $userIsAdmin
* @return string
*/
private function render_aliases($aliases, $userIsLogged, $userIsAdmin) {
$html = "";
if(count($aliases) > 0) {
$aliasViewLink = str_replace("_", " ", $aliases[0]['alias_name']); // no link anymore
$aliasEditLink = "<a href='" . make_link("artist/alias/edit/" . $aliases[0]['alias_id']) . "'>Edit</a>";
$aliasDeleteLink = "<a href='" . make_link("artist/alias/delete/" . $aliases[0]['alias_id']) . "'>Delete</a>";
$html .= "<tr>
<td class='left'>Aliases:</td>
<td class='left'>" . $aliasViewLink . "</td>";
if ($userIsLogged)
$html .= "<td class='left'>" . $aliasEditLink . "</td>";
if ($userIsAdmin)
$html .= "<td class='left'>" . $aliasDeleteLink . "</td>";
$html .= "</tr>";
if (count($aliases) > 1) {
for ($i = 1; $i < count($aliases); $i++) {
$aliasViewLink = str_replace("_", " ", $aliases[$i]['alias_name']); // no link anymore
$aliasEditLink = "<a href='" . make_link("artist/alias/edit/" . $aliases[$i]['alias_id']) . "'>Edit</a>";
$aliasDeleteLink = "<a href='" . make_link("artist/alias/delete/" . $aliases[$i]['alias_id']) . "'>Delete</a>";
$html .= "<tr>
<td class='left'>&nbsp;</td>
<td class='left'>" . $aliasViewLink . "</td>";
if ($userIsLogged)
$html .= "<td class='left'>" . $aliasEditLink . "</td>";
if ($userIsAdmin)
$html .= "<td class='left'>" . $aliasDeleteLink . "</td>";
$html .= "</tr>";
}
}
}
return $html;
}
/**
* @param $members
* @param $userIsLogged
* @param $userIsAdmin
* @return string
*/
private function render_members($members, $userIsLogged, $userIsAdmin) {
$html = "";
if(count($members) > 0) {
$memberViewLink = str_replace("_", " ", $members[0]['name']); // no link anymore
$memberEditLink = "<a href='" . make_link("artist/member/edit/" . $members[0]['id']) . "'>Edit</a>";
$memberDeleteLink = "<a href='" . make_link("artist/member/delete/" . $members[0]['id']) . "'>Delete</a>";
$html .= "<tr>
<td class='left'>Members:</td>
<td class='left'>" . $memberViewLink . "</td>";
if ($userIsLogged)
$html .= "<td class='left'>" . $memberEditLink . "</td>";
if ($userIsAdmin)
$html .= "<td class='left'>" . $memberDeleteLink . "</td>";
$html .= "</tr>";
if (count($members) > 1) {
for ($i = 1; $i < count($members); $i++) {
$memberViewLink = str_replace("_", " ", $members[$i]['name']); // no link anymore
$memberEditLink = "<a href='" . make_link("artist/member/edit/" . $members[$i]['id']) . "'>Edit</a>";
$memberDeleteLink = "<a href='" . make_link("artist/member/delete/" . $members[$i]['id']) . "'>Delete</a>";
$html .= "<tr>
<td class='left'>&nbsp;</td>
<td class='left'>" . $memberViewLink . "</td>";
if ($userIsLogged)
$html .= "<td class='left'>" . $memberEditLink . "</td>";
if ($userIsAdmin)
$html .= "<td class='left'>" . $memberDeleteLink . "</td>";
$html .= "</tr>";
}
}
}
return $html;
}
/**
* @param $urls
* @param $userIsLogged
* @param $userIsAdmin
* @return string
*/
private function render_urls($urls, $userIsLogged, $userIsAdmin) {
$html = "";
if(count($urls) > 0) {
$urlViewLink = "<a href='" . str_replace("_", " ", $urls[0]['url']) . "' target='_blank'>" . str_replace("_", " ", $urls[0]['url']) . "</a>";
$urlEditLink = "<a href='" . make_link("artist/url/edit/" . $urls[0]['id']) . "'>Edit</a>";
$urlDeleteLink = "<a href='" . make_link("artist/url/delete/" . $urls[0]['id']) . "'>Delete</a>";
$html .= "<tr>
<td class='left'>URLs:</td>
<td class='left'>" . $urlViewLink . "</td>";
if ($userIsLogged)
$html .= "<td class='left'>" . $urlEditLink . "</td>";
if ($userIsAdmin)
$html .= "<td class='left'>" . $urlDeleteLink . "</td>";
$html .= "</tr>";
if (count($urls) > 1) {
for ($i = 1; $i < count($urls); $i++) {
$urlViewLink = "<a href='" . str_replace("_", " ", $urls[$i]['url']) . "' target='_blank'>" . str_replace("_", " ", $urls[$i]['url']) . "</a>";
$urlEditLink = "<a href='" . make_link("artist/url/edit/" . $urls[$i]['id']) . "'>Edit</a>";
$urlDeleteLink = "<a href='" . make_link("artist/url/delete/" . $urls[$i]['id']) . "'>Delete</a>";
$html .= "<tr>
<td class='left'>&nbsp;</td>
<td class='left'>" . $urlViewLink . "</td>";
if ($userIsLogged)
$html .= "<td class='left'>" . $urlEditLink . "</td>";
if ($userIsAdmin)
$html .= "<td class='left'>" . $urlDeleteLink . "</td>";
$html .= "</tr>";
}
return $html;
}
}
return $html;
}
}

View File

@ -1,6 +1,6 @@
<?php
class BanWordsTest extends ShimmiePHPUnitTestCase {
function check_blocked($image_id, $words) {
public function check_blocked($image_id, $words) {
global $user;
try {
send_event(new CommentPostingEvent($image_id, $user, $words));
@ -11,7 +11,7 @@ class BanWordsTest extends ShimmiePHPUnitTestCase {
}
}
function testWordBan() {
public function testWordBan() {
global $config;
$config->set_string("banned_words", "viagra\nporn\n\n/http:.*\.cn\//");

View File

@ -93,7 +93,7 @@ class BBCode extends FormatterExtension {
/**
* @param string $text
* @return mixed
* @return string
*/
private function filter_spoiler(/*string*/ $text) {
return str_replace(

View File

@ -1,6 +1,6 @@
<?php
class BlocksTest extends ShimmiePHPUnitTestCase {
function testBlocks() {
public function testBlocks() {
$this->log_in_as_admin();
$this->get_page("blocks/list");
$this->assert_response(200);

View File

@ -1,13 +1,13 @@
<?php
class BlotterTest extends ShimmiePHPUnitTestCase {
function testLogin() {
public function testLogin() {
$this->log_in_as_admin();
//$this->assert_text("Blotter Editor");
//$this->click("Blotter Editor");
//$this->log_out();
}
function testDenial() {
public function testDenial() {
$this->get_page("blotter/editor");
$this->assert_response(403);
$this->get_page("blotter/add");
@ -16,7 +16,7 @@ class BlotterTest extends ShimmiePHPUnitTestCase {
$this->assert_response(403);
}
function testAddViewRemove() {
public function testAddViewRemove() {
$this->log_in_as_admin();
$this->get_page("blotter/editor");

View File

@ -62,7 +62,7 @@ class BlotterTheme extends Themelet {
if($entries[$i]['important'] == 'Y') { $important = 'Y'; } else { $important = 'N'; }
// Add the new table row(s)
$table_rows .=
$table_rows .=
"<tr>
<td>$entry_date</td>
<td>$entry_text</td>
@ -114,7 +114,7 @@ class BlotterTheme extends Themelet {
$i_open = "<font color='#{$i_color}'>";
$i_close="</font>";
}
$html .= "{$i_open}{$clean_date} - {$entry_text}{$i_close}<br /><br />";
$html .= "{$i_open}{$clean_date} - {$entry_text}{$i_close}<br /><br />";
}
$html .= "</pre>";
return $html;
@ -139,9 +139,9 @@ class BlotterTheme extends Themelet {
$entry_text = $entries[$i]['entry_text'];
if($entries[$i]['important'] == 'Y') {
$i_open = "<font color='#{$i_color}'>";
$i_close="</font>";
$i_close="</font>";
}
$entries_list .= "<li>{$i_open}{$clean_date} - {$entry_text}{$i_close}</li>";
$entries_list .= "<li>{$i_open}{$clean_date} - {$entry_text}{$i_close}</li>";
}
$pos_break = "";
@ -149,7 +149,7 @@ class BlotterTheme extends Themelet {
if($position === "left") {
$pos_break = "<br />";
$pos_align = "";
$pos_align = "";
}
if(count($entries) === 0) {
@ -176,4 +176,3 @@ class BlotterTheme extends Themelet {
return $html;
}
}

View File

@ -1,6 +1,6 @@
<?php
class BookmarksTest extends ShimmiePHPUnitTestCase {
function testBookmarks() {
public function testBookmarks() {
$this->get_page("bookmark/add");
$this->get_page("bookmark/remove");
}

View File

@ -1,6 +1,6 @@
<?php
class BrowserSearchTest extends ShimmiePHPUnitTestCase {
function testBasic() {
public function testBasic() {
$this->get_page("browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml");
$this->get_page("browser_search/test");
}

View File

@ -1,6 +1,6 @@
<?php
class BulkAddTest extends ShimmiePHPUnitTestCase {
function testBulkAdd() {
public function testBulkAdd() {
$this->log_in_as_admin();
$this->get_page('admin');
@ -11,7 +11,8 @@ class BulkAddTest extends ShimmiePHPUnitTestCase {
$this->assertContains("Error, asdf is not a readable directory",
$bae->results, implode("\n", $bae->results));
return; // FIXME: have BAE return a list of successes as well as errors?
// FIXME: have BAE return a list of successes as well as errors?
$this->markTestIncomplete();
$this->get_page('admin');
$this->assert_title("Admin Tools");

View File

@ -54,6 +54,14 @@ class BulkAddCSV extends Extension {
/**
* Generate the necessary DataUploadEvent for a given image and tags.
*
* @param string $tmpname
* @param string $filename
* @param string $tags
* @param string $source
* @param string $rating
* @param string $thumbfile
* @throws UploadException
*/
private function add_image($tmpname, $filename, $tags, $source, $rating, $thumbfile) {
assert(file_exists($tmpname));

View File

@ -71,12 +71,16 @@ class Comment {
}
/**
* @param \User $user
* @param User $user
* @return mixed
*/
public static function count_comments_by_user($user) {
global $database;
return $database->get_one("SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id", array("owner_id"=>$user->id));
return $database->get_one("
SELECT COUNT(*) AS count
FROM comments
WHERE owner_id=:owner_id
", array("owner_id"=>$user->id));
}
/**
@ -89,6 +93,9 @@ class Comment {
}
class CommentList extends Extension {
/** @var CommentListTheme $theme */
var $theme;
public function onInitExt(InitExtEvent $event) {
global $config, $database;
$config->set_default_int('comment_window', 5);
@ -147,78 +154,92 @@ class CommentList extends Extension {
}
public function onPageRequest(PageRequestEvent $event) {
global $page, $user, $database;
if($event->page_matches("comment")) {
if($event->get_arg(0) === "add") {
if(isset($_POST['image_id']) && isset($_POST['comment'])) {
try {
$i_iid = int_escape($_POST['image_id']);
$cpe = new CommentPostingEvent($_POST['image_id'], $user, $_POST['comment']);
send_event($cpe);
$page->set_mode("redirect");
$page->set_redirect(make_link("post/view/$i_iid#comment_on_$i_iid"));
}
catch(CommentPostingException $ex) {
$this->theme->display_error(403, "Comment Blocked", $ex->getMessage());
}
}
}
else if($event->get_arg(0) === "delete") {
if($user->can("delete_comment")) {
// FIXME: post, not args
if($event->count_args() === 3) {
send_event(new CommentDeletionEvent($event->get_arg(1)));
flash_message("Deleted comment");
$page->set_mode("redirect");
if(!empty($_SERVER['HTTP_REFERER'])) {
$page->set_redirect($_SERVER['HTTP_REFERER']);
}
else {
$page->set_redirect(make_link("post/view/".$event->get_arg(2)));
}
}
}
else {
$this->theme->display_permission_denied();
}
}
else if($event->get_arg(0) === "bulk_delete") {
if($user->can("delete_comment") && !empty($_POST["ip"])) {
$ip = $_POST['ip'];
$cids = $database->get_col("SELECT id FROM comments WHERE owner_ip=:ip", array("ip"=>$ip));
$num = count($cids);
log_warning("comment", "Deleting $num comments from $ip");
foreach($cids as $cid) {
send_event(new CommentDeletionEvent($cid));
}
flash_message("Deleted $num comments");
$page->set_mode("redirect");
$page->set_redirect(make_link("admin"));
}
else {
$this->theme->display_permission_denied();
}
}
else if($event->get_arg(0) === "list") {
$page_num = int_escape($event->get_arg(1));
$this->build_page($page_num);
}
else if($event->get_arg(0) === "beta-search") {
$search = $event->get_arg(1);
$page_num = int_escape($event->get_arg(2));
$duser = User::by_name($search);
$i_comment_count = Comment::count_comments_by_user($duser);
$com_per_page = 50;
$total_pages = ceil($i_comment_count/$com_per_page);
$page_num = $this->sanity_check_pagenumber($page_num, $total_pages);
$comments = $this->get_user_comments($duser->id, $com_per_page, ($page_num-1) * $com_per_page);
$this->theme->display_all_user_comments($comments, $page_num, $total_pages, $duser);
switch($event->get_arg(0)) {
case "add": $this->onPageRequest_add(); break;
case "delete": $this->onPageRequest_delete($event); break;
case "bulk_delete": $this->onPageRequest_bulk_delete(); break;
case "list": $this->onPageRequest_list($event); break;
case "beta-search": $this->onPageRequest_beta_search($event); break;
}
}
}
private function onPageRequest_add() {
global $user, $page;
if (isset($_POST['image_id']) && isset($_POST['comment'])) {
try {
$i_iid = int_escape($_POST['image_id']);
$cpe = new CommentPostingEvent($_POST['image_id'], $user, $_POST['comment']);
send_event($cpe);
$page->set_mode("redirect");
$page->set_redirect(make_link("post/view/$i_iid#comment_on_$i_iid"));
} catch (CommentPostingException $ex) {
$this->theme->display_error(403, "Comment Blocked", $ex->getMessage());
}
}
}
private function onPageRequest_delete(PageRequestEvent $event) {
global $user, $page;
if ($user->can("delete_comment")) {
// FIXME: post, not args
if ($event->count_args() === 3) {
send_event(new CommentDeletionEvent($event->get_arg(1)));
flash_message("Deleted comment");
$page->set_mode("redirect");
if (!empty($_SERVER['HTTP_REFERER'])) {
$page->set_redirect($_SERVER['HTTP_REFERER']);
} else {
$page->set_redirect(make_link("post/view/" . $event->get_arg(2)));
}
}
} else {
$this->theme->display_permission_denied();
}
}
private function onPageRequest_bulk_delete() {
global $user, $database, $page;
if ($user->can("delete_comment") && !empty($_POST["ip"])) {
$ip = $_POST['ip'];
$comment_ids = $database->get_col("
SELECT id
FROM comments
WHERE owner_ip=:ip
", array("ip" => $ip));
$num = count($comment_ids);
log_warning("comment", "Deleting $num comments from $ip");
foreach($comment_ids as $cid) {
send_event(new CommentDeletionEvent($cid));
}
flash_message("Deleted $num comments");
$page->set_mode("redirect");
$page->set_redirect(make_link("admin"));
} else {
$this->theme->display_permission_denied();
}
}
private function onPageRequest_list(PageRequestEvent $event) {
$page_num = int_escape($event->get_arg(1));
$this->build_page($page_num);
}
private function onPageRequest_beta_search(PageRequestEvent $event) {
$search = $event->get_arg(1);
$page_num = int_escape($event->get_arg(2));
$duser = User::by_name($search);
$i_comment_count = Comment::count_comments_by_user($duser);
$com_per_page = 50;
$total_pages = ceil($i_comment_count / $com_per_page);
$page_num = clamp($page_num, 1, $total_pages);
$comments = $this->get_user_comments($duser->id, $com_per_page, ($page_num - 1) * $com_per_page);
$this->theme->display_all_user_comments($comments, $page_num, $total_pages, $duser);
}
public function onAdminBuilding(AdminBuildingEvent $event) {
$this->theme->display_admin_block();
}
@ -264,7 +285,10 @@ class CommentList extends Extension {
public function onCommentDeletion(CommentDeletionEvent $event) {
global $database;
$database->Execute("DELETE FROM comments WHERE id=:comment_id", array("comment_id"=>$event->comment_id));
$database->Execute("
DELETE FROM comments
WHERE id=:comment_id
", array("comment_id"=>$event->comment_id));
log_info("comment", "Deleting Comment #{$event->comment_id}");
}
@ -328,38 +352,32 @@ class CommentList extends Extension {
") / 10);
$database->cache->set("comment_pages", $total_pages, 600);
}
if(is_null($current_page) || $current_page <= 0) {
$current_page = 1;
}
$current_page = $this->sanity_check_pagenumber($current_page, $total_pages);
$total_pages = max($total_pages, 1);
$current_page = clamp($current_page, 1, $total_pages);
$threads_per_page = 10;
$start = $threads_per_page * ($current_page - 1);
$get_threads = "
$result = $database->Execute("
SELECT image_id,MAX(posted) AS latest
FROM comments
$where
GROUP BY image_id
ORDER BY latest DESC
LIMIT :limit OFFSET :offset
";
$result = $database->Execute($get_threads, array("limit"=>$threads_per_page, "offset"=>$start));
", array("limit"=>$threads_per_page, "offset"=>$start));
if(ext_is_live("Ratings")) {
$user_ratings = Ratings::get_user_privs($user);
} else {
$user_ratings = "";
}
$user_ratings = ext_is_live("Ratings") ? Ratings::get_user_privs($user) : "";
$images = array();
while($row = $result->fetch()) {
$image = Image::by_id($row["image_id"]);
if(ext_is_live("Ratings") && !is_null($image)) {
if(strpos($user_ratings, $image->rating) === FALSE) {
$image = null; // this is "clever", I may live to regret it
}
if(
ext_is_live("Ratings") && !is_null($image) &&
strpos($user_ratings, $image->rating) === FALSE
) {
$image = null; // this is "clever", I may live to regret it
}
if(!is_null($image)) {
$comments = $this->get_comments($image->id);
@ -373,22 +391,13 @@ class CommentList extends Extension {
// get comments {{{
/**
* @param int $count
* @return array
* @param string $query
* @param array $args
* @return Comment[]
*/
private function get_recent_comments($count) {
private function get_generic_comments($query, $args) {
global $database;
$rows = $database->get_all("
SELECT
users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class,
comments.comment as comment, comments.id as comment_id,
comments.image_id as image_id, comments.owner_ip as poster_ip,
comments.posted as posted
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
ORDER BY comments.id DESC
LIMIT :limit
", array("limit"=>$count));
$rows = $database->get_all($query, $args);
$comments = array();
foreach($rows as $row) {
$comments[] = new Comment($row);
@ -396,60 +405,68 @@ class CommentList extends Extension {
return $comments;
}
/**
* @param int $count
* @return Comment[]
*/
private function get_recent_comments($count) {
return $this->get_generic_comments("
SELECT
users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class,
comments.comment as comment, comments.id as comment_id,
comments.image_id as image_id, comments.owner_ip as poster_ip,
comments.posted as posted
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
ORDER BY comments.id DESC
LIMIT :limit
", array("limit"=>$count));
}
/**
* @param int $user_id
* @param int $count
* @param int $offset
* @return array
* @return Comment[]
*/
private function get_user_comments(/*int*/ $user_id, /*int*/ $count, /*int*/ $offset=0) {
global $database;
$rows = $database->get_all("
SELECT
return $this->get_generic_comments("
SELECT
users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class,
comments.comment as comment, comments.id as comment_id,
comments.image_id as image_id, comments.owner_ip as poster_ip,
comments.posted as posted
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
WHERE users.id = :user_id
ORDER BY comments.id DESC
LIMIT :limit OFFSET :offset
", array("user_id"=>$user_id, "offset"=>$offset, "limit"=>$count));
$comments = array();
foreach($rows as $row) {
$comments[] = new Comment($row);
}
return $comments;
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
WHERE users.id = :user_id
ORDER BY comments.id DESC
LIMIT :limit OFFSET :offset
", array("user_id"=>$user_id, "offset"=>$offset, "limit"=>$count));
}
/**
* @param int $image_id
* @return array
* @return Comment[]
*/
private function get_comments(/*int*/ $image_id) {
global $database;
$i_image_id = int_escape($image_id);
$rows = $database->get_all("
SELECT
return $this->get_generic_comments("
SELECT
users.id as user_id, users.name as user_name, users.email as user_email, users.class as user_class,
comments.comment as comment, comments.id as comment_id,
comments.image_id as image_id, comments.owner_ip as poster_ip,
comments.posted as posted
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
WHERE comments.image_id=:image_id
ORDER BY comments.id ASC
", array("image_id"=>$i_image_id));
$comments = array();
foreach($rows as $row) {
$comments[] = new Comment($row);
}
return $comments;
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
WHERE comments.image_id=:image_id
ORDER BY comments.id ASC
", array("image_id"=>$image_id));
}
// }}}
// add / remove / edit comments {{{
/**
* @return bool
*/
private function is_comment_limit_hit() {
global $config, $database;
@ -463,9 +480,11 @@ class CommentList extends Extension {
else $window_sql = "interval '$window minute'";
// window doesn't work as an SQL param because it's inside quotes >_<
$result = $database->get_all("SELECT * FROM comments WHERE owner_ip = :remote_ip ".
"AND posted > now() - $window_sql",
Array("remote_ip"=>$_SERVER['REMOTE_ADDR']));
$result = $database->get_all("
SELECT *
FROM comments
WHERE owner_ip = :remote_ip AND posted > now() - $window_sql
", array("remote_ip"=>$_SERVER['REMOTE_ADDR']));
return (count($result) >= $max);
}
@ -483,6 +502,8 @@ class CommentList extends Extension {
* many times.
*
* FIXME: assumes comments are posted via HTTP...
*
* @return string
*/
public static function get_hash() {
return md5($_SERVER['REMOTE_ADDR'] . date("%Y%m%d"));
@ -537,28 +558,14 @@ class CommentList extends Extension {
*/
private function is_dupe(/*int*/ $image_id, /*string*/ $comment) {
global $database;
return ($database->get_row("SELECT * FROM comments WHERE image_id=:image_id AND comment=:comment", array("image_id"=>$image_id, "comment"=>$comment)));
return $database->get_row("
SELECT *
FROM comments
WHERE image_id=:image_id AND comment=:comment
", array("image_id"=>$image_id, "comment"=>$comment));
}
// do some checks
/**
* @param int $pagenum
* @param int $maxpage
* @return int
*/
private function sanity_check_pagenumber(/*int*/ $pagenum, /*int*/ $maxpage){
if (!is_numeric($pagenum)){
$pagenum=1;
}
if ($pagenum>$maxpage){
$pagenum=$maxpage;
}
if ($pagenum<=0){
$pagenum=1;
}
return $pagenum;
}
/**
* @param int $image_id
* @param User $user
@ -588,6 +595,12 @@ class CommentList extends Extension {
log_info("comment", "Comment #$cid added to Image #$image_id: $snippet", false, array("image_id"=>$image_id, "comment_id"=>$cid));
}
/**
* @param int $image_id
* @param User $user
* @param string $comment
* @throws CommentPostingException
*/
private function comment_checks(/*int*/ $image_id, User $user, /*string*/ $comment) {
global $config, $page;

View File

@ -1,19 +1,19 @@
<?php
class CommentListTest extends ShimmiePHPUnitTestCase {
function setUp() {
public function setUp() {
global $config;
parent::setUp();
$config->set_int("comment_limit", 100);
$this->log_out();
}
function tearDown() {
public function tearDown() {
global $config;
$config->set_int("comment_limit", 10);
parent::tearDown();
}
function testCommentsPage() {
public function testCommentsPage() {
global $user;
$this->log_in_as_user();
@ -85,8 +85,9 @@ class CommentListTest extends ShimmiePHPUnitTestCase {
$this->assert_no_text('ASDFASDF');
}
/*
function testSingleDel() {
public function testSingleDel() {
$this->markTestIncomplete();
$this->log_in_as_admin();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
@ -106,5 +107,4 @@ class CommentListTest extends ShimmiePHPUnitTestCase {
$this->delete_image($image_id);
$this->log_out();
}
*/
}

View File

@ -55,360 +55,46 @@ class DanbooruApi extends Extension {
}
// Danbooru API
private function api_danbooru(PageRequestEvent $event)
{
private function api_danbooru(PageRequestEvent $event) {
global $page;
global $config;
global $database;
global $user;
$page->set_mode("data");
$page->set_type("application/xml");
//debug
//$page->set_type("text/plain");
$results = array();
$danboorup_kludge=1; // danboorup for firefox makes broken links out of location: /path
/*
add_post()
Adds a post to the database.
Parameters
* login: login
* password: password
* file: file as a multipart form
* source: source url
* title: title **IGNORED**
* tags: list of tags as a string, delimited by whitespace
* md5: MD5 hash of upload in hexadecimal format
* rating: rating of the post. can be explicit, questionable, or safe. **IGNORED**
Notes
* The only necessary parameter is tags and either file or source.
* If you want to sign your post, you need a way to authenticate your account, either by supplying login and password, or by supplying a cookie.
* If an account is not supplied or if it doesn‘t authenticate, he post will be added anonymously.
* If the md5 parameter is supplied and does not match the hash of what‘s on the server, the post is rejected.
Response
The response depends on the method used:
Post
* X-Danbooru-Location set to the URL for newly uploaded post.
Get
* Redirected to the newly uploaded post.
*/
if(($event->get_arg(1) == 'add_post') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'create.xml')))
{
if(($event->get_arg(1) == 'add_post') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'create.xml'))) {
// No XML data is returned from this function
$page->set_type("text/plain");
// Check first if a login was supplied, if it wasn't check if the user is logged in via cookie
// If all that fails, it's an anonymous upload
$this->authenticate_user();
// Now we check if a file was uploaded or a url was provided to transload
// Much of this code is borrowed from /ext/upload
if($user->can("create_image"))
{
if(isset($_FILES['file']))
{ // A file was POST'd in
$file = $_FILES['file']['tmp_name'];
$filename = $_FILES['file']['name'];
// If both a file is posted and a source provided, I'm assuming source is the source of the file
if(isset($_REQUEST['source']) && !empty($_REQUEST['source']))
{
$source = $_REQUEST['source'];
} else
{
$source = null;
}
} elseif(isset($_FILES['post']))
{
$file = $_FILES['post']['tmp_name']['file'];
$filename = $_FILES['post']['name']['file'];
if(isset($_REQUEST['post']['source']) && !empty($_REQUEST['post']['source']))
{
$source = $_REQUEST['post']['source'];
} else
{
$source = null;
}
} elseif(isset($_REQUEST['source']) || isset($_REQUEST['post']['source']))
{ // A url was provided
$url = isset($_REQUEST['source']) ? $_REQUEST['source'] : $_REQUEST['post']['source'];
$source = $url;
$tmp_filename = tempnam("/tmp", "shimmie_transload");
// Are we using fopen wrappers or curl?
if($config->get_string("transload_engine") == "fopen")
{
$fp = fopen($url, "r");
if(!$fp) {
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: fopen read error");
}
$data = "";
$length = 0;
while(!feof($fp) && $length <= $config->get_int('upload_size'))
{
$data .= fread($fp, 8192);
$length = strlen($data);
}
fclose($fp);
$fp = fopen($tmp_filename, "w");
fwrite($fp, $data);
fclose($fp);
}
if($config->get_string("transload_engine") == "curl")
{
$ch = curl_init($url);
$fp = fopen($tmp_filename, "w");
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
fclose($fp);
}
$file = $tmp_filename;
$filename = basename($url);
} else
{ // Nothing was specified at all
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: no input files");
return;
}
// Get tags out of url
$posttags = Tag::explode(isset($_REQUEST['tags']) ? $_REQUEST['tags'] : $_REQUEST['post']['tags']);
$hash = md5_file($file);
// Was an md5 supplied? Does it match the file hash?
if(isset($_REQUEST['md5']))
{
if(strtolower($_REQUEST['md5']) != $hash)
{
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: md5 mismatch");
return;
}
}
// Upload size checking is now performed in the upload extension
// It is also currently broken due to some confusion over file variable ($tmp_filename?)
// Does it exist already?
$existing = Image::by_hash($hash);
if(!is_null($existing)) {
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: duplicate");
$existinglink = make_link("post/view/" . $existing->id);
if($danboorup_kludge) $existinglink=make_http($existinglink);
$page->add_http_header("X-Danbooru-Location: $existinglink");
return; // wut!
}
// Fire off an event which should process the new file and add it to the db
$fileinfo = pathinfo($filename);
$metadata = array();
$metadata['filename'] = $fileinfo['basename'];
$metadata['extension'] = $fileinfo['extension'];
$metadata['tags'] = $posttags;
$metadata['source'] = $source;
//log_debug("danbooru_api","========== NEW($filename) =========");
//log_debug("danbooru_api", "upload($filename): fileinfo(".var_export($fileinfo,TRUE)."), metadata(".var_export($metadata,TRUE).")...");
try {
$nevent = new DataUploadEvent($file, $metadata);
//log_debug("danbooru_api", "send_event(".var_export($nevent,TRUE).")");
send_event($nevent);
// If it went ok, grab the id for the newly uploaded image and pass it in the header
$newimg = Image::by_hash($hash); // FIXME: Unsupported file doesn't throw an error?
$newid = make_link("post/view/" . $newimg->id);
if($danboorup_kludge) $newid=make_http($newid);
// Did we POST or GET this call?
if($_SERVER['REQUEST_METHOD'] == 'POST')
{
$page->add_http_header("X-Danbooru-Location: $newid");
}
else
$page->add_http_header("Location: $newid");
}
catch(UploadException $ex) {
// Did something screw up?
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: exception - " . $ex->getMessage());
return;
}
} else
{
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: authentication error");
return;
}
$this->api_add_post();
}
/*
find_posts()
Find all posts that match the search criteria. Posts will be ordered by id descending.
Parameters
* md5: md5 hash to search for (comma delimited)
* id: id to search for (comma delimited)
* tags: what tags to search for
* limit: limit
* page: page number
* after_id: limit results to posts added after this id
*/
if(($event->get_arg(1) == 'find_posts') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'index.xml')))
{
$this->authenticate_user();
$start = 0;
if(isset($_GET['md5']))
{
$md5list = explode(",",$_GET['md5']);
foreach($md5list as $md5)
{
$results[] = Image::by_hash($md5);
}
$count = count($results);
} elseif(isset($_GET['id']))
{
$idlist = explode(",",$_GET['id']);
foreach($idlist as $id)
{
$results[] = Image::by_id($id);
}
$count = count($results);
} else
{
$limit = isset($_GET['limit']) ? int_escape($_GET['limit']) : 100;
// Calculate start offset.
if (isset($_GET['page'])) // Danbooru API uses 'page' >= 1
$start = (int_escape($_GET['page'])-1) * $limit;
else if (isset($_GET['pid'])) // Gelbooru API uses 'pid' >= 0
$start = int_escape($_GET['pid']) * $limit;
else
$start = 0;
$tags = isset($_GET['tags']) ? Tag::explode($_GET['tags']) : array();
$count = Image::count_images($tags);
$results = Image::find_images(max($start, 0), min($limit, 100), $tags);
}
// Now we have the array $results filled with Image objects
// Let's display them
$xml = "<posts count=\"{$count}\" offset=\"{$start}\">\n";
foreach($results as $img)
{
// Sanity check to see if $img is really an image object
// If it isn't (e.g. someone requested an invalid md5 or id), break out of the this
if(!is_object($img))
continue;
$taglist = $img->get_tag_list();
$owner = $img->get_owner();
$previewsize = get_thumbnail_size($img->width, $img->height);
$xml .= xml_tag("post", array(
"id" => $img->id,
"md5" => $img->hash,
"file_name" => $img->filename,
"file_url" => $img->get_image_link(),
"height" => $img->height,
"width" => $img->width,
"preview_url" => $img->get_thumb_link(),
"preview_height" => $previewsize[1],
"preview_width" => $previewsize[0],
"rating" => "u",
"date" => $img->posted,
"is_warehoused" => false,
"tags" => $taglist,
"source" => $img->source,
"score" => 0,
"author" => $owner->name
));
}
$xml .= "</posts>";
$page->set_data($xml);
elseif(($event->get_arg(1) == 'find_posts') || (($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'index.xml'))) {
$page->set_type("application/xml");
$page->set_data($this->api_find_posts());
}
/*
find_tags() Find all tags that match the search criteria.
Parameters
* id: A comma delimited list of tag id numbers.
* name: A comma delimited list of tag names.
* tags: any typical tag query. See Tag#parse_query for details.
* after_id: limit results to tags with an id number after after_id. Useful if you only want to refresh
*/
if($event->get_arg(1) == 'find_tags') {
if(isset($_GET['id'])) {
$idlist = explode(",",$_GET['id']);
foreach($idlist as $id) {
$sqlresult = $database->get_all(
"SELECT id,tag,count FROM tags WHERE id = ?",
array($id));
foreach($sqlresult as $row) {
$results[] = array($row['count'], $row['tag'], $row['id']);
}
}
}
elseif(isset($_GET['name'])) {
$namelist = explode(",",$_GET['name']);
foreach($namelist as $name) {
$sqlresult = $database->get_all(
"SELECT id,tag,count FROM tags WHERE tag = ?",
array($name));
foreach($sqlresult as $row) {
$results[] = array($row['count'], $row['tag'], $row['id']);
}
}
}
/* Currently disabled to maintain identical functionality to danbooru 1.0's own "broken" find_tags
elseif(isset($_GET['tags'])) {
$start = isset($_GET['after_id']) ? int_escape($_GET['offset']) : 0;
$tags = Tag::explode($_GET['tags']);
}
*/
else {
$start = isset($_GET['after_id']) ? int_escape($_GET['offset']) : 0;
$sqlresult = $database->get_all(
"SELECT id,tag,count FROM tags WHERE count > 0 AND id >= ? ORDER BY id DESC",
array($start));
foreach($sqlresult as $row) {
$results[] = array($row['count'], $row['tag'], $row['id']);
}
}
// Tag results collected, build XML output
$xml = "<tags>\n";
foreach($results as $tag) {
$xml .= "<tag type=\"0\" count=\"$tag[0]\" name=\"" . $this->xmlspecialchars($tag[1]) . "\" id=\"$tag[2]\"/>\n";
}
$xml .= "</tags>";
$page->set_data($xml);
elseif($event->get_arg(1) == 'find_tags') {
$page->set_type("application/xml");
$page->set_data($this->api_find_tags());
}
// Hackery for danbooruup 0.3.2 providing the wrong view url. This simply redirects to the proper
// Shimmie view page
// Example: danbooruup says the url is http://shimmie/api/danbooru/post/show/123
// This redirects that to http://shimmie/post/view/123
if(($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show')) {
elseif(($event->get_arg(1) == 'post') && ($event->get_arg(2) == 'show')) {
$fixedlocation = make_link("post/view/" . $event->get_arg(3));
$page->set_mode("redirect");
$page->set_redirect($fixedlocation);
}
}
// Turns out I use this a couple times so let's make it a utility function
// Authenticates a user based on the contents of the login and password parameters
// or makes them anonymous. Does not set any cookies or anything permanent.
private function authenticate_user()
{
global $config;
global $user;
/**
* Turns out I use this a couple times so let's make it a utility function
* Authenticates a user based on the contents of the login and password parameters
* or makes them anonymous. Does not set any cookies or anything permanent.
*/
private function authenticate_user() {
global $config, $user;
if(isset($_REQUEST['login']) && isset($_REQUEST['password']))
{
if(isset($_REQUEST['login']) && isset($_REQUEST['password'])) {
// Get this user from the db, if it fails the user becomes anonymous
// Code borrowed from /ext/user
$name = $_REQUEST['login'];
@ -416,18 +102,294 @@ class DanbooruApi extends Extension {
$duser = User::by_name_and_pass($name, $pass);
if(!is_null($duser)) {
$user = $duser;
} else
{
}
else {
$user = User::by_id($config->get_int("anon_id", 0));
}
}
}
// From htmlspecialchars man page on php.net comments
// If tags contain quotes they need to be htmlified
private function xmlspecialchars($text)
{
return str_replace('&#039;', '&apos;', htmlspecialchars($text, ENT_QUOTES));
/**
* find_tags()
* Find all tags that match the search criteria.
*
* Parameters
* - id: A comma delimited list of tag id numbers.
* - name: A comma delimited list of tag names.
* - tags: any typical tag query. See Tag#parse_query for details.
* - after_id: limit results to tags with an id number after after_id. Useful if you only want to refresh
*
* @return string
*/
private function api_find_tags() {
global $database;
$results = array();
if(isset($_GET['id'])) {
$idlist = explode(",", $_GET['id']);
foreach ($idlist as $id) {
$sqlresult = $database->get_all(
"SELECT id,tag,count FROM tags WHERE id = ?",
array($id));
foreach ($sqlresult as $row) {
$results[] = array($row['count'], $row['tag'], $row['id']);
}
}
}
elseif(isset($_GET['name'])) {
$namelist = explode(",", $_GET['name']);
foreach ($namelist as $name) {
$sqlresult = $database->get_all(
"SELECT id,tag,count FROM tags WHERE tag = ?",
array($name));
foreach ($sqlresult as $row) {
$results[] = array($row['count'], $row['tag'], $row['id']);
}
}
}
// Currently disabled to maintain identical functionality to danbooru 1.0's own "broken" find_tags
elseif(false && isset($_GET['tags'])) {
$start = isset($_GET['after_id']) ? int_escape($_GET['offset']) : 0;
$tags = Tag::explode($_GET['tags']);
}
else {
$start = isset($_GET['after_id']) ? int_escape($_GET['offset']) : 0;
$sqlresult = $database->get_all(
"SELECT id,tag,count FROM tags WHERE count > 0 AND id >= ? ORDER BY id DESC",
array($start));
foreach ($sqlresult as $row) {
$results[] = array($row['count'], $row['tag'], $row['id']);
}
}
// Tag results collected, build XML output
$xml = "<tags>\n";
foreach ($results as $tag) {
$xml .= xml_tag("tag", array(
"type" => "0",
"counts" => $tag[0],
"name" => $tag[1],
"id" => $tag[2],
));
}
$xml .= "</tags>";
return $xml;
}
/**
* find_posts()
* Find all posts that match the search criteria. Posts will be ordered by id descending.
*
* Parameters:
* - md5: md5 hash to search for (comma delimited)
* - id: id to search for (comma delimited)
* - tags: what tags to search for
* - limit: limit
* - page: page number
* - after_id: limit results to posts added after this id
*
* @return string
* @throws SCoreException
*/
private function api_find_posts() {
$results = array();
$this->authenticate_user();
$start = 0;
if(isset($_GET['md5'])) {
$md5list = explode(",", $_GET['md5']);
foreach ($md5list as $md5) {
$results[] = Image::by_hash($md5);
}
$count = count($results);
}
elseif(isset($_GET['id'])) {
$idlist = explode(",", $_GET['id']);
foreach ($idlist as $id) {
$results[] = Image::by_id($id);
}
$count = count($results);
}
else {
$limit = isset($_GET['limit']) ? int_escape($_GET['limit']) : 100;
// Calculate start offset.
if (isset($_GET['page'])) // Danbooru API uses 'page' >= 1
$start = (int_escape($_GET['page']) - 1) * $limit;
else if (isset($_GET['pid'])) // Gelbooru API uses 'pid' >= 0
$start = int_escape($_GET['pid']) * $limit;
else
$start = 0;
$tags = isset($_GET['tags']) ? Tag::explode($_GET['tags']) : array();
$count = Image::count_images($tags);
$results = Image::find_images(max($start, 0), min($limit, 100), $tags);
}
// Now we have the array $results filled with Image objects
// Let's display them
$xml = "<posts count=\"{$count}\" offset=\"{$start}\">\n";
foreach ($results as $img) {
// Sanity check to see if $img is really an image object
// If it isn't (e.g. someone requested an invalid md5 or id), break out of the this
if (!is_object($img))
continue;
$taglist = $img->get_tag_list();
$owner = $img->get_owner();
$previewsize = get_thumbnail_size($img->width, $img->height);
$xml .= xml_tag("post", array(
"id" => $img->id,
"md5" => $img->hash,
"file_name" => $img->filename,
"file_url" => $img->get_image_link(),
"height" => $img->height,
"width" => $img->width,
"preview_url" => $img->get_thumb_link(),
"preview_height" => $previewsize[1],
"preview_width" => $previewsize[0],
"rating" => "u",
"date" => $img->posted,
"is_warehoused" => false,
"tags" => $taglist,
"source" => $img->source,
"score" => 0,
"author" => $owner->name
));
}
$xml .= "</posts>";
return $xml;
}
/**
* add_post()
* Adds a post to the database.
*
* Parameters:
* - login: login
* - password: password
* - file: file as a multipart form
* - source: source url
* - title: title **IGNORED**
* - tags: list of tags as a string, delimited by whitespace
* - md5: MD5 hash of upload in hexadecimal format
* - rating: rating of the post. can be explicit, questionable, or safe. **IGNORED**
*
* Notes:
* - The only necessary parameter is tags and either file or source.
* - If you want to sign your post, you need a way to authenticate your account, either by supplying login and password, or by supplying a cookie.
* - If an account is not supplied or if it doesn‘t authenticate, he post will be added anonymously.
* - If the md5 parameter is supplied and does not match the hash of what‘s on the server, the post is rejected.
*
* Response
* The response depends on the method used:
* Post:
* - X-Danbooru-Location set to the URL for newly uploaded post.
* Get:
* - Redirected to the newly uploaded post.
*/
private function api_add_post() {
global $user, $config, $page;
$danboorup_kludge = 1; // danboorup for firefox makes broken links out of location: /path
// Check first if a login was supplied, if it wasn't check if the user is logged in via cookie
// If all that fails, it's an anonymous upload
$this->authenticate_user();
// Now we check if a file was uploaded or a url was provided to transload
// Much of this code is borrowed from /ext/upload
if (!$user->can("create_image")) {
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: authentication error");
return;
}
if (isset($_FILES['file'])) { // A file was POST'd in
$file = $_FILES['file']['tmp_name'];
$filename = $_FILES['file']['name'];
// If both a file is posted and a source provided, I'm assuming source is the source of the file
if (isset($_REQUEST['source']) && !empty($_REQUEST['source'])) {
$source = $_REQUEST['source'];
} else {
$source = null;
}
} elseif (isset($_FILES['post'])) {
$file = $_FILES['post']['tmp_name']['file'];
$filename = $_FILES['post']['name']['file'];
if (isset($_REQUEST['post']['source']) && !empty($_REQUEST['post']['source'])) {
$source = $_REQUEST['post']['source'];
} else {
$source = null;
}
} elseif (isset($_REQUEST['source']) || isset($_REQUEST['post']['source'])) { // A url was provided
$source = isset($_REQUEST['source']) ? $_REQUEST['source'] : $_REQUEST['post']['source'];
$file = tempnam("/tmp", "shimmie_transload");
$ok = transload($source, $file);
if (!$ok) {
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: fopen read error");
return;
}
$filename = basename($source);
} else { // Nothing was specified at all
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: no input files");
return;
}
// Get tags out of url
$posttags = Tag::explode(isset($_REQUEST['tags']) ? $_REQUEST['tags'] : $_REQUEST['post']['tags']);
// Was an md5 supplied? Does it match the file hash?
$hash = md5_file($file);
if (isset($_REQUEST['md5']) && strtolower($_REQUEST['md5']) != $hash) {
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: md5 mismatch");
return;
}
// Upload size checking is now performed in the upload extension
// It is also currently broken due to some confusion over file variable ($tmp_filename?)
// Does it exist already?
$existing = Image::by_hash($hash);
if (!is_null($existing)) {
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: duplicate");
$existinglink = make_link("post/view/" . $existing->id);
if ($danboorup_kludge) $existinglink = make_http($existinglink);
$page->add_http_header("X-Danbooru-Location: $existinglink");
return;
}
// Fire off an event which should process the new file and add it to the db
$fileinfo = pathinfo($filename);
$metadata = array();
$metadata['filename'] = $fileinfo['basename'];
$metadata['extension'] = $fileinfo['extension'];
$metadata['tags'] = $posttags;
$metadata['source'] = $source;
//log_debug("danbooru_api","========== NEW($filename) =========");
//log_debug("danbooru_api", "upload($filename): fileinfo(".var_export($fileinfo,TRUE)."), metadata(".var_export($metadata,TRUE).")...");
try {
$nevent = new DataUploadEvent($file, $metadata);
//log_debug("danbooru_api", "send_event(".var_export($nevent,TRUE).")");
send_event($nevent);
// If it went ok, grab the id for the newly uploaded image and pass it in the header
$newimg = Image::by_hash($hash); // FIXME: Unsupported file doesn't throw an error?
$newid = make_link("post/view/" . $newimg->id);
if ($danboorup_kludge) $newid = make_http($newid);
// Did we POST or GET this call?
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$page->add_http_header("X-Danbooru-Location: $newid");
} else {
$page->add_http_header("Location: $newid");
}
} catch (UploadException $ex) {
// Did something screw up?
$page->set_code(409);
$page->add_http_header("X-Danbooru-Errors: exception - " . $ex->getMessage());
}
}
}

View File

@ -1,6 +1,6 @@
<?php
class DanbooruApiTest extends ShimmiePHPUnitTestCase {
function testSearch() {
public function testSearch() {
$this->log_in_as_admin();
$image_id = $this->post_image("tests/bedroom_workshop.jpg", "data");

View File

@ -1,11 +1,11 @@
<?php
class DowntimeTest extends ShimmiePHPUnitTestCase {
function tearDown() {
public function tearDown() {
global $config;
$config->set_bool("downtime", false);
}
function testDowntime() {
public function testDowntime() {
global $config;
$config->set_string("downtime_message", "brb, unit testing");

View File

@ -1,6 +1,6 @@
<?php
class EmoticonTest extends ShimmiePHPUnitTestCase {
function testEmoticons() {
public function testEmoticons() {
global $user;
$this->log_in_as_user();

View File

@ -1,6 +1,6 @@
<?php
class ETTest extends ShimmiePHPUnitTestCase {
function testET() {
public function testET() {
$this->log_in_as_admin();
$this->get_page("system_info");
$this->assert_title("System Info");

View File

@ -23,7 +23,7 @@ class ExtensionInfo {
var $description, $documentation, $version, $visibility;
var $enabled;
function __construct($main) {
public function __construct($main) {
$matches = array();
$lines = file($main);
$number_of_lines = count($lines);
@ -37,26 +37,26 @@ class ExtensionInfo {
if(preg_match("/Name: (.*)/", $line, $matches)) {
$this->name = $matches[1];
}
if(preg_match("/Visibility: (.*)/", $line, $matches)) {
else if(preg_match("/Visibility: (.*)/", $line, $matches)) {
$this->visibility = $matches[1];
}
if(preg_match("/Link: (.*)/", $line, $matches)) {
else if(preg_match("/Link: (.*)/", $line, $matches)) {
$this->link = $matches[1];
if($this->link[0] == "/") {
$this->link = make_link(substr($this->link, 1));
}
}
if(preg_match("/Version: (.*)/", $line, $matches)) {
else if(preg_match("/Version: (.*)/", $line, $matches)) {
$this->version = $matches[1];
}
if(preg_match("/Author: (.*) [<\(](.*@.*)[>\)]/", $line, $matches)) {
else if(preg_match("/Author: (.*) [<\(](.*@.*)[>\)]/", $line, $matches)) {
$this->author = $matches[1];
$this->email = $matches[2];
}
else if(preg_match("/Author: (.*)/", $line, $matches)) {
$this->author = $matches[1];
}
if(preg_match("/(.*)Description: ?(.*)/", $line, $matches)) {
else if(preg_match("/(.*)Description: ?(.*)/", $line, $matches)) {
$this->description = $matches[2];
$start = $matches[1]." ";
$start_len = strlen($start);
@ -65,7 +65,7 @@ class ExtensionInfo {
$i++;
}
}
if(preg_match("/(.*)Documentation: ?(.*)/", $line, $matches)) {
else if(preg_match("/(.*)Documentation: ?(.*)/", $line, $matches)) {
$this->documentation = $matches[2];
$start = $matches[1]." ";
$start_len = strlen($start);
@ -75,7 +75,7 @@ class ExtensionInfo {
}
$this->documentation = str_replace('$site', make_http(get_base_href()), $this->documentation);
}
if(preg_match("/\*\//", $line, $matches)) {
else if(preg_match("/\*\//", $line, $matches)) {
break;
}
}
@ -156,7 +156,7 @@ class ExtManager extends Extension {
/**
* @param bool $all
* @return array
* @return ExtensionInfo[]
*/
private function get_extensions(/*bool*/ $all) {
$extensions = array();

View File

@ -1,6 +1,6 @@
<?php
class ExtManagerTest extends ShimmiePHPUnitTestCase {
function testAuth() {
public function testAuth() {
$this->get_page('ext_manager');
$this->assert_title("Extensions");

View File

@ -204,7 +204,7 @@ class Favorites extends Extension {
/**
* @param Image $image
* @return array
* @return string[]
*/
private function list_persons_who_have_favorited(Image $image) {
global $database;

View File

@ -1,6 +1,6 @@
<?php
class FavoritesTest extends ShimmiePHPUnitTestCase {
function testFavorites() {
public function testFavorites() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "test");

View File

@ -1,6 +1,6 @@
<?php
class FeaturedTest extends ShimmiePHPUnitTestCase {
function testFeatured() {
public function testFeatured() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");

View File

@ -1,6 +1,6 @@
<?php
class Handle404Test extends ShimmiePHPUnitTestCase {
function test404Handler() {
public function test404Handler() {
$this->get_page('not/a/page');
// most descriptive error first
$this->assert_text("No handler could be found for the page 'not/a/page'");

View File

@ -44,7 +44,7 @@ class ArchiveFileHandler extends Extension {
}
/**
* @param $ext
* @param string $ext
* @return bool
*/
private function supported_ext($ext) {

View File

@ -50,7 +50,7 @@ class FlashFileHandler extends DataHandlerExtension {
}
/**
* @param $file
* @param string $file
* @return bool
*/
protected function check_contents(/*string*/ $file) {

View File

@ -50,7 +50,7 @@ class IcoFileHandler extends Extension {
}
/**
* @param $ext
* @param string $ext
* @return bool
*/
private function supported_ext($ext) {
@ -59,8 +59,8 @@ class IcoFileHandler extends Extension {
}
/**
* @param $filename
* @param $metadata
* @param string $filename
* @param mixed[] $metadata
* @return Image
*/
private function create_image_from_data($filename, $metadata) {

View File

@ -1,6 +1,6 @@
<?php
class IcoHandlerTest extends ShimmiePHPUnitTestCase {
function testIcoHander() {
public function testIcoHander() {
$this->log_in_as_user();
$image_id = $this->post_image("lib/static/favicon.ico", "shimmie favicon");
$this->get_page("post/view/$image_id"); // test for no crash

View File

@ -26,7 +26,7 @@ class MP3FileHandler extends DataHandlerExtension {
/**
* @param string $filename
* @param array $metadata
* @param mixed[] $metadata
* @return Image|null
*/
protected function create_image_from_data($filename, $metadata) {

View File

@ -67,7 +67,7 @@ class PixelFileHandler extends DataHandlerExtension {
}
/**
* @param $hash
* @param string $hash
* @return bool
*/
protected function create_thumb_force(/*string*/ $hash) {
@ -91,9 +91,6 @@ class PixelFileHandler extends DataHandlerExtension {
return $ok;
}
/**
* @param ImageAdminBlockBuildingEvent $event
*/
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) {
$event->add_part("
<form>

View File

@ -1,6 +1,6 @@
<?php
class PixelHandlerTest extends ShimmiePHPUnitTestCase {
function testPixelHander() {
public function testPixelHander() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
//$this->assert_response(302);

View File

@ -51,7 +51,7 @@ class SVGFileHandler extends Extension {
}
/**
* @param $ext
* @param string $ext
* @return bool
*/
private function supported_ext($ext) {
@ -60,8 +60,8 @@ class SVGFileHandler extends Extension {
}
/**
* @param $filename
* @param $metadata
* @param string $filename
* @param mixed[] $metadata
* @return Image
*/
private function create_image_from_data($filename, $metadata) {
@ -82,7 +82,7 @@ class SVGFileHandler extends Extension {
}
/**
* @param $file
* @param string $file
* @return bool
*/
private function check_contents($file) {

View File

@ -1,6 +1,6 @@
<?php
class SVGHandlerTest extends ShimmiePHPUnitTestCase {
function testSVGHander() {
public function testSVGHander() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/test.svg", "something");
$this->get_page("post/view/$image_id"); // test for no crash

View File

@ -118,7 +118,7 @@ class VideoFileHandler extends DataHandlerExtension {
/**
* @param string $filename
* @param array $metadata
* @param mixed[] $metadata
* @return Image|null
*/
protected function create_image_from_data($filename, $metadata) {
@ -162,7 +162,7 @@ class VideoFileHandler extends DataHandlerExtension {
}
/**
* @param $file
* @param string $file
* @return bool
*/
protected function check_contents($file) {

View File

@ -1,6 +1,6 @@
<?php
class HomeTest extends ShimmiePHPUnitTestCase {
function testHomePage() {
public function testHomePage() {
$this->get_page('home');
// FIXME: this page doesn't use blocks; need assert_data_contains

View File

@ -32,6 +32,9 @@ class ImageAdditionEvent extends Event {
class ImageAdditionException extends SCoreException {
var $error;
/**
* @param string $error
*/
public function __construct($error) {
$this->error = $error;
}

View File

@ -13,6 +13,9 @@
class RemoveImageHashBanEvent extends Event {
var $hash;
/**
* @param string $hash
*/
public function __construct($hash) {
$this->hash = $hash;
}
@ -23,6 +26,10 @@ class AddImageHashBanEvent extends Event {
var $hash;
var $reason;
/**
* @param string $hash
* @param string $reason
*/
public function __construct($hash, $reason) {
$this->hash = $hash;
$this->reason = $reason;
@ -126,6 +133,11 @@ class ImageBan extends Extension {
// DB funness
/**
* @param int $page
* @param int $size
* @return array
*/
public function get_image_hash_bans($page, $size=100) {
global $database;

View File

@ -1,6 +1,6 @@
<?php
class HashBanTest extends ShimmiePHPUnitTestCase {
function testBan() {
public function testBan() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
$this->log_out();

View File

@ -253,9 +253,9 @@ class Index extends Extension {
$search_terms = $event->get_search_terms();
$page_number = $event->get_page_number();
$page_size = $event->get_page_size();
$count_search_terms = count($search_terms);
try {
#log_debug("index", "Search for ".implode(" ", $search_terms), false, array("terms"=>$search_terms));
$total_pages = Image::count_pages($search_terms);
@ -277,7 +277,7 @@ class Index extends Extension {
}
$count_images = count($images);
if($count_search_terms === 0 && $count_images === 0 && $page_number === 1) {
$this->theme->display_intro($page);
send_event(new PostListBuildingEvent($search_terms));
@ -322,8 +322,17 @@ class Index extends Extension {
// check for tags first as tag based searches are more common.
if(preg_match("/^tags([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+)$/i", $event->term, $matches)) {
$cmp = ltrim($matches[1], ":") ?: "=";
$tags = $matches[2];
$event->add_querylet(new Querylet('images.id IN (SELECT DISTINCT image_id FROM image_tags GROUP BY image_id HAVING count(image_id) '.$cmp.' '.$tags.')'));
$count = $matches[2];
$event->add_querylet(
new Querylet("EXISTS (
SELECT 1
FROM image_tags it
LEFT JOIN tags t ON it.tag_id = t.id
WHERE images.id = it.image_id
GROUP BY image_id
HAVING COUNT(*) $cmp $count
)")
);
}
else if(preg_match("/^ratio([:]?<|[:]?>|[:]?<=|[:]?>=|[:|=])(\d+):(\d+)$/i", $event->term, $matches)) {
$cmp = preg_replace('/^:/', '=', $matches[1]);
@ -394,4 +403,3 @@ class Index extends Extension {
$this->stpen++;
}
}

View File

@ -1,6 +1,6 @@
<?php
class IndexTest extends ShimmiePHPUnitTestCase {
function testIndexPage() {
public function testIndexPage() {
$this->get_page('post/list');
$this->assert_title("Welcome to Shimmie ".VERSION);
$this->assert_no_text("Prev | Index | Next");
@ -29,7 +29,7 @@ class IndexTest extends ShimmiePHPUnitTestCase {
# FIXME: test search box
}
function testSearches() {
public function testSearches() {
$this->log_in_as_user();
$image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
$image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "computer bedroom workshop");

View File

@ -3,6 +3,11 @@
class IndexTheme extends Themelet {
var $page_number, $total_pages, $search_terms;
/**
* @param int $page_number
* @param int $total_pages
* @param string[] $search_terms
*/
public function set_page($page_number, $total_pages, $search_terms) {
$this->page_number = $page_number;
$this->total_pages = $total_pages;
@ -27,6 +32,10 @@ and of course start organising your images :-)
$page->add_block(new Block("Installation Succeeded!", $text, "main", 0));
}
/**
* @param Page $page
* @param Image[] $images
*/
public function display_page(Page $page, $images) {
$this->display_page_header($page, $images);
@ -41,12 +50,21 @@ and of course start organising your images :-)
}
}
public function display_admin_block(/*array(string)*/ $parts) {
/**
* @param string[] $parts
*/
public function display_admin_block($parts) {
global $page;
$page->add_block(new Block("List Controls", join("<br>", $parts), "left", 50));
}
/**
* @param int $page_number
* @param int $total_pages
* @param string[] $search_terms
* @return string
*/
protected function build_navigation($page_number, $total_pages, $search_terms) {
$prev = $page_number - 1;
$next = $page_number + 1;
@ -72,6 +90,11 @@ and of course start organising your images :-)
return $h_prev.' | '.$h_index.' | '.$h_next.'<br>'.$h_search;
}
/**
* @param Image[] $images
* @param string $query
* @return string
*/
protected function build_table($images, $query) {
$h_query = html_escape($query);
$table = "<div class='shm-image-list' data-query='$h_query'>";
@ -82,6 +105,10 @@ and of course start organising your images :-)
return $table;
}
/**
* @param Page $page
* @param Image[] $images
*/
protected function display_page_header(Page $page, $images) {
global $config;
@ -102,6 +129,10 @@ and of course start organising your images :-)
$page->set_heading($page_title);
}
/**
* @param Page $page
* @param Image[] $images
*/
protected function display_page_images(Page $page, $images) {
if (count($this->search_terms) > 0) {
$query = url_escape(implode(' ', $this->search_terms));

View File

@ -1,6 +1,6 @@
<?php
class IPBanTest extends ShimmiePHPUnitTestCase {
function testIPBan() {
public function testIPBan() {
$this->get_page('ip_ban/list');
$this->assert_response(403);
$this->assert_title("Permission Denied");
@ -9,7 +9,9 @@ class IPBanTest extends ShimmiePHPUnitTestCase {
$this->get_page('ip_ban/list');
$this->assert_no_text("42.42.42.42");
/*
$this->markTestIncomplete();
$this->set_field('ip', '42.42.42.42');
$this->set_field('reason', 'unit testing');
$this->set_field('end', '1 week');
@ -18,7 +20,6 @@ class IPBanTest extends ShimmiePHPUnitTestCase {
$this->assert_text("42.42.42.42");
$this->click("Remove"); // FIXME: remove which ban? :S
$this->assert_no_text("42.42.42.42");
*/
$this->get_page('ip_ban/list?all=on'); // just test it doesn't crash for now

View File

@ -1,6 +1,6 @@
<?php
class LinkImageTest extends ShimmiePHPUnitTestCase {
function testLinkImage() {
public function testLinkImage() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pie");
@ -9,7 +9,8 @@ class LinkImageTest extends ShimmiePHPUnitTestCase {
# in there, see if it takes us to the right page
$this->get_page("post/view/$image_id");
/*
$this->markTestIncomplete();
// FIXME
$matches = array();
preg_match("#value='(http://.*(/|%2F)post(/|%2F)view(/|%2F)[0-9]+)'#", $raw, $matches);
@ -18,7 +19,6 @@ class LinkImageTest extends ShimmiePHPUnitTestCase {
$this->get($matches[1]);
$this->assert_title("Image $image_id: pie");
}
*/
}
}

View File

@ -1,6 +1,6 @@
<?php
class LogDatabaseTest extends ShimmiePHPUnitTestCase {
function testLog() {
public function testLog() {
$this->log_in_as_admin();
$this->get_page("log/view");
$this->get_page("log/view?module=core-image");

View File

@ -16,62 +16,54 @@ class MassTagger extends Extension {
public function onPostListBuilding(PostListBuildingEvent $event) {
global $config, $page, $user;
if( !$user->is_admin() ) return;
$this->theme->display_mass_tagger( $page, $event, $config );
if($user->is_admin()) {
$this->theme->display_mass_tagger( $page, $event, $config );
}
}
public function onPageRequest(PageRequestEvent $event) {
global $config, $page, $user;
if( !$event->page_matches("mass_tagger") ) return;
if( !$user->is_admin() ) return;
if($event->get_arg(0) == "tag") $this->_apply_mass_tags( $config, $page, $user, $event );
}
private function _apply_mass_tags( $config, Page $page, $user, $event ) {
if( !isset($_POST['ids']) or !isset($_POST['tag']) ) return;
$tag = $_POST['tag'];
$tag_array = explode(" ",$tag);
$pos_tag_array = array();
$neg_tag_array = array();
foreach($tag_array as $new_tag) {
if (strpos($new_tag, '-') === 0)
$neg_tag_array[] = substr($new_tag,1);
else
$pos_tag_array[] = $new_tag;
}
$ids = explode( ':', $_POST['ids'] );
$ids = array_filter ( $ids , 'is_numeric' );
$images = array_map( "Image::by_id", $ids );
if(isset($_POST['setadd']) &&
$_POST['setadd'] == 'set')
{
foreach($images as $image) {
$image->set_tags(Tag::explode($tag));
}
}
else
{
foreach($images as $image) {
if (!empty($neg_tag_array)) {
$img_tags = array_merge($pos_tag_array, explode(" ",$image->get_tag_list()));
$img_tags = array_diff($img_tags, $neg_tag_array);
$image->set_tags(Tag::explode($img_tags));
}
global $page, $user;
if($event->page_matches("mass_tagger/tag") && $user->is_admin()) {
if( !isset($_POST['ids']) or !isset($_POST['tag']) ) return;
$tag = $_POST['tag'];
$tag_array = explode(" ",$tag);
$pos_tag_array = array();
$neg_tag_array = array();
foreach($tag_array as $new_tag) {
if (strpos($new_tag, '-') === 0)
$neg_tag_array[] = substr($new_tag,1);
else
$image->set_tags(Tag::explode($tag . " " . $image->get_tag_list()));
$pos_tag_array[] = $new_tag;
}
$ids = explode( ':', $_POST['ids'] );
$ids = array_filter ( $ids , 'is_numeric' );
$images = array_map( "Image::by_id", $ids );
if(isset($_POST['setadd']) && $_POST['setadd'] == 'set') {
foreach($images as $image) {
$image->set_tags(Tag::explode($tag));
}
}
else {
foreach($images as $image) {
if (!empty($neg_tag_array)) {
$img_tags = array_merge($pos_tag_array, explode(" ",$image->get_tag_list()));
$img_tags = array_diff($img_tags, $neg_tag_array);
$image->set_tags(Tag::explode($img_tags));
}
else
$image->set_tags(Tag::explode($tag . " " . $image->get_tag_list()));
}
}
$page->set_mode("redirect");
if(!isset($_SERVER['HTTP_REFERER'])) $_SERVER['HTTP_REFERER'] = make_link();
$page->set_redirect($_SERVER['HTTP_REFERER']);
}
$page->set_mode("redirect");
if(!isset($_SERVER['HTTP_REFERER'])) $_SERVER['HTTP_REFERER'] = make_link();
$page->set_redirect($_SERVER['HTTP_REFERER']);
}
}

View File

@ -28,7 +28,10 @@ class NotATag extends Extension {
$this->scan($event->tags);
}
private function scan(/*array*/ $tags_mixed) {
/**
* @param string[] $tags_mixed
*/
private function scan($tags_mixed) {
global $database;
$tags = array();
@ -90,6 +93,11 @@ class NotATag extends Extension {
}
}
/**
* @param int $page
* @param int $size
* @return array
*/
public function get_untags($page, $size=100) {
global $database;

View File

@ -276,8 +276,7 @@ class Notes extends Extension {
(?, ?, ?, ?, now(), ?, ?, ?, ?, ?)",
array(1, $imageID, $user_id, $_SERVER['REMOTE_ADDR'], $noteX1, $noteY1, $noteHeight, $noteWidth, $noteText));
$result = $database->get_row("SELECT LAST_INSERT_ID() AS noteID", array());
$noteID = $result["noteID"];
$noteID = $database->get_last_insert_id('notes_id_seq');
log_info("notes", "Note added {$noteID} by {$user->name}");
@ -304,9 +303,9 @@ class Notes extends Extension {
(?, ?, now())",
array($image_id, $user_id));
$result = $database->get_row("SELECT LAST_INSERT_ID() AS requestID", array());
$resultID = $database->get_last_insert_id('note_request_id_seq');
log_info("notes", "Note requested {$result["requestID"]} by {$user->name}");
log_info("notes", "Note requested {$requestID} by {$user->name}");
}

View File

@ -13,7 +13,12 @@
class NumericScoreSetEvent extends Event {
var $image_id, $user, $score;
public function __construct(/*int*/ $image_id, User $user, /*int*/ $score) {
/**
* @param int $image_id
* @param User $user
* @param int $score
*/
public function __construct($image_id, User $user, $score) {
$this->image_id = $image_id;
$this->user = $user;
$this->score = $score;
@ -102,15 +107,15 @@ class NumericScore extends Extension {
if(!empty($_GET['day'])){
$D = (int) $_GET['day'];
if($D >= 1 && $D <= 31) $day = $D;
$day = clamp($D, 1, 31);
}
if(!empty($_GET['month'])){
$M = (int) $_GET['month'];
if($M >= 1 && $M <= 12) $month = $M;
$month = clamp($M, 1 ,12);
}
if(!empty($_GET['year'])){
$Y = (int) $_GET['year'];
if($Y >= 1970 && $Y < 2100) $year = $Y;
$year = clamp($Y, 1970, 2100);
}
$totaldate = $year."/".$month."/".$day;
@ -168,7 +173,10 @@ class NumericScore extends Extension {
$this->delete_votes_by($event->id);
}
public function delete_votes_by(/*int*/ $user_id) {
/**
* @param int $user_id
*/
public function delete_votes_by($user_id) {
global $database;
$image_ids = $database->get_col("SELECT image_id FROM numeric_score_votes WHERE user_id=?", array($user_id));
@ -239,9 +247,9 @@ class NumericScore extends Extension {
"images.id in (SELECT image_id FROM numeric_score_votes WHERE user_id=:ns_user_id AND score=-1)",
array("ns_user_id"=>$iid)));
}
else if(preg_match("/^order[=|:](numeric_)?(score)[_]?(desc|asc)?$/i", $event->term, $matches)){
else if(preg_match("/^order[=|:](?:numeric_)?(score)(?:_(desc|asc))?$/i", $event->term, $matches)){
$default_order_for_column = "DESC";
$sort = isset($matches[3]) ? strtoupper($matches[3]) : $default_order_for_column;
$sort = isset($matches[2]) ? strtoupper($matches[2]) : $default_order_for_column;
Image::$order_sql = "images.numeric_score $sort";
$event->add_querylet(new Querylet("1=1")); //small hack to avoid metatag being treated as normal tag
}
@ -250,7 +258,7 @@ class NumericScore extends Extension {
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches)) {
if(preg_match("/^vote[=|:](up|down|remove)$/", $event->term, $matches) && $event->parse) {
global $user;
$score = ($matches[1] == "up" ? 1 : ($matches[1] == "down" ? -1 : 0));
if(!$user->is_anonymous()) {
@ -290,7 +298,7 @@ class NumericScore extends Extension {
* @param int $user_id
* @param int $score
*/
private function add_vote(/*int*/ $image_id, /*int*/ $user_id, /*int*/ $score) {
private function add_vote($image_id, $user_id, $score) {
global $database;
$database->execute(
"DELETE FROM numeric_score_votes WHERE image_id=:imageid AND user_id=:userid",

View File

@ -1,6 +1,6 @@
<?php
class NumericScoreTest extends ShimmiePHPUnitTestCase {
function testNumericScore() {
public function testNumericScore() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
$this->get_page("post/view/$image_id");

View File

@ -1,6 +1,6 @@
<?php
class OekakiTest extends ShimmiePHPUnitTestCase {
function testLog() {
public function testLog() {
$this->log_in_as_user();
$this->get_page("oekaki/create");
}

View File

@ -208,7 +208,7 @@ class _SafeOuroborosImage
// meta
$this->change = intval($img->id); //DaFug is this even supposed to do? ChangeID?
// Should be JSON specific, just strip this when converting to XML
$this->created_at = array('n' => 123456789, 's' => $img->posted_timestamp, 'json_class' => 'Time');
$this->created_at = array('n' => 123456789, 's' => strtotime($img->posted), 'json_class' => 'Time');
$this->id = intval($img->id);
$this->parent_id = null;
if (defined('ENABLED_EXTS')) {

View File

@ -1,6 +1,6 @@
<?php
class PrivMsgTest extends ShimmiePHPUnitTestCase {
function testPM() {
public function testPM() {
$this->log_in_as_admin();
$this->get_page("user/test");
@ -31,7 +31,7 @@ class PrivMsgTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testAdminAccess() {
public function testAdminAccess() {
$this->log_in_as_admin();
$this->get_page("user/test");

View File

@ -252,19 +252,21 @@ class Pools extends Extension {
* When displaying an image, optionally list all the pools that the
* image is currently a member of on a side panel, as well as a link
* to the Next image in the pool.
*
* @var DisplayingImageEvent $event
*/
public function onDisplayingImage(DisplayingImageEvent $event) {
global $config;
if($config->get_bool("poolsInfoOnViewImage")) {
$imageID = $event->image->id;
$poolsIDs = $this->get_pool_id($imageID);
$poolsIDs = $this->get_pool_ids($imageID);
$show_nav = $config->get_bool("poolsShowNavLinks", false);
$navInfo = array();
foreach($poolsIDs as $poolID) {
$pool = $this->get_single_pool($poolID['pool_id']);
$pool = $this->get_single_pool($poolID);
$navInfo[$pool['id']] = array();
$navInfo[$pool['id']]['info'] = $pool;
@ -374,16 +376,10 @@ class Pools extends Extension {
private function list_pools(Page $page, /*int*/ $pageNumber) {
global $config, $database;
if(is_null($pageNumber) || !is_numeric($pageNumber))
$pageNumber = 0;
else if ($pageNumber <= 0)
$pageNumber = 0;
else
$pageNumber--;
$pageNumber = clamp($pageNumber, 1, null) - 1;
$poolsPerPage = $config->get_int("poolsListsPerPage");
$order_by = "";
$order = $page->get_cookie("ui-order-pool");
if($order == "created" || is_null($order)){
@ -397,15 +393,14 @@ class Pools extends Extension {
}
$pools = $database->get_all("
SELECT p.id, p.user_id, p.public, p.title, p.description,
p.posts, u.name as user_name
FROM pools AS p
INNER JOIN users AS u
ON p.user_id = u.id
$order_by
LIMIT :l OFFSET :o
", array("l"=>$poolsPerPage, "o"=>$pageNumber * $poolsPerPage)
);
SELECT p.id, p.user_id, p.public, p.title, p.description,
p.posts, u.name as user_name
FROM pools AS p
INNER JOIN users AS u
ON p.user_id = u.id
$order_by
LIMIT :l OFFSET :o
", array("l"=>$poolsPerPage, "o"=>$pageNumber * $poolsPerPage));
$totalPages = ceil($database->get_one("SELECT COUNT(*) FROM pools") / $poolsPerPage);
@ -416,7 +411,7 @@ class Pools extends Extension {
/**
* HERE WE CREATE A NEW POOL
*
* @return mixed
* @return int
* @throws PoolCreationException
*/
private function add_pool() {
@ -438,12 +433,9 @@ class Pools extends Extension {
VALUES (:uid, :public, :title, :desc, now())",
array("uid"=>$user->id, "public"=>$public, "title"=>$_POST["title"], "desc"=>$_POST["description"]));
$result = array();
$result['poolID'] = $database->get_last_insert_id('pools_id_seq');
log_info("pools", "Pool {$result["poolID"]} created by {$user->name}");
return $result["poolID"];
$poolID = $database->get_last_insert_id('pools_id_seq');
log_info("pools", "Pool {$poolID} created by {$user->name}");
return $poolID;
}
/**
@ -482,11 +474,11 @@ class Pools extends Extension {
/**
* Get all of the pool IDs that an image is in, given an image ID.
* @param int $imageID Integer ID for the image
* @return array
* @return int[]
*/
private function get_pool_id(/*int*/ $imageID) {
private function get_pool_ids(/*int*/ $imageID) {
global $database;
return $database->get_all("SELECT pool_id FROM pool_images WHERE image_id=:iid", array("iid"=>$imageID));
return $database->get_col("SELECT pool_id FROM pool_images WHERE image_id=:iid", array("iid"=>$imageID));
}
/**

View File

@ -1,6 +1,6 @@
<?php
class PoolsTest extends ShimmiePHPUnitTestCase {
function testPools() {
public function testPools() {
$this->get_page('pool/list');
$this->assert_title("Pools");

View File

@ -1,6 +1,6 @@
<?php
class RandomTest extends ShimmiePHPUnitTestCase {
function testRandom() {
public function testRandom() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "test");
$this->log_out();
@ -15,7 +15,7 @@ class RandomTest extends ShimmiePHPUnitTestCase {
# FIXME: assert($raw == file(blah.jpg))
}
function testPostListBlock() {
public function testPostListBlock() {
$this->log_in_as_admin();
$this->get_page("setup");

View File

@ -1,6 +1,6 @@
<?php
class RatingTest extends ShimmiePHPUnitTestCase {
function testRating() {
public function testRating() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");

View File

@ -1,6 +1,6 @@
<?php
class RegenThumbTest extends ShimmiePHPUnitTestCase {
function testRegenThumb() {
public function testRegenThumb() {
$this->log_in_as_admin();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
$this->get_page("post/view/$image_id");

View File

@ -58,7 +58,7 @@ class Relationships extends Extension {
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^parent[=|:]([0-9]+|none)$/", $event->term, $matches)) {
if(preg_match("/^parent[=|:]([0-9]+|none)$/", $event->term, $matches) && $event->parse) {
$parentID = $matches[1];
if($parentID == "none" || $parentID == "0"){
@ -67,7 +67,7 @@ class Relationships extends Extension {
$this->set_parent($event->id, $parentID);
}
}
else if(preg_match("/^child[=|:]([0-9]+)$/", $event->term, $matches)) {
else if(preg_match("/^child[=|:]([0-9]+)$/", $event->term, $matches) && $event->parse) {
$childID = $matches[1];
$this->set_child($event->id, $childID);

View File

@ -141,7 +141,10 @@ class ReportImage extends Extension {
$this->delete_reports_by($event->id);
}
public function delete_reports_by(/*int*/ $user_id) {
/**
* @param int $user_id
*/
public function delete_reports_by($user_id) {
global $database;
$database->execute("DELETE FROM image_reports WHERE reporter_id=?", array($user_id));
$database->cache->delete("image-report-count");
@ -165,7 +168,7 @@ class ReportImage extends Extension {
/**
* @param Image $image
* @return array
* @return string[]
*/
public function get_reporters(Image $image) {
global $database;
@ -206,7 +209,7 @@ class ReportImage extends Extension {
}
/**
* @return mixed
* @return int
*/
public function count_reported_images() {
global $database;
@ -220,13 +223,3 @@ class ReportImage extends Extension {
return $count;
}
}
// ===== Changelog =====
// * Version 0.3a / 0.3a_rc - 11/06/07 - I can no longer use the same theme.php file for both SVN and RCx. Sorry.
// * Same deal with theme.php as it is with main.php
// * Version 0.3 / 0.3_rc - 11/06/07 - Added the option to display thumbnails, moved the reported image list to it's
// own page, and checked to make sure the user is an admin before letting them delete / view reported images.
// * Version 0.2c_rc2 - 10/27/07 - Now (really!) supports Shimmie2 RC2!
// * Version 0.2b - 10/27/07 - Now supports Shimmie2 RC2!
// * Version 0.2a - 10/24/07 - Fixed some SQL issues. I will make sure to test before commiting :)
// * Version 0.2 - 10/24/07 - First public release.

View File

@ -1,6 +1,6 @@
<?php
class ReportImageTest extends ShimmiePHPUnitTestCase {
function testReportImage() {
public function testReportImage() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
$this->get_page("post/view/$image_id");

View File

@ -1,6 +1,6 @@
<?php
class ResLimitTest extends ShimmiePHPUnitTestCase {
function testResLimitOK() {
public function testResLimitOK() {
global $config;
$config->set_int("upload_min_height", 0);
$config->set_int("upload_min_width", 0);
@ -16,7 +16,7 @@ class ResLimitTest extends ShimmiePHPUnitTestCase {
$this->assert_no_text("ratio");
}
function testResLimitSmall() {
public function testResLimitSmall() {
global $config;
$config->set_int("upload_min_height", 900);
$config->set_int("upload_min_width", 900);
@ -33,7 +33,7 @@ class ResLimitTest extends ShimmiePHPUnitTestCase {
}
}
function testResLimitLarge() {
public function testResLimitLarge() {
global $config;
$config->set_int("upload_min_height", 0);
$config->set_int("upload_min_width", 0);
@ -50,7 +50,7 @@ class ResLimitTest extends ShimmiePHPUnitTestCase {
}
function testResLimitRatio() {
public function testResLimitRatio() {
global $config;
$config->set_int("upload_min_height", -1);
$config->set_int("upload_min_width", -1);

View File

@ -75,12 +75,12 @@ class ResizeImage extends Extension {
$isanigif = 0;
if($image_obj->ext == "gif"){
$image_filename = warehouse_path("images", $image_obj->hash);
if(!($fh = @fopen($image_filename, 'rb'))){ //check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473)
return false;
}
while(!feof($fh) && $isanigif < 2) {
$chunk = fread($fh, 1024 * 100);
$isanigif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
if(($fh = @fopen($image_filename, 'rb'))) {
//check if gif is animated (via http://www.php.net/manual/en/function.imagecreatefromgif.php#104473)
while(!feof($fh) && $isanigif < 2) {
$chunk = fread($fh, 1024 * 100);
$isanigif += preg_match_all('#\x00\x21\xF9\x04.{4}\x00(\x2C|\x21)#s', $chunk, $matches);
}
}
}
if($isanigif == 0){
@ -180,51 +180,15 @@ class ResizeImage extends Extension {
if (($image_obj->width != $info[0] ) || ($image_obj->height != $info[1])) {
throw new ImageResizeException("The current image size does not match what is set in the database! - Aborting Resize.");
}
/*
Check Memory usage limits
Old check: $memory_use = (filesize($image_filename)*2) + ($width*$height*4) + (4*1024*1024);
New check: memory_use = width * height * (bits per channel) * channels * 2.5
It didn't make sense to compute the memory usage based on the NEW size for the image. ($width*$height*4)
We need to consider the size that we are GOING TO instead.
The factor of 2.5 is simply a rough guideline.
http://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize
*/
if (isset($info['bits']) && isset($info['channels']))
{
$memory_use = ($info[0] * $info[1] * ($info['bits'] / 8) * $info['channels'] * 2.5) / 1024;
} else {
//
// If we don't have bits and channel info from the image then assume default values
// of 8 bits per color and 4 channels (R,G,B,A) -- ie: regular 24-bit color
//
$memory_use = ($info[0] * $info[1] * 1 * 4 * 2.5) / 1024;
}
$memory_use = $this->calc_memory_use($info);
$memory_limit = get_memory_limit();
if ($memory_use > $memory_limit) {
throw new ImageResizeException("The image is too large to resize given the memory limits. ($memory_use > $memory_limit)");
}
/* Calculate the new size of the image */
if ( $height > 0 && $width > 0 ) {
$new_height = $height;
$new_width = $width;
} else {
// Scale the new image
if ($width == 0) $factor = $height/$image_obj->height;
elseif ($height == 0) $factor = $width/$image_obj->width;
else $factor = min( $width / $image_obj->width, $height / $image_obj->height );
$new_width = round( $image_obj->width * $factor );
$new_height = round( $image_obj->height * $factor );
}
list($new_height, $new_width) = $this->calc_new_size($image_obj, $width, $height);
/* Attempt to load the image */
switch ( $info[2] ) {
case IMAGETYPE_GIF: $image = imagecreatefromgif($image_filename); break;
@ -303,19 +267,65 @@ class ResizeImage extends Extension {
send_event(new ThumbnailGenerationEvent($new_hash, $filetype));
/* Update the database */
$database->Execute(
"UPDATE images SET
filename = :filename, filesize = :filesize, hash = :hash, width = :width, height = :height
WHERE
id = :id
",
array(
"filename"=>$new_filename, "filesize"=>$new_size, "hash"=>$new_hash,
"width"=>$new_width, "height"=>$new_height, "id"=>$image_obj->id
)
);
$database->Execute("
UPDATE images SET filename = :filename, filesize = :filesize, hash = :hash, width = :width, height = :height
WHERE id = :id
", array(
"filename"=>$new_filename, "filesize"=>$new_size, "hash"=>$new_hash,
"width"=>$new_width, "height"=>$new_height, "id"=>$image_obj->id
));
log_info("resize", "Resized Image #{$image_obj->id} - New hash: {$new_hash}");
}
/**
* Check Memory usage limits
*
* Old check: $memory_use = (filesize($image_filename)*2) + ($width*$height*4) + (4*1024*1024);
* New check: memory_use = width * height * (bits per channel) * channels * 2.5
*
* It didn't make sense to compute the memory usage based on the NEW size for the image. ($width*$height*4)
* We need to consider the size that we are GOING TO instead.
*
* The factor of 2.5 is simply a rough guideline.
* http://stackoverflow.com/questions/527532/reasonable-php-memory-limit-for-image-resize
*
* @param $info
* @return int
*/
private function calc_memory_use($info) {
if (isset($info['bits']) && isset($info['channels'])) {
return $memory_use = ($info[0] * $info[1] * ($info['bits'] / 8) * $info['channels'] * 2.5) / 1024;
}
else {
// If we don't have bits and channel info from the image then assume default values
// of 8 bits per color and 4 channels (R,G,B,A) -- ie: regular 24-bit color
return $memory_use = ($info[0] * $info[1] * 1 * 4 * 2.5) / 1024;
}
}
/**
* @param Image $image_obj
* @param $width
* @param $height
* @return int[]
*/
private function calc_new_size(Image $image_obj, $width, $height) {
/* Calculate the new size of the image */
if ($height > 0 && $width > 0) {
$new_height = $height;
$new_width = $width;
return array($new_height, $new_width);
} else {
// Scale the new image
if ($width == 0) $factor = $height / $image_obj->height;
elseif ($height == 0) $factor = $width / $image_obj->width;
else $factor = min($width / $image_obj->width, $height / $image_obj->height);
$new_width = round($image_obj->width * $factor);
$new_height = round($image_obj->height * $factor);
return array($new_height, $new_width);
}
}
}

View File

@ -25,16 +25,16 @@ class RSS_Comments extends Extension {
$page->set_type("application/rss+xml");
$comments = $database->get_all("
SELECT
SELECT
users.id as user_id, users.name as user_name,
comments.comment as comment, comments.id as comment_id,
comments.image_id as image_id, comments.owner_ip as poster_ip,
UNIX_TIMESTAMP(posted) AS posted_timestamp
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
ORDER BY comments.id DESC
LIMIT 10
");
comments.posted as posted
FROM comments
LEFT JOIN users ON comments.owner_id=users.id
ORDER BY comments.id DESC
LIMIT 10
");
$data = "";
foreach($comments as $comment) {
@ -42,7 +42,7 @@ class RSS_Comments extends Extension {
$comment_id = $comment['comment_id'];
$link = make_http(make_link("post/view/$image_id"));
$owner = html_escape($comment['user_name']);
$posted = date(DATE_RSS, $comment['posted_timestamp']);
$posted = date(DATE_RSS, strtotime($comment['posted']));
$comment = html_escape($comment['comment']);
$content = html_escape("$owner: $comment");

View File

@ -98,7 +98,7 @@ class RSS_Images extends Extension {
$owner = $image->get_owner();
$thumb_url = $image->get_thumb_link();
$image_url = $image->get_image_link();
$posted = date(DATE_RSS, $image->posted_timestamp);
$posted = date(DATE_RSS, strtotime($image->posted));
$content = html_escape(
"<p>" . $this->theme->build_thumb_html($image) . "</p>" .
"<p>Uploaded by " . html_escape($owner->name) . "</p>"

View File

@ -1,6 +1,6 @@
<?php
class SetupTest extends ShimmiePHPUnitTestCase {
function testNiceUrlsTest() {
public function testNiceUrlsTest() {
# XXX: this only checks that the text is "ok", to check
# for a bug where it was coming out as "\nok"; it doesn't
# check that niceurls actually work
@ -9,27 +9,27 @@ class SetupTest extends ShimmiePHPUnitTestCase {
$this->assert_no_content("\n");
}
function testAuthAnon() {
public function testAuthAnon() {
$this->get_page('setup');
$this->assert_response(403);
$this->assert_title("Permission Denied");
}
function testAuthUser() {
public function testAuthUser() {
$this->log_in_as_user();
$this->get_page('setup');
$this->assert_response(403);
$this->assert_title("Permission Denied");
}
function testAuthAdmin() {
public function testAuthAdmin() {
$this->log_in_as_admin();
$this->get_page('setup');
$this->assert_title("Shimmie Setup");
$this->assert_text("General");
}
function testAdvanced() {
public function testAdvanced() {
$this->log_in_as_admin();
$this->get_page('setup/advanced');
$this->assert_title("Shimmie Setup");

View File

@ -19,8 +19,6 @@
class _SafeImage {
#{"id":"2","height":"768","width":"1024","hash":"71cdfaabbcdad3f777e0b60418532e94","filesize":"439561","filename":"HeilAmu.png","ext":"png","owner_ip":"0.0.0.0","posted":"0000-00-00 00:00:00","source":null,"locked":"N","owner_id":"0","rating":"u","numeric_score":"0","text_score":"0","notes":"0","favorites":"0","posted_timestamp":-62169955200,"tag_array":["cat","kunimitsu"]}
public $id;
public $height;
public $width;
@ -39,7 +37,7 @@ class _SafeImage {
$this->hash = $img->hash;
$this->filesize = $img->filesize;
$this->ext = $img->ext;
$this->posted = $img->posted_timestamp;
$this->posted = strtotime($img->posted);
$this->source = $img->source;
$this->owner_id = $img->owner_id;
$this->tags = $img->get_tag_array();
@ -48,52 +46,30 @@ class _SafeImage {
class ShimmieApi extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $database, $page, $user;
global $page, $user;
if($event->page_matches("api/shimmie")) {
$page->set_mode("data");
$page->set_type("text/plain");
if(!$event->page_matches("api/shimmie/get_tags") && !$event->page_matches("api/shimmie/get_image") && !$event->page_matches("api/shimmie/find_images") && !$event->page_matches("api/shimmie/get_user")){
$page->set_mode("redirect");
$page->set_redirect(make_link("ext_doc/shimmie_api"));
}
if($event->page_matches("api/shimmie/get_tags")){
$arg = $event->get_arg(0);
if(!empty($arg)){
$all = $database->get_all(
"SELECT tag FROM tags WHERE tag LIKE ?",
array($arg."%"));
}
elseif(isset($_GET['tag'])){
$all = $database->get_all(
"SELECT tag FROM tags WHERE tag LIKE ?",
array($_GET['tag']."%"));
}
else {
$all = $database->get_all("SELECT tag FROM tags");
}
$res = array();
foreach($all as $row) {$res[] = $row["tag"];}
$tag = $event->get_arg(0);
if(empty($tag) && isset($_GET['tag'])) $tag = $_GET['tag'];
$res = $this->api_get_tags($tag);
$page->set_data(json_encode($res));
}
if($event->page_matches("api/shimmie/get_image")) {
elseif($event->page_matches("api/shimmie/get_image")) {
$arg = $event->get_arg(0);
if(!empty($arg)){
$image = Image::by_id(int_escape($event->get_arg(0)));
}
elseif(isset($_GET['id'])){
$image = Image::by_id(int_escape($_GET['id']));
}
if(empty($arg) && isset($_GET['id'])) $arg = $_GET['id'];
$image = Image::by_id(int_escape($arg));
// FIXME: handle null image
$image->get_tag_array(); // tag data isn't loaded into the object until necessary
$safe_image = new _SafeImage($image);
$page->set_data(json_encode($safe_image));
}
if($event->page_matches("api/shimmie/find_images")) {
elseif($event->page_matches("api/shimmie/find_images")) {
$search_terms = $event->get_search_terms();
$page_number = $event->get_page_number();
$page_size = $event->get_page_size();
@ -106,7 +82,7 @@ class ShimmieApi extends Extension {
$page->set_data(json_encode($safe_images));
}
if($event->page_matches("api/shimmie/get_user")) {
elseif($event->page_matches("api/shimmie/get_user")) {
$query = $user->id;
$type = "id";
if($event->count_args() == 1) {
@ -121,41 +97,77 @@ class ShimmieApi extends Extension {
$type = "name";
}
$all = $database->get_row(
"SELECT id,name,joindate,class FROM users WHERE $type=?",
array($query));
if(!empty($all)){
//FIXME?: For some weird reason, get_all seems to return twice. Unsetting second value to make things look nice..
// - it returns data as eg array(0=>1234, 'id'=>1234, 1=>'bob', 'name'=>bob, ...);
for($i=0; $i<4; $i++) unset($all[$i]);
$all['uploadcount'] = Image::count_images(array("user_id=".$all['id']));
$all['commentcount'] = $database->get_one(
"SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id",
array("owner_id"=>$all['id']));
if(isset($_GET['recent'])){
$recent = $database->get_all(
"SELECT * FROM images WHERE owner_id=? ORDER BY id DESC LIMIT 0, 5",
array($all['id']));
$i = 0;
foreach($recent as $all['recentposts'][$i]){
unset($all['recentposts'][$i]['owner_id']); //We already know the owners id..
unset($all['recentposts'][$i]['owner_ip']);
for($x=0; $x<14; $x++) unset($all['recentposts'][$i][$x]);
if(empty($all['recentposts'][$i]['author'])) unset($all['recentposts'][$i]['author']);
if($all['recentposts'][$i]['notes'] > 0) $all['recentposts'][$i]['has_notes'] = "Y";
else $all['recentposts'][$i]['has_notes'] = "N";
unset($all['recentposts'][$i]['notes']);
$i += 1;
}
}
}
$all = $this->api_get_user($type, $query);
$page->set_data(json_encode($all));
}
else {
$page->set_mode("redirect");
$page->set_redirect(make_link("ext_doc/shimmie_api"));
}
}
}
/**
* @param string $arg
* @return string[]
*/
private function api_get_tags($arg) {
global $database;
if (!empty($arg)) {
$all = $database->get_all("SELECT tag FROM tags WHERE tag LIKE ?", array($arg . "%"));
} else {
$all = $database->get_all("SELECT tag FROM tags");
}
$res = array();
foreach ($all as $row) {
$res[] = $row["tag"];
}
return $res;
}
/**
* @param $type
* @param $query
* @return array
*/
private function api_get_user($type, $query) {
global $database;
$all = $database->get_row(
"SELECT id, name, joindate, class FROM users WHERE $type=?",
array($query)
);
if (!empty($all)) {
//FIXME?: For some weird reason, get_all seems to return twice. Unsetting second value to make things look nice..
// - it returns data as eg array(0=>1234, 'id'=>1234, 1=>'bob', 'name'=>bob, ...);
for ($i = 0; $i < 4; $i++) unset($all[$i]);
$all['uploadcount'] = Image::count_images(array("user_id=" . $all['id']));
$all['commentcount'] = $database->get_one(
"SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id",
array("owner_id" => $all['id']));
if (isset($_GET['recent'])) {
$recent = $database->get_all(
"SELECT * FROM images WHERE owner_id=? ORDER BY id DESC LIMIT 0, 5",
array($all['id']));
$i = 0;
foreach ($recent as $all['recentposts'][$i]) {
unset($all['recentposts'][$i]['owner_id']); //We already know the owners id..
unset($all['recentposts'][$i]['owner_ip']);
for ($x = 0; $x < 14; $x++) unset($all['recentposts'][$i][$x]);
if (empty($all['recentposts'][$i]['author'])) unset($all['recentposts'][$i]['author']);
if ($all['recentposts'][$i]['notes'] > 0) $all['recentposts'][$i]['has_notes'] = "Y";
else $all['recentposts'][$i]['has_notes'] = "N";
unset($all['recentposts'][$i]['notes']);
$i += 1;
}
}
}
return $all;
}
}

View File

@ -1,6 +1,6 @@
<?php
class ShimmieApiTest extends ShimmiePHPUnitTestCase {
function testAPI() {
public function testAPI() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");

View File

@ -1,6 +1,6 @@
<?php
class SiteDescriptionTest extends ShimmiePHPUnitTestCase {
function testSiteDescription() {
public function testSiteDescription() {
global $config, $page;
$config->set_string("site_description", "A Shimmie testbed");
$this->get_page("post/list");
@ -10,7 +10,7 @@ class SiteDescriptionTest extends ShimmiePHPUnitTestCase {
);
}
function testSiteKeywords() {
public function testSiteKeywords() {
global $config, $page;
$config->set_string("site_keywords", "foo,bar,baz");
$this->get_page("post/list");

View File

@ -56,7 +56,7 @@ class XMLSitemap extends Extension
$latestimages_urllist[$arrayid] = "post/view/$image->id";
}
$this->add_sitemap_queue($latestimages_urllist, "monthly", "0.8", date("Y-m-d", $image->posted_timestamp));
$this->add_sitemap_queue($latestimages_urllist, "monthly", "0.8", date("Y-m-d", strtotime($image->posted)));
/* --- Display page --- */
// when sitemap is ok, display it from the file
@ -88,7 +88,7 @@ class XMLSitemap extends Extension
// create url from image id's
$latestimages_urllist[$arrayid] = "post/view/$image->id";
}
$this->add_sitemap_queue($latestimages_urllist, "monthly", "0.8", date("Y-m-d", $image->posted_timestamp));
$this->add_sitemap_queue($latestimages_urllist, "monthly", "0.8", date("Y-m-d", strtotime($image->posted)));
/* --- Add other tags --- */
$other_tags = $database->get_all("SELECT tag, count FROM tags ORDER BY `count` DESC LIMIT 21,10000000");
@ -106,7 +106,7 @@ class XMLSitemap extends Extension
// create url from image id's
$otherimages[$arrayid] = "post/view/$image->id";
}
$this->add_sitemap_queue($otherimages, "monthly", "0.6", date("Y-m-d", $image->posted_timestamp));
$this->add_sitemap_queue($otherimages, "monthly", "0.6", date("Y-m-d", strtotime($image->posted)));
/* --- Display page --- */

View File

@ -1,6 +1,6 @@
<?php
class XMLSitemapTest extends ShimmiePHPUnitTestCase {
function testBasic() {
public function testBasic() {
# this will implicitly check that there are no
# PHP-level error messages
$this->get_page('sitemap.xml');

View File

@ -95,11 +95,38 @@ class SourceSetEvent extends Event {
class TagSetEvent extends Event {
/** @var \Image */
public $image;
var $tags;
public $tags;
public $metatags;
public function __construct(Image $image, $tags) {
$this->image = $image;
$this->tags = Tag::explode($tags);
$this->image = $image;
$this->tags = array();
$this->metatags = array();
//tags need to be sanitised, alias checked & have metatags removed before being passed to onTagSet
$tag_array = Tag::explode($tags);
$tag_array = array_map(array('Tag', 'sanitise'), $tag_array);
$tag_array = Tag::resolve_aliases($tag_array);
foreach($tag_array as $tag) {
if((strpos($tag, ':') === FALSE) && (strpos($tag, '=') === FALSE)) {
//Tag doesn't contain : or =, meaning it can't possibly be a metatag.
//This should help speed wise, as it avoids running every single tag through a bunch of preg_match instead.
array_push($this->tags, $tag);
continue;
}
$ttpe = new TagTermParseEvent($tag, $this->image->id, FALSE); //Only check for metatags, don't parse. Parsing is done after set_tags.
send_event($ttpe);
//seperate tags from metatags
if(!$ttpe->is_metatag()) {
array_push($this->tags, $tag);
}else{
array_push($this->metatags, $tag);
}
}
}
}
@ -131,14 +158,17 @@ class LockSetEvent extends Event {
* Signal that a tag term needs parsing
*/
class TagTermParseEvent extends Event {
var $term = null;
var $id = null;
public $term = NULL; //tag
public $id = NULL; //image_id
/** @var bool */
public $metatag = false;
public $metatag = FALSE;
/** @var bool */
public $parse = TRUE; //marks the tag to be parsed, and not just checked if valid metatag
public function __construct($term, $id) {
$this->term = $term;
$this->id = $id;
public function __construct($term, $id, $parse) {
$this->term = $term;
$this->id = $id;
$this->parse = $parse;
}
/**
@ -215,6 +245,7 @@ class TagEdit extends Extension {
if($user->can("edit_image_tag") && (!$event->image->is_locked() || $user->can("edit_image_lock"))) {
$event->image->set_tags($event->tags);
}
$event->image->parse_metatags($event->metatags, $event->image->id);
}
public function onSourceSet(SourceSetEvent $event) {
@ -257,7 +288,7 @@ class TagEdit extends Extension {
public function onTagTermParse(TagTermParseEvent $event) {
$matches = array();
if(preg_match("/^source[=|:](.*)$/i", $event->term, $matches)) {
if(preg_match("/^source[=|:](.*)$/i", $event->term, $matches) && $event->parse) {
$source = ($matches[1] !== "none" ? $matches[1] : null);
send_event(new SourceSetEvent(Image::by_id($event->id), $source));
}

View File

@ -1,6 +1,6 @@
<?php
class TagEditTest extends ShimmiePHPUnitTestCase {
function testTagEdit() {
public function testTagEdit() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
$this->get_page("post/view/$image_id");
@ -21,7 +21,7 @@ class TagEditTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testSourceEdit() {
public function testSourceEdit() {
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
$this->get_page("post/view/$image_id");
@ -48,10 +48,12 @@ class TagEditTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
/*
* FIXME: Mass Tagger seems to be broken, and this test case always fails.
*
function testMassEdit() {
/*
* FIXME: Mass Tagger seems to be broken, and this test case always fails.
*/
public function testMassEdit() {
$this->markTestIncomplete();
$this->log_in_as_admin();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
@ -71,6 +73,5 @@ class TagEditTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
*/
}

View File

@ -22,7 +22,7 @@ class TagEditCloud extends Extension {
}
}
}
public function onInitExt(InitExtEvent $event) {
global $config;
$config->set_default_bool("tageditcloud_disable", false);
@ -74,16 +74,14 @@ class TagEditCloud extends Extension {
$ignore_tags = Tag::explode($config->get_string("tageditcloud_ignoretags"));
if(class_exists("TagCategories")){
if(ext_is_live("TagCategories")) {
$categories = $database->get_all("SELECT category, color FROM image_tag_categories");
$cat_color = array();
foreach($categories as $row){
foreach($categories as $row) {
$cat_color[$row['category']] = $row['color'];
}
}
$tag_data = null;
switch($sort_method) {
case 'a':
case 'p':
@ -99,31 +97,29 @@ class TagEditCloud extends Extension {
break;
case 'r':
$relevant_tags = array_diff($image->get_tag_array(),$ignore_tags);
if(count($relevant_tags) > 0) {
$relevant_tags = implode(",",array_map(array($database,"escape"),$relevant_tags));
$tag_data = $database->get_all("
SELECT t2.tag AS tag, COUNT(image_id) AS count, FLOOR(LN(LN(COUNT(image_id) - :tag_min1 + 1)+1)*150)/200 AS scaled
FROM image_tags it1
JOIN image_tags it2 USING(image_id)
JOIN tags t1 ON it1.tag_id = t1.id
JOIN tags t2 ON it2.tag_id = t2.id
WHERE t1.count >= :tag_min2 AND t1.tag IN($relevant_tags)
GROUP BY t2.tag
ORDER BY count DESC
LIMIT :limit",
array("tag_min1" => $tags_min, "tag_min2" => $tags_min, "limit" => $max_count));
if(count($relevant_tags) == 0) {
return null;
}
$relevant_tags = implode(",",array_map(array($database,"escape"),$relevant_tags));
$tag_data = $database->get_all("
SELECT t2.tag AS tag, COUNT(image_id) AS count, FLOOR(LN(LN(COUNT(image_id) - :tag_min1 + 1)+1)*150)/200 AS scaled
FROM image_tags it1
JOIN image_tags it2 USING(image_id)
JOIN tags t1 ON it1.tag_id = t1.id
JOIN tags t2 ON it2.tag_id = t2.id
WHERE t1.count >= :tag_min2 AND t1.tag IN($relevant_tags)
GROUP BY t2.tag
ORDER BY count DESC
LIMIT :limit",
array("tag_min1" => $tags_min, "tag_min2" => $tags_min, "limit" => $max_count));
break;
}
if(is_null($tag_data)) {
return null;
}
$counter = 1;
foreach($tag_data as $row) {
$full_tag = $row['tag'];
if(class_exists("TagCategories")){
if(ext_is_live("TagCategories")){
$tc = explode(':',$row['tag']);
if(isset($tc[1]) && isset($cat_color[$tc[0]])){
$h_tag = html_escape($tc[1]);

View File

@ -329,7 +329,8 @@ class Tag_History extends Extension {
$image = Image::by_id($stored_image_id);
if ( ! $image instanceof Image) {
throw new ImageDoesNotExist("Error: cannot find any image with the ID = ". $stored_image_id);
continue;
//throw new ImageDoesNotExist("Error: cannot find any image with the ID = ". $stored_image_id);
}
log_debug("tag_history", 'Reverting tags of Image #'.$stored_image_id.' to ['.$stored_tags.']');

View File

@ -1,12 +1,13 @@
<?php
class TagHistoryTest extends ShimmiePHPUnitTestCase {
function testTagHistory() {
public function testTagHistory() {
$this->log_in_as_admin();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx");
$this->get_page("post/view/$image_id");
$this->assert_title("Image $image_id: pbx");
/*
$this->markTestIncomplete();
// FIXME
$this->set_field("tag_edit__tags", "new");
$this->click("Set");
@ -15,7 +16,6 @@ class TagHistoryTest extends ShimmiePHPUnitTestCase {
$this->assert_text("new (Set by demo");
$this->click("Revert To");
$this->assert_title("Image $image_id: pbx");
*/
$this->get_page("tag_history/all/1");
$this->assert_title("Global Tag History");

View File

@ -2,7 +2,7 @@
class TagListTest extends ShimmiePHPUnitTestCase {
var $pages = array("map", "alphabetic", "popularity", "categories");
function testTagList() {
public function testTagList() {
$this->get_page('tags/map');
$this->assert_title('Tag List');
@ -18,7 +18,7 @@ class TagListTest extends ShimmiePHPUnitTestCase {
# FIXME: test that these show the right stuff
}
function testMinCount() {
public function testMinCount() {
foreach($this->pages as $page) {
$this->get_page("tags/$page?mincount=999999");
$this->assert_title("Tag List");

View File

@ -1,6 +1,6 @@
<?php
class TipsTest extends ShimmiePHPUnitTestCase {
function setUp() {
public function setUp() {
parent::setUp();
$this->log_in_as_admin();
@ -15,7 +15,7 @@ class TipsTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testImageless() {
public function testImageless() {
$this->log_in_as_admin();
$this->get_page("tips/list");
@ -37,7 +37,7 @@ class TipsTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testImaged() {
public function testImaged() {
$this->log_in_as_admin();
$this->get_page("tips/list");
@ -59,7 +59,7 @@ class TipsTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testDisabled() {
public function testDisabled() {
$this->log_in_as_admin();
$this->get_page("tips/list");

View File

@ -234,8 +234,8 @@ class Upload extends Extension {
}
/**
* @param string|int $id
* @return array
* @param int $id
* @return string[]
*/
private function tags_for_upload_slot($id) {
if(isset($_POST["tags$id"])) {

View File

@ -1,18 +1,18 @@
<?php
class UploadTest extends ShimmiePHPUnitTestCase {
function testUploadPage() {
public function testUploadPage() {
$this->log_in_as_user();
$this->get_page("upload");
$this->assert_title("Upload");
}
function testUpload() {
public function testUpload() {
$this->log_in_as_user();
$this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
}
function testRejectDupe() {
public function testRejectDupe() {
$this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
try {
@ -23,7 +23,7 @@ class UploadTest extends ShimmiePHPUnitTestCase {
}
}
function testRejectUnknownFiletype() {
public function testRejectUnknownFiletype() {
try {
$this->post_image("index.php", "test");
}
@ -32,16 +32,16 @@ class UploadTest extends ShimmiePHPUnitTestCase {
}
}
function testRejectHuge() {
/*
public function testRejectHuge() {
$this->markTestIncomplete();
// FIXME: huge.dat is rejected for other reasons; manual testing shows that this works
file_put_contents("huge.dat", file_get_contents("tests/pbx_screenshot.jpg") . str_repeat("U", 1024*1024*3));
$image_id_4 = $this->post_image("index.php", "test");
$this->post_image("index.php", "test");
$this->assert_response(200);
$this->assert_title("Upload Status");
$this->assert_text("File too large");
unlink("huge.dat");
*/
}
}

View File

@ -80,6 +80,9 @@ class UserCreationException extends SCoreException {}
class NullUserException extends SCoreException {}
class UserPage extends Extension {
/** @var UserPageTheme $theme */
var $theme;
public function onInitExt(InitExtEvent $event) {
global $config;
$config->set_default_bool("login_signup_enabled", true);
@ -94,64 +97,22 @@ class UserPage extends Extension {
public function onPageRequest(PageRequestEvent $event) {
global $config, $page, $user;
// user info is shown on all pages
if($user->is_anonymous()) {
$this->theme->display_login_block($page);
}
else {
$ubbe = new UserBlockBuildingEvent();
send_event($ubbe);
ksort($ubbe->parts);
$this->theme->display_user_block($page, $user, $ubbe->parts);
}
$this->show_user_info();
if($event->page_matches("user_admin")) {
if($event->get_arg(0) == "login") {
if(isset($_POST['user']) && isset($_POST['pass'])) {
$this->login($page);
$this->page_login($_POST['user'], $_POST['pass']);
}
else {
$this->theme->display_login_page($page);
}
}
else if($event->get_arg(0) == "recover") {
$user = User::by_name($_POST['username']);
if(is_null($user)) {
$this->theme->display_error(404, "Error", "There's no user with that name");
}
else if(is_null($user->email)) {
$this->theme->display_error(400, "Error", "That user has no registered email address");
}
else {
// send email
}
$this->page_recover($_POST['username']);
}
else if($event->get_arg(0) == "create") {
if(!$config->get_bool("login_signup_enabled")) {
$this->theme->display_signups_disabled($page);
}
else if(!isset($_POST['name'])) {
$this->theme->display_signup_page($page);
}
else if($_POST['pass1'] != $_POST['pass2']) {
$this->theme->display_error(400, "Password Mismatch", "Passwords don't match");
}
else {
try {
if(!captcha_check()) {
throw new UserCreationException("Error in captcha");
}
$uce = new UserCreationEvent($_POST['name'], $_POST['pass1'], $_POST['email']);
send_event($uce);
$this->set_login_cookie($uce->username, $uce->password);
$page->set_mode("redirect");
$page->set_redirect(make_link("user"));
}
catch(UserCreationException $ex) {
$this->theme->display_error(400, "User Creation Error", $ex->getMessage());
}
}
$this->page_create();
}
else if($event->get_arg(0) == "list") {
// select users.id,name,joindate,admin,
@ -165,24 +126,7 @@ class UserPage extends Extension {
$this->theme->display_user_list($page, User::by_list(0), $user);
}
else if($event->get_arg(0) == "logout") {
$page->add_cookie("session", "", time()+60*60*24*$config->get_int('login_memory'), "/");
if(CACHE_HTTP || SPEED_HAX) {
# to keep as few versions of content as possible,
# make cookies all-or-nothing
$page->add_cookie("user", "", time()+60*60*24*$config->get_int('login_memory'), "/");
}
log_info("user", "Logged out");
$page->set_mode("redirect");
// Try forwarding to same page on logout unless user comes from registration page
if ($config->get_int("user_loginshowprofile",0) == 0 &&
isset($_SERVER['HTTP_REFERER']) &&
strstr($_SERVER['HTTP_REFERER'], "post/"))
{
$page->set_redirect ($_SERVER['HTTP_REFERER']);
} else {
$page->set_redirect(make_link());
}
$this->page_logout();
}
if(!$user->check_auth_token()) {
@ -369,8 +313,8 @@ class UserPage extends Extension {
global $user;
$matches = array();
if(preg_match("/^(poster|user)[=|:](.*)$/i", $event->term, $matches)) {
$duser = User::by_name($matches[2]);
if(preg_match("/^(?:poster|user)[=|:](.*)$/i", $event->term, $matches)) {
$duser = User::by_name($matches[1]);
if(!is_null($duser)) {
$user_id = $duser->id;
}
@ -379,25 +323,33 @@ class UserPage extends Extension {
}
$event->add_querylet(new Querylet("images.owner_id = $user_id"));
}
else if(preg_match("/^(poster|user)_id[=|:]([0-9]+)$/i", $event->term, $matches)) {
$user_id = int_escape($matches[2]);
else if(preg_match("/^(?:poster|user)_id[=|:]([0-9]+)$/i", $event->term, $matches)) {
$user_id = int_escape($matches[1]);
$event->add_querylet(new Querylet("images.owner_id = $user_id"));
}
else if($user->can("view_ip") && preg_match("/^(poster|user)_ip[=|:]([0-9\.]+)$/i", $event->term, $matches)) {
$user_ip = $matches[2]; // FIXME: ip_escape?
else if($user->can("view_ip") && preg_match("/^(?:poster|user)_ip[=|:]([0-9\.]+)$/i", $event->term, $matches)) {
$user_ip = $matches[1]; // FIXME: ip_escape?
$event->add_querylet(new Querylet("images.owner_ip = '$user_ip'"));
}
}
private function show_user_info() {
global $user, $page;
// user info is shown on all pages
if ($user->is_anonymous()) {
$this->theme->display_login_block($page);
} else {
$ubbe = new UserBlockBuildingEvent();
send_event($ubbe);
ksort($ubbe->parts);
$this->theme->display_user_block($page, $user, $ubbe->parts);
}
}
// }}}
// Things done *with* the user {{{
/**
* @param Page $page
*/
private function login(Page $page) {
global $config, $user;
private function page_login($name, $pass) {
global $config, $user, $page;
$name = $_POST['user'];
$pass = $_POST['pass'];
if(empty($name) || empty($pass)) {
$this->theme->display_error(400, "Error", "Username or password left blank");
@ -427,12 +379,72 @@ class UserPage extends Extension {
}
}
private function page_logout() {
global $page, $config;
$page->add_cookie("session", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/");
if (CACHE_HTTP || SPEED_HAX) {
# to keep as few versions of content as possible,
# make cookies all-or-nothing
$page->add_cookie("user", "", time() + 60 * 60 * 24 * $config->get_int('login_memory'), "/");
}
log_info("user", "Logged out");
$page->set_mode("redirect");
// Try forwarding to same page on logout unless user comes from registration page
if ($config->get_int("user_loginshowprofile", 0) == 0 &&
isset($_SERVER['HTTP_REFERER']) &&
strstr($_SERVER['HTTP_REFERER'], "post/")
) {
$page->set_redirect($_SERVER['HTTP_REFERER']);
} else {
$page->set_redirect(make_link());
}
}
/**
* @param string $username
*/
private function page_recover($username) {
$user = User::by_name($username);
if (is_null($user)) {
$this->theme->display_error(404, "Error", "There's no user with that name");
} else if (is_null($user->email)) {
$this->theme->display_error(400, "Error", "That user has no registered email address");
} else {
// send email
}
}
private function page_create() {
global $config, $page;
if (!$config->get_bool("login_signup_enabled")) {
$this->theme->display_signups_disabled($page);
} else if (!isset($_POST['name'])) {
$this->theme->display_signup_page($page);
} else if ($_POST['pass1'] != $_POST['pass2']) {
$this->theme->display_error(400, "Password Mismatch", "Passwords don't match");
} else {
try {
if (!captcha_check()) {
throw new UserCreationException("Error in captcha");
}
$uce = new UserCreationEvent($_POST['name'], $_POST['pass1'], $_POST['email']);
send_event($uce);
$this->set_login_cookie($uce->username, $uce->password);
$page->set_mode("redirect");
$page->set_redirect(make_link("user"));
} catch (UserCreationException $ex) {
$this->theme->display_error(400, "User Creation Error", $ex->getMessage());
}
}
}
/**
* @param UserCreationEvent $event
* @throws UserCreationException
*/
private function check_user_creation(UserCreationEvent $event)
{
private function check_user_creation(UserCreationEvent $event) {
$name = $event->username;
//$pass = $event->password;
//$email = $event->email;
@ -450,8 +462,7 @@ class UserPage extends Extension {
}
}
private function create_user(UserCreationEvent $event)
{
private function create_user(UserCreationEvent $event) {
global $database, $user;
$email = (!empty($event->email)) ? $event->email : null;

View File

@ -1,6 +1,6 @@
<?php
class UserPageTest extends ShimmiePHPUnitTestCase {
function testUserPage() {
public function testUserPage() {
$this->get_page('user');
$this->assert_title("Not Logged In");
$this->assert_no_text("Options");

View File

@ -1,6 +1,11 @@
<?php
class ViewTest extends ShimmiePHPUnitTestCase {
function testViewPage() {
public function setUp() {
parent::setUp();
// FIXME: upload images
}
public function testViewPage() {
$this->log_in_as_user();
$image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test");
$image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2");
@ -9,8 +14,16 @@ class ViewTest extends ShimmiePHPUnitTestCase {
$this->get_page("post/view/$image_id_1");
$this->assert_title("Image $image_id_1: test");
}
public function testPrevNext() {
$this->markTestIncomplete();
$this->log_in_as_user();
$image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test");
$image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2");
$image_id_3 = $this->post_image("tests/favicon.png", "test");
/*
$this->click("Prev");
$this->assert_title("Image $image_id_2: test2");
@ -19,22 +32,35 @@ class ViewTest extends ShimmiePHPUnitTestCase {
$this->click("Next");
$this->assert_title("Image not found");
*/
}
public function testView404() {
$this->log_in_as_user();
$image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test");
$image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2");
$image_id_3 = $this->post_image("tests/favicon.png", "test");
$idp1 = $image_id_3 + 1;
$this->get_page("post/view/$idp1");
$this->assert_title('Image not found');
$this->get_page('post/view/-1');
$this->assert_title('Image not found');
}
/*
* FIXME: this assumes Nice URLs.
*
public function testNextSearchResult() {
$this->markTestIncomplete();
$this->log_in_as_user();
$image_id_1 = $this->post_image("tests/pbx_screenshot.jpg", "test");
$image_id_2 = $this->post_image("tests/bedroom_workshop.jpg", "test2");
$image_id_3 = $this->post_image("tests/favicon.png", "test");
// FIXME: this assumes Nice URLs.
# note: skips image #2
$this->get_page("post/view/$image_id_1?search=test"); // FIXME: assumes niceurls
$this->click("Prev");
$this->assert_title("Image $image_id_3: test");
*/
}
}

View File

@ -1,13 +1,14 @@
<?php
class WikiTest extends ShimmiePHPUnitTestCase {
function testIndex() {
public function testIndex() {
$this->get_page("wiki");
$this->assert_title("Index");
$this->assert_text("This is a default page");
}
/*
function testAccess() {
public function testAccess() {
$this->markTestIncomplete();
global $config;
foreach(array("anon", "user", "admin") as $user) {
foreach(array(false, true) as $allowed) {
@ -39,7 +40,9 @@ class WikiTest extends ShimmiePHPUnitTestCase {
}
}
function testLock() {
public function testLock() {
$this->markTestIncomplete();
global $config;
$config->set_bool("wiki_edit_anon", true);
$config->set_bool("wiki_edit_user", false);
@ -73,7 +76,9 @@ class WikiTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testDefault() {
public function testDefault() {
$this->markTestIncomplete();
$this->log_in_as_admin();
$this->get_page("wiki/wiki:default");
$this->assert_title("wiki:default");
@ -90,7 +95,9 @@ class WikiTest extends ShimmiePHPUnitTestCase {
$this->log_out();
}
function testRevisions() {
public function testRevisions() {
$this->markTestIncomplete();
$this->log_in_as_admin();
$this->get_page("wiki/test");
$this->assert_title("test");
@ -111,6 +118,5 @@ class WikiTest extends ShimmiePHPUnitTestCase {
$this->click("Delete All");
$this->log_out();
}
*/
}

View File

@ -1,12 +1,12 @@
<?php
class WordFilterTest extends ShimmiePHPUnitTestCase {
function setUp() {
public function setUp() {
global $config;
parent::setUp();
$config->set_string("word_filter", "whore,nice lady\na duck,a kitten\n white ,\tspace\ninvalid");
}
function _doThings($in, $out) {
public function _doThings($in, $out) {
global $user;
$this->log_in_as_user();
$image_id = $this->post_image("tests/pbx_screenshot.jpg", "pbx computer screenshot");
@ -15,49 +15,49 @@ class WordFilterTest extends ShimmiePHPUnitTestCase {
$this->assert_text($out);
}
function testRegular() {
public function testRegular() {
$this->_doThings(
"posted by a whore",
"posted by a nice lady"
);
}
function testReplaceAll() {
public function testReplaceAll() {
$this->_doThings(
"a whore is a whore is a whore",
"a nice lady is a nice lady is a nice lady"
);
}
function testMixedCase() {
public function testMixedCase() {
$this->_doThings(
"monkey WhorE",
"monkey nice lady"
);
}
function testOnlyWholeWords() {
public function testOnlyWholeWords() {
$this->_doThings(
"my name is whoretta",
"my name is whoretta"
);
}
function testMultipleWords() {
public function testMultipleWords() {
$this->_doThings(
"I would like a duck",
"I would like a kitten"
);
}
function testWhitespace() {
public function testWhitespace() {
$this->_doThings(
"A colour is white",
"A colour is space"
);
}
function testIgnoreInvalid() {
public function testIgnoreInvalid() {
$this->_doThings(
"The word was invalid",
"The word was invalid"

9
tests/test-deep.sh Executable file
View File

@ -0,0 +1,9 @@
#!/bin/sh
php \
-d extension.dir=/usr/lib/php/extensions/no-debug-non-zts-20121212/ \
-d extension=xdebug.so \
-d xdebug.profiler_output_dir=./data/prof/ \
-d xdebug.profiler_enable=1 \
./phpunit.phar \
--config tests/phpunit.xml \
--coverage-clover data/coverage.clover

Some files were not shown because too many files have changed in this diff Show More