Merge branch 'master' into speed_tweaks
This commit is contained in:
		
						commit
						d69fa6ae9d
					
				| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: Comment Word Ban |  * Name: Comment Word Ban | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: For stopping spam and other comment abuse |  * Description: For stopping spam and other comment abuse | ||||||
|  * Documentation: |  * Documentation: | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: Bulk Add |  * Name: Bulk Add | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Bulk add server-side images |  * Description: Bulk add server-side images | ||||||
|  * Documentation: |  * Documentation: | ||||||
| @ -30,7 +31,9 @@ class BulkAdd extends SimpleExtension { | |||||||
| 		$this->theme->display_admin_block(); | 		$this->theme->display_admin_block(); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 	/** | ||||||
|  | 	 * Generate the necessary DataUploadEvent for a given image and tags. | ||||||
|  | 	 */ | ||||||
| 	private function add_image($tmpname, $filename, $tags) { | 	private function add_image($tmpname, $filename, $tags) { | ||||||
| 		assert(file_exists($tmpname)); | 		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() { | 	private function get_info() { | ||||||
| 		global $config, $database; | 		global $config, $database; | ||||||
| 		global $_event_listeners; // yay for using secret globals \o/
 | 		global $_event_listeners; // yay for using secret globals \o/
 | ||||||
|  | |||||||
| @ -152,6 +152,17 @@ class Favorites extends SimpleExtension { | |||||||
| 			");
 | 			");
 | ||||||
| 			$config->set_int("ext_favorites_version", 1); | 			$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) { | 	private function add_vote($image_id, $user_id, $do_set) { | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: Featured Image |  * Name: Featured Image | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Bring a specific image to the users' attentions |  * Description: Bring a specific image to the users' attentions | ||||||
|  * Documentation: |  * Documentation: | ||||||
|  | |||||||
| @ -2,7 +2,8 @@ | |||||||
| /* | /* | ||||||
|  * Name: Handle Flash |  * Name: Handle Flash | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * 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 { | class FlashFileHandler extends DataHandlerExtension { | ||||||
|  | |||||||
| @ -2,7 +2,8 @@ | |||||||
| /* | /* | ||||||
|  * Name: Handle SVG |  * Name: Handle SVG | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * 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 { | class SVGFileHandler implements Extension { | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: IP Ban |  * Name: IP Ban | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Ban IP addresses |  * Description: Ban IP addresses | ||||||
|  * Documentation: |  * Documentation: | ||||||
| @ -92,7 +93,7 @@ class IPBan extends SimpleExtension { | |||||||
| 	public function onRemoveIPBan($event) { | 	public function onRemoveIPBan($event) { | ||||||
| 		global $database; | 		global $database; | ||||||
| 		$database->Execute("DELETE FROM bans WHERE id = :id", array("id"=>$event->id)); | 		$database->Execute("DELETE FROM bans WHERE id = :id", array("id"=>$event->id)); | ||||||
| 		$database->cache->delete("ip_bans"); | 		$database->cache->delete("ip_bans_sorted"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| // installer {{{
 | // installer {{{
 | ||||||
| @ -261,7 +262,7 @@ class IPBan extends SimpleExtension { | |||||||
| 		global $database; | 		global $database; | ||||||
| 		$sql = "INSERT INTO bans (ip, reason, end_timestamp, banner_id) VALUES (:ip, :reason, :end, :admin_id)"; | 		$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->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'"); | 		log_info("ipban", "'$user->name' has banned '$ip' because '$reason' until '$end'"); | ||||||
| 	} | 	} | ||||||
| // }}}
 | // }}}
 | ||||||
|  | |||||||
| @ -1,8 +1,9 @@ | |||||||
| <?php | <?php | ||||||
| /* | /* | ||||||
|  * Name: Logging (Database) |  * Name: Logging (Database) | ||||||
|  * Author: Shish |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  * Description: Keep a record of SCore events |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  |  * Description: Keep a record of SCore events (in the database). | ||||||
|  * Visibility: admin |  * Visibility: admin | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: News |  * Name: News | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Show a short amount of text in a block on the post list |  * Description: Show a short amount of text in a block on the post list | ||||||
|  * Documentation: |  * 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) |  * Name: Image Scores (Numeric) | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Allow users to score images |  * Description: Allow users to score images | ||||||
|  * Documentation: |  * Documentation: | ||||||
|  | |||||||
| @ -57,11 +57,24 @@ class PrivMsg extends SimpleExtension { | |||||||
| 				subject VARCHAR(64) NOT NULL, | 				subject VARCHAR(64) NOT NULL, | ||||||
| 				message TEXT NOT NULL, | 				message TEXT NOT NULL, | ||||||
| 				is_read SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N, | 				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); | 			$config->set_int("pm_version", 1); | ||||||
| 			log_info("pm", "extension installed"); | 			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 |  * Name: Random Image | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Do things with a random image |  * Description: Do things with a random image | ||||||
|  * Documentation: |  * Documentation: | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: Image Ratings |  * Name: Image Ratings | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Allow users to rate images "safe", "questionable" or "explicit" |  * Description: Allow users to rate images "safe", "questionable" or "explicit" | ||||||
|  */ |  */ | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: Regen Thumb |  * Name: Regen Thumb | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Description: Regenerate a thumbnail image |  * Description: Regenerate a thumbnail image | ||||||
|  * Documentation: |  * Documentation: | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ | |||||||
| /* | /* | ||||||
|  * Name: Site Description |  * Name: Site Description | ||||||
|  * Author: Shish <webmaster@shishnet.org> |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * License: GPLv2 |  * License: GPLv2 | ||||||
|  * Visibility: admin |  * Visibility: admin | ||||||
|  * Description: A description for search engines |  * 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 | 	 * so that the next time a page is loaded it will use the new | ||||||
| 	 * configuration | 	 * configuration | ||||||
| 	 */ | 	 */ | ||||||
| 	public function save($name=null); | 	public function save(/*string*/ $name=null); | ||||||
| 
 | 
 | ||||||
| 	/** @name set_* | 	/** @name set_* | ||||||
| 	 * Set a configuration option to a new value, regardless | 	 * Set a configuration option to a new value, regardless | ||||||
| 	 * of what the value is at the moment | 	 * of what the value is at the moment | ||||||
| 	 */ | 	 */ | ||||||
| 	//@{
 | 	//@{
 | ||||||
| 	public function set_int($name, $value); | 	public function set_int(/*string*/ $name, $value); | ||||||
| 	public function set_string($name, $value); | 	public function set_string(/*string*/ $name, $value); | ||||||
| 	public function set_bool($name, $value); | 	public function set_bool(/*string*/ $name, $value); | ||||||
| 	public function set_array($name, $value); | 	public function set_array(/*string*/ $name, $value); | ||||||
| 	//@}
 | 	//@}
 | ||||||
| 
 | 
 | ||||||
| 	/** @name set_default_* | 	/** @name set_default_* | ||||||
| @ -30,10 +30,10 @@ interface Config { | |||||||
| 	 * "default" paramater won't show up. | 	 * "default" paramater won't show up. | ||||||
| 	 */ | 	 */ | ||||||
| 	//@{
 | 	//@{
 | ||||||
| 	public function set_default_int($name, $value); | 	public function set_default_int(/*string*/ $name, $value); | ||||||
| 	public function set_default_string($name, $value); | 	public function set_default_string(/*string*/ $name, $value); | ||||||
| 	public function set_default_bool($name, $value); | 	public function set_default_bool(/*string*/ $name, $value); | ||||||
| 	public function set_default_array($name, $value); | 	public function set_default_array(/*string*/ $name, $value); | ||||||
| 	//@}
 | 	//@}
 | ||||||
| 
 | 
 | ||||||
| 	/** @name get_* | 	/** @name get_* | ||||||
| @ -41,10 +41,10 @@ interface Config { | |||||||
| 	 * appropritate data type | 	 * appropritate data type | ||||||
| 	 */ | 	 */ | ||||||
| 	//@{
 | 	//@{
 | ||||||
| 	public function get_int($name, $default=null); | 	public function get_int(/*string*/ $name, $default=null); | ||||||
| 	public function get_string($name, $default=null); | 	public function get_string(/*string*/ $name, $default=null); | ||||||
| 	public function get_bool($name, $default=null); | 	public function get_bool(/*string*/ $name, $default=null); | ||||||
| 	public function get_array($name, $default=array()); | 	public function get_array(/*string*/ $name, $default=array()); | ||||||
| 	//@}
 | 	//@}
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -56,60 +56,60 @@ interface Config { | |||||||
| abstract class BaseConfig implements Config { | abstract class BaseConfig implements Config { | ||||||
| 	var $values = array(); | 	var $values = array(); | ||||||
| 
 | 
 | ||||||
| 	public function set_int($name, $value) { | 	public function set_int(/*string*/ $name, $value) { | ||||||
| 		$this->values[$name] = parse_shorthand_int($value); | 		$this->values[$name] = parse_shorthand_int($value); | ||||||
| 		$this->save($name); | 		$this->save($name); | ||||||
| 	} | 	} | ||||||
| 	public function set_string($name, $value) { | 	public function set_string(/*string*/ $name, $value) { | ||||||
| 		$this->values[$name] = $value; | 		$this->values[$name] = $value; | ||||||
| 		$this->save($name); | 		$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->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N'); | ||||||
| 		$this->save($name); | 		$this->save($name); | ||||||
| 	} | 	} | ||||||
| 	public function set_array($name, $value) { | 	public function set_array(/*string*/ $name, $value) { | ||||||
| 		assert(is_array($value)); | 		assert(is_array($value)); | ||||||
| 		$this->values[$name] = implode(",", $value); | 		$this->values[$name] = implode(",", $value); | ||||||
| 		$this->save($name); | 		$this->save($name); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public function set_default_int($name, $value) { | 	public function set_default_int(/*string*/ $name, $value) { | ||||||
| 		if(is_null($this->get($name))) { | 		if(is_null($this->get($name))) { | ||||||
| 			$this->values[$name] = parse_shorthand_int($value); | 			$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))) { | 		if(is_null($this->get($name))) { | ||||||
| 			$this->values[$name] = $value; | 			$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))) { | 		if(is_null($this->get($name))) { | ||||||
| 			$this->values[$name] = (($value == 'on' || $value === true) ? 'Y' : 'N'); | 			$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)); | 		assert(is_array($value)); | ||||||
| 		if(is_null($this->get($name))) { | 		if(is_null($this->get($name))) { | ||||||
| 			$this->values[$name] = implode(",", $value); | 			$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)); | 		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); | 		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)); | 		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, "")); | 		return explode(",", $this->get($name, "")); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	private function get($name, $default=null) { | 	private function get(/*string*/ $name, $default=null) { | ||||||
| 		if(isset($this->values[$name])) { | 		if(isset($this->values[$name])) { | ||||||
| 			return $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
 | 		// static config is static
 | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| @ -167,7 +167,7 @@ class DatabaseConfig extends BaseConfig { | |||||||
| 	/* | 	/* | ||||||
| 	 * Load the config table from a database | 	 * Load the config table from a database | ||||||
| 	 */ | 	 */ | ||||||
| 	public function DatabaseConfig($database) { | 	public function DatabaseConfig(Database $database) { | ||||||
| 		$this->database = $database; | 		$this->database = $database; | ||||||
| 
 | 
 | ||||||
| 		$cached = $this->database->cache->get("config"); | 		$cached = $this->database->cache->get("config"); | ||||||
| @ -186,11 +186,11 @@ class DatabaseConfig extends BaseConfig { | |||||||
| 	/* | 	/* | ||||||
| 	 * Save the current values as the new config table | 	 * Save the current values as the new config table | ||||||
| 	 */ | 	 */ | ||||||
| 	public function save($name=null) { | 	public function save(/*string*/ $name=null) { | ||||||
| 		if(is_null($name)) { | 		if(is_null($name)) { | ||||||
| 			reset($this->values); // rewind the array to the first element
 | 			reset($this->values); // rewind the array to the first element
 | ||||||
| 			foreach($this->values as $name => $value) { | 			foreach($this->values as $name => $value) { | ||||||
| 				$this->save($name); | 				$this->save(/*string*/ $name); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
|  | |||||||
| @ -310,7 +310,7 @@ class Database { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		$matches = array(); | 		$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") { | 			if($matches[1] == "memcache") { | ||||||
| 				$this->cache = new MemcacheCache($matches[2]); | 				$this->cache = new MemcacheCache($matches[2]); | ||||||
| 			} | 			} | ||||||
|  | |||||||
| @ -39,6 +39,8 @@ class PageRequestEvent extends Event { | |||||||
| 	 * Test if the requested path matches a given pattern. | 	 * Test if the requested path matches a given pattern. | ||||||
| 	 * | 	 * | ||||||
| 	 * If it matches, store the remaining path elements in $args | 	 * If it matches, store the remaining path elements in $args | ||||||
|  | 	 * | ||||||
|  | 	 * @retval bool | ||||||
| 	 */ | 	 */ | ||||||
| 	public function page_matches(/*string*/ $name) { | 	public function page_matches(/*string*/ $name) { | ||||||
| 		$parts = explode("/", $name); | 		$parts = explode("/", $name); | ||||||
| @ -57,6 +59,11 @@ class PageRequestEvent extends Event { | |||||||
| 		return true; | 		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) { | 	public function get_arg(/*int*/ $n) { | ||||||
| 		$offset = $this->part_count + $n; | 		$offset = $this->part_count + $n; | ||||||
| 		if($offset >= 0 && $offset < $this->arg_count) { | 		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() { | 	public function count_args() { | ||||||
| 		return (int)($this->arg_count - $this->part_count); | 		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($this->supported_ext($event->type)) { | ||||||
| 			if (method_exists($this, 'create_thumb_force') && $event->force == true) { | 			if (method_exists($this, 'create_thumb_force') && $event->force == true) { | ||||||
| 				 $this->create_thumb_force($event->hash); | 				 $this->create_thumb_force($event->hash); | ||||||
|  | |||||||
| @ -106,18 +106,26 @@ class Image { | |||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Search for an array of images | 	 * 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($start)); | ||||||
| 		assert(is_numeric($limit)); | 		assert(is_numeric($limit)); | ||||||
| 		assert(is_array($tags)); | 		assert(is_array($tags)); | ||||||
| 		global $database; | 		global $database, $user; | ||||||
| 
 | 
 | ||||||
| 		$images = array(); | 		$images = array(); | ||||||
| 
 | 
 | ||||||
| 		if($start < 0) $start = 0; | 		if($start < 0) $start = 0; | ||||||
| 		if($limit < 1) $limit = 1; | 		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 = Image::build_search_querylet($tags); | ||||||
| 		$querylet->append(new Querylet("ORDER BY images.id DESC LIMIT :limit OFFSET :offset", array("limit"=>$limit, "offset"=>$start))); | 		$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);
 | 		#var_dump($querylet->sql); var_dump($querylet->variables);
 | ||||||
| @ -377,7 +385,7 @@ class Image { | |||||||
| 	/** | 	/** | ||||||
| 	 * Set the image's source URL | 	 * Set the image's source URL | ||||||
| 	 */ | 	 */ | ||||||
| 	public function set_source($source) { | 	public function set_source(/*string*/ $source) { | ||||||
| 		global $database; | 		global $database; | ||||||
| 		if(empty($source)) $source = null; | 		if(empty($source)) $source = null; | ||||||
| 		if($source != $this->source) { | 		if($source != $this->source) { | ||||||
| @ -386,7 +394,10 @@ class Image { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 
 | 	/** | ||||||
|  | 	 * Check if the image is locked. | ||||||
|  | 	 * @retval bool | ||||||
|  | 	 */ | ||||||
| 	public function is_locked() { | 	public function is_locked() { | ||||||
| 		return ($this->locked === true || $this->locked == "Y" || $this->locked == "t"); | 		return ($this->locked === true || $this->locked == "Y" || $this->locked == "t"); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -39,7 +39,7 @@ class Page { | |||||||
| 	/** @private */ | 	/** @private */ | ||||||
| 	var $mode = "page"; | 	var $mode = "page"; | ||||||
| 	/** @private */ | 	/** @private */ | ||||||
| 	var $type = "text/html"; | 	var $type = "text/html; charset=utf-8"; | ||||||
| 
 | 
 | ||||||
| 	/** | 	/** | ||||||
| 	 * Set what this page should do; "page", "data", or "redirect". | 	 * Set what this page should do; "page", "data", or "redirect". | ||||||
| @ -196,8 +196,8 @@ class Page { | |||||||
| 
 | 
 | ||||||
| 		switch($this->mode) { | 		switch($this->mode) { | ||||||
| 			case "page": | 			case "page": | ||||||
| 				header("Vary: Cookie, Accept-Encoding"); |  | ||||||
| 				if(CACHE_HTTP) { | 				if(CACHE_HTTP) { | ||||||
|  | 					header("Vary: Cookie, Accept-Encoding"); | ||||||
| 					if($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { | 					if($user->is_anonymous() && $_SERVER["REQUEST_METHOD"] == "GET") { | ||||||
| 						header("Cache-control: public, max-age=600"); | 						header("Cache-control: public, max-age=600"); | ||||||
| 						header('Expires: ' . gmdate('D, d M Y H:i:s', time() + 600) . ' GMT'); | 						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() { | 	protected function add_auto_html_headers() { | ||||||
| 		$data_href = get_base_href(); | 		$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 */ | 		/* Attempt to cache the CSS & JavaScript files */ | ||||||
| 		if ($this->add_cached_auto_html_headers() === FALSE) { | 		if ($this->add_cached_auto_html_headers() === FALSE) { | ||||||
| 			// caching failed, add all files to html_headers.
 | 			// caching failed, add all files to html_headers.
 | ||||||
|  | |||||||
| @ -4,6 +4,7 @@ function _new_user($row) { | |||||||
| 	return new User($row); | 	return new User($row); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /** | /** | ||||||
|  * An object representing a row in the "users" table. |  * An object representing a row in the "users" table. | ||||||
|  * |  * | ||||||
| @ -90,6 +91,77 @@ class User { | |||||||
| 	/* | 	/* | ||||||
| 	 * useful user object functions start here | 	 * 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) | 	 * 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 | 	 * 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 | 	 * a local file, a remote file, a gravatar, a something else, etc | ||||||
|  | 	 * @retval String of HTML | ||||||
| 	 */ | 	 */ | ||||||
| 	public function get_avatar_html() { | 	public function get_avatar_html() { | ||||||
| 		// FIXME: configurable
 | 		// FIXME: configurable
 | ||||||
| @ -170,6 +243,8 @@ class User { | |||||||
| 	 * authtok  = md5(sesskey, salt), presented to the user in web forms, to make sure that | 	 * 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 | 	 *            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 | 	 *            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() { | 	public function get_auth_token() { | ||||||
| 		global $config; | 		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; | 	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); | 	$length = strlen($needle); | ||||||
| 	return (substr($haystack, 0, $length) === $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); | 	$length = strlen($needle); | ||||||
| 	$start  = $length * -1; //negative
 | 	$start  = $length * -1; //negative
 | ||||||
| 	return (substr($haystack, $start) === $needle); | 	return (substr($haystack, $start) === $needle); | ||||||
| @ -621,6 +635,7 @@ function log_msg($section, $priority, $message) { | |||||||
| 	send_event(new LogEvent($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_debug($section, $message) {log_msg($section, SCORE_LOG_DEBUG, $message);} | ||||||
| function log_info($section, $message)  {log_msg($section, SCORE_LOG_INFO, $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);} | 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.
 | // string representation of a number, it's two numbers separated by a space.
 | ||||||
| // What the fuck were the PHP developers smoking.
 | // What the fuck were the PHP developers smoking.
 | ||||||
| $_load_start = microtime(true); | $_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() { | function get_debug_info() { | ||||||
| 	global $config, $_event_count, $database, $_execs, $_load_start; | 	global $config, $_event_count, $database, $_execs, $_load_start; | ||||||
| 
 | 
 | ||||||
| @ -879,7 +901,7 @@ function get_debug_info() { | |||||||
| // print_obj ($object, $title, $return)
 | // print_obj ($object, $title, $return)
 | ||||||
| function print_obj($object,$title="Object Information", $return=false) { | function print_obj($object,$title="Object Information", $return=false) { | ||||||
| 	global $user; | 	global $user; | ||||||
| 	if(DEBUG && isset($_GET['debug']) && $user->is_admin()) { | 	if(DEBUG && isset($_GET['DEBUG']) && $user->can("override_config")) { | ||||||
| 		$pr = print_r($object,true); | 		$pr = print_r($object,true); | ||||||
| 		$count = substr_count($pr,"\n")<=25?substr_count($pr,"\n"):25; | 		$count = substr_count($pr,"\n")<=25?substr_count($pr,"\n"):25; | ||||||
| 		$pr = "<textarea rows='".$count."' cols='80'>$pr</textarea>"; | 		$pr = "<textarea rows='".$count."' cols='80'>$pr</textarea>"; | ||||||
| @ -1051,6 +1073,9 @@ function _load_extensions() { | |||||||
| 	ctx_log_endok(); | 	ctx_log_endok(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /** | ||||||
|  |  * Used to display fatal errors to the web user. | ||||||
|  |  */ | ||||||
| function _fatal_error(Exception $e) { | function _fatal_error(Exception $e) { | ||||||
| 	$version = VERSION; | 	$version = VERSION; | ||||||
| 	$message = $e->getMessage(); | 	$message = $e->getMessage(); | ||||||
|  | |||||||
| @ -28,7 +28,7 @@ class AliasEditor extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 		if($event->page_matches("alias")) { | 		if($event->page_matches("alias")) { | ||||||
| 			if($event->get_arg(0) == "add") { | 			if($event->get_arg(0) == "add") { | ||||||
| 				if($user->is_admin()) { | 				if($user->can("manage_alias_list")) { | ||||||
| 					if(isset($_POST['oldtag']) && isset($_POST['newtag'])) { | 					if(isset($_POST['oldtag']) && isset($_POST['newtag'])) { | ||||||
| 						try { | 						try { | ||||||
| 							$aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); | 							$aae = new AddAliasEvent($_POST['oldtag'], $_POST['newtag']); | ||||||
| @ -43,7 +43,7 @@ class AliasEditor extends SimpleExtension { | |||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			else if($event->get_arg(0) == "remove") { | 			else if($event->get_arg(0) == "remove") { | ||||||
| 				if($user->is_admin()) { | 				if($user->can("manage_alias_list")) { | ||||||
| 					if(isset($_POST['oldtag'])) { | 					if(isset($_POST['oldtag'])) { | ||||||
| 						$database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", array("oldtag" => $_POST['oldtag'])); | 						$database->execute("DELETE FROM aliases WHERE oldtag=:oldtag", array("oldtag" => $_POST['oldtag'])); | ||||||
| 						log_info("alias_editor", "Deleted alias for ".$_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); | 				$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") { | 			else if($event->get_arg(0) == "export") { | ||||||
| 				$page->set_mode("data"); | 				$page->set_mode("data"); | ||||||
| @ -82,7 +82,7 @@ class AliasEditor extends SimpleExtension { | |||||||
| 				$page->set_data($this->get_alias_csv($database)); | 				$page->set_data($this->get_alias_csv($database)); | ||||||
| 			} | 			} | ||||||
| 			else if($event->get_arg(0) == "import") { | 			else if($event->get_arg(0) == "import") { | ||||||
| 				if($user->is_admin()) { | 				if($user->can("manage_alias_list")) { | ||||||
| 					if(count($_FILES) > 0) { | 					if(count($_FILES) > 0) { | ||||||
| 						$tmp = $_FILES['alias_file']['tmp_name']; | 						$tmp = $_FILES['alias_file']['tmp_name']; | ||||||
| 						$contents = file_get_contents($tmp); | 						$contents = file_get_contents($tmp); | ||||||
| @ -115,7 +115,7 @@ class AliasEditor extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | ||||||
| 		global $user; | 		global $user; | ||||||
| 		if($user->is_admin()) { | 		if($user->can("manage_alias_list")) { | ||||||
| 			$event->add_link("Alias Editor", make_link("alias/list")); | 			$event->add_link("Alias Editor", make_link("alias/list")); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -5,10 +5,13 @@ class AliasEditorTheme extends Themelet { | |||||||
| 	 * Show a page of aliases: | 	 * Show a page of aliases: | ||||||
| 	 * | 	 * | ||||||
| 	 * $aliases = an array of ($old_tag => $new_tag) | 	 * $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) { | 	public function display_aliases($aliases, $pageNumber, $totalPages) { | ||||||
| 		if($is_admin) { | 		global $page, $user; | ||||||
|  | 
 | ||||||
|  | 		$can_manage = $user->can("manage_alias_list"); | ||||||
|  | 		if($can_manage) { | ||||||
| 			$action = "<th width='10%'>Action</th>"; | 			$action = "<th width='10%'>Action</th>"; | ||||||
| 			$add = " | 			$add = " | ||||||
| 				<tr> | 				<tr> | ||||||
| @ -33,7 +36,7 @@ class AliasEditorTheme extends Themelet { | |||||||
| 			$oe = ($n++ % 2 == 0) ? "even" : "odd"; | 			$oe = ($n++ % 2 == 0) ? "even" : "odd"; | ||||||
| 			 | 			 | ||||||
| 			$h_aliases .= "<tr class='$oe'><td>$h_old</td><td>$h_new</td>"; | 			$h_aliases .= "<tr class='$oe'><td>$h_old</td><td>$h_new</td>"; | ||||||
| 			if($is_admin) { | 			if($can_manage) { | ||||||
| 				$h_aliases .= " | 				$h_aliases .= " | ||||||
| 					<td> | 					<td> | ||||||
| 						".make_form(make_link("alias/remove"))." | 						".make_form(make_link("alias/remove"))." | ||||||
| @ -70,7 +73,7 @@ class AliasEditorTheme extends Themelet { | |||||||
| 		$page->set_heading("Alias List"); | 		$page->set_heading("Alias List"); | ||||||
| 		$page->add_block(new NavBlock()); | 		$page->add_block(new NavBlock()); | ||||||
| 		$page->add_block(new Block("Aliases", $html)); | 		$page->add_block(new Block("Aliases", $html)); | ||||||
| 		if($is_admin) { | 		if($can_manage) { | ||||||
| 			$page->add_block(new Block("Bulk Upload", $bulk_html, "main", 51)); | 			$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("/\[i\](.*?)\[\/i\]/s", "<i>\\1</i>", $text); | ||||||
| 		$text = preg_replace("/\[u\](.*?)\[\/u\]/s", "<u>\\1</u>", $text); | 		$text = preg_replace("/\[u\](.*?)\[\/u\]/s", "<u>\\1</u>", $text); | ||||||
| 		$text = preg_replace("/\[s\](.*?)\[\/s\]/s", "<s>\\1</s>", $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("/>>([^\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\">\\2</a>", $text); | ||||||
| 		$text = preg_replace("/\[url\]((?:https?|ftp|irc|mailto):\/\/.*?)\[\/url\]/s", "<a href=\"\\1\">\\1</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") { | 			else if($event->get_arg(0) === "delete") { | ||||||
| 				if($user->is_admin()) { | 				if($user->can("delete_comment")) { | ||||||
| 					// FIXME: post, not args
 | 					// FIXME: post, not args
 | ||||||
| 					if($event->count_args() === 3) { | 					if($event->count_args() === 3) { | ||||||
| 						send_event(new CommentDeletionEvent($event->get_arg(1))); | 						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)); | 		$h_comment_rate = sprintf("%.1f", ($i_comment_count / $i_days_old)); | ||||||
| 		$event->add_stats("Comments made: $i_comment_count, $h_comment_rate per day"); | 		$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); | 		$recent = $this->get_user_recent_comments($event->display_user->id, 10); | ||||||
| 		$this->theme->display_user_comments($recent); | 		$this->theme->display_user_comments($recent); | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -143,46 +143,53 @@ class CommentListTheme extends Themelet { | |||||||
| 		$h_name = html_escape($comment->owner_name); | 		$h_name = html_escape($comment->owner_name); | ||||||
| 		$h_poster_ip = html_escape($comment->poster_ip); | 		$h_poster_ip = html_escape($comment->poster_ip); | ||||||
| 		$h_timestamp = autodate($comment->posted); | 		$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_comment_id = int_escape($comment->comment_id); | ||||||
| 		$i_image_id = int_escape($comment->image_id); | 		$i_image_id = int_escape($comment->image_id); | ||||||
| 
 | 
 | ||||||
| 		$anoncode = ""; | 		if($h_name == "Anonymous") { | ||||||
| 		if($h_name == "Anonymous" && $this->anon_id >= 0) { | 			$anoncode = ""; | ||||||
| 			$anoncode = '<sup>'.$this->anon_id.'</sup>'; | 			if($this->anon_id >= 0) { | ||||||
| 			$this->anon_id++; | 				$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("\n", "\\n", substr($tfe->stripped, 0, 50)); | ||||||
| 		$stripped_nonl = str_replace("\r", "\\r", $stripped_nonl); | 		$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) { | 		if($trim) { | ||||||
| 			return ' | 			return ' | ||||||
| 				'.$h_userlink.': '.$h_comment.' | 				'.$h_userlink.': '.$h_comment.' | ||||||
| 				<a href="'.make_link('post/view/'.$i_image_id).'">>>></a> | 				<a href="'.make_link('post/view/'.$i_image_id).'">>>></a> | ||||||
| 				'.$h_dellink.' |  | ||||||
| 			'; | 			'; | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
| 			//$avatar = "";
 | 			$avatar = ""; | ||||||
| 			//if(!empty($comment->owner->email)) {
 | 			if(!empty($comment->owner_email)) { | ||||||
| 			//	$hash = md5(strtolower($comment->owner->email));
 | 				$hash = md5(strtolower($comment->owner_email)); | ||||||
| 			//	$avatar = "<img src=\"http://www.gravatar.com/avatar/$hash.jpg\"><br>";
 | 				$avatar = "<img src=\"http://www.gravatar.com/avatar/$hash.jpg\"><br>"; | ||||||
| 			//}
 | 			} | ||||||
| 			$oe = ($this->comments_shown++ % 2 == 0) ? "even" : "odd"; | 			$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 ' | 			return ' | ||||||
| 				<a name="'.$i_comment_id.'"></a> | 				<a name="'.$i_comment_id.'"></a> | ||||||
| 				<div class="'.$oe.' comment"> | 				<div class="comment"> | ||||||
| 				<!--<span class="timeago" style="float: right;">'.$h_timestamp.'</span>--> | 					<div class="info"> | ||||||
| 				'.$h_userlink.': '.$h_comment.' | 					'.$avatar.' | ||||||
| 				'.$h_dellink.' | 					'.$h_timestamp.$h_reply.$h_ip.$h_del.' | ||||||
|  | 					</div> | ||||||
|  | 					'.$h_userlink.': '.$h_comment.' | ||||||
| 				</div> | 				</div> | ||||||
| 			'; | 			'; | ||||||
| 		} | 		} | ||||||
|  | 		return ""; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	protected function build_postbox($image_id) { | 	protected function build_postbox($image_id) { | ||||||
| @ -196,7 +203,7 @@ class CommentListTheme extends Themelet { | |||||||
| 			'.make_form(make_link("comment/add")).' | 			'.make_form(make_link("comment/add")).' | ||||||
| 				<input type="hidden" name="image_id" value="'.$i_image_id.'" /> | 				<input type="hidden" name="image_id" value="'.$i_image_id.'" /> | ||||||
| 				<input type="hidden" name="hash" value="'.$hash.'" /> | 				<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.' | 				'.$captcha.' | ||||||
| 				<br><input type="submit" value="Post Comment" /> | 				<br><input type="submit" value="Post Comment" /> | ||||||
| 			</form> | 			</form> | ||||||
|  | |||||||
| @ -91,7 +91,7 @@ class ExtManager extends SimpleExtension { | |||||||
| 	public function onPageRequest(PageRequestEvent $event) { | 	public function onPageRequest(PageRequestEvent $event) { | ||||||
| 		global $page, $user; | 		global $page, $user; | ||||||
| 		if($event->page_matches("ext_manager")) { | 		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($event->get_arg(0) == "set" && $user->check_auth_token()) { | ||||||
| 					if(is_writable("ext")) { | 					if(is_writable("ext")) { | ||||||
| 						$this->set_things($_POST); | 						$this->set_things($_POST); | ||||||
| @ -130,7 +130,7 @@ class ExtManager extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | ||||||
| 		global $user; | 		global $user; | ||||||
| 		if($user->is_admin()) { | 		if($user->can("manage_extension_list")) { | ||||||
| 			$event->add_link("Extension Manager", make_link("ext_manager")); | 			$event->add_link("Extension Manager", make_link("ext_manager")); | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
|  | |||||||
| @ -162,7 +162,7 @@ class ImageIO extends SimpleExtension { | |||||||
| 		} | 		} | ||||||
| 		if($event->page_matches("image_admin/delete")) { | 		if($event->page_matches("image_admin/delete")) { | ||||||
| 			global $page, $user; | 			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']); | 				$image = Image::by_id($_POST['image_id']); | ||||||
| 				if($image) { | 				if($image) { | ||||||
| 					send_event(new ImageDeletionEvent($image)); | 					send_event(new ImageDeletionEvent($image)); | ||||||
| @ -173,7 +173,7 @@ class ImageIO extends SimpleExtension { | |||||||
| 		} | 		} | ||||||
| 		if($event->page_matches("image_admin/replace")) { | 		if($event->page_matches("image_admin/replace")) { | ||||||
| 			global $page, $user; | 			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']); | 				$image = Image::by_id($_POST['image_id']); | ||||||
| 				if($image) { | 				if($image) { | ||||||
| 					$page->set_mode("redirect"); | 					$page->set_mode("redirect"); | ||||||
| @ -190,11 +190,11 @@ class ImageIO extends SimpleExtension { | |||||||
| 		global $user; | 		global $user; | ||||||
| 		global $config; | 		global $config; | ||||||
| 		 | 		 | ||||||
| 		if($user->is_admin()) { | 		if($user->can("delete_image")) { | ||||||
| 			$event->add_part($this->theme->get_deleter_html($event->image->id)); | 			$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... */ | 		/* 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)); | 			$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_string = html_escape(implode(" ", $search_terms)); | ||||||
| 		$h_search_link = make_link(); | 		$h_search_link = make_link(); | ||||||
| 		$h_search = " | 		$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'> | 			<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' /> | 						value='$h_search_string' autocomplete='off' /> | ||||||
| 				<input type='hidden' name='q' value='/post/list'> | 				<input type='hidden' name='q' value='/post/list'> | ||||||
| 				<input type='submit' value='Find' style='display: none;' /> | 				<input type='submit' value='Find' style='display: none;' /> | ||||||
|  | |||||||
| @ -187,7 +187,7 @@ class Setup extends SimpleExtension { | |||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if($event->page_matches("setup")) { | 		if($event->page_matches("setup")) { | ||||||
| 			if(!$user->is_admin()) { | 			if(!$user->can("change_setting")) { | ||||||
| 				$this->theme->display_permission_denied($page); | 				$this->theme->display_permission_denied($page); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| @ -329,7 +329,7 @@ class Setup extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | 	public function onUserBlockBuilding(UserBlockBuildingEvent $event) { | ||||||
| 		global $user; | 		global $user; | ||||||
| 		if($user->is_admin()) { | 		if($user->can("change_setting")) { | ||||||
| 			$event->add_link("Board Config", make_link("setup")); | 			$event->add_link("Board Config", make_link("setup")); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
|  | |||||||
| @ -60,7 +60,7 @@ class TagEdit extends SimpleExtension { | |||||||
| 		global $user, $page; | 		global $user, $page; | ||||||
| 		if($event->page_matches("tag_edit")) { | 		if($event->page_matches("tag_edit")) { | ||||||
| 			if($event->get_arg(0) == "replace") { | 			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']; | 					$search = $_POST['search']; | ||||||
| 					$replace = $_POST['replace']; | 					$replace = $_POST['replace']; | ||||||
| 					$this->mass_tag_edit($search, $replace); | 					$this->mass_tag_edit($search, $replace); | ||||||
| @ -82,7 +82,7 @@ class TagEdit extends SimpleExtension { | |||||||
| 		else { | 		else { | ||||||
| 			$this->theme->display_error($page, "Error", "Anonymous tag editing is disabled"); | 			$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"; | 			$locked = isset($_POST['tag_edit__locked']) && $_POST['tag_edit__locked']=="on"; | ||||||
| 			send_event(new LockSetEvent($event->image, $locked)); | 			send_event(new LockSetEvent($event->image, $locked)); | ||||||
| 		} | 		} | ||||||
| @ -90,21 +90,21 @@ class TagEdit extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 	public function onTagSet(TagSetEvent $event) { | 	public function onTagSet(TagSetEvent $event) { | ||||||
| 		global $user; | 		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); | 			$event->image->set_tags($event->tags); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public function onSourceSet(SourceSetEvent $event) { | 	public function onSourceSet(SourceSetEvent $event) { | ||||||
| 		global $user; | 		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); | 			$event->image->set_source($event->source); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	public function onLockSet(LockSetEvent $event) { | 	public function onLockSet(LockSetEvent $event) { | ||||||
| 		global $user; | 		global $user; | ||||||
| 		if($user->is_admin()) { | 		if($user->can("lock_image")) { | ||||||
| 			$event->image->set_locked($event->locked); | 			$event->image->set_locked($event->locked); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -130,7 +130,7 @@ class TagEdit extends SimpleExtension { | |||||||
| 		if($this->can_source($event->image)) { | 		if($this->can_source($event->image)) { | ||||||
| 			$event->add_part($this->theme->get_source_editor_html($event->image), 41); | 			$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); | 			$event->add_part($this->theme->get_lock_editor_html($event->image), 42); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -147,7 +147,7 @@ class TagEdit extends SimpleExtension { | |||||||
| 		global $config, $user; | 		global $config, $user; | ||||||
| 		return ( | 		return ( | ||||||
| 			($config->get_bool("tag_edit_anon") || !$user->is_anonymous()) && | 			($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; | 		global $config, $user; | ||||||
| 		return ( | 		return ( | ||||||
| 			($config->get_bool("source_edit_anon") || !$user->is_anonymous()) && | 			($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 | <?php | ||||||
| /* | /** | ||||||
|  * Name: Tag List |  * Name: Tag List | ||||||
|  * Author: Shish |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * Description: Show the tags in various ways |  * Description: Show the tags in various ways | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| @ -107,13 +108,18 @@ class TagList extends SimpleExtension { | |||||||
| 		return make_link("post/list/$u_tag/1"); | 		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() { | 	private function get_tags_min() { | ||||||
| 		if(isset($_GET['mincount'])) { | 		if(isset($_GET['mincount'])) { | ||||||
| 			return int_escape($_GET['mincount']); | 			return int_escape($_GET['mincount']); | ||||||
| 		} | 		} | ||||||
| 		else { | 		else { | ||||||
| 			global $config; | 			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(); | 		$tags_min = $this->get_tags_min(); | ||||||
| 		$starts_with = $this->get_starts_with(); | 		$starts_with = $this->get_starts_with(); | ||||||
|  | 		 | ||||||
|  | 		// check if we have a cached version
 | ||||||
| 		$cache_key = "data/tag_cloud-" . md5("tc" . $tags_min . $starts_with) . ".html"; | 		$cache_key = "data/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);} | ||||||
| 
 | 
 | ||||||
| @ -205,6 +213,8 @@ class TagList extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 		$tags_min = $this->get_tags_min(); | 		$tags_min = $this->get_tags_min(); | ||||||
| 		$starts_with = $this->get_starts_with(); | 		$starts_with = $this->get_starts_with(); | ||||||
|  | 		 | ||||||
|  | 		// check if we have a cached version
 | ||||||
| 		$cache_key = "data/tag_alpha-" . md5("ta" . $tags_min . $starts_with) . ".html"; | 		$cache_key = "data/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);} | ||||||
| 
 | 
 | ||||||
| @ -239,6 +249,8 @@ class TagList extends SimpleExtension { | |||||||
| 		global $database; | 		global $database; | ||||||
| 
 | 
 | ||||||
| 		$tags_min = $this->get_tags_min(); | 		$tags_min = $this->get_tags_min(); | ||||||
|  | 		 | ||||||
|  | 		// check if we have a cached version
 | ||||||
| 		$cache_key = "data/tag_popul-" . md5("tp" . $tags_min) . ".html"; | 		$cache_key = "data/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);} | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -1,7 +1,8 @@ | |||||||
| <?php | <?php | ||||||
| /* | /* | ||||||
|  * Name: Database Upgrader |  * Name: Database Upgrader | ||||||
|  * Author: Shish |  * Author: Shish <webmaster@shishnet.org> | ||||||
|  |  * Link: http://code.shishnet.org/shimmie2/ | ||||||
|  * Description: Keeps things happy behind the scenes |  * Description: Keeps things happy behind the scenes | ||||||
|  * Visibility: admin |  * Visibility: admin | ||||||
|  */ |  */ | ||||||
| @ -10,6 +11,8 @@ class Upgrade extends SimpleExtension { | |||||||
| 	public function onInitExt(InitExtEvent $event) { | 	public function onInitExt(InitExtEvent $event) { | ||||||
| 		global $config, $database; | 		global $config, $database; | ||||||
| 
 | 
 | ||||||
|  | 		if($config->get_bool("in_upgrade")) return; | ||||||
|  | 
 | ||||||
| 		if(!is_numeric($config->get_string("db_version"))) { | 		if(!is_numeric($config->get_string("db_version"))) { | ||||||
| 			$config->set_int("db_version", 2); | 			$config->set_int("db_version", 2); | ||||||
| 		} | 		} | ||||||
| @ -18,28 +21,43 @@ class Upgrade extends SimpleExtension { | |||||||
| 			// cry :S
 | 			// cry :S
 | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		if($config->get_int("db_version") < 7) { | 		// v7 is convert to innodb with adodb
 | ||||||
| 			/* | 		// now done again as v9 with PDO
 | ||||||
| 			// 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"); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		if($config->get_int("db_version") < 8) { | 		if($config->get_int("db_version") < 8) { | ||||||
| 			// if this fails, don't try again
 | 			// if this fails, don't try again
 | ||||||
|  | 			$config->set_bool("in_upgrade", true); | ||||||
| 			$config->set_int("db_version", 8); | 			$config->set_int("db_version", 8); | ||||||
| 			$database->execute($database->engine->scoreql_to_sql( | 			$database->execute($database->engine->scoreql_to_sql( | ||||||
| 				"ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" | 				"ALTER TABLE images ADD COLUMN locked SCORE_BOOL NOT NULL DEFAULT SCORE_BOOL_N" | ||||||
| 			)); | 			)); | ||||||
| 			log_info("upgrade", "Database at version 8"); | 			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 | <?php | ||||||
| /* | /** | ||||||
|  * Name: Uploader |  * Name: Uploader | ||||||
|  * Author: Shish |  * Author: Shish | ||||||
|  * Description: Allows people to upload files to the website |  * 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.
 | 			// 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); | 				$this->theme->display_permission_denied($page); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| @ -224,14 +224,28 @@ class Upload extends SimpleExtension { | |||||||
| 	} | 	} | ||||||
| // }}}
 | // }}}
 | ||||||
| // do things {{{
 | // do things {{{
 | ||||||
|  | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Check if a given user can upload. | ||||||
|  | 	 * @param $user The user to check. | ||||||
|  | 	 * @retval bool | ||||||
|  | 	 */ | ||||||
| 	private function can_upload(User $user) { | 	private function can_upload(User $user) { | ||||||
| 		global $config; | 		global $config; | ||||||
| 		return ($config->get_bool("upload_anon") || !$user->is_anonymous()); | 		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
 | 	 * Returns a descriptive error message for the specified PHP error code. | ||||||
| 	// TODO: Make these messages user/admin editable
 | 	 * | ||||||
|  | 	 * 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) { | 	private function upload_error_message($error_code) { | ||||||
| 		switch ($error_code) { | 		switch ($error_code) { | ||||||
| 			case UPLOAD_ERR_INI_SIZE: | 			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='') { | 	private function try_upload($file, $tags, $source, $replace='') { | ||||||
| 		global $page; | 		global $page; | ||||||
| 		global $config; | 		global $config; | ||||||
| @ -299,6 +317,10 @@ class Upload extends SimpleExtension { | |||||||
| 		return $ok; | 		return $ok; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/** | ||||||
|  | 	 * Handle an transload. | ||||||
|  | 	 * @retval bool TRUE on transload successful. | ||||||
|  | 	 */ | ||||||
| 	private function try_transload($url, $tags, $source, $replace='') { | 	private function try_transload($url, $tags, $source, $replace='') { | ||||||
| 		global $page; | 		global $page; | ||||||
| 		global $config; | 		global $config; | ||||||
| @ -314,7 +336,7 @@ class Upload extends SimpleExtension { | |||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		// Checks if user is admin > check if you want locked.
 | 		// 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']); | 			$locked = bool_escape($_GET['locked']); | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
|  | |||||||
| @ -158,7 +158,7 @@ class UserPage extends SimpleExtension { | |||||||
| 				$this->theme->display_error($page, "Not Logged In", | 				$this->theme->display_error($page, "Not Logged In", | ||||||
| 					"You aren't logged in. First do that, then you can see your stats."); | 					"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)); | 				send_event(new UserPageBuildingEvent($display_user)); | ||||||
| 			} | 			} | ||||||
| 			else { | 			else { | ||||||
| @ -187,7 +187,7 @@ class UserPage extends SimpleExtension { | |||||||
| 			$this->theme->display_user_links($page, $user, $ubbe->parts); | 			$this->theme->display_user_links($page, $user, $ubbe->parts); | ||||||
| 		} | 		} | ||||||
| 		if( | 		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
 | 			($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( | 			$this->theme->display_ip_list( | ||||||
| @ -256,7 +256,7 @@ class UserPage extends SimpleExtension { | |||||||
| 			$user_id = int_escape($matches[2]); | 			$user_id = int_escape($matches[2]); | ||||||
| 			$event->add_querylet(new Querylet("images.owner_id = $user_id")); | 			$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?
 | 			$user_ip = $matches[2]; // FIXME: ip_escape?
 | ||||||
| 			$event->add_querylet(new Querylet("images.owner_ip = '$user_ip'")); | 			$event->add_querylet(new Querylet("images.owner_ip = '$user_ip'")); | ||||||
| 		} | 		} | ||||||
| @ -354,7 +354,7 @@ class UserPage extends SimpleExtension { | |||||||
| 
 | 
 | ||||||
| 			$duser = User::by_id($id); | 			$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", | 				$this->theme->display_error($page, "Error", | ||||||
| 						"You need to be an admin to change other people's passwords"); | 						"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); | 			$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", | 				$this->theme->display_error($page, "Error", | ||||||
| 						"You need to be an admin to change other people's addressess"); | 						"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_title("Error"); | ||||||
| 		$page->set_heading("Error"); | 		$page->set_heading("Error"); | ||||||
| 		$page->add_block(new NavBlock()); | 		$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")); | 			$page->add_block(new Block("Not Admin", "Only admins can edit accounts")); | ||||||
| 		} | 		} | ||||||
| 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | ||||||
| @ -479,7 +479,7 @@ class UserPage extends SimpleExtension { | |||||||
| 		$page->set_heading("Error"); | 		$page->set_heading("Error"); | ||||||
| 		$page->add_block(new NavBlock()); | 		$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")); | 			$page->add_block(new Block("Not Admin", "Only admins can delete accounts")); | ||||||
| 		} | 		} | ||||||
| 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | ||||||
| @ -510,7 +510,7 @@ class UserPage extends SimpleExtension { | |||||||
| 		$page->set_heading("Error"); | 		$page->set_heading("Error"); | ||||||
| 		$page->add_block(new NavBlock()); | 		$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")); | 			$page->add_block(new Block("Not Admin", "Only admins can delete accounts")); | ||||||
| 		} | 		} | ||||||
| 		else if(!isset($_POST['id']) || !is_numeric($_POST['id'])) { | 		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)); | 		$page->add_block(new Block("Stats", join("<br>", $stats), "main", 0)); | ||||||
| 
 | 
 | ||||||
| 		if(!$user->is_anonymous()) { | 		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)); | 				$page->add_block(new Block("Options", $this->build_options($duser), "main", 20)); | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -173,7 +173,7 @@ class UserPageTheme extends Themelet { | |||||||
| 			</form> | 			</form> | ||||||
| 			";
 | 			";
 | ||||||
| 
 | 
 | ||||||
| 			if($user->is_admin()) { | 			if($user->can("change_user_info")) { | ||||||
| 				$i_user_id = int_escape($duser->id); | 				$i_user_id = int_escape($duser->id); | ||||||
| 				$h_is_admin = $duser->is_admin() ? " checked" : ""; | 				$h_is_admin = $duser->is_admin() ? " checked" : ""; | ||||||
| 				$html .= " | 				$html .= " | ||||||
|  | |||||||
| @ -90,7 +90,7 @@ class ViewImageTheme extends Themelet { | |||||||
| 		$html = ""; | 		$html = ""; | ||||||
| 		$html .= "<p>Uploaded by <a href='".make_link("user/$h_owner")."'>$h_owner</a> $h_date"; | 		$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)"; | 			$html .= " ($h_ip)"; | ||||||
| 		} | 		} | ||||||
| 		if(!is_null($image->source)) { | 		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;" |  * 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"); | 	header("Location: install.php"); | ||||||
| 	exit; | 	exit; | ||||||
| } | } | ||||||
|  | |||||||
							
								
								
									
										153
									
								
								install.php
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								install.php
									
									
									
									
									
								
							| @ -1,7 +1,8 @@ | |||||||
| <?php ob_start(); ?>
 | <?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 |  - Initialise the database, check that folder | ||||||
|  - permissions are set properly, set an admin |  - permissions are set properly, set an admin | ||||||
| @ -12,17 +13,18 @@ | |||||||
| --> | --> | ||||||
| 	<head> | 	<head> | ||||||
| 		<title>Shimmie Installation</title> | 		<title>Shimmie Installation</title> | ||||||
| 		<style> | 		<link rel="shortcut icon" href="/favicon.ico" /> | ||||||
| BODY {background: #EEE;font-family: "Arial", sans-serif;font-size: 14px;}
 | 		<style type="text/css"> | ||||||
| H1, H3 {border: 1px solid black;background: #DDD;text-align: center;}
 | 			BODY {background: #EEE;font-family: "Arial", sans-serif;font-size: 14px;}
 | ||||||
| H1 {margin-top: 0px;margin-bottom: 0px;padding: 2px;} | 			H1, H3 {border: 1px solid black;background: #DDD;text-align: center;}
 | ||||||
| H3 {margin-top: 32px;padding: 1px;} | 			H1 {margin-top: 0px;margin-bottom: 0px;padding: 2px;} | ||||||
| FORM {margin: 0px;} | 			H3 {margin-top: 32px;padding: 1px;} | ||||||
| A {text-decoration: none;} | 			FORM {margin: 0px;} | ||||||
| A:hover {text-decoration: underline;} | 			A {text-decoration: none;} | ||||||
| #block {width: 512px; margin: auto; margin-top: 64px;}
 | 			A:hover {text-decoration: underline;} | ||||||
| #iblock {width: 512px; margin: auto; margin-top: 16px;}
 | 			#block {width: 512px; margin: auto; margin-top: 64px;}
 | ||||||
| TD INPUT {width: 350px;} | 			#iblock {width: 512px; margin: auto; margin-top: 16px;}
 | ||||||
|  | 			TD INPUT {width: 350px;} | ||||||
| 		</style> | 		</style> | ||||||
| 	</head> | 	</head> | ||||||
| 	<body> | 	<body> | ||||||
| @ -31,9 +33,10 @@ TD INPUT {width: 350px;} | |||||||
| 			<h1>Install Error</h1> | 			<h1>Install Error</h1> | ||||||
| 			<p>Shimmie needs to be run via a web server with PHP support -- you | 			<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 | 			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 | 			<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> | ||||||
| 		<div style="display: none;"> | 		<div style="display: none;"> | ||||||
| 			<PLAINTEXT> | 			<PLAINTEXT> | ||||||
| @ -51,9 +54,32 @@ if(is_readable("config.php")) { | |||||||
| 		<div id="iblock"> | 		<div id="iblock"> | ||||||
| 			<h1>Shimmie Repair Console</h1> | 			<h1>Shimmie Repair Console</h1> | ||||||
| <?php | <?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"])) { | 		if(empty($_GET["action"])) { | ||||||
| 			echo "<h3>Basic Checks</h3>"; | 			echo "<h3>Basic Checks</h3>"; | ||||||
| @ -76,15 +102,6 @@ if(is_readable("config.php")) { | |||||||
| 				</form> | 				</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 "<h3>Log Out</h3>"; | ||||||
| 			echo " | 			echo " | ||||||
| @ -95,15 +112,12 @@ if(is_readable("config.php")) { | |||||||
| 		} | 		} | ||||||
| 		else if($_GET["action"] == "logout") { | 		else if($_GET["action"] == "logout") { | ||||||
| 			session_destroy(); | 			session_destroy(); | ||||||
| 		} | 			echo "<h3>Logged Out</h3><p>You have been logged out.</p><a href='index.php'>Main Shimmie Page</a>"; | ||||||
| 		else if($_GET["action"] == "Database_user_deletion_fix") { |  | ||||||
| 			Database_user_deletion_fix(); |  | ||||||
| 		} | 		} | ||||||
| 	} else { | 	} else { | ||||||
| 		echo " | 		echo " | ||||||
| 			<h3>Login</h3> | 			<h3>Login</h3> | ||||||
| 			Enter the database DSN exactly as in config.php (ie, as originally | 			<p>Enter the database DSN exactly as in config.php (ie, as originally installed) to access advanced recovery tools:</p> | ||||||
| 			installed) to access advanced recovery tools: |  | ||||||
| 
 | 
 | ||||||
| 			<form action='install.php' method='POST'> | 			<form action='install.php' method='POST'> | ||||||
| 				<center> | 				<center> | ||||||
| @ -118,13 +132,24 @@ if(is_readable("config.php")) { | |||||||
| 	echo "\t\t</div>"; | 	echo "\t\t</div>"; | ||||||
| 	exit; | 	exit; | ||||||
| } | } | ||||||
| require_once "core/compat.inc.php"; |  | ||||||
| require_once "core/util.inc.php"; |  | ||||||
| require_once "core/database.class.php"; |  | ||||||
| 
 | 
 | ||||||
| do_install(); | do_install(); | ||||||
| 
 | 
 | ||||||
| // utilities {{{
 | // 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() { | function check_gd_version() { | ||||||
| 	$gdversion = 0; | 	$gdversion = 0; | ||||||
| 
 | 
 | ||||||
| @ -249,7 +274,7 @@ function begin() { // {{{ | |||||||
| 			<h3>Help</h3> | 			<h3>Help</h3> | ||||||
| 					 | 					 | ||||||
| 			<p>Please make sure the database you have chosen exists and is empty.<br> | 			<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> | 		</div> | ||||||
| EOD; | 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_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 | 			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) | 	catch (PDOException $e) | ||||||
| 	{ | 	{ | ||||||
| @ -354,11 +379,12 @@ function build_dirs() { // {{{ | |||||||
| 			!file_exists("images") || !file_exists("thumbs") || !file_exists("data") || | 			!file_exists("images") || !file_exists("thumbs") || !file_exists("data") || | ||||||
| 			!is_writable("images") || !is_writable("thumbs") || !is_writable("data") | 			!is_writable("images") || !is_writable("thumbs") || !is_writable("data") | ||||||
| 	) { | 	) { | ||||||
| 		print "Shimmie needs three folders in it's directory, 'images', 'thumbs', and 'data',
 | 		print "<p>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, | 		       and they need to be writable by the PHP user.</p> | ||||||
| 			   if probably means the folders are owned by you, and they need to be | 			   <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). | 			   writable by the web server.</p> | ||||||
| 			   <p>Once you have created these folders, hit 'refresh' to continue.";
 | 			   <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; | 		exit; | ||||||
| 	} | 	} | ||||||
| } // }}}
 | } // }}}
 | ||||||
| @ -387,49 +413,6 @@ EOD; | |||||||
| 		exit; | 		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> | 	</body> | ||||||
| </html> | </html> | ||||||
|  | |||||||
| @ -27,70 +27,25 @@ $(document).ready(function() { | |||||||
| 	}); | 	}); | ||||||
| 	 | 	 | ||||||
| 	$("time").timeago(); | 	$("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(); | 	var sections=get_sections(); | ||||||
| 	for(var i=0;i<sections.length;i++) toggle(sections[i]); | 	for(var i=0;i<sections.length;i++) toggle(sections[i]); | ||||||
| 
 | 
 | ||||||
| 	initGray("search_input", "Search"); | 	$("#commentBox").DefaultValue("Comment"); | ||||||
| 	initGray("commentBox", "Comment"); | 	$("#tagBox").DefaultValue("tagme"); | ||||||
| 	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"); |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ | /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ | ||||||
| @ -111,6 +66,7 @@ function byId(id) { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // used once in ext/setup/main
 | ||||||
| function getHTTPObject() {  | function getHTTPObject() {  | ||||||
| 	if (window.XMLHttpRequest){ | 	if (window.XMLHttpRequest){ | ||||||
| 		return new 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 */ | /* get, set, and delete cookies */ | ||||||
| function getCookie( name ) { | function getCookie( name ) { | ||||||
| @ -164,3 +111,10 @@ function deleteCookie( name, path, domain ) { | |||||||
| 			";expires=Thu, 01-Jan-1970 00:00:01 GMT"; | 			";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> |         <em> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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. | 			based on the Danbooru concept. | ||||||
| 			$debug | 			$debug | ||||||
| 			$contact | 			$contact | ||||||
|  | |||||||
| @ -71,7 +71,9 @@ $header_html | |||||||
| 		<div id="footer"> | 		<div id="footer"> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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. | 			based on the Danbooru concept. | ||||||
| 			$debug | 			$debug | ||||||
| 			$contact | 			$contact | ||||||
|  | |||||||
| @ -128,9 +128,8 @@ UL { | |||||||
| .comment { | .comment { | ||||||
| 	text-align: left; | 	text-align: left; | ||||||
| } | } | ||||||
| .comment .timeago { | .comment .info { | ||||||
| 	float: right; | 	display: none; | ||||||
| 	font-size: 75%; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| .more:after { | .more:after { | ||||||
|  | |||||||
| @ -71,7 +71,9 @@ $header_html | |||||||
| 		<div id="footer"> | 		<div id="footer"> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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. | 			based on the Danbooru concept. | ||||||
| 			$debug | 			$debug | ||||||
| 			$contact | 			$contact | ||||||
|  | |||||||
| @ -79,7 +79,9 @@ $header_html | |||||||
| 			<hr> | 			<hr> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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. | 			based on the Danbooru concept. | ||||||
| 			<br>Futaba theme based on 4chan's layout and CSS :3 | 			<br>Futaba theme based on 4chan's layout and CSS :3 | ||||||
| 			$debug | 			$debug | ||||||
|  | |||||||
| @ -184,7 +184,9 @@ class Layout { | |||||||
| 		<div id="footer"> | 		<div id="footer"> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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 /> | 			based on the Danbooru concept.<br /> | ||||||
| 			Lite Theme by <a href="http://seemslegit.com">Zach</a> | 			Lite Theme by <a href="http://seemslegit.com">Zach</a> | ||||||
| 			$debug | 			$debug | ||||||
|  | |||||||
| @ -69,7 +69,9 @@ $header_html | |||||||
| 			<hr> | 			<hr> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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. | 			based on the Danbooru concept. | ||||||
| 			$debug | 			$debug | ||||||
| 			$contact | 			$contact | ||||||
|  | |||||||
| @ -85,7 +85,9 @@ $header_html | |||||||
| 		<div id="footer"> | 		<div id="footer"> | ||||||
| 			Images © their respective owners, | 			Images © their respective owners, | ||||||
| 			<a href="http://code.shishnet.org/shimmie2/">Shimmie</a> © | 			<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. | 			based on the Danbooru concept. | ||||||
| 			$debug | 			$debug | ||||||
| 			$contact | 			$contact | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user