Merge branch 'master' into speed_tweaks

This commit is contained in:
green-ponies (jgen) 2012-02-07 23:21:56 -05:00
commit d69fa6ae9d
52 changed files with 478 additions and 3723 deletions

View file

@ -2,6 +2,7 @@
/*
* Name: Comment Word Ban
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: For stopping spam and other comment abuse
* Documentation:

View file

@ -2,6 +2,7 @@
/*
* Name: Bulk Add
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Bulk add server-side images
* Documentation:
@ -30,7 +31,9 @@ class BulkAdd extends SimpleExtension {
$this->theme->display_admin_block();
}
/**
* Generate the necessary DataUploadEvent for a given image and tags.
*/
private function add_image($tmpname, $filename, $tags) {
assert(file_exists($tmpname));

View file

@ -29,6 +29,9 @@ class ET extends SimpleExtension {
}
}
/**
* Collect the information and return it in a keyed array.
*/
private function get_info() {
global $config, $database;
global $_event_listeners; // yay for using secret globals \o/

View file

@ -152,6 +152,17 @@ class Favorites extends SimpleExtension {
");
$config->set_int("ext_favorites_version", 1);
}
if($config->get_int("ext_favorites_version") < 2) {
log_info("favorites", "Cleaning user favourites");
$database->Execute("DELETE FROM user_favorites WHERE user_id NOT IN (SELECT id FROM users)");
$database->Execute("DELETE FROM user_favorites WHERE image_id NOT IN (SELECT id FROM images)");
log_info("favorites", "Adding foreign keys to user favourites");
$database->Execute("ALTER TABLE user_favorites ADD CONSTRAINT foreign_user_favorites_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;");
$database->Execute("ALTER TABLE user_favorites ADD CONSTRAINT user_favorites_image_id FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE;");
$config->set_int("ext_favorites_version", 2);
}
}
private function add_vote($image_id, $user_id, $do_set) {

View file

@ -2,6 +2,7 @@
/*
* Name: Featured Image
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Bring a specific image to the users' attentions
* Documentation:

View file

@ -2,7 +2,8 @@
/*
* Name: Handle Flash
* Author: Shish <webmaster@shishnet.org>
* Description: Handle Flash files
* Link: http://code.shishnet.org/shimmie2/
* Description: Handle Flash files. (No thumbnail is generated for flash files)
*/
class FlashFileHandler extends DataHandlerExtension {

View file

@ -2,7 +2,8 @@
/*
* Name: Handle SVG
* Author: Shish <webmaster@shishnet.org>
* Description: Handle SVG files
* Link: http://code.shishnet.org/shimmie2/
* Description: Handle SVG files. (No thumbnail is generated for SVG files)
*/
class SVGFileHandler implements Extension {

View file

@ -2,6 +2,7 @@
/*
* Name: IP Ban
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Ban IP addresses
* Documentation:
@ -92,7 +93,7 @@ class IPBan extends SimpleExtension {
public function onRemoveIPBan($event) {
global $database;
$database->Execute("DELETE FROM bans WHERE id = :id", array("id"=>$event->id));
$database->cache->delete("ip_bans");
$database->cache->delete("ip_bans_sorted");
}
// installer {{{
@ -261,7 +262,7 @@ class IPBan extends SimpleExtension {
global $database;
$sql = "INSERT INTO bans (ip, reason, end_timestamp, banner_id) VALUES (:ip, :reason, :end, :admin_id)";
$database->Execute($sql, array("ip"=>$ip, "reason"=>$reason, "end"=>strtotime($end), "admin_id"=>$user->id));
$database->cache->delete("ip_bans");
$database->cache->delete("ip_bans_sorted");
log_info("ipban", "'$user->name' has banned '$ip' because '$reason' until '$end'");
}
// }}}

View file

@ -1,8 +1,9 @@
<?php
/*
* Name: Logging (Database)
* Author: Shish
* Description: Keep a record of SCore events
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* Description: Keep a record of SCore events (in the database).
* Visibility: admin
*/

View file

@ -2,6 +2,7 @@
/*
* Name: News
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Show a short amount of text in a block on the post list
* Documentation:

3408
contrib/notes/jquery.js vendored

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
/*
* Name: Image Scores (Numeric)
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Allow users to score images
* Documentation:

View file

@ -57,11 +57,24 @@ class PrivMsg extends SimpleExtension {
subject VARCHAR(64) NOT NULL,
message TEXT NOT NULL,
is_read SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N,
INDEX (to_id)
INDEX (to_id),
FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE,
FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE
");
$config->set_int("pm_version", 1);
log_info("pm", "extension installed");
}
if($config->get_int("pm_version") < 2) {
log_info("pm", "Adding foreign keys to private messages");
$database->Execute("delete from private_message where to_id not in (select id from users);");
$database->Execute("delete from private_message where from_id not in (select id from users);");
$database->Execute("ALTER TABLE private_message
ADD CONSTRAINT foreign_private_message_from_id FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT foreign_private_message_to_id FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE;");
$config->set_int("pm_version", 2);
log_info("pm", "extension installed");
}
}
/*

View file

@ -2,6 +2,7 @@
/*
* Name: Random Image
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Do things with a random image
* Documentation:

View file

@ -2,6 +2,7 @@
/*
* Name: Image Ratings
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Allow users to rate images "safe", "questionable" or "explicit"
*/

View file

@ -2,6 +2,7 @@
/*
* Name: Regen Thumb
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Description: Regenerate a thumbnail image
* Documentation:

View file

@ -2,6 +2,7 @@
/*
* Name: Site Description
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* License: GPLv2
* Visibility: admin
* Description: A description for search engines

View file

@ -8,17 +8,17 @@ interface Config {
* so that the next time a page is loaded it will use the new
* configuration
*/
public function save($name=null);
public function save(/*string*/ $name=null);
/** @name set_*
* Set a configuration option to a new value, regardless
* of what the value is at the moment
*/
//@{
public function set_int($name, $value);
public function set_string($name, $value);
public function set_bool($name, $value);
public function set_array($name, $value);
public function set_int(/*string*/ $name, $value);
public function set_string(/*string*/ $name, $value);
public function set_bool(/*string*/ $name, $value);
public function set_array(/*string*/ $name, $value);
//@}
/** @name set_default_*
@ -30,10 +30,10 @@ interface Config {
* "default" paramater won't show up.
*/
//@{
public function set_default_int($name, $value);
public function set_default_string($name, $value);
public function set_default_bool($name, $value);
public function set_default_array($name, $value);
public function set_default_int(/*string*/ $name, $value);
public function set_default_string(/*string*/ $name, $value);
public function set_default_bool(/*string*/ $name, $value);
public function set_default_array(/*string*/ $name, $value);
//@}
/** @name get_*
@ -41,10 +41,10 @@ interface Config {
* appropritate data type
*/
//@{
public function get_int($name, $default=null);
public function get_string($name, $default=null);
public function get_bool($name, $default=null);
public function get_array($name, $default=array());
public function get_int(/*string*/ $name, $default=null);
public function get_string(/*string*/ $name, $default=null);
public function get_bool(/*string*/ $name, $default=null);
public function get_array(/*string*/ $name, $default=array());
//@}
}
@ -56,60 +56,60 @@ interface Config {
abstract class BaseConfig implements Config {
var $values = array();
public function set_int($name, $value) {
public function set_int(/*string*/ $name, $value) {
$this->values[$name] = parse_shorthand_int($value);
$this->save($name);
}
public function set_string($name, $value) {
public function set_string(/*string*/ $name, $value) {
$this->values[$name] = $value;
$this->save($name);
}
public function set_bool($name, $value) {
public function set_bool(/*string*/ $name, $value) {
$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N');
$this->save($name);
}
public function set_array($name, $value) {
public function set_array(/*string*/ $name, $value) {
assert(is_array($value));
$this->values[$name] = implode(",", $value);
$this->save($name);
}
public function set_default_int($name, $value) {
public function set_default_int(/*string*/ $name, $value) {
if(is_null($this->get($name))) {
$this->values[$name] = parse_shorthand_int($value);
}
}
public function set_default_string($name, $value) {
public function set_default_string(/*string*/ $name, $value) {
if(is_null($this->get($name))) {
$this->values[$name] = $value;
}
}
public function set_default_bool($name, $value) {
public function set_default_bool(/*string*/ $name, $value) {
if(is_null($this->get($name))) {
$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N');
}
}
public function set_default_array($name, $value) {
public function set_default_array(/*string*/ $name, $value) {
assert(is_array($value));
if(is_null($this->get($name))) {
$this->values[$name] = implode(",", $value);
}
}
public function get_int($name, $default=null) {
public function get_int(/*string*/ $name, $default=null) {
return (int)($this->get($name, $default));
}
public function get_string($name, $default=null) {
public function get_string(/*string*/ $name, $default=null) {
return $this->get($name, $default);
}
public function get_bool($name, $default=null) {
public function get_bool(/*string*/ $name, $default=null) {
return undb_bool($this->get($name, $default));
}
public function get_array($name, $default=array()) {
public function get_array(/*string*/ $name, $default=array()) {
return explode(",", $this->get($name, ""));
}
private function get($name, $default=null) {
private function get(/*string*/ $name, $default=null) {
if(isset($this->values[$name])) {
return $this->values[$name];
}
@ -144,7 +144,7 @@ class StaticConfig extends BaseConfig {
}
}
public function save($name=null) {
public function save(/*string*/ $name=null) {
// static config is static
}
}
@ -167,7 +167,7 @@ class DatabaseConfig extends BaseConfig {
/*
* Load the config table from a database
*/
public function DatabaseConfig($database) {
public function DatabaseConfig(Database $database) {
$this->database = $database;
$cached = $this->database->cache->get("config");
@ -186,11 +186,11 @@ class DatabaseConfig extends BaseConfig {
/*
* Save the current values as the new config table
*/
public function save($name=null) {
public function save(/*string*/ $name=null) {
if(is_null($name)) {
reset($this->values); // rewind the array to the first element
foreach($this->values as $name => $value) {
$this->save($name);
$this->save(/*string*/ $name);
}
}
else {

View file

@ -310,7 +310,7 @@ class Database {
}
$matches = array();
if(CACHE_DSN && preg_match("#(memcache|apc)://(.*)#", CACHE_DSN, $matches)) {
if( defined("CACHE_DSN") && CACHE_DSN && preg_match("#(memcache|apc)://(.*)#", CACHE_DSN, $matches)) {
if($matches[1] == "memcache") {
$this->cache = new MemcacheCache($matches[2]);
}

View file

@ -39,6 +39,8 @@ class PageRequestEvent extends Event {
* Test if the requested path matches a given pattern.
*
* If it matches, store the remaining path elements in $args
*
* @retval bool
*/
public function page_matches(/*string*/ $name) {
$parts = explode("/", $name);
@ -57,6 +59,11 @@ class PageRequestEvent extends Event {
return true;
}
/**
* Get the n th argument of the page request (if it exists.)
* @param $n integer
* @retval The argmuent (string) or NULL
*/
public function get_arg(/*int*/ $n) {
$offset = $this->part_count + $n;
if($offset >= 0 && $offset < $this->arg_count) {
@ -67,6 +74,10 @@ class PageRequestEvent extends Event {
}
}
/**
* Returns the number of arguments the page request has.
* @retval int
*/
public function count_args() {
return (int)($this->arg_count - $this->part_count);
}

View file

@ -191,7 +191,7 @@ abstract class DataHandlerExtension extends SimpleExtension {
}
}
public function onThumnbnailGeneration(ThumbnailGenerationEvent $event) {
public function onThumbnailGeneration(ThumbnailGenerationEvent $event) {
if($this->supported_ext($event->type)) {
if (method_exists($this, 'create_thumb_force') && $event->force == true) {
$this->create_thumb_force($event->hash);

View file

@ -106,18 +106,26 @@ class Image {
/**
* Search for an array of images
*
* @retval Array
*/
public static function find_images($start, $limit, $tags=array()) {
public static function find_images(/*int*/ $start, /*int*/ $limit, $tags=array()) {
assert(is_numeric($start));
assert(is_numeric($limit));
assert(is_array($tags));
global $database;
global $database, $user;
$images = array();
if($start < 0) $start = 0;
if($limit < 1) $limit = 1;
if(SPEED_HAX) {
if(!$user->can("big_search") and count($tags) > 3) {
die("Anonymous users may only search for up to 3 tags at a time"); // FIXME: throw an exception?
}
}
$querylet = Image::build_search_querylet($tags);
$querylet->append(new Querylet("ORDER BY images.id DESC LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start)));
#var_dump($querylet->sql); var_dump($querylet->variables);
@ -377,7 +385,7 @@ class Image {
/**
* Set the image's source URL
*/
public function set_source($source) {
public function set_source(/*string*/ $source) {
global $database;
if(empty($source)) $source = null;
if($source != $this->source) {
@ -386,7 +394,10 @@ class Image {
}
}
/**
* Check if the image is locked.
* @retval bool
*/
public function is_locked() {
return ($this->locked === true || $this->locked == "Y" || $this->locked == "t");
}

View file

@ -39,7 +39,7 @@ class Page {
/** @private */
var $mode = "page";
/** @private */
var $type = "text/html";
var $type = "text/html; charset=utf-8";
/**
* Set what this page should do; "page", "data", or "redirect".
@ -196,8 +196,8 @@ class Page {
switch($this->mode) {
case "page":
header("Vary: Cookie, Accept-Encoding");
if(CACHE_HTTP) {
header("Vary: Cookie, Accept-Encoding");
if($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") {
header("Cache-control: public, max-age=600");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT');
@ -236,6 +236,8 @@ class Page {
protected function add_auto_html_headers() {
$data_href = get_base_href();
$this->add_html_header("<script type='text/javascript'>base_href = '$data_href';</script>");
/* Attempt to cache the CSS & JavaScript files */
if ($this->add_cached_auto_html_headers() === FALSE) {

View file

@ -4,6 +4,7 @@ function _new_user($row) {
return new User($row);
}
/**
* An object representing a row in the "users" table.
*
@ -90,6 +91,77 @@ class User {
/*
* useful user object functions start here
*/
public function can($ability) {
global $config;
// TODO: make this into an editable database table
$user_classes = array(
"anonymous" => array(
"change_setting" => False, # web-level settings, eg the config table
"override_config" => False, # sys-level config, eg config.php
"big_search" => False, # more than 3 tags (speed mode only)
"lock_image" => False,
"view_ip" => False, # view IP addresses associated with things
"change_password" => False,
"change_user_info" => False,
"delete_user" => False,
"delete_image" => False,
"delete_comment" => False,
"replace_image" => False,
"manage_extension_list" => False,
"manage_alias_list" => False,
"edit_tag" => $config->get_bool("tag_edit_anon"),
"edit_source" => $config->get_bool("source_edit_anon"),
"mass_tag_edit" => False,
),
"user" => array(
"change_setting" => False,
"override_config" => False,
"big_search" => True,
"lock_image" => False,
"view_ip" => False,
"change_password" => False,
"change_user_info" => False,
"delete_user" => False,
"delete_image" => False,
"delete_comment" => False,
"replace_image" => False,
"manage_extension_list" => False,
"manage_alias_list" => False,
"edit_tag" => True,
"edit_source" => True,
"mass_tag_edit" => False,
),
"admin" => array(
"change_setting" => True,
"override_config" => True,
"big_search" => True,
"lock_image" => True,
"view_ip" => True,
"change_password" => True,
"change_user_info" => True,
"delete_user" => True,
"delete_image" => True,
"delete_comment" => True,
"replace_image" => True,
"manage_extension_list" => True,
"manage_alias_list" => True,
"edit_tag" => True,
"edit_source" => True,
"mass_tag_edit" => True,
),
);
return $user_classes[$this->get_class()][$ability];
}
// FIXME: this should be a column in the users table
public function get_class() {
if($this->is_admin()) return "admin";
else if($this->is_logged_in()) return "user";
else return"anonymous";
}
/**
* Test if this user is anonymous (not logged in)
@ -144,6 +216,7 @@ class User {
/**
* Get a snippet of HTML which will render the user's avatar, be that
* a local file, a remote file, a gravatar, a something else, etc
* @retval String of HTML
*/
public function get_avatar_html() {
// FIXME: configurable
@ -170,6 +243,8 @@ class User {
* authtok = md5(sesskey, salt), presented to the user in web forms, to make sure that
* the form was generated within the session. Salted and re-hashed so that
* reading a web page from the user's cache doesn't give access to the session key
*
* @retval String containing auth token (MD5sum)
*/
public function get_auth_token() {
global $config;

View file

@ -190,12 +190,26 @@ function undb_bool($val) {
if($val === false || $val == 'N' || $val == 'n' || $val == 'F' || $val == 'f' || $val === 0) return false;
}
function startsWith($haystack, $needle) {
/**
* Checks if a given string contains another at the beginning.
*
* @param $haystack String to examine.
* @param $needle String to look for.
* @retval bool
*/
function startsWith(/*string*/ $haystack, /*string*/ $needle) {
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}
function endsWith($haystack, $needle) {
/**
* Checks if a given string contains another at the end.
*
* @param $haystack String to examine.
* @param $needle String to look for.
* @retval bool
*/
function endsWith(/*string*/ $haystack, /*string*/ $needle) {
$length = strlen($needle);
$start = $length * -1; //negative
return (substr($haystack, $start) === $needle);
@ -621,6 +635,7 @@ function log_msg($section, $priority, $message) {
send_event(new LogEvent($section, $priority, $message));
}
// More shorthand ways of logging
function log_debug($section, $message) {log_msg($section, SCORE_LOG_DEBUG, $message);}
function log_info($section, $message) {log_msg($section, SCORE_LOG_INFO, $message);}
function log_warning($section, $message) {log_msg($section, SCORE_LOG_WARNING, $message);}
@ -847,6 +862,13 @@ function send_event(Event $event) {
// string representation of a number, it's two numbers separated by a space.
// What the fuck were the PHP developers smoking.
$_load_start = microtime(true);
/**
* Collects some debug information (execution time, memory usage, queries, etc)
* and formats it to stick in the footer of the page.
*
* @retval String of debug info to add to the page.
*/
function get_debug_info() {
global $config, $_event_count, $database, $_execs, $_load_start;
@ -879,7 +901,7 @@ function get_debug_info() {
// print_obj ($object, $title, $return)
function print_obj($object,$title="Object Information", $return=false) {
global $user;
if(DEBUG && isset($_GET['debug']) && $user->is_admin()) {
if(DEBUG && isset($_GET['DEBUG']) && $user->can("override_config")) {
$pr = print_r($object,true);
$count = substr_count($pr,"\n")<=25?substr_count($pr,"\n"):25;
$pr = "<textarea rows='".$count."' cols='80'>$pr</textarea>";
@ -1051,6 +1073,9 @@ function _load_extensions() {
ctx_log_endok();
}
/**
* Used to display fatal errors to the web user.
*/
function _fatal_error(Exception $e) {
$version = VERSION;
$message = $e->getMessage();

View file

@ -28,7 +28,7 @@ class AliasEditor extends SimpleExtension {
if($event->page_matches("alias")) {
if($event->get_arg(0) == "add") {
if($user->is_admin()) {
if($user->can("manage_alias_list")) {
if(isset($_POST['oldtag']) && isset($_POST['newtag'])) {
try {
$aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']);
@ -43,7 +43,7 @@ class AliasEditor extends SimpleExtension {
}
}
else if($event->get_arg(0) == "remove") {
if($user->is_admin()) {
if($user->can("manage_alias_list")) {
if(isset($_POST['oldtag'])) {
$database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", array("oldtag" => $_POST['oldtag']));
log_info("alias_editor", "Deleted alias for ".$_POST['oldtag']);
@ -74,7 +74,7 @@ class AliasEditor extends SimpleExtension {
$total_pages = ceil($database->get_one("SELECT COUNT(*) FROM aliases") / $alias_per_page);
$this->theme->display_aliases($page, $alias, $user->is_admin(), $page_number + 1, $total_pages);
$this->theme->display_aliases($alias, $page_number + 1, $total_pages);
}
else if($event->get_arg(0) == "export") {
$page->set_mode("data");
@ -82,7 +82,7 @@ class AliasEditor extends SimpleExtension {
$page->set_data($this->get_alias_csv($database));
}
else if($event->get_arg(0) == "import") {
if($user->is_admin()) {
if($user->can("manage_alias_list")) {
if(count($_FILES) > 0) {
$tmp = $_FILES['alias_file']['tmp_name'];
$contents = file_get_contents($tmp);
@ -115,7 +115,7 @@ class AliasEditor extends SimpleExtension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user;
if($user->is_admin()) {
if($user->can("manage_alias_list")) {
$event->add_link("Alias Editor", make_link("alias/list"));
}
}

View file

@ -5,10 +5,13 @@ class AliasEditorTheme extends Themelet {
* Show a page of aliases:
*
* $aliases = an array of ($old_tag => $new_tag)
* $is_admin = whether things like "add new alias" should be shown
* $can_manage = whether things like "add new alias" should be shown
*/
public function display_aliases(Page $page, $aliases, $is_admin, $pageNumber, $totalPages) {
if($is_admin) {
public function display_aliases($aliases, $pageNumber, $totalPages) {
global $page, $user;
$can_manage = $user->can("manage_alias_list");
if($can_manage) {
$action = "<th width='10%'>Action</th>";
$add = "
<tr>
@ -33,7 +36,7 @@ class AliasEditorTheme extends Themelet {
$oe = ($n++ % 2 == 0) ? "even" : "odd";
$h_aliases .= "<tr class='$oe'><td>$h_old</td><td>$h_new</td>";
if($is_admin) {
if($can_manage) {
$h_aliases .= "
<td>
".make_form(make_link("alias/remove"))."
@ -70,7 +73,7 @@ class AliasEditorTheme extends Themelet {
$page->set_heading("Alias List");
$page->add_block(new NavBlock());
$page->add_block(new Block("Aliases", $html));
if($is_admin) {
if($can_manage) {
$page->add_block(new Block("Bulk Upload", $bulk_html, "main", 51));
}

View file

@ -38,7 +38,8 @@ class BBCode extends FormatterExtension {
$text = preg_replace("/\[i\](.*?)\[\/i\]/s", "<i>\\1</i>", $text);
$text = preg_replace("/\[u\](.*?)\[\/u\]/s", "<u>\\1</u>", $text);
$text = preg_replace("/\[s\](.*?)\[\/s\]/s", "<s>\\1</s>", $text);
$text = preg_replace("/&gt;&gt;(\d+)/s", "<a href=\"".make_link("post/view/\\1")."\">&gt;&gt;\\1</a>", $text);
$text = preg_replace("/&gt;&gt;(\d+)(#\d+)?/s", "<a href=\"".make_link("post/view/\\1\\2")."\">&gt;&gt;\\1\\2</a>", $text);
$text = preg_replace("/(^|\s)#(\d+)/s", "\\1<a href=\"#\\2\">#\\2</a>", $text);
$text = preg_replace("/&gt;&gt;([^\d].+)/", "<blockquote><small>\\1</small></blockquote>", $text);
$text = preg_replace("/\[url=((?:https?|ftp|irc|mailto):\/\/.*?)\](.*?)\[\/url\]/s", "<a href=\"\\1\">\\2</a>", $text);
$text = preg_replace("/\[url\]((?:https?|ftp|irc|mailto):\/\/.*?)\[\/url\]/s", "<a href=\"\\1\">\\1</a>", $text);

View file

@ -128,7 +128,7 @@ class CommentList extends SimpleExtension {
}
}
else if($event->get_arg(0) === "delete") {
if($user->is_admin()) {
if($user->can("delete_comment")) {
// FIXME: post, not args
if($event->count_args() === 3) {
send_event(new CommentDeletionEvent($event->get_arg(1)));
@ -173,7 +173,6 @@ class CommentList extends SimpleExtension {
$h_comment_rate = sprintf("%.1f", ($i_comment_count / $i_days_old));
$event->add_stats("Comments made: $i_comment_count, $h_comment_rate per day");
global $user;
$recent = $this->get_user_recent_comments($event->display_user->id, 10);
$this->theme->display_user_comments($recent);
}

View file

@ -143,46 +143,53 @@ class CommentListTheme extends Themelet {
$h_name = html_escape($comment->owner_name);
$h_poster_ip = html_escape($comment->poster_ip);
$h_timestamp = autodate($comment->posted);
$h_comment = ($trim ? substr($tfe->stripped, 0, 50)."..." : $tfe->formatted);
$h_comment = ($trim ? substr($tfe->stripped, 0, 50) . (strlen($tfe->stripped) > 50 ? "..." : "") : $tfe->formatted);
$i_comment_id = int_escape($comment->comment_id);
$i_image_id = int_escape($comment->image_id);
$anoncode = "";
if($h_name == "Anonymous" && $this->anon_id >= 0) {
$anoncode = '<sup>'.$this->anon_id.'</sup>';
$this->anon_id++;
if($h_name == "Anonymous") {
$anoncode = "";
if($this->anon_id >= 0) {
$anoncode = '<sup>'.$this->anon_id.'</sup>';
$this->anon_id++;
}
$h_userlink = $h_name . $anoncode;
}
else {
$h_userlink = '<a href="'.make_link('user/'.$h_name).'">'.$h_name.'</a>';
}
$h_userlink = '<a href="'.make_link('user/'.$h_name).'">'.$h_name.'</a>'.$anoncode;
$stripped_nonl = str_replace("\n", "\\n", substr($tfe->stripped, 0, 50));
$stripped_nonl = str_replace("\r", "\\r", $stripped_nonl);
$h_dellink = $user->is_admin() ?
'<br>('.$h_poster_ip.', '.$h_timestamp.', <a '.
'onclick="return confirm(\'Delete comment by '.$h_name.':\\n'.$stripped_nonl.'\');" '.
'href="'.make_link('comment/delete/'.$i_comment_id.'/'.$i_image_id).'">Del</a>)' : '';
if($trim) {
return '
'.$h_userlink.': '.$h_comment.'
<a href="'.make_link('post/view/'.$i_image_id).'">&gt;&gt;&gt;</a>
'.$h_dellink.'
';
}
else {
//$avatar = "";
//if(!empty($comment->owner->email)) {
// $hash = md5(strtolower($comment->owner->email));
// $avatar = "<img src=\"http://www.gravatar.com/avatar/$hash.jpg\"><br>";
//}
$oe = ($this->comments_shown++ % 2 == 0) ? "even" : "odd";
$avatar = "";
if(!empty($comment->owner_email)) {
$hash = md5(strtolower($comment->owner_email));
$avatar = "<img src=\"http://www.gravatar.com/avatar/$hash.jpg\"><br>";
}
$h_reply = " - <a href='javascript: replyTo($i_image_id, $i_comment_id)'>Reply</a>";
$h_ip = $user->can("view_ip") ? "<br>$h_poster_ip" : "";
$h_del = $user->can("delete_comment") ?
' - <a onclick="return confirm(\'Delete comment by '.$h_name.':\\n'.$stripped_nonl.'\');" '.
'href="'.make_link('comment/delete/'.$i_comment_id.'/'.$i_image_id).'">Del</a>' : '';
return '
<a name="'.$i_comment_id.'"></a>
<div class="'.$oe.' comment">
<!--<span class="timeago" style="float: right;">'.$h_timestamp.'</span>-->
'.$h_userlink.': '.$h_comment.'
'.$h_dellink.'
<div class="comment">
<div class="info">
'.$avatar.'
'.$h_timestamp.$h_reply.$h_ip.$h_del.'
</div>
'.$h_userlink.': '.$h_comment.'
</div>
';
}
return "";
}
protected function build_postbox($image_id) {
@ -196,7 +203,7 @@ class CommentListTheme extends Themelet {
'.make_form(make_link("comment/add")).'
<input type="hidden" name="image_id" value="'.$i_image_id.'" />
<input type="hidden" name="hash" value="'.$hash.'" />
<textarea name="comment" rows="5" cols="50"></textarea>
<textarea id="comment_on_'.$i_image_id.'" name="comment" rows="5" cols="50"></textarea>
'.$captcha.'
<br><input type="submit" value="Post Comment" />
</form>

View file

@ -91,7 +91,7 @@ class ExtManager extends SimpleExtension {
public function onPageRequest(PageRequestEvent $event) {
global $page, $user;
if($event->page_matches("ext_manager")) {
if($user->is_admin()) {
if($user->can("manage_extension_list")) {
if($event->get_arg(0) == "set" && $user->check_auth_token()) {
if(is_writable("ext")) {
$this->set_things($_POST);
@ -130,7 +130,7 @@ class ExtManager extends SimpleExtension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user;
if($user->is_admin()) {
if($user->can("manage_extension_list")) {
$event->add_link("Extension Manager", make_link("ext_manager"));
}
else {

View file

@ -162,7 +162,7 @@ class ImageIO extends SimpleExtension {
}
if($event->page_matches("image_admin/delete")) {
global $page, $user;
if($user->is_admin() && isset($_POST['image_id']) && $user->check_auth_token()) {
if($user->can("delete_image") && isset($_POST['image_id']) && $user->check_auth_token()) {
$image = Image::by_id($_POST['image_id']);
if($image) {
send_event(new ImageDeletionEvent($image));
@ -173,7 +173,7 @@ class ImageIO extends SimpleExtension {
}
if($event->page_matches("image_admin/replace")) {
global $page, $user;
if($user->is_admin() && isset($_POST['image_id']) && $user->check_auth_token()) {
if($user->can("replace_image") && isset($_POST['image_id']) && $user->check_auth_token()) {
$image = Image::by_id($_POST['image_id']);
if($image) {
$page->set_mode("redirect");
@ -190,11 +190,11 @@ class ImageIO extends SimpleExtension {
global $user;
global $config;
if($user->is_admin()) {
if($user->can("delete_image")) {
$event->add_part($this->theme->get_deleter_html($event->image->id));
}
/* In the future, could perhaps allow users to replace images that they own as well... */
if ($user->is_admin() && $config->get_bool("upload_replace")) {
if ($user->can("replace_image") && $config->get_bool("upload_replace")) {
$event->add_part($this->theme->get_replace_html($event->image->id));
}
}

View file

@ -79,23 +79,8 @@ and of course start organising your images :-)
$h_search_string = html_escape(implode(" ", $search_terms));
$h_search_link = make_link();
$h_search = "
<script type='text/javascript'><!--
$(document).ready(function() {
$('#search_input').DefaultValue('Search');
$('#search_input').autocomplete('".make_link("api/internal/tag_list/complete")."', {
width: 320,
max: 15,
highlight: false,
multiple: true,
multipleSeparator: ' ',
scroll: true,
scrollHeight: 300,
selectFirst: false
});
});
//--></script>
<p><form action='$h_search_link' method='GET'>
<input id='search_input' name='search' type='text'
<input class='search_input' id='search_input' name='search' type='text'
value='$h_search_string' autocomplete='off' />
<input type='hidden' name='q' value='/post/list'>
<input type='submit' value='Find' style='display: none;' />

View file

@ -187,7 +187,7 @@ class Setup extends SimpleExtension {
}
if($event->page_matches("setup")) {
if(!$user->is_admin()) {
if(!$user->can("change_setting")) {
$this->theme->display_permission_denied($page);
}
else {
@ -329,7 +329,7 @@ class Setup extends SimpleExtension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user;
if($user->is_admin()) {
if($user->can("change_setting")) {
$event->add_link("Board Config", make_link("setup"));
}
}

View file

@ -60,7 +60,7 @@ class TagEdit extends SimpleExtension {
global $user, $page;
if($event->page_matches("tag_edit")) {
if($event->get_arg(0) == "replace") {
if($user->is_admin() && isset($_POST['search']) && isset($_POST['replace'])) {
if($user->can("mass_tag_edit") && isset($_POST['search']) && isset($_POST['replace'])) {
$search = $_POST['search'];
$replace = $_POST['replace'];
$this->mass_tag_edit($search, $replace);
@ -82,7 +82,7 @@ class TagEdit extends SimpleExtension {
else {
$this->theme->display_error($page, "Error", "Anonymous tag editing is disabled");
}
if($user->is_admin()) {
if($user->can("lock_image")) {
$locked = isset($_POST['tag_edit__locked']) && $_POST['tag_edit__locked']=="on";
send_event(new LockSetEvent($event->image, $locked));
}
@ -90,21 +90,21 @@ class TagEdit extends SimpleExtension {
public function onTagSet(TagSetEvent $event) {
global $user;
if($user->is_admin() || !$event->image->is_locked()) {
if($user->can("edit_tag") || !$event->image->is_locked()) {
$event->image->set_tags($event->tags);
}
}
public function onSourceSet(SourceSetEvent $event) {
global $user;
if($user->is_admin() || !$event->image->is_locked()) {
if($user->can("edit_tag") || !$event->image->is_locked()) {
$event->image->set_source($event->source);
}
}
public function onLockSet(LockSetEvent $event) {
global $user;
if($user->is_admin()) {
if($user->can("lock_image")) {
$event->image->set_locked($event->locked);
}
}
@ -130,7 +130,7 @@ class TagEdit extends SimpleExtension {
if($this->can_source($event->image)) {
$event->add_part($this->theme->get_source_editor_html($event->image), 41);
}
if($user->is_admin()) {
if($user->can("lock_image")) {
$event->add_part($this->theme->get_lock_editor_html($event->image), 42);
}
}
@ -147,7 +147,7 @@ class TagEdit extends SimpleExtension {
global $config, $user;
return (
($config->get_bool("tag_edit_anon") || !$user->is_anonymous()) &&
($user->is_admin() || !$image->is_locked())
($user->can("edit_tag") || !$image->is_locked())
);
}
@ -155,7 +155,7 @@ class TagEdit extends SimpleExtension {
global $config, $user;
return (
($config->get_bool("source_edit_anon") || !$user->is_anonymous()) &&
($user->is_admin() || !$image->is_locked())
($user->can("edit_source") || !$image->is_locked())
);
}

View file

@ -1,7 +1,8 @@
<?php
/*
/**
* Name: Tag List
* Author: Shish
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* Description: Show the tags in various ways
*/
@ -107,13 +108,18 @@ class TagList extends SimpleExtension {
return make_link("post/list/$u_tag/1");
}
/**
* Get the minimum number of times a tag needs to be used
* in order to be considered in the tag list.
* @retval int
*/
private function get_tags_min() {
if(isset($_GET['mincount'])) {
return int_escape($_GET['mincount']);
}
else {
global $config;
return $config->get_int('tags_min');
return $config->get_int('tags_min'); // get the default.
}
}
@ -170,6 +176,8 @@ class TagList extends SimpleExtension {
$tags_min = $this->get_tags_min();
$starts_with = $this->get_starts_with();
// check if we have a cached version
$cache_key = "data/tag_cloud-" . md5("tc" . $tags_min . $starts_with) . ".html";
if(file_exists($cache_key)) {return file_get_contents($cache_key);}
@ -205,6 +213,8 @@ class TagList extends SimpleExtension {
$tags_min = $this->get_tags_min();
$starts_with = $this->get_starts_with();
// check if we have a cached version
$cache_key = "data/tag_alpha-" . md5("ta" . $tags_min . $starts_with) . ".html";
if(file_exists($cache_key)) {return file_get_contents($cache_key);}
@ -239,6 +249,8 @@ class TagList extends SimpleExtension {
global $database;
$tags_min = $this->get_tags_min();
// check if we have a cached version
$cache_key = "data/tag_popul-" . md5("tp" . $tags_min) . ".html";
if(file_exists($cache_key)) {return file_get_contents($cache_key);}

View file

@ -1,7 +1,8 @@
<?php
/*
* Name: Database Upgrader
* Author: Shish
* Author: Shish <webmaster@shishnet.org>
* Link: http://code.shishnet.org/shimmie2/
* Description: Keeps things happy behind the scenes
* Visibility: admin
*/
@ -10,6 +11,8 @@ class Upgrade extends SimpleExtension {
public function onInitExt(InitExtEvent $event) {
global $config, $database;
if($config->get_bool("in_upgrade")) return;
if(!is_numeric($config->get_string("db_version"))) {
$config->set_int("db_version", 2);
}
@ -18,28 +21,43 @@ class Upgrade extends SimpleExtension {
// cry :S
}
if($config->get_int("db_version") < 7) {
/*
// mysql-adodb specific
if($database->engine->name == "mysql") {
$tables = $database->db->MetaTables();
foreach($tables as $table) {
log_info("upgrade", "converting $table to innodb");
$database->execute("ALTER TABLE $table TYPE=INNODB");
}
}
*/
$config->set_int("db_version", 7);
log_info("upgrade", "Database at version 7");
}
// v7 is convert to innodb with adodb
// now done again as v9 with PDO
if($config->get_int("db_version") < 8) {
// if this fails, don't try again
$config->set_bool("in_upgrade", true);
$config->set_int("db_version", 8);
$database->execute($database->engine->scoreql_to_sql(
"ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N"
));
log_info("upgrade", "Database at version 8");
$config->set_bool("in_upgrade", false);
}
if($config->get_int("db_version") < 9) {
$config->set_bool("in_upgrade", true);
if($database->db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') {
$tables = $database->get_col("SHOW TABLES");
foreach($tables as $table) {
log_info("upgrade", "converting $table to innodb");
$database->execute("ALTER TABLE $table TYPE=INNODB");
}
}
$config->set_int("db_version", 9);
log_info("upgrade", "Database at version 9");
$config->set_bool("in_upgrade", false);
}
if($config->get_int("db_version") < 10) {
$config->set_bool("in_upgrade", true);
log_info("upgrade", "Adding foreign keys to images");
$database->Execute("ALTER TABLE images ADD CONSTRAINT foreign_images_owner_id FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT");
$config->set_int("db_version", 10);
log_info("upgrade", "Database at version 10");
$config->set_bool("in_upgrade", false);
}
}

View file

@ -1,5 +1,5 @@
<?php
/*
/**
* Name: Uploader
* Author: Shish
* Description: Allows people to upload files to the website
@ -122,7 +122,7 @@ class Upload extends SimpleExtension {
}
// check if the user is an administrator and can upload files.
if(!$user->is_admin()) {
if(!$user->can("replace_image")) {
$this->theme->display_permission_denied($page);
}
else {
@ -224,14 +224,28 @@ class Upload extends SimpleExtension {
}
// }}}
// do things {{{
/**
* Check if a given user can upload.
* @param $user The user to check.
* @retval bool
*/
private function can_upload(User $user) {
global $config;
return ($config->get_bool("upload_anon") || !$user->is_anonymous());
}
// Helper function based on the one from the online PHP Documentation
// which is licensed under Creative Commons Attribution 3.0 License
// TODO: Make these messages user/admin editable
/**
* Returns a descriptive error message for the specified PHP error code.
*
* This is a helper function based on the one from the online PHP Documentation
* which is licensed under Creative Commons Attribution 3.0 License
*
* TODO: Make these messages user/admin editable
*
* @param $error_code PHP error code (int)
* @retval String
*/
private function upload_error_message($error_code) {
switch ($error_code) {
case UPLOAD_ERR_INI_SIZE:
@ -253,6 +267,10 @@ class Upload extends SimpleExtension {
}
}
/**
* Handle an upload.
* @retval bool TRUE on upload successful.
*/
private function try_upload($file, $tags, $source, $replace='') {
global $page;
global $config;
@ -299,6 +317,10 @@ class Upload extends SimpleExtension {
return $ok;
}
/**
* Handle an transload.
* @retval bool TRUE on transload successful.
*/
private function try_transload($url, $tags, $source, $replace='') {
global $page;
global $config;
@ -314,7 +336,7 @@ class Upload extends SimpleExtension {
}
// Checks if user is admin > check if you want locked.
if($user->is_admin() && !empty($_GET['locked'])){
if($user->can("lock_image") && !empty($_GET['locked'])){
$locked = bool_escape($_GET['locked']);
}

View file

@ -158,7 +158,7 @@ class UserPage extends SimpleExtension {
$this->theme->display_error($page, "Not Logged In",
"You aren't logged in. First do that, then you can see your stats.");
}
else if(!is_null($display_user)) {
else if(!is_null($display_user) && ($display_user->id != $config->get_int("anon_id"))) {
send_event(new UserPageBuildingEvent($display_user));
}
else {
@ -187,7 +187,7 @@ class UserPage extends SimpleExtension {
$this->theme->display_user_links($page, $user, $ubbe->parts);
}
if(
($user->is_admin() || ($user->is_logged_in() && $user->id == $event->display_user->id)) && # admin or self-user
($user->can("view_ip") || ($user->is_logged_in() && $user->id == $event->display_user->id)) && # admin or self-user
($event->display_user->id != $config->get_int('anon_id')) # don't show anon's IP list, it is le huge
) {
$this->theme->display_ip_list(
@ -256,7 +256,7 @@ class UserPage extends SimpleExtension {
$user_id = int_escape($matches[2]);
$event->add_querylet(new Querylet("images.owner_id = $user_id"));
}
else if($user->is_admin() && preg_match("/^(poster|user)_ip=([0-9\.]+)$/i", $event->term, $matches)) {
else if($user->can("view_ip") && preg_match("/^(poster|user)_ip=([0-9\.]+)$/i", $event->term, $matches)) {
$user_ip = $matches[2]; // FIXME: ip_escape?
$event->add_querylet(new Querylet("images.owner_ip = '$user_ip'"));
}
@ -354,7 +354,7 @@ class UserPage extends SimpleExtension {
$duser = User::by_id($id);
if((!$user->is_admin()) && ($duser->name != $user->name)) {
if((!$user->can("change_user_info")) && ($duser->name != $user->name)) {
$this->theme->display_error($page, "Error",
"You need to be an admin to change other people's passwords");
}
@ -392,7 +392,7 @@ class UserPage extends SimpleExtension {
$duser = User::by_id($id);
if((!$user->is_admin()) && ($duser->name != $user->name)) {
if((!$user->can("change_user_info")) && ($duser->name != $user->name)) {
$this->theme->display_error($page, "Error",
"You need to be an admin to change other people's addressess");
}
@ -419,7 +419,7 @@ class UserPage extends SimpleExtension {
$page->set_title("Error");
$page->set_heading("Error");
$page->add_block(new NavBlock());
if(!$user->is_admin()) {
if(!$user->can("change_user_info")) {
$page->add_block(new Block("Not Admin", "Only admins can edit accounts"));
}
else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) {
@ -479,7 +479,7 @@ class UserPage extends SimpleExtension {
$page->set_heading("Error");
$page->add_block(new NavBlock());
if (!$user->is_admin()) {
if (!$user->can("delete_user")) {
$page->add_block(new Block("Not Admin", "Only admins can delete accounts"));
}
else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) {
@ -510,7 +510,7 @@ class UserPage extends SimpleExtension {
$page->set_heading("Error");
$page->add_block(new NavBlock());
if (!$user->is_admin()) {
if (!$user->can("delete_user") || !$user->can("delete_image")) {
$page->add_block(new Block("Not Admin", "Only admins can delete accounts"));
}
else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) {

View file

@ -141,7 +141,7 @@ class UserPageTheme extends Themelet {
$page->add_block(new Block("Stats", join("<br>", $stats), "main", 0));
if(!$user->is_anonymous()) {
if($user->id == $duser->id || $user->is_admin()) {
if($user->id == $duser->id || $user->can("change_user_info")) {
$page->add_block(new Block("Options", $this->build_options($duser), "main", 20));
}
}
@ -173,7 +173,7 @@ class UserPageTheme extends Themelet {
</form>
";
if($user->is_admin()) {
if($user->can("change_user_info")) {
$i_user_id = int_escape($duser->id);
$h_is_admin = $duser->is_admin() ? " checked" : "";
$html .= "

View file

@ -90,7 +90,7 @@ class ViewImageTheme extends Themelet {
$html = "";
$html .= "<p>Uploaded by <a href='".make_link("user/$h_owner")."'>$h_owner</a> $h_date";
if($user->is_admin()) {
if($user->can("view_ip")) {
$html .= " ($h_ip)";
}
if(!is_null($image->source)) {

View file

@ -50,7 +50,7 @@
* Each of these can be imported at the start of a function with eg "global $page, $user;"
*/
if(empty($database_dsn) && !file_exists("config.php")) {
if(!file_exists("config.php")) {
header("Location: install.php");
exit;
}

View file

@ -1,7 +1,8 @@
<?php ob_start(); ?>
<html>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<!--
- install.php (c) Shish 2007
- install.php (c) Shish et all. 2007-2012
-
- Initialise the database, check that folder
- permissions are set properly, set an admin
@ -12,17 +13,18 @@
-->
<head>
<title>Shimmie Installation</title>
<style>
BODY {background: #EEE;font-family: "Arial", sans-serif;font-size: 14px;}
H1, H3 {border: 1px solid black;background: #DDD;text-align: center;}
H1 {margin-top: 0px;margin-bottom: 0px;padding: 2px;}
H3 {margin-top: 32px;padding: 1px;}
FORM {margin: 0px;}
A {text-decoration: none;}
A:hover {text-decoration: underline;}
#block {width: 512px; margin: auto; margin-top: 64px;}
#iblock {width: 512px; margin: auto; margin-top: 16px;}
TD INPUT {width: 350px;}
<link rel="shortcut icon" href="/favicon.ico" />
<style type="text/css">
BODY {background: #EEE;font-family: "Arial", sans-serif;font-size: 14px;}
H1, H3 {border: 1px solid black;background: #DDD;text-align: center;}
H1 {margin-top: 0px;margin-bottom: 0px;padding: 2px;}
H3 {margin-top: 32px;padding: 1px;}
FORM {margin: 0px;}
A {text-decoration: none;}
A:hover {text-decoration: underline;}
#block {width: 512px; margin: auto; margin-top: 64px;}
#iblock {width: 512px; margin: auto; margin-top: 16px;}
TD INPUT {width: 350px;}
</style>
</head>
<body>
@ -31,9 +33,10 @@ TD INPUT {width: 350px;}
<h1>Install Error</h1>
<p>Shimmie needs to be run via a web server with PHP support -- you
appear to be either opening the file from your hard disk, or your
web server is mis-configured.
web server is mis-configured.</p>
<p>If you've installed a web server on your desktop PC, you probably
want to visit <a href="http://localhost/">the local web server</a>.
want to visit <a href="http://localhost/">the local web server</a>.<br/><br/>
</p>
</div>
<div style="display: none;">
<PLAINTEXT>
@ -51,9 +54,32 @@ if(is_readable("config.php")) {
<div id="iblock">
<h1>Shimmie Repair Console</h1>
<?php
include "config.php";
if($_SESSION['dsn'] == DATABASE_DSN || $_POST['dsn'] == DATABASE_DSN) {
if($_POST['dsn']) {$_SESSION['dsn'] = $_POST['dsn'];}
/*
* Compute the path to the folder containing "install.php" and
* store it as the 'Shimmie Root' folder for later on.
*
* Example:
* __SHIMMIE_ROOT__ = '/var/www/shimmie2/'
*
*/
define('__SHIMMIE_ROOT__', trim( remove_trailing_slash( dirname(__FILE__) ) ) . '/' );
// Pull in necessary files
require_once __SHIMMIE_ROOT__."config.php"; // Load user/site specifics First
require_once __SHIMMIE_ROOT__."core/default_config.inc.php"; // Defaults for the rest.
require_once __SHIMMIE_ROOT__."core/util.inc.php";
require_once __SHIMMIE_ROOT__."core/database.class.php";
if (
( array_key_exists('dsn', $_SESSION) && $_SESSION['dsn'] === DATABASE_DSN ) ||
( array_key_exists('dsn', $_POST) && $_POST['dsn'] === DATABASE_DSN )
)
{
if ( array_key_exists('dsn', $_POST) && !empty($_POST['dsn']) )
{
$_SESSION['dsn'] = $_POST['dsn'];
}
if(empty($_GET["action"])) {
echo "<h3>Basic Checks</h3>";
@ -76,15 +102,6 @@ if(is_readable("config.php")) {
</form>
";
*/
echo "<h3>Database quick fix for User deletion</h3>";
echo "just a database fix for those who instaled shimmie before 2012 january the 22rd.<br>";
echo "Note: some things needs to be done manually, to work properly.<br>";
echo "WARNING: ONLY PROCEEDS IF YOU KNOW WHAT YOU ARE DOING!";
echo "
<form action='install.php?action=Database_user_deletion_fix' method='POST'>
<input type='submit' value='go!'>
</form>
";
echo "<h3>Log Out</h3>";
echo "
@ -95,15 +112,12 @@ if(is_readable("config.php")) {
}
else if($_GET["action"] == "logout") {
session_destroy();
}
else if($_GET["action"] == "Database_user_deletion_fix") {
Database_user_deletion_fix();
echo "<h3>Logged Out</h3><p>You have been logged out.</p><a href='index.php'>Main Shimmie Page</a>";
}
} else {
echo "
<h3>Login</h3>
Enter the database DSN exactly as in config.php (ie, as originally
installed) to access advanced recovery tools:
<p>Enter the database DSN exactly as in config.php (ie, as originally installed) to access advanced recovery tools:</p>
<form action='install.php' method='POST'>
<center>
@ -118,13 +132,24 @@ if(is_readable("config.php")) {
echo "\t\t</div>";
exit;
}
require_once "core/compat.inc.php";
require_once "core/util.inc.php";
require_once "core/database.class.php";
do_install();
// utilities {{{
/**
* Strips off any kind of slash at the end so as to normalise the path.
* @param string $path Path to normalise.
* @return string Path without trailing slash.
*/
function remove_trailing_slash($path) {
if ((substr($path, -1) === '/') || (substr($path, -1) === '\\')) {
return substr($path, 0, -1);
} else {
return $path;
}
}
function check_gd_version() {
$gdversion = 0;
@ -249,7 +274,7 @@ function begin() { // {{{
<h3>Help</h3>
<p>Please make sure the database you have chosen exists and is empty.<br>
The username provided must have access to create tables within the database.
The username provided must have access to create tables within the database.</p>
</div>
EOD;
@ -315,7 +340,7 @@ function create_tables() { // {{{
CONSTRAINT foreign_image_tags_image_id FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE,
CONSTRAINT foreign_image_tags_tag_id FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE
");
$db->execute("INSERT INTO config(name, value) VALUES('db_version', 8)");
$db->execute("INSERT INTO config(name, value) VALUES('db_version', 10)");
}
catch (PDOException $e)
{
@ -354,11 +379,12 @@ function build_dirs() { // {{{
!file_exists("images") || !file_exists("thumbs") || !file_exists("data") ||
!is_writable("images") || !is_writable("thumbs") || !is_writable("data")
) {
print "Shimmie needs three folders in it's directory, 'images', 'thumbs', and 'data',
and they need to be writable by the PHP user (if you see this error,
if probably means the folders are owned by you, and they need to be
writable by the web server).
<p>Once you have created these folders, hit 'refresh' to continue.";
print "<p>Shimmie needs three folders in it's directory, 'images', 'thumbs', and 'data',
and they need to be writable by the PHP user.</p>
<p>If you see this error, if probably means the folders are owned by you, and they need to be
writable by the web server.</p>
<p>PHP reports that it is currently running as user: ".$_ENV["USER"]." (". $_SERVER["USER"] .")</p>
<p>Once you have created these folders and/or changed the ownership of the shimmie folder, hit 'refresh' to continue.</p>";
exit;
}
} // }}}
@ -387,49 +413,6 @@ EOD;
exit;
}
} // }}}
function Database_user_deletion_fix() {
try {
require_once "core/database.class.php";
$db = new Database();
echo "Fixing user_favorites table....";
($db->Execute("ALTER TABLE user_favorites ENGINE=InnoDB;")) ? print_r("ok<br>") : print_r("failed<br>");
echo "adding Foreign key to user ids...";
($db->Execute("ALTER TABLE user_favorites ADD CONSTRAINT foreign_user_favorites_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;"))? print_r("ok<br>"):print_r("failed<br>");
echo "cleaning, the table from deleted image favorites...<br>";
$rows = $db->get_all("SELECT * FROM user_favorites WHERE image_id NOT IN ( SELECT id FROM images );");
foreach( $rows as $key => $value)
$db->Execute("DELETE FROM user_favorites WHERE image_id = :image_id;", array("image_id" => $value["image_id"]));
echo "adding forign key to image ids...";
($db->Execute("ALTER TABLE user_favorites ADD CONSTRAINT user_favorites_image_id FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE;"))? print_r("ok<br>"):print_r("failed<br>");
echo "adding foreign keys to private messages...";
($db->Execute("ALTER TABLE private_message
ADD CONSTRAINT foreign_private_message_from_id FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE,
ADD CONSTRAINT foreign_private_message_to_id FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE;")) ? print_r("ok<br>"):print_r("failed<br>");
echo "Just one more step...which you need to do manually:<br>";
echo "You need to go to your database and Delete the foreign key on the owner_id in the images table.<br><br>";
echo "<a href='http://www.justin-cook.com/wp/2006/05/09/how-to-remove-foreign-keys-in-mysql/'>How to remove foreign keys</a><br><br>";
echo "and finally execute this querry:<br><br>";
echo "ALTER TABLE images ADD CONSTRAINT foreign_images_owner_id FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;<br><br>";
echo "if this is all sucesfull you are done!";
}
catch (PDOException $e)
{
// FIXME: Make the error message user friendly
exit($e->getMessage());
}
}
?>
</body>
</html>

View file

@ -27,70 +27,25 @@ $(document).ready(function() {
});
$("time").timeago();
});
var defaultTexts = new Array();
$('.search_input').DefaultValue('Search');
$('#search_input').autocomplete(base_href + '/api/internal/tag_list/complete', {
width: 320,
max: 15,
highlight: false,
multiple: true,
multipleSeparator: ' ',
scroll: true,
scrollHeight: 300,
selectFirst: false
});
window.onload = function(e) {
var sections=get_sections();
for(var i=0;i<sections.length;i++) toggle(sections[i]);
initGray("search_input", "Search");
initGray("commentBox", "Comment");
initGray("tagBox", "tagme");
// if we're going to show with JS, hide with JS first
pass_confirm = byId("pass_confirm");
if(pass_confirm) {
pass_confirm.style.display = "none";
}
}
function initGray(boxname, text) {
var box = byId(boxname);
if(!box) return;
var clr = function () {cleargray(box, text);};
var set = function () {setgray(box, text);};
addEvent(box, "focus", clr, false);
addEvent(box, "blur", set, false);
if(box.value == text) {
box.style.color = "#999";
box.style.textAlign = "center";
}
else {
box.style.color = "#000";
box.style.textAlign = "left";
}
}
function cleargray(box, text) {
if(box.value == text) {
box.value = "";
box.style.color = "#000";
box.style.textAlign = "left";
}
}
function setgray(box, text) {
if(box.value == "") {
box.style.textAlign = "center";
box.style.color = "gray";
box.value = text;
}
}
function showUp(elem) {
e = document.getElementById(elem)
if(!e) return;
e.style.display = "";
// alert(e.type+": "+e.value);
if(e.value.match(/^http|^ftp/)) {
e.type = "text";
alert("Box is web upload");
}
}
$("#commentBox").DefaultValue("Comment");
$("#tagBox").DefaultValue("tagme");
});
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
@ -111,6 +66,7 @@ function byId(id) {
}
// used once in ext/setup/main
function getHTTPObject() {
if (window.XMLHttpRequest){
return new XMLHttpRequest();
@ -120,15 +76,6 @@ function getHTTPObject() {
}
}
function ajaxRequest(url, callback) {
var http = getHTTPObject();
http.open("GET", url, true);
http.onreadystatechange = function() {
if(http.readyState == 4) callback(http.responseText);
}
http.send(null);
}
/* get, set, and delete cookies */
function getCookie( name ) {
@ -164,3 +111,10 @@ function deleteCookie( name, path, domain ) {
";expires=Thu, 01-Jan-1970 00:00:01 GMT";
}
function replyTo(imageId, commentId) {
var box = $("#comment_on_"+imageId);
var text = ">>"+imageId+"#"+commentId+": ";
box.focus();
box.val(box.val() + text);
}

View file

@ -223,7 +223,9 @@ $header_html
<em>
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.
$debug
$contact

View file

@ -71,7 +71,9 @@ $header_html
<div id="footer">
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.
$debug
$contact

View file

@ -128,9 +128,8 @@ UL {
.comment {
text-align: left;
}
.comment .timeago {
float: right;
font-size: 75%;
.comment .info {
display: none;
}
.more:after {

View file

@ -71,7 +71,9 @@ $header_html
<div id="footer">
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.
$debug
$contact

View file

@ -79,7 +79,9 @@ $header_html
<hr>
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.
<br>Futaba theme based on 4chan's layout and CSS :3
$debug

View file

@ -184,7 +184,9 @@ class Layout {
<div id="footer">
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.<br />
Lite Theme by <a href="http://seemslegit.com">Zach</a>
$debug

View file

@ -69,7 +69,9 @@ $header_html
<hr>
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.
$debug
$contact

View file

@ -85,7 +85,9 @@ $header_html
<div id="footer">
Images &copy; their respective owners,
<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> &copy;
<a href="http://www.shishnet.org/">Shish</a> &amp; Co 2007-2012,
<a href="http://www.shishnet.org/">Shish</a> &amp;
<a href="https://github.com/shish/shimmie2/contributors">The Team</a>
2007-2012,
based on the Danbooru concept.
$debug
$contact