Pastoid

The page you are looking at now is at this URL: http://pastoid.com/bzz

This paste was last updated on February 13, 2010 at 12:54 am.

post.phpraw

<?php
/**
 * @package Habari
 *
 */
 
/**
 *
 * Includes an instance of the PostInfo class; for holding inforecords about a Post
 * If the Post object describes an existing post; use the internal info object to
 * get, set, unset and test for existence (isset) of info records.
 * <code>
 * $this->info= new PostInfo( 1 );  // Info records of post with id = 1
 * $this->info->option1= "blah"; // set info record with name "option1" to value "blah"
 * $info_value= $this->info->option1; // get value of info record with name "option1" into variable $info_value
 * if ( isset ( $this->info->option1 ) )  // test for existence of "option1"
 * unset ( $this->info->option1 ); // delete "option1" info record
 * </code>
 *
 */
class Post extends QueryRecord implements IsContent
{
	// static variables to hold post status and post type values
	static $post_status_list = array();
	static $post_type_list_active = array();
	static $post_type_list_all = array();
 
	private $tags = null;
	private $comments_object = null;
	private $author_object = null;
	private $tokens = null;
 
	private $inforecords = null;
 
	protected $url_args;
 
	/**
	 * returns an associative array of active post types
	 * @param bool whether to force a refresh of the cached values
	 * @return array An array of post type names => integer values
	 */
	public static function list_active_post_types( $refresh = false )
	{
		if ( ( ! $refresh ) && ( ! empty( self::$post_type_list_active ) ) ) {
			return self::$post_type_list_active;
		}
		self::$post_type_list_active['any'] = 0;
		$sql = 'SELECT * FROM {posttype} WHERE active = 1 ORDER BY id ASC';
		$results = DB::get_results( $sql );
		foreach ( $results as $result ) {
			self::$post_type_list_active[$result->name] = $result->id;
		}
		return self::$post_type_list_active;
	}
 
	/**
	 * returns an associative array of all post types
	 * @param bool whether to force a refresh of the cached values
	 * @return array An array of post type names => (integer values, active values)
	 */
	public static function list_all_post_types( $refresh = false )
	{
		if ( ( ! $refresh ) && ( ! empty( self::$post_type_list_all ) ) ) {
			return self::$post_type_list_all;
		}
		self::$post_type_list_all['any'] = 0;
		$sql = 'SELECT * FROM {posttype} ORDER BY id ASC';
		$results = DB::get_results( $sql );
		foreach ( $results as $result ) {
			self::$post_type_list_all[$result->name] = array(
				'id' => $result->id,
				'active' => $result->active
				);
		}
		return self::$post_type_list_all;
	}
 
	/**
	 * Activate an existing post type
	 *
	 * @param string The post type to activate
	 */
	public static function activate_post_type( $type )
	{
		$all_post_types = Post::list_all_post_types( true ); // We force a refresh
 
		// Check if it exists
		if ( array_key_exists( $type, $all_post_types ) ) {
			if ( ! $all_post_types[$type]['active'] == 1 ) {
				// Activate it
				$sql = 'UPDATE {posttype} SET active = 1 WHERE id = ' . $all_post_types[$type]['id'];
				DB::query( $sql );
			}
			return true;
		}
		else {
			return false; // Doesn't exist
		}
	}
 
	/**
	 * Deactivate a post type
	 *
	 * @param string The post type to deactivate
	 */
	public static function deactivate_post_type( $type )
	{
		$active_post_types = Post::list_active_post_types( false ); // We force a refresh
 
		if ( array_key_exists( $type, $active_post_types ) ) {
			// $type is active so we'll deactivate it
			$sql = 'UPDATE {posttype} SET active = 0 WHERE id = ' . $active_post_types[$type];
			DB::query( $sql );
			return true;
		}
		return false;
	}
 
	/**
	 * returns an associative array of post statuses
	 * @param mixed $all true to list all statuses, not just external ones, Post to list external and any that match the Post status
	 * @param boolean $refresh true to force a refresh of the cached values
	 * @return array An array of post statuses names => interger values
	 */
	public static function list_post_statuses( $all = true, $refresh = false )
	{
		$statuses = array();
		$statuses['any'] = 0;
		if ( $refresh || empty( self::$post_status_list ) ) {
			$sql = 'SELECT * FROM {poststatus} ORDER BY id ASC';
			$results = DB::get_results( $sql );
			self::$post_status_list = $results;
		}
		foreach ( self::$post_status_list as $status ) {
			if ( $all instanceof Post ) {
				if( ! $status->internal || $status->id == $all->status ) {
					$statuses[$status->name] = $status->id;
				}
			}
			elseif ( $all ) {
				$statuses[$status->name] = $status->id;
			}
			elseif ( ! $status->internal ) {
				$statuses[$status->name] = $status->id;
			}
		}
		return $statuses;
	}
 
	/**
	 * returns the integer value of the specified post status, or false
	 * @param mixed a post status name or value
	 * @return mixed an integer or boolean false
	 */
	public static function status( $name )
	{
		$statuses = Post::list_post_statuses();
		if ( is_numeric( $name ) && ( FALSE !== in_array( $name, $statuses ) ) ) {
			return $name;
		}
		if ( isset( $statuses[strtolower( $name )] ) ) {
			return $statuses[strtolower( $name )];
		}
		return false;
	}
 
	/**
	 * returns the friendly name of a post status, or null
	 * @param mixed a post status value, or name
	 * @return mixed a string of the status name, or null
	 */
	public static function status_name( $status )
	{
		$statuses = array_flip( Post::list_post_statuses() );
		if ( is_numeric( $status ) && isset( $statuses[$status] ) ) {
			return $statuses[$status];
		}
		if ( FALSE !== in_array( $status, $statuses ) ) {
			return $status;
		}
		return '';
	}
 
	/**
	 * returns the integer value of the specified post type, or false
	 * @param mixed a post type name or number
	 * @return mixed an integer or boolean false
	 */
	public static function type( $name )
	{
		$types = Post::list_active_post_types();
		if ( is_numeric( $name ) && ( FALSE !== in_array( $name, $types ) ) ) {
			return $name;
		}
		if ( isset( $types[strtolower( $name )] ) ) {
			return $types[strtolower( $name )];
		}
		return false;
	}
 
	/**
	 * returns the friendly name of a post type, or null
	 * @param mixed a post type number, or name
	 * @return mixed a string of the post type, or null
	 */
	public static function type_name( $type )
	{
		$types = array_flip( Post::list_active_post_types() );
		if ( is_numeric( $type ) && isset( $types[$type] ) ) {
			return $types[$type];
		}
		if ( FALSE !== in_array( $type, $types ) ) {
			return $type;
		}
		return '';
	}
 
	/**
	 * inserts a new post type into the database, if it doesn't exist
	 * @param string The name of the new post type
	 * @param bool Whether the new post type is active or not
	 * @return none
	 */
	public static function add_new_type( $type, $active = true )
	{
		// refresh the cache from the DB, just to be sure
		$types = self::list_all_post_types( true );
 
		if ( ! array_key_exists( $type, $types ) ) {
			// Doesn't exist in DB.. add it and activate it.
			DB::query( 'INSERT INTO {posttype} (name, active) VALUES (?, ?)', array( $type, $active ) );
		}
		elseif ( $types[$type]['active'] == 0 ) {
			// Isn't active so we activate it
			self::activate_post_type( $type );
		}
		ACL::create_token( 'post_' . Utils::slugify($type), _t('Permissions to posts of type "%s"', array($type) ), _t('Content'), TRUE );
 
		// now force a refresh of the caches, so the new/activated type
		// is available for immediate use
		$types = self::list_active_post_types( true );
		$types = self::list_all_post_types( true );
	}
 
	/**
	 * inserts a new post status into the database, if it doesn't exist
	 * @param string The name of the new post status
	 * @param bool Whether this status is for internal use only.  If true, this status will NOT be presented to the user
	 * @return none
	 */
	public static function add_new_status( $status, $internal = false )
	{
		// refresh the cache from the DB, just to be sure
		$statuses = self::list_post_statuses( true );
		if ( ! array_key_exists( $status, $statuses ) ) {
			// let's make sure we only insert an integer
			$internal = intval( $internal );
			DB::query( 'INSERT INTO {poststatus} (name, internal) VALUES (?, ?)', array( $status, $internal ) );
			// force a refresh of the cache, so the new status
			// is available for immediate use
			$statuses = self::list_post_statuses( true, true );
		}
	}
 
	/**
	 * Return the defined database columns for a Post.
	 * @return array Array of columns in the Post table
	 */
	public static function default_fields()
	{
		return array(
			'id' => 0,
			'slug' => '',
			'title' => '',
			'guid' => '',
			'content' => '',
			'cached_content' => '',
			'user_id' => 0,
			'status' => Post::status( 'draft' ),
			'pubdate' => HabariDateTime::date_create(),
			'updated' => HabariDateTime::date_create(),
			'modified' => HabariDateTime::date_create(),
			'content_type' => Post::type( 'entry' )
		);
	}
 
	/**
	 * Constructor for the Post class.
	 * @param array $paramarray an associative array of initial Post field values.
	 */
	public function __construct( $paramarray = array() )
	{
		// Defaults
		$this->fields = array_merge(
			self::default_fields(),
			$this->fields
		);
 
		parent::__construct( $paramarray );
		if ( isset( $this->fields['tags'] ) ) {
			$this->tags = $this->parsetags( $this->fields['tags'] );
			unset( $this->fields['tags'] );
		}
 
		$this->exclude_fields( 'id' );
		 /* $this->fields['id'] could be null in case of a new post. If so, the info object is _not_ safe to use till after set_key has been called. Info records can be set immediately in any other case. */
	}
 
	/**
	 * Return a single requested post.
	 *
	 * <code>
	 * $post= Post::get( array( 'slug' => 'wooga' ) );
	 * </code>
	 *
	 * @param array $paramarray An associative array of parameters, or a querystring
	 * @return Post The first post that matched the given criteria
	 */
	static function get( $paramarray = array() )
	{
		// Defaults
		$defaults = array (
			'where' => array(
				array(
					'status' => Post::status( 'published' ),
				),
			),
			'fetch_fn' => 'get_row',
		);
		foreach ( $defaults['where'] as $index => $where ) {
			$defaults['where'][$index] = array_merge( $where, Utils::get_params( $paramarray ) );
		}
		// make sure we get at most one result
		$defaults['limit'] = 1;
 
		return Posts::get( $defaults );
	}
 
	/**
	 * Create a post and save it.
	 *
	 * @param array $paramarray An associative array of post fields
	 * @return Post The new Post object
	 */
	static function create( $paramarray )
	{
		$post = new Post( $paramarray );
		$post->insert();
		return $post;
	}
 
	/**
	 * Generate a new slug for the post.
	 *
	 * @return string The slug
	 */
	private function setslug()
	{
		// determine the base value from:
		// - the new slug
		if ( isset( $this->newfields['slug']) && $this->newfields['slug'] != '' ) {
			$value = $this->newfields['slug'];
		}
		// - the existing slug
		elseif ( $this->fields['slug'] != '' ) {
			$value = $this->fields['slug'];
		}
		// - the new post title
		elseif ( isset( $this->newfields['title'] ) && $this->newfields['title'] != '' ) {
			$value = $this->newfields['title'];
		}
		// - the existing post title
		elseif ( $this->fields['title'] != '' ) {
			$value = $this->fields['title'];
		}
		// - default
		else {
			$value = 'Post';
		}
 
		// make sure our slug is unique
		$slug = Plugins::filter( 'post_setslug', $value );
		$slug = Utils::slugify( $slug );
		$postfix = '';
		$postfixcount = 0;
		do {
			if ( ! $slugcount = DB::get_row( 'SELECT COUNT(slug) AS ct FROM {posts} WHERE slug = ?;', array( $slug . $postfix ) ) ) {
				Utils::debug( DB::get_errors() );
				exit;
			}
			if ( $slugcount->ct != 0 ) {
				$postfix = "-" . ( ++$postfixcount );
			}
		} while ( $slugcount->ct != 0 );
 
		return $this->newfields['slug'] = $slug . $postfix;
	}
 
	/**
	 * Generate the GUID for the new post.
	 */
	private function setguid()
	{
		if ( ! isset( $this->newfields['guid'] )
			|| ( $this->newfields['guid'] == '' )  // GUID is empty
			|| ( $this->newfields['guid'] == '//?p=' ) // GUID created by WP was erroneous (as is too common)
		) {
			$result = 'tag:' . Site::get_url( 'hostname' ) . ',' . date( 'Y' ) . ':' . rawurlencode($this->setslug()) . '/' . time();
			$this->newfields['guid'] = $result;
		}
		return $this->newfields['guid'];
	}
 
	/**
	 * function setstatus
	 * @param mixed the status to set it to. String or integer.
	 * @return integer the status of the post, or false if the new status isn't valid
	 * Sets the status for a post, given a string or integer.
	 */
	private function setstatus( $value )
	{
		$statuses = Post::list_post_statuses();
		if ( is_numeric( $value ) && in_array( $value, $statuses ) ) {
			return $this->newfields['status'] = $value;
		}
		elseif ( array_key_exists( $value, $statuses ) ) {
			return $this->newfields['status'] = Post::status( $value );
		}
 
		return false;
	}
 
	/**
	 * Ensure this is an array of tags.
	 *
	 * @param Mixed A string to parse for tags or an array of tags.
	 * @return Array An array of tags
	 */
	private static function parsetags( $tags )
	{
		if ( is_string( $tags ) ) {
			if ( '' === $tags ) {
				return array();
			}
			// dirrty ;)
			$rez = array( '\\"'=>':__unlikely_quote__:', '\\\''=>':__unlikely_apos__:' );
			$zer = array( ':__unlikely_quote__:'=>'"', ':__unlikely_apos__:'=>"'" );
			// escape
			$tagstr = str_replace( array_keys( $rez ), $rez, $tags );
			// match-o-matic
			preg_match_all( '/((("|((?<= )|^)\')\\S([^\\3]*?)\\3((?=[\\W])|$))|[^,])+/', $tagstr, $matches );
			// cleanup
			$tags = array_map( 'trim', $matches[0] );
			$tags = preg_replace( array_fill( 0, count( $tags ), '/^(["\'])(((?!").)+)(\\1)$/'), '$2', $tags );
			// unescape
			$tags = str_replace( array_keys( $zer ), $zer, $tags );
			// hooray
			return $tags;
		}
		elseif ( is_array( $tags ) ) {
			return $tags;
		}
	}
 
	/**
	 * Save the tags associated to this post into the terms and object_terms tables
	 */
	private function save_tags()
	{
		return Tags::save_associations( $this->tags, $this->id );
	}
 
	/**
	 * function insert
	 * Saves a new post to the posts table
	 */
	public function insert()
	{
		$this->newfields['updated'] = HabariDateTime::date_create();
		$this->newfields['modified'] = $this->newfields['updated'];
		$this->setguid();
 
		$allow = true;
		$allow = Plugins::filter( 'post_insert_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		Plugins::act( 'post_insert_before', $this );
 
		// Invoke plugins for all fields, since they're all "changed" when inserted
		foreach ( $this->fields as $fieldname => $value ) {
			Plugins::act( 'post_update_' . $fieldname, $this, ( $this->id == 0 ) ? null : $value, $this->$fieldname );
		}
		// invoke plugins for status changes
		Plugins::act( 'post_status_' . self::status_name( $this->status ), $this, null );
 
		$result = parent::insertRecord( DB::table( 'posts' ) );
		$this->newfields['id'] = DB::last_insert_id(); // Make sure the id is set in the post object to match the row id
		$this->fields = array_merge( $this->fields, $this->newfields );
		$this->newfields = array();
		$this->info->commit( DB::last_insert_id() );
		$this->save_tags();
		$this->create_default_permissions();
		EventLog::log( sprintf(_t('New post %1$s (%2$s);  Type: %3$s; Status: %4$s'), $this->id, $this->slug, Post::type_name( $this->content_type ), $this->statusname), 'info', 'content', 'habari' );
		Plugins::act( 'post_insert_after', $this );
 
		//scheduled post
		if( $this->status == Post::status( 'scheduled' ) ) {
			Posts::update_scheduled_posts_cronjob();
		}
 
		return $result;
	}
 
	/**
	 * function update
	 * Updates an existing post in the posts table
	 * @param bool $minor Indicates if this is a major or minor update
	 */
	public function update( $minor = true )
	{
		$this->modified = HabariDateTime::date_create();
		if ( ! $minor ) {
			$this->updated = $this->modified;
		}
		if ( isset( $this->fields['guid'] ) ) {
			unset( $this->newfields['guid'] );
		}
 
		$allow = true;
		$allow = Plugins::filter( 'post_update_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		Plugins::act( 'post_update_before', $this );
 
		// Call setslug() only when post slug is changed
		if ( isset( $this->newfields['slug'] ) && $this->newfields['slug'] != '' ) {
			if ( $this->fields['slug'] != $this->newfields['slug'] ) {
				$this->setslug();
			}
		}
 
		// invoke plugins for all fields which have been changed
		// For example, a plugin action "post_update_status" would be
		// triggered if the post has a new status value
		foreach ( $this->newfields as $fieldname => $value ) {
			Plugins::act( 'post_update_' . $fieldname, $this, $this->fields[$fieldname], $value );
		}
 
		// invoke plugins for status changes
		if ( isset( $this->newfields['status'] ) && $this->fields['status'] != $this->newfields['status'] ) {
		  Plugins::act( 'post_status_' . self::status_name( $this->newfields['status'] ), $this, $this->fields['status'] );
		}
 
		$result = parent::updateRecord( DB::table( 'posts' ), array( 'id' => $this->id ) );
 
		//scheduled post
		if ( $this->fields['status'] == Post::status( 'scheduled' ) || $this->status == Post::status( 'scheduled' ) ) {
			Posts::update_scheduled_posts_cronjob();
		}
 
		$this->fields = array_merge( $this->fields, $this->newfields );
		$this->newfields = array();
		$this->save_tags();
		$this->info->commit();
		Plugins::act( 'post_update_after', $this );
		return $result;
	}
 
	/**
	 * function delete
	 * Deletes an existing post
	 */
	public function delete()
	{
		$allow = true;
		$allow = Plugins::filter( 'post_delete_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		// invoke plugins
		Plugins::act( 'post_delete_before', $this );
 
		// delete all the tags associated with this post
		foreach ( $this->get_tags() as $tag_slug => $tag_text ) {
			$tag = Tags::get_by_slug( $tag_slug );
			Tag::detach_from_post( $tag->id, $this->id );
		}
 
		// Delete all comments associated with this post
		if ( $this->comments->count() > 0 ) {
			$this->comments->delete();
		}
		// Delete all info records associated with this post
		if ( isset( $this->info ) ) {
			$this->info->delete_all();
		}
		// Delete all post_tokens associated with this post
		$this->delete_tokens();
 
		$result = parent::deleteRecord( DB::table( 'posts' ), array( 'slug'=>$this->slug ) );
		EventLog::log( sprintf(_t('Post %1$s (%2$s) deleted.'), $this->id, $this->slug), 'info', 'content', 'habari' );
 
		//scheduled post
		if( $this->status == Post::status( 'scheduled' ) ) {
			Posts::update_scheduled_posts_cronjob();
		}
 
		// invoke plugins on the after_post_delete action
		Plugins::act( 'post_delete_after', $this );
		return $result;
	}
 
	/**
	 * function publish
	 * Updates an existing post to published status
	 * @return boolean True on success, false if not
	 */
	public function publish()
	{
		if ( $this->status == Post::status( 'published' ) ) {
			return true;
		}
		$allow = true;
		$allow = Plugins::filter( 'post_publish_allow', $allow, $this );
		if ( ! $allow ) {
			return;
		}
		Plugins::act( 'post_publish_before', $this );
 
		if ( $this->status != Post::status( 'scheduled' ) )  {
			$this->pubdate = HabariDateTime::date_create();
		}
 
		if ( $this->status == Post::status( 'scheduled' ) ) {
			$this->get_tags();
			$msg = sprintf(_t('Scheduled Post %1$s (%2$s) published at %3$s.'), $this->id, $this->slug, $this->pubdate->format());
		}
		else {
			$msg = sprintf(_t('Post %1$s (%2$s) published.'), $this->id, $this->slug);
		}
 
		$this->status = Post::status( 'published' );
		$result = $this->update( false );
		EventLog::log( $msg, 'info', 'content', 'habari' );
 
		// and call any final plugins
		Plugins::act( 'post_publish_after', $this );
		return $result;
	}
 
	/**
	 * function __get
	 * Overrides QueryRecord __get to implement custom object properties
	 * @param string Name of property to return
	 * @return mixed The requested field value
	 */
	public function __get( $name )
	{
		$fieldnames = array_merge( array_keys( $this->fields ), array( 'permalink', 'tags', 'comments', 'comment_count', 'comment_feed_link', 'author', 'editlink' ) );
		if ( !in_array( $name, $fieldnames ) && strpos( $name, '_' ) !== false ) {
			preg_match( '/^(.*)_([^_]+)$/', $name, $matches );
			list( $junk, $name, $filter )= $matches;
		}
		else {
			$filter = false;
		}
 
		switch ( $name ) {
			case 'statusname':
				$out = self::status_name( $this->status );
				break;
			case 'typename':
				$out = self::type_name( $this->content_type );
				break;
			case 'permalink':
				$out = $this->get_permalink();
				break;
			case 'editlink':
				$out = $this->get_editlink();
				break;
			case 'tags':
				$out = $this->get_tags();
				break;
			case 'comments':
				$out = $this->get_comments();
				break;
			case 'comment_count':
				$out = $this->get_comments()->count();
				break;
			case 'comment_feed_link':
				$out = $this->get_comment_feed_link();
				break;
			case 'author':
				$out = $this->get_author();
				break;
			case 'info':
				$out = $this->get_info();
				break;
			default:
				$out = parent::__get( $name );
				break;
		}
		$out = Plugins::filter( "post_get", $out, $name, $this );
		$out = Plugins::filter( "post_{$name}", $out, $this );
		if ( $filter ) {
			$out = Plugins::filter( "post_{$name}_{$filter}", $out, $this );
		}
		return $out;
	}
 
	/**
	 * function __set
	 * Overrides QueryRecord __set to implement custom object properties
	 * @param string Name of property to return
	 * @return mixed The requested field value
	 */
	public function __set( $name, $value )
	{
		switch( $name ) {
			case 'pubdate':
			case 'updated':
			case 'modified':
				if ( !($value instanceOf HabariDateTime) ) {
					$value = HabariDateTime::date_create($value);
				}
				break;
			case 'tags':
				if ( is_array( $value) ) {
					return $this->tags = $value;
				}
				else {
					return $this->tags = $this->parsetags( $value );
				}
			case 'status':
				return $this->setstatus( $value );
		}
		return parent::__set( $name, $value );
	}
 
	/**
	 * Handle calls to this Post object that are implemented by plugins
	 * @param string $name The name of the function called
	 * @param array $args Arguments passed to the function call
	 * @return mixed The value returned from any plugin filters, null if no value is returned
	 */
	public function __call( $name, $args )
	{
		array_unshift($args, 'post_call_' . $name, null, $this);
		return call_user_func_array(array('Plugins', 'filter'), $args);
	}
 
	/**
	 * Returns a form for editing this post
	 * @param string $context The context the form is being created in, most often 'admin'
	 * @return FormUI A form appropriate for creating and updating this post.
	 */
	public function get_form($context)
	{
		$form = new FormUI('create-content');
		$form->class[] = 'create';
 
		$newpost = ( 0 === $this->id );
 
		// If the post has already been saved, add a link to its permalink
		if ( !$newpost ) {
			$post_links = $form->append('wrapper', 'post_links');
			$permalink = ( $this->status != Post::status( 'published' ) ) ? $this->permalink . '?preview=1' : $this->permalink;
			$post_links->append('static', 'post_permalink', '<a href="'. $permalink .'" class="viewpost" >'.( $this->status != Post::status('published') ? _t('Preview Post') : _t('View Post') ).'</a>');
			$post_links->class ='container';
		}
 
		// Create the Title field
		$form->append('text', 'title', 'null:null', _t('Title'), 'admincontrol_text');
		$form->title->class[] = 'important';
		$form->title->class[] = 'check-change';
		$form->title->tabindex = 1;
		$form->title->value = $this->title;
		$form->title->add_validator( 'validate_required' );
 
 
		// Create the silos
		if ( count( Plugins::get_by_interface( 'MediaSilo' ) ) ) {
			$form->append('silos', 'silos');
			$form->silos->silos = Media::dir();
		}
 
		// Create the Content field
		$form->append('textarea', 'content', 'null:null', _t('Content'), 'admincontrol_textarea');
		$form->content->class[] = 'resizable';
		$form->content->class[] = 'check-change';
		$form->content->tabindex = 2;
		$form->content->value = $this->content;
		$form->content->raw = true;
 
		// Create the tags field
		$form->append('text', 'tags', 'null:null', _t('Tags, separated by, commas'), 'admincontrol_text');
		$form->tags->class = 'check-change';
		$form->tags->tabindex = 3;
		$form->tags->value = implode(', ', $this->get_tags());
 
		// Create the splitter
		$publish_controls = $form->append('tabs', 'publish_controls');
 
		// Create the publishing controls
		// pass "false" to list_post_statuses() so that we don't include internal post statuses
		$statuses = Post::list_post_statuses( $this );
		unset( $statuses[array_search( 'any', $statuses )] );
		$statuses = Plugins::filter( 'admin_publish_list_post_statuses', $statuses );
 
		$settings = $publish_controls->append('fieldset', 'settings', _t('Settings'));
 
		$settings->append('select', 'status', 'null:null', _t('Content State'), array_flip($statuses), 'tabcontrol_select');
		$settings->status->value = $this->status;
 
		// hide the minor edit checkbox if the post is new
		if ( $newpost ) {
			$settings->append('hidden', 'minor_edit', 'null:null');
			$settings->minor_edit->value = false;
		}
		else {
			$settings->append('checkbox', 'minor_edit', 'null:null', _t('Minor Edit'), 'tabcontrol_checkbox');
			$settings->minor_edit->value = true;
			$form->append('hidden', 'modified', 'null:null')->value = $this->modified;
		}
 
		$settings->append('checkbox', 'comments_enabled', 'null:null', _t('Comments Allowed'), 'tabcontrol_checkbox');
		$settings->comments_enabled->value = $this->info->comments_disabled ? false : true;
 
		$settings->append('text', 'pubdate', 'null:null', _t('Publication Time'), 'tabcontrol_text');
		$settings->pubdate->value = $this->pubdate->format('Y-m-d H:i:s');
 
		$settings->append('text', 'newslug', 'null:null', _t('Content Address'), 'tabcontrol_text');
		$settings->newslug->value = $this->slug;
 
		// Create the button area
		$buttons = $form->append('fieldset', 'buttons');
		$buttons->template = 'admincontrol_buttons';
		$buttons->class[] = 'container';
		$buttons->class[] = 'buttons';
		$buttons->class[] = 'publish';
 
		// Create the Save button
		$require_any = array( 'own_posts' => 'create', 'post_any' => 'create', 'post_' . Post::type_name( $this->content_type ) => 'create' );
		if ( ( $newpost && User::identify()->can_any( $require_any ) ) || ( !$newpost && ACL::access_check( $this->get_access(), 'edit' ) ) ) {
			$buttons->append('submit', 'save', _t('Save'), 'admincontrol_submit');
			$buttons->save->tabindex = 4;
		}
 
		// Add required hidden controls
		$form->append('hidden', 'content_type', 'null:null');
		$form->content_type->id = 'content_type';
		$form->content_type->value = $this->content_type;
		$form->append('hidden', 'post_id', 'null:null');
		$form->post_id->id = 'id';
		$form->post_id->value = $this->id;
		$form->append('hidden', 'slug', 'null:null');
		$form->slug->value = $this->slug;
// 		$form->on_success( array( 'AdminHandler', 'form_publish_success' ), $this );
		$form->on_success( array( $this, 'form_publish_success' ) );
		// Let plugins alter this form
		Plugins::act('form_publish', $form, $this, $context);
 
		// Return the form object
		return $form;
	}
 
	public function form_publish_success( FormUI $form )
	{
Utils::debug( $this->id );
// die();
 
		$post_id = 0;
// 		if ( isset($this->handler_vars['id']) ) {
 		if ( isset($this->id) ) {
// 			$post_id = intval($this->handler_vars['id']);
			$post_id = intval($this->id);
		}
 
		// If an id has been passed in, we're updating an existing post, otherwise we're creating one
		if ( 0 !== $post_id ) {
			$post = Post::get( array( 'id' => $post_id, 'status' => Post::status( 'any' ) ) );
 
			$this->theme->admin_page = sprintf(_t('Publish %s'), Plugins::filter('post_type_display', Post::type_name($post->content_type), 'singular')); 
// 			$form = $post->get_form( 'admin' );
 
			// Verify that the post hasn't already been updated since the form was loaded
			if ( $post->modified != $form->modified->value ) {
				Session::notice( _t( 'The post %1$s was updated since you made changes.  Please review those changes before overwriting them.', array( sprintf('<a href="%1$s">\'%2$s\'</a>', $post->permalink, htmlspecialchars( $post->title ) ) ) ) );
				Utils::redirect( URL::get( 'admin', 'page=publish&id=' . $post->id ) );
				exit;
			}
 
			// Don't try to update form values that have been removed by plugins
			$expected = array('title', 'tags', 'content');
 
			foreach ( $expected as $field ) {
				if ( isset($form->$field) ) {
					$post->$field = $form->$field->value;
				}
			}
			if ( $form->newslug->value == '' ) {
				Session::notice( _t( 'A post slug cannot be empty. Keeping old slug.' ) );
			}
			elseif ( $form->newslug->value != $form->slug->value ) {
				$post->slug = $form->newslug->value;
			}
 
			// sorry, we just don't allow changing posts you don't have rights to
			if ( ! ACL::access_check( $post->get_access(), 'edit' ) ) {
				Session::error( _t( 'You don\'t have permission to edit that post' ) );
				$this->get_blank();
			}
			// sorry, we just don't allow changing content types to types you don't have rights to
			$user = User::identify();
			$type = 'post_' . Post::type_name( $form->content_type->value );
			if ( $form->content_type->value != $post->content_type && ( $user->cannot( $type ) || ! $user->can_any( array( 'own_posts' => 'edit', 'post_any' => 'edit', $type => 'edit' ) ) ) ) {
				Session::error(_t('Changing content types is not allowed'));
				$this->get_blank();
			}
			$post->content_type = $form->content_type->value;
 
			// if not previously published and the user wants to publish now, change the pubdate to the current date/time
			// if the post pubdate is <= the current date/time.
			if ( ( $post->status != Post::status( 'published' ) )
				&& ( $form->status->value == Post::status( 'published' ) )
				&& ( HabariDateTime::date_create( $form->pubdate->value )->int <= HabariDateTime::date_create()->int )
				) {
				$post->pubdate = HabariDateTime::date_create();
			}
			// else let the user change the publication date.
			//  If previously published and the new date is in the future, the post will be unpublished and scheduled. Any other status, and the post will just get the new pubdate.
			// This will result in the post being scheduled for future publication if the date/time is in the future and the new status is published.
			else {
				$post->pubdate = HabariDateTime::date_create( $form->pubdate->value );
			}
			$minor = $form->minor_edit->value && ($post->status != Post::status('draft'));
			$post->status = $form->status->value;
		}
		else {
			$post = new Post();
// 			$form = $post->get_form( 'admin' );
			// check the user can create new posts of the set type.
			$user = User::identify();
			$type = 'post_'  . Post::type_name($form->content_type->value);
			if ( ACL::user_cannot( $user, $type) || ( ! ACL::user_can( $user, 'post_any', 'create' ) && ! ACL::user_can( $user, $type, 'create') ) ) {
				Session::error(_t('Creating that post type is denied'));
				$this->get_blank();
			}
 
// 			$form->set_option( 'form_action', URL::get('admin', 'page=publish' ) );
			$form->on_success( array( $this, 'form_publish_success' ) );
 
			if ( HabariDateTime::date_create( $form->pubdate->value )->int > $post->pubdate->int ) {
				$post->pubdate = HabariDateTime::date_create( $form->pubdate->value );
			}
 
			$postdata = array(
				'slug' => $form->newslug->value,
				'user_id' => User::identify()->id,
				'pubdate' => $post->pubdate,
				'status' => $form->status->value,
				'content_type' => $form->content_type->value,
			);
 
			// Don't try to add form values that have been removed by plugins
			$expected = array('title', 'tags', 'content');
 
			foreach ( $expected as $field ) {
				if ( isset($form->$field) ) {
					$postdata[$field] = $form->$field->value;
				}
			}
 
			$minor = false;
 
			$post = Post::create( $postdata );
		}
 
		if ( $post->pubdate->int > HabariDateTime::date_create()->int && $post->status == Post::status( 'published' ) ) {
			$post->status = Post::status( 'scheduled' );
		}
 
		$post->info->comments_disabled = !$form->comments_enabled->value;
 
		Plugins::act('publish_post', $post, $form);
 
		$post->update( $minor );
 
		$permalink = ( $post->status != Post::status( 'published' ) ) ? $post->permalink . '?preview=1' : $post->permalink;
		Session::notice( sprintf( _t( 'The post %1$s has been saved as %2$s.' ), sprintf('<a href="%1$s">\'%2$s\'</a>', $permalink, htmlspecialchars( $post->title ) ), Post::status_name( $post->status ) ) );
		if ( $post->slug != Utils::slugify( $post->title ) ) {
			Session::notice( sprintf( _t( 'The content address is \'%1$s\'.'), $post->slug ));
		}
		Utils::redirect( URL::get( 'admin', 'page=publish&id=' . $post->id ) );
	}
 
	/**
	 * Manage this post's comment form
	 *
	 * @param String context // What is $context for ?
	 * @return FormUI The comment form for this post
	 */
	public function comment_form($context = 'public')
	{
		// Handle comment submissions and default commenter id values
		$cookie = 'comment_' . Options::get( 'GUID' );
		$commenter_name = '';
		$commenter_email = '';
		$commenter_url = '';
		$commenter_content = '';
		$user = User::identify();
		if ( isset( $_SESSION['comment'] ) ) {
			$details = Session::get_set( 'comment' );
			$commenter_name = $details['name'];
			$commenter_email = $details['email'];
			$commenter_url = $details['url'];
			$commenter_content = $details['content'];
		}
		elseif ( $user->loggedin ) {
			$commenter_name = $user->displayname;
			$commenter_email = $user->email;
			$commenter_url = Site::get_url( 'habari' );
		}
		elseif ( isset( $_COOKIE[$cookie] ) ) {
			list( $commenter_name, $commenter_email, $commenter_url )= explode( '#', $_COOKIE[$cookie] );
		}
 
		// Now start the form.
		$form = new FormUI('comment-' . $context, 'comment');
		$form->class[] = $context;
		$form->class[] = 'commentform';
		$form->set_option( 'form_action',  URL::get( 'submit_feedback', array( 'id' => $this->id ) ) );
 
		// Create the Name field
		$form->append(
			'text',
			'cf_commenter',
			'null:null',
			_t('Name <span class="required">*Required</span>'),
			'formcontrol_text'
		)->add_validator('validate_required', _t('The Name field value is required'))
		->id = 'comment_name';
		$form->cf_commenter->tabindex = 1;
		$form->cf_commenter->value = $commenter_name;
 
		// Create the Email field
		$form->append(
			'text',
			'cf_email',
			'null:null',
			_t('Email'),
			'formcontrol_text'
		)->add_validator('validate_email', _t('The Email field value must be a valid email address'))
		->id = 'comment_email';
		$form->cf_email->tabindex = 2;
		if ( Options::get('comments_require_id') == 1 ) {
			$form->cf_email->caption = _t('Email <span class="required">*Required</span>');
		}
		$form->cf_email->value = $commenter_email;
 
		// Create the URL field
		$form->append(
			'text',
			'cf_url',
			'null:null',
			_t('Website'),
			'formcontrol_text'
		)->add_validator('validate_url', _t('The Web Site field value must be a valid URL'))
		->id = 'comment_url';
		$form->cf_url->tabindex = 3;
		$form->cf_url->value = $commenter_url;
 
		// Create the Comment field
		$form->append(
			'text',
			'cf_content',
			'null:null',
			_t('Comment'),
			'formcontrol_textarea'
		)->add_validator('validate_required', _t('The Content field value is required'))
		->id = 'comment_content';
		$form->cf_content->tabindex = 4;
		$form->cf_content->value = $commenter_content;
 
		// Create the Submit button
		$form->append('submit', 'cf_submit', _t('Submit'), 'formcontrol_submit');
		$form->cf_submit->tabindex = 5;
 
		// Add required hidden controls
		/*
		$form->append('hidden', 'content_type', 'null:null');
		$form->content_type->value = $this->content_type;
		$form->append('hidden', 'post_id', 'null:null');
		$form->post_id->id = 'id';
		$form->post_id->value = $this->id;
		$form->append('hidden', 'slug', 'null:null');
		$form->slug->value = $this->slug;
		*/
 
		// Let plugins alter this form
		Plugins::act('form_comment', $form, $this, $context);
 
		// Return the form object
		return $form;
	}
 
 
	/**
	 * Returns a URL for the ->permalink property of this class.
	 * @return string A URL to this post.
	 * @todo separate permalink rule?  (Not sure what this means - OW)
	 */
	private function get_permalink()
	{
		$content_type = Post::type_name( $this->content_type );
		return URL::get(
			array(
				"display_{$content_type}",
				"display_post"
			),
			$this,
			false
		);
	}
 
	/**
	 * Returns a URL for the ->editlink property of this class.
	 * @return string A url to edit this post in the admin.
	 */
	private function get_editlink()
	{
		return URL::get('admin', 'page=publish&id=' . $this->id);
	}
 
	/**
	 * function get_tags
	 * Gets the tags for the post
	 * @return array The tags array for this post
	 */
	private function get_tags()
	{
		if ( empty( $this->tags ) ) {
			$result = Tags::get_associations( $this->id );
			if ( $result ) {
				foreach ( $result as $t ) {
					$this->tags[$t->term] = $t->term_display;
				}
			}
		}
		if ( count( $this->tags ) == 0 ) {
			return array();
		}
		return $this->tags;
	}
 
	/**
	 * function get_comments
	 * Gets the comments for the post
	 * @return &array A reference to the comments array for this post
	 */
	private function &get_comments()
	{
		if ( ! $this->comments_object ) {
			$this->comments_object = Comments::by_post_id( $this->id );
		}
		return $this->comments_object;
	}
 
	/**
	 * private function get_comment_feed_link
	 * Returns the permalink for this post's comments Atom feed
	 * @return string The permalink of this post's comments Atom feed
	 */
	private function get_comment_feed_link()
	{
		$content_type = Post::type_name( $this->content_type );
		return URL::get( array( "atom_feed_{$content_type}_comments" ), $this, false );
	}
 
	/**
	 * function get_info
	 * Gets the info object for this post, which contains data from the postinfo table
	 * related to this post.
	 * @return PostInfo object
	 */
	private function get_info()
	{
		if ( ! isset( $this->inforecords ) ) {
			// If this post isn't in the database yet...
			if(  0 == $this->id ) {
				$this->inforecords = new PostInfo();
			}
			else {
				$this->inforecords = new PostInfo( $this->id );
			}
		}
		else {
			$this->inforecords->set_key( $this->id );
		}
		return $this->inforecords;
	}
 
	/**
	 * private function get_author()
	 * returns a User object for the author of this post
	 * @return User a User object for the author of the current post
	 */
	private function get_author()
	{
		if ( ! isset( $this->author_object ) ) {
			// XXX for some reason, user_id is a string sometimes?
			$this->author_object = User::get_by_id( $this->user_id );
		}
		return $this->author_object;
	}
 
	/**
	 * Returns a set of properties used by URL::get to create URLs
	 * @return array Properties of this post used to build a URL
	 */
	public function get_url_args()
	{
		if ( !$this->url_args ) {
			$arr = array( 'content_type_name' => Post::type_name( $this->content_type ) );
			$author = URL::extract_args( $this->author, 'author_' );
			$info = URL::extract_args( $this->info, 'info_' );
			$this->url_args = array_merge( $author, $info, $arr, $this->to_array(), $this->pubdate->getdate() );
		}
		return $this->url_args;
	}
 
	/**
	 * Returns the ascending post, relative to this post, according to params
	 * @params The params by which to work out what is the ascending post
	 * @return Post The ascending post
	 */
	public function ascend($params = null)
	{
		return Posts::ascend($this, $params);
	}
 
	/**
	 * Returns the descending post, relative to this post, according to params
	 * @params The params by which to work out what is the descending post
	 * @return Post The descending post
	 */
	public function descend($params = null)
	{
		return Posts::descend($this, $params);
	}
 
	/**
	 * Return the content type of this object
	 *
	 * @return array An array of content types that this object represents, starting with the most specific
	 * @see IsContent
	 */
	public function content_type()
	{
		return array(Post::type_name($this->content_type), 'Post');
	}
 
	/**
	 * Adds the default tokens to this post when it's saved
	 */
	public function create_default_tokens()
	{
		$tokens = array();
		$tokens = Plugins::filter('post_tokens', $tokens, $this);
		$this->add_tokens( $this->content_type() );
	}
 
	/**
	 * Checks if this post has one or more tokens
	 *
	 * @param mixed $tokens A single token string or an array of tokens
	 * @return mixed false if no tokens match, an array of matching token ids if any match
	 */
	public function has_tokens( $tokens )
	{
		$this->get_tokens();
		$tokens = Utils::single_array( $tokens );
		$tokens = array_map(array('ACL', 'token_id'), $tokens);
		$tokens = array_intersect($tokens, $this->tokens);
		if ( count($tokens) == 0 ) {
			return false;
		}
		return $tokens;
	}
 
	/**
	 * Add a token to a post
	 * @param mixed $token The name of the permission to add, or an array of permissions to add
	 */
	public function add_tokens( $tokens )
	{
		$this->get_tokens();
		$tokens = Utils::single_array( $tokens );
		$tokens = array_map(array('ACL', 'token_id'), $tokens);
		$add_tokens = array_diff($tokens, $this->tokens);
		$add_tokens = array_unique($add_tokens);
		foreach ( $add_tokens as $token_id ) {
			DB::insert( '{post_tokens}', array( 'post_id' => $this->id, 'token_id' => $token_id ) );
		}
		$this->tokens = array_merge($this->tokens, $add_tokens);
		$this->tokens = array_unique($this->tokens);
	}
 
	/**
	 * Deletes all tokens from a post
	 */
	public function delete_tokens()
	{
		DB::delete( '{post_tokens}', array( 'post_id' => $this->id ) );
		$this->tokens = array();
	}
 
	/**
	 * Deletes tokens from a post
	 * @param mixed $token The name of the permission to remove, or an array of permissions to remove
	 */
	public function remove_tokens( $tokens )
	{
		$this->get_tokens();
		$tokens = Utils::single_array( $tokens );
		$tokens = array_map(array('ACL', 'token_id'), $tokens);
		$remove_tokens = array_intersect($tokens, $this->tokens);
		foreach ( $remove_tokens as $token_id ) {
			DB::delete( '{post_tokens}', array( 'post_id' => $this->id, 'token_id' => $token_id ) );
		}
		$this->tokens = array_diff($this->tokens, $remove_tokens);
	}
 
	/**
	 * Applies a new set of specific tokens to a post
	 * @param mixed $tokens A string token, or an array of tokens to apply to this post
	 */
	public function set_tokens( $tokens )
	{
		$tokens = Utils::single_array( $tokens );
		$new_tokens = array_map(array('ACL', 'token_id'), $tokens);
		$new_tokens = array_unique($new_tokens);
		DB::delete( '{post_tokens}', array( 'post_id' => $this->id ) );
		foreach ( $new_tokens as $token_id ) {
			DB::insert( '{post_tokens}', array( 'post_id' => $this->id, 'token_id' => $token_id ) );
		}
		$this->tokens = $new_tokens;
	}
 
	/**
	 * Returns an array of token ids that are associated with this post
	 * Also initializes the internal token array for use by other token operations
	 *
	 * @return array An array of token ids
	 */
	public function get_tokens()
	{
		if ( empty( $this->tokens ) ) {
			$this->tokens = DB::get_column( 'SELECT token_id FROM {post_tokens} WHERE post_id = ?', array($this->id) );
		}
		return $this->tokens;
	}
 
	/**
	 * Returns an access Bitmask for the given user on this post
	 * @param User $user The user mask to fetch
	 * @return Bitmask
	 */
	public function get_access( $user = null )
	{
		if ( ! $user instanceof User ) {
			$user = User::identify();
		}
 
		if ( $user->can( 'super_user' ) ) {
			return ACL::get_bitmask( 'full' );
		}
 
		// Collect a list of applicable tokens
		$tokens = array(
			'post_any',
			'post_' . Post::type_name( $this->content_type ),
		);
 
		if ( $user->id == $this->user_id) {
			$tokens[] = 'own_posts';
		}
 
		$tokens = array_merge($tokens, $this->get_tokens());
 
		// collect all possible token accesses on this post
		$token_accesses = array();
		foreach ( $tokens as $token ) {
			$access = ACL::get_user_token_access( $user, $token );
			if ( $access instanceof Bitmask ) {
				$token_accesses[] = ACL::get_user_token_access( $user, $token )->value;
			}
		}
 
		// now that we have all the accesses, loop through them to build the access to the particular post
		if ( in_array( 0, $token_accesses ) ) {
			return ACL::get_bitmask( 0 );
		}
		return ACL::get_bitmask( Utils::array_or( $token_accesses ) );
	}
 
}
?>

Toggle wordwrap

adminhandler.phpraw

<?php
/**
 * @package Habari
 *
 */
 
/**
 * Habari AdminHandler Class
 * Backbone of the admin area, handles requests and functionality.
 *
 * @todo Split into page-specific controllers.
 * Discussion: See http://groups.google.com/group/habari-dev/browse_thread/thread/9c469a4fcb61c814
 * Branch: https://trac.habariproject.org/habari/browser/branches/adminhandler
 * Related branch: http://trac.habariproject.org/habari/browser/branches/handlers
 */
class AdminHandler extends ActionHandler
{
	/** An instance of the active public theme, which allows plugin hooks to execute */
	protected $active_theme = NULL;
 
	/**
	 * Verifies user credentials before creating the theme and displaying the request.
	 */
	public function __construct()
	{
		$user = User::identify();
		if ( !$user->loggedin ) {
			Session::add_to_set( 'login', $_SERVER['REQUEST_URI'], 'original' );
			if ( URL::get_matched_rule()->name == 'admin_ajax' && isset($_SERVER['HTTP_REFERER']) ) {
				header( 'Content-Type: text/javascript;charset=utf-8' );
				echo '{callback: function(){location.href="'.$_SERVER['HTTP_REFERER'].'"} }';
			}
			else {
				$post_raw = $_POST->get_array_copy_raw();
				if ( !empty( $post_raw ) ) {
					Session::add_to_set( 'last_form_data', $post_raw, 'post' );
					Session::error( _t('We saved the last form you posted. Log back in to continue its submission.'), 'expired_form_submission' );
				}
				$get_raw = $_GET->get_array_copy_raw();
				if ( !empty( $get_raw ) ) {
					Session::add_to_set( 'last_form_data', $get_raw, 'get' );
					Session::error( _t('We saved the last form you posted. Log back in to continue its submission.'), 'expired_form_submission' );
				}
				Utils::redirect( URL::get( 'user', array( 'page' => 'login' ) ) );
			}
			exit;
		}
 
		$last_form_data = Session::get_set( 'last_form_data' ); // This was saved in the "if ( !$user )" above, UserHandler transferred it properly.
		/* At this point, Controller has not created handler_vars, so we have to modify $_POST/$_GET. */
		if ( isset( $last_form_data['post'] ) ) {
			$_POST = $_POST->merge( $last_form_data['post'] );
			$_SERVER['REQUEST_METHOD'] = 'POST'; // This will trigger the proper act_admin switches.
			Session::remove_error( 'expired_form_submission' );
		}
		if ( isset( $last_form_data['get'] ) ) {
			$_GET = $_GET->merge( $last_form_data['get'] );
			Session::remove_error( 'expired_form_submission' );
			// No need to change REQUEST_METHOD since GET is the default.
		}
		$user->remember();
 
		// Create an instance of the active public theme so that its plugin functions are implemented
		$this->active_theme = Themes::create();
 
		// setup the stacks for javascript in the admin - it's a method so a plugin can call it externally
		self::setup_stacks();
	}
 
	/**
	 * Dispatches the request to the defined method. (ie: post_{page})
	 */
	public function act_admin()
	{
		$page = ( isset( $this->handler_vars['page'] ) && !empty( $this->handler_vars['page'] ) ) ? $this->handler_vars['page'] : 'dashboard';
		if ( isset($this->handler_vars['content_type']) ) {
			$type = Plugins::filter('post_type_display', Post::type_name($this->handler_vars['content_type']), 'singular');
		}
		elseif ( $page == 'publish' && isset($this->handler_vars['id'] ) ) {
			$type = Plugins::filter('post_type_display', Post::type_name(Post::get(intval($this->handler_vars['id']))->content_type), 'singular');
		}
		else {
			$type = '';
		}
		//$type = ( isset( $this->handler_vars['content_type'] ) && !empty( $this->handler_vars['content_type'] ) ) ? $this->handler_vars['content_type'] : '';
		$theme_dir = Plugins::filter( 'admin_theme_dir', Site::get_dir( 'admin_theme', TRUE ) );
		$this->theme = Themes::create( 'admin', 'RawPHPEngine', $theme_dir );
 
		// Add some default stylesheets
		Stack::add('admin_stylesheet', array(Site::get_url('admin_theme') . '/css/admin.css', 'screen'), 'admin');
 
			// Add some default template variables
		$this->set_admin_template_vars( $this->theme );
		$this->theme->admin_type = $type;
		$this->theme->admin_page = $page;
		$this->theme->admin_page_url = ( $page == 'dashboard' ) ? URL::get( 'admin', 'page=' ) : URL::get( 'admin', 'page=' . $page );
		$this->theme->page = $page;
		$this->theme->admin_title = ucwords($page) . ( $type != '' ? ' ' . ucwords($type) : '' );
		$this->theme->admin_title =
			isset( $this->theme->mainmenu[$this->theme->admin_page]['text'] )
				? $this->theme->mainmenu[$this->theme->admin_page]['text']
				: ucwords($page) . ( $type != '' ? ' ' . ucwords($type) : '' );
 
		// Access check to see if the user is allowed the requested page
		Utils::check_request_method( array( 'GET', 'HEAD', 'POST' ) );
		if ( !$this->access_allowed( $page, $type ) ) {
			Session::error(_t('Access to that page has been denied by the administrator.'));
			$this->get_blank();
		}
 
		switch( $_SERVER['REQUEST_METHOD'] ) {
			case 'POST':
				// Let plugins try to handle the page
				Plugins::act('admin_theme_post_' . $page, $this, $this->theme);
				// Handle POSTs to the admin pages
				$fn = 'post_' . $page;
				if ( method_exists( $this, $fn ) ) {
					$this->$fn();
				}
				else {
					$classname = get_class( $this );
					echo sprintf( _t( '%1$s->%2$s() does not exist.' ), $classname, $fn );
					exit;
				}
				break;
			case 'GET':
			case 'HEAD':
				// Let plugins try to handle the page
				Plugins::act('admin_theme_get_' . $page, $this, $this->theme);
				// Handle GETs of the admin pages
				$fn = 'get_' . $page;
				if ( method_exists( $this, $fn ) ) {
					$this->$fn();
					exit;
				}
				// If a get_ function doesn't exist, just load the template and display it
				if ( $this->theme->template_exists( $page ) ) {
					$this->display( $page );
				}
				else {
					// The requested console page doesn't exist
					header( 'HTTP/1.0 404 Not Found' );
					$this->get_blank(_t('The page you were looking for was not found.'));
				}
				break;
		}
	}
 
	/**
	 * Handle incoming requests to /admin_ajax for admin ajax requests
	 */
	public function act_admin_ajax()
	{
		header( 'Content-Type: text/javascript;charset=utf-8' );
		$context = $this->handler_vars['context'];
		if ( method_exists( $this, 'ajax_' . $context ) ) {
			$type = ( isset( $this->handler_vars['content_type'] ) && !empty( $this->handler_vars['content_type'] ) ) ? $this->handler_vars['content_type'] : '';
			// Access check to see if the user is allowed the requested page
			if ( $this->access_allowed( 'ajax_' . $context, $type ) ) {
				call_user_func( array( $this, 'ajax_' . $context ), $this->handler_vars );
			}
		}
		else {
			header( 'HTTP/1.1 403 Forbidden', true, 403 );
			die();
		}
	}
 
	/**
	 * Handles get requests from the options admin page
	 */
	public function get_options()
	{
		$this->post_options();
	}
 
	/**
	 * Handles POST requests from the options admin page
	 */
	public function post_options()
	{
		$option_items = array();
		$timezones = DateTimeZone::listIdentifiers();
		$timezones = array_merge( array( ''=>'' ), array_combine( array_values( $timezones ), array_values( $timezones ) ) );
 
		$option_items[_t('Name & Tagline')] = array(
			'title' => array(
				'label' => _t('Site Name'),
				'type' => 'text',
				'helptext' => '',
				),
			'tagline' => array(
				'label' => _t('Site Tagline'),
				'type' => 'text',
				'helptext' => '',
				),
			'about'   => array(
				'label'    => _t('About'),
				'type'     => 'textarea',
				'helptext' => '',
				),
			);
 
		$option_items[_t('Publishing')] = array(
			'pagination' => array(
				'label' => _t('Items per Page'),
				'type' => 'text',
				'helptext' => '',
				),
			'atom_entries' => array(
				'label' => _t('Entries to show in Atom feed'),
				'type' => 'text',
				'helptext' => '',
				),
			'comments_require_id' => array(
				'label' => _t('Require Comment Author Info'),
				'type' => 'checkbox',
				'helptext' => '',
				),
			);
 
		$option_items[_t('Time & Date')] = array(
			/*'presets' => array(
				'label' => _t('Presets'),
				'type' => 'select',
				'selectarray' => array(
					'europe' => _t('Europe')
					),
				'helptext' => '',
				),*/
			'timezone' => array(
				'label' => _t('Time Zone'),
				'type' => 'select',
				'selectarray' => $timezones,
				'helptext' => _t( 'Current Date Time: %s', array( HabariDateTime::date_create()->format() ) ),
				),
			'dateformat' => array(
				'label' => _t('Date Format'),
				'type' => 'text',
				'helptext' => _t( 'Current Date: %s', array( HabariDateTime::date_create()->date ) ),
				),
			'timeformat' => array(
				'label' => _t('Time Format'),
				'type' => 'text',
				'helptext' => _t( 'Current Time: %s', array( HabariDateTime::date_create()->time ) ),
				)
			);
 
		$option_items[_t('Language')] = array(
			'locale' => array(
				'label' => _t( 'Locale' ),
				'type' => 'select',
				'selectarray' => array_merge( array( '' => 'default' ), array_combine( HabariLocale::list_all(), HabariLocale::list_all() ) ),
				'helptext' => _t( 'International language code' ),
			),
			'system_locale' => array(
				'label' => _t('System Locale'),
				'type' => 'text',
				'helptext' => _t( 'The appropriate locale code for your server' ),
			),
		);
 
		$option_items[_t('Troubleshooting')] = array(
			'log_backtraces' => array(
				'label' => _t( 'Log Backtraces' ),
				'type' => 'checkbox',
				'helptext' => _t( 'Logs error backtraces to the log table\'s data column. Can drastically increase log size!' ),
			),
		);
 
			/*$option_items[_t('Presentation')] = array(
			'encoding' => array(
				'label' => _t('Encoding'),
				'type' => 'select',
				'selectarray' => array(
					'UTF-8' => 'UTF-8'
					),
				'helptext' => '',
				),
			);*/
 
		$option_items = Plugins::filter( 'admin_option_items', $option_items );
 
		$form = new FormUI('Admin Options');
		$tab_index = 3;
		foreach ( $option_items as $name => $option_fields ) {
			$fieldset = $form->append( 'wrapper', Utils::slugify( _u($name) ), $name );
			$fieldset->class = 'container settings';
			$fieldset->append( 'static', $name, '<h2>' . htmlentities( $name, ENT_COMPAT, 'UTF-8' ) . '</h2>' );
			foreach ( $option_fields as $option_name => $option ) {
				$field = $fieldset->append( $option['type'], $option_name, $option_name, $option['label'] );
				$field->template = 'optionscontrol_' . $option['type'];
				$field->class = 'item clear';
				if ( $option['type'] == 'select' && isset( $option['selectarray'] ) ) {
					$field->options = $option['selectarray'];
				}
				$field->tabindex = $tab_index;
				$tab_index++;
				if ( isset( $option['helptext'] ) ) {
					$field->helptext = $option['helptext'];
				}
				else {
					$field->helptext = '';
				}
			}
		}
 
		/* @todo: filter for additional options from plugins
		 * We could either use existing config forms and simply extract
		 * the form controls, or we could create something different
		 */
 
		$submit = $form->append( 'submit', 'apply', _t('Apply'), 'admincontrol_submit' );
		$submit->tabindex = $tab_index;
		$form->on_success( array( $this, 'form_options_success' ) );
 
		$this->theme->form = $form->get();
		$this->theme->option_names = array_keys( $option_items );
		$this->theme->display( 'options' );
		}
 
	/**
	 * Display a message when the site options are saved, and save those options
	 *
	 * @param FormUI $form The successfully submitted form
	 */
	public function form_options_success($form)
	{
		Session::notice( _t( 'Successfully updated options' ) );
		$form->save();
		Utils::redirect();
	}
 
	/**
	 * Handles POST requests from the dashboard.
	 */
	public function post_dashboard()
	{
		$this->get_dashboard();
	}
 
	/**
	 * Handles get requests for the dashboard
	 * @todo update check should probably be cron'd and cached, not re-checked every load
	 */
	public function get_dashboard()
	{
		// Not sure how best to determine this yet, maybe set an option on install, maybe do this:
		$firstpostdate = DB::get_value('SELECT min(pubdate) FROM {posts} WHERE status = ?', array(Post::status('published')));
		if ( intval( $firstpostdate ) !== 0 ) $firstpostdate = time() - $firstpostdate;
		$this->theme->active_time = array(
			'years' => floor($firstpostdate / 31556736),
			'months' => floor(($firstpostdate % 31556736) / 2629728),
			'days' => round(($firstpostdate % 2629728) / 86400),
		);
 
 
		// get the active theme, so we can check it
		$active_theme = Themes::get_active();
		$active_theme = $active_theme->name . ':' . $active_theme->version;
 
		// if the active plugin list has changed, expire the updates cache
		if ( Cache::has( 'dashboard_updates' ) && ( Cache::get( 'dashboard_updates_plugins' ) != Options::get( 'active_plugins' ) ) ) {
			Cache::expire( 'dashboard_updates' );
		}
 
		// if the theme version has changed, expire the updates cache
		if ( Cache::has( 'dashboard_updates' ) && ( Cache::get( 'dashboard_updates_theme' ) != $active_theme ) ) {
			Cache::expire( 'dashboard_updates' );
		}
 
		/*
		 * Check for updates to core and any hooked plugins
		 * cache the output so we don't make a request every load but can still display updates
		 */
		if ( Cache::has( 'dashboard_updates' ) ) {
			$this->theme->updates = Cache::get( 'dashboard_updates' );
		}
		else {
			$updates = Update::check();
 
			if ( !Error::is_error( $updates ) ) {
				Cache::set( 'dashboard_updates', $updates );
				$this->theme->updates = $updates;
 
				// cache the set of plugins we just used to check for
				Cache::set( 'dashboard_updates_plugins', Options::get( 'active_plugins' ) );
 
				// cache the active theme we just used to check for
				Cache::set( 'dashboard_updates_theme', $active_theme );
			}
			else {
				$this->theme->updates = array();
			}
		}
 
		$this->theme->stats = array(
			'author_count' => Users::get( array( 'count' => 1 ) ),
			'page_count' => Posts::get( array( 'count' => 1, 'content_type' => Post::type('page'), 'status' => Post::status('published') ) ),
			'entry_count' => Posts::get( array( 'count' => 1, 'content_type' => Post::type('entry'), 'status' => Post::status('published') ) ),
			'comment_count' => Comments::count_total( Comment::STATUS_APPROVED, FALSE ),
			'tag_count' => Tags::count_total(),
			'page_draft_count' => Posts::get( array( 'count' => 1, 'content_type' => Post::type('page'), 'status' => Post::status('draft'), 'user_id' => User::identify()->id ) ),
			'entry_draft_count' => Posts::get( array( 'count' => 1, 'content_type' => Post::type('entry'), 'status' => Post::status('draft'), 'user_id' => User::identify()->id ) ),
			'unapproved_comment_count' => User::identify()->can( 'manage_all_comments' ) ? Comments::count_total( Comment::STATUS_UNAPPROVED, FALSE ) : Comments::count_by_author( User::identify()->id, Comment::STATUS_UNAPPROVED ),
			'spam_comment_count' => User::identify()->can( 'manage_all_comments' ) ? Comments::count_total( Comment::STATUS_SPAM, FALSE ) : Comments::count_by_author( User::identify()->id, Comment::STATUS_SPAM ),
			'user_entry_scheduled_count' => Posts::get( array( 'count' => 1, 'content_type' => Post::type( 'any' ), 'status' => Post::status( 'scheduled' ), 'user_id' => User::identify()->id ) ),
		);
 
		$this->fetch_dashboard_modules();
 
		// check for first run
		$u = User::identify();
		if ( ! isset( $u->info->experience_level ) ) {
			$this->theme->first_run = true;
			$u->info->experience_level = 'user';
			$u->info->commit();
		}
		else {
			$this->theme->first_run = false;
		}
 
		$this->display( 'dashboard' );
	}
 
	/**
	 * Fetches active modules for display on the dashboard
	 */
/* 	public function fetch_dashboard_modules()
	{
 
		if ( count( Modules::get_all() ) == 0 ) {
			$this->theme->modules = array();
			return;
		}
 
		// get the active module list
		$modules = Modules::get_active();
 
		if(User::identify()->can('manage_dash_modules')) {
			// append the 'Add Item' module
			$modules['nosort'] = 'Add Item';
 
			// register the 'Add Item' filter
			Plugins::register( array( $this, 'filter_dash_module_add_item' ), 'filter', 'dash_module_add_item');
		}
 
		foreach ( $modules as $id => $module_name ) {
			$slug = Utils::slugify( (string) $module_name, '_' );
			$module = array(
				'name' => $module_name,
				'title' => $module_name,
				'content' => '',
				'options' => ''
				);
 
			$module = Plugins::filter( 'dash_module_' .$slug, $module, $id, $this->theme );
 
			$modules[$id] = $module;
		}
 
		$this->theme->modules = $modules;
	}
*/
	/**
	 * Handles POST requests from the publish page.
	 */
	public function post_publish()
	{
		$this->get_publish();
	}
 
	public static function form_publish_success( FormUI $form , $thispost )
	{
		$post_id = 0;
		if ( isset($thispost->id) ) {
			$post_id = intval($thispost->id);
		}
Utils::debug( $post_id );
		// If an id has been passed in, we're updating an existing post, otherwise we're creating one
		if ( 0 !== $post_id ) {
			$post = Post::get( array( 'id' => $post_id, 'status' => Post::status( 'any' ) ) );
 
			$thispost->theme->admin_page = sprintf(_t('Publish %s'), Plugins::filter('post_type_display', Post::type_name($post->content_type), 'singular')); 
// 			$form = $post->get_form( 'admin' );
 
			// Verify that the post hasn't already been updated since the form was loaded
			if ( $post->modified != $form->modified->value ) {
				Session::notice( _t( 'The post %1$s was updated since you made changes.  Please review those changes before overwriting them.', array( sprintf('<a href="%1$s">\'%2$s\'</a>', $post->permalink, htmlspecialchars( $post->title ) ) ) ) );
				Utils::redirect( URL::get( 'admin', 'page=publish&id=' . $post->id ) );
				exit;
			}
 
			// Don't try to update form values that have been removed by plugins
			$expected = array('title', 'tags', 'content');
 
			foreach ( $expected as $field ) {
				if ( isset($form->$field) ) {
					$post->$field = $form->$field->value;
				}
			}
			if ( $form->newslug->value == '' ) {
				Session::notice( _t( 'A post slug cannot be empty. Keeping old slug.' ) );
			}
			elseif ( $form->newslug->value != $form->slug->value ) {
				$post->slug = $form->newslug->value;
			}
 
			// sorry, we just don't allow changing posts you don't have rights to
			if ( ! ACL::access_check( $post->get_access(), 'edit' ) ) {
				Session::error( _t( 'You don\'t have permission to edit that post' ) );
				$thispost->get_blank();
			}
			// sorry, we just don't allow changing content types to types you don't have rights to
			$user = User::identify();
			$type = 'post_' . Post::type_name( $form->content_type->value );
			if ( $form->content_type->value != $post->content_type && ( $user->cannot( $type ) || ! $user->can_any( array( 'own_posts' => 'edit', 'post_any' => 'edit', $type => 'edit' ) ) ) ) {
				Session::error(_t('Changing content types is not allowed'));
				$thispost->get_blank();
			}
			$post->content_type = $form->content_type->value;
 
			// if not previously published and the user wants to publish now, change the pubdate to the current date/time
			// if the post pubdate is <= the current date/time.
			if ( ( $post->status != Post::status( 'published' ) )
				&& ( $form->status->value == Post::status( 'published' ) )
				&& ( HabariDateTime::date_create( $form->pubdate->value )->int <= HabariDateTime::date_create()->int )
				) {
				$post->pubdate = HabariDateTime::date_create();
			}
			// else let the user change the publication date.
			//  If previously published and the new date is in the future, the post will be unpublished and scheduled. Any other status, and the post will just get the new pubdate.
			// This will result in the post being scheduled for future publication if the date/time is in the future and the new status is published.
			else {
				$post->pubdate = HabariDateTime::date_create( $form->pubdate->value );
			}
			$minor = $form->minor_edit->value && ($post->status != Post::status('draft'));
			$post->status = $form->status->value;
		}
		else {
			$post = new Post();
// 			$form = $post->get_form( 'admin' );
			// check the user can create new posts of the set type.
			$user = User::identify();
			$type = 'post_'  . Post::type_name($form->content_type->value);
			if ( ACL::user_cannot( $user, $type) || ( ! ACL::user_can( $user, 'post_any', 'create' ) && ! ACL::user_can( $user, $type, 'create') ) ) {
				Session::error(_t('Creating that post type is denied'));
				$thispost->get_blank();
			}
 
// 			$form->set_option( 'form_action', URL::get('admin', 'page=publish' ) );
			$form->on_success( array( $thispost, 'form_publish_success' ) );
 
			if ( HabariDateTime::date_create( $form->pubdate->value )->int > $post->pubdate->int ) {
				$post->pubdate = HabariDateTime::date_create( $form->pubdate->value );
			}
 
			$postdata = array(
				'slug' => $form->newslug->value,
				'user_id' => User::identify()->id,
				'pubdate' => $post->pubdate,
				'status' => $form->status->value,
				'content_type' => $form->content_type->value,
			);
 
			// Don't try to add form values that have been removed by plugins
			$expected = array('title', 'tags', 'content');
 
			foreach ( $expected as $field ) {
				if ( isset($form->$field) ) {
					$postdata[$field] = $form->$field->value;
				}
			}
 
			$minor = false;
 
			$post = Post::create( $postdata );
		}
 
		if ( $post->pubdate->int > HabariDateTime::date_create()->int && $post->status == Post::status( 'published' ) ) {
			$post->status = Post::status( 'scheduled' );
		}
 
		$post->info->comments_disabled = !$form->comments_enabled->value;
 
		Plugins::act('publish_post', $post, $form);
 
		$post->update( $minor );
 
		$permalink = ( $post->status != Post::status( 'published' ) ) ? $post->permalink . '?preview=1' : $post->permalink;
		Session::notice( sprintf( _t( 'The post %1$s has been saved as %2$s.' ), sprintf('<a href="%1$s">\'%2$s\'</a>', $permalink, htmlspecialchars( $post->title ) ), Post::status_name( $post->status ) ) );
		if ( $post->slug != Utils::slugify( $post->title ) ) {
			Session::notice( sprintf( _t( 'The content address is \'%1$s\'.'), $post->slug ));
		}
		Utils::redirect( URL::get( 'admin', 'page=publish&id=' . $post->id ) );
	}
 
	/**
	 * Handles GET requests of the publish page.
	 */
	public function get_publish( $template = 'publish')
	{
		$extract = $this->handler_vars->filter_keys('id', 'content_type');
		foreach ( $extract as $key => $value ) {
			$$key = $value;
		}
 
// Utils::debug( $id );
		// 0 is what's assigned to new posts
 		if ( isset( $id ) && ( $id != 0 )) {
			$post = Post::get( array( 'id' => $id, 'status' => Post::status( 'any' ) ) );
			if ( !$post ) {
				Session::error(_t('Access to that post id is denied'));
				$this->get_blank();
			}
			$this->theme->post = $post;
		}
		else {
			$post = new Post();
			$this->theme->post = $post;
			$post->content_type = Post::type( ( isset( $content_type ) ) ? $content_type : 'entry' );
 
			// check the user can create new posts of the set type.
			$user = User::identify();
			$type = 'post_' . Post::type_name( $post->content_type );
			if ( ACL::user_cannot( $user, $type ) || ( ! ACL::user_can( $user, 'post_any', 'create' ) && ! ACL::user_can( $user, $type, 'create' ) ) ) {
				Session::error( _t( 'Access to create posts of type %s is denied', array( Post::type_name( $post->content_type ) ) ) );
				$this->get_blank();
			}
		}
// Utils::debug( $this->theme );
 
		$this->theme->admin_page = sprintf(_t('Publish %s'), Plugins::filter('post_type_display', Post::type_name($post->content_type), 'singular')); 
		$this->theme->admin_title = sprintf(_t('Publish %s'), Plugins::filter('post_type_display', Post::type_name($post->content_type), 'singular')); 
// Utils::debug( $this->theme );
 
		$statuses = Post::list_post_statuses( false );
		$this->theme->statuses = $statuses;
 
		$form = $post->get_form( 'admin' );
		$form->set_option( 'form_action', URL::get('admin', 'page=publish' ) );
 
		$this->theme->form = $form;
 
		$this->theme->wsse = Utils::WSSE();
		$this->display( $template );
 
	}
 
	/**
	 * Deletes a post from the database.
	 */
	public function post_delete_post()
	{
		$extract = $this->handler_vars->filter_keys('id', 'nonce', 'timestamp', 'digest');
		foreach ( $extract as $key => $value ) {
			$$key = $value;
		}
 
		$okay = TRUE;
		if ( empty( $id ) || empty( $nonce ) || empty( $timestamp ) || empty( $digest ) ) {
			$okay = FALSE;
		}
		$wsse = Utils::WSSE( $nonce, $timestamp );
		if ( $digest != $wsse['digest'] ) {
			$okay = FALSE;
		}
 
		$post = Post::get( array( 'id' => $id, 'status' => Post::status( 'any' ) ) );
		if ( ! ACL::access_check( $post->get_access(), 'delete' ) ) {
			$okay = FALSE;
		}
 
		if ( !$okay )	{
			Utils::redirect( URL::get( 'admin', 'page=posts&type='. Post::status( 'any' ) ) );
		}
 
		$post->delete();
		Session::notice( sprintf( _t( 'Deleted the %1$s titled "%2$s".' ), Post::type_name( $post->content_type ), htmlspecialchars( $post->title ) ) );
		Utils::redirect( URL::get( 'admin', 'page=posts&type=' . Post::status( 'any' ) ) );
	}
 
	/**
	 * Handles GET requests of a user page.
	 */
	public function get_user()
	{
 
		$edit_user = User::identify();
		$permission = false;
 
		if ( ($this->handler_vars['user'] == '') || (User::get_by_name($this->handler_vars['user']) == $edit_user) ) {
			if($edit_user->can('manage_self') || $edit_user->can('manage_users')) {
				$permission = true;
			}
			$who = _t("You");
			$possessive = _t("Your User Information");
		}
		else {
			if($edit_user->can('manage_users')) {
				$permission = true;
			}
			$edit_user = User::get_by_name($this->handler_vars['user']);
			$who = $edit_user->username;
			$possessive = sprintf( _t("%s's User Information"), $who );
		}
 
		if(!$permission) {
			Session::error(_t('Access to that page has been denied by the administrator.'));
			$this->get_blank();
			return;
		}
 
		// Get author list
		$author_list = Users::get_all();
		$authors[0] = _t('nobody');
		foreach ( $author_list as $author ) {
			$authors[ $author->id ] = $author->displayname;
		}
 
		unset($authors[ $edit_user->id ]); // We can't reassign posts to ourself
 
		$this->theme->authors = $authors;
		$this->theme->edit_user = $edit_user;
		$this->theme->who = $who;
		$this->theme->possessive = $possessive;
 
		// Redirect to the users management page if we're trying to edit a non-existent user
		if ( !$edit_user ) {
			Session::error( _t( 'No such user!' ) );
			Utils::redirect( URL::get( 'admin', 'page=users' ) );
		}
 
		$this->theme->edit_user = $edit_user;
 
		$field_sections = array(
			'user_info' => $possessive,
			'change_password' => _t('Change Password'),
			'regional_settings' => _t('Regional Settings'),
			'dashboard' => _t( 'Dashboard' ),
		);
 
		$form = new FormUI('User Options');
 
		// Create a tracker for who we are dealing with
		$form->append('hidden', 'edit_user', 'edit_user');
		$form->edit_user->value = $edit_user->id;
 
		// Generate sections
		foreach ( $field_sections as $key => $name ) {
			$fieldset = $form->append( 'wrapper', $key, $name );
			$fieldset->class = 'container settings';
			$fieldset->append( 'static', $key, '<h2>' . htmlentities( $name, ENT_COMPAT, 'UTF-8' ) . '</h2>' );
		}
 
		// User Info
		$displayname = $form->user_info->append('text', 'displayname', 'null:null',  _t('Display Name'), 'optionscontrol_text');
		$displayname->class[] = 'important item clear';
		$displayname->value = $edit_user->displayname;
 
		$username = $form->user_info->append('text', 'username', 'null:null',  _t('User Name'), 'optionscontrol_text');
		$username->class[] = 'item clear';
		$username->value = $edit_user->username;
		$username->add_validator('validate_username', $edit_user->username);
 
		$email = $form->user_info->append('text', 'email', 'null:null',  _t('Email'), 'optionscontrol_text');
		$email->class[] = 'item clear';
		$email->value = $edit_user->email;
		$email->add_validator('validate_email');
 
		$imageurl = $form->user_info->append('text', 'imageurl', 'null:null',  _t('Portrait URL'), 'optionscontrol_text');
		$imageurl->class[] = 'item clear';
		$imageurl->value = $edit_user->info->imageurl;
 
		// Change Password
		$password1 = $form->change_password->append('text', 'password1', 'null:null',  _t('New Password'), 'optionscontrol_text');
		$password1->class[] = 'item clear';
		$password1->type = 'password';
		$password1->value = '';
 
		$password2 = $form->change_password->append('text', 'password2', 'null:null',  _t('New Password Again'), 'optionscontrol_text');
		$password2->class[] = 'item clear';
		$password2->type = 'password';
		$password2->value = '';
		$delete = $this->handler_vars->filter_keys('delete');
		// don't validate password match if action is delete
		if (!isset($delete['delete'])) {
			$password2->add_validator('validate_same', $password1, _t('Passwords must match.'));
		}
 
		// Regional settings
		$timezones = DateTimeZone::listIdentifiers();
		$timezones = array_merge( array_combine( array_values( $timezones ), array_values( $timezones ) ) );
		$locale_tz = $form->regional_settings->append('text', 'locale_tz', 'null:null',  _t('Timezone'), 'optionscontrol_select');
		$locale_tz->class[] = 'item clear';
		$locale_tz->value = $edit_user->info->locale_tz;
		$locale_tz->options = $timezones;
		$locale_tz->multiple = false;
 
		$locale_date_format = $form->regional_settings->append('text', 'locale_date_format', 'null:null',  _t('Date Format'), 'optionscontrol_text');
		$locale_date_format->class[] = 'item clear';
		$locale_date_format->value = $edit_user->info->locale_date_format;
		if ( isset($edit_user->info->locale_date_format) && $edit_user->info->locale_date_format != '' ) {
			$current = HabariDateTime::date_create()->get($edit_user->info->locale_date_format);
		}
		else {
			$current = HabariDateTime::date_create()->date;
		}
		$locale_date_format->helptext = _t('See <a href="%s">php.net/date</a> for details. Current format: %s', array('http://php.net/date', $current) );
 
		$locale_time_format = $form->regional_settings->append('text', 'locale_time_format', 'null:null',  _t('Time Format'), 'optionscontrol_text');
		$locale_time_format->class[] = 'item clear';
		$locale_time_format->value = $edit_user->info->locale_time_format;
		if ( isset($edit_user->info->locale_time_format) && $edit_user->info->locale_time_format != '' ) {
			$current = HabariDateTime::date_create()->get($edit_user->info->locale_time_format);
		}
		else {
			$current = HabariDateTime::date_create()->time;
		}
		$locale_time_format->helptext = _t('See <a href="%s">php.net/date</a> for details. Current format: %s', array('http://php.net/date', $current) );
 
 
		$spam_count = $form->dashboard->append( 'checkbox', 'dashboard_hide_spam_count', 'null:null', _t( 'Hide Spam Count' ), 'optionscontrol_checkbox' );
		$spam_count->class[] = 'item clear';
		$spam_count->helptext = _t( 'Hide the number of SPAM comments on your dashboard.' );
		$spam_count->value = $edit_user->info->dashboard_hide_spam_count;
 
 
		// Controls
		$controls = $form->append( 'wrapper', 'page_controls' );
		$controls->class = 'container controls transparent';
 
		$submit = $controls->append( 'submit', 'apply', _t('Apply'), 'optionscontrol_submit' );
		$submit->class[] = 'pct30';
 
		$controls->append( 'static', 'reassign', '<span class="pct35 reassigntext">' . _t('Reassign posts to: %s', array(Utils::html_select('reassign', $authors)) ) . '</span><span class="minor pct5 conjunction">' . _t('and') . '</span><span class="pct30"><input type="submit" name="delete" value="' . _t('Delete') . '" class="delete button"></span>');
 
		$form->on_success( array( $this, 'form_user_success' ) );
 
		// Let plugins alter this form
		Plugins::act('form_user', $form, $edit_user);
 
		$this->theme->form = $form->get();
 
		$this->theme->display('user');
 
	}
 
	/**
	 * Handles form submission from a user's page.
	 */
	public function form_user_success($form)
	{
		$edit_user = User::get_by_id($form->edit_user->value);
		$current_user = User::identify();
 
		// Let's check for deletion
		if ( Controller::get_var('delete') != NULL ) {
			if ( $current_user->id != $edit_user->id ) {
 
				// We're going to delete the user before we need it, so store the username
				$username = $edit_user->username;
 
				$posts = Posts::get( array( 'user_id' => $edit_user->id, 'nolimit' => true ) );
 
				if ( ( Controller::get_var('reassign') != NULL ) && (Controller::get_var('reassign') != 0) && (Controller::get_var('reassign') != $edit_user->id)) {
					// we're going to re-assign all of this user's posts
					$newauthor = Controller::get_var('reassign');
					Posts::reassign( $newauthor, $posts );
					$edit_user->delete();
				}
				else {
					// delete user, then delete posts
					$edit_user->delete();
 
					// delete posts
					foreach ( $posts as $post ) {
						$post->delete();
					}
				}
 
				Session::notice( sprintf( _t( '%s has been deleted' ), $username ) );
 
				Utils::redirect(URL::get('admin', array('page' => 'users')));
			}
			else {
				Session::notice( _t( 'You cannot delete yourself.') );
			}
		}
 
		$update = false;
 
		// Change username
		if ( isset($form->username) && $edit_user->username != $form->username->value ) {
			Session::notice( _t( '%1$s has been renamed to %2$s.', array($edit_user->username, $form->username->value) ) );
			$edit_user->username = $form->username->value;
			$update = true;
		}
 
		// Change email
		if ( isset($form->email) && $edit_user->email != $form->email->value ) {
			$edit_user->email = $form->email->value;
			$update = true;
		}
 
		// Change password
		if ( isset($form->password1) && !(Utils::crypt($form->password1->value, $edit_user->password)) && ($form->password1->value != '') ) {
			Session::notice( _t( 'Password changed.' ) );
			$edit_user->password = Utils::crypt( $form->password1->value );
			$edit_user->update();
		}
 
		// Set various info fields
		$info_fields = array('displayname', 'imageurl', 'locale_tz', 'locale_date_format', 'locale_time_format', 'dashboard_hide_spam_count');
 
		// let plugins easily specify other user info fields to pick
		$info_fields = Plugins::filter( 'adminhandler_post_user_fields', $info_fields );
 
		foreach ( $info_fields as $info_field ) {
			if ( isset($form->{$info_field}) && ($edit_user->info->{$info_field} != $form->{$info_field}->value) ) {
				$edit_user->info->{$info_field} = $form->$info_field->value;
				$update = true;
			}
		}
 
		// Let plugins tell us to update
		$update = Plugins::filter( 'form_user_update', $update, $form, $edit_user );
 
		if ( $update ) {
			$edit_user->update();
			Session::notice( _t('User updated.') );
		}
 
		Utils::redirect(URL::get('admin', array('page' => 'user', 'user' => $edit_user->username)));
	}
 
	/**
	 * Handles POST requests from the user profile page.
	 */
	public function post_user()
	{
		$this->get_user();
	}
 
	/**
	 * Handles AJAX from /users.
	 * Used to delete users and fetch new ones.
	 */
	public function ajax_update_users($handler_vars)
	{
		Utils::check_request_method( array( 'POST' ) );
 
		echo json_encode( $this->update_users( $handler_vars ) );
	}
 
	/**
	 * Update an array of POSTed users.
	 */
	public function update_users($handler_vars)
	{
		if ( isset($handler_vars['delete']) ) {
 
			$currentuser = User::identify();
 
			$wsse = Utils::WSSE( $handler_vars['nonce'], $handler_vars['timestamp'] );
			if ( isset($handler_vars['digest']) && $handler_vars['digest'] != $wsse['digest'] ) {
				Session::error( _t('WSSE authentication failed.') );
				return Session::messages_get( true, 'array' );
			}
 
			foreach ( $_POST as $id => $delete ) {
 
				// skip POST elements which are not log ids
				if ( preg_match( '/^p\d+/', $id ) && $delete ) {
					$id = substr($id, 1);
 
					$ids[] = array( 'id' => $id );
 
				}
 
			}
 
			if ( isset( $handler_vars['checkbox_ids'] ) ) {
				$checkbox_ids = $handler_vars['checkbox_ids'];
				foreach ( $checkbox_ids as $id => $delete ) {
					if ( $delete ) {
						$ids[] = array( 'id' => $id );
					}
				}
			}
 
			$count = 0;
 
			if ( ! isset($ids) ) {
				Session::notice( _t('No users deleted.') );
				return Session::messages_get( true, 'array' );
			}
 
			foreach ( $ids as $id ) {
				$id = $id['id'];
				$user = User::get_by_id( $id );
 
				if ( $currentuser != $user ) {
					$assign = intval( $handler_vars['reassign'] );
 
					if ( $user->id == $assign ) {
						return;
					}
 
					$posts = Posts::get( array( 'user_id' => $user->id, 'nolimit' => 1) );
 
					if ( isset($posts[0]) ) {
						if ( 0 == $assign ) {
							foreach ( $posts as $post ) {
								$post->delete();
							}
						}
						else {
							Posts::reassign( $assign, $posts );
						}
					}
					$user->delete();
				}
				else {
					$msg_status = _t('You cannot delete yourself.');
				}
 
				$count++;
			}
 
			if ( !isset($msg_status) ) {
				$msg_status = sprintf( _t('Deleted %d users.'), $count );
			}
 
			Session::notice( $msg_status );
		}
	}
 
	/**
	 * Assign values needed to display the users listing
	 *
	 */
	private function fetch_users($params = NULL)
	{
		// prepare the WSSE tokens
		$this->theme->wsse = Utils::WSSE();
 
		// Get author list
		$author_list = Users::get_all();
		$authors[0] = _t('nobody');
		foreach ( $author_list as $author ) {
			$authors[ $author->id ] = $author->displayname;
		}
		$this->theme->authors = $authors;
	}
 
	/**
	 * Handles GET requests of the users page.
	 */
	public function get_users()
	{
		$this->fetch_users();
 
		$this->theme->display('users');
	}
 
	/**
	 * Handles POST requests from the Users listing (ie: creating a new user)
	 */
	public function post_users()
	{
		$this->fetch_users();
 
		$extract = $this->handler_vars->filter_keys('newuser', 'delete', 'new_pass1', 'new_pass2', 'new_email', 'new_username');
		foreach ( $extract as $key => $value ) {
			$$key = $value;
		}
 
		if ( isset($newuser) ) {
			$action = 'newuser';
		}
		elseif ( isset($delete) ) {
			$action = 'delete';
		}
 
		$error = '';
		if ( isset( $action ) && ( 'newuser' == $action ) ) {
			if ( !isset( $new_pass1 ) || !isset( $new_pass2 ) || empty( $new_pass1 ) || empty( $new_pass2 ) ) {
				Session::error( _t( 'Password is required.' ), 'adduser' );
			}
			else if ( $new_pass1 !== $new_pass2 ) {
				Session::error( _t( 'Password mis-match.'), 'adduser' );
			}
			if ( !isset( $new_email ) || empty( $new_email ) || ( !strstr( $new_email, '@' ) ) ) {
				Session::error( _t( 'Please supply a valid email address.' ), 'adduser' );
			}
			if ( !isset( $new_username ) || empty( $new_username ) ) {
				Session::error( _t( 'Please supply a user name.' ), 'adduser' );
			}
			// safety check to make sure no such username exists
			$user = User::get_by_name( $new_username );
			if ( isset( $user->id ) ) {
				Session::error( _t( 'That username is already assigned.' ), 'adduser' );
			}
			if ( !Session::has_errors( 'adduser' ) ) {
				$user = new User( array( 'username' => $new_username, 'email' => $new_email, 'password' => Utils::crypt( $new_pass1 ) ) );
				if ( $user->insert() ) {
					Session::notice( sprintf( _t( "Added user '%s'" ), $new_username ) );
				}
				else {
					$dberror = DB::get_last_error();
					Session::error( $dberror[2], 'adduser' );
				}
			}
			else {
				$settings = array();
				if ( isset($username) ) {
					$settings['new_username'] = $new_username;
				}
				if ( isset( $new_email ) ) {
					$settings['new_email'] = $new_email;
				}
				$this->theme->assign( 'settings', $settings );
			}
		}
		else if ( isset( $action ) && ( 'delete' == $action ) ) {
 
			$this->update_users($this->handler_vars);
 
		}
 
		$this->theme->display('users');
	}
 
	/**
	 * Handles plugin activation or deactivation.
	 */
	public function get_plugin_toggle()
	{
		$extract = $this->handler_vars->filter_keys('plugin_id', 'action');
		foreach ( $extract as $key => $value ) {
			$$key = $value;
		}
 
		$plugins = Plugins::list_all();
		foreach ( $plugins as $file ) {
			if ( Plugins::id_from_file($file) == $plugin_id ) {
				switch ( strtolower($action) ) {
					case 'activate':
						if ( Plugins::activate_plugin($file) ) {
							$plugins = Plugins::get_active();
							Session::notice(
								_t( "Activated plugin '%s'", array($plugins[Plugins::id_from_file( $file )]->info->name) ),
								$plugins[Plugins::id_from_file($file)]->plugin_id
							);
						}
					break;
					case 'deactivate':
						if ( Plugins::deactivate_plugin($file) ) {
							$plugins = Plugins::get_active();
							Session::notice(
								_t( "Deactivated plugin '%s'", array($plugins[Plugins::id_from_file( $file )]->info->name) ),
								$plugins[Plugins::id_from_file($file)]->plugin_id
							);
						}
					break;
					default:
						Plugins::act(
							'adminhandler_get_plugin_toggle_action',
							$action,
							$file,
							$plugin_id,
							$plugins
						);
					break;
				}
			}
		}
		Utils::redirect( URL::get( 'admin', 'page=plugins' ) );
	}
 
	/**
	 * A POST handler for the admin themes page that simply passes those options through.
	 */
	public function post_themes()
	{
		return $this->get_themes();
	}
 
	/**
	 * Handles GET requests for the theme listing
	 */
	public function get_themes()
	{
		$all_themes = Themes::get_all_data();
		foreach ( $all_themes as $name => $theme ) {
			if ( isset($all_themes[$name]['info']->update) && $all_themes[$name]['info']->update != '' && isset($all_themes[$name]['info']->version) && $all_themes[$name]['info']->version != '' ) {
				Update::add($name, $all_themes[$name]['info']->update, $all_themes[$name]['info']->version);
			}
		}
		$updates = Update::check();
		foreach ( $all_themes as $name => $theme ) {
			if ( isset($all_themes[$name]['info']->update) && isset($updates[$all_themes[$name]['info']->update]) ) {
				$all_themes[$name]['info']->update = $updates[$all_themes[$name]['info']->update]['latest_version'];
			}
			else {
				$all_themes[$name]['info']->update = '';
			}
		}
		$this->theme->all_themes = $all_themes;
 
		$this->theme->active_theme = Themes::get_active_data();
		$this->theme->active_theme_dir = $this->theme->active_theme['path'];
 
		// If the active theme is configurable, allow it to configure
		$this->theme->active_theme_name = $this->theme->active_theme['info']->name;
		$this->theme->configurable = Plugins::filter( 'theme_config', false, $this->active_theme);
		$this->theme->assign( 'configure', Controller::get_var('configure') );
 
		$activedata = Themes::get_active_data();
		$areas = array();
		if ( isset($activedata['info']->areas->area) ) {
			foreach ( $activedata['info']->areas->area as $area ) {
				$areas[] = (string)$area;
			}
		}
		$this->theme->areas = $areas;
 
		$this->theme->blocks = Plugins::filter('block_list', array());
		$this->theme->block_instances = DB::get_results('SELECT b.* FROM {blocks} b ORDER BY b.title ASC', array(), 'Block');
		$blocks_areas_t = DB::get_results('SELECT b.*, ba.scope_id, ba.area FROM {blocks} b INNER JOIN {blocks_areas} ba ON ba.block_id = b.id ORDER BY ba.scope_id ASC, ba.area ASC, ba.display_order ASC', array(), 'Block');
		$blocks_areas = array();
		foreach ( $blocks_areas_t as $block ) {
			if ( !isset($blocks_areas[$block->scope_id]) ) {
				$blocks_areas[$block->scope_id] = array();
			}
			$blocks_areas[$block->scope_id][$block->area][$block->display_order] = $block;
		}
		$this->theme->blocks_areas = $blocks_areas;
 
		$this->theme->scopes = DB::get_results('SELECT * FROM {scopes} ORDER BY id ASC;');
 
		$this->theme->display( 'themes' );
	}
 
	/**
	 * Activates a theme.
	 */
	public function get_activate_theme()
	{
		$theme_name = $this->handler_vars['theme_name'];
		$theme_dir = $this->handler_vars['theme_dir'];
		if ( isset($theme_name)  && isset($theme_dir) ) {
			Themes::activate_theme( $theme_name,  $theme_dir );
		}
		Session::notice( sprintf( _t( "Activated theme '%s'" ), $theme_name ) );
		Utils::redirect( URL::get( 'admin', 'page=themes' ) );
	}
 
	/**
	 * Handles GET requests for the import page.
	 */
	public function get_import()
	{
 
		$importer = isset( $_POST['importer'] ) ? $_POST['importer'] : '';
		$stage = isset( $_POST['stage'] ) ? $_POST['stage'] : '';
 
		$this->theme->enctype = Plugins::filter( 'import_form_enctype', 'application/x-www-form-urlencoded', $importer, $stage );
 
		$this->display( 'import' );
 
	}
 
	/**
	 * Handles the submission of the import form, importing data from a WordPress database.
	 * This function should probably be broken into an importer class, since it is WordPress-specific.
	 */
	public function post_import()
	{
		if ( !isset( $_POST['importer'] ) ) {
			Utils::redirect( URL::get( 'admin', 'page=import' ) );
		}
 
		$importer = isset( $_POST['importer'] ) ? $_POST['importer'] : '';
		$stage = isset( $_POST['stage'] ) ? $_POST['stage'] : '';
 
		$this->theme->enctype = Plugins::filter( 'import_form_enctype', 'application/x-www-form-urlencoded', $importer, $stage );
 
		$this->display( 'import' );
	}
 
	/**
	 * Construct a form for a comment.
	 * @return FormUI The comment's form.
	 */
	public function form_comment($comment, $actions)
	{
		$form = new FormUI( 'comment' );
 
		$user = User::identify();
 
		// Create the top description
		$top = $form->append('wrapper', 'buttons_1');
		$top->class = 'container buttons comment overview';
 
		$top->append('static', 'overview', $this->theme->fetch('comment.overview'));
 
		$buttons_1 = $top->append('wrapper', 'buttons_1');
		$buttons_1->class = 'item buttons';
 
 
		foreach ( $actions as $status => $action ) {
			$id = $action . '_1';
			$buttons_1->append('submit', $id, _t(ucfirst($action)));
			$buttons_1->$id->class = 'button ' . $action;
			if ( Comment::status_name($comment->status) == $status ) {
				$buttons_1->$id->class = 'button active ' . $action;
				$buttons_1->$id->disabled = true;
			}
			else {
				$buttons_1->$id->disabled = false;
			}
		}
 
		// Content
		$form->append('wrapper', 'content_wrapper');
		$content = $form->content_wrapper->append('textarea', 'content', 'null:null', _t('Comment'), 'admincontrol_textarea');
		$content->class = 'resizable';
		$content->value = $comment->content;
 
		// Create the splitter
		$comment_controls = $form->append('tabs', 'comment_controls');
 
		// Create the author info
		$author = $comment_controls->append('fieldset', 'authorinfo', _t('Author'));
 
		$author->append('text', 'author_name', 'null:null', _t('Author Name'), 'tabcontrol_text');
		$author->author_name->value = $comment->name;
 
		$author->append('text', 'author_email', 'null:null', _t('Author Email'), 'tabcontrol_text');
		$author->author_email->value = $comment->email;
 
		$author->append('text', 'author_url', 'null:null', _t('Author URL'), 'tabcontrol_text');
		$author->author_url->value = $comment->url;
 
		$author->append('text', 'author_ip', 'null:null', _t('IP Address:'), 'tabcontrol_text');
		$author->author_ip->value = long2ip($comment->ip);
 
		// Create the advanced settings
		$settings = $comment_controls->append('fieldset', 'settings', _t('Settings'));
 
		$settings->append('text', 'comment_date', 'null:null', _t('Date:'), 'tabcontrol_text');
		$settings->comment_date->value = $comment->date->get('Y-m-d H:i:s');
 
 
 
		$settings->append('text', 'comment_post', 'null:null', _t('Post ID:'), 'tabcontrol_text');
		$settings->comment_post->value = $comment->post->id;
 
		$statuses = Comment::list_comment_statuses( false );
		$statuses = Plugins::filter( 'admin_publish_list_comment_statuses', $statuses );
		$settings->append('select', 'comment_status', 'null:null', _t('Status'), $statuses, 'tabcontrol_select');
		$settings->comment_status->value = $comment->status;
 
		// // Create the stats
		// $comment_controls->append('fieldset', 'stats_tab', _t('Stats'));
		// $stats = $form->stats_tab->append('wrapper', 'tags_buttons');
		// $stats->class = 'container';
		//
		// $stats->append('static', 'post_count', '<div class="container"><p class="pct25">'._t('Comments on this post:').'</p><p><strong>' . Comments::count_by_id($comment->post->id) . '</strong></p></div><hr />');
		// $stats->append('static', 'ip_count', '<div class="container"><p class="pct25">'._t('Comments from this IP:').'</p><p><strong>' . Comments::count_by_ip($comment->ip) . '</strong></p></div><hr />');
		// $stats->append('static', 'email_count', '<div class="container"><p class="pct25">'._t('Comments by this author:').'</p><p><strong>' . Comments::count_by_email($comment->email) . '</strong></p></div><hr />');
		// $stats->append('static', 'url_count', '<div class="container"><p class="pct25">'._t('Comments with this URL:').'</p><p><strong>' . Comments::count_by_url($comment->url) . '</strong></p></div><hr />');
 
		// Create the second set of action buttons
		$buttons_2 = $form->append('wrapper', 'buttons_2');
		$buttons_2->class = 'container buttons comment';
 
		foreach ( $actions as $status => $action ) {
			$id = $action . '_2';
			$buttons_2->append('submit', $id, _t(ucfirst($action)));
			$buttons_2->$id->class = 'button ' . $action;
			if ( Comment::status_name($comment->status) == $status ) {
				$buttons_2->$id->class = 'button active ' . $action;
				$buttons_2->$id->disabled = true;
			}
			else {
				$buttons_2->$id->disabled = false;
			}
		}
 
		// Allow plugins to alter form
		Plugins::act('form_comment_edit', $form, $comment);
 
		return $form;
	}
 
	/**
	 * Handles GET requests for an individual comment.
	 */
	public function get_comment($update = FALSE)
	{
		if ( isset( $this->handler_vars['id'] ) && $comment = Comment::get( $this->handler_vars['id'] ) ) {
			$this->theme->comment = $comment;
 
			// Convenience array to output actions twice
			$actions = array(
				'deleted' => 'delete',
				'spam' => 'spam',
				'unapproved' => 'unapprove',
				'approved' => 'approve',
				'saved' => 'save'
				);
 
			$form = $this->form_comment( $comment, $actions );
 
			if ( $update ) {
				foreach ( $actions as $key => $action ) {
					$id_one = $action . '_1';
					$id_two = $action . '_2';
					if ( $form->$id_one->value != NULL || $form->$id_two->value != NULL ) {
						if ( $action == 'delete' ) {
							$comment->delete();
							Utils::redirect(URL::get('admin', 'page=comments'));
						}
						if ( $action != 'save' ) {
							foreach ( Comment::list_comment_statuses() as $status ) {
								if ( $status == $key ) {
									$comment->status = Comment::status_name( $status );
									$set_status = true;
								}
							}
						}
					}
				}
 
				$comment->content = $form->content;
				$comment->name = $form->author_name;
				$comment->url = $form->author_url;
				$comment->email = $form->author_email;
				$comment->ip = ip2long( $form->author_ip );
 
				$comment->date = HabariDateTime::date_create( $form->comment_date );
				$comment->post_id = $form->comment_post;
 
				if ( ! isset($set_status) ) {
					$comment->status = $form->comment_status->value;
				}
 
				$comment->update();
 
				Plugins::act('comment_edit', $comment, $form);
 
				Utils::redirect();
			}
 
			$comment->content = $form;
			$this->theme->form = $form;
 
			$this->display('comment');
		}
		else {
			Utils::redirect(URL::get('admin', 'page=comments'));
		}
	}
 
	/**
	 * Handles POST requests for an individual comment.
	 */
	public function post_comment()
	{
		$this->get_comment(true);
	}
 
	/**
	 * Handles GET requests for the comments  page.
	 */
	public function get_comments()
	{
		$this->post_comments();
	}
 
	/**
	 * Handles the submission of the comment moderation form.
	 * @todo Separate delete from "delete until purge"
	 */
	public function post_comments()
	{
		// Get special search statuses
		$statuses = Comment::list_comment_statuses();
		$statuses = array_combine(
			$statuses,
			array_map(
				create_function('$a', 'return "status:{$a}";'),
				$statuses
			)
		);
 
		// Get special search types
		$types = Comment::list_comment_types();
		$types = array_combine(
			$types,
			array_map(
				create_function('$a', 'return "type:{$a}";'),
				$types
			)
		);
 
		$this->theme->special_searches = array_merge($statuses, $types);
 
		$this->fetch_comments();
		$this->display( 'comments' );
	}
 
	/**
	 * Retrieve comments.
	 */
	public function fetch_comments( $params = array() )
	{
		// Make certain handler_vars local with defaults, and add them to the theme output
		$locals = array(
			'do_delete' => false,
			'do_spam' => false,
			'do_approve' => false,
			'do_unapprove' => false,
			'comment_ids' => null,
			'nonce' => '',
			'timestamp' => '',
			'PasswordDigest' => '',
			'mass_spam_delete' => null,
			'mass_delete' => null,
			'type' => 'All',
			'limit' => 20,
			'offset' => 0,
			'search' => '',
			'status' => 'All',
			'orderby' => 'date DESC',
		);
		foreach ( $locals as $varname => $default ) {
			$$varname = isset( $this->handler_vars[$varname] ) ? $this->handler_vars[$varname] : (isset($params[$varname]) ? $params[$varname] : $default);
			$this->theme->{$varname} = $$varname;
		}
 
		// Setting these mass_delete options prevents any other processing.  Desired?
		if ( isset( $mass_spam_delete ) && $status == Comment::STATUS_SPAM ) {
			// Delete all comments that have the spam status.
			Comments::delete_by_status( Comment::STATUS_SPAM );
			// let's optimize the table
			$result = DB::query('OPTIMIZE TABLE {comments}');
			Session::notice( _t( 'Deleted all spam comments' ) );
			Utils::redirect();
		}
		elseif ( isset( $mass_delete ) && $status == Comment::STATUS_UNAPPROVED ) {
			// Delete all comments that are unapproved.
			Comments::delete_by_status( Comment::STATUS_UNAPPROVED );
			Session::notice( _t( 'Deleted all unapproved comments' ) );
			Utils::redirect();
		}
		// if we're updating posts, let's do so:
		elseif ( ( $do_delete || $do_spam || $do_approve || $do_unapprove ) && isset( $comment_ids )) {
			$okay = true;
			if ( empty( $nonce ) || empty( $timestamp ) ||  empty( $PasswordDigest ) ) {
				$okay = false;
			}
			$wsse = Utils::WSSE( $nonce, $timestamp );
			if ( $PasswordDigest != $wsse['digest'] ) {
				$okay = false;
			}
			if ( $okay ) {
				if ( $do_delete ) {
					$action = 'delete';
				}
				elseif ( $do_spam ) {
					$action = 'spam';
				}
				elseif ( $do_approve ) {
					$action = 'approve';
				}
				elseif ( $do_unapprove ) {
					$action = 'unapprove';
				}
				$ids = array();
				foreach ( $comment_ids as $id => $id_value ) {
					if ( ! isset( ${'$comment_ids['.$id.']'} ) ) { // Skip unmoderated submitted comment_ids
						$ids[] = $id;
					}
				}
				$to_update = Comments::get( array( 'id' => $ids ) );
				$modstatus = array(
					_t( 'Deleted %d comments' ) => 0,
					_t( 'Marked %d comments as spam' ) => 0,
					_t( 'Approved %d comments' ) => 0,
					_t( 'Unapproved %d comments' ) => 0,
					_t( 'Edited %d comments' ) => 0
				);
				Plugins::act( 'admin_moderate_comments', $action, $to_update, $this );
 
				switch ( $action ) {
 
					case 'delete':
						// This comment was marked for deletion
						$to_update = $this->comment_access_filter( $to_update, 'delete' );
						Comments::delete_these( $to_update );
						$modstatus[_t( 'Deleted %d comments' )] = count( $to_update );
						break;
 
					case 'spam':
						// This comment was marked as spam
						$to_update = $this->comment_access_filter( $to_update, 'edit' );
						Comments::moderate_these( $to_update, Comment::STATUS_SPAM );
						$modstatus[_t( 'Marked %d comments as spam' )] = count( $to_update );
						break;
 
					case 'approve':
					case 'approved':
						// Comments marked for approval
						$to_update = $this->comment_access_filter( $to_update, 'edit' );
						Comments::moderate_these( $to_update, Comment::STATUS_APPROVED );
						$modstatus[_t('Approved %d comments')] = count( $to_update );
						foreach ( $to_update as $comment ) {
									$modstatus[_t( 'Approved comments on these posts: %s' )] = (isset($modstatus[_t( 'Approved comments on these posts: %s' )])? $modstatus[_t( 'Approved comments on these posts: %s' )] . ' &middot; ' : '') . '<a href="' . $comment->post->permalink . '">' . $comment->post->title . '</a> ';
						}
						break;
 
					case 'unapprove':
					case 'unapproved':
						// This comment was marked for unapproval
						$to_update = $this->comment_access_filter( $to_update, 'edit' );
						Comments::moderate_these( $to_update, Comment::STATUS_UNAPPROVED );
						$modstatus[_t( 'Unapproved %d comments' )] = count ( $to_update );
						break;
 
					case 'edit':
						$to_update = $this->comment_access_filter( $to_update, 'edit' );
						foreach ( $to_update as $comment ) {
							// This comment was edited
							if ( $_POST['name_' . $comment->id] != NULL ) {
								$comment->name = $_POST['name_' . $comment->id];
							}
							if ( $_POST['email_' . $comment->id] != NULL ) {
								$comment->email = $_POST['email_' . $comment->id];
							}
							if ( $_POST['url_' . $comment->id] != NULL ) {
								$comment->url = $_POST['url_' . $comment->id];
							}
							if ( $_POST['content_' . $comment->id] != NULL ) {
								$comment->content = $_POST['content_' . $comment->id];
							}
 
							$comment->update();
						}
						$modstatus[_t( 'Edited %d comments' )] = count( $to_update );
						break;
 
				}
 
				foreach ( $modstatus as $key => $value ) {
					if ( $value ) {
						Session::notice( sprintf( $key, $value ) );
					}
				}
 
			}
 
			Utils::redirect();
 
		}
 
		// we load the WSSE tokens
		// for use in the delete button
		$this->theme->wsse = Utils::WSSE();
 
		$arguments = array(
			'type' => $type,
			'status' => $status,
			'limit' => $limit,
			'offset' => $offset,
			'orderby' => $orderby,
		);
 
		// only get comments the user is allowed to manage
		if ( !User::identify()->can( 'manage_all_comments' ) ) {
			$arguments['post_author'] = User::identify()->id;
		}
 
		// there is no explicit 'all' type/status for comments, so we need to unset these arguments
		// if that's what we want. At the same time we can set up the search field
		$this->theme->search_args = '';
		if ( $type == 'All') {
			unset( $arguments['type'] );
		}
		else {
			$this->theme->search_args = 'type:' . Comment::type_name( $type ) . ' ';
		}
 
		if ( $status == 'All') {
			unset ( $arguments['status'] );
		}
		else {
			$this->theme->search_args .= 'status:' . Comment::status_name( $status );
		}
 
		if ( '' != $search ) {
			$arguments = array_merge( $arguments, Comments::search_to_get( $search ) );
		}
 
		$this->theme->comments = Comments::get( $arguments );
		$monthcts = Comments::get( array_merge( $arguments, array( 'month_cts' => 1 ) ) );
		$years = array();
		foreach ( $monthcts as $month ) {
			if ( isset($years[$month->year]) ) {
				$years[$month->year][] = $month;
			}
			else
			{
				$years[$month->year] = array( $month );
			}
		}
		$this->theme->years = $years;
 
		$baseactions = array();
		$statuses = Comment::list_comment_statuses();
		foreach ( $statuses as $statusid => $statusname ) {
			$baseactions[$statusname] = array('url' => 'javascript:itemManage.update(\'' . $statusname . '\',__commentid__);', 'title' => _t('Change this comment\'s status to %s', array($statusname)), 'label' => Comment::status_action($statusid), 'access' => 'edit' );
		}
 
		/* Standard actions */
		$baseactions['delete'] = array('url' => 'javascript:itemManage.update(\'delete\',__commentid__);', 'title' => _t('Delete this comment'), 'label' => _t('Delete'), 'access' => 'delete' );
		$baseactions['edit'] = array('url' => URL::get('admin', 'page=comment&id=__commentid__'), 'title' => _t('Edit this comment'), 'label' => _t('Edit'), 'access' => 'edit' );
 
		/* Allow plugins to apply actions */
		$actions = Plugins::filter('comments_actions', $baseactions, $this->theme->comments);
 
		foreach ( $this->theme->comments as $comment ) {
			// filter the actions based on the user's permissions
			$comment_access = $comment->get_access();
			$menu = array();
			foreach ( $actions as $name => $action ) {
				if ( !isset( $action['access'] ) || ACL::access_check( $comment_access, $action['access'] ) ) {
					$menu[$name] = $action;
				}
			}
			// remove the current status from the dropmenu
			unset($menu[Comment::status_name($comment->status)]);
			$comment->menu = Plugins::filter('comment_actions', $menu, $comment);
		}
	}
 
	/**
	 * A helper function for fetch_comments()
	 * Filters a list of comments by ACL access
	 * @param object $comments an array of Comment objects
	 * @param string $access the access type to check for
	 * @return a filtered array of Comment objects.
	 */
	public function comment_access_filter( $comments, $access )
	{
		$result = array();
		foreach ( $comments as $comment ) {
			if ( ACL::access_check( $comment->get_access(), $access ) ) {
				$result[] = $comment;
			}
		}
		return $result;
	}
 
	/**
	 * A POST handler for the admin plugins page that simply passes those options through.
	 */
	public function post_plugins()
	{
		return $this->get_plugins();
	}
 
	/**
	 * Display the plugin administration page
	 */
	public function get_plugins()
	{
		$all_plugins = Plugins::list_all();
		$active_plugins = Plugins::get_active();
 
		$sort_active_plugins = array();
		$sort_inactive_plugins = array();
 
		foreach ( $all_plugins as $file ) {
			$plugin = array();
			$plugin_id = Plugins::id_from_file( $file );
			$plugin['plugin_id'] = $plugin_id;
			$plugin['file'] = $file;
 
			$error = '';
 
			$providing = array();
 
			if ( Utils::php_check_file_syntax( $file, $error ) ) {
				$plugin['debug'] = false;
				if ( array_key_exists( $plugin_id, $active_plugins ) ) {
					$plugin['verb'] = _t( 'Deactivate' );
					$pluginobj = $active_plugins[$plugin_id];
					$plugin['active'] = true;
					$plugin_actions = array();
					$plugin_actions = Plugins::filter( 'plugin_config', $plugin_actions, $plugin_id );
					$plugin['actions'] = array();
					foreach ( $plugin_actions as $plugin_action => $plugin_action_caption ) {
						if ( is_numeric($plugin_action) ) {
							$plugin_action = $plugin_action_caption;
						}
						$action = array(
							'caption' => $plugin_action_caption,
							'action' => $plugin_action,
						);
						$urlparams = array('page' => 'plugins', 'configure'=>$plugin_id);
						$action['url'] = URL::get( 'admin', $urlparams );
 
						if ( $action['caption'] == '?' ) {
							if ( isset($_GET['configaction']) ) {
								$urlparams['configaction'] = $_GET['configaction'];
							}
							if ( $_GET['help'] != $plugin_action ) {
								$urlparams['help'] = $plugin_action;
							}
							$action['url'] = URL::get( 'admin', $urlparams );
							$plugin['help'] = $action;
						}
						else {
							if ( isset($_GET['help']) ) {
								$urlparams['help'] = $_GET['help'];
							}
							$urlparams['configaction'] = $plugin_action;
							$action['url'] = URL::get( 'admin', $urlparams );
							$plugin['actions'][$plugin_action] = $action;
						}
					}
					$plugin['actions']['deactivate'] = array(
						'url' =>  URL::get( 'admin', 'page=plugin_toggle&plugin_id=' . $plugin['plugin_id'] . '&action=deactivate'),
						'caption' => _t('Deactivate'),
						'action' => 'Deactivate',
					);
 
					if ( isset($plugin['info']->provides) ) {
						foreach ( $plugin['info']->provides->feature as $feature ) {
							$providing[(string) $feature] = $feature;
						}
					}
				}
				else {
					// instantiate this plugin
					// in order to get its info()
					$plugin['active'] = false;
					$plugin['verb'] = _t( 'Activate' );
					$plugin['actions'] = array(
						'activate' => array(
							'url' =>  URL::get( 'admin', 'page=plugin_toggle&plugin_id=' . $plugin['plugin_id'] . '&action=activate'),
							'caption' => _t('Activate'),
							'action' => 'activate',
						),
					);
				}
				$plugin['info'] = Plugins::load_info( $file );
			}
			else {
				$plugin['debug'] = true;
				$plugin['error'] = $error;
				$plugin['active'] = false;
			}
			if ( isset( $this->handler_vars['configure'] ) && ( $this->handler_vars['configure'] == $plugin['plugin_id'] ) ) {
				if ( i

Toggle wordwrap

Referring DomainHits
Unknown Referer 149
pastoid.com 28
Is this paste spam?
<Hide