Merge branch 'master' of github.com:shish/shimmie2

This commit is contained in:
Shish 2012-03-31 12:38:44 +01:00
commit 567755a185
49 changed files with 348 additions and 491 deletions

5
.gitignore vendored
View File

@ -1,12 +1,7 @@
.svn
backup backup
config.php
data data
images images
imgdump-*.zip
thumbs thumbs
sql.log
shimmie.log
!lib/images !lib/images
ext/admin ext/admin
ext/amazon_s3 ext/amazon_s3

View File

@ -42,6 +42,8 @@ Installation
Upgrade from 2.3.X 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 The database connection setting in config.php has changed; now using
PDO DSN format rather than ADODB URI: 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 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 site, then those customisations belong to you, and you can do what you want
with them. with them.

View File

@ -43,7 +43,7 @@ class AdminPage extends Extension {
global $page, $user; global $page, $user;
if($event->page_matches("admin")) { if($event->page_matches("admin")) {
if(!$user->is_admin()) { if(!$user->can("manage_admintools")) {
$this->theme->display_permission_denied(); $this->theme->display_permission_denied();
} }
else { else {
@ -76,7 +76,7 @@ class AdminPage extends Extension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) { public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("manage_admintools")) {
$event->add_link("Board Admin", make_link("admin")); $event->add_link("Board Admin", make_link("admin"));
} }
} }
@ -90,7 +90,7 @@ class AdminPage extends Extension {
public function onPostListBuilding(PostListBuildingEvent $event) { public function onPostListBuilding(PostListBuildingEvent $event) {
global $user; 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)); $this->theme->display_dbq(implode(" ", $event->search_terms));
} }
} }
@ -167,7 +167,7 @@ class AdminPage extends Extension {
$zip = new ZipArchive; $zip = new ZipArchive;
$images = $database->get_all("SELECT * FROM images"); $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){ if($zip->open($filename, 1 ? ZIPARCHIVE::OVERWRITE:ZIPARCHIVE::CREATE) === TRUE){
foreach($images as $img){ foreach($images as $img){

View File

@ -26,7 +26,7 @@ class Downtime extends Extension {
global $config, $page, $user; global $config, $page, $user;
if($config->get_bool("downtime")) { 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"); $msg = $config->get_string("downtime_message");
$this->theme->display_message($msg); $this->theme->display_message($msg);
exit; exit;

View File

@ -29,7 +29,7 @@ class Featured extends Extension {
global $config, $page, $user; global $config, $page, $user;
if($event->page_matches("featured_image")) { if($event->page_matches("featured_image")) {
if($event->get_arg(0) == "set" && $user->check_auth_token()) { 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']); $id = int_escape($_POST['image_id']);
if($id > 0) { if($id > 0) {
$config->set_int("featured_id", $id); $config->set_int("featured_id", $id);
@ -77,7 +77,7 @@ class Featured extends Extension {
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) { public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("edit_feature")) {
$event->add_part($this->theme->get_buttons_html($event->image->id)); $event->add_part($this->theme->get_buttons_html($event->image->id));
} }
} }

View File

@ -56,7 +56,7 @@ class ImageBan extends Extension {
global $config, $database, $page, $user; global $config, $database, $page, $user;
if($event->page_matches("image_hash_ban")) { if($event->page_matches("image_hash_ban")) {
if($user->is_admin()) { if($user->can("ban_image")) {
if($event->get_arg(0) == "dnp") { if($event->get_arg(0) == "dnp") {
$image = Image::by_id(int_escape($event->get_arg(1))); $image = Image::by_id(int_escape($event->get_arg(1)));
if($image) { if($image) {
@ -105,7 +105,7 @@ class ImageBan extends Extension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) { public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("ban_image")) {
$event->add_link("Image Bans", make_link("image_hash_ban/list/1")); $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) { public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("ban_image")) {
$event->add_part($this->theme->get_buttons_html($event->image)); $event->add_part($this->theme->get_buttons_html($event->image));
} }
} }

View File

@ -26,24 +26,19 @@ class ImageBanTheme extends Themelet {
foreach($bans as $ban) { foreach($bans as $ban) {
$h_bans .= " $h_bans .= "
<tr> <tr>
<td width='30%'>{$ban['hash']}</td> ".make_form(make_link("image_hash_ban/remove"))."
<td>{$ban['reason']}</td> <td width='30%'>{$ban['hash']}</td>
<td width='10%'> <td>{$ban['reason']}</td>
".make_form(make_link("image_hash_ban/remove"))." <td width='10%'>
<input type='hidden' name='hash' value='{$ban['hash']}'> <input type='hidden' name='hash' value='{$ban['hash']}'>
<input type='submit' value='Remove'> <input type='submit' value='Remove'>
</form> </td>
</td> </form>
</tr> </tr>
"; ";
} }
$html = " $html = "
<script type='text/javascript'> <table id='image_bans' class='zebra sortable'>
$(document).ready(function() {
$(\"#image_bans\").tablesorter();
});
</script>
<table id='image_bans' class='zebra'>
<thead> <thead>
<th>Hash</th><th>Reason</th><th>Action</th> <th>Hash</th><th>Reason</th><th>Action</th>
<tr> <tr>

View File

@ -49,7 +49,7 @@ class IPBan extends Extension {
public function onPageRequest(PageRequestEvent $event) { public function onPageRequest(PageRequestEvent $event) {
if($event->page_matches("ip_ban")) { if($event->page_matches("ip_ban")) {
global $config, $database, $page, $user; 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($event->get_arg(0) == "add" && $user->check_auth_token()) {
if(isset($_POST['ip']) && isset($_POST['reason']) && isset($_POST['end'])) { if(isset($_POST['ip']) && isset($_POST['reason']) && isset($_POST['end'])) {
if(empty($_POST['end'])) $end = null; if(empty($_POST['end'])) $end = null;
@ -80,7 +80,7 @@ class IPBan extends Extension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) { public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("ban_ip")) {
$event->add_link("IP Bans", make_link("ip_ban/list")); $event->add_link("IP Bans", make_link("ip_ban/list"));
} }
} }

View File

@ -44,7 +44,7 @@ class LogDatabase extends Extension {
public function onPageRequest(PageRequestEvent $event) { public function onPageRequest(PageRequestEvent $event) {
global $database, $user; global $database, $user;
if($event->page_matches("log/view")) { if($event->page_matches("log/view")) {
if($user->is_admin()) { if($user->can("view_eventlog")) {
$wheres = array(); $wheres = array();
$args = array(); $args = array();
$page_num = int_escape($event->get_arg(0)); $page_num = int_escape($event->get_arg(0));
@ -111,7 +111,7 @@ class LogDatabase extends Extension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) { public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("view_eventlog")) {
$event->add_link("Event Log", make_link("log/view")); $event->add_link("Event Log", make_link("log/view"));
} }
} }

View File

@ -20,7 +20,7 @@ class LogDatabaseTheme extends Themelet {
</style> </style>
<table class='zebra'> <table class='zebra'>
<thead> <thead>
<tr><th>Time</th><th>Module</th><th>User</th><th>Message</th></tr> <tr><th>Time</th><th>Module</th><th>User</th><th colspan='2'>Message</th></tr>
<form action='".make_link("log/view")."' method='GET'> <form action='".make_link("log/view")."' method='GET'>
<tr class='sizedinputs'> <tr class='sizedinputs'>
<td><input type='text' name='time' value='".$this->heie("time")."'></td> <td><input type='text' name='time' value='".$this->heie("time")."'></td>
@ -34,8 +34,8 @@ class LogDatabaseTheme extends Themelet {
<option value='".SCORE_LOG_ERROR."'>Error</option> <option value='".SCORE_LOG_ERROR."'>Error</option>
<option value='".SCORE_LOG_CRITICAL."'>Critical</option> <option value='".SCORE_LOG_CRITICAL."'>Critical</option>
</select> </select>
<input type='submit' value='Search' style='width: 20%'>
</td> </td>
<td><input type='submit' value='Search'></td>
</tr> </tr>
</form> </form>
</thead> </thead>
@ -56,7 +56,7 @@ class LogDatabaseTheme extends Themelet {
"<a href='".make_link("user/".url_escape($event['username']))."'>".html_escape($event['username'])."</a>". "<a href='".make_link("user/".url_escape($event['username']))."'>".html_escape($event['username'])."</a>".
"</span></td>"; "</span></td>";
} }
$table .= "<td>".$this->scan_entities(html_escape($event['message']))."</td>"; $table .= "<td colspan='2'>".$this->scan_entities(html_escape($event['message']))."</td>";
$table .= "</tr>\n"; $table .= "</tr>\n";
} }
$table .= "</tbody></table>"; $table .= "</tbody></table>";

View File

@ -13,15 +13,17 @@ class LogNet extends Extension {
public function onLog(LogEvent $event) { public function onLog(LogEvent $event) {
global $user; global $user;
if($this->count < 10 && $event->priority > 10) { if($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");
$this->count++; $this->count++;
} if($this->count < 10) {
else { // TODO: colour based on event->priority
system("echo 'suppressing flood, check the web log' | nc -q 0 localhost 5000"); $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");
}
} }
} }
} }

View File

@ -38,7 +38,7 @@ class NumericScore extends Extension {
public function onUserPageBuilding(UserPageBuildingEvent $event) { public function onUserPageBuilding(UserPageBuildingEvent $event) {
global $page, $user; global $page, $user;
if($user->is_admin()) { if($user->can("edit_other_votes")) {
$html = $this->theme->get_nuller_html($event->display_user); $html = $this->theme->get_nuller_html($event->display_user);
$page->add_block(new Block("Votes", $html, "main", 60)); $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($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']); $image_id = int_escape($_POST['image_id']);
$database->execute( $database->execute(
"DELETE FROM numeric_score_votes WHERE image_id=?", "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($event->page_matches("numeric_score/remove_votes_by") && $user->check_auth_token()) {
if($user->is_admin()) { if($user->can("edit_other_vote")) {
$user_id = int_escape($_POST['user_id']); $this->delete_votes_by(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));
$page->set_mode("redirect"); $page->set_mode("redirect");
$page->set_redirect(make_link()); $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)); $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 deletion
// FIXME: on user vote nuke // FIXME: on user vote nuke
@ -274,7 +291,12 @@ class NumericScore extends Extension {
array("imageid" => $image_id, "userid" => $user_id, "score" => $score)); array("imageid" => $image_id, "userid" => $user_id, "score" => $score));
} }
$database->Execute( $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)); array("imageid" => $image_id, "id" => $image_id));
} }
} }

View File

@ -30,7 +30,7 @@ class NumericScoreTheme extends Themelet {
<input type='submit' value='Vote Down'> <input type='submit' value='Vote Down'>
</form> </form>
"; ";
if($user->is_admin()) { if($user->can("edit_other_vote")) {
$html .= " $html .= "
<form action='".make_link("numeric_score/remove_votes_on")."' method='POST'> <form action='".make_link("numeric_score/remove_votes_on")."' method='POST'>
".$user->get_auth_html()." ".$user->get_auth_html()."

View File

@ -24,12 +24,10 @@ class Oekaki extends Extension {
if(isset($_FILES["picture"])) { if(isset($_FILES["picture"])) {
header('Content-type: text/plain'); header('Content-type: text/plain');
$uploaddir = './data/oekaki_unclaimed/';
if(!file_exists($uploaddir)) mkdir($uploaddir, 0755, true);
$file = $_FILES['picture']['name']; $file = $_FILES['picture']['name'];
$ext = (strpos($file, '.') === FALSE) ? '' : substr($file, strrpos($file, '.')); $ext = (strpos($file, '.') === FALSE) ? '' : substr($file, strrpos($file, '.'));
$uploadname = $_SERVER['REMOTE_ADDR'] . "." . time(); $uploadname = $_SERVER['REMOTE_ADDR'] . "." . time();
$uploadfile = $uploaddir . $uploadname; $uploadfile = data_path('oekaki_unclaimed/'.$uploadname);
log_info("oekaki", "Uploading file [$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: move .chi to data/oekaki/$ha/$hash mirroring images and thumbs
// FIXME: .chi viewer? // FIXME: .chi viewer?
// FIXME: clean out old unclaimed images? // 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) { foreach(glob($pattern) as $tmpname) {
assert(file_exists($tmpname)); assert(file_exists($tmpname));

View File

@ -90,7 +90,7 @@ class PrivMsg extends Extension {
global $page, $user; global $page, $user;
$duser = $event->display_user; $duser = $event->display_user;
if(!$user->is_anonymous() && !$duser->is_anonymous()) { 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)); $this->theme->display_pms($page, $this->get_pms($duser));
} }
if($user->id != $duser->id) { if($user->id != $duser->id) {
@ -110,7 +110,7 @@ class PrivMsg extends Extension {
if(is_null($pm)) { if(is_null($pm)) {
$this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); $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"])); $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->execute("UPDATE private_message SET is_read='Y' WHERE id = :id", array("id" => $pm_id));
$database->cache->delete("pm-count-{$user->id}"); $database->cache->delete("pm-count-{$user->id}");
@ -127,7 +127,7 @@ class PrivMsg extends Extension {
if(is_null($pm)) { if(is_null($pm)) {
$this->theme->display_error(404, "No such PM", "There is no PM #$pm_id"); $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->execute("DELETE FROM private_message WHERE id = :id", array("id" => $pm_id));
$database->cache->delete("pm-count-{$user->id}"); $database->cache->delete("pm-count-{$user->id}");
log_info("pm", "Deleted PM #$pm_id"); log_info("pm", "Deleted PM #$pm_id");

View File

@ -265,7 +265,6 @@ class ResizeImage extends Extension {
$new_hash = md5_file($tmp_filename); $new_hash = md5_file($tmp_filename);
$new_size = filesize($tmp_filename); $new_size = filesize($tmp_filename);
$target = warehouse_path("images", $new_hash); $target = warehouse_path("images", $new_hash);
if(!file_exists(dirname($target))) mkdir(dirname($target), 0755, true);
if(!@copy($tmp_filename, $target)) { if(!@copy($tmp_filename, $target)) {
throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)"); throw new ImageResizeException("Failed to copy new image file from temporary location ({$tmp_filename}) to archive ($target)");
} }

View File

@ -97,29 +97,50 @@ class ShimmieApi extends Extension {
if($event->page_matches("api/shimmie/get_user")) { if($event->page_matches("api/shimmie/get_user")) {
$query = $user->id; $query = $user->id;
$type = "id";
if($event->count_args() == 1) { if($event->count_args() == 1) {
$query = $event->get_arg(0); $query = $event->get_arg(0);
} }
if(isset($_GET['name'])) { elseif(isset($_GET['id'])) {
$query = $_GET['name'];
}
if(isset($_GET['id'])) {
$query = $_GET['id']; $query = $_GET['id'];
} }
elseif(isset($_GET['name'])) {
$query = $_GET['name'];
$type = "name";
}
$all = $database->get_row( $all = $database->get_row(
"SELECT id,name,joindate,class FROM users WHERE name=? OR id=?", "SELECT id,name,joindate,class FROM users WHERE ".$type."=?",
array($_GET['name'], int_escape($_GET['id']))); array($query));
//FIXME?: For some weird reason, get_all seems to return twice. Unsetting second value to make things look nice.. if(!empty($all)){
// - it returns data as eg array(0=>1234, 'id'=>1234, 1=>'bob', 'name'=>bob, ...); //FIXME?: For some weird reason, get_all seems to return twice. Unsetting second value to make things look nice..
for($i=0; $i<4; $i++) unset($all[$i]); // - it returns data as eg array(0=>1234, 'id'=>1234, 1=>'bob', 'name'=>bob, ...);
$all['uploadcount'] = Image::count_images(array("user_id=".$all['id'])); for($i=0; $i<4; $i++) unset($all[$i]);
$all['uploadperday'] = sprintf("%.1f", ($all['uploadcount'] / (((time() - strtotime($all['joindate'])) / 86400) + 1))); $all['uploadcount'] = Image::count_images(array("user_id=".$all['id']));
$all['commentcount'] = $database->get_one( $all['commentcount'] = $database->get_one(
"SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id", "SELECT COUNT(*) AS count FROM comments WHERE owner_id=:owner_id",
array("owner_id"=>$all['id'])); array("owner_id"=>$all['id']));
$all['commentperday'] = sprintf("%.1f", ($all['commentcount'] / (((time() - strtotime($all['joindate'])) / 86400) + 1)));
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)); $page->set_data(json_encode($all));
} }
} }

View File

@ -35,7 +35,7 @@ class Tag_History extends Extension {
} }
} }
else if($event->page_matches("tag_history/bulk_revert")) { 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(); $this->process_bulk_revert_request();
} }
} }
@ -78,7 +78,7 @@ class Tag_History extends Extension {
public function onUserBlockBuilding(UserBlockBuildingEvent $event) { public function onUserBlockBuilding(UserBlockBuildingEvent $event) {
global $user; global $user;
if($user->is_admin()) { if($user->can("bulk_edit_image_tag")) {
$event->add_link("Tag Changes", make_link("tag_history/all/1")); $event->add_link("Tag Changes", make_link("tag_history/all/1"));
} }
} }

View File

@ -27,6 +27,14 @@ class Tag_HistoryTheme extends Themelet {
$setter = "<a href='".make_link("user/".url_escape($name))."'>".html_escape($name)."</a>$h_ip"; $setter = "<a href='".make_link("user/".url_escape($name))."'>".html_escape($name)."</a>$h_ip";
$selected = ($n == 2) ? " checked" : ""; $selected = ($n == 2) ? " checked" : "";
$current_tags = Tag::explode($current_tags);
$taglinks = array();
foreach($current_tags as $tag){
$taglinks[] = "<a href='".make_link("post/list/".$tag."/1")."'>".$tag."</a>";
}
$current_tags = Tag::implode($taglinks);
$history_list .= " $history_list .= "
<li> <li>
<input type='radio' name='revert' id='$current_id' value='$current_id'$selected> <input type='radio' name='revert' id='$current_id' value='$current_id'$selected>

View File

@ -91,7 +91,7 @@ class Update extends Extension {
$commit = $matches[2]; $commit = $matches[2];
mkdir("./backup"); mkdir("./backup");
$html .= "<br>backup folder created!"; $html .= "<br>backup folder created!";
$d_dir = "data/cache"; $d_dir = data_path("cache");
//This should empty the /data/cache/ folder. //This should empty the /data/cache/ folder.
if (is_dir($d_dir)) { if (is_dir($d_dir)) {
$objects = scandir($d_dir); $objects = scandir($d_dir);
@ -103,7 +103,7 @@ class Update extends Extension {
reset($objects); reset($objects);
$html .= "<br>data folder emptied!"; $html .= "<br>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"); $folders = array("./core", "./lib", "./themes", "./.htaccess", "./doxygen.conf", "./index.php", "./install.php", "./ext", "./contrib");
foreach($folders as $folder){ foreach($folders as $folder){
//TODO: Check MD5 of each file, don't rename if same. //TODO: Check MD5 of each file, don't rename if same.

View File

@ -34,6 +34,7 @@ class BaseThemelet {
$h_view_link = make_link('post/view/'.$i_id, $query); $h_view_link = make_link('post/view/'.$i_id, $query);
$h_thumb_link = $image->get_thumb_link(); $h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip()); $h_tip = html_escape($image->get_tooltip());
$h_tags = strtolower($image->get_tag_list());
$base = get_base_href(); $base = get_base_href();
// If file is flash or svg then sets thumbnail to max size. // 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); $tsize = get_thumbnail_size($image->width, $image->height);
} }
return '<a href="'.$h_view_link.'" class="thumb">'. return '<a href="'.$h_view_link.'" class="thumb" data-tags="'.$h_tags.'">'.
'<img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" class="lazy" data-original="'.$h_thumb_link.'" src="'.$base.'/lib/static/grey.gif">'. '<img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" class="lazy" data-original="'.$h_thumb_link.'" src="'.$base.'/lib/static/grey.gif">'.
'<noscript><img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" src="'.$h_thumb_link.'"></noscript>'. '<noscript><img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" src="'.$h_thumb_link.'"></noscript>'.
"</a>\n"; "</a>\n";

View File

@ -273,7 +273,7 @@ class Database {
/** /**
* Create a new database object using connection info * 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() { public function Database() {
# FIXME: detect ADODB URI, automatically translate PDO DSN # FIXME: detect ADODB URI, automatically translate PDO DSN

View File

@ -2,7 +2,7 @@
/** /**
* These are the default configuration options for Shimmie. * 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! * Do NOT change them in this file. These are the defaults only!
* *

View File

@ -1080,7 +1080,6 @@ class Tag {
*/ */
function move_upload_to_archive(DataUploadEvent $event) { function move_upload_to_archive(DataUploadEvent $event) {
$target = warehouse_path("images", $event->hash); $target = warehouse_path("images", $event->hash);
if(!file_exists(dirname($target))) mkdir(dirname($target), 0755, true);
if(!@copy($event->tmpname, $target)) { if(!@copy($event->tmpname, $target)) {
$errors = error_get_last(); // note: requires php 5.2 $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']}"); throw new UploadException("Failed to copy file from uploads ({$event->tmpname}) to archive ($target): {$errors['type']} / {$errors['message']}");

View File

@ -245,222 +245,42 @@ class Page {
# 404/static handler will map these to themes/foo/bar.ico or lib/static/bar.ico # 404/static handler will map these to themes/foo/bar.ico or lib/static/bar.ico
$this->add_html_header("<link rel='icon' type='image/x-icon' href='$data_href/favicon.ico'>"); $this->add_html_header("<link rel='icon' type='image/x-icon' href='$data_href/favicon.ico'>");
$this->add_html_header("<link rel='apple-touch-icon' href='$data_href/apple-touch-icon.png'>"); $this->add_html_header("<link rel='apple-touch-icon' href='$data_href/apple-touch-icon.png'>");
/* Attempt to cache the CSS & JavaScript files */ $css_files = array();
if ($this->add_cached_auto_html_headers() === FALSE) { $css_latest = 0;
// caching failed, add all files to html_headers. foreach(array_merge(zglob("lib/*.css"), zglob("ext/*/style.css"), zglob("themes/$theme_name/style.css")) as $css) {
$css_files[] = $css;
foreach(glob("lib/*.css") as $css) { $css_latest = max($css_latest, filemtime($css));
$this->add_html_header('<link rel="stylesheet" href="'.mtimefile($css).'" type="text/css">');
}
$css_files = glob("ext/*/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$this->add_html_header('<link rel="stylesheet" href="'.mtimefile($css_file).'" type="text/css">');
}
}
$css_files = glob("themes/$theme_name/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$this->add_html_header('<link rel="stylesheet" href="'.mtimefile($css_file).'" type="text/css">');
}
}
foreach(glob("lib/*.js") as $js) {
$this->add_html_header('<script src="'.mtimefile($js).'" type="text/javascript"></script>');
}
$js_files = glob("ext/*/script.js");
if($js_files) {
foreach($js_files as $js_file) {
$this->add_html_header('<script src="'.mtimefile($js_file).'" type="text/javascript"></script>');
}
}
} }
} $css_cache_file = data_path("cache/style.$css_latest.css");
if(!file_exists($css_cache_file)) {
/** $css_data = "";
* Automatic caching of CSS and Javascript files foreach($css_files as $file) {
* $file_data = file_get_contents($file);
* 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.
$pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/'; $pattern = '/url[\s]*\([\s]*["\']?([^"\'\)]+)["\']?[\s]*\)/';
$replace = 'url("../../lib/${1}")'; $replace = 'url("../../'.dirname($file).'/$1")';
$contents_from_lib = preg_replace($pattern, $replace, $contents_from_lib); $file_data = preg_replace($pattern, $replace, $file_data);
} $css_data .= $file_data . "\n";
// 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.
} }
file_put_contents($css_cache_file, $css_data);
}
$this->add_html_header("<link rel='stylesheet' href='$data_href/$css_cache_file' type='text/css'>");
// compute the MD5 sum of the concatenated CSS files $js_files = array();
$md5sum = md5($data); $js_latest = 0;
foreach(array_merge(zglob("lib/*.js"), zglob("ext/*/script.js"), zglob("themes/$theme_name/script.js")) as $js) {
if(!file_exists($cache_location.$md5sum.'.css')) { $js_files[] = $js;
// remove any old cached CSS files. $js_latest = max($js_latest, filemtime($js));
$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('<link rel="stylesheet" href="'.$data_href.'/'.$cache_location.$md5sum.'.css" type="text/css">');
} }
else { $js_cache_file = data_path("cache/script.$js_latest.js");
// Caching of CSS disabled. if(!file_exists($js_cache_file)) {
foreach(glob("lib/*.css") as $css) { $js_data = "";
$this->add_html_header('<link rel="stylesheet" href="'.$data_href.'/'.$css.'" type="text/css">'); foreach($js_files as $file) {
} $js_data .= file_get_contents($file) . "\n";
$css_files = glob("ext/*/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$this->add_html_header('<link rel="stylesheet" href="'.$data_href.'/'.$css_file.'" type="text/css">');
}
}
$css_files = glob("themes/$theme_name/style.css");
if($css_files) {
foreach($css_files as $css_file) {
$this->add_html_header('<link rel="stylesheet" href="'.$data_href.'/'.$css_file.'" type="text/css">');
}
} }
file_put_contents($js_cache_file, $js_data);
} }
$this->add_html_header("<script src='$data_href/$js_cache_file' type='text/javascript'></script>");
/* ----- 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('<script src="'.$data_href.'/'.$cache_location.$md5sum.'.js" type="text/javascript"></script>');
}
else {
// Caching of Javascript disabled.
foreach(glob("lib/*.js") as $js) {
$this->add_html_header('<script src="'.$data_href.'/'.$js.'" type="text/javascript"></script>');
}
$js_files = glob("ext/*/script.js");
if($js_files) {
foreach($js_files as $js_file) {
$this->add_html_header('<script src="'.$data_href.'/'.$js_file.'" type="text/javascript"></script>');
}
}
}
return true;
} }
} }
?> ?>

View File

@ -40,7 +40,7 @@ class UserClass {
// object = image / user / tag / setting // object = image / user / tag / setting
new UserClass("base", null, array( new UserClass("base", null, array(
"change_setting" => False, # modify web-level settings, eg the config table "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) "big_search" => False, # search for more than 3 tags at once (speed mode only)
"manage_extension_list" => False, "manage_extension_list" => False,
@ -63,8 +63,14 @@ new UserClass("base", null, array(
"edit_image_source" => False, "edit_image_source" => False,
"edit_image_owner" => False, "edit_image_owner" => False,
"edit_image_lock" => False, "edit_image_lock" => False,
"bulk_edit_image_tag" => False,
"delete_image" => False, "delete_image" => False,
"ban_image" => False,
"view_eventlog" => False,
"ignore_downtime" => False,
"create_image_report" => False, "create_image_report" => False,
"view_image_report" => False, # deal with reported images "view_image_report" => False, # deal with reported images
@ -73,6 +79,13 @@ new UserClass("base", null, array(
"manage_blocks" => False, "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) "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, "delete_user" => True,
"create_image" => True, "create_image" => True,
"delete_image" => True, "delete_image" => True,
"ban_image" => True,
"create_comment" => True, "create_comment" => True,
"delete_comment" => True, "delete_comment" => True,
"replace_image" => True, "replace_image" => True,
@ -108,12 +122,20 @@ new UserClass("admin", "base", array(
"edit_image_tag" => True, "edit_image_tag" => True,
"edit_image_source" => True, "edit_image_source" => True,
"edit_image_owner" => True, "edit_image_owner" => True,
"bulk_edit_image_tag" => True,
"mass_tag_edit" => True, "mass_tag_edit" => True,
"create_image_report" => True, "create_image_report" => True,
"view_image_report" => True, "view_image_report" => True,
"edit_wiki_page" => True, "edit_wiki_page" => True,
"delete_wiki_page" => True, "delete_wiki_page" => True,
"view_eventlog" => True,
"manage_blocks" => 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, "protected" => True,
)); ));

View File

@ -361,6 +361,11 @@ function mtimefile($file) {
return "$data_href/$file?$mtime"; 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; 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) { function transload($url, $mfile) {
global $config; global $config;
@ -879,9 +890,10 @@ $_event_listeners = array();
*/ */
function add_event_listener(Extension $extension, $pos=50, $events=array()) { function add_event_listener(Extension $extension, $pos=50, $events=array()) {
global $_event_listeners; global $_event_listeners;
$pos *= 100;
foreach($events as $event) { foreach($events as $event) {
while(isset($_event_listeners[$event][$pos])) { while(isset($_event_listeners[$event][$pos])) {
$pos++; $pos += 1;
} }
$_event_listeners[$event][$pos] = $extension; $_event_listeners[$event][$pos] = $extension;
} }
@ -1024,8 +1036,8 @@ function _load_extensions() {
ctx_log_start("Loading extensions"); ctx_log_start("Loading extensions");
if(COMPILE_ELS && file_exists("data/event_listeners.php")) { if(COMPILE_ELS && file_exists("data/cache/event_listeners.php")) {
require_once("data/event_listeners.php"); require_once("data/cache/event_listeners.php");
} }
else { else {
foreach(get_declared_classes() as $class) { foreach(get_declared_classes() as $class) {
@ -1069,7 +1081,7 @@ function _load_extensions() {
$p .= ");\n"; $p .= ");\n";
$p .= "?".">"; $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"]); $_cache_hash = md5($_SERVER["QUERY_STRING"]);
$ab = substr($_cache_hash, 0, 2); $ab = substr($_cache_hash, 0, 2);
$cd = substr($_cache_hash, 2, 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)) { if(file_exists($_cache_filename) && (filemtime($_cache_filename) > time() - 3600)) {
$gmdate_mod = gmdate('D, d M Y H:i:s', filemtime($_cache_filename)) . ' GMT'; $gmdate_mod = gmdate('D, d M Y H:i:s', filemtime($_cache_filename)) . ' GMT';

View File

@ -640,11 +640,11 @@ RECURSIVE = YES
# excluded from the INPUT source files. This way you can easily exclude a # 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. # subdirectory from a directory tree whose root is specified with the INPUT tag.
EXCLUDE = config.php \ EXCLUDE = install.php \
install.php \
phpinfo.php \ phpinfo.php \
contrib/simpletest/simpletest \ contrib/simpletest/simpletest \
lib \ lib \
data \
images \ images \
thumbs \ thumbs \
.git \ .git \

7
ext/alias_editor/main.php Executable file → Normal file
View File

@ -122,7 +122,7 @@ class AliasEditor extends Extension {
private function get_alias_csv(Database $database) { private function get_alias_csv(Database $database) {
$csv = ""; $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) { foreach($aliases as $old => $new) {
$csv .= "$old,$new\n"; $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;}
} }
?> ?>

View File

@ -33,7 +33,7 @@ class BBCode extends FormatterExtension {
) as $el) { ) as $el) {
$text = preg_replace("!\[$el\](.*?)\[/$el\]!s", "<$el>$1</$el>", $text); $text = preg_replace("!\[$el\](.*?)\[/$el\]!s", "<$el>$1</$el>", $text);
} }
$text = preg_replace('!&gt;&gt;([^\d].+)!s', '<blockquote><small>$1</small></blockquote>', $text); $text = preg_replace('!&gt;&gt;([^\d].+)!', '<blockquote><small>$1</small></blockquote>', $text);
$text = preg_replace('!&gt;&gt;(\d+)(#c?\d+)?!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('post/view/$1$2').'">&gt;&gt;$1$2</a>', $text); $text = preg_replace('!&gt;&gt;(\d+)(#c?\d+)?!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('post/view/$1$2').'">&gt;&gt;$1$2</a>', $text);
$text = preg_replace('!\[url=site://(.*?)(#c\d+)?\](.*?)\[/url\]!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('$1$2').'">$3</a>', $text); $text = preg_replace('!\[url=site://(.*?)(#c\d+)?\](.*?)\[/url\]!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('$1$2').'">$3</a>', $text);
$text = preg_replace('!\[url\]site://(.*?)(#c\d+)?\[/url\]!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('$1$2').'">$1$2</a>', $text); $text = preg_replace('!\[url\]site://(.*?)(#c\d+)?\[/url\]!s', '<a class="shm-clink" data-clink-sel="$2" href="'.make_link('$1$2').'">$1$2</a>', $text);

View File

@ -75,6 +75,19 @@ class PixelFileHandler extends DataHandlerExtension {
return $ok; return $ok;
} }
public function onImageAdminBlockBuilding(ImageAdminBlockBuildingEvent $event) {
$event->add_part("
<form>
<select id='zoomer'>
<option value='full'>Full Size</option>
<option value='width'>Fit Width</option>
<option value='height'>Fit Height</option>
<option value='both'>Fit Both</option>
</select>
</form>
", 20);
}
// IM thumber {{{ // IM thumber {{{
private function make_thumb_convert(/*string*/ $inname, /*string*/ $outname) { private function make_thumb_convert(/*string*/ $inname, /*string*/ $outname) {

View File

@ -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});
}

View File

@ -5,7 +5,6 @@ class PixelFileHandlerTheme extends Themelet {
global $config; global $config;
$u_ilink = $image->get_image_link(); $u_ilink = $image->get_image_link();
$html = "<img alt='main image' id='main_image' src='$u_ilink'>";
if($config->get_bool("image_show_meta") && function_exists("exif_read_data")) { if($config->get_bool("image_show_meta") && function_exists("exif_read_data")) {
# FIXME: only read from jpegs? # FIXME: only read from jpegs?
$exif = @exif_read_data($image->get_image_filename(), 0, true); $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);" : ""; $html = "<img alt='main image' id='main_image' src='$u_ilink' data-width='{$image->width}' data-height='{$image->height}'>";
$zoom = "<script type=\"text/javascript\"> $page->add_block(new Block("Image", $html, "main", 10));
img = document.getElementById(\"main_image\");
if(img) {
img.onclick = function() {scale(img);};
msg_div = document.createElement(\"div\");
msg_div.id = \"msg_div\";
msg_div.appendChild(document.createTextNode(\"Note: Image has been scaled to fit the screen; click to enlarge\"));
msg_div.style.display=\"none\";
img.parentNode.insertBefore(msg_div, img);
orig_width = $image->width;
$zoom_default
}
function scale(img) {
if(orig_width >= img.parentNode.clientWidth * 0.9) {
if(img.style.width != \"90%\") {
img.style.width = \"90%\";
msg_div.style.display = \"block\";
}
else {
img.style.width = orig_width + 'px';
msg_div.style.display = \"none\";
}
}
}
</script>";
$page->add_block(new Block("Image", $html.$zoom, "main", 10));
} }
} }
?> ?>

View File

@ -298,11 +298,6 @@ class ImageIO extends Extension {
if(strlen(trim($image->source)) == 0) { if(strlen(trim($image->source)) == 0) {
$image->source = null; $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 * Check for an existing image
@ -431,11 +426,6 @@ class ImageIO extends Extension {
if(strlen(trim($image->source)) == 0) { if(strlen(trim($image->source)) == 0) {
$image->source = $existing->get_source(); $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 This step could be optional, ie: perhaps move the image somewhere

30
ext/index/script.js Normal file
View File

@ -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);
}
}

View File

@ -166,12 +166,6 @@ class Setup extends Extension {
$config->set_default_string("theme", "default"); $config->set_default_string("theme", "default");
$config->set_default_bool("word_wrap", true); $config->set_default_bool("word_wrap", true);
$config->set_default_bool("comment_captcha", false); $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) { public function onPageRequest(PageRequestEvent $event) {
@ -279,19 +273,6 @@ class Setup extends Extension {
$sb->add_text_option("api_recaptcha_privkey", "<br>Private key: "); $sb->add_text_option("api_recaptcha_privkey", "<br>Private key: ");
$sb->add_text_option("api_recaptcha_pubkey", "<br>Public key: "); $sb->add_text_option("api_recaptcha_pubkey", "<br>Public key: ");
$event->panel->add_block($sb); $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("<br><i>This location needs to be writeable by the webserver.</i>");
$sb->add_bool_option("autocache_css", "Automatic caching of CSS: ");
$sb->add_bool_option("autocache_js", "<br>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", "<br>Minimize CSS files: ");
//$sb->add_bool_option("autocache_min_js", "<br>Minimize JS files: ");
$event->panel->add_block($sb);
} }
public function onConfigSave(ConfigSaveEvent $event) { public function onConfigSave(ConfigSaveEvent $event) {

View File

@ -187,6 +187,8 @@ class TagEdit extends Extension {
$search_set = Tag::explode($search); $search_set = Tag::explode($search);
$replace_set = Tag::explode($replace); $replace_set = Tag::explode($replace);
log_info("tag_edit", "Mass editing tags: '$search' -> '$replace'");
$last_id = -1; $last_id = -1;
while(true) { while(true) {
// make sure we don't look at the same images twice. // make sure we don't look at the same images twice.

View File

@ -45,11 +45,23 @@ class TagEditTest extends ShimmieWebTestCase {
function testMassEdit() { function testMassEdit() {
$this->log_in_as_admin(); $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->get_page("admin");
$this->assert_text("Mass Tag Edit"); // just test it exists $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();
} }
} }
?> ?>

View File

@ -188,7 +188,7 @@ class TagList extends Extension {
$starts_with = $this->get_starts_with(); $starts_with = $this->get_starts_with();
// check if we have a cached version // 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);} if(file_exists($cache_key)) {return file_get_contents($cache_key);}
// SHIT: PDO/pgsql has problems using the same named param twice -_-;; // 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(); $starts_with = $this->get_starts_with();
// check if we have a cached version // 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);} if(file_exists($cache_key)) {return file_get_contents($cache_key);}
$tag_data = $database->get_all($database->engine->scoreql_to_sql(" $tag_data = $database->get_all($database->engine->scoreql_to_sql("
@ -261,7 +261,7 @@ class TagList extends Extension {
$tags_min = $this->get_tags_min(); $tags_min = $this->get_tags_min();
// check if we have a cached version // 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);} if(file_exists($cache_key)) {return file_get_contents($cache_key);}
$tag_data = $database->get_all(" $tag_data = $database->get_all("

View File

@ -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 UserCreationException extends SCoreException {}
class UserPage extends Extension { class UserPage extends Extension {
@ -519,6 +527,8 @@ class UserPage extends Extension {
); );
} }
send_event(new UserDeletionEvent($_POST['id']));
$database->execute( $database->execute(
"DELETE FROM users WHERE id = :id", "DELETE FROM users WHERE id = :id",
array("id" => $_POST['id']) array("id" => $_POST['id'])

View File

@ -43,11 +43,11 @@
* Each of these can be imported at the start of a function with eg "global $page, $user;" * 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"); header("Location: install.php");
exit; exit;
} }
require_once "config.php"; require_once "data/config/shimmie.conf.php";
require_once "core/default_config.inc.php"; require_once "core/default_config.inc.php";
require_once "core/util.inc.php"; require_once "core/util.inc.php";
require_once "lib/context.php"; require_once "lib/context.php";

View File

@ -64,13 +64,13 @@ require_once __SHIMMIE_ROOT__."core/database.class.php";
* This file lets anyone destroy the database -- disable it * This file lets anyone destroy the database -- disable it
* as soon as the admin is done installing for the first time * 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(); session_start();
echo '<div id="iblock">'; echo '<div id="iblock">';
echo '<h1>Shimmie Repair Console</h1>'; echo '<h1>Shimmie Repair Console</h1>';
// Load the config // 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. require_once __SHIMMIE_ROOT__."core/default_config.inc.php"; // Defaults for the rest.
if( if(
@ -120,7 +120,7 @@ if(is_readable("config.php")) {
else { else {
echo " echo "
<h3>Login</h3> <h3>Login</h3>
<p>Enter the database DSN exactly as in config.php (ie, as originally installed) to access advanced recovery tools:</p> <p>Enter the database DSN exactly as in shimmie.conf.php (ie, as originally installed) to access advanced recovery tools:</p>
<form action='install.php' method='POST'> <form action='install.php' method='POST'>
<center> <center>
@ -403,14 +403,15 @@ function write_config() { // {{{
"define('DATABASE_DSN', '".DATABASE_DSN."');\n" . "define('DATABASE_DSN', '".DATABASE_DSN."');\n" .
'?' . '>'; '?' . '>';
if(is_writable("./") && file_put_contents("config.php", $file_content)) { if(!file_exists("data/config")) {
assert(file_exists("config.php")); mkdir("data/config", 0755, true);
} }
else {
if(!file_put_contents("data/config/shimmie.conf.php", $file_content)) {
$h_file_content = htmlentities($file_content); $h_file_content = htmlentities($file_content);
print <<<EOD print <<<EOD
The web server isn't allowed to write to the config file; please copy The web server isn't allowed to write to the config file; please copy
the text below, save it as 'config.php', and upload it into the shimmie the text below, save it as 'data/config/shimmie.conf.php', and upload it into the shimmie
folder manually. Make sure that when you save it, there is no whitespace folder manually. Make sure that when you save it, there is no whitespace
before the "&lt;?php" or after the "?&gt;" before the "&lt;?php" or after the "?&gt;"

View File

@ -12,4 +12,4 @@
* Version: 1.7.2 * Version: 1.7.2
* *
*/ */
(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("<img />").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("<img />").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);

View File

@ -38,7 +38,7 @@ $(document).ready(function() {
}); });
try { 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) { for(var i in sidebar_hidden) {
if(sidebar_hidden[i].length > 0) { if(sidebar_hidden[i].length > 0) {
$(sidebar_hidden[i]+" .blockbody").hide(); $(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});
}) })
}); });

View File

@ -98,47 +98,5 @@ class CustomUserPageTheme extends UserPageTheme {
$page->disable_left(); $page->disable_left();
parent::display_user_page($duser, $stats); parent::display_user_page($duser, $stats);
} }
protected function build_options($duser) {
global $database;
global $config;
global $user;
$html = "";
$html .= "
<form action='".make_link("user_admin/change_pass")."' method='POST'>
<input type='hidden' name='name' value='{$duser->name}'>
<input type='hidden' name='id' value='{$duser->id}'>
<table style='width: 300px;'>
<tr><td colspan='2'>Change Password</td></tr>
<tr><td>Password</td><td><input type='password' name='pass1'></td></tr>
<tr><td>Repeat Password</td><td><input type='password' name='pass2'></td></tr>
<tr><td colspan='2'><input type='Submit' value='Change Password'></td></tr>
</table>
</form>
<p><form action='".make_link("user_admin/change_email")."' method='POST'>
<input type='hidden' name='id' value='{$duser->id}'>
<table style='width: 300px;'>
<tr><th colspan='2'>Change Email</th></tr>
<tr><td>Address</td><td><input type='text' name='address' value='".html_escape($duser->email)."'></td></tr>
<tr><td colspan='2'><input type='Submit' value='Set'></td></tr>
</table>
</form></p>
";
if($user->is_admin()) {
$i_user_id = int_escape($duser->id);
$h_is_admin = $duser->is_admin() ? " checked" : "";
$html .= "
<p>".make_form(make_link("user_admin/set_more"))."
<input type='hidden' name='id' value='$i_user_id'>
Admin: <input name='admin' type='checkbox'$h_is_admin>
<input type='submit' value='Set'>
</form>
";
}
return $html;
}
} }
?> ?>

View File

@ -70,7 +70,7 @@ a.tab:hover, a.tab:active, .tab-selected {
-moz-border-radius:4px; -moz-border-radius:4px;
-webkit-border-radius:4px; -webkit-border-radius:4px;
} }
.highlighted { .lazy{
background:none repeat scroll 0 0 #CEDFF0; background:none repeat scroll 0 0 #CEDFF0;
padding:4px; padding:4px;
border:1px solid #C3D2E0; border:1px solid #C3D2E0;

View File

@ -6,28 +6,26 @@ class Themelet extends BaseThemelet {
*/ */
public function build_thumb_html(Image $image, $query=null) { public function build_thumb_html(Image $image, $query=null) {
global $config; global $config;
$i_id = int_escape($image->id); $i_id = (int) $image->id;
$h_view_link = make_link("post/view/$i_id", $query); $h_view_link = make_link('post/view/'.$i_id, $query);
$h_thumb_link = $image->get_thumb_link(); $h_thumb_link = $image->get_thumb_link();
$h_tip = html_escape($image->get_tooltip()); $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 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')); $tsize = get_thumbnail_size($config->get_int('thumb_width'), $config->get_int('thumb_height'));
} }
else { else{
$tsize = get_thumbnail_size($image->width, $image->height); $tsize = get_thumbnail_size($image->width, $image->height);
} }
return " return '<center><div class="thumbblock">'.
<center><div class='thumbblock'> '<a href="'.$h_view_link.'" class="thumb" data-tags="'.$h_tags.'">'.
'<img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" class="lazy" data-original="'.$h_thumb_link.'" src="'.$base.'/lib/static/grey.gif">'.
<a href='$h_view_link' style='position: relative; display: block; height: {$tsize[1]}px; width: {$tsize[0]}px;'> '<noscript><img id="thumb_'.$i_id.'" title="'.$h_tip.'" alt="'.$h_tip.'" height="'.$tsize[1].'" width="'.$tsize[0].'" src="'.$h_thumb_link.'"></noscript>'.
<img id='thumb_$i_id' title='$h_tip' alt='$h_tip' class='highlighted' style='height: {$tsize[1]}px; width: {$tsize[0]}px;' src='$h_thumb_link'> "</a></div></center>\n";
</a>
</div></center>
";
} }

View File

@ -95,47 +95,5 @@ class CustomUserPageTheme extends UserPageTheme {
$page->disable_left(); $page->disable_left();
parent::display_user_page($duser, $stats); parent::display_user_page($duser, $stats);
} }
protected function build_options($duser) {
global $database;
global $config;
global $user;
$html = "";
$html .= "
<form action='".make_link("user_admin/change_pass")."' method='POST'>
<input type='hidden' name='name' value='{$duser->name}'>
<input type='hidden' name='id' value='{$duser->id}'>
<table style='width: 300px;'>
<tr><th colspan='2'>Change Password</th></tr>
<tr><td>Password</td><td><input type='password' name='pass1'></td></tr>
<tr><td>Repeat Password</td><td><input type='password' name='pass2'></td></tr>
<tr><td colspan='2'><input type='Submit' value='Change Password'></td></tr>
</table>
</form>
<p><form action='".make_link("user_admin/change_email")."' method='POST'>
<input type='hidden' name='id' value='{$duser->id}'>
<table style='width: 300px;'>
<tr><th colspan='2'>Change Email</th></tr>
<tr><td>Address</td><td><input type='text' name='address' value='".html_escape($duser->email)."'></td></tr>
<tr><td colspan='2'><input type='Submit' value='Set'></td></tr>
</table>
</form></p>
";
if($user->is_admin()) {
$i_user_id = int_escape($duser->id);
$h_is_admin = $duser->is_admin() ? " checked" : "";
$html .= "
<p>".make_form(make_link("user_admin/set_more"))."
<input type='hidden' name='id' value='$i_user_id'>
Admin: <input name='admin' type='checkbox'$h_is_admin>
<input type='submit' value='Set'>
</form>
";
}
return $html;
}
} }
?> ?>

View File

@ -13,7 +13,7 @@ class CustomViewImageTheme extends ViewImageTheme {
$page->add_html_header("<meta property=\"og:url\" content=\"".make_http(make_link("post/view/{$image->id}"))."\">"); $page->add_html_header("<meta property=\"og:url\" content=\"".make_http(make_link("post/view/{$image->id}"))."\">");
$page->add_block(new Block("Navigation", $this->build_navigation($image), "left", 0)); $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("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)); $page->add_block(new Block(null, $this->build_pin($image), "main", 11));
} }