diff --git a/.gitignore b/.gitignore index e88558e9..48f0bfcf 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,7 @@ -.svn backup -config.php data images -imgdump-*.zip thumbs -sql.log -shimmie.log !lib/images ext/admin ext/amazon_s3 diff --git a/README.txt b/README.txt index 796317cc..df6d7f26 100644 --- a/README.txt +++ b/README.txt @@ -42,6 +42,8 @@ Installation Upgrade from 2.3.X ~~~~~~~~~~~~~~~~~~ +config.php has been moved from /config.php to /data/config/shimmie.conf.php + The database connection setting in config.php has changed; now using PDO DSN format rather than ADODB URI: @@ -111,6 +113,3 @@ someone else, you have to give them the source (which should be easy, as PHP is an interpreted language...). If you want to add customisations to your own site, then those customisations belong to you, and you can do what you want with them. - - - diff --git a/contrib/admin/main.php b/contrib/admin/main.php index a799a571..f70e77bf 100644 --- a/contrib/admin/main.php +++ b/contrib/admin/main.php @@ -43,7 +43,7 @@ class AdminPage extends Extension { global $page, $user; if($event->page_matches("admin")) { - if(!$user->is_admin()) { + if(!$user->can("manage_admintools")) { $this->theme->display_permission_denied(); } else { @@ -76,7 +76,7 @@ class AdminPage extends Extension { public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("manage_admintools")) { $event->add_link("Board Admin", make_link("admin")); } } @@ -90,7 +90,7 @@ class AdminPage extends Extension { public function onPostListBuilding(PostListBuildingEvent $event) { global $user; - if($user->is_admin() && !empty($event->search_terms)) { + if($user->can("manage_admintools") && !empty($event->search_terms)) { $this->theme->display_dbq(implode(" ", $event->search_terms)); } } @@ -167,7 +167,7 @@ class AdminPage extends Extension { $zip = new ZipArchive; $images = $database->get_all("SELECT * FROM images"); - $filename = 'imgdump-'.date('Ymd').'.zip'; + $filename = data_path('imgdump-'.date('Ymd').'.zip'); if($zip->open($filename, 1 ? ZIPARCHIVE::OVERWRITE:ZIPARCHIVE::CREATE) === TRUE){ foreach($images as $img){ diff --git a/contrib/downtime/main.php b/contrib/downtime/main.php index 462e530f..63421db8 100644 --- a/contrib/downtime/main.php +++ b/contrib/downtime/main.php @@ -26,7 +26,7 @@ class Downtime extends Extension { global $config, $page, $user; if($config->get_bool("downtime")) { - if(!$user->is_admin() && !$this->is_safe_page($event)) { + if(!$user->can("ignore_downtime") && !$this->is_safe_page($event)) { $msg = $config->get_string("downtime_message"); $this->theme->display_message($msg); exit; diff --git a/contrib/featured/main.php b/contrib/featured/main.php index 5dbc41dd..dda66100 100644 --- a/contrib/featured/main.php +++ b/contrib/featured/main.php @@ -29,7 +29,7 @@ class Featured extends Extension { global $config, $page, $user; if($event->page_matches("featured_image")) { if($event->get_arg(0) == "set" && $user->check_auth_token()) { - if($user->is_admin() && isset($_POST['image_id'])) { + if($user->can("edit_feature") && isset($_POST['image_id'])) { $id = int_escape($_POST['image_id']); if($id > 0) { $config->set_int("featured_id", $id); @@ -77,7 +77,7 @@ class Featured extends Extension { public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("edit_feature")) { $event->add_part($this->theme->get_buttons_html($event->image->id)); } } diff --git a/contrib/image_hash_ban/main.php b/contrib/image_hash_ban/main.php index f68c7205..cf20fb37 100644 --- a/contrib/image_hash_ban/main.php +++ b/contrib/image_hash_ban/main.php @@ -56,7 +56,7 @@ class ImageBan extends Extension { global $config, $database, $page, $user; if($event->page_matches("image_hash_ban")) { - if($user->is_admin()) { + if($user->can("ban_image")) { if($event->get_arg(0) == "dnp") { $image = Image::by_id(int_escape($event->get_arg(1))); if($image) { @@ -105,7 +105,7 @@ class ImageBan extends Extension { public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("ban_image")) { $event->add_link("Image Bans", make_link("image_hash_ban/list/1")); } } @@ -120,7 +120,7 @@ class ImageBan extends Extension { public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("ban_image")) { $event->add_part($this->theme->get_buttons_html($event->image)); } } diff --git a/contrib/image_hash_ban/theme.php b/contrib/image_hash_ban/theme.php index d23721f7..d09cad2b 100644 --- a/contrib/image_hash_ban/theme.php +++ b/contrib/image_hash_ban/theme.php @@ -26,24 +26,19 @@ class ImageBanTheme extends Themelet { foreach($bans as $ban) { $h_bans .= " - {$ban['hash']} - {$ban['reason']} - - ".make_form(make_link("image_hash_ban/remove"))." + ".make_form(make_link("image_hash_ban/remove"))." + {$ban['hash']} + {$ban['reason']} + - - + + "; } $html = " - - +
diff --git a/contrib/ipban/main.php b/contrib/ipban/main.php index 4dd485ed..f3346a6c 100644 --- a/contrib/ipban/main.php +++ b/contrib/ipban/main.php @@ -49,7 +49,7 @@ class IPBan extends Extension { public function onPageRequest(PageRequestEvent $event) { if($event->page_matches("ip_ban")) { global $config, $database, $page, $user; - if($user->is_admin()) { + if($user->can("ban_ip")) { if($event->get_arg(0) == "add" && $user->check_auth_token()) { if(isset($_POST['ip']) && isset($_POST['reason']) && isset($_POST['end'])) { if(empty($_POST['end'])) $end = null; @@ -80,7 +80,7 @@ class IPBan extends Extension { public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("ban_ip")) { $event->add_link("IP Bans", make_link("ip_ban/list")); } } diff --git a/contrib/log_db/main.php b/contrib/log_db/main.php index 8399720a..39a58f36 100644 --- a/contrib/log_db/main.php +++ b/contrib/log_db/main.php @@ -44,7 +44,7 @@ class LogDatabase extends Extension { public function onPageRequest(PageRequestEvent $event) { global $database, $user; if($event->page_matches("log/view")) { - if($user->is_admin()) { + if($user->can("view_eventlog")) { $wheres = array(); $args = array(); $page_num = int_escape($event->get_arg(0)); @@ -111,7 +111,7 @@ class LogDatabase extends Extension { public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("view_eventlog")) { $event->add_link("Event Log", make_link("log/view")); } } diff --git a/contrib/log_db/theme.php b/contrib/log_db/theme.php index 5f387d39..e5fd8b87 100644 --- a/contrib/log_db/theme.php +++ b/contrib/log_db/theme.php @@ -20,7 +20,7 @@ class LogDatabaseTheme extends Themelet {
HashReasonAction
- + @@ -34,8 +34,8 @@ class LogDatabaseTheme extends Themelet { - + @@ -56,7 +56,7 @@ class LogDatabaseTheme extends Themelet { "".html_escape($event['username'])."". ""; } - $table .= ""; + $table .= ""; $table .= "\n"; } $table .= "
TimeModuleUserMessage
TimeModuleUserMessage
".$this->scan_entities(html_escape($event['message']))."".$this->scan_entities(html_escape($event['message']))."
"; diff --git a/contrib/log_net/main.php b/contrib/log_net/main.php index a9c69b11..94d9d94c 100644 --- a/contrib/log_net/main.php +++ b/contrib/log_net/main.php @@ -13,15 +13,17 @@ class LogNet extends Extension { public function onLog(LogEvent $event) { global $user; - if($this->count < 10 && $event->priority > 10) { - // TODO: colour based on event->priority - $username = ($user && $user->name) ? $user->name : "Anonymous"; - $str = sprintf("%-15s %-10s: %s", $_SERVER['REMOTE_ADDR'], $username, $event->message); - system("echo ".escapeshellarg($str)." | nc -q 0 localhost 5000"); + if($event->priority > 10) { $this->count++; - } - else { - system("echo 'suppressing flood, check the web log' | nc -q 0 localhost 5000"); + if($this->count < 10) { + // TODO: colour based on event->priority + $username = ($user && $user->name) ? $user->name : "Anonymous"; + $str = sprintf("%-15s %-10s: %s", $_SERVER['REMOTE_ADDR'], $username, $event->message); + system("echo ".escapeshellarg($str)." | nc -q 0 localhost 5000"); + } + else if($this->count == 10) { + system("echo 'suppressing flood, check the web log' | nc -q 0 localhost 5000"); + } } } } diff --git a/contrib/numeric_score/main.php b/contrib/numeric_score/main.php index c9811538..98aaf45d 100644 --- a/contrib/numeric_score/main.php +++ b/contrib/numeric_score/main.php @@ -38,7 +38,7 @@ class NumericScore extends Extension { public function onUserPageBuilding(UserPageBuildingEvent $event) { global $page, $user; - if($user->is_admin()) { + if($user->can("edit_other_votes")) { $html = $this->theme->get_nuller_html($event->display_user); $page->add_block(new Block("Votes", $html, "main", 60)); } @@ -79,7 +79,7 @@ class NumericScore extends Extension { } } if($event->page_matches("numeric_score/remove_votes_on") && $user->check_auth_token()) { - if($user->is_admin()) { + if($user->can("edit_other_vote")) { $image_id = int_escape($_POST['image_id']); $database->execute( "DELETE FROM numeric_score_votes WHERE image_id=?", @@ -92,16 +92,8 @@ class NumericScore extends Extension { } } if($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) { - if($user->is_admin()) { - $user_id = int_escape($_POST['user_id']); - $image_ids = $database->get_col("SELECT image_id FROM numeric_score_votes WHERE user_id=?", array($user_id)); - - $database->execute( - "DELETE FROM numeric_score_votes WHERE user_id=? AND image_id IN ?", - array($user_id, $image_ids)); - $database->execute( - "UPDATE images SET numeric_score=(SELECT SUM(score) FROM numeric_score_votes WHERE image_id=images.id) WHERE images.id IN ?", - array($image_ids)); + if($user->can("edit_other_vote")) { + $this->delete_votes_by(int_escape($_POST['user_id'])); $page->set_mode("redirect"); $page->set_redirect(make_link()); } @@ -191,6 +183,31 @@ class NumericScore extends Extension { $database->execute("DELETE FROM numeric_score_votes WHERE image_id=:id", array("id" => $event->image->id)); } + public function onUserDeletion(UserDeletionEvent $event) { + $this->delete_votes_by($event->id); + } + + public function delete_votes_by(/*int*/ $user_id) { + global $database; + + $image_ids = $database->get_col("SELECT image_id FROM numeric_score_votes WHERE user_id=?", array($user_id)); + + $database->execute( + "DELETE FROM numeric_score_votes WHERE user_id=? AND image_id IN (".implode(",", $image_ids).")", + array($user_id)); + $database->execute(" + UPDATE images + SET numeric_score=COALESCE( + ( + SELECT SUM(score) + FROM numeric_score_votes + WHERE image_id=images.id + ), + 0 + ) + WHERE images.id IN (".implode(",", $image_ids).")"); + } + // FIXME: on user deletion // FIXME: on user vote nuke @@ -274,7 +291,12 @@ class NumericScore extends Extension { array("imageid" => $image_id, "userid" => $user_id, "score" => $score)); } $database->Execute( - "UPDATE images SET numeric_score=(SELECT SUM(score) FROM numeric_score_votes WHERE image_id=:imageid) WHERE id=:id", + "UPDATE images SET numeric_score=( + COALESCE( + (SELECT SUM(score) FROM numeric_score_votes WHERE image_id=:imageid), + 0 + ) + ) WHERE id=:id", array("imageid" => $image_id, "id" => $image_id)); } } diff --git a/contrib/numeric_score/theme.php b/contrib/numeric_score/theme.php index b33043e0..fdd2fa90 100644 --- a/contrib/numeric_score/theme.php +++ b/contrib/numeric_score/theme.php @@ -30,7 +30,7 @@ class NumericScoreTheme extends Themelet { "; - if($user->is_admin()) { + if($user->can("edit_other_vote")) { $html .= "
".$user->get_auth_html()." diff --git a/contrib/oekaki/main.php b/contrib/oekaki/main.php index 2c534889..49e1e2cc 100644 --- a/contrib/oekaki/main.php +++ b/contrib/oekaki/main.php @@ -24,12 +24,10 @@ class Oekaki extends Extension { if(isset($_FILES["picture"])) { header('Content-type: text/plain'); - $uploaddir = './data/oekaki_unclaimed/'; - if(!file_exists($uploaddir)) mkdir($uploaddir, 0755, true); $file = $_FILES['picture']['name']; $ext = (strpos($file, '.') === FALSE) ? '' : substr($file, strrpos($file, '.')); $uploadname = $_SERVER['REMOTE_ADDR'] . "." . time(); - $uploadfile = $uploaddir . $uploadname; + $uploadfile = data_path('oekaki_unclaimed/'.$uploadname); log_info("oekaki", "Uploading file [$uploadname]"); @@ -53,7 +51,7 @@ class Oekaki extends Extension { // FIXME: move .chi to data/oekaki/$ha/$hash mirroring images and thumbs // FIXME: .chi viewer? // FIXME: clean out old unclaimed images? - $pattern = './data/oekaki_unclaimed/' . $_SERVER['REMOTE_ADDR'] . ".*.png"; + $pattern = data_path('oekaki_unclaimed/' . $_SERVER['REMOTE_ADDR'] . ".*.png"); foreach(glob($pattern) as $tmpname) { assert(file_exists($tmpname)); diff --git a/contrib/pm/main.php b/contrib/pm/main.php index b1b6f81b..d33c975d 100644 --- a/contrib/pm/main.php +++ b/contrib/pm/main.php @@ -90,7 +90,7 @@ class PrivMsg extends Extension { global $page, $user; $duser = $event->display_user; if(!$user->is_anonymous() && !$duser->is_anonymous()) { - if(($user->id == $duser->id) || $user->is_admin()) { + if(($user->id == $duser->id) || $user->can("view_other_pms")) { $this->theme->display_pms($page, $this->get_pms($duser)); } if($user->id != $duser->id) { @@ -110,7 +110,7 @@ class PrivMsg extends Extension { if(is_null($pm)) { $this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); } - else if(($pm["to_id"] == $user->id) || $user->is_admin()) { + else if(($pm["to_id"] == $user->id) || $user->can("view_other_pms")) { $from_user = User::by_id(int_escape($pm["from_id"])); $database->execute("UPDATE private_message SET is_read='Y' WHERE id = :id", array("id" => $pm_id)); $database->cache->delete("pm-count-{$user->id}"); @@ -127,7 +127,7 @@ class PrivMsg extends Extension { if(is_null($pm)) { $this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); } - else if(($pm["to_id"] == $user->id) || $user->is_admin()) { + else if(($pm["to_id"] == $user->id) || $user->can("view_other_pms")) { $database->execute("DELETE FROM private_message WHERE id = :id", array("id" => $pm_id)); $database->cache->delete("pm-count-{$user->id}"); log_info("pm", "Deleted PM #$pm_id"); diff --git a/contrib/resize/main.php b/contrib/resize/main.php index caba3ed4..139f3ca8 100644 --- a/contrib/resize/main.php +++ b/contrib/resize/main.php @@ -265,7 +265,6 @@ class ResizeImage extends Extension { $new_hash = md5_file($tmp_filename); $new_size = filesize($tmp_filename); $target = warehouse_path("images", $new_hash); - if(!file_exists(dirname($target))) mkdir(dirname($target), 0755, true); if(!@copy($tmp_filename, $target)) { throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); } diff --git a/contrib/shimmie_api/main.php b/contrib/shimmie_api/main.php index e7ddc59e..da65a2d6 100644 --- a/contrib/shimmie_api/main.php +++ b/contrib/shimmie_api/main.php @@ -97,29 +97,50 @@ class ShimmieApi extends Extension { if($event->page_matches("api/shimmie/get_user")) { $query = $user->id; + $type = "id"; if($event->count_args() == 1) { $query = $event->get_arg(0); } - if(isset($_GET['name'])) { - $query = $_GET['name']; - } - if(isset($_GET['id'])) { + elseif(isset($_GET['id'])) { $query = $_GET['id']; } + elseif(isset($_GET['name'])) { + $query = $_GET['name']; + $type = "name"; + } $all = $database->get_row( - "SELECT id,name,joindate,class FROM users WHERE name=? OR id=?", - array($_GET['name'], int_escape($_GET['id']))); + "SELECT id,name,joindate,class FROM users WHERE ".$type."=?", + array($query)); - //FIXME?: For some weird reason, get_all seems to return twice. Unsetting second value to make things look nice.. - // - it returns data as eg array(0=>1234, 'id'=>1234, 1=>'bob', 'name'=>bob, ...); - for($i=0; $i<4; $i++) unset($all[$i]); - $all['uploadcount'] = Image::count_images(array("user_id=".$all['id'])); - $all['uploadperday'] = sprintf("%.1f", ($all['uploadcount'] / (((time() - strtotime($all['joindate'])) / 86400) + 1))); - $all['commentcount'] = $database->get_one( - "SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id", - array("owner_id"=>$all['id'])); - $all['commentperday'] = sprintf("%.1f", ($all['commentcount'] / (((time() - strtotime($all['joindate'])) / 86400) + 1))); + if(!empty($all)){ + //FIXME?: For some weird reason, get_all seems to return twice. Unsetting second value to make things look nice.. + // - it returns data as eg array(0=>1234, 'id'=>1234, 1=>'bob', 'name'=>bob, ...); + for($i=0; $i<4; $i++) unset($all[$i]); + $all['uploadcount'] = Image::count_images(array("user_id=".$all['id'])); + $all['commentcount'] = $database->get_one( + "SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id", + array("owner_id"=>$all['id'])); + + if(isset($_GET['recent'])){ + $recent = $database->get_all( + "SELECT * FROM images WHERE owner_id=? ORDER BY id DESC LIMIT 0, 5", + array($all['id'])); + + $i = 0; + foreach($recent as $all['recentposts'][$i]){ + unset($all['recentposts'][$i]['owner_id']); //We already know the owners id.. + unset($all['recentposts'][$i]['owner_ip']); + + for($x=0; $x<14; $x++) unset($all['recentposts'][$i][$x]); + if(empty($all['recentposts'][$i]['author'])) unset($all['recentposts'][$i]['author']); + if($all['recentposts'][$i]['notes'] > 0) $all['recentposts'][$i]['has_notes'] = "Y"; + else $all['recentposts'][$i]['has_notes'] = "N"; + unset($all['recentposts'][$i]['notes']); + $i += 1; + } + } + } $page->set_data(json_encode($all)); } } diff --git a/contrib/tag_history/main.php b/contrib/tag_history/main.php index 7bcddbd3..b6fe5cea 100644 --- a/contrib/tag_history/main.php +++ b/contrib/tag_history/main.php @@ -35,7 +35,7 @@ class Tag_History extends Extension { } } else if($event->page_matches("tag_history/bulk_revert")) { - if($user->is_admin() && $user->check_auth_token()) { + if($user->can("bulk_edit_image_tag") && $user->check_auth_token()) { $this->process_bulk_revert_request(); } } @@ -78,7 +78,7 @@ class Tag_History extends Extension { public function onUserBlockBuilding(UserBlockBuildingEvent $event) { global $user; - if($user->is_admin()) { + if($user->can("bulk_edit_image_tag")) { $event->add_link("Tag Changes", make_link("tag_history/all/1")); } } diff --git a/contrib/tag_history/theme.php b/contrib/tag_history/theme.php index e88a2b81..a889e748 100644 --- a/contrib/tag_history/theme.php +++ b/contrib/tag_history/theme.php @@ -27,6 +27,14 @@ class Tag_HistoryTheme extends Themelet { $setter = "".html_escape($name)."$h_ip"; $selected = ($n == 2) ? " checked" : ""; + + $current_tags = Tag::explode($current_tags); + $taglinks = array(); + foreach($current_tags as $tag){ + $taglinks[] = "".$tag.""; + } + $current_tags = Tag::implode($taglinks); + $history_list .= "
  • diff --git a/contrib/update/main.php b/contrib/update/main.php index 8e7b2133..9aad4c2c 100644 --- a/contrib/update/main.php +++ b/contrib/update/main.php @@ -91,7 +91,7 @@ class Update extends Extension { $commit = $matches[2]; mkdir("./backup"); $html .= "
    backup folder created!"; - $d_dir = "data/cache"; + $d_dir = data_path("cache"); //This should empty the /data/cache/ folder. if (is_dir($d_dir)) { $objects = scandir($d_dir); @@ -103,7 +103,7 @@ class Update extends Extension { reset($objects); $html .= "
    data folder emptied!"; } - copy ("./config.php", "./backup/config.php");//Although this stays the same, will keep backup just incase. + copy ("./data/config/shimmie.conf.php", "./backup/shimmie.conf.php");//Although this stays the same, will keep backup just incase. $folders = array("./core", "./lib", "./themes", "./.htaccess", "./doxygen.conf", "./index.php", "./install.php", "./ext", "./contrib"); foreach($folders as $folder){ //TODO: Check MD5 of each file, don't rename if same. diff --git a/core/basethemelet.class.php b/core/basethemelet.class.php index aa07045a..075122fa 100644 --- a/core/basethemelet.class.php +++ b/core/basethemelet.class.php @@ -34,6 +34,7 @@ class BaseThemelet { $h_view_link = make_link('post/view/'.$i_id, $query); $h_thumb_link = $image->get_thumb_link(); $h_tip = html_escape($image->get_tooltip()); + $h_tags = strtolower($image->get_tag_list()); $base = get_base_href(); // If file is flash or svg then sets thumbnail to max size. @@ -44,7 +45,7 @@ class BaseThemelet { $tsize = get_thumbnail_size($image->width, $image->height); } - return ''. + return ''. ''.$h_tip.''. ''. "\n"; diff --git a/core/database.class.php b/core/database.class.php index 2f63ab1a..fc93269f 100644 --- a/core/database.class.php +++ b/core/database.class.php @@ -273,7 +273,7 @@ class Database { /** * Create a new database object using connection info - * stored in config.php in the root shimmie folder + * stored in the config file */ public function Database() { # FIXME: detect ADODB URI, automatically translate PDO DSN diff --git a/core/default_config.inc.php b/core/default_config.inc.php index f2ddfcda..3f6b6e50 100644 --- a/core/default_config.inc.php +++ b/core/default_config.inc.php @@ -2,7 +2,7 @@ /** * These are the default configuration options for Shimmie. * - * All of these can be over-ridden by placing a 'define' in config.php + * All of these can be over-ridden by placing a 'define' in data/config/shimmie.conf.php * * Do NOT change them in this file. These are the defaults only! * diff --git a/core/imageboard.pack.php b/core/imageboard.pack.php index 83a30d3a..e562de10 100644 --- a/core/imageboard.pack.php +++ b/core/imageboard.pack.php @@ -1080,7 +1080,6 @@ class Tag { */ function move_upload_to_archive(DataUploadEvent $event) { $target = warehouse_path("images", $event->hash); - if(!file_exists(dirname($target))) mkdir(dirname($target), 0755, true); if(!@copy($event->tmpname, $target)) { $errors = error_get_last(); // note: requires php 5.2 throw new UploadException("Failed to copy file from uploads ({$event->tmpname}) to archive ($target): {$errors['type']} / {$errors['message']}"); diff --git a/core/page.class.php b/core/page.class.php index 6547c3f2..6a562f38 100644 --- a/core/page.class.php +++ b/core/page.class.php @@ -245,222 +245,42 @@ class Page { # 404/static handler will map these to themes/foo/bar.ico or lib/static/bar.ico $this->add_html_header(""); $this->add_html_header(""); - - /* Attempt to cache the CSS & JavaScript files */ - if ($this->add_cached_auto_html_headers() === FALSE) { - // caching failed, add all files to html_headers. - - foreach(glob("lib/*.css") as $css) { - $this->add_html_header(''); - } - $css_files = glob("ext/*/style.css"); - if($css_files) { - foreach($css_files as $css_file) { - $this->add_html_header(''); - } - } - $css_files = glob("themes/$theme_name/style.css"); - if($css_files) { - foreach($css_files as $css_file) { - $this->add_html_header(''); - } - } - - foreach(glob("lib/*.js") as $js) { - $this->add_html_header(''); - } - $js_files = glob("ext/*/script.js"); - if($js_files) { - foreach($js_files as $js_file) { - $this->add_html_header(''); - } - } + + $css_files = array(); + $css_latest = 0; + foreach(array_merge(zglob("lib/*.css"), zglob("ext/*/style.css"), zglob("themes/$theme_name/style.css")) as $css) { + $css_files[] = $css; + $css_latest = max($css_latest, filemtime($css)); } - } - - /** - * Automatic caching of CSS and Javascript files - * - * Allows site admins to have Shimmie automatically cache and minify all CSS and JS files. - * This is done to reduce the number of HTTP requests (recommended by the Yahoo high-performance - * guidelines). It combines all of the CSS and JavaScript files into one for each type, and - * stores them in cached files to serve the client. Changes to the CSS or JavaScript files are - * caught by taking the md5sum of the concatenated files. - * - * Note: This can be somewhat problematic, as it edits the links to your CSS files (as well - * as the links to images inside them). - * Also, the directory cache directory needs to be writeable by the php/webserver user. - * PLEASE: Ensure that you test your site out throughly after enabling this module! - * Either that, or don't use this module unless you are sure of what it is doing. - * - * TODO: Add support for minify-ing CSS and Javascript files. (similar to Minify. See: http://code.google.com/p/minify/ or https://github.com/mrclay/minify) - * TODO: For performance reasons: Before performing the regex's, compute the md5 of the CSS & JS files and store somewhere to check later. - * - * @return - * This function returns FALSE if it failed to cache the files, - * and returns TRUE if it was successful. - */ - private function add_cached_auto_html_headers() { - global $config; - - // store local copy for speed. - $autocache_css = $config->get_bool("autocache_css"); - $autocache_js = $config->get_bool("autocache_js"); - $theme_name = $config->get_string('theme', 'default'); - - if (!$autocache_css && !$autocache_js) { - return false; // caching disabled - } - - $cache_location = $config->get_string("autocache_location", 'data/cache'); - // Detect is there is a trailing slash, and add one if not. - $cache_location = ((strrpos($cache_location, '/') + 1) == strlen($cache_location)) ? $cache_location : $cache_location.'/'; - - // Create directory if needed. - if(!file_exists($cache_location)) { - if (!mkdir($cache_location, 0750, true)) { - return false; // failed to create directory - } - } - - $data_href = get_base_href(); - - /* ----- CSS Files ----- */ - if($autocache_css) { - // First get all the CSS from the lib directory - $contents_from_lib = ''; - $css_files = glob("lib/*.css"); - if($css_files) { - foreach($css_files as $css_file) { - $contents_from_lib .= file_get_contents($css_file); - } - // Can't directly cache the CSS files, as they might have relative locations to images, etc. in them. - // We have to adjust the URLs accordingly before saving the cached file. + $css_cache_file = data_path("cache/style.$css_latest.css"); + if(!file_exists($css_cache_file)) { + $css_data = ""; + foreach($css_files as $file) { + $file_data = file_get_contents($file); $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; - $replace = 'url("../../lib/${1}")'; - $contents_from_lib = preg_replace($pattern, $replace, $contents_from_lib); - } - // Next get all the CSS from the extensions - $contents_from_extensions = ''; - $css_files = glob("ext/*/style.css"); - if($css_files) { - foreach($css_files as $css_file) { - $contents_from_extensions .= file_get_contents($css_file); - } - // Can't directly cache the CSS files, as they might have relative locations to images, etc. in them. - // We have to adjust the URLs accordingly before saving the cached file. - $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; - $replace = 'url("../../${1}")'; - $contents_from_extensions = preg_replace($pattern, $replace, $contents_from_extensions); - } - // Get CSS from theme - $contents_from_theme = ''; - $css_files = glob("themes/$theme_name/style.css"); - if($css_files) { - foreach($css_files as $css_file) { - $contents_from_theme .= file_get_contents($css_file); - } - // Can't directly cache the CSS files, as they might have relative locations to images, etc. in them. - // We have to adjust the URLs accordingly before saving the cached file. - $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; - $replace = 'url("../../${1}")'; - $contents_from_theme = preg_replace($pattern, $replace, $contents_from_theme); - } - // Combine the three - $data = $contents_from_lib .' '. $contents_from_extensions .' '. $contents_from_theme; - - // Minify the CSS if enabled. - if($config->get_bool("autocache_min_css")) { - // not supported yet. - // TODO: add support for Minifying CSS files. + $replace = 'url("../../'.dirname($file).'/$1")'; + $file_data = preg_replace($pattern, $replace, $file_data); + $css_data .= $file_data . "\n"; } + file_put_contents($css_cache_file, $css_data); + } + $this->add_html_header(""); - // compute the MD5 sum of the concatenated CSS files - $md5sum = md5($data); - - if(!file_exists($cache_location.$md5sum.'.css')) { - // remove any old cached CSS files. - $mask = '*.css'; - array_map( 'unlink', glob( $mask ) ); - - // output the combined file - if(file_put_contents($cache_location.$md5sum.'.css', $data, LOCK_EX) === FALSE) { - return false; // failed to write the file - } - } - // tell the client where to get the css cache file - $this->add_html_header(''); + $js_files = array(); + $js_latest = 0; + foreach(array_merge(zglob("lib/*.js"), zglob("ext/*/script.js"), zglob("themes/$theme_name/script.js")) as $js) { + $js_files[] = $js; + $js_latest = max($js_latest, filemtime($js)); } - else { - // Caching of CSS disabled. - foreach(glob("lib/*.css") as $css) { - $this->add_html_header(''); - } - $css_files = glob("ext/*/style.css"); - if($css_files) { - foreach($css_files as $css_file) { - $this->add_html_header(''); - } - } - $css_files = glob("themes/$theme_name/style.css"); - if($css_files) { - foreach($css_files as $css_file) { - $this->add_html_header(''); - } + $js_cache_file = data_path("cache/script.$js_latest.js"); + if(!file_exists($js_cache_file)) { + $js_data = ""; + foreach($js_files as $file) { + $js_data .= file_get_contents($file) . "\n"; } + file_put_contents($js_cache_file, $js_data); } - - - /* ----- JavaScript Files ----- */ - if($autocache_js) { - $data = ''; - $js_files = glob("lib/*.js"); - if($js_files) { - foreach($js_files as $js_file) { - $data .= file_get_contents($js_file); - } - } - $js_files = glob("ext/*/script.js"); - if($js_files) { - foreach($js_files as $js_file) { - $data .= file_get_contents($js_file); - } - } - // Minify the JS if enabled. - if ($config->get_bool("autocache_min_js")){ - // not supported yet. - // TODO: add support for Minifying JS files. - } - - // compute the MD5 sum of the concatenated JavaScript files - $md5sum = md5($data); - - if (!file_exists($cache_location.$md5sum.'.js')) { - // remove any old cached js files. - $mask = '*.js'; - array_map( 'unlink', glob( $mask ) ); - // output the combined file - if (file_put_contents($cache_location.$md5sum.'.js', $data, LOCK_EX) === FALSE) { - return false; - } - } - // tell the client where to get the js cache file - $this->add_html_header(''); - } - else { - // Caching of Javascript disabled. - foreach(glob("lib/*.js") as $js) { - $this->add_html_header(''); - } - $js_files = glob("ext/*/script.js"); - if($js_files) { - foreach($js_files as $js_file) { - $this->add_html_header(''); - } - } - } - - return true; + $this->add_html_header(""); } } ?> diff --git a/core/userclass.class.php b/core/userclass.class.php index e342040b..8b12d9af 100644 --- a/core/userclass.class.php +++ b/core/userclass.class.php @@ -40,7 +40,7 @@ class UserClass { // object = image / user / tag / setting new UserClass("base", null, array( "change_setting" => False, # modify web-level settings, eg the config table - "override_config" => False, # modify sys-level settings, eg config.php + "override_config" => False, # modify sys-level settings, eg shimmie.conf.php "big_search" => False, # search for more than 3 tags at once (speed mode only) "manage_extension_list" => False, @@ -63,8 +63,14 @@ new UserClass("base", null, array( "edit_image_source" => False, "edit_image_owner" => False, "edit_image_lock" => False, + "bulk_edit_image_tag" => False, "delete_image" => False, + "ban_image" => False, + + "view_eventlog" => False, + "ignore_downtime" => False, + "create_image_report" => False, "view_image_report" => False, # deal with reported images @@ -73,6 +79,13 @@ new UserClass("base", null, array( "manage_blocks" => False, + "manage_admintools" => False, + + "view_other_pms" => False, + "edit_feature" => False, + "bulk_edit_vote" => False, + "edit_other_vote" => False, + "protected" => False, # only admins can modify protected users (stops a moderator changing an admin's password) )); @@ -100,6 +113,7 @@ new UserClass("admin", "base", array( "delete_user" => True, "create_image" => True, "delete_image" => True, + "ban_image" => True, "create_comment" => True, "delete_comment" => True, "replace_image" => True, @@ -108,12 +122,20 @@ new UserClass("admin", "base", array( "edit_image_tag" => True, "edit_image_source" => True, "edit_image_owner" => True, + "bulk_edit_image_tag" => True, "mass_tag_edit" => True, "create_image_report" => True, "view_image_report" => True, "edit_wiki_page" => True, "delete_wiki_page" => True, + "view_eventlog" => True, "manage_blocks" => True, + "manage_admintools" => True, + "ignore_downtime" => True, + "view_other_pms" => True, + "edit_feature" => True, + "bulk_edit_vote" => True, + "edit_other_vote" => True, "protected" => True, )); diff --git a/core/util.inc.php b/core/util.inc.php index b9b5e905..9fce4dda 100644 --- a/core/util.inc.php +++ b/core/util.inc.php @@ -361,6 +361,11 @@ function mtimefile($file) { return "$data_href/$file?$mtime"; } +function zglob($pattern) { + $r = glob($pattern); + if($r) return $r; + else return array(); +} /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ @@ -640,6 +645,12 @@ function warehouse_path(/*string*/ $base, /*string*/ $hash, /*bool*/ $create=tru return $pa; } +function data_path($filename) { + $filename = "data/" . $filename; + if(!file_exists(dirname($filename))) mkdir(dirname($filename), 0755, true); + return $filename; +} + function transload($url, $mfile) { global $config; @@ -879,9 +890,10 @@ $_event_listeners = array(); */ function add_event_listener(Extension $extension, $pos=50, $events=array()) { global $_event_listeners; + $pos *= 100; foreach($events as $event) { while(isset($_event_listeners[$event][$pos])) { - $pos++; + $pos += 1; } $_event_listeners[$event][$pos] = $extension; } @@ -1024,8 +1036,8 @@ function _load_extensions() { ctx_log_start("Loading extensions"); - if(COMPILE_ELS && file_exists("data/event_listeners.php")) { - require_once("data/event_listeners.php"); + if(COMPILE_ELS && file_exists("data/cache/event_listeners.php")) { + require_once("data/cache/event_listeners.php"); } else { foreach(get_declared_classes() as $class) { @@ -1069,7 +1081,7 @@ function _load_extensions() { $p .= ");\n"; $p .= "?".">"; - file_put_contents("data/event_listeners.php", $p); + file_put_contents(data_path("cache/event_listeners.php"), $p); } } @@ -1223,11 +1235,9 @@ function _start_cache() { $_cache_hash = md5($_SERVER["QUERY_STRING"]); $ab = substr($_cache_hash, 0, 2); $cd = substr($_cache_hash, 2, 2); - $_cache_filename = "data/http_cache/$ab/$cd/$_cache_hash"; + $_cache_filename = data_path("http_cache/$ab/$cd/$_cache_hash"); + @chmod(data_path('http_cache'), 750); - if(!file_exists(dirname($_cache_filename))) { - mkdir(dirname($_cache_filename), 0750, true); - } if(file_exists($_cache_filename) && (filemtime($_cache_filename) > time() - 3600)) { $gmdate_mod = gmdate('D, d M Y H:i:s', filemtime($_cache_filename)) . ' GMT'; diff --git a/doxygen.conf b/doxygen.conf index c934f615..085ca149 100644 --- a/doxygen.conf +++ b/doxygen.conf @@ -640,11 +640,11 @@ RECURSIVE = YES # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. -EXCLUDE = config.php \ - install.php \ +EXCLUDE = install.php \ phpinfo.php \ contrib/simpletest/simpletest \ lib \ + data \ images \ thumbs \ .git \ diff --git a/ext/alias_editor/main.php b/ext/alias_editor/main.php old mode 100755 new mode 100644 index f03f0bac..539bafde --- a/ext/alias_editor/main.php +++ b/ext/alias_editor/main.php @@ -122,7 +122,7 @@ class AliasEditor extends Extension { private function get_alias_csv(Database $database) { $csv = ""; - $aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases"); + $aliases = $database->get_pairs("SELECT oldtag, newtag FROM aliases ORDER BY newtag"); foreach($aliases as $old => $new) { $csv .= "$old,$new\n"; } @@ -138,5 +138,10 @@ class AliasEditor extends Extension { } } } + + // add alias *after* mass tag editing, else the MTE will + // search for the images and be redirected to the alias, + // missing out the images tagged with the oldtag + public function get_priority() {return 60;} } ?> diff --git a/ext/bbcode/main.php b/ext/bbcode/main.php index eb5acf05..8b613af7 100644 --- a/ext/bbcode/main.php +++ b/ext/bbcode/main.php @@ -33,7 +33,7 @@ class BBCode extends FormatterExtension { ) as $el) { $text = preg_replace("!\[$el\](.*?)\[/$el\]!s", "<$el>$1", $text); } - $text = preg_replace('!>>([^\d].+)!s', '
    $1
    ', $text); + $text = preg_replace('!>>([^\d].+)!', '
    $1
    ', $text); $text = preg_replace('!>>(\d+)(#c?\d+)?!s', '>>$1$2', $text); $text = preg_replace('!\[url=site://(.*?)(#c\d+)?\](.*?)\[/url\]!s', '$3', $text); $text = preg_replace('!\[url\]site://(.*?)(#c\d+)?\[/url\]!s', '$1$2', $text); diff --git a/ext/handle_pixel/main.php b/ext/handle_pixel/main.php index 36dbef25..061a155a 100644 --- a/ext/handle_pixel/main.php +++ b/ext/handle_pixel/main.php @@ -75,6 +75,19 @@ class PixelFileHandler extends DataHandlerExtension { return $ok; } + + public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { + $event->add_part(" + + +
  • + ", 20); + } // IM thumber {{{ private function make_thumb_convert(/*string*/ $inname, /*string*/ $outname) { diff --git a/ext/handle_pixel/script.js b/ext/handle_pixel/script.js new file mode 100644 index 00000000..c95bc3e0 --- /dev/null +++ b/ext/handle_pixel/script.js @@ -0,0 +1,40 @@ +$(function() { + $("#zoomer").change(function(e) { + zoom(this.options[this.selectedIndex].value); + }); + + $("#main_image").click(function(e) { + switch($.cookie("ui-image-zoom")) { + case "full": zoom("width"); break; + default: zoom("full"); break; + } + }); + + if($.cookie("ui-image-zoom")) { + zoom($.cookie("ui-image-zoom")); + } +}); + +function zoom(zoom) { + var img = $('#main_image'); + if(zoom == "full") { + img.css('max-width', img.data('width') + 'px'); + img.css('max-height', img.data('height') + 'px'); + } + if(zoom == "width") { + img.css('max-width', '95%'); + img.css('max-height', img.data('height') + 'px'); + } + if(zoom == "height") { + img.css('max-width', img.data('width') + 'px'); + img.css('max-height', (window.innerHeight * 0.95) + 'px'); + } + if(zoom == "both") { + img.css('max-width', '95%'); + img.css('max-height', (window.innerHeight * 0.95) + 'px'); + } + + $("#zoomer").val(zoom); + + $.cookie("ui-image-zoom", zoom, {path: '/', expires: 365}); +} diff --git a/ext/handle_pixel/theme.php b/ext/handle_pixel/theme.php index 88c14d63..03e6c99f 100644 --- a/ext/handle_pixel/theme.php +++ b/ext/handle_pixel/theme.php @@ -5,7 +5,6 @@ class PixelFileHandlerTheme extends Themelet { global $config; $u_ilink = $image->get_image_link(); - $html = "main image"; if($config->get_bool("image_show_meta") && function_exists("exif_read_data")) { # FIXME: only read from jpegs? $exif = @exif_read_data($image->get_image_filename(), 0, true); @@ -24,39 +23,8 @@ class PixelFileHandlerTheme extends Themelet { } } - $zoom_default = $config->get_bool("image_zoom", false) ? "scale(img);" : ""; - $zoom = ""; - - $page->add_block(new Block("Image", $html.$zoom, "main", 10)); + $html = "main image"; + $page->add_block(new Block("Image", $html, "main", 10)); } } ?> diff --git a/ext/image/main.php b/ext/image/main.php index d991a674..ca902f4c 100644 --- a/ext/image/main.php +++ b/ext/image/main.php @@ -298,11 +298,6 @@ class ImageIO extends Extension { if(strlen(trim($image->source)) == 0) { $image->source = null; } - if(!empty($image->source)) { - if(!preg_match("#^(https?|ftp)://#", $image->source)) { - throw new ImageAdditionException("Image's source isn't a valid URL"); - } - } /* * Check for an existing image @@ -431,11 +426,6 @@ class ImageIO extends Extension { if(strlen(trim($image->source)) == 0) { $image->source = $existing->get_source(); } - if(!empty($image->source)) { - if(!preg_match("#^(https?|ftp)://#", $image->source)) { - throw new ImageReplaceException("Image's source isn't a valid URL"); - } - } /* This step could be optional, ie: perhaps move the image somewhere diff --git a/ext/index/script.js b/ext/index/script.js new file mode 100644 index 00000000..459118fb --- /dev/null +++ b/ext/index/script.js @@ -0,0 +1,30 @@ +$(function() { + var blocked_tags = ($.cookie("ui-blocked-tags") || $.cookie("blocked-tags") || "").split(" "); + var themecheck = $(".thumb[data-tags~='tagme']").parent().attr('class'); + var needs_refresh = false; + for(i in blocked_tags) { + var tag = blocked_tags[i]; + if(tag) { + $(".thumb[data-tags~='"+tag+"']").hide(); + if(themecheck == "thumbblock") { + $(".thumb[data-tags~='tagme']").parent().height(0); //required for lite theme + } + needs_refresh = true; + } + } + // need to trigger a reflow in opera, because opera implements + // text-align: justify with element margins and doesn't recalculate + // these margins when part of the line disappears... + if(needs_refresh) { + $('#image-list').hide(); + $('#image-list').show(); + } +}); + +function select_blocked_tags() { + var blocked_tags = prompt("Enter tags to ignore", $.cookie("ui-blocked-tags") || "My_Little_Pony"); + if(blocked_tags) { + $.cookie("ui-blocked-tags", blocked_tags.toLowerCase(), {path: '/', expires: 365}); + location.reload(true); + } +} diff --git a/ext/setup/main.php b/ext/setup/main.php index b20e8b45..195c0904 100644 --- a/ext/setup/main.php +++ b/ext/setup/main.php @@ -166,12 +166,6 @@ class Setup extends Extension { $config->set_default_string("theme", "default"); $config->set_default_bool("word_wrap", true); $config->set_default_bool("comment_captcha", false); - // Automatic caching is disabled by default - $config->set_default_string("autocache_location", "data/cache"); - $config->set_default_bool("autocache_css", false); - $config->set_default_bool("autocache_jss", false); - $config->set_default_bool("autocache_min_css", false); - $config->set_default_bool("autocache_min_js", false); } public function onPageRequest(PageRequestEvent $event) { @@ -279,19 +273,6 @@ class Setup extends Extension { $sb->add_text_option("api_recaptcha_privkey", "
    Private key: "); $sb->add_text_option("api_recaptcha_pubkey", "
    Public key: "); $event->panel->add_block($sb); - - - $sb = new SetupBlock("Automatic Caching of CSS & JS"); - // the default is fine for just about everyone - //$sb->add_text_option("autocache_location", "Location: "); - //$sb->add_label("
    This location needs to be writeable by the webserver."); - $sb->add_bool_option("autocache_css", "Automatic caching of CSS: "); - $sb->add_bool_option("autocache_js", "
    Automatic caching of JS: "); - // if the option does nothing, there's no point showing a - // "hey look, nothing!" message... - //$sb->add_bool_option("autocache_min_css", "
    Minimize CSS files: "); - //$sb->add_bool_option("autocache_min_js", "
    Minimize JS files: "); - $event->panel->add_block($sb); } public function onConfigSave(ConfigSaveEvent $event) { diff --git a/ext/tag_edit/main.php b/ext/tag_edit/main.php index 6364b404..ffb70982 100644 --- a/ext/tag_edit/main.php +++ b/ext/tag_edit/main.php @@ -187,6 +187,8 @@ class TagEdit extends Extension { $search_set = Tag::explode($search); $replace_set = Tag::explode($replace); + log_info("tag_edit", "Mass editing tags: '$search' -> '$replace'"); + $last_id = -1; while(true) { // make sure we don't look at the same images twice. diff --git a/ext/tag_edit/test.php b/ext/tag_edit/test.php index f620b42b..79ac50fb 100644 --- a/ext/tag_edit/test.php +++ b/ext/tag_edit/test.php @@ -45,11 +45,23 @@ class TagEditTest extends ShimmieWebTestCase { function testMassEdit() { $this->log_in_as_admin(); + + $image_id = $this->post_image("ext/simpletest/data/pbx_screenshot.jpg", "pbx"); + $this->get_page("post/view/$image_id"); + $this->assert_title("Image $image_id: pbx"); + $this->get_page("admin"); $this->assert_text("Mass Tag Edit"); // just test it exists - $this->log_out(); + $this->set_field("search", "pbx"); + $this->set_field("replace", "pox"); + $this->click("Set"); - # FIXME: test mass tag editor + $this->get_page("post/view/$image_id"); + $this->assert_title("Image $image_id: pox"); + + $this->delete_image($image_id); + + $this->log_out(); } } ?> diff --git a/ext/tag_list/main.php b/ext/tag_list/main.php index 20fcdfd7..8f36345f 100644 --- a/ext/tag_list/main.php +++ b/ext/tag_list/main.php @@ -188,7 +188,7 @@ class TagList extends Extension { $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"; + $cache_key = data_path("cache/tag_cloud-" . md5("tc" . $tags_min . $starts_with) . ".html"); if(file_exists($cache_key)) {return file_get_contents($cache_key);} // SHIT: PDO/pgsql has problems using the same named param twice -_-;; @@ -225,7 +225,7 @@ class TagList extends Extension { $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"; + $cache_key = data_path("cache/tag_alpha-" . md5("ta" . $tags_min . $starts_with) . ".html"); if(file_exists($cache_key)) {return file_get_contents($cache_key);} $tag_data = $database->get_all($database->engine->scoreql_to_sql(" @@ -261,7 +261,7 @@ class TagList extends Extension { $tags_min = $this->get_tags_min(); // check if we have a cached version - $cache_key = "data/tag_popul-" . md5("tp" . $tags_min) . ".html"; + $cache_key = data_path("cache/tag_popul-" . md5("tp" . $tags_min) . ".html"); if(file_exists($cache_key)) {return file_get_contents($cache_key);} $tag_data = $database->get_all(" diff --git a/ext/user/main.php b/ext/user/main.php index 2c4dba9a..9674032a 100644 --- a/ext/user/main.php +++ b/ext/user/main.php @@ -40,6 +40,14 @@ class UserCreationEvent extends Event { } } +class UserDeletionEvent extends Event { + var $id; + + public function __construct($id) { + $this->id = $id; + } +} + class UserCreationException extends SCoreException {} class UserPage extends Extension { @@ -519,6 +527,8 @@ class UserPage extends Extension { ); } + send_event(new UserDeletionEvent($_POST['id'])); + $database->execute( "DELETE FROM users WHERE id = :id", array("id" => $_POST['id']) diff --git a/index.php b/index.php index 9895d7c7..3ef60456 100644 --- a/index.php +++ b/index.php @@ -43,11 +43,11 @@ * Each of these can be imported at the start of a function with eg "global $page, $user;" */ -if(!file_exists("config.php")) { +if(!file_exists("data/config/shimmie.conf.php")) { header("Location: install.php"); exit; } -require_once "config.php"; +require_once "data/config/shimmie.conf.php"; require_once "core/default_config.inc.php"; require_once "core/util.inc.php"; require_once "lib/context.php"; diff --git a/install.php b/install.php index 142fa9f5..795bc5e5 100644 --- a/install.php +++ b/install.php @@ -64,13 +64,13 @@ require_once __SHIMMIE_ROOT__."core/database.class.php"; * This file lets anyone destroy the database -- disable it * as soon as the admin is done installing for the first time */ -if(is_readable("config.php")) { +if(is_readable("data/config/shimmie.conf.php")) { session_start(); echo '
    '; echo '

    Shimmie Repair Console

    '; // Load the config - require_once __SHIMMIE_ROOT__."config.php"; // Load user/site specifics First + require_once __SHIMMIE_ROOT__."data/config/shimmie.conf.php"; // Load user/site specifics First require_once __SHIMMIE_ROOT__."core/default_config.inc.php"; // Defaults for the rest. if( @@ -120,7 +120,7 @@ if(is_readable("config.php")) { else { echo "

    Login

    -

    Enter the database DSN exactly as in config.php (ie, as originally installed) to access advanced recovery tools:

    +

    Enter the database DSN exactly as in shimmie.conf.php (ie, as originally installed) to access advanced recovery tools:

    @@ -403,14 +403,15 @@ function write_config() { // {{{ "define('DATABASE_DSN', '".DATABASE_DSN."');\n" . '?' . '>'; - if(is_writable("./") && file_put_contents("config.php", $file_content)) { - assert(file_exists("config.php")); + if(!file_exists("data/config")) { + mkdir("data/config", 0755, true); } - else { + + if(!file_put_contents("data/config/shimmie.conf.php", $file_content)) { $h_file_content = htmlentities($file_content); print <<e.failure_limit)return!1})}var d=this,e={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!0,appear:null,load:null};return c&&(undefined!==c.failurelimit&&(c.failure_limit=c.failurelimit,delete c.failurelimit),undefined!==c.effectspeed&&(c.effect_speed=c.effectspeed,delete c.effectspeed),a.extend(e,c)),$container=e.container===undefined||e.container===b?$window:a(e.container),0===e.event.indexOf("scroll")&&$container.bind(e.event,function(a){return f()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,c.one("appear",function(){if(!this.loaded){if(e.appear){var f=d.length;e.appear.call(b,f,e)}a("").bind("load",function(){c.hide().attr("src",c.data(e.data_attribute))[e.effect](e.effect_speed),b.loaded=!0;var f=a.grep(d,function(a){return!a.loaded});d=a(f);if(e.load){var g=d.length;e.load.call(b,g,e)}}).attr("src",c.data(e.data_attribute))}}),0!==e.event.indexOf("scroll")&&c.bind(e.event,function(a){b.loaded||c.trigger("appear")})}),$window.bind("resize",function(a){f()}),f(),this},a.belowthefold=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.height()+$window.scrollTop():e=$container.offset().top+$container.height(),e<=a(c).offset().top-d.threshold},a.rightoffold=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.width()+$window.scrollLeft():e=$container.offset().left+$container.width(),e<=a(c).offset().left-d.threshold},a.abovethetop=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.scrollTop():e=$container.offset().top,e>=a(c).offset().top+d.threshold+a(c).height()},a.leftofbegin=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.scrollLeft():e=$container.offset().left,e>=a(c).offset().left+d.threshold+a(c).width()},a.inviewport=function(b,c){return!a.rightofscreen(b,c)&&!a.leftofscreen(b,c)&&!a.belowthefold(b,c)&&!a.abovethetop(b,c)},a.extend(a.expr[":"],{"below-the-fold":function(c){return a.belowthefold(c,{threshold:0,container:b})},"above-the-top":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-screen":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-screen":function(c){return!a.rightoffold(c,{threshold:0,container:b})},"in-viewport":function(c){return!a.inviewport(c,{threshold:0,container:b})},"above-the-fold":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-fold":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-fold":function(c){return!a.rightoffold(c,{threshold:0,container:b})}})})(jQuery,window) +(function(a,b){$window=a(b),a.fn.lazyload=function(c){function f(){var b=0;d.each(function(){var c=a(this);if(e.skip_invisible&&!c.is(":visible"))return;if(!a.abovethetop(this,e)&&!a.leftofbegin(this,e))if(!a.belowthefold(this,e)&&!a.rightoffold(this,e))c.trigger("appear");else if(++b>e.failure_limit)return!1})}var d=this,e={threshold:0,failure_limit:0,event:"scroll",effect:"show",container:b,data_attribute:"original",skip_invisible:!0,appear:null,load:null};return c&&(undefined!==c.failurelimit&&(c.failure_limit=c.failurelimit,delete c.failurelimit),undefined!==c.effectspeed&&(c.effect_speed=c.effectspeed,delete c.effectspeed),a.extend(e,c)),$container=e.container===undefined||e.container===b?$window:a(e.container),0===e.event.indexOf("scroll")&&$container.bind(e.event,function(a){return f()}),this.each(function(){var b=this,c=a(b);b.loaded=!1,c.one("appear",function(){if(!this.loaded){if(e.appear){var f=d.length;e.appear.call(b,f,e)}a("").bind("load",function(){c.hide().attr("src",c.data(e.data_attribute))[e.effect](e.effect_speed),b.loaded=!0;var f=a.grep(d,function(a){return!a.loaded});d=a(f);if(e.load){var g=d.length;e.load.call(b,g,e)}}).attr("src",c.data(e.data_attribute))}}),0!==e.event.indexOf("scroll")&&c.bind(e.event,function(a){b.loaded||c.trigger("appear")})}),$window.bind("resize",function(a){f()}),f(),this},a.belowthefold=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.height()+$window.scrollTop():e=$container.offset().top+$container.height(),e<=a(c).offset().top-d.threshold},a.rightoffold=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.width()+$window.scrollLeft():e=$container.offset().left+$container.width(),e<=a(c).offset().left-d.threshold},a.abovethetop=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.scrollTop():e=$container.offset().top,e>=a(c).offset().top+d.threshold+a(c).height()},a.leftofbegin=function(c,d){var e;return d.container===undefined||d.container===b?e=$window.scrollLeft():e=$container.offset().left,e>=a(c).offset().left+d.threshold+a(c).width()},a.inviewport=function(b,c){return!a.rightofscreen(b,c)&&!a.leftofscreen(b,c)&&!a.belowthefold(b,c)&&!a.abovethetop(b,c)},a.extend(a.expr[":"],{"below-the-fold":function(c){return a.belowthefold(c,{threshold:0,container:b})},"above-the-top":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-screen":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-screen":function(c){return!a.rightoffold(c,{threshold:0,container:b})},"in-viewport":function(c){return!a.inviewport(c,{threshold:0,container:b})},"above-the-fold":function(c){return!a.belowthefold(c,{threshold:0,container:b})},"right-of-fold":function(c){return a.rightoffold(c,{threshold:0,container:b})},"left-of-fold":function(c){return!a.rightoffold(c,{threshold:0,container:b})}})})(jQuery,window); diff --git a/lib/shimmie.js b/lib/shimmie.js index 8eb6f616..7bc91bff 100644 --- a/lib/shimmie.js +++ b/lib/shimmie.js @@ -38,7 +38,7 @@ $(document).ready(function() { }); try { - var sidebar_hidden = ($.cookie("sidebar-hidden") || "").split("|"); + var sidebar_hidden = ($.cookie("ui-sidebar-hidden") || $.cookie("sidebar-hidden") || "").split("|"); for(var i in sidebar_hidden) { if(sidebar_hidden[i].length > 0) { $(sidebar_hidden[i]+" .blockbody").hide(); @@ -63,7 +63,7 @@ $(document).ready(function() { } } } - $.cookie("sidebar-hidden", sidebar_hidden.join("|"), {path: '/'}); + $.cookie("ui-sidebar-hidden", sidebar_hidden.join("|"), {path: '/', expires: 365}); }) }); diff --git a/themes/danbooru/user.theme.php b/themes/danbooru/user.theme.php index a3329c80..51e3b32b 100644 --- a/themes/danbooru/user.theme.php +++ b/themes/danbooru/user.theme.php @@ -98,47 +98,5 @@ class CustomUserPageTheme extends UserPageTheme { $page->disable_left(); parent::display_user_page($duser, $stats); } - - protected function build_options($duser) { - global $database; - global $config; - global $user; - - $html = ""; - $html .= " - - - - - - - - -
    Change Password
    Password
    Repeat Password
    - -

    - - - - - -
    Change Email
    Address
    -

    - "; - - if($user->is_admin()) { - $i_user_id = int_escape($duser->id); - $h_is_admin = $duser->is_admin() ? " checked" : ""; - $html .= " -

    ".make_form(make_link("user_admin/set_more"))." - - Admin: - - - "; - } - - return $html; - } } ?> diff --git a/themes/lite/style.css b/themes/lite/style.css index 1560e7d0..fe519214 100644 --- a/themes/lite/style.css +++ b/themes/lite/style.css @@ -70,7 +70,7 @@ a.tab:hover, a.tab:active, .tab-selected { -moz-border-radius:4px; -webkit-border-radius:4px; } -.highlighted { +.lazy{ background:none repeat scroll 0 0 #CEDFF0; padding:4px; border:1px solid #C3D2E0; diff --git a/themes/lite/themelet.class.php b/themes/lite/themelet.class.php index 8afa7754..3633860b 100644 --- a/themes/lite/themelet.class.php +++ b/themes/lite/themelet.class.php @@ -6,28 +6,26 @@ class Themelet extends BaseThemelet { */ public function build_thumb_html(Image $image, $query=null) { global $config; - $i_id = int_escape($image->id); - $h_view_link = make_link("post/view/$i_id", $query); + $i_id = (int) $image->id; + $h_view_link = make_link('post/view/'.$i_id, $query); $h_thumb_link = $image->get_thumb_link(); $h_tip = html_escape($image->get_tooltip()); + $h_tags = strtolower($image->get_tag_list()); + $base = get_base_href(); // If file is flash or svg then sets thumbnail to max size. - if($image->ext == 'swf' || $image->ext == 'svg') { + if($image->ext === 'swf' || $image->ext === 'svg'){ $tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height')); } - else { + else{ $tsize = get_thumbnail_size($image->width, $image->height); } - return " -

    - - - $h_tip - - -
    - "; + return '
    \n"; } diff --git a/themes/lite/user.theme.php b/themes/lite/user.theme.php index 7f6d6440..9aa476ab 100644 --- a/themes/lite/user.theme.php +++ b/themes/lite/user.theme.php @@ -95,47 +95,5 @@ class CustomUserPageTheme extends UserPageTheme { $page->disable_left(); parent::display_user_page($duser, $stats); } - - protected function build_options($duser) { - global $database; - global $config; - global $user; - - $html = ""; - $html .= " -
    - - - - - - - -
    Change Password
    Password
    Repeat Password
    -
    -

    - - - - - -
    Change Email
    Address
    -

    - "; - - if($user->is_admin()) { - $i_user_id = int_escape($duser->id); - $h_is_admin = $duser->is_admin() ? " checked" : ""; - $html .= " -

    ".make_form(make_link("user_admin/set_more"))." - - Admin: - - - "; - } - - return $html; - } } ?> diff --git a/themes/lite/view.theme.php b/themes/lite/view.theme.php index 1d075041..f54d45b1 100644 --- a/themes/lite/view.theme.php +++ b/themes/lite/view.theme.php @@ -13,7 +13,7 @@ class CustomViewImageTheme extends ViewImageTheme { $page->add_html_header("id}"))."\">"); $page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0)); $page->add_block(new Block("Statistics", $this->build_stats($image), "left", 15)); - $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 10)); + $page->add_block(new Block(null, $this->build_info($image, $editor_parts), "main", 11)); $page->add_block(new Block(null, $this->build_pin($image), "main", 11)); }