Merge branch 'master' into speed_tweaks
This commit is contained in:
		
						commit
						d69fa6ae9d
					
				| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Comment Word Ban | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: For stopping spam and other comment abuse | ||||
|  * Documentation: | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Bulk Add | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Bulk add server-side images | ||||
|  * Documentation: | ||||
| @ -30,7 +31,9 @@ class BulkAdd extends SimpleExtension { | ||||
| 		$this->theme->display_admin_block(); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Generate the necessary DataUploadEvent for a given image and tags. | ||||
| 	 */ | ||||
| 	private function add_image($tmpname, $filename, $tags) { | ||||
| 		assert(file_exists($tmpname)); | ||||
| 
 | ||||
|  | ||||
| @ -29,6 +29,9 @@ class ET extends SimpleExtension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Collect the information and return it in a keyed array. | ||||
| 	 */ | ||||
| 	private function get_info() { | ||||
| 		global $config, $database; | ||||
| 		global $_event_listeners; // yay for using secret globals \o/
 | ||||
|  | ||||
| @ -152,6 +152,17 @@ class Favorites extends SimpleExtension { | ||||
| 			");
 | ||||
| 			$config->set_int("ext_favorites_version", 1); | ||||
| 		} | ||||
| 
 | ||||
| 		if($config->get_int("ext_favorites_version") < 2) { | ||||
| 			log_info("favorites", "Cleaning user favourites"); | ||||
| 			$database->Execute("DELETE FROM user_favorites WHERE user_id NOT IN (SELECT id FROM users)"); | ||||
| 			$database->Execute("DELETE FROM user_favorites WHERE image_id NOT IN (SELECT id FROM images)"); | ||||
| 
 | ||||
| 			log_info("favorites", "Adding foreign keys to user favourites"); | ||||
| 			$database->Execute("ALTER TABLE user_favorites ADD CONSTRAINT foreign_user_favorites_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;"); | ||||
| 			$database->Execute("ALTER TABLE user_favorites ADD CONSTRAINT user_favorites_image_id FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE;"); | ||||
| 			$config->set_int("ext_favorites_version", 2); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private function add_vote($image_id, $user_id, $do_set) { | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Featured Image | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Bring a specific image to the users' attentions | ||||
|  * Documentation: | ||||
|  | ||||
| @ -2,7 +2,8 @@ | ||||
| /* | ||||
|  * Name: Handle Flash | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Description: Handle Flash files | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * Description: Handle Flash files. (No thumbnail is generated for flash files) | ||||
|  */ | ||||
| 
 | ||||
| class FlashFileHandler extends DataHandlerExtension { | ||||
|  | ||||
| @ -2,7 +2,8 @@ | ||||
| /* | ||||
|  * Name: Handle SVG | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Description: Handle SVG files | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * Description: Handle SVG files. (No thumbnail is generated for SVG files) | ||||
|  */ | ||||
| 
 | ||||
| class SVGFileHandler implements Extension { | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: IP Ban | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Ban IP addresses | ||||
|  * Documentation: | ||||
| @ -92,7 +93,7 @@ class IPBan extends SimpleExtension { | ||||
| 	public function onRemoveIPBan($event) { | ||||
| 		global $database; | ||||
| 		$database->Execute("DELETE FROM bans WHERE id = :id", array("id"=>$event->id)); | ||||
| 		$database->cache->delete("ip_bans"); | ||||
| 		$database->cache->delete("ip_bans_sorted"); | ||||
| 	} | ||||
| 
 | ||||
| // installer {{{
 | ||||
| @ -261,7 +262,7 @@ class IPBan extends SimpleExtension { | ||||
| 		global $database; | ||||
| 		$sql = "INSERT INTO bans (ip, reason, end_timestamp, banner_id) VALUES (:ip, :reason, :end, :admin_id)"; | ||||
| 		$database->Execute($sql, array("ip"=>$ip, "reason"=>$reason, "end"=>strtotime($end), "admin_id"=>$user->id)); | ||||
| 		$database->cache->delete("ip_bans"); | ||||
| 		$database->cache->delete("ip_bans_sorted"); | ||||
| 		log_info("ipban", "'$user->name' has banned '$ip' because '$reason' until '$end'"); | ||||
| 	} | ||||
| // }}}
 | ||||
|  | ||||
| @ -1,8 +1,9 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Name: Logging (Database) | ||||
|  * Author: Shish | ||||
|  * Description: Keep a record of SCore events | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * Description: Keep a record of SCore events (in the database). | ||||
|  * Visibility: admin | ||||
|  */ | ||||
| 
 | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: News | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Show a short amount of text in a block on the post list | ||||
|  * Documentation: | ||||
|  | ||||
							
								
								
									
										3408
									
								
								contrib/notes/jquery.js
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3408
									
								
								contrib/notes/jquery.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Image Scores (Numeric) | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Allow users to score images | ||||
|  * Documentation: | ||||
|  | ||||
| @ -57,11 +57,24 @@ class PrivMsg extends SimpleExtension { | ||||
| 				subject VARCHAR(64) NOT NULL, | ||||
| 				message TEXT NOT NULL, | ||||
| 				is_read SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N, | ||||
| 				INDEX (to_id) | ||||
| 				INDEX (to_id), | ||||
| 				FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE, | ||||
| 				FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE | ||||
| 			");
 | ||||
| 			$config->set_int("pm_version", 1); | ||||
| 			log_info("pm", "extension installed"); | ||||
| 		} | ||||
| 
 | ||||
| 		if($config->get_int("pm_version") < 2) { | ||||
| 			log_info("pm", "Adding foreign keys to private messages"); | ||||
| 			$database->Execute("delete from private_message where to_id not in (select id from users);"); | ||||
| 			$database->Execute("delete from private_message where from_id not in (select id from users);"); | ||||
| 			$database->Execute("ALTER TABLE private_message 
 | ||||
| 			ADD CONSTRAINT foreign_private_message_from_id FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE, | ||||
| 			ADD CONSTRAINT foreign_private_message_to_id FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE;");
 | ||||
| 			$config->set_int("pm_version", 2); | ||||
| 			log_info("pm", "extension installed"); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/* | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Random Image | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Do things with a random image | ||||
|  * Documentation: | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Image Ratings | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Allow users to rate images "safe", "questionable" or "explicit" | ||||
|  */ | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Regen Thumb | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Description: Regenerate a thumbnail image | ||||
|  * Documentation: | ||||
|  | ||||
| @ -2,6 +2,7 @@ | ||||
| /* | ||||
|  * Name: Site Description | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * License: GPLv2 | ||||
|  * Visibility: admin | ||||
|  * Description: A description for search engines | ||||
|  | ||||
| @ -8,17 +8,17 @@ interface Config { | ||||
| 	 * so that the next time a page is loaded it will use the new | ||||
| 	 * configuration | ||||
| 	 */ | ||||
| 	public function save($name=null); | ||||
| 	public function save(/*string*/ $name=null); | ||||
| 
 | ||||
| 	/** @name set_* | ||||
| 	 * Set a configuration option to a new value, regardless | ||||
| 	 * of what the value is at the moment | ||||
| 	 */ | ||||
| 	//@{
 | ||||
| 	public function set_int($name, $value); | ||||
| 	public function set_string($name, $value); | ||||
| 	public function set_bool($name, $value); | ||||
| 	public function set_array($name, $value); | ||||
| 	public function set_int(/*string*/ $name, $value); | ||||
| 	public function set_string(/*string*/ $name, $value); | ||||
| 	public function set_bool(/*string*/ $name, $value); | ||||
| 	public function set_array(/*string*/ $name, $value); | ||||
| 	//@}
 | ||||
| 
 | ||||
| 	/** @name set_default_* | ||||
| @ -30,10 +30,10 @@ interface Config { | ||||
| 	 * "default" paramater won't show up. | ||||
| 	 */ | ||||
| 	//@{
 | ||||
| 	public function set_default_int($name, $value); | ||||
| 	public function set_default_string($name, $value); | ||||
| 	public function set_default_bool($name, $value); | ||||
| 	public function set_default_array($name, $value); | ||||
| 	public function set_default_int(/*string*/ $name, $value); | ||||
| 	public function set_default_string(/*string*/ $name, $value); | ||||
| 	public function set_default_bool(/*string*/ $name, $value); | ||||
| 	public function set_default_array(/*string*/ $name, $value); | ||||
| 	//@}
 | ||||
| 
 | ||||
| 	/** @name get_* | ||||
| @ -41,10 +41,10 @@ interface Config { | ||||
| 	 * appropritate data type | ||||
| 	 */ | ||||
| 	//@{
 | ||||
| 	public function get_int($name, $default=null); | ||||
| 	public function get_string($name, $default=null); | ||||
| 	public function get_bool($name, $default=null); | ||||
| 	public function get_array($name, $default=array()); | ||||
| 	public function get_int(/*string*/ $name, $default=null); | ||||
| 	public function get_string(/*string*/ $name, $default=null); | ||||
| 	public function get_bool(/*string*/ $name, $default=null); | ||||
| 	public function get_array(/*string*/ $name, $default=array()); | ||||
| 	//@}
 | ||||
| } | ||||
| 
 | ||||
| @ -56,60 +56,60 @@ interface Config { | ||||
| abstract class BaseConfig implements Config { | ||||
| 	var $values = array(); | ||||
| 
 | ||||
| 	public function set_int($name, $value) { | ||||
| 	public function set_int(/*string*/ $name, $value) { | ||||
| 		$this->values[$name] = parse_shorthand_int($value); | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 	public function set_string($name, $value) { | ||||
| 	public function set_string(/*string*/ $name, $value) { | ||||
| 		$this->values[$name] = $value; | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 	public function set_bool($name, $value) { | ||||
| 	public function set_bool(/*string*/ $name, $value) { | ||||
| 		$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N'); | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 	public function set_array($name, $value) { | ||||
| 	public function set_array(/*string*/ $name, $value) { | ||||
| 		assert(is_array($value)); | ||||
| 		$this->values[$name] = implode(",", $value); | ||||
| 		$this->save($name); | ||||
| 	} | ||||
| 
 | ||||
| 	public function set_default_int($name, $value) { | ||||
| 	public function set_default_int(/*string*/ $name, $value) { | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = parse_shorthand_int($value); | ||||
| 		} | ||||
| 	} | ||||
| 	public function set_default_string($name, $value) { | ||||
| 	public function set_default_string(/*string*/ $name, $value) { | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = $value; | ||||
| 		} | ||||
| 	} | ||||
| 	public function set_default_bool($name, $value) { | ||||
| 	public function set_default_bool(/*string*/ $name, $value) { | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N'); | ||||
| 		} | ||||
| 	} | ||||
| 	public function set_default_array($name, $value) { | ||||
| 	public function set_default_array(/*string*/ $name, $value) { | ||||
| 		assert(is_array($value)); | ||||
| 		if(is_null($this->get($name))) { | ||||
| 			$this->values[$name] = implode(",", $value); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function get_int($name, $default=null) { | ||||
| 	public function get_int(/*string*/ $name, $default=null) { | ||||
| 		return (int)($this->get($name, $default)); | ||||
| 	} | ||||
| 	public function get_string($name, $default=null) { | ||||
| 	public function get_string(/*string*/ $name, $default=null) { | ||||
| 		return $this->get($name, $default); | ||||
| 	} | ||||
| 	public function get_bool($name, $default=null) { | ||||
| 	public function get_bool(/*string*/ $name, $default=null) { | ||||
| 		return undb_bool($this->get($name, $default)); | ||||
| 	} | ||||
| 	public function get_array($name, $default=array()) { | ||||
| 	public function get_array(/*string*/ $name, $default=array()) { | ||||
| 		return explode(",", $this->get($name, "")); | ||||
| 	} | ||||
| 
 | ||||
| 	private function get($name, $default=null) { | ||||
| 	private function get(/*string*/ $name, $default=null) { | ||||
| 		if(isset($this->values[$name])) { | ||||
| 			return $this->values[$name]; | ||||
| 		} | ||||
| @ -144,7 +144,7 @@ class StaticConfig extends BaseConfig { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function save($name=null) { | ||||
| 	public function save(/*string*/ $name=null) { | ||||
| 		// static config is static
 | ||||
| 	} | ||||
| } | ||||
| @ -167,7 +167,7 @@ class DatabaseConfig extends BaseConfig { | ||||
| 	/* | ||||
| 	 * Load the config table from a database | ||||
| 	 */ | ||||
| 	public function DatabaseConfig($database) { | ||||
| 	public function DatabaseConfig(Database $database) { | ||||
| 		$this->database = $database; | ||||
| 
 | ||||
| 		$cached = $this->database->cache->get("config"); | ||||
| @ -186,11 +186,11 @@ class DatabaseConfig extends BaseConfig { | ||||
| 	/* | ||||
| 	 * Save the current values as the new config table | ||||
| 	 */ | ||||
| 	public function save($name=null) { | ||||
| 	public function save(/*string*/ $name=null) { | ||||
| 		if(is_null($name)) { | ||||
| 			reset($this->values); // rewind the array to the first element
 | ||||
| 			foreach($this->values as $name => $value) { | ||||
| 				$this->save($name); | ||||
| 				$this->save(/*string*/ $name); | ||||
| 			} | ||||
| 		} | ||||
| 		else { | ||||
|  | ||||
| @ -310,7 +310,7 @@ class Database { | ||||
| 		} | ||||
| 
 | ||||
| 		$matches = array(); | ||||
| 		if(CACHE_DSN && preg_match("#(memcache|apc)://(.*)#", CACHE_DSN, $matches)) { | ||||
| 		if( defined("CACHE_DSN") && CACHE_DSN && preg_match("#(memcache|apc)://(.*)#", CACHE_DSN, $matches)) { | ||||
| 			if($matches[1] == "memcache") { | ||||
| 				$this->cache = new MemcacheCache($matches[2]); | ||||
| 			} | ||||
|  | ||||
| @ -39,6 +39,8 @@ class PageRequestEvent extends Event { | ||||
| 	 * Test if the requested path matches a given pattern. | ||||
| 	 * | ||||
| 	 * If it matches, store the remaining path elements in $args | ||||
| 	 * | ||||
| 	 * @retval bool | ||||
| 	 */ | ||||
| 	public function page_matches(/*string*/ $name) { | ||||
| 		$parts = explode("/", $name); | ||||
| @ -57,6 +59,11 @@ class PageRequestEvent extends Event { | ||||
| 		return true; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get the n th argument of the page request (if it exists.) | ||||
| 	 * @param $n integer | ||||
| 	 * @retval The argmuent (string) or NULL | ||||
| 	 */ | ||||
| 	public function get_arg(/*int*/ $n) { | ||||
| 		$offset = $this->part_count + $n; | ||||
| 		if($offset >= 0 && $offset < $this->arg_count) { | ||||
| @ -67,6 +74,10 @@ class PageRequestEvent extends Event { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Returns the number of arguments the page request has. | ||||
| 	 * @retval int | ||||
| 	 */ | ||||
| 	public function count_args() { | ||||
| 		return (int)($this->arg_count - $this->part_count); | ||||
| 	} | ||||
|  | ||||
| @ -191,7 +191,7 @@ abstract class DataHandlerExtension extends SimpleExtension { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function onThumnbnailGeneration(ThumbnailGenerationEvent $event) { | ||||
| 	public function onThumbnailGeneration(ThumbnailGenerationEvent $event) { | ||||
| 		if($this->supported_ext($event->type)) { | ||||
| 			if (method_exists($this, 'create_thumb_force') && $event->force == true) { | ||||
| 				 $this->create_thumb_force($event->hash); | ||||
|  | ||||
| @ -106,18 +106,26 @@ class Image { | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Search for an array of images | ||||
| 	 * | ||||
| 	 * @retval Array | ||||
| 	 */ | ||||
| 	public static function find_images($start, $limit, $tags=array()) { | ||||
| 	public static function find_images(/*int*/ $start, /*int*/ $limit, $tags=array()) { | ||||
| 		assert(is_numeric($start)); | ||||
| 		assert(is_numeric($limit)); | ||||
| 		assert(is_array($tags)); | ||||
| 		global $database; | ||||
| 		global $database, $user; | ||||
| 
 | ||||
| 		$images = array(); | ||||
| 
 | ||||
| 		if($start < 0) $start = 0; | ||||
| 		if($limit < 1) $limit = 1; | ||||
| 
 | ||||
| 		if(SPEED_HAX) { | ||||
| 			if(!$user->can("big_search") and count($tags) > 3) { | ||||
| 				die("Anonymous users may only search for up to 3 tags at a time"); // FIXME: throw an exception?
 | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		$querylet = Image::build_search_querylet($tags); | ||||
| 		$querylet->append(new Querylet("ORDER BY images.id DESC LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start))); | ||||
| 		#var_dump($querylet->sql); var_dump($querylet->variables);
 | ||||
| @ -377,7 +385,7 @@ class Image { | ||||
| 	/** | ||||
| 	 * Set the image's source URL | ||||
| 	 */ | ||||
| 	public function set_source($source) { | ||||
| 	public function set_source(/*string*/ $source) { | ||||
| 		global $database; | ||||
| 		if(empty($source)) $source = null; | ||||
| 		if($source != $this->source) { | ||||
| @ -386,7 +394,10 @@ class Image { | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Check if the image is locked. | ||||
| 	 * @retval bool | ||||
| 	 */ | ||||
| 	public function is_locked() { | ||||
| 		return ($this->locked === true || $this->locked == "Y" || $this->locked == "t"); | ||||
| 	} | ||||
|  | ||||
| @ -39,7 +39,7 @@ class Page { | ||||
| 	/** @private */ | ||||
| 	var $mode = "page"; | ||||
| 	/** @private */ | ||||
| 	var $type = "text/html"; | ||||
| 	var $type = "text/html; charset=utf-8"; | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set what this page should do; "page", "data", or "redirect". | ||||
| @ -196,8 +196,8 @@ class Page { | ||||
| 
 | ||||
| 		switch($this->mode) { | ||||
| 			case "page": | ||||
| 				header("Vary: Cookie, Accept-Encoding"); | ||||
| 				if(CACHE_HTTP) { | ||||
| 					header("Vary: Cookie, Accept-Encoding"); | ||||
| 					if($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { | ||||
| 						header("Cache-control: public, max-age=600"); | ||||
| 						header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT'); | ||||
| @ -237,6 +237,8 @@ class Page { | ||||
| 	protected function add_auto_html_headers() { | ||||
| 		$data_href = get_base_href(); | ||||
| 
 | ||||
| 		$this->add_html_header("<script type='text/javascript'>base_href = '$data_href';</script>"); | ||||
| 		 | ||||
| 		/* Attempt to cache the CSS & JavaScript files */ | ||||
| 		if ($this->add_cached_auto_html_headers() === FALSE) { | ||||
| 			// caching failed, add all files to html_headers.
 | ||||
|  | ||||
| @ -4,6 +4,7 @@ function _new_user($row) { | ||||
| 	return new User($row); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /** | ||||
|  * An object representing a row in the "users" table. | ||||
|  * | ||||
| @ -90,6 +91,77 @@ class User { | ||||
| 	/* | ||||
| 	 * useful user object functions start here | ||||
| 	 */ | ||||
| 	public function can($ability) { | ||||
| 		global $config; | ||||
| 
 | ||||
| 		// TODO: make this into an editable database table
 | ||||
| 		$user_classes = array( | ||||
| 			"anonymous" => array( | ||||
| 				"change_setting" => False,  # web-level settings, eg the config table
 | ||||
| 				"override_config" => False, # sys-level config, eg config.php
 | ||||
| 				"big_search" => False,      # more than 3 tags (speed mode only)
 | ||||
| 				"lock_image" => False, | ||||
| 				"view_ip" => False,         # view IP addresses associated with things
 | ||||
| 				"change_password" => False, | ||||
| 				"change_user_info" => False, | ||||
| 				"delete_user" => False, | ||||
| 				"delete_image" => False, | ||||
| 				"delete_comment" => False, | ||||
| 				"replace_image" => False, | ||||
| 				"manage_extension_list" => False, | ||||
| 				"manage_alias_list" => False, | ||||
| 				"edit_tag" => $config->get_bool("tag_edit_anon"), | ||||
| 				"edit_source" => $config->get_bool("source_edit_anon"), | ||||
| 				"mass_tag_edit" => False, | ||||
| 			), | ||||
| 			"user" => array( | ||||
| 				"change_setting" => False, | ||||
| 				"override_config" => False, | ||||
| 				"big_search" => True, | ||||
| 				"lock_image" => False, | ||||
| 				"view_ip" => False, | ||||
| 				"change_password" => False, | ||||
| 				"change_user_info" => False, | ||||
| 				"delete_user" => False, | ||||
| 				"delete_image" => False, | ||||
| 				"delete_comment" => False, | ||||
| 				"replace_image" => False, | ||||
| 				"manage_extension_list" => False, | ||||
| 				"manage_alias_list" => False, | ||||
| 				"edit_tag" => True, | ||||
| 				"edit_source" => True, | ||||
| 				"mass_tag_edit" => False, | ||||
| 			), | ||||
| 			"admin" => array( | ||||
| 				"change_setting" => True, | ||||
| 				"override_config" => True, | ||||
| 				"big_search" => True, | ||||
| 				"lock_image" => True, | ||||
| 				"view_ip" => True, | ||||
| 				"change_password" => True, | ||||
| 				"change_user_info" => True, | ||||
| 				"delete_user" => True, | ||||
| 				"delete_image" => True, | ||||
| 				"delete_comment" => True, | ||||
| 				"replace_image" => True, | ||||
| 				"manage_extension_list" => True, | ||||
| 				"manage_alias_list" => True, | ||||
| 				"edit_tag" => True, | ||||
| 				"edit_source" => True, | ||||
| 				"mass_tag_edit" => True, | ||||
| 			), | ||||
| 		); | ||||
| 
 | ||||
| 		return $user_classes[$this->get_class()][$ability]; | ||||
| 	} | ||||
| 
 | ||||
| 	// FIXME: this should be a column in the users table
 | ||||
| 	public function get_class() { | ||||
| 		if($this->is_admin()) return "admin"; | ||||
| 		else if($this->is_logged_in()) return "user"; | ||||
| 		else return"anonymous"; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Test if this user is anonymous (not logged in) | ||||
| @ -144,6 +216,7 @@ class User { | ||||
| 	/** | ||||
| 	 * Get a snippet of HTML which will render the user's avatar, be that | ||||
| 	 * a local file, a remote file, a gravatar, a something else, etc | ||||
| 	 * @retval String of HTML | ||||
| 	 */ | ||||
| 	public function get_avatar_html() { | ||||
| 		// FIXME: configurable
 | ||||
| @ -170,6 +243,8 @@ class User { | ||||
| 	 * authtok  = md5(sesskey, salt), presented to the user in web forms, to make sure that | ||||
| 	 *            the form was generated within the session. Salted and re-hashed so that | ||||
| 	 *            reading a web page from the user's cache doesn't give access to the session key | ||||
| 	 * | ||||
| 	 * @retval String containing auth token (MD5sum) | ||||
| 	 */ | ||||
| 	public function get_auth_token() { | ||||
| 		global $config; | ||||
|  | ||||
| @ -190,12 +190,26 @@ function undb_bool($val) { | ||||
| 	if($val === false || $val == 'N' || $val == 'n' || $val == 'F' || $val == 'f' || $val === 0) return false; | ||||
| } | ||||
| 
 | ||||
| function startsWith($haystack, $needle) { | ||||
| /** | ||||
|  * Checks if a given string contains another at the beginning. | ||||
|  * | ||||
|  * @param $haystack String to examine. | ||||
|  * @param $needle String to look for. | ||||
|  * @retval bool | ||||
|  */ | ||||
| function startsWith(/*string*/ $haystack, /*string*/ $needle) { | ||||
| 	$length = strlen($needle); | ||||
| 	return (substr($haystack, 0, $length) === $needle); | ||||
| } | ||||
| 
 | ||||
| function endsWith($haystack, $needle) { | ||||
| /** | ||||
|  * Checks if a given string contains another at the end. | ||||
|  * | ||||
|  * @param $haystack String to examine. | ||||
|  * @param $needle String to look for. | ||||
|  * @retval bool | ||||
|  */ | ||||
| function endsWith(/*string*/ $haystack, /*string*/ $needle) { | ||||
| 	$length = strlen($needle); | ||||
| 	$start  = $length * -1; //negative
 | ||||
| 	return (substr($haystack, $start) === $needle); | ||||
| @ -621,6 +635,7 @@ function log_msg($section, $priority, $message) { | ||||
| 	send_event(new LogEvent($section, $priority, $message)); | ||||
| } | ||||
| 
 | ||||
| // More shorthand ways of logging
 | ||||
| function log_debug($section, $message) {log_msg($section, SCORE_LOG_DEBUG, $message);} | ||||
| function log_info($section, $message)  {log_msg($section, SCORE_LOG_INFO, $message);} | ||||
| function log_warning($section, $message) {log_msg($section, SCORE_LOG_WARNING, $message);} | ||||
| @ -847,6 +862,13 @@ function send_event(Event $event) { | ||||
| // string representation of a number, it's two numbers separated by a space.
 | ||||
| // What the fuck were the PHP developers smoking.
 | ||||
| $_load_start = microtime(true); | ||||
| 
 | ||||
| /** | ||||
|  * Collects some debug information (execution time, memory usage, queries, etc) | ||||
|  * and formats it to stick in the footer of the page. | ||||
|  * | ||||
|  * @retval String of debug info to add to the page. | ||||
|  */ | ||||
| function get_debug_info() { | ||||
| 	global $config, $_event_count, $database, $_execs, $_load_start; | ||||
| 
 | ||||
| @ -879,7 +901,7 @@ function get_debug_info() { | ||||
| // print_obj ($object, $title, $return)
 | ||||
| function print_obj($object,$title="Object Information", $return=false) { | ||||
| 	global $user; | ||||
| 	if(DEBUG && isset($_GET['debug']) && $user->is_admin()) { | ||||
| 	if(DEBUG && isset($_GET['DEBUG']) && $user->can("override_config")) { | ||||
| 		$pr = print_r($object,true); | ||||
| 		$count = substr_count($pr,"\n")<=25?substr_count($pr,"\n"):25; | ||||
| 		$pr = "<textarea rows='".$count."' cols='80'>$pr</textarea>"; | ||||
| @ -1051,6 +1073,9 @@ function _load_extensions() { | ||||
| 	ctx_log_endok(); | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Used to display fatal errors to the web user. | ||||
|  */ | ||||
| function _fatal_error(Exception $e) { | ||||
| 	$version = VERSION; | ||||
| 	$message = $e->getMessage(); | ||||
|  | ||||
| @ -28,7 +28,7 @@ class AliasEditor extends SimpleExtension { | ||||
| 
 | ||||
| 		if($event->page_matches("alias")) { | ||||
| 			if($event->get_arg(0) == "add") { | ||||
| 				if($user->is_admin()) { | ||||
| 				if($user->can("manage_alias_list")) { | ||||
| 					if(isset($_POST['oldtag']) && isset($_POST['newtag'])) { | ||||
| 						try { | ||||
| 							$aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); | ||||
| @ -43,7 +43,7 @@ class AliasEditor extends SimpleExtension { | ||||
| 				} | ||||
| 			} | ||||
| 			else if($event->get_arg(0) == "remove") { | ||||
| 				if($user->is_admin()) { | ||||
| 				if($user->can("manage_alias_list")) { | ||||
| 					if(isset($_POST['oldtag'])) { | ||||
| 						$database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", array("oldtag" => $_POST['oldtag'])); | ||||
| 						log_info("alias_editor", "Deleted alias for ".$_POST['oldtag']); | ||||
| @ -74,7 +74,7 @@ class AliasEditor extends SimpleExtension { | ||||
| 
 | ||||
| 				$total_pages = ceil($database->get_one("SELECT COUNT(*) FROM aliases") / $alias_per_page); | ||||
| 
 | ||||
| 				$this->theme->display_aliases($page, $alias, $user->is_admin(), $page_number + 1, $total_pages); | ||||
| 				$this->theme->display_aliases($alias, $page_number + 1, $total_pages); | ||||
| 			} | ||||
| 			else if($event->get_arg(0) == "export") { | ||||
| 				$page->set_mode("data"); | ||||
| @ -82,7 +82,7 @@ class AliasEditor extends SimpleExtension { | ||||
| 				$page->set_data($this->get_alias_csv($database)); | ||||
| 			} | ||||
| 			else if($event->get_arg(0) == "import") { | ||||
| 				if($user->is_admin()) { | ||||
| 				if($user->can("manage_alias_list")) { | ||||
| 					if(count($_FILES) > 0) { | ||||
| 						$tmp = $_FILES['alias_file']['tmp_name']; | ||||
| 						$contents = file_get_contents($tmp); | ||||
| @ -115,7 +115,7 @@ class AliasEditor extends SimpleExtension { | ||||
| 
 | ||||
| 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | ||||
| 		global $user; | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("manage_alias_list")) { | ||||
| 			$event->add_link("Alias Editor", make_link("alias/list")); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -5,10 +5,13 @@ class AliasEditorTheme extends Themelet { | ||||
| 	 * Show a page of aliases: | ||||
| 	 * | ||||
| 	 * $aliases = an array of ($old_tag => $new_tag) | ||||
| 	 * $is_admin = whether things like "add new alias" should be shown | ||||
| 	 * $can_manage = whether things like "add new alias" should be shown | ||||
| 	 */ | ||||
| 	public function display_aliases(Page $page, $aliases, $is_admin, $pageNumber, $totalPages) { | ||||
| 		if($is_admin) { | ||||
| 	public function display_aliases($aliases, $pageNumber, $totalPages) { | ||||
| 		global $page, $user; | ||||
| 
 | ||||
| 		$can_manage = $user->can("manage_alias_list"); | ||||
| 		if($can_manage) { | ||||
| 			$action = "<th width='10%'>Action</th>"; | ||||
| 			$add = " | ||||
| 				<tr> | ||||
| @ -33,7 +36,7 @@ class AliasEditorTheme extends Themelet { | ||||
| 			$oe = ($n++ % 2 == 0) ? "even" : "odd"; | ||||
| 			 | ||||
| 			$h_aliases .= "<tr class='$oe'><td>$h_old</td><td>$h_new</td>"; | ||||
| 			if($is_admin) { | ||||
| 			if($can_manage) { | ||||
| 				$h_aliases .= " | ||||
| 					<td> | ||||
| 						".make_form(make_link("alias/remove"))." | ||||
| @ -70,7 +73,7 @@ class AliasEditorTheme extends Themelet { | ||||
| 		$page->set_heading("Alias List"); | ||||
| 		$page->add_block(new NavBlock()); | ||||
| 		$page->add_block(new Block("Aliases", $html)); | ||||
| 		if($is_admin) { | ||||
| 		if($can_manage) { | ||||
| 			$page->add_block(new Block("Bulk Upload", $bulk_html, "main", 51)); | ||||
| 		} | ||||
| 
 | ||||
|  | ||||
| @ -38,7 +38,8 @@ class BBCode extends FormatterExtension { | ||||
| 		$text = preg_replace("/\[i\](.*?)\[\/i\]/s", "<i>\\1</i>", $text); | ||||
| 		$text = preg_replace("/\[u\](.*?)\[\/u\]/s", "<u>\\1</u>", $text); | ||||
| 		$text = preg_replace("/\[s\](.*?)\[\/s\]/s", "<s>\\1</s>", $text); | ||||
| 		$text = preg_replace("/>>(\d+)/s", "<a href=\"".make_link("post/view/\\1")."\">>>\\1</a>", $text); | ||||
| 		$text = preg_replace("/>>(\d+)(#\d+)?/s", "<a href=\"".make_link("post/view/\\1\\2")."\">>>\\1\\2</a>", $text); | ||||
| 		$text = preg_replace("/(^|\s)#(\d+)/s", "\\1<a href=\"#\\2\">#\\2</a>", $text); | ||||
| 		$text = preg_replace("/>>([^\d].+)/", "<blockquote><small>\\1</small></blockquote>", $text); | ||||
| 		$text = preg_replace("/\[url=((?:https?|ftp|irc|mailto):\/\/.*?)\](.*?)\[\/url\]/s", "<a href=\"\\1\">\\2</a>", $text); | ||||
| 		$text = preg_replace("/\[url\]((?:https?|ftp|irc|mailto):\/\/.*?)\[\/url\]/s", "<a href=\"\\1\">\\1</a>", $text); | ||||
|  | ||||
| @ -128,7 +128,7 @@ class CommentList extends SimpleExtension { | ||||
| 				} | ||||
| 			} | ||||
| 			else if($event->get_arg(0) === "delete") { | ||||
| 				if($user->is_admin()) { | ||||
| 				if($user->can("delete_comment")) { | ||||
| 					// FIXME: post, not args
 | ||||
| 					if($event->count_args() === 3) { | ||||
| 						send_event(new CommentDeletionEvent($event->get_arg(1))); | ||||
| @ -173,7 +173,6 @@ class CommentList extends SimpleExtension { | ||||
| 		$h_comment_rate = sprintf("%.1f", ($i_comment_count / $i_days_old)); | ||||
| 		$event->add_stats("Comments made: $i_comment_count, $h_comment_rate per day"); | ||||
| 
 | ||||
| 		global $user; | ||||
| 		$recent = $this->get_user_recent_comments($event->display_user->id, 10); | ||||
| 		$this->theme->display_user_comments($recent); | ||||
| 	} | ||||
|  | ||||
| @ -143,46 +143,53 @@ class CommentListTheme extends Themelet { | ||||
| 		$h_name = html_escape($comment->owner_name); | ||||
| 		$h_poster_ip = html_escape($comment->poster_ip); | ||||
| 		$h_timestamp = autodate($comment->posted); | ||||
| 		$h_comment = ($trim ? substr($tfe->stripped, 0, 50)."..." : $tfe->formatted); | ||||
| 		$h_comment = ($trim ? substr($tfe->stripped, 0, 50) . (strlen($tfe->stripped) > 50 ? "..." : "") : $tfe->formatted); | ||||
| 		$i_comment_id = int_escape($comment->comment_id); | ||||
| 		$i_image_id = int_escape($comment->image_id); | ||||
| 
 | ||||
| 		$anoncode = ""; | ||||
| 		if($h_name == "Anonymous" && $this->anon_id >= 0) { | ||||
| 			$anoncode = '<sup>'.$this->anon_id.'</sup>'; | ||||
| 			$this->anon_id++; | ||||
| 		if($h_name == "Anonymous") { | ||||
| 			$anoncode = ""; | ||||
| 			if($this->anon_id >= 0) { | ||||
| 				$anoncode = '<sup>'.$this->anon_id.'</sup>'; | ||||
| 				$this->anon_id++; | ||||
| 			} | ||||
| 			$h_userlink = $h_name . $anoncode; | ||||
| 		} | ||||
| 		else { | ||||
| 			$h_userlink = '<a href="'.make_link('user/'.$h_name).'">'.$h_name.'</a>'; | ||||
| 		} | ||||
| 		$h_userlink = '<a href="'.make_link('user/'.$h_name).'">'.$h_name.'</a>'.$anoncode; | ||||
| 		$stripped_nonl = str_replace("\n", "\\n", substr($tfe->stripped, 0, 50)); | ||||
| 		$stripped_nonl = str_replace("\r", "\\r", $stripped_nonl); | ||||
| 		$h_dellink = $user->is_admin() ? | ||||
| 			'<br>('.$h_poster_ip.', '.$h_timestamp.', <a '. | ||||
| 			'onclick="return confirm(\'Delete comment by '.$h_name.':\\n'.$stripped_nonl.'\');" '. | ||||
| 			'href="'.make_link('comment/delete/'.$i_comment_id.'/'.$i_image_id).'">Del</a>)' : ''; | ||||
| 
 | ||||
| 		if($trim) { | ||||
| 			return ' | ||||
| 				'.$h_userlink.': '.$h_comment.' | ||||
| 				<a href="'.make_link('post/view/'.$i_image_id).'">>>></a> | ||||
| 				'.$h_dellink.' | ||||
| 			'; | ||||
| 		} | ||||
| 		else { | ||||
| 			//$avatar = "";
 | ||||
| 			//if(!empty($comment->owner->email)) {
 | ||||
| 			//	$hash = md5(strtolower($comment->owner->email));
 | ||||
| 			//	$avatar = "<img src=\"http://www.gravatar.com/avatar/$hash.jpg\"><br>";
 | ||||
| 			//}
 | ||||
| 			$oe = ($this->comments_shown++ % 2 == 0) ? "even" : "odd"; | ||||
| 			$avatar = ""; | ||||
| 			if(!empty($comment->owner_email)) { | ||||
| 				$hash = md5(strtolower($comment->owner_email)); | ||||
| 				$avatar = "<img src=\"http://www.gravatar.com/avatar/$hash.jpg\"><br>"; | ||||
| 			} | ||||
| 			$h_reply = " - <a href='javascript: replyTo($i_image_id, $i_comment_id)'>Reply</a>"; | ||||
| 			$h_ip = $user->can("view_ip") ? "<br>$h_poster_ip" : ""; | ||||
| 			$h_del = $user->can("delete_comment") ? | ||||
| 				' - <a onclick="return confirm(\'Delete comment by '.$h_name.':\\n'.$stripped_nonl.'\');" '. | ||||
| 				'href="'.make_link('comment/delete/'.$i_comment_id.'/'.$i_image_id).'">Del</a>' : ''; | ||||
| 			return ' | ||||
| 				<a name="'.$i_comment_id.'"></a> | ||||
| 				<div class="'.$oe.' comment"> | ||||
| 				<!--<span class="timeago" style="float: right;">'.$h_timestamp.'</span>--> | ||||
| 				'.$h_userlink.': '.$h_comment.' | ||||
| 				'.$h_dellink.' | ||||
| 				<div class="comment"> | ||||
| 					<div class="info"> | ||||
| 					'.$avatar.' | ||||
| 					'.$h_timestamp.$h_reply.$h_ip.$h_del.' | ||||
| 					</div> | ||||
| 					'.$h_userlink.': '.$h_comment.' | ||||
| 				</div> | ||||
| 			'; | ||||
| 		} | ||||
| 		return ""; | ||||
| 	} | ||||
| 
 | ||||
| 	protected function build_postbox($image_id) { | ||||
| @ -196,7 +203,7 @@ class CommentListTheme extends Themelet { | ||||
| 			'.make_form(make_link("comment/add")).' | ||||
| 				<input type="hidden" name="image_id" value="'.$i_image_id.'" /> | ||||
| 				<input type="hidden" name="hash" value="'.$hash.'" /> | ||||
| 				<textarea name="comment" rows="5" cols="50"></textarea> | ||||
| 				<textarea id="comment_on_'.$i_image_id.'" name="comment" rows="5" cols="50"></textarea> | ||||
| 				'.$captcha.' | ||||
| 				<br><input type="submit" value="Post Comment" /> | ||||
| 			</form> | ||||
|  | ||||
| @ -91,7 +91,7 @@ class ExtManager extends SimpleExtension { | ||||
| 	public function onPageRequest(PageRequestEvent $event) { | ||||
| 		global $page, $user; | ||||
| 		if($event->page_matches("ext_manager")) { | ||||
| 			if($user->is_admin()) { | ||||
| 			if($user->can("manage_extension_list")) { | ||||
| 				if($event->get_arg(0) == "set" && $user->check_auth_token()) { | ||||
| 					if(is_writable("ext")) { | ||||
| 						$this->set_things($_POST); | ||||
| @ -130,7 +130,7 @@ class ExtManager extends SimpleExtension { | ||||
| 
 | ||||
| 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | ||||
| 		global $user; | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("manage_extension_list")) { | ||||
| 			$event->add_link("Extension Manager", make_link("ext_manager")); | ||||
| 		} | ||||
| 		else { | ||||
|  | ||||
| @ -162,7 +162,7 @@ class ImageIO extends SimpleExtension { | ||||
| 		} | ||||
| 		if($event->page_matches("image_admin/delete")) { | ||||
| 			global $page, $user; | ||||
| 			if($user->is_admin() && isset($_POST['image_id']) && $user->check_auth_token()) { | ||||
| 			if($user->can("delete_image") && isset($_POST['image_id']) && $user->check_auth_token()) { | ||||
| 				$image = Image::by_id($_POST['image_id']); | ||||
| 				if($image) { | ||||
| 					send_event(new ImageDeletionEvent($image)); | ||||
| @ -173,7 +173,7 @@ class ImageIO extends SimpleExtension { | ||||
| 		} | ||||
| 		if($event->page_matches("image_admin/replace")) { | ||||
| 			global $page, $user; | ||||
| 			if($user->is_admin() && isset($_POST['image_id']) && $user->check_auth_token()) { | ||||
| 			if($user->can("replace_image") && isset($_POST['image_id']) && $user->check_auth_token()) { | ||||
| 				$image = Image::by_id($_POST['image_id']); | ||||
| 				if($image) { | ||||
| 					$page->set_mode("redirect"); | ||||
| @ -190,11 +190,11 @@ class ImageIO extends SimpleExtension { | ||||
| 		global $user; | ||||
| 		global $config; | ||||
| 		 | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("delete_image")) { | ||||
| 			$event->add_part($this->theme->get_deleter_html($event->image->id)); | ||||
| 		} | ||||
| 		/* In the future, could perhaps allow users to replace images that they own as well... */ | ||||
| 		if ($user->is_admin() && $config->get_bool("upload_replace")) { | ||||
| 		if ($user->can("replace_image") && $config->get_bool("upload_replace")) { | ||||
| 			$event->add_part($this->theme->get_replace_html($event->image->id)); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -79,23 +79,8 @@ and of course start organising your images :-) | ||||
| 		$h_search_string = html_escape(implode(" ", $search_terms)); | ||||
| 		$h_search_link = make_link(); | ||||
| 		$h_search = " | ||||
| 			<script type='text/javascript'><!-- | ||||
| 			$(document).ready(function() { | ||||
| 				$('#search_input').DefaultValue('Search'); | ||||
| 				$('#search_input').autocomplete('".make_link("api/internal/tag_list/complete")."', { | ||||
| 					width: 320, | ||||
| 					max: 15, | ||||
| 					highlight: false, | ||||
| 					multiple: true, | ||||
| 					multipleSeparator: ' ', | ||||
| 					scroll: true, | ||||
| 					scrollHeight: 300, | ||||
| 					selectFirst: false | ||||
| 				}); | ||||
| 			}); | ||||
| 			//--></script>
 | ||||
| 			<p><form action='$h_search_link' method='GET'> | ||||
| 				<input id='search_input' name='search' type='text' | ||||
| 				<input class='search_input' id='search_input' name='search' type='text' | ||||
| 						value='$h_search_string' autocomplete='off' /> | ||||
| 				<input type='hidden' name='q' value='/post/list'> | ||||
| 				<input type='submit' value='Find' style='display: none;' /> | ||||
|  | ||||
| @ -187,7 +187,7 @@ class Setup extends SimpleExtension { | ||||
| 		} | ||||
| 
 | ||||
| 		if($event->page_matches("setup")) { | ||||
| 			if(!$user->is_admin()) { | ||||
| 			if(!$user->can("change_setting")) { | ||||
| 				$this->theme->display_permission_denied($page); | ||||
| 			} | ||||
| 			else { | ||||
| @ -329,7 +329,7 @@ class Setup extends SimpleExtension { | ||||
| 
 | ||||
| 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | ||||
| 		global $user; | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("change_setting")) { | ||||
| 			$event->add_link("Board Config", make_link("setup")); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @ -60,7 +60,7 @@ class TagEdit extends SimpleExtension { | ||||
| 		global $user, $page; | ||||
| 		if($event->page_matches("tag_edit")) { | ||||
| 			if($event->get_arg(0) == "replace") { | ||||
| 				if($user->is_admin() && isset($_POST['search']) && isset($_POST['replace'])) { | ||||
| 				if($user->can("mass_tag_edit") && isset($_POST['search']) && isset($_POST['replace'])) { | ||||
| 					$search = $_POST['search']; | ||||
| 					$replace = $_POST['replace']; | ||||
| 					$this->mass_tag_edit($search, $replace); | ||||
| @ -82,7 +82,7 @@ class TagEdit extends SimpleExtension { | ||||
| 		else { | ||||
| 			$this->theme->display_error($page, "Error", "Anonymous tag editing is disabled"); | ||||
| 		} | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("lock_image")) { | ||||
| 			$locked = isset($_POST['tag_edit__locked']) && $_POST['tag_edit__locked']=="on"; | ||||
| 			send_event(new LockSetEvent($event->image, $locked)); | ||||
| 		} | ||||
| @ -90,21 +90,21 @@ class TagEdit extends SimpleExtension { | ||||
| 
 | ||||
| 	public function onTagSet(TagSetEvent $event) { | ||||
| 		global $user; | ||||
| 		if($user->is_admin() || !$event->image->is_locked()) { | ||||
| 		if($user->can("edit_tag") || !$event->image->is_locked()) { | ||||
| 			$event->image->set_tags($event->tags); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function onSourceSet(SourceSetEvent $event) { | ||||
| 		global $user; | ||||
| 		if($user->is_admin() || !$event->image->is_locked()) { | ||||
| 		if($user->can("edit_tag") || !$event->image->is_locked()) { | ||||
| 			$event->image->set_source($event->source); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	public function onLockSet(LockSetEvent $event) { | ||||
| 		global $user; | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("lock_image")) { | ||||
| 			$event->image->set_locked($event->locked); | ||||
| 		} | ||||
| 	} | ||||
| @ -130,7 +130,7 @@ class TagEdit extends SimpleExtension { | ||||
| 		if($this->can_source($event->image)) { | ||||
| 			$event->add_part($this->theme->get_source_editor_html($event->image), 41); | ||||
| 		} | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("lock_image")) { | ||||
| 			$event->add_part($this->theme->get_lock_editor_html($event->image), 42); | ||||
| 		} | ||||
| 	} | ||||
| @ -147,7 +147,7 @@ class TagEdit extends SimpleExtension { | ||||
| 		global $config, $user; | ||||
| 		return ( | ||||
| 			($config->get_bool("tag_edit_anon") || !$user->is_anonymous()) && | ||||
| 			($user->is_admin() || !$image->is_locked()) | ||||
| 			($user->can("edit_tag") || !$image->is_locked()) | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
| @ -155,7 +155,7 @@ class TagEdit extends SimpleExtension { | ||||
| 		global $config, $user; | ||||
| 		return ( | ||||
| 			($config->get_bool("source_edit_anon") || !$user->is_anonymous()) && | ||||
| 			($user->is_admin() || !$image->is_locked()) | ||||
| 			($user->can("edit_source") || !$image->is_locked()) | ||||
| 		); | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| <?php | ||||
| /* | ||||
| /** | ||||
|  * Name: Tag List | ||||
|  * Author: Shish | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * Description: Show the tags in various ways | ||||
|  */ | ||||
| 
 | ||||
| @ -107,13 +108,18 @@ class TagList extends SimpleExtension { | ||||
| 		return make_link("post/list/$u_tag/1"); | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Get the minimum number of times a tag needs to be used | ||||
| 	 * in order to be considered in the tag list. | ||||
| 	 * @retval int | ||||
| 	 */ | ||||
| 	private function get_tags_min() { | ||||
| 		if(isset($_GET['mincount'])) { | ||||
| 			return int_escape($_GET['mincount']); | ||||
| 		} | ||||
| 		else { | ||||
| 			global $config; | ||||
| 			return $config->get_int('tags_min'); | ||||
| 			return $config->get_int('tags_min');	// get the default.
 | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -170,6 +176,8 @@ class TagList extends SimpleExtension { | ||||
| 
 | ||||
| 		$tags_min = $this->get_tags_min(); | ||||
| 		$starts_with = $this->get_starts_with(); | ||||
| 		 | ||||
| 		// check if we have a cached version
 | ||||
| 		$cache_key = "data/tag_cloud-" . md5("tc" . $tags_min . $starts_with) . ".html"; | ||||
| 		if(file_exists($cache_key)) {return file_get_contents($cache_key);} | ||||
| 
 | ||||
| @ -205,6 +213,8 @@ class TagList extends SimpleExtension { | ||||
| 
 | ||||
| 		$tags_min = $this->get_tags_min(); | ||||
| 		$starts_with = $this->get_starts_with(); | ||||
| 		 | ||||
| 		// check if we have a cached version
 | ||||
| 		$cache_key = "data/tag_alpha-" . md5("ta" . $tags_min . $starts_with) . ".html"; | ||||
| 		if(file_exists($cache_key)) {return file_get_contents($cache_key);} | ||||
| 
 | ||||
| @ -239,6 +249,8 @@ class TagList extends SimpleExtension { | ||||
| 		global $database; | ||||
| 
 | ||||
| 		$tags_min = $this->get_tags_min(); | ||||
| 		 | ||||
| 		// check if we have a cached version
 | ||||
| 		$cache_key = "data/tag_popul-" . md5("tp" . $tags_min) . ".html"; | ||||
| 		if(file_exists($cache_key)) {return file_get_contents($cache_key);} | ||||
| 
 | ||||
|  | ||||
| @ -1,7 +1,8 @@ | ||||
| <?php | ||||
| /* | ||||
|  * Name: Database Upgrader | ||||
|  * Author: Shish | ||||
|  * Author: Shish <webmaster@shishnet.org> | ||||
|  * Link: http://code.shishnet.org/shimmie2/ | ||||
|  * Description: Keeps things happy behind the scenes | ||||
|  * Visibility: admin | ||||
|  */ | ||||
| @ -10,6 +11,8 @@ class Upgrade extends SimpleExtension { | ||||
| 	public function onInitExt(InitExtEvent $event) { | ||||
| 		global $config, $database; | ||||
| 
 | ||||
| 		if($config->get_bool("in_upgrade")) return; | ||||
| 
 | ||||
| 		if(!is_numeric($config->get_string("db_version"))) { | ||||
| 			$config->set_int("db_version", 2); | ||||
| 		} | ||||
| @ -18,28 +21,43 @@ class Upgrade extends SimpleExtension { | ||||
| 			// cry :S
 | ||||
| 		} | ||||
| 
 | ||||
| 		if($config->get_int("db_version") < 7) { | ||||
| 			/* | ||||
| 			// mysql-adodb specific
 | ||||
| 			if($database->engine->name == "mysql") { | ||||
| 				$tables = $database->db->MetaTables(); | ||||
| 				foreach($tables as $table) { | ||||
| 					log_info("upgrade", "converting $table to innodb"); | ||||
| 					$database->execute("ALTER TABLE $table TYPE=INNODB"); | ||||
| 				} | ||||
| 			} | ||||
| 			*/ | ||||
| 			$config->set_int("db_version", 7); | ||||
| 			log_info("upgrade", "Database at version 7"); | ||||
| 		} | ||||
| 		// v7 is convert to innodb with adodb
 | ||||
| 		// now done again as v9 with PDO
 | ||||
| 
 | ||||
| 		if($config->get_int("db_version") < 8) { | ||||
| 			// if this fails, don't try again
 | ||||
| 			$config->set_bool("in_upgrade", true); | ||||
| 			$config->set_int("db_version", 8); | ||||
| 			$database->execute($database->engine->scoreql_to_sql( | ||||
| 				"ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" | ||||
| 			)); | ||||
| 			log_info("upgrade", "Database at version 8"); | ||||
| 			$config->set_bool("in_upgrade", false); | ||||
| 		} | ||||
| 
 | ||||
| 		if($config->get_int("db_version") < 9) { | ||||
| 			$config->set_bool("in_upgrade", true); | ||||
| 			if($database->db->getAttribute(PDO::ATTR_DRIVER_NAME) == 'mysql') { | ||||
| 				$tables = $database->get_col("SHOW TABLES"); | ||||
| 				foreach($tables as $table) { | ||||
| 					log_info("upgrade", "converting $table to innodb"); | ||||
| 					$database->execute("ALTER TABLE $table TYPE=INNODB"); | ||||
| 				} | ||||
| 			} | ||||
| 			$config->set_int("db_version", 9); | ||||
| 			log_info("upgrade", "Database at version 9"); | ||||
| 			$config->set_bool("in_upgrade", false); | ||||
| 		} | ||||
| 
 | ||||
| 		if($config->get_int("db_version") < 10) { | ||||
| 			$config->set_bool("in_upgrade", true); | ||||
| 
 | ||||
| 			log_info("upgrade", "Adding foreign keys to images"); | ||||
| 			$database->Execute("ALTER TABLE images ADD CONSTRAINT foreign_images_owner_id FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT"); | ||||
| 		 | ||||
| 			$config->set_int("db_version", 10); | ||||
| 			log_info("upgrade", "Database at version 10"); | ||||
| 			$config->set_bool("in_upgrade", false); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| <?php | ||||
| /* | ||||
| /** | ||||
|  * Name: Uploader | ||||
|  * Author: Shish | ||||
|  * Description: Allows people to upload files to the website | ||||
| @ -122,7 +122,7 @@ class Upload extends SimpleExtension { | ||||
| 			} | ||||
| 			 | ||||
| 			// check if the user is an administrator and can upload files.
 | ||||
| 			if(!$user->is_admin()) { | ||||
| 			if(!$user->can("replace_image")) { | ||||
| 				$this->theme->display_permission_denied($page); | ||||
| 			} | ||||
| 			else { | ||||
| @ -224,14 +224,28 @@ class Upload extends SimpleExtension { | ||||
| 	} | ||||
| // }}}
 | ||||
| // do things {{{
 | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Check if a given user can upload. | ||||
| 	 * @param $user The user to check. | ||||
| 	 * @retval bool | ||||
| 	 */ | ||||
| 	private function can_upload(User $user) { | ||||
| 		global $config; | ||||
| 		return ($config->get_bool("upload_anon") || !$user->is_anonymous()); | ||||
| 	} | ||||
| 
 | ||||
| 	// Helper function based on the one from the online PHP Documentation
 | ||||
| 	// which is licensed under Creative Commons Attribution 3.0 License
 | ||||
| 	// TODO: Make these messages user/admin editable
 | ||||
| 	/** | ||||
| 	 * Returns a descriptive error message for the specified PHP error code. | ||||
| 	 * | ||||
| 	 * This is a helper function based on the one from the online PHP Documentation | ||||
| 	 * which is licensed under Creative Commons Attribution 3.0 License | ||||
| 	 * | ||||
| 	 * TODO: Make these messages user/admin editable | ||||
| 	 * | ||||
| 	 * @param $error_code PHP error code (int) | ||||
| 	 * @retval String | ||||
| 	 */ | ||||
| 	private function upload_error_message($error_code) { | ||||
| 		switch ($error_code) { | ||||
| 			case UPLOAD_ERR_INI_SIZE: | ||||
| @ -253,6 +267,10 @@ class Upload extends SimpleExtension { | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| 	/** | ||||
| 	 * Handle an upload. | ||||
| 	 * @retval bool TRUE on upload successful. | ||||
| 	 */ | ||||
| 	private function try_upload($file, $tags, $source, $replace='') { | ||||
| 		global $page; | ||||
| 		global $config; | ||||
| @ -299,6 +317,10 @@ class Upload extends SimpleExtension { | ||||
| 		return $ok; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Handle an transload. | ||||
| 	 * @retval bool TRUE on transload successful. | ||||
| 	 */ | ||||
| 	private function try_transload($url, $tags, $source, $replace='') { | ||||
| 		global $page; | ||||
| 		global $config; | ||||
| @ -314,7 +336,7 @@ class Upload extends SimpleExtension { | ||||
| 		} | ||||
| 		 | ||||
| 		// Checks if user is admin > check if you want locked.
 | ||||
| 		if($user->is_admin() && !empty($_GET['locked'])){ | ||||
| 		if($user->can("lock_image") && !empty($_GET['locked'])){ | ||||
| 			$locked = bool_escape($_GET['locked']); | ||||
| 		} | ||||
| 		 | ||||
|  | ||||
| @ -158,7 +158,7 @@ class UserPage extends SimpleExtension { | ||||
| 				$this->theme->display_error($page, "Not Logged In", | ||||
| 					"You aren't logged in. First do that, then you can see your stats."); | ||||
| 			} | ||||
| 			else if(!is_null($display_user)) { | ||||
| 			else if(!is_null($display_user) && ($display_user->id != $config->get_int("anon_id"))) { | ||||
| 				send_event(new UserPageBuildingEvent($display_user)); | ||||
| 			} | ||||
| 			else { | ||||
| @ -187,7 +187,7 @@ class UserPage extends SimpleExtension { | ||||
| 			$this->theme->display_user_links($page, $user, $ubbe->parts); | ||||
| 		} | ||||
| 		if( | ||||
| 			($user->is_admin() || ($user->is_logged_in() && $user->id == $event->display_user->id)) && # admin or self-user
 | ||||
| 			($user->can("view_ip") || ($user->is_logged_in() && $user->id == $event->display_user->id)) && # admin or self-user
 | ||||
| 			($event->display_user->id != $config->get_int('anon_id')) # don't show anon's IP list, it is le huge
 | ||||
| 		) { | ||||
| 			$this->theme->display_ip_list( | ||||
| @ -256,7 +256,7 @@ class UserPage extends SimpleExtension { | ||||
| 			$user_id = int_escape($matches[2]); | ||||
| 			$event->add_querylet(new Querylet("images.owner_id = $user_id")); | ||||
| 		} | ||||
| 		else if($user->is_admin() && preg_match("/^(poster|user)_ip=([0-9\.]+)$/i", $event->term, $matches)) { | ||||
| 		else if($user->can("view_ip") && preg_match("/^(poster|user)_ip=([0-9\.]+)$/i", $event->term, $matches)) { | ||||
| 			$user_ip = $matches[2]; // FIXME: ip_escape?
 | ||||
| 			$event->add_querylet(new Querylet("images.owner_ip = '$user_ip'")); | ||||
| 		} | ||||
| @ -354,7 +354,7 @@ class UserPage extends SimpleExtension { | ||||
| 
 | ||||
| 			$duser = User::by_id($id); | ||||
| 
 | ||||
| 			if((!$user->is_admin()) && ($duser->name != $user->name)) { | ||||
| 			if((!$user->can("change_user_info")) && ($duser->name != $user->name)) { | ||||
| 				$this->theme->display_error($page, "Error", | ||||
| 						"You need to be an admin to change other people's passwords"); | ||||
| 			} | ||||
| @ -392,7 +392,7 @@ class UserPage extends SimpleExtension { | ||||
| 
 | ||||
| 			$duser = User::by_id($id); | ||||
| 
 | ||||
| 			if((!$user->is_admin()) && ($duser->name != $user->name)) { | ||||
| 			if((!$user->can("change_user_info")) && ($duser->name != $user->name)) { | ||||
| 				$this->theme->display_error($page, "Error", | ||||
| 						"You need to be an admin to change other people's addressess"); | ||||
| 			} | ||||
| @ -419,7 +419,7 @@ class UserPage extends SimpleExtension { | ||||
| 		$page->set_title("Error"); | ||||
| 		$page->set_heading("Error"); | ||||
| 		$page->add_block(new NavBlock()); | ||||
| 		if(!$user->is_admin()) { | ||||
| 		if(!$user->can("change_user_info")) { | ||||
| 			$page->add_block(new Block("Not Admin", "Only admins can edit accounts")); | ||||
| 		} | ||||
| 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | ||||
| @ -479,7 +479,7 @@ class UserPage extends SimpleExtension { | ||||
| 		$page->set_heading("Error"); | ||||
| 		$page->add_block(new NavBlock()); | ||||
| 		 | ||||
| 		if (!$user->is_admin()) { | ||||
| 		if (!$user->can("delete_user")) { | ||||
| 			$page->add_block(new Block("Not Admin", "Only admins can delete accounts")); | ||||
| 		} | ||||
| 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | ||||
| @ -510,7 +510,7 @@ class UserPage extends SimpleExtension { | ||||
| 		$page->set_heading("Error"); | ||||
| 		$page->add_block(new NavBlock()); | ||||
| 		 | ||||
| 		if (!$user->is_admin()) { | ||||
| 		if (!$user->can("delete_user") || !$user->can("delete_image")) { | ||||
| 			$page->add_block(new Block("Not Admin", "Only admins can delete accounts")); | ||||
| 		} | ||||
| 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | ||||
|  | ||||
| @ -141,7 +141,7 @@ class UserPageTheme extends Themelet { | ||||
| 		$page->add_block(new Block("Stats", join("<br>", $stats), "main", 0)); | ||||
| 
 | ||||
| 		if(!$user->is_anonymous()) { | ||||
| 			if($user->id == $duser->id || $user->is_admin()) { | ||||
| 			if($user->id == $duser->id || $user->can("change_user_info")) { | ||||
| 				$page->add_block(new Block("Options", $this->build_options($duser), "main", 20)); | ||||
| 			} | ||||
| 		} | ||||
| @ -173,7 +173,7 @@ class UserPageTheme extends Themelet { | ||||
| 			</form> | ||||
| 			";
 | ||||
| 
 | ||||
| 			if($user->is_admin()) { | ||||
| 			if($user->can("change_user_info")) { | ||||
| 				$i_user_id = int_escape($duser->id); | ||||
| 				$h_is_admin = $duser->is_admin() ? " checked" : ""; | ||||
| 				$html .= " | ||||
|  | ||||
| @ -90,7 +90,7 @@ class ViewImageTheme extends Themelet { | ||||
| 		$html = ""; | ||||
| 		$html .= "<p>Uploaded by <a href='".make_link("user/$h_owner")."'>$h_owner</a> $h_date"; | ||||
| 
 | ||||
| 		if($user->is_admin()) { | ||||
| 		if($user->can("view_ip")) { | ||||
| 			$html .= " ($h_ip)"; | ||||
| 		} | ||||
| 		if(!is_null($image->source)) { | ||||
|  | ||||
| @ -50,7 +50,7 @@ | ||||
|  * Each of these can be imported at the start of a function with eg "global $page, $user;" | ||||
|  */ | ||||
| 
 | ||||
| if(empty($database_dsn) && !file_exists("config.php")) { | ||||
| if(!file_exists("config.php")) { | ||||
| 	header("Location: install.php"); | ||||
| 	exit; | ||||
| } | ||||
|  | ||||
							
								
								
									
										153
									
								
								install.php
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								install.php
									
									
									
									
									
								
							| @ -1,7 +1,8 @@ | ||||
| <?php ob_start(); ?>
 | ||||
| <html> | ||||
| <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> | ||||
| <html xmlns="http://www.w3.org/1999/xhtml"> | ||||
| <!-- | ||||
|  - install.php (c) Shish 2007 | ||||
|  - install.php (c) Shish et all. 2007-2012 | ||||
|  - | ||||
|  - Initialise the database, check that folder | ||||
|  - permissions are set properly, set an admin | ||||
| @ -12,17 +13,18 @@ | ||||
| --> | ||||
| 	<head> | ||||
| 		<title>Shimmie Installation</title> | ||||
| 		<style> | ||||
| BODY {background: #EEE;font-family: "Arial", sans-serif;font-size: 14px;}
 | ||||
| H1, H3 {border: 1px solid black;background: #DDD;text-align: center;}
 | ||||
| H1 {margin-top: 0px;margin-bottom: 0px;padding: 2px;} | ||||
| H3 {margin-top: 32px;padding: 1px;} | ||||
| FORM {margin: 0px;} | ||||
| A {text-decoration: none;} | ||||
| A:hover {text-decoration: underline;} | ||||
| #block {width: 512px; margin: auto; margin-top: 64px;}
 | ||||
| #iblock {width: 512px; margin: auto; margin-top: 16px;}
 | ||||
| TD INPUT {width: 350px;} | ||||
| 		<link rel="shortcut icon" href="/favicon.ico" /> | ||||
| 		<style type="text/css"> | ||||
| 			BODY {background: #EEE;font-family: "Arial", sans-serif;font-size: 14px;}
 | ||||
| 			H1, H3 {border: 1px solid black;background: #DDD;text-align: center;}
 | ||||
| 			H1 {margin-top: 0px;margin-bottom: 0px;padding: 2px;} | ||||
| 			H3 {margin-top: 32px;padding: 1px;} | ||||
| 			FORM {margin: 0px;} | ||||
| 			A {text-decoration: none;} | ||||
| 			A:hover {text-decoration: underline;} | ||||
| 			#block {width: 512px; margin: auto; margin-top: 64px;}
 | ||||
| 			#iblock {width: 512px; margin: auto; margin-top: 16px;}
 | ||||
| 			TD INPUT {width: 350px;} | ||||
| 		</style> | ||||
| 	</head> | ||||
| 	<body> | ||||
| @ -31,9 +33,10 @@ TD INPUT {width: 350px;} | ||||
| 			<h1>Install Error</h1> | ||||
| 			<p>Shimmie needs to be run via a web server with PHP support -- you | ||||
| 			appear to be either opening the file from your hard disk, or your | ||||
| 			web server is mis-configured. | ||||
| 			web server is mis-configured.</p> | ||||
| 			<p>If you've installed a web server on your desktop PC, you probably | ||||
| 			want to visit <a href="http://localhost/">the local web server</a>. | ||||
| 			want to visit <a href="http://localhost/">the local web server</a>.<br/><br/> | ||||
| 			</p> | ||||
| 		</div> | ||||
| 		<div style="display: none;"> | ||||
| 			<PLAINTEXT> | ||||
| @ -51,9 +54,32 @@ if(is_readable("config.php")) { | ||||
| 		<div id="iblock"> | ||||
| 			<h1>Shimmie Repair Console</h1> | ||||
| <?php | ||||
| 	include "config.php"; | ||||
| 	if($_SESSION['dsn'] == DATABASE_DSN || $_POST['dsn'] == DATABASE_DSN) { | ||||
| 		if($_POST['dsn']) {$_SESSION['dsn'] = $_POST['dsn'];} | ||||
| 
 | ||||
| 	/* | ||||
| 	 * Compute the path to the folder containing "install.php" and  | ||||
| 	 * store it as the 'Shimmie Root' folder for later on. | ||||
| 	 * | ||||
| 	 * Example: | ||||
| 	 *	__SHIMMIE_ROOT__ = '/var/www/shimmie2/' | ||||
| 	 * | ||||
| 	 */ | ||||
| 	define('__SHIMMIE_ROOT__', trim( remove_trailing_slash( dirname(__FILE__) ) ) . '/' );  | ||||
| 
 | ||||
| 	// Pull in necessary files
 | ||||
| 	require_once __SHIMMIE_ROOT__."config.php";			// Load user/site specifics First
 | ||||
| 	require_once __SHIMMIE_ROOT__."core/default_config.inc.php";	// Defaults for the rest.
 | ||||
| 	require_once __SHIMMIE_ROOT__."core/util.inc.php"; | ||||
| 	require_once __SHIMMIE_ROOT__."core/database.class.php"; | ||||
| 	 | ||||
| 	if ( | ||||
| 	      ( array_key_exists('dsn', $_SESSION) && $_SESSION['dsn'] === DATABASE_DSN ) || | ||||
| 	      ( array_key_exists('dsn', $_POST)    && $_POST['dsn']    === DATABASE_DSN ) | ||||
| 	   ) | ||||
| 	{ | ||||
| 		if ( array_key_exists('dsn', $_POST) && !empty($_POST['dsn']) ) | ||||
| 		{ | ||||
| 		    $_SESSION['dsn'] = $_POST['dsn']; | ||||
| 		} | ||||
| 
 | ||||
| 		if(empty($_GET["action"])) { | ||||
| 			echo "<h3>Basic Checks</h3>"; | ||||
| @ -76,15 +102,6 @@ if(is_readable("config.php")) { | ||||
| 				</form> | ||||
| 			";
 | ||||
| 			*/ | ||||
| 			echo "<h3>Database quick  fix for User deletion</h3>"; | ||||
| 			echo "just a database fix for those who instaled shimmie before 2012 january the 22rd.<br>"; | ||||
| 			echo "Note: some things needs to be done manually, to work properly.<br>"; | ||||
| 			echo "WARNING: ONLY  PROCEEDS IF YOU KNOW WHAT YOU ARE DOING!"; | ||||
| 			echo " | ||||
| 				<form action='install.php?action=Database_user_deletion_fix' method='POST'> | ||||
| 					<input type='submit' value='go!'> | ||||
| 				</form> | ||||
| 			";
 | ||||
| 
 | ||||
| 			echo "<h3>Log Out</h3>"; | ||||
| 			echo " | ||||
| @ -95,15 +112,12 @@ if(is_readable("config.php")) { | ||||
| 		} | ||||
| 		else if($_GET["action"] == "logout") { | ||||
| 			session_destroy(); | ||||
| 		} | ||||
| 		else if($_GET["action"] == "Database_user_deletion_fix") { | ||||
| 			Database_user_deletion_fix(); | ||||
| 			echo "<h3>Logged Out</h3><p>You have been logged out.</p><a href='index.php'>Main Shimmie Page</a>"; | ||||
| 		} | ||||
| 	} else { | ||||
| 		echo " | ||||
| 			<h3>Login</h3> | ||||
| 			Enter the database DSN exactly as in config.php (ie, as originally | ||||
| 			installed) to access advanced recovery tools: | ||||
| 			<p>Enter the database DSN exactly as in config.php (ie, as originally installed) to access advanced recovery tools:</p> | ||||
| 
 | ||||
| 			<form action='install.php' method='POST'> | ||||
| 				<center> | ||||
| @ -118,13 +132,24 @@ if(is_readable("config.php")) { | ||||
| 	echo "\t\t</div>"; | ||||
| 	exit; | ||||
| } | ||||
| require_once "core/compat.inc.php"; | ||||
| require_once "core/util.inc.php"; | ||||
| require_once "core/database.class.php"; | ||||
| 
 | ||||
| do_install(); | ||||
| 
 | ||||
| // utilities {{{
 | ||||
| 
 | ||||
| /** | ||||
|   * Strips off any kind of slash at the end so as to normalise the path. | ||||
|   * @param string $path    Path to normalise. | ||||
|   * @return string         Path without trailing slash. | ||||
|   */ | ||||
| function remove_trailing_slash($path) { | ||||
| 	if ((substr($path, -1) === '/') || (substr($path, -1) === '\\')) { | ||||
| 		return substr($path, 0, -1); | ||||
| 	} else { | ||||
| 		return $path; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function check_gd_version() { | ||||
| 	$gdversion = 0; | ||||
| 
 | ||||
| @ -249,7 +274,7 @@ function begin() { // {{{ | ||||
| 			<h3>Help</h3> | ||||
| 					 | ||||
| 			<p>Please make sure the database you have chosen exists and is empty.<br> | ||||
| 			The username provided must have access to create tables within the database. | ||||
| 			The username provided must have access to create tables within the database.</p> | ||||
| 			 | ||||
| 		</div> | ||||
| EOD; | ||||
| @ -315,7 +340,7 @@ function create_tables() { // {{{ | ||||
| 			CONSTRAINT foreign_image_tags_image_id FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE, | ||||
| 			CONSTRAINT foreign_image_tags_tag_id FOREIGN KEY (tag_id) REFERENCES tags(id) ON DELETE CASCADE | ||||
| 		");
 | ||||
| 		$db->execute("INSERT INTO config(name, value) VALUES('db_version', 8)"); | ||||
| 		$db->execute("INSERT INTO config(name, value) VALUES('db_version', 10)"); | ||||
| 	} | ||||
| 	catch (PDOException $e) | ||||
| 	{ | ||||
| @ -354,11 +379,12 @@ function build_dirs() { // {{{ | ||||
| 			!file_exists("images") || !file_exists("thumbs") || !file_exists("data") || | ||||
| 			!is_writable("images") || !is_writable("thumbs") || !is_writable("data") | ||||
| 	) { | ||||
| 		print "Shimmie needs three folders in it's directory, 'images', 'thumbs', and 'data',
 | ||||
| 		       and they need to be writable by the PHP user (if you see this error, | ||||
| 			   if probably means the folders are owned by you, and they need to be | ||||
| 			   writable by the web server). | ||||
| 			   <p>Once you have created these folders, hit 'refresh' to continue.";
 | ||||
| 		print "<p>Shimmie needs three folders in it's directory, 'images', 'thumbs', and 'data',
 | ||||
| 		       and they need to be writable by the PHP user.</p> | ||||
| 			   <p>If you see this error, if probably means the folders are owned by you, and they need to be | ||||
| 			   writable by the web server.</p> | ||||
| 			   <p>PHP reports that it is currently running as user: ".$_ENV["USER"]." (". $_SERVER["USER"] .")</p> | ||||
| 			   <p>Once you have created these folders and/or changed the ownership of the shimmie folder, hit 'refresh' to continue.</p>";
 | ||||
| 		exit; | ||||
| 	} | ||||
| } // }}}
 | ||||
| @ -387,49 +413,6 @@ EOD; | ||||
| 		exit; | ||||
| 	} | ||||
| } // }}}
 | ||||
| 
 | ||||
| function Database_user_deletion_fix() { | ||||
| 	try { | ||||
| 		require_once "core/database.class.php"; | ||||
| 		$db = new Database(); | ||||
| 		 | ||||
| 		echo "Fixing user_favorites table...."; | ||||
| 		 | ||||
| 		($db->Execute("ALTER TABLE user_favorites ENGINE=InnoDB;")) ? print_r("ok<br>") : print_r("failed<br>"); | ||||
| 		echo "adding Foreign key to user ids..."; | ||||
| 		 | ||||
| 		($db->Execute("ALTER TABLE user_favorites ADD CONSTRAINT foreign_user_favorites_user_id FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;"))? print_r("ok<br>"):print_r("failed<br>"); | ||||
| 		echo "cleaning, the table from deleted image favorites...<br>"; | ||||
| 		 | ||||
| 		$rows = $db->get_all("SELECT * FROM user_favorites WHERE image_id NOT IN ( SELECT id FROM images );"); | ||||
| 		 | ||||
| 		foreach( $rows as $key => $value) | ||||
| 			$db->Execute("DELETE FROM user_favorites WHERE image_id = :image_id;", array("image_id" => $value["image_id"])); | ||||
| 		 | ||||
| 		echo "adding forign key to image ids..."; | ||||
| 		 | ||||
| 		($db->Execute("ALTER TABLE user_favorites ADD CONSTRAINT user_favorites_image_id FOREIGN KEY (image_id) REFERENCES images(id) ON DELETE CASCADE;"))? print_r("ok<br>"):print_r("failed<br>"); | ||||
| 		 | ||||
| 		echo "adding foreign keys to private messages..."; | ||||
| 		 | ||||
| 		($db->Execute("ALTER TABLE private_message 
 | ||||
| 		ADD CONSTRAINT foreign_private_message_from_id FOREIGN KEY (from_id) REFERENCES users(id) ON DELETE CASCADE, | ||||
| 		ADD CONSTRAINT foreign_private_message_to_id FOREIGN KEY (to_id) REFERENCES users(id) ON DELETE CASCADE;")) ? print_r("ok<br>"):print_r("failed<br>");
 | ||||
| 		 | ||||
| 		echo "Just one more step...which you need to do manually:<br>"; | ||||
| 		echo "You need to go to your database and Delete the foreign key on the owner_id in the images table.<br><br>"; | ||||
| 		echo "<a href='http://www.justin-cook.com/wp/2006/05/09/how-to-remove-foreign-keys-in-mysql/'>How to remove foreign keys</a><br><br>"; | ||||
| 		echo "and finally execute this querry:<br><br>"; | ||||
| 		echo "ALTER TABLE images ADD CONSTRAINT foreign_images_owner_id FOREIGN KEY (owner_id) REFERENCES users(id) ON DELETE RESTRICT;<br><br>"; | ||||
| 		echo "if this is all sucesfull you are done!"; | ||||
| 
 | ||||
| 	} | ||||
| 	catch (PDOException $e) | ||||
| 	{ | ||||
| 		// FIXME: Make the error message user friendly
 | ||||
| 		exit($e->getMessage()); | ||||
| 	} | ||||
| } | ||||
| ?>
 | ||||
| 	</body> | ||||
| </html> | ||||
|  | ||||
| @ -27,70 +27,25 @@ $(document).ready(function() { | ||||
| 	}); | ||||
| 	 | ||||
| 	$("time").timeago(); | ||||
| }); | ||||
| 
 | ||||
| var defaultTexts = new Array(); | ||||
| 	$('.search_input').DefaultValue('Search'); | ||||
| 	$('#search_input').autocomplete(base_href + '/api/internal/tag_list/complete', { | ||||
| 		width: 320, | ||||
| 		max: 15, | ||||
| 		highlight: false, | ||||
| 		multiple: true, | ||||
| 		multipleSeparator: ' ', | ||||
| 		scroll: true, | ||||
| 		scrollHeight: 300, | ||||
| 		selectFirst: false | ||||
| 	}); | ||||
| 
 | ||||
| window.onload = function(e) { | ||||
| 	var sections=get_sections(); | ||||
| 	for(var i=0;i<sections.length;i++) toggle(sections[i]); | ||||
| 
 | ||||
| 	initGray("search_input", "Search"); | ||||
| 	initGray("commentBox", "Comment"); | ||||
| 	initGray("tagBox", "tagme"); | ||||
| 	 | ||||
| 	// if we're going to show with JS, hide with JS first
 | ||||
| 	pass_confirm = byId("pass_confirm"); | ||||
| 	if(pass_confirm) { | ||||
| 		pass_confirm.style.display = "none"; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function initGray(boxname, text) { | ||||
| 	var box = byId(boxname); | ||||
| 	if(!box) return; | ||||
| 
 | ||||
| 	var clr = function () {cleargray(box, text);}; | ||||
| 	var set = function () {setgray(box, text);}; | ||||
| 
 | ||||
| 	addEvent(box, "focus", clr, false); | ||||
| 	addEvent(box, "blur",  set, false); | ||||
| 
 | ||||
| 	if(box.value == text) { | ||||
| 		box.style.color = "#999"; | ||||
| 		box.style.textAlign = "center"; | ||||
| 	} | ||||
| 	else { | ||||
| 		box.style.color = "#000"; | ||||
| 		box.style.textAlign = "left"; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function cleargray(box, text) { | ||||
| 	if(box.value == text) { | ||||
| 		box.value = ""; | ||||
| 		box.style.color = "#000"; | ||||
| 		box.style.textAlign = "left"; | ||||
| 	} | ||||
| } | ||||
| function setgray(box, text) { | ||||
| 	if(box.value == "") { | ||||
| 		box.style.textAlign = "center"; | ||||
| 		box.style.color = "gray"; | ||||
| 		box.value = text; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function showUp(elem) { | ||||
| 	e = document.getElementById(elem) | ||||
| 	if(!e) return; | ||||
| 	e.style.display = ""; | ||||
| //	alert(e.type+": "+e.value);
 | ||||
| 	if(e.value.match(/^http|^ftp/)) { | ||||
| 		e.type = "text"; | ||||
| 		alert("Box is web upload"); | ||||
| 	} | ||||
| } | ||||
| 	$("#commentBox").DefaultValue("Comment"); | ||||
| 	$("#tagBox").DefaultValue("tagme"); | ||||
| }); | ||||
| 
 | ||||
| 
 | ||||
| /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ | ||||
| @ -111,6 +66,7 @@ function byId(id) { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| // used once in ext/setup/main
 | ||||
| function getHTTPObject() {  | ||||
| 	if (window.XMLHttpRequest){ | ||||
| 		return new XMLHttpRequest(); | ||||
| @ -120,15 +76,6 @@ function getHTTPObject() { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function ajaxRequest(url, callback) { | ||||
| 	var http = getHTTPObject(); | ||||
| 	http.open("GET", url, true); | ||||
| 	http.onreadystatechange = function() { | ||||
| 		if(http.readyState == 4) callback(http.responseText); | ||||
| 	} | ||||
| 	http.send(null); | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* get, set, and delete cookies */ | ||||
| function getCookie( name ) { | ||||
| @ -164,3 +111,10 @@ function deleteCookie( name, path, domain ) { | ||||
| 			";expires=Thu, 01-Jan-1970 00:00:01 GMT"; | ||||
| } | ||||
| 
 | ||||
| function replyTo(imageId, commentId) { | ||||
| 	var box = $("#comment_on_"+imageId); | ||||
| 	var text = ">>"+imageId+"#"+commentId+": "; | ||||
| 
 | ||||
| 	box.focus(); | ||||
| 	box.val(box.val() + text); | ||||
| } | ||||
|  | ||||
| @ -223,7 +223,9 @@ $header_html | ||||
|         <em> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept. | ||||
| 			$debug | ||||
| 			$contact | ||||
|  | ||||
| @ -71,7 +71,9 @@ $header_html | ||||
| 		<div id="footer"> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept. | ||||
| 			$debug | ||||
| 			$contact | ||||
|  | ||||
| @ -128,9 +128,8 @@ UL { | ||||
| .comment { | ||||
| 	text-align: left; | ||||
| } | ||||
| .comment .timeago { | ||||
| 	float: right; | ||||
| 	font-size: 75%; | ||||
| .comment .info { | ||||
| 	display: none; | ||||
| } | ||||
| 
 | ||||
| .more:after { | ||||
|  | ||||
| @ -71,7 +71,9 @@ $header_html | ||||
| 		<div id="footer"> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept. | ||||
| 			$debug | ||||
| 			$contact | ||||
|  | ||||
| @ -79,7 +79,9 @@ $header_html | ||||
| 			<hr> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept. | ||||
| 			<br>Futaba theme based on 4chan's layout and CSS :3 | ||||
| 			$debug | ||||
|  | ||||
| @ -184,7 +184,9 @@ class Layout { | ||||
| 		<div id="footer"> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept.<br /> | ||||
| 			Lite Theme by <a href="http://seemslegit.com">Zach</a> | ||||
| 			$debug | ||||
|  | ||||
| @ -69,7 +69,9 @@ $header_html | ||||
| 			<hr> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept. | ||||
| 			$debug | ||||
| 			$contact | ||||
|  | ||||
| @ -85,7 +85,9 @@ $header_html | ||||
| 		<div id="footer"> | ||||
| 			Images © their respective owners, | ||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & Co 2007-2012, | ||||
| 			<a href="http://www.shishnet.org/">Shish</a> & | ||||
| 			<a href="https://github.com/shish/shimmie2/contributors">The Team</a> | ||||
| 			2007-2012, | ||||
| 			based on the Danbooru concept. | ||||
| 			$debug | ||||
| 			$contact | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user