diff --git a/.gitignore b/.gitignore index 6dd0495a..57872564 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,10 @@ .svn +backup config.php -images -thumbs data +images +imgdump-*.zip +thumbs sql.log shimmie.log !lib/images diff --git a/contrib/admin/main.php b/contrib/admin/main.php index 3d03915d..e03cd69d 100644 --- a/contrib/admin/main.php +++ b/contrib/admin/main.php @@ -30,13 +30,13 @@ */ class AdminBuildingEvent extends Event { var $page; - public function AdminBuildingEvent($page) { + public function AdminBuildingEvent(Page $page) { $this->page = $page; } } -class AdminPage extends SimpleExtension { - public function onPageRequest($event) { +class AdminPage extends Extension { + public function onPageRequest(PageRequestEvent $event) { global $page, $user; if($event->page_matches("admin")) { @@ -78,6 +78,13 @@ class AdminPage extends SimpleExtension { case 'database dump': $this->dbdump($page); break; + case 'reset image ids': + $this->reset_imageids(); + $redirect = true; + break; + case 'image dump': + $this->imgdump($page); + break; } if($redirect) { @@ -88,20 +95,20 @@ class AdminPage extends SimpleExtension { } } - public function onAdminBuilding($event) { + public function onAdminBuilding(AdminBuildingEvent $event) { global $page; $this->theme->display_page($page); $this->theme->display_form($page); } - public function onUserBlockBuilding($event) { + public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; if($user->is_admin()) { $event->add_link("Board Admin", make_link("admin")); } } - private function delete_by_query($query) { + private function delete_by_query(/*array(string)*/ $query) { global $page, $user; assert(strlen($query) > 1); foreach(Image::find_images(0, 1000000, Tag::explode($query)) as $image) { @@ -175,5 +182,67 @@ class AdminPage extends SimpleExtension { } } */ + + private function reset_imageids() { + global $database; + //This might be a bit laggy on boards with lots of images (?) + //Seems to work fine with 1.2k~ images though. + $i = 0; + $image = $database->get_all("SELECT * FROM images ORDER BY images.id ASC"); + /*$score_log = $database->get_all("SELECT message FROM score_log");*/ + foreach($image as $img){ + $xid = $img[0]; + $i = $i + 1; + $table = array( //Might be missing some tables? + "image_tags", "tag_histories", "image_reports", "comments", "user_favorites", "tag_histories", + "numeric_score_votes", "pool_images", "slext_progress_cache", "notes"); + + $sql = + "SET FOREIGN_KEY_CHECKS=0; + UPDATE images + SET id=".$i. + " WHERE id=".$xid.";"; //id for images + + foreach($table as $tbl){ + $sql .= " + UPDATE ".$tbl." + SET image_id=".$i." + WHERE image_id=".$xid.";"; + } + + /*foreach($score_log as $sl){ + //This seems like a bad idea. + //TODO: Might be better for log_info to have an $id option (which would then affix the id to the table?) + preg_replace(".Image \\#[0-9]+.", "Image #".$i, $sl); + }*/ + $sql .= " SET FOREIGN_KEY_CHECKS=1;"; + $database->execute($sql); + } + $count = (count($image)) + 1; + $database->execute("ALTER TABLE images AUTO_INCREMENT=".$count); + } + + private function imgdump($page) { + global $database; + $zip = new ZipArchive; + $images = $database->get_all("SELECT * FROM images"); + $filename = 'imgdump-'.date('Ymd').'.zip'; + + if($zip->open($filename, 1 ? ZIPARCHIVE::OVERWRITE:ZIPARCHIVE::CREATE)===TRUE){ + foreach($images as $img){ + $hash = $img["hash"]; + preg_match("^[A-Za-z0-9]{2}^", $hash, $matches); + $img_loc = "images/".$matches[0]."/".$hash; + if(file_exists($img_loc)){ + $zip->addFile($img_loc, $hash.".".$img["ext"]); + } + + } + $zip->close(); + } + $page->set_mode("redirect"); + $page->set_redirect(make_link($filename)); //Fairly sure there is better way to do this.. + //TODO: Delete file after downloaded? + } } ?> diff --git a/contrib/admin/theme.php b/contrib/admin/theme.php index 18cc9687..e72a372a 100644 --- a/contrib/admin/theme.php +++ b/contrib/admin/theme.php @@ -19,13 +19,26 @@ class AdminPageTheme extends Themelet { public function display_form(Page $page) { global $user; - $html = " - ".make_form(make_link("admin_utils"))." - + + diff --git a/contrib/amazon_s3/main.php b/contrib/amazon_s3/main.php index 741b7378..b4191a69 100644 --- a/contrib/amazon_s3/main.php +++ b/contrib/amazon_s3/main.php @@ -9,7 +9,7 @@ require_once "lib/S3.php"; -class UploadS3 extends SimpleExtension { +class UploadS3 extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_string("amazon_s3_access", ""); diff --git a/contrib/artists/main.php b/contrib/artists/main.php index 0bde987d..4c2422fa 100644 --- a/contrib/artists/main.php +++ b/contrib/artists/main.php @@ -11,7 +11,7 @@ class AuthorSetEvent extends Event { var $image, $user, $author; - public function AuthorSetEvent(Image $image, User $user, $author) + public function AuthorSetEvent(Image $image, User $user, /*string*/ $author) { $this->image = $image; $this->user = $user; @@ -19,41 +19,37 @@ class AuthorSetEvent extends Event { } } -class Artists implements Extension { - var $theme; - - public function get_priority() {return 50;} - - public function receive_event(Event $event) - { +class Artists extends Extension { + public function onImageInfoSet(ImageInfoSetEvent $event) { global $user; - - if(is_null($this->theme)) $this->theme = get_theme_object($this); - - if ($event instanceof ImageInfoSetEvent) - if (isset($_POST["tag_edit__author"])) - send_event(new AuthorSetEvent($event->image, $user, $_POST["tag_edit__author"])); - - if ($event instanceof AuthorSetEvent) - $this->update_author($event); - - if($event instanceof InitExtEvent) - $this->try_install(); - - if ($event instanceof ImageInfoBoxBuildingEvent) - $this->add_author_field_to_image($event); - - if ($event instanceof PageRequestEvent) - $this->handle_commands($event); - - if ($event instanceof SearchTermParseEvent) { - $matches = array(); - if(preg_match("/^author=(.*)$/", $event->term, $matches)) { - $char = $matches[1]; - $event->add_querylet(new Querylet("Author = :author_char", array("author_char"=>$char))); - } + if (isset($_POST["tag_edit__author"])) { + send_event(new AuthorSetEvent($event->image, $user, $_POST["tag_edit__author"])); } - } + } + + public function onAuthorSet(AuthorSetEvent $event) { + $this->update_author($event); + } + + public function onInitExt(InitExtEvent $event) { + $this->try_install(); + } + + public function onImageInfoBoxBuilding(ImageInfoBoxBuildingEvent $event) { + $this->add_author_field_to_image($event); + } + + public function onPageRequest(PageRequestEvent $event) { + $this->handle_commands($event); + } + + public function onSearchTermParse(SearchTermParseEvent $event) { + $matches = array(); + if(preg_match("/^author=(.*)$/", $event->term, $matches)) { + $char = $matches[1]; + $event->add_querylet(new Querylet("Author = :author_char", array("author_char"=>$char))); + } + } public function try_install() { global $config, $database; diff --git a/contrib/ban_words/main.php b/contrib/ban_words/main.php index aee98417..f17b76bf 100644 --- a/contrib/ban_words/main.php +++ b/contrib/ban_words/main.php @@ -2,6 +2,7 @@ /* * Name: Comment Word Ban * Author: Shish + * Link: http://code.shishnet.org/shimmie2/ * License: GPLv2 * Description: For stopping spam and other comment abuse * Documentation: @@ -19,7 +20,7 @@ * from Essex" */ -class BanWords extends SimpleExtension { +class BanWords extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_string('banned_words', " diff --git a/contrib/blocks/main.php b/contrib/blocks/main.php index c3525c63..f3ee274d 100644 --- a/contrib/blocks/main.php +++ b/contrib/blocks/main.php @@ -27,8 +27,8 @@ * */ -class Blocks extends SimpleExtension { - public function onPageRequest($event) { +class Blocks extends Extension { + public function onPageRequest(PageRequestEvent $event) { global $config, $page; $all = $config->get_string("blocks_text"); $blocks = explode("----", $all); @@ -70,7 +70,7 @@ class Blocks extends SimpleExtension { } } - public function onSetupBuilding($event) { + public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("Blocks"); $sb->add_label("See the docs for formatting"); $sb->add_longtext_option("blocks_text"); diff --git a/contrib/blotter/main.php b/contrib/blotter/main.php index d689ba15..23dc5fe8 100644 --- a/contrib/blotter/main.php +++ b/contrib/blotter/main.php @@ -8,8 +8,8 @@ * * Development TODO at http://github.com/zshall/shimmie2/issues */ -class Blotter extends SimpleExtension { - public function onInitExt(Event $event) { +class Blotter extends Extension { + public function onInitExt(InitExtEvent $event) { /** * I love re-using this installer don't I... */ @@ -43,7 +43,7 @@ class Blotter extends SimpleExtension { $config->set_default_string("blotter_position", "subheading"); } - public function onSetupBuilding(Event $event) { + public function onSetupBuilding(SetupBuildingEvent $event) { global $config; $sb = new SetupBlock("Blotter"); $sb->add_int_option("blotter_recent", "
Number of recent entries to display: "); @@ -51,13 +51,13 @@ class Blotter extends SimpleExtension { $sb->add_choice_option("blotter_position", array("Top of page" => "subheading", "In navigation bar" => "left"), "
Position: "); $event->panel->add_block($sb); } - public function onUserBlockBuilding(Event $event) { + public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; if($user->is_admin()) { $event->add_link("Blotter Editor", make_link("blotter/editor")); } } - public function onPageRequest(Event $event) { + public function onPageRequest(PageRequestEvent $event) { global $page, $database, $user; if($event->page_matches("blotter")) { switch($event->get_arg(0)) { diff --git a/contrib/bookmarks/main.php b/contrib/bookmarks/main.php index da86f605..8e47bc83 100644 --- a/contrib/bookmarks/main.php +++ b/contrib/bookmarks/main.php @@ -6,16 +6,15 @@ * Description: Allow users to bookmark searches */ -class Bookmarks implements Extension { - var $theme; +class Bookmarks extends Extension { + public function onInitExt(InitExtEvent $event) { + $this->install(); + } - public function get_priority() {return 50;} + public function onPageRequest(PageRequestEvent $event) { + global $page; - public function receive_event(Event $event) { - global $config, $database, $page, $user; - if(is_null($this->theme)) $this->theme = get_theme_object($this); - - if(($event instanceof PageRequestEvent) && $event->page_matches("bookmark")) { + if($event->page_matches("bookmark")) { if($event->get_arg(0) == "add") { if(isset($_POST['url'])) { $page->set_mode("redirect"); diff --git a/contrib/browser_search/main.php b/contrib/browser_search/main.php index cf5ee6ac..78c3b878 100755 --- a/contrib/browser_search/main.php +++ b/contrib/browser_search/main.php @@ -13,36 +13,29 @@ * engine" notification they have */ -class BrowserSearch implements Extension { +class BrowserSearch extends Extension { + public function onInitExt(InitExtEvent $event) { + global $config; + $config->set_default_string("search_suggestions_results_order", 'a'); + } - public function get_priority() {return 50;} - public function receive_event(Event $event) { - global $page; - global $config; - - if($event instanceof InitExtEvent) { - $config->set_default_string("search_suggestions_results_order", 'a'); - } + public function onPageRequest(PageRequestEvent $event) { + global $config, $database, $page; // Add in header code to let the browser know that the search plugin exists - if($event instanceof PageRequestEvent) { - // We need to build the data for the header - global $config; - $search_title = $config->get_string('title'); - $search_file_url = make_link('browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml'); - $page->add_html_header(""); - } + // We need to build the data for the header + $search_title = $config->get_string('title'); + $search_file_url = make_link('browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml'); + $page->add_html_header(""); // The search.xml file that is generated on the fly - if(($event instanceof PageRequestEvent) && $event->page_matches("browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml")) { + if($event->page_matches("browser_search/please_dont_use_this_tag_as_it_would_break_stuff__search.xml")) { // First, we need to build all the variables we'll need - $search_title = $config->get_string('title'); $search_form_url = make_link('post/list/{searchTerms}'); $suggenton_url = make_link('browser_search/')."{searchTerms}"; $icon_b64 = base64_encode(file_get_contents("favicon.ico")); - // Now for the XML $xml = " @@ -63,12 +56,10 @@ class BrowserSearch implements Extension { $page->set_data($xml); } - else if(($event instanceof PageRequestEvent) && ( - $event->page_matches("browser_search") && - !$config->get_bool("disable_search_suggestions") - )) { - global $database; - + else if( + $event->page_matches("browser_search") && + !$config->get_bool("disable_search_suggestions") + ) { // We have to build some json stuff $tag_search = $event->get_arg(0); @@ -89,29 +80,25 @@ class BrowserSearch implements Extension { array_push($tags_array,$tag['tag']); } - $json_tag_list .= implode("\",\"", $tags_array); -// $json_tag_list = implode($tags_array,", "); -// $json_tag_list = "\"".implode($tags_array,"\", \"")."\""; - // And now for the final output $json_string = "[\"$tag_search\",[\"$json_tag_list\"],[],[]]"; $page->set_mode("data"); $page->set_data($json_string); } + } - if($event instanceof SetupBuildingEvent) { - $sort_by = array(); - $sort_by['Alphabetical'] = 'a'; - $sort_by['Tag Count'] = 't'; + public function onSetupBuilding(SetupBuildingEvent $event) { + $sort_by = array(); + $sort_by['Alphabetical'] = 'a'; + $sort_by['Tag Count'] = 't'; - $sb = new SetupBlock("Browser Search"); - $sb->add_bool_option("disable_search_suggestions", "Disable search suggestions: "); - $sb->add_label("
"); - $sb->add_choice_option("search_suggestions_results_order", $sort_by, "Sort the suggestions by:"); - $event->panel->add_block($sb); - } + $sb = new SetupBlock("Browser Search"); + $sb->add_bool_option("disable_search_suggestions", "Disable search suggestions: "); + $sb->add_label("
"); + $sb->add_choice_option("search_suggestions_results_order", $sort_by, "Sort the suggestions by:"); + $event->panel->add_block($sb); } } ?> diff --git a/contrib/bulk_add/main.php b/contrib/bulk_add/main.php index 0fa89029..90f6f96a 100644 --- a/contrib/bulk_add/main.php +++ b/contrib/bulk_add/main.php @@ -2,6 +2,7 @@ /* * Name: Bulk Add * Author: Shish + * Link: http://code.shishnet.org/shimmie2/ * License: GPLv2 * Description: Bulk add server-side images * Documentation: @@ -14,8 +15,8 @@ *

Note: requires the "admin" extension to be enabled */ -class BulkAdd extends SimpleExtension { - public function onPageRequest($event) { +class BulkAdd extends Extension { + public function onPageRequest(PageRequestEvent $event) { global $page, $user; if($event->page_matches("bulk_add")) { if($user->is_admin() && $user->check_auth_token() && isset($_POST['dir'])) { @@ -26,11 +27,13 @@ class BulkAdd extends SimpleExtension { } } - public function onAdminBuilding($event) { + public function onAdminBuilding(AdminBuildingEvent $event) { $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)); diff --git a/contrib/danbooru_api/main.php b/contrib/danbooru_api/main.php index 898680f2..ad9cc13c 100644 --- a/contrib/danbooru_api/main.php +++ b/contrib/danbooru_api/main.php @@ -47,33 +47,23 @@ Completely compatibility will probably involve a rewrite with a different URL */ -class DanbooruApi implements Extension -{ - - public function get_priority() {return 50;} - // Receive the event - public function receive_event(Event $event) - { - // Check if someone is accessing /api/danbooru (us) - if(($event instanceof PageRequestEvent) && ($event->page_matches("api")) && ($event->get_arg(0) == 'danbooru')) - { - // execute the danbooru processing code +class DanbooruApi extends Extension { + public function onPageRequest(PageRequestEvent $event) { + if($event->page_matches("api") && ($event->get_arg(0) == 'danbooru')) { $this->api_danbooru($event); } - if($event instanceof SearchTermParseEvent) - { - $matches = array(); - if(preg_match("/^md5:([0-9a-fA-F]*)$/i", $event->term, $matches)) - { - $hash = strtolower($matches[1]); - $event->add_querylet(new Querylet("images.hash = '$hash'")); // :-O -// $event->set_querylet(new Querylet("images.hash = '$hash'")); - } + } + + public function onSearchTermParse(SearchTermParseEvent $event) { + $matches = array(); + if(preg_match("/^md5:([0-9a-fA-F]*)$/i", $event->term, $matches)) { + $hash = strtolower($matches[1]); + $event->add_querylet(new Querylet("images.hash = '$hash'")); // :-O } } // Danbooru API - private function api_danbooru($event) + private function api_danbooru(PageRequestEvent $event) { global $page; global $config; diff --git a/contrib/downtime/main.php b/contrib/downtime/main.php index 8c9ced34..3e87bdf3 100644 --- a/contrib/downtime/main.php +++ b/contrib/downtime/main.php @@ -11,7 +11,7 @@ * message specified in the box. */ -class Downtime extends SimpleExtension { +class Downtime extends Extension { public function get_priority() {return 10;} public function onSetupBuilding($event) { diff --git a/contrib/emoticons/main.php b/contrib/emoticons/main.php index 67d14e29..be958040 100644 --- a/contrib/emoticons/main.php +++ b/contrib/emoticons/main.php @@ -13,19 +13,19 @@ */ class Emoticons extends FormatterExtension { - public function format($text) { + public function format(/*string*/ $text) { $data_href = get_base_href(); $text = preg_replace("/:([a-z]*?):/s", "", $text); return $text; } - public function strip($text) { + public function strip(/*string*/ $text) { return $text; } } -class EmoticonList extends SimpleExtension { - public function onPageRequest($event) { +class EmoticonList extends Extension { + public function onPageRequest(PageRequestEvent $event) { if($event->page_matches("emote/list")) { $this->theme->display_emotes(glob("ext/emoticons/default/*")); } diff --git a/contrib/et/main.php b/contrib/et/main.php index dd6babe2..63545b08 100644 --- a/contrib/et/main.php +++ b/contrib/et/main.php @@ -12,8 +12,8 @@ * versions of PHP I should test with, etc. */ -class ET extends SimpleExtension { - public function onPageRequest($event) { +class ET extends Extension { + public function onPageRequest(PageRequestEvent $event) { global $user; if($event->page_matches("system_info")) { if($user->is_admin()) { @@ -22,13 +22,16 @@ class ET extends SimpleExtension { } } - public function onUserBlockBuilding($event) { + public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; if($user->is_admin()) { $event->add_link("System Info", make_link("system_info")); } } + /** + * 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/ @@ -46,9 +49,6 @@ class ET extends SimpleExtension { $info['sys_disk'] = to_shorthand_int(disk_total_space("./") - disk_free_space("./")) . " / " . to_shorthand_int(disk_total_space("./")); $info['sys_server'] = $_SERVER["SERVER_SOFTWARE"]; - $proto = preg_replace("#(.*)://.*#", "$1", DATABASE_DSN); - #$db = $database->db->ServerInfo(); - #$info['sys_db'] = "$proto / {$db['version']}"; $info['stat_images'] = $database->get_one("SELECT COUNT(*) FROM images"); $info['stat_comments'] = $database->get_one("SELECT COUNT(*) FROM comments"); diff --git a/contrib/favorites/main.php b/contrib/favorites/main.php index ad37edd0..7c14554f 100644 --- a/contrib/favorites/main.php +++ b/contrib/favorites/main.php @@ -16,7 +16,7 @@ class FavoriteSetEvent extends Event { var $image_id, $user, $do_set; - public function FavoriteSetEvent($image_id, User $user, $do_set) { + public function FavoriteSetEvent(/*int*/ $image_id, User $user, /*boolean*/ $do_set) { assert(is_numeric($image_id)); assert(is_bool($do_set)); @@ -26,15 +26,15 @@ class FavoriteSetEvent extends Event { } } -class Favorites extends SimpleExtension { - public function onInitExt($event) { +class Favorites extends Extension { + public function onInitExt(InitExtEvent $event) { global $config; if($config->get_int("ext_favorites_version", 0) < 1) { $this->install(); } } - public function onImageAdminBlockBuilding($event) { + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $database, $page, $user; if(!$user->is_anonymous()) { $user_id = $user->id; @@ -48,14 +48,14 @@ class Favorites extends SimpleExtension { } } - public function onDisplayingImage($event) { + public function onDisplayingImage(DisplayingImageEvent $event) { $people = $this->list_persons_who_have_favorited($event->image); if(count($people) > 0) { $html = $this->theme->display_people($people); } } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { global $page, $user; if($event->page_matches("change_favorite") && !$user->is_anonymous() && $user->check_auth_token()) { $image_id = int_escape($_POST['image_id']); @@ -67,7 +67,7 @@ class Favorites extends SimpleExtension { } } - public function onUserPageBuilding($event) { + public function onUserPageBuilding(UserPageBuildingEvent $event) { $i_favorites_count = Image::count_images(array("favorited_by={$event->display_user->name}")); $i_days_old = ((time() - strtotime($event->display_user->join_date)) / 86400) + 1; $h_favorites_rate = sprintf("%.1f", ($i_favorites_count / $i_days_old)); @@ -75,7 +75,7 @@ class Favorites extends SimpleExtension { $event->add_stats("Images favorited: $i_favorites_count, $h_favorites_rate per day"); } - public function onImageInfoSet($event) { + public function onImageInfoSet(ImageInfoSetEvent $event) { global $user; if( in_array('favorite_action', $_POST) && @@ -85,28 +85,30 @@ class Favorites extends SimpleExtension { } } - public function onFavoriteSet($event) { + public function onFavoriteSet(FavoriteSetEvent $event) { global $user; $this->add_vote($event->image_id, $user->id, $event->do_set); } - public function onImageDeletion($event) { + // FIXME: this should be handled by the foreign key. Check that it + // is, and then remove this + public function onImageDeletion(ImageDeletionEvent $event) { global $database; $database->execute("DELETE FROM user_favorites WHERE image_id=:image_id", array("image_id"=>$event->image->id)); } - public function onParseLinkTemplate($event) { + public function onParseLinkTemplate(ParseLinkTemplateEvent $event) { $event->replace('$favorites', $event->image->favorites); } - public function onUserBlockBuilding($event) { + public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; $username = url_escape($user->name); $event->add_link("My Favorites", make_link("post/list/favorited_by=$username/1"), 20); } - public function onSearchTermParse($event) { + public function onSearchTermParse(SearchTermParseEvent $event) { $matches = array(); if(preg_match("/favorites(<|>|<=|>=|=)(\d+)/", $event->term, $matches)) { $cmp = $matches[1]; @@ -152,6 +154,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) { @@ -170,7 +183,7 @@ class Favorites extends SimpleExtension { array("image_id"=>$image_id, "user_id"=>$user_id)); } - private function list_persons_who_have_favorited($image) { + private function list_persons_who_have_favorited(Image $image) { global $database; return $database->get_col( diff --git a/contrib/favorites/theme.php b/contrib/favorites/theme.php index 4bb452ae..14a4fd39 100644 --- a/contrib/favorites/theme.php +++ b/contrib/favorites/theme.php @@ -24,6 +24,8 @@ class FavoritesTheme extends Themelet { $i_favorites = count($username_array); $html = "$i_favorites people:"; + reset($username_array); // rewind to first element in array. + foreach($username_array as $row) { $username = html_escape($row); $html .= "
$username"; diff --git a/contrib/featured/main.php b/contrib/featured/main.php index 12f06b08..5dbc41dd 100644 --- a/contrib/featured/main.php +++ b/contrib/featured/main.php @@ -2,6 +2,7 @@ /* * Name: Featured Image * Author: Shish + * Link: http://code.shishnet.org/shimmie2/ * License: GPLv2 * Description: Bring a specific image to the users' attentions * Documentation: @@ -18,13 +19,13 @@ * every couple of hours. */ -class Featured extends SimpleExtension { - public function onInitExt($event) { +class Featured extends Extension { + public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_int('featured_id', 0); } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { global $config, $page, $user; if($event->page_matches("featured_image")) { if($event->get_arg(0) == "set" && $user->check_auth_token()) { @@ -54,7 +55,7 @@ class Featured extends SimpleExtension { } } - public function onPostListBuilding($event) { + public function onPostListBuilding(PostListBuildingEvent $event) { global $config, $database, $page, $user; $fid = $config->get_int("featured_id"); if($fid > 0) { @@ -74,7 +75,7 @@ class Featured extends SimpleExtension { } } - public function onImageAdminBlockBuilding($event) { + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user; if($user->is_admin()) { $event->add_part($this->theme->get_buttons_html($event->image->id)); diff --git a/contrib/forum/main.php b/contrib/forum/main.php index a2b2365e..cd5ccdaf 100644 --- a/contrib/forum/main.php +++ b/contrib/forum/main.php @@ -8,8 +8,8 @@ * Documentation: */ -class Forum extends SimpleExtension { - public function onInitExt($event) { +class Forum extends Extension { + public function onInitExt(InitExtEvent $event) { global $config, $database; // shortcut to latest @@ -57,7 +57,7 @@ class Forum extends SimpleExtension { $event->panel->add_block($sb); } - public function onUserPageBuilding($event) { + public function onUserPageBuilding(UserPageBuildingEvent $event) { global $page, $user, $database; $threads_count = $database->get_one("SELECT COUNT(*) FROM forum_threads WHERE user_id=?", array($event->display_user->id)); @@ -73,7 +73,7 @@ class Forum extends SimpleExtension { } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { global $page, $user; if($event->page_matches("forum")) { diff --git a/contrib/handle_archive/main.php b/contrib/handle_archive/main.php index 976f3ca0..2fb2498b 100644 --- a/contrib/handle_archive/main.php +++ b/contrib/handle_archive/main.php @@ -10,13 +10,13 @@ *
7-zip: 7zr x -o"%d" "%f" */ -class ArchiveFileHandler extends SimpleExtension { - public function onInitExt($event) { +class ArchiveFileHandler extends Extension { + public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_string('archive_extract_command', 'unzip -d "%d" "%f"'); } - public function onSetupBuilding($event) { + public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("Archive Handler Options"); $sb->add_text_option("archive_tmp_dir", "Temporary folder: "); $sb->add_text_option("archive_extract_command", "
Extraction command: "); @@ -24,7 +24,7 @@ class ArchiveFileHandler extends SimpleExtension { $event->panel->add_block($sb); } - public function onDataUpload($event) { + public function onDataUpload(DataUploadEvent $event) { if($this->supported_ext($event->type)) { global $config; $tmp = sys_get_temp_dir(); diff --git a/contrib/handle_flash/main.php b/contrib/handle_flash/main.php index 013528ac..21b19b30 100644 --- a/contrib/handle_flash/main.php +++ b/contrib/handle_flash/main.php @@ -2,7 +2,8 @@ /* * Name: Handle Flash * Author: Shish - * 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 { diff --git a/contrib/handle_ico/main.php b/contrib/handle_ico/main.php index 771dd506..7582fc53 100644 --- a/contrib/handle_ico/main.php +++ b/contrib/handle_ico/main.php @@ -5,8 +5,8 @@ * Description: Handle windows icons */ -class IcoFileHandler extends SimpleExtension { - public function onDataUpload($event) { +class IcoFileHandler extends Extension { + public function onDataUpload(DataUploadEvent $event) { if($this->supported_ext($event->type) && $this->check_contents($event->tmpname)) { $hash = $event->hash; $ha = substr($hash, 0, 2); @@ -22,20 +22,20 @@ class IcoFileHandler extends SimpleExtension { } } - public function onThumbnailGeneration($event) { + public function onThumbnailGeneration(ThumbnailGenerationEvent $event) { if($this->supported_ext($event->type)) { $this->create_thumb($event->hash); } } - public function onDisplayingImage($event) { + public function onDisplayingImage(DisplayingImageEvent $event) { global $page; if($this->supported_ext($event->image->ext)) { $this->theme->display_image($page, $event->image); } } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { global $config, $database, $page; if($event->page_matches("get_ico")) { $id = int_escape($event->get_arg(0)); diff --git a/contrib/handle_svg/main.php b/contrib/handle_svg/main.php index e2d02a3f..6cc3efe8 100644 --- a/contrib/handle_svg/main.php +++ b/contrib/handle_svg/main.php @@ -2,18 +2,13 @@ /* * Name: Handle SVG * Author: Shish - * 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 { - var $theme; - - public function get_priority() {return 50;} - - public function receive_event(Event $event) { - if(is_null($this->theme)) $this->theme = get_theme_object($this); - - if(($event instanceof DataUploadEvent) && $this->supported_ext($event->type) && $this->check_contents($event->tmpname)) { +class SVGFileHandler extends Extension { + public function onDataUpload(DataUploadEvent $event) { + if($this->supported_ext($event->type) && $this->check_contents($event->tmpname)) { $hash = $event->hash; $ha = substr($hash, 0, 2); if(!move_upload_to_archive($event)) return; @@ -26,33 +21,28 @@ class SVGFileHandler implements Extension { send_event($iae); $event->image_id = $iae->image->id; } + } - if(($event instanceof ThumbnailGenerationEvent) && $this->supported_ext($event->type)) { + public function onThumbnailGeneration(ThumbnailGenerationEvent $event) { + global $config; + if($this->supported_ext($event->type)) { $hash = $event->hash; $ha = substr($hash, 0, 2); - global $config; - -// if($config->get_string("thumb_engine") == "convert") { -// $w = $config->get_int("thumb_width"); -// $h = $config->get_int("thumb_height"); -// $q = $config->get_int("thumb_quality"); -// $mem = $config->get_int("thumb_max_memory") / 1024 / 1024; // IM takes memory in MB -// -// exec("convert images/{$ha}/{$hash}[0] -geometry {$w}x{$h} -quality {$q} jpg:thumbs/{$ha}/{$hash}"); -// } -// else { - copy("ext/handle_svg/thumb.jpg", warehouse_path("thumbs", $hash)); -// } + copy("ext/handle_svg/thumb.jpg", warehouse_path("thumbs", $hash)); } + } - if(($event instanceof DisplayingImageEvent) && $this->supported_ext($event->image->ext)) { - global $page; + public function onDisplayingImage(DisplayingImageEvent $event) { + global $page; + if($this->supported_ext($event->image->ext)) { $this->theme->display_image($page, $event->image); } + } - if(($event instanceof PageRequestEvent) && $event->page_matches("get_svg")) { - global $config, $database, $page; + public function onPageRequest(PageRequestEvent $event) { + global $config, $database, $page; + if($event->page_matches("get_svg")) { $id = int_escape($event->get_arg(0)); $image = Image::by_id($id); $hash = $image->hash; diff --git a/contrib/holiday/main.php b/contrib/holiday/main.php index aea352f8..f435099a 100644 --- a/contrib/holiday/main.php +++ b/contrib/holiday/main.php @@ -6,20 +6,20 @@ * License: GPLv2 * Description: Use an additional stylesheet on certain holidays. */ -class Holiday extends SimpleExtension { - public function onInitExt(Event $event) { +class Holiday extends Extension { + public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_bool("holiday_aprilfools", false); } - public function onSetupBuilding(Event $event) { + public function onSetupBuilding(SetupBuildingEvent $event) { global $config; $sb = new SetupBlock("Holiday Theme"); $sb->add_bool_option("holiday_aprilfools", "Enable April Fools"); $event->panel->add_block($sb); } - public function onPageRequest(Event $event) { + public function onPageRequest(PageRequestEvent $event) { global $config; $date = /*date('d/m') == '01/01' ||date('d/m') == '14/02' || */date('d/m') == '01/04'/* || date('d/m') == '24/12' || date('d/m') == '25/12' || date('d/m') == '31/12'*/; if($date){ diff --git a/contrib/home/main.php b/contrib/home/main.php index f9485309..2ac2412d 100644 --- a/contrib/home/main.php +++ b/contrib/home/main.php @@ -15,7 +15,7 @@ * alongside the default choices. */ -class Home extends SimpleExtension { +class Home extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_string("home_links", '[$base/post/list|Posts] diff --git a/contrib/image_hash_ban/main.php b/contrib/image_hash_ban/main.php index ab0f9bf0..79150d98 100644 --- a/contrib/image_hash_ban/main.php +++ b/contrib/image_hash_ban/main.php @@ -29,7 +29,7 @@ class AddImageHashBanEvent extends Event { } } // }}} -class ImageBan extends SimpleExtension { +class ImageBan extends Extension { public function onInitExt(InitExtEvent $event) { global $config, $database; if($config->get_int("ext_imageban_version") < 1) { diff --git a/contrib/ipban/main.php b/contrib/ipban/main.php index bd9a11d0..ceaa0f6a 100644 --- a/contrib/ipban/main.php +++ b/contrib/ipban/main.php @@ -2,6 +2,7 @@ /* * Name: IP Ban * Author: Shish + * Link: http://code.shishnet.org/shimmie2/ * License: GPLv2 * Description: Ban IP addresses * Documentation: @@ -34,10 +35,10 @@ class AddIPBanEvent extends Event { } // }}} -class IPBan extends SimpleExtension { +class IPBan extends Extension { public function get_priority() {return 10;} - public function onInitExt($event) { + public function onInitExt(InitExtEvent $event) { global $config; if($config->get_int("ext_ipban_version") < 5) { $this->install(); @@ -45,7 +46,7 @@ class IPBan extends SimpleExtension { $this->check_ip_ban(); } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { if($event->page_matches("ip_ban")) { global $config, $database, $page, $user; if($user->is_admin()) { @@ -77,19 +78,19 @@ class IPBan extends SimpleExtension { } } - public function onUserBlockBuilding($event) { + public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; if($user->is_admin()) { $event->add_link("IP Bans", make_link("ip_ban/list")); } } - public function onAddIPBan($event) { + public function onAddIPBan(AddIPBanEvent $event) { global $user; $this->add_ip_ban($event->ip, $event->reason, $event->end, $user); } - public function onRemoveIPBan($event) { + public function onRemoveIPBan(RemoveIPBanEvent $event) { global $database; $database->Execute("DELETE FROM bans WHERE id = :id", array("id"=>$event->id)); $database->cache->delete("ip_bans_sorted"); @@ -178,7 +179,7 @@ class IPBan extends SimpleExtension { } } - private function block($remote) { + private function block(/*string*/ $remote) { global $config, $database; $prefix = ($database->engine->name == "sqlite" ? "bans." : ""); diff --git a/contrib/link_image/main.php b/contrib/link_image/main.php index d8773362..ab52935e 100644 --- a/contrib/link_image/main.php +++ b/contrib/link_image/main.php @@ -4,29 +4,22 @@ * Author: Artanis * Description: Show various forms of link to each image, for copy & paste */ -class LinkImage implements Extension { - var $theme; +class LinkImage extends Extension { + public function onDisplayingImage(DisplayingImageEvent $event) { + global $page; + $this->theme->links_block($page, $this->data($event->image)); + } - public function get_priority() {return 50;} + public function onSetupBuildingEvent(SetupBuildingEvent $event) { + $sb = new SetupBlock("Link to Image"); + $sb->add_text_option("ext_link-img_text-link_format", "Text Link Format: "); + $event->panel->add_block($sb); + } - public function receive_event(Event $event) { - global $config, $database, $page, $user; - if(is_null($this->theme)) $this->theme = get_theme_object($this); - - if(($event instanceof DisplayingImageEvent)) { - $this->theme->links_block($page, $this->data($event->image)); - } - if($event instanceof SetupBuildingEvent) { - $sb = new SetupBlock("Link to Image"); - $sb->add_text_option("ext_link-img_text-link_format", "Text Link Format: "); - $event->panel->add_block($sb); - } - if($event instanceof InitExtEvent) { - //just set default if empty. - $config->set_default_string("ext_link-img_text-link_format", - '$title - $id ($ext $size $filesize)'); - } - } + public function onInitExtEvent(InitExtEvent $event) { + global $config; + $config->set_default_string("ext_link-img_text-link_format", '$title - $id ($ext $size $filesize)'); + } private function hostify($str) { $str = str_replace(" ", "%20", $str); @@ -37,7 +30,8 @@ class LinkImage implements Extension { return "http://" . $_SERVER["HTTP_HOST"] . $str; } } - private function data($image) { + + private function data(Image $image) { global $config; $text_link = $image->parse_link_template($config->get_string("ext_link-img_text-link_format")); diff --git a/contrib/log_db/main.php b/contrib/log_db/main.php index 2e51ce24..626b4360 100644 --- a/contrib/log_db/main.php +++ b/contrib/log_db/main.php @@ -1,13 +1,14 @@ + * Link: http://code.shishnet.org/shimmie2/ + * Description: Keep a record of SCore events (in the database). * Visibility: admin */ -class LogDatabase extends SimpleExtension { - public function onInitExt($event) { +class LogDatabase extends Extension { + public function onInitExt(InitExtEvent $event) { global $database; global $config; @@ -28,7 +29,7 @@ class LogDatabase extends SimpleExtension { $config->set_default_int("log_db_priority", SCORE_LOG_INFO); } - public function onSetupBuilding($event) { + public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("Logging (Database)"); $sb->add_choice_option("log_db_priority", array( "Debug" => SCORE_LOG_DEBUG, @@ -40,7 +41,7 @@ class LogDatabase extends SimpleExtension { $event->panel->add_block($sb); } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { global $database, $user; if($event->page_matches("log/view")) { if($user->is_admin()) { @@ -104,14 +105,14 @@ class LogDatabase extends SimpleExtension { } } - public function onUserBlockBuilding($event) { + public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; if($user->is_admin()) { $event->add_link("Event Log", make_link("log/view")); } } - public function onLog($event) { + public function onLog(LogEvent $event) { global $config, $database, $user; $username = ($user && $user->name) ? $user->name : "null"; diff --git a/contrib/log_db/theme.php b/contrib/log_db/theme.php index 6ac2d3a1..1d3d8ccf 100644 --- a/contrib/log_db/theme.php +++ b/contrib/log_db/theme.php @@ -41,6 +41,8 @@ class LogDatabaseTheme extends Themelet { \n"; $n = 0; + reset($events); // rewind to first element in array. + foreach($events as $event) { $oe = ($n++ % 2 == 0) ? "even" : "odd"; $c = $this->pri_to_col($event['priority']); diff --git a/contrib/mass_tagger/main.php b/contrib/mass_tagger/main.php index a83dda44..751cfcdf 100644 --- a/contrib/mass_tagger/main.php +++ b/contrib/mass_tagger/main.php @@ -14,8 +14,8 @@ * As of now only compatible with the lite theme. */ -class MassTagger extends SimpleExtension { - public function onPostListBuilding($event) { +class MassTagger extends Extension { + public function onPostListBuilding(PostListBuildingEvent $event) { global $config, $page, $user; if( !$user->is_admin() ) return; @@ -23,7 +23,7 @@ class MassTagger extends SimpleExtension { $this->theme->display_mass_tagger( $page, $event, $config ); } - public function onPageRequest($event) { + public function onPageRequest(PageRequestEvent $event) { global $config, $page, $user; if( !$event->page_matches("mass_tagger") ) return; if( !$user->is_admin() ) return; diff --git a/contrib/news/main.php b/contrib/news/main.php index 69c87255..e0b5911d 100644 --- a/contrib/news/main.php +++ b/contrib/news/main.php @@ -2,21 +2,22 @@ /* * Name: News * Author: Shish + * Link: http://code.shishnet.org/shimmie2/ * License: GPLv2 * Description: Show a short amount of text in a block on the post list * Documentation: * Any HTML is allowed */ -class News extends SimpleExtension { - public function onPostListBuilding($event) { +class News extends Extension { + public function onPostListBuilding(PostListBuildingEvent $event) { global $config, $page; if(strlen($config->get_string("news_text")) > 0) { $this->theme->display_news($page, $config->get_string("news_text")); } } - public function onSetupBuilding($event) { + public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("News"); $sb->add_longtext_option("news_text"); $event->panel->add_block($sb); diff --git a/contrib/notes/jquery.js b/contrib/notes/jquery.js deleted file mode 100644 index 2e43a823..00000000 --- a/contrib/notes/jquery.js +++ /dev/null @@ -1,3408 +0,0 @@ -(function(){ -/* - * jQuery 1.2.3 - New Wave Javascript - * - * Copyright (c) 2008 John Resig (jquery.com) - * Dual licensed under the MIT (MIT-LICENSE.txt) - * and GPL (GPL-LICENSE.txt) licenses. - * - * $Date: 2008-02-06 00:21:25 -0500 (Wed, 06 Feb 2008) $ - * $Rev: 4663 $ - */ - -// Map over jQuery in case of overwrite -if ( window.jQuery ) - var _jQuery = window.jQuery; - -var jQuery = window.jQuery = function( selector, context ) { - // The jQuery object is actually just the init constructor 'enhanced' - return new jQuery.prototype.init( selector, context ); -}; - -// Map over the $ in case of overwrite -if ( window.$ ) - var _$ = window.$; - -// Map the jQuery namespace to the '$' one -window.$ = jQuery; - -// A simple way to check for HTML strings or ID strings -// (both of which we optimize for) -var quickExpr = /^[^<]*(<(.|\s)+>)[^>]*$|^#(\w+)$/; - -// Is it a simple selector -var isSimple = /^.[^:#\[\.]*$/; - -jQuery.fn = jQuery.prototype = { - init: function( selector, context ) { - // Make sure that a selection was provided - selector = selector || document; - - // Handle $(DOMElement) - if ( selector.nodeType ) { - this[0] = selector; - this.length = 1; - return this; - - // Handle HTML strings - } else if ( typeof selector == "string" ) { - // Are we dealing with HTML string or an ID? - var match = quickExpr.exec( selector ); - - // Verify a match, and that no context was specified for #id - if ( match && (match[1] || !context) ) { - - // HANDLE: $(html) -> $(array) - if ( match[1] ) - selector = jQuery.clean( [ match[1] ], context ); - - // HANDLE: $("#id") - else { - var elem = document.getElementById( match[3] ); - - // Make sure an element was located - if ( elem ) - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id != match[3] ) - return jQuery().find( selector ); - - // Otherwise, we inject the element directly into the jQuery object - else { - this[0] = elem; - this.length = 1; - return this; - } - - else - selector = []; - } - - // HANDLE: $(expr, [context]) - // (which is just equivalent to: $(content).find(expr) - } else - return new jQuery( context ).find( selector ); - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) - return new jQuery( document )[ jQuery.fn.ready ? "ready" : "load" ]( selector ); - - return this.setArray( - // HANDLE: $(array) - selector.constructor == Array && selector || - - // HANDLE: $(arraylike) - // Watch for when an array-like object, contains DOM nodes, is passed in as the selector - (selector.jquery || selector.length && selector != window && !selector.nodeType && selector[0] != undefined && selector[0].nodeType) && jQuery.makeArray( selector ) || - - // HANDLE: $(*) - [ selector ] ); - }, - - // The current version of jQuery being used - jquery: "1.2.3", - - // The number of elements contained in the matched element set - size: function() { - return this.length; - }, - - // The number of elements contained in the matched element set - length: 0, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num == undefined ? - - // Return a 'clean' array - jQuery.makeArray( this ) : - - // Return just the object - this[ num ]; - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - // Build a new jQuery matched element set - var ret = jQuery( elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - - // Return the newly-formed element set - return ret; - }, - - // Force the current matched set of elements to become - // the specified array of elements (destroying the stack in the process) - // You should use pushStack() in order to do this, but maintain the stack - setArray: function( elems ) { - // Resetting the length to 0, then using the native Array push - // is a super-fast way to populate an object with array-like properties - this.length = 0; - Array.prototype.push.apply( this, elems ); - - return this; - }, - - // Execute a callback for every element in the matched set. - // (You can seed the arguments with an array of args, but this is - // only used internally.) - each: function( callback, args ) { - return jQuery.each( this, callback, args ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - var ret = -1; - - // Locate the position of the desired element - this.each(function(i){ - if ( this == elem ) - ret = i; - }); - - return ret; - }, - - attr: function( name, value, type ) { - var options = name; - - // Look for the case where we're accessing a style value - if ( name.constructor == String ) - if ( value == undefined ) - return this.length && jQuery[ type || "attr" ]( this[0], name ) || undefined; - - else { - options = {}; - options[ name ] = value; - } - - // Check to see if we're setting style values - return this.each(function(i){ - // Set all the styles - for ( name in options ) - jQuery.attr( - type ? - this.style : - this, - name, jQuery.prop( this, options[ name ], type, i, name ) - ); - }); - }, - - css: function( key, value ) { - // ignore negative width and height values - if ( (key == 'width' || key == 'height') && parseFloat(value) < 0 ) - value = undefined; - return this.attr( key, value, "curCSS" ); - }, - - text: function( text ) { - if ( typeof text != "object" && text != null ) - return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) ); - - var ret = ""; - - jQuery.each( text || this, function(){ - jQuery.each( this.childNodes, function(){ - if ( this.nodeType != 8 ) - ret += this.nodeType != 1 ? - this.nodeValue : - jQuery.fn.text( [ this ] ); - }); - }); - - return ret; - }, - - wrapAll: function( html ) { - if ( this[0] ) - // The elements to wrap the target around - jQuery( html, this[0].ownerDocument ) - .clone() - .insertBefore( this[0] ) - .map(function(){ - var elem = this; - - while ( elem.firstChild ) - elem = elem.firstChild; - - return elem; - }) - .append(this); - - return this; - }, - - wrapInner: function( html ) { - return this.each(function(){ - jQuery( this ).contents().wrapAll( html ); - }); - }, - - wrap: function( html ) { - return this.each(function(){ - jQuery( this ).wrapAll( html ); - }); - }, - - append: function() { - return this.domManip(arguments, true, false, function(elem){ - if (this.nodeType == 1) - this.appendChild( elem ); - }); - }, - - prepend: function() { - return this.domManip(arguments, true, true, function(elem){ - if (this.nodeType == 1) - this.insertBefore( elem, this.firstChild ); - }); - }, - - before: function() { - return this.domManip(arguments, false, false, function(elem){ - this.parentNode.insertBefore( elem, this ); - }); - }, - - after: function() { - return this.domManip(arguments, false, true, function(elem){ - this.parentNode.insertBefore( elem, this.nextSibling ); - }); - }, - - end: function() { - return this.prevObject || jQuery( [] ); - }, - - find: function( selector ) { - var elems = jQuery.map(this, function(elem){ - return jQuery.find( selector, elem ); - }); - - return this.pushStack( /[^+>] [^+>]/.test( selector ) || selector.indexOf("..") > -1 ? - jQuery.unique( elems ) : - elems ); - }, - - clone: function( events ) { - // Do the clone - var ret = this.map(function(){ - if ( jQuery.browser.msie && !jQuery.isXMLDoc(this) ) { - // IE copies events bound via attachEvent when - // using cloneNode. Calling detachEvent on the - // clone will also remove the events from the orignal - // In order to get around this, we use innerHTML. - // Unfortunately, this means some modifications to - // attributes in IE that are actually only stored - // as properties will not be copied (such as the - // the name attribute on an input). - var clone = this.cloneNode(true), - container = document.createElement("div"); - container.appendChild(clone); - return jQuery.clean([container.innerHTML])[0]; - } else - return this.cloneNode(true); - }); - - // Need to set the expando to null on the cloned set if it exists - // removeData doesn't work here, IE removes it from the original as well - // this is primarily for IE but the data expando shouldn't be copied over in any browser - var clone = ret.find("*").andSelf().each(function(){ - if ( this[ expando ] != undefined ) - this[ expando ] = null; - }); - - // Copy the events from the original to the clone - if ( events === true ) - this.find("*").andSelf().each(function(i){ - if (this.nodeType == 3) - return; - var events = jQuery.data( this, "events" ); - - for ( var type in events ) - for ( var handler in events[ type ] ) - jQuery.event.add( clone[ i ], type, events[ type ][ handler ], events[ type ][ handler ].data ); - }); - - // Return the cloned set - return ret; - }, - - filter: function( selector ) { - return this.pushStack( - jQuery.isFunction( selector ) && - jQuery.grep(this, function(elem, i){ - return selector.call( elem, i ); - }) || - - jQuery.multiFilter( selector, this ) ); - }, - - not: function( selector ) { - if ( selector.constructor == String ) - // test special case where just one selector is passed in - if ( isSimple.test( selector ) ) - return this.pushStack( jQuery.multiFilter( selector, this, true ) ); - else - selector = jQuery.multiFilter( selector, this ); - - var isArrayLike = selector.length && selector[selector.length - 1] !== undefined && !selector.nodeType; - return this.filter(function() { - return isArrayLike ? jQuery.inArray( this, selector ) < 0 : this != selector; - }); - }, - - add: function( selector ) { - return !selector ? this : this.pushStack( jQuery.merge( - this.get(), - selector.constructor == String ? - jQuery( selector ).get() : - selector.length != undefined && (!selector.nodeName || jQuery.nodeName(selector, "form")) ? - selector : [selector] ) ); - }, - - is: function( selector ) { - return selector ? - jQuery.multiFilter( selector, this ).length > 0 : - false; - }, - - hasClass: function( selector ) { - return this.is( "." + selector ); - }, - - val: function( value ) { - if ( value == undefined ) { - - if ( this.length ) { - var elem = this[0]; - - // We need to handle select boxes special - if ( jQuery.nodeName( elem, "select" ) ) { - var index = elem.selectedIndex, - values = [], - options = elem.options, - one = elem.type == "select-one"; - - // Nothing was selected - if ( index < 0 ) - return null; - - // Loop through all the selected options - for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { - var option = options[ i ]; - - if ( option.selected ) { - // Get the specifc value for the option - value = jQuery.browser.msie && !option.attributes.value.specified ? option.text : option.value; - - // We don't need an array for one selects - if ( one ) - return value; - - // Multi-Selects return an array - values.push( value ); - } - } - - return values; - - // Everything else, we just grab the value - } else - return (this[0].value || "").replace(/\r/g, ""); - - } - - return undefined; - } - - return this.each(function(){ - if ( this.nodeType != 1 ) - return; - - if ( value.constructor == Array && /radio|checkbox/.test( this.type ) ) - this.checked = (jQuery.inArray(this.value, value) >= 0 || - jQuery.inArray(this.name, value) >= 0); - - else if ( jQuery.nodeName( this, "select" ) ) { - var values = value.constructor == Array ? - value : - [ value ]; - - jQuery( "option", this ).each(function(){ - this.selected = (jQuery.inArray( this.value, values ) >= 0 || - jQuery.inArray( this.text, values ) >= 0); - }); - - if ( !values.length ) - this.selectedIndex = -1; - - } else - this.value = value; - }); - }, - - html: function( value ) { - return value == undefined ? - (this.length ? - this[0].innerHTML : - null) : - this.empty().append( value ); - }, - - replaceWith: function( value ) { - return this.after( value ).remove(); - }, - - eq: function( i ) { - return this.slice( i, i + 1 ); - }, - - slice: function() { - return this.pushStack( Array.prototype.slice.apply( this, arguments ) ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map(this, function(elem, i){ - return callback.call( elem, i, elem ); - })); - }, - - andSelf: function() { - return this.add( this.prevObject ); - }, - - data: function( key, value ){ - var parts = key.split("."); - parts[1] = parts[1] ? "." + parts[1] : ""; - - if ( value == null ) { - var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); - - if ( data == undefined && this.length ) - data = jQuery.data( this[0], key ); - - return data == null && parts[1] ? - this.data( parts[0] ) : - data; - } else - return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function(){ - jQuery.data( this, key, value ); - }); - }, - - removeData: function( key ){ - return this.each(function(){ - jQuery.removeData( this, key ); - }); - }, - - domManip: function( args, table, reverse, callback ) { - var clone = this.length > 1, elems; - - return this.each(function(){ - if ( !elems ) { - elems = jQuery.clean( args, this.ownerDocument ); - - if ( reverse ) - elems.reverse(); - } - - var obj = this; - - if ( table && jQuery.nodeName( this, "table" ) && jQuery.nodeName( elems[0], "tr" ) ) - obj = this.getElementsByTagName("tbody")[0] || this.appendChild( this.ownerDocument.createElement("tbody") ); - - var scripts = jQuery( [] ); - - jQuery.each(elems, function(){ - var elem = clone ? - jQuery( this ).clone( true )[0] : - this; - - // execute all scripts after the elements have been injected - if ( jQuery.nodeName( elem, "script" ) ) { - scripts = scripts.add( elem ); - } else { - // Remove any inner scripts for later evaluation - if ( elem.nodeType == 1 ) - scripts = scripts.add( jQuery( "script", elem ).remove() ); - - // Inject the elements into the document - callback.call( obj, elem ); - } - }); - - scripts.each( evalScript ); - }); - } -}; - -// Give the init function the jQuery prototype for later instantiation -jQuery.prototype.init.prototype = jQuery.prototype; - -function evalScript( i, elem ) { - if ( elem.src ) - jQuery.ajax({ - url: elem.src, - async: false, - dataType: "script" - }); - - else - jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); - - if ( elem.parentNode ) - elem.parentNode.removeChild( elem ); -} - -jQuery.extend = jQuery.fn.extend = function() { - // copy reference to target object - var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options; - - // Handle a deep copy situation - if ( target.constructor == Boolean ) { - deep = target; - target = arguments[1] || {}; - // skip the boolean and the target - i = 2; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target != "object" && typeof target != "function" ) - target = {}; - - // extend jQuery itself if only one argument is passed - if ( length == 1 ) { - target = this; - i = 0; - } - - for ( ; i < length; i++ ) - // Only deal with non-null/undefined values - if ( (options = arguments[ i ]) != null ) - // Extend the base object - for ( var name in options ) { - // Prevent never-ending loop - if ( target === options[ name ] ) - continue; - - // Recurse if we're merging object values - if ( deep && options[ name ] && typeof options[ name ] == "object" && target[ name ] && !options[ name ].nodeType ) - target[ name ] = jQuery.extend( target[ name ], options[ name ] ); - - // Don't bring in undefined values - else if ( options[ name ] != undefined ) - target[ name ] = options[ name ]; - - } - - // Return the modified object - return target; -}; - -var expando = "jQuery" + (new Date()).getTime(), uuid = 0, windowData = {}; - -// exclude the following css properties to add px -var exclude = /z-?index|font-?weight|opacity|zoom|line-?height/i; - -jQuery.extend({ - noConflict: function( deep ) { - window.$ = _$; - - if ( deep ) - window.jQuery = _jQuery; - - return jQuery; - }, - - // See test/unit/core.js for details concerning this function. - isFunction: function( fn ) { - return !!fn && typeof fn != "string" && !fn.nodeName && - fn.constructor != Array && /function/i.test( fn + "" ); - }, - - // check if an element is in a (or is an) XML document - isXMLDoc: function( elem ) { - return elem.documentElement && !elem.body || - elem.tagName && elem.ownerDocument && !elem.ownerDocument.body; - }, - - // Evalulates a script in a global context - globalEval: function( data ) { - data = jQuery.trim( data ); - - if ( data ) { - // Inspired by code by Andrea Giammarchi - // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html - var head = document.getElementsByTagName("head")[0] || document.documentElement, - script = document.createElement("script"); - - script.type = "text/javascript"; - if ( jQuery.browser.msie ) - script.text = data; - else - script.appendChild( document.createTextNode( data ) ); - - head.appendChild( script ); - head.removeChild( script ); - } - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toUpperCase() == name.toUpperCase(); - }, - - cache: {}, - - data: function( elem, name, data ) { - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ]; - - // Compute a unique ID for the element - if ( !id ) - id = elem[ expando ] = ++uuid; - - // Only generate the data cache if we're - // trying to access or manipulate it - if ( name && !jQuery.cache[ id ] ) - jQuery.cache[ id ] = {}; - - // Prevent overriding the named cache with undefined values - if ( data != undefined ) - jQuery.cache[ id ][ name ] = data; - - // Return the named cache data, or the ID for the element - return name ? - jQuery.cache[ id ][ name ] : - id; - }, - - removeData: function( elem, name ) { - elem = elem == window ? - windowData : - elem; - - var id = elem[ expando ]; - - // If we want to remove a specific section of the element's data - if ( name ) { - if ( jQuery.cache[ id ] ) { - // Remove the section of cache data - delete jQuery.cache[ id ][ name ]; - - // If we've removed all the data, remove the element's cache - name = ""; - - for ( name in jQuery.cache[ id ] ) - break; - - if ( !name ) - jQuery.removeData( elem ); - } - - // Otherwise, we want to remove all of the element's data - } else { - // Clean up the element expando - try { - delete elem[ expando ]; - } catch(e){ - // IE has trouble directly removing the expando - // but it's ok with using removeAttribute - if ( elem.removeAttribute ) - elem.removeAttribute( expando ); - } - - // Completely remove the data cache - delete jQuery.cache[ id ]; - } - }, - - // args is for internal usage only - each: function( object, callback, args ) { - if ( args ) { - if ( object.length == undefined ) { - for ( var name in object ) - if ( callback.apply( object[ name ], args ) === false ) - break; - } else - for ( var i = 0, length = object.length; i < length; i++ ) - if ( callback.apply( object[ i ], args ) === false ) - break; - - // A special, fast, case for the most common use of each - } else { - if ( object.length == undefined ) { - for ( var name in object ) - if ( callback.call( object[ name ], name, object[ name ] ) === false ) - break; - } else - for ( var i = 0, length = object.length, value = object[0]; - i < length && callback.call( value, i, value ) !== false; value = object[++i] ){} - } - - return object; - }, - - prop: function( elem, value, type, i, name ) { - // Handle executable functions - if ( jQuery.isFunction( value ) ) - value = value.call( elem, i ); - - // Handle passing in a number to a CSS property - return value && value.constructor == Number && type == "curCSS" && !exclude.test( name ) ? - value + "px" : - value; - }, - - className: { - // internal only, use addClass("class") - add: function( elem, classNames ) { - jQuery.each((classNames || "").split(/\s+/), function(i, className){ - if ( elem.nodeType == 1 && !jQuery.className.has( elem.className, className ) ) - elem.className += (elem.className ? " " : "") + className; - }); - }, - - // internal only, use removeClass("class") - remove: function( elem, classNames ) { - if (elem.nodeType == 1) - elem.className = classNames != undefined ? - jQuery.grep(elem.className.split(/\s+/), function(className){ - return !jQuery.className.has( classNames, className ); - }).join(" ") : - ""; - }, - - // internal only, use is(".class") - has: function( elem, className ) { - return jQuery.inArray( className, (elem.className || elem).toString().split(/\s+/) ) > -1; - } - }, - - // A method for quickly swapping in/out CSS properties to get correct calculations - swap: function( elem, options, callback ) { - var old = {}; - // Remember the old values, and insert the new ones - for ( var name in options ) { - old[ name ] = elem.style[ name ]; - elem.style[ name ] = options[ name ]; - } - - callback.call( elem ); - - // Revert the old values - for ( var name in options ) - elem.style[ name ] = old[ name ]; - }, - - css: function( elem, name, force ) { - if ( name == "width" || name == "height" ) { - var val, props = { position: "absolute", visibility: "hidden", display:"block" }, which = name == "width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ]; - - function getWH() { - val = name == "width" ? elem.offsetWidth : elem.offsetHeight; - var padding = 0, border = 0; - jQuery.each( which, function() { - padding += parseFloat(jQuery.curCSS( elem, "padding" + this, true)) || 0; - border += parseFloat(jQuery.curCSS( elem, "border" + this + "Width", true)) || 0; - }); - val -= Math.round(padding + border); - } - - if ( jQuery(elem).is(":visible") ) - getWH(); - else - jQuery.swap( elem, props, getWH ); - - return Math.max(0, val); - } - - return jQuery.curCSS( elem, name, force ); - }, - - curCSS: function( elem, name, force ) { - var ret; - - // A helper method for determining if an element's values are broken - function color( elem ) { - if ( !jQuery.browser.safari ) - return false; - - var ret = document.defaultView.getComputedStyle( elem, null ); - return !ret || ret.getPropertyValue("color") == ""; - } - - // We need to handle opacity special in IE - if ( name == "opacity" && jQuery.browser.msie ) { - ret = jQuery.attr( elem.style, "opacity" ); - - return ret == "" ? - "1" : - ret; - } - // Opera sometimes will give the wrong display answer, this fixes it, see #2037 - if ( jQuery.browser.opera && name == "display" ) { - var save = elem.style.outline; - elem.style.outline = "0 solid black"; - elem.style.outline = save; - } - - // Make sure we're using the right name for getting the float value - if ( name.match( /float/i ) ) - name = styleFloat; - - if ( !force && elem.style && elem.style[ name ] ) - ret = elem.style[ name ]; - - else if ( document.defaultView && document.defaultView.getComputedStyle ) { - - // Only "float" is needed here - if ( name.match( /float/i ) ) - name = "float"; - - name = name.replace( /([A-Z])/g, "-$1" ).toLowerCase(); - - var getComputedStyle = document.defaultView.getComputedStyle( elem, null ); - - if ( getComputedStyle && !color( elem ) ) - ret = getComputedStyle.getPropertyValue( name ); - - // If the element isn't reporting its values properly in Safari - // then some display: none elements are involved - else { - var swap = [], stack = []; - - // Locate all of the parent display: none elements - for ( var a = elem; a && color(a); a = a.parentNode ) - stack.unshift(a); - - // Go through and make them visible, but in reverse - // (It would be better if we knew the exact display type that they had) - for ( var i = 0; i < stack.length; i++ ) - if ( color( stack[ i ] ) ) { - swap[ i ] = stack[ i ].style.display; - stack[ i ].style.display = "block"; - } - - // Since we flip the display style, we have to handle that - // one special, otherwise get the value - ret = name == "display" && swap[ stack.length - 1 ] != null ? - "none" : - ( getComputedStyle && getComputedStyle.getPropertyValue( name ) ) || ""; - - // Finally, revert the display styles back - for ( var i = 0; i < swap.length; i++ ) - if ( swap[ i ] != null ) - stack[ i ].style.display = swap[ i ]; - } - - // We should always get a number back from opacity - if ( name == "opacity" && ret == "" ) - ret = "1"; - - } else if ( elem.currentStyle ) { - var camelCase = name.replace(/\-(\w)/g, function(all, letter){ - return letter.toUpperCase(); - }); - - ret = elem.currentStyle[ name ] || elem.currentStyle[ camelCase ]; - - // From the awesome hack by Dean Edwards - // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291 - - // If we're not dealing with a regular pixel number - // but a number that has a weird ending, we need to convert it to pixels - if ( !/^\d+(px)?$/i.test( ret ) && /^\d/.test( ret ) ) { - // Remember the original values - var style = elem.style.left, runtimeStyle = elem.runtimeStyle.left; - - // Put in the new values to get a computed value out - elem.runtimeStyle.left = elem.currentStyle.left; - elem.style.left = ret || 0; - ret = elem.style.pixelLeft + "px"; - - // Revert the changed values - elem.style.left = style; - elem.runtimeStyle.left = runtimeStyle; - } - } - - return ret; - }, - - clean: function( elems, context ) { - var ret = []; - context = context || document; - // !context.createElement fails in IE with an error but returns typeof 'object' - if (typeof context.createElement == 'undefined') - context = context.ownerDocument || context[0] && context[0].ownerDocument || document; - - jQuery.each(elems, function(i, elem){ - if ( !elem ) - return; - - if ( elem.constructor == Number ) - elem = elem.toString(); - - // Convert html string into DOM nodes - if ( typeof elem == "string" ) { - // Fix "XHTML"-style tags in all browsers - elem = elem.replace(/(<(\w+)[^>]*?)\/>/g, function(all, front, tag){ - return tag.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i) ? - all : - front + ">"; - }); - - // Trim whitespace, otherwise indexOf won't work as expected - var tags = jQuery.trim( elem ).toLowerCase(), div = context.createElement("div"); - - var wrap = - // option or optgroup - !tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - tags.match(/^<(thead|tbody|tfoot|colg|cap)/) && - [ 1, "", "
" ] || - - !tags.indexOf("", "" ] || - - // matched above - (!tags.indexOf("", "" ] || - - !tags.indexOf("", "" ] || - - // IE can't serialize and "); + $this->add_html_header(""); /* Attempt to cache the CSS & JavaScript files */ if ($this->add_cached_auto_html_headers() === FALSE) { @@ -291,7 +291,11 @@ class Page { { global $config; - if (!$config->get_bool("autocache_css") && !$config->get_bool("autocache_js")) { + // store local copy for speed. + $autocache_css = $config->get_bool("autocache_css"); + $autocache_js = $config->get_bool("autocache_js"); + + if (!$autocache_css && !$autocache_js) { return false; // caching disabled } @@ -309,7 +313,7 @@ class Page { $data_href = get_base_href(); /* ----- CSS Files ----- */ - if ($config->get_bool("autocache_css")) + if ($autocache_css) { // First get all the CSS from the lib directory $contents_from_lib = ''; @@ -376,7 +380,7 @@ class Page { /* ----- JavaScript Files ----- */ - if ($config->get_bool("autocache_js")) + if ($autocache_js) { $data = ''; $js_files = glob("lib/*.js"); @@ -394,7 +398,7 @@ class Page { // Minify the JS if enabled. if ($config->get_bool("autocache_min_js")){ // not supported yet. - // TODO: add support for Minifying CSS files. + // TODO: add support for Minifying JS files. } // compute the MD5 sum of the concatenated JavaScript files diff --git a/core/user.class.php b/core/user.class.php index 85d90df5..843d6c9d 100644 --- a/core/user.class.php +++ b/core/user.class.php @@ -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; diff --git a/core/util.inc.php b/core/util.inc.php index 882c8560..1f653574 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -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);} @@ -824,6 +839,7 @@ $_event_count = 0; function send_event(Event $event) { global $_event_listeners, $_event_count; if(!isset($_event_listeners[get_class($event)])) return; + $method_name = "on".str_replace("Event", "", get_class($event)); ctx_log_start(get_class($event)); // SHIT: http://bugs.php.net/bug.php?id=35106 @@ -831,7 +847,7 @@ function send_event(Event $event) { ksort($my_event_listeners); foreach($my_event_listeners as $listener) { ctx_log_start(get_class($listener)); - $listener->receive_event($event); + $listener->$method_name($event); ctx_log_endok(); } $_event_count++; @@ -847,6 +863,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 +902,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 = ""; @@ -1001,7 +1024,7 @@ function _load_extensions() { if($rclass->isAbstract()) { // don't do anything } - elseif(is_subclass_of($class, "SimpleExtension")) { + elseif(is_subclass_of($class, "Extension")) { $c = new $class(); $c->i_am($c); $my_events = array(); @@ -1012,10 +1035,6 @@ function _load_extensions() { } add_event_listener($c, $c->get_priority(), $my_events); } - elseif(is_subclass_of($class, "Extension")) { - $c = new $class(); - add_event_listener($c, $c->get_priority(), $all_events); - } } if(COMPILE_ELS) { @@ -1024,13 +1043,10 @@ function _load_extensions() { foreach(get_declared_classes() as $class) { $rclass = new ReflectionClass($class); if($rclass->isAbstract()) {} - elseif(is_subclass_of($class, "SimpleExtension")) { + elseif(is_subclass_of($class, "Extension")) { $p .= "\$$class = new $class(); "; $p .= "\${$class}->i_am(\$$class);\n"; } - elseif(is_subclass_of($class, "Extension")) { - $p .= "\$$class = new $class();\n"; - } } $p .= "\$_event_listeners = array(\n"; @@ -1051,6 +1067,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(); diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php index 2942809d..cfbf1777 100755 --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -22,13 +22,13 @@ class AddAliasEvent extends Event { class AddAliasException extends SCoreException {} -class AliasEditor extends SimpleExtension { +class AliasEditor extends Extension { public function onPageRequest(PageRequestEvent $event) { global $config, $database, $page, $user; 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")); } } diff --git a/ext/alias_editor/theme.php b/ext/alias_editor/theme.php index cec35af0..7b6bfb49 100644 --- a/ext/alias_editor/theme.php +++ b/ext/alias_editor/theme.php @@ -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 = "Action"; $add = " @@ -33,7 +36,7 @@ class AliasEditorTheme extends Themelet { $oe = ($n++ % 2 == 0) ? "even" : "odd"; $h_aliases .= "$h_old$h_new"; - if($is_admin) { + if($can_manage) { $h_aliases .= " ".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)); } diff --git a/ext/comment/main.php b/ext/comment/main.php index 0a1aaebf..451cbd51 100644 --- a/ext/comment/main.php +++ b/ext/comment/main.php @@ -60,7 +60,7 @@ class Comment { } } -class CommentList extends SimpleExtension { +class CommentList extends Extension { public function onInitExt(InitExtEvent $event) { global $config, $database; $config->set_default_bool('comment_anon', true); @@ -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))); diff --git a/ext/comment/theme.php b/ext/comment/theme.php index c0f8ca0b..472d2daa 100644 --- a/ext/comment/theme.php +++ b/ext/comment/theme.php @@ -35,14 +35,17 @@ class CommentListTheme extends Themelet { // parts for each image $position = 10; + + $comment_limit = $config->get_int("comment_list_count", 10); + $comment_captcha = $config->get_bool('comment_captcha'); + foreach($images as $pair) { $image = $pair[0]; $comments = $pair[1]; $thumb_html = $this->build_thumb_html($image); - $comment_html = ""; - $comment_limit = $config->get_int("comment_list_count", 10); + $comment_count = count($comments); if($comment_limit > 0 && $comment_count > $comment_limit) { $hidden = $comment_count - $comment_limit; @@ -59,7 +62,7 @@ class CommentListTheme extends Themelet { } } else { if ($can_post) { - if(!$config->get_bool('comment_captcha')) { + if(!$comment_captcha) { $comment_html .= $this->build_postbox($image->id); } else { @@ -170,10 +173,9 @@ class CommentListTheme extends Themelet { $hash = md5(strtolower($comment->owner_email)); $avatar = "
"; } - $a = $user->is_admin(); $h_reply = " - Reply"; - $h_ip = $a ? "
$h_poster_ip" : ""; - $h_del = $a ? + $h_ip = $user->can("view_ip") ? "
$h_poster_ip" : ""; + $h_del = $user->can("delete_comment") ? ' - Del' : ''; return ' diff --git a/ext/ext_manager/main.php b/ext/ext_manager/main.php index 1b90ef0a..911274e5 100644 --- a/ext/ext_manager/main.php +++ b/ext/ext_manager/main.php @@ -87,11 +87,11 @@ class ExtensionInfo { } } -class ExtManager extends SimpleExtension { +class ExtManager extends Extension { 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 { diff --git a/ext/handle_404/main.php b/ext/handle_404/main.php index b7e80aa0..ed01cec1 100644 --- a/ext/handle_404/main.php +++ b/ext/handle_404/main.php @@ -8,7 +8,7 @@ * Description: Shows an error message when the user views a page with no content */ -class Handle404 extends SimpleExtension { +class Handle404 extends Extension { public function onPageRequest(PageRequestEvent $event) { global $page; // hax. diff --git a/ext/image/main.php b/ext/image/main.php index 0fde1e24..b6d842b0 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -129,7 +129,7 @@ class ParseLinkTemplateEvent extends Event { /** * A class to handle adding / getting / removing image files from the disk. */ -class ImageIO extends SimpleExtension { +class ImageIO extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_int('thumb_width', 192); @@ -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)); } } diff --git a/ext/index/main.php b/ext/index/main.php index 14a0ac5c..3494edef 100644 --- a/ext/index/main.php +++ b/ext/index/main.php @@ -128,7 +128,7 @@ class PostListBuildingEvent extends Event { } } -class Index extends SimpleExtension { +class Index extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_int("index_width", 3); diff --git a/ext/mail/main.php b/ext/mail/main.php index 9bf09169..fb3aec97 100644 --- a/ext/mail/main.php +++ b/ext/mail/main.php @@ -7,7 +7,7 @@ * Description: Provides an interface for sending and receiving mail. */ -class Mail extends SimpleExtension { +class Mail extends Extension { public function onSetupBuilding(SetupBuildingEvent $event) { $sb = new SetupBlock("Mailing Options"); $sb->add_text_option("mail_sub", "
Subject prefix: "); @@ -26,7 +26,7 @@ class Mail extends SimpleExtension { $config->set_default_string("mail_fot", "".$config->get_string("site_title").""); } } -class MailTest extends SimpleExtension { +class MailTest extends Extension { public function onPageRequest(PageRequestEvent $event) { if($event->page_matches("mail/test")) { global $page; diff --git a/ext/setup/main.php b/ext/setup/main.php index f93ac7fa..40551e5c 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -161,7 +161,7 @@ class SetupBlock extends Block { } // }}} -class Setup extends SimpleExtension { +class Setup extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_string("title", "Shimmie"); @@ -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")); } } diff --git a/ext/tag_edit/main.php b/ext/tag_edit/main.php index a06425c1..bdae3ec0 100644 --- a/ext/tag_edit/main.php +++ b/ext/tag_edit/main.php @@ -55,12 +55,12 @@ class LockSetEvent extends Event { } } -class TagEdit extends SimpleExtension { +class TagEdit extends Extension { public function onPageRequest(PageRequestEvent $event) { 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()) ); } diff --git a/ext/tag_list/main.php b/ext/tag_list/main.php index c30aacb6..58d8b24e 100644 --- a/ext/tag_list/main.php +++ b/ext/tag_list/main.php @@ -1,11 +1,12 @@ + * Link: http://code.shishnet.org/shimmie2/ * Description: Show the tags in various ways */ -class TagList extends SimpleExtension { +class TagList extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_int("tag_list_length", 15); @@ -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);} diff --git a/ext/tag_list/theme.php b/ext/tag_list/theme.php index 99d83664..23065572 100644 --- a/ext/tag_list/theme.php +++ b/ext/tag_list/theme.php @@ -69,23 +69,28 @@ class TagListTheme extends Themelet { */ public function display_popular_block(Page $page, $tag_infos) { global $config; + + // store local copies for speed. + $info_link = $config->get_string('info_link'); + $tag_list_num = $config->get_bool("tag_list_numbers"); $html = ""; $n = 0; + foreach($tag_infos as $row) { $tag = $row['tag']; $h_tag = html_escape($tag); $h_tag_no_underscores = str_replace("_", " ", $h_tag); $count = $row['count']; if($n++) $html .= "\n
"; - if(!is_null($config->get_string('info_link'))) { - $link = str_replace('$tag', $tag, $config->get_string('info_link')); - $html .= " ?"; + if(!is_null($info_link)) { + $link = str_replace('$tag', $tag, $info_link); + $html .= ' ?'; } $link = $this->tag_link($row['tag']); - $html .= " $h_tag_no_underscores"; - if($config->get_bool("tag_list_numbers")) { - $html .= " $count"; + $html .= ' '.$h_tag_no_underscores.''; + if($tag_list_num) { + $html .= ' '.$count.''; } } @@ -103,19 +108,23 @@ class TagListTheme extends Themelet { public function display_refine_block(Page $page, $tag_infos, $search) { global $config; + // store local copy for speed. + $info_link = $config->get_string('info_link'); + $html = ""; $n = 0; + foreach($tag_infos as $row) { $tag = $row['tag']; $h_tag = html_escape($tag); $h_tag_no_underscores = str_replace("_", " ", $h_tag); if($n++) $html .= "\n
"; - if(!is_null($config->get_string('info_link'))) { - $link = str_replace('$tag', $tag, $config->get_string('info_link')); - $html .= " ?"; + if(!is_null($info_link)) { + $link = str_replace('$tag', $tag, $info_link); + $html .= ' ?'; } $link = $this->tag_link($row['tag']); - $html .= " $h_tag_no_underscores"; + $html .= ' '.$h_tag_no_underscores.''; $html .= $this->ars($tag, $search); } diff --git a/ext/upgrade/main.php b/ext/upgrade/main.php index 4d8f32b9..a61b0860 100644 --- a/ext/upgrade/main.php +++ b/ext/upgrade/main.php @@ -1,15 +1,18 @@ + * Link: http://code.shishnet.org/shimmie2/ * Description: Keeps things happy behind the scenes * Visibility: admin */ -class Upgrade extends SimpleExtension { +class Upgrade extends Extension { 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); } } diff --git a/ext/upload/bookmarklet.js b/ext/upload/bookmarklet.js index 2838bdca..590adaef 100644 --- a/ext/upload/bookmarklet.js +++ b/ext/upload/bookmarklet.js @@ -4,22 +4,49 @@ var maxsze = (maxsze.match("(?:\.*[0-9])")) * 1024; //This assumes we are only working with MB. var toobig = "The file you are trying to upload is too big to upload!"; var notsup = "The file you are trying to upload is not supported!"; +if (CA === 0 || CA > 2){ //Default + if (confirm("OK = Use Current tags.\nCancel = Use new tags.")==true){ + }else{ + var tag=prompt("Enter Tags",""); + var chk=1; //This makes sure it doesn't use current tags. + } +}else if (CA === 1){ //Current Tags +}else if (CA === 2){ //New Tags + var tag=prompt("Enter Tags",""); + var chk=1; +} -if (confirm("OK = Use Current tags.\nCancel = Use new tags.")==true){}else{var tag=prompt("Enter Tags","");var chk=1;}; - -// Danbooru +// Danbooru | oreno.imouto | konachan | sankakucomplex if(document.getElementById("post_tags") !== null){ if (typeof tag !=="ftp://ftp." && chk !==1){var tag=document.getElementById("post_tags").value;} - var rtg=document.getElementById("stats").innerHTML.match("

  • Rating: (.*)<\/li>")[1]; - var srx="http://" + document.location.hostname + document.location.href.match("\/post\/show\/[0-9]+\/"); + var srx="http://" + document.location.hostname + document.location.href.match("\/post\/show\/[0-9]+"); + if(srx.search("oreno\\.imouto") >= 0 || srx.search("konachan\\.com") >= 0){ + var rtg=document.getElementById("stats").innerHTML.match("
  • Rating: (.*) Rating: (.*)<\/li>")[1]; + } if(tag.search(/\bflash\b/)===-1){ - var filesze=document.getElementById("stats").innerHTML.match("[0-9] \\(((?:\.*[0-9])) ([a-zA-Z]+)"); + var hrs=document.getElementById("highres").href; + if(srx.search("oreno\\.imouto") >= 0 || srx.search("konachan\\.com") >= 0){ //oreno's theme seems to have moved the filesize + var filesze = document.getElementById("highres").innerHTML.match("[a-zA-Z0-9]+ \\(+([0-9]+\\.[0-9]+) ([a-zA-Z]+)"); + }else{ + var filesze=document.getElementById("stats").innerHTML.match("[0-9] \\(((?:\.*[0-9])) ([a-zA-Z]+)"); + } if(filesze[2] == "MB"){var filesze = filesze[1] * 1024;}else{var filesze = filesze[2].match("[0-9]+");} - if(supext.search(document.getElementById("highres").href.match("http\:\/\/.*\\.([a-z0-9]+)")[1]) !== -1){ + if(supext.search(hrs.match("http\:\/\/.*\\.([a-z0-9]+)")[1]) !== -1){ if(filesze <= maxsze){ - location.href=ste+document.getElementById("highres").href+"&tags="+tag+"&rating="+rtg+"&source="+srx; + if(srx.search("oreno\\.imouto") >= 0){ + //this regex tends to be a bit picky with tags -_-;; + var hrs=hrs.match("(http\:\/\/[a-z0-9]+\.[a-z]+\.[a-z]\/[a-z0-9]+\/[a-z0-9]+)\/[a-z0-9A-Z%_-]+(\.[a-zA-Z0-9]+)"); + var hrs=hrs[1]+hrs[2]; //this should bypass hotlink protection + }else if(srx.search("konachan\\.com") >= 0){ + //konachan affixs konachan.com to the start of the tags, this requires different regex + var hrs=hrs.match("(http\:\/\/[a-z0-9]+\.[a-z]+\.[a-z]\/[a-z0-9]+\/[a-z0-9]+)\/[a-z0-9A-Z%_]+\.[a-zA-Z0-9%_-]+(\.[a-z0-9A-Z]+)") + var hrs=hrs[1]+hrs[2]; + } + location.href=ste+hrs+"&tags="+tag+"&rating="+rtg+"&source="+srx; }else{alert(toobig);} }else{alert(notsup);} }else{ @@ -29,6 +56,7 @@ if(document.getElementById("post_tags") !== null){ } } /* Shimmie +One problem with shimmie is each theme does not show the same info as other themes (I.E only the danbooru & lite themes show statistics) Shimmie doesn't seem to have any way to grab tags via id unless you have the ability to edit tags. Have to go the round about way of checking the title for tags. This crazy way of checking "should" work with older releases though (Seems to work with 2009~ ver) */ @@ -36,7 +64,6 @@ else if(document.getElementsByTagName("title")[0].innerHTML.search("Image [0-9.- if (typeof tag !=="ftp://ftp." && chk !==1){var tag=document.getElementsByTagName("title")[0].innerHTML.match("Image [0-9.-]+\: (.*)")[1];} //TODO: Make rating show in statistics. var srx="http://" + document.location.hostname + document.location.href.match("\/post\/view\/[0-9]+"); - /*TODO: Figure out regex for shortening file link. I.E http://blah.net/_images/1234abcd/everysingletag.png > http://blah.net/_images/1234abcd.png*/ /*TODO: Make file size show on all themes (Only seems to show in lite/Danbooru themes.)*/ if(tag.search(/\bflash\b/)==-1){ var img = document.getElementById("main_image").src; @@ -52,7 +79,6 @@ else if(document.getElementsByTagName("title")[0].innerHTML.search("Image [0-9.- } // Gelbooru else if(document.getElementById("tags") !== null){ - //Gelbooru has an annoying anti-hotlinking thing which doesn't seem to like the bookmarklet. if (typeof tag !=="ftp://ftp." && chk !==1){var tag=document.getElementById("tags").value;} var rtg=document.getElementById("stats").innerHTML.match("
  • Rating: (.*)<\/li>")[1]; //Can't seem to grab source due to url containing a & @@ -61,6 +87,6 @@ else if(document.getElementById("tags") !== null){ //Since Gelbooru does not allow flash, no need to search for flash tag. //Gelbooru doesn't show file size in statistics either... if(supext.search(gmi.match("http\:\/\/.*\\.([a-z0-9]+)")[1]) !== -1){ - location.href=ste+gmi+"&tags="+tag+"&rating="+rtg[1];//+"&source="+srx; + location.href=ste+gmi+"&tags="+tag+"&rating="+rtg;//+"&source="+srx; }else{alert(notsup);} } diff --git a/ext/upload/main.php b/ext/upload/main.php index 979ab413..d438febb 100644 --- a/ext/upload/main.php +++ b/ext/upload/main.php @@ -1,5 +1,5 @@ is_full = false; } else { + // TODO: This size limit should be configureable by the admin... + // currently set to 100 MB $this->is_full = $free_num < 100*1024*1024; } @@ -120,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 { @@ -150,12 +152,14 @@ class Upload extends SimpleExtension { $tags = ''; // Tags aren't changed when uploading. Set to null to stop PHP warnings. if(count($_FILES)) { + reset($_FILES); // rewind to first element in array. foreach($_FILES as $file) { $ok = $this->try_upload($file, $tags, $source, $image_id); break; // leave the foreach loop. } } else { + reset($_POST); // rewind to first element in array. foreach($_POST as $name => $value) { if(substr($name, 0, 3) == "url" && strlen($value) > 0) { $ok = $this->try_transload($value, $tags, $source, $image_id); @@ -186,9 +190,11 @@ class Upload extends SimpleExtension { $source = isset($_POST['source']) ? $_POST['source'] : null; $ok = true; foreach($_FILES as $file) { + reset($_FILES); // rewind to first element in array. $ok = $ok & $this->try_upload($file, $tags, $source); } foreach($_POST as $name => $value) { + reset($_POST); // rewind to first element in array. if(substr($name, 0, 3) == "url" && strlen($value) > 0) { $ok = $ok & $this->try_transload($value, $tags, $source); } @@ -218,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: @@ -247,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; @@ -293,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; @@ -308,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']); } diff --git a/ext/upload/theme.php b/ext/upload/theme.php index 9e66e457..ecf71c51 100644 --- a/ext/upload/theme.php +++ b/ext/upload/theme.php @@ -18,6 +18,7 @@ class UploadTheme extends Themelet { $upload_list = ""; $upload_count = $config->get_int('upload_count'); + for($i=0; $i<$upload_count; $i++) { $a=$i+1; @@ -53,7 +54,7 @@ class UploadTheme extends Themelet { ". ""; - if($a==$config->get_int('upload_count')){ + if($a == $upload_count){ $upload_list .=""; }else{ $js1 = 'javascript:$(function() { @@ -145,8 +146,7 @@ class UploadTheme extends Themelet { { /* Imageboard > Shimmie Bookmarklet This is more or less, an upgraded version of the "Danbooru>Shimmie" bookmarklet. - At the moment this works with Shimmie & Danbooru. - It would also work with Gelbooru but unless someone can figure out how to bypass their hotlinking..meh. + At the moment this is known to work with Shimmie/Danbooru/Gelbooru/oreno.imouto/konachan/sankakucomplex. The bookmarklet is now also loaded via the .js file in this folder. */ //Bookmarklet checks if shimmie supports ext. If not, won't upload to site/shows alert saying not supported. @@ -156,7 +156,8 @@ class UploadTheme extends Themelet { if(file_exists("ext/handle_mp3")){$supported_ext .= " mp3";} if(file_exists("ext/handle_svg")){$supported_ext .= " svg";} $title = "Booru to " . $config->get_string('title'); - $html .= '

    '. + //CA=0: Ask to use current or new tags | CA=1: Always use current tags | CA=2: Always use new tags + $html .= '

    '. $title . ' (Click when looking at an image page. Works on sites running Shimmie/Danbooru/Gelbooru. (This also grabs the tags/rating/source!))'; } diff --git a/ext/user/main.php b/ext/user/main.php index b5c9dc64..96f5ac69 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -42,7 +42,7 @@ class UserCreationEvent extends Event { class UserCreationException extends SCoreException {} -class UserPage extends SimpleExtension { +class UserPage extends Extension { public function onInitExt(InitExtEvent $event) { global $config; $config->set_default_bool("login_signup_enabled", true); @@ -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'])) { diff --git a/ext/user/theme.php b/ext/user/theme.php index df6b7553..69b852fc 100644 --- a/ext/user/theme.php +++ b/ext/user/theme.php @@ -141,7 +141,7 @@ class UserPageTheme extends Themelet { $page->add_block(new Block("Stats", join("
    ", $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 { "; - 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 .= " diff --git a/ext/view/main.php b/ext/view/main.php index 3fa700f6..4c4eb074 100644 --- a/ext/view/main.php +++ b/ext/view/main.php @@ -66,7 +66,7 @@ class ImageAdminBlockBuildingEvent extends Event { } } -class ViewImage extends SimpleExtension { +class ViewImage extends Extension { public function onPageRequest(PageRequestEvent $event) { global $page, $user; diff --git a/ext/view/theme.php b/ext/view/theme.php index 59f6b730..666ac8bf 100644 --- a/ext/view/theme.php +++ b/ext/view/theme.php @@ -90,7 +90,7 @@ class ViewImageTheme extends Themelet { $html = ""; $html .= "

    Uploaded by $h_owner $h_date"; - if($user->is_admin()) { + if($user->can("view_ip")) { $html .= " ($h_ip)"; } if(!is_null($image->source)) { diff --git a/install.php b/install.php index 09da4d33..139bc4c5 100755 --- a/install.php +++ b/install.php @@ -1,7 +1,8 @@ - + + Shimmie Installation - @@ -31,9 +33,10 @@ TD INPUT {width: 350px;}

    Install Error

    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.

    If you've installed a web server on your desktop PC, you probably - want to visit the local web server. + want to visit the local web server.

    +

    @@ -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> diff --git a/lib/shimmie.js b/lib/shimmie.js index 6ed41062..611d49ee 100644 --- a/lib/shimmie.js +++ b/lib/shimmie.js @@ -43,63 +43,10 @@ $(document).ready(function() { 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"; - } + $("#commentBox").DefaultValue("Comment"); + $("#tagBox").DefaultValue("tagme"); }); -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"); - } -} - /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ * LibShish-JS * @@ -119,6 +66,7 @@ function byId(id) { } +// used once in ext/setup/main function getHTTPObject() { if (window.XMLHttpRequest){ return new XMLHttpRequest(); @@ -128,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 ) { diff --git a/themes/danbooru/comment.theme.php b/themes/danbooru/comment.theme.php index ff728eac..a9ee90e1 100644 --- a/themes/danbooru/comment.theme.php +++ b/themes/danbooru/comment.theme.php @@ -25,6 +25,10 @@ class CustomCommentListTheme extends CommentListTheme { // parts for each image $position = 10; + + $comment_captcha = $config->get_bool('comment_captcha'); + $comment_limit = $config->get_int("comment_list_count", 10); + foreach($images as $pair) { $image = $pair[0]; $comments = $pair[1]; @@ -42,7 +46,7 @@ class CustomCommentListTheme extends CommentListTheme { $r = class_exists("Ratings") ? "<b>Rating</b> ".Ratings::rating_to_human($image->rating) : ""; $comment_html = "<b>Date</b> $p $s <b>User</b> $un $s $r<br><b>Tags</b> $t<p>&nbsp;"; - $comment_limit = $config->get_int("comment_list_count", 10); + $comment_count = count($comments); if($comment_limit > 0 && $comment_count > $comment_limit) { $hidden = $comment_count - $comment_limit; @@ -57,7 +61,7 @@ class CustomCommentListTheme extends CommentListTheme { $comment_html .= $this->build_postbox($image->id); } else { - if(!$config->get_bool('comment_captcha')) { + if(!$comment_captcha) { $comment_html .= $this->build_postbox($image->id); } else { diff --git a/themes/danbooru/view.theme.php b/themes/danbooru/view.theme.php index 31c553e9..ae5895e6 100644 --- a/themes/danbooru/view.theme.php +++ b/themes/danbooru/view.theme.php @@ -38,7 +38,7 @@ class CustomViewImageTheme extends ViewImageTheme { $html .= "<br>Source: <a href='$h_source'>link</a>"; } - if(!is_null($image->rating) && file_exists("ext/rating")) { + if(file_exists("ext/rating")) { if($image->rating == null || $image->rating == "u"){ $image->rating = "u"; } diff --git a/themes/lite/view.theme.php b/themes/lite/view.theme.php index 70fd4583..1327b33a 100644 --- a/themes/lite/view.theme.php +++ b/themes/lite/view.theme.php @@ -44,7 +44,7 @@ class CustomViewImageTheme extends ViewImageTheme { $html .= "<br>Source: <a href='$h_source'>link</a>"; } - if(!is_null($image->rating) && file_exists("ext/rating")) { + if(file_exists("ext/rating")) { if($image->rating == null || $image->rating == "u"){ $image->rating = "u"; }