<?php
 if (!defined('VB_ENTRY')) die('Access denied.');
/*======================================================================*\
   || #################################################################### ||
   || # vBulletin 4.0.0 Release Candidate 2                              # ||
   || # ---------------------------------------------------------------- # ||
   || # Copyright ©2000-2009 vBulletin Solutions Inc. All Rights Reserved. ||
   || # This file may not be redistributed in whole or significant part. # ||
   || # ---------------- VBULLETIN IS NOT FREE SOFTWARE ---------------- # ||
   || # http://www.vbulletin.com | http://www.vbulletin.com/license.html # ||
   || #################################################################### ||
   \*======================================================================*/


/**
 * CMS Content Controller
 * Base content controller for CMS specific content types.
 *
 * @package vBulletin
 * @author Ed Brown, vBulletin Development Team
 * @version $Revision: 34307 $
 * @since $Date: 2009-12-10 12:28:01 -0600 (Thu, 10 Dec 2009) $
 * @copyright vBulletin Solutions Inc.
 */

 /**
  * Class to return permissions
  *
  */

 class vBCMS_Permissions
{
	/**** Caching time in minutes for permissions info ********/
 	protected static $cache_ttl = 5;

 	//Permissions are:
 	//1: canview
 	//2: cancreate
 	//4: canedit
 	//8: canpublish
 	//16: canUseHtml
 	protected static $permissionsfrom = array();

 	//We may have to check "canUseHtml" for several articles.
 	//Might as well cache the usergroups info.

 	private static $known_users = array();

	public static function getUserPerms($userid = false)
	{
		require_once DIR . '/includes/class_bootstrap_framework.php' ;
		vB_Bootstrap_Framework::init();
		$cache_ttl = 1440;

		if ($userid > 0)
		{
			$record = vB::$vbulletin->db->query_first("SELECT usergroupid, membergroupids FROM "
				. TABLE_PREFIX . "user WHERE userid = $userid");
			$usergroups = $record['usergroupid']
			. (strlen($record['membergroupids']) ? ',' . $record['membergroupids'] : '');
		}
		else
		{
			$userid = vB::$vbulletin->userinfo['userid'];
			$usergroups = vB::$vbulletin->userinfo['usergroupid']
			. (strlen(vB::$vbulletin->userinfo['membergroupids']) ? ',' . vB::$vbulletin->userinfo['membergroupids'] : '');
		}
		vB::$vbulletin->userinfo['permissions']['cms'] = self::getPerms($userid, $usergroups);
	}


 	public static function getPerms($userid, $usergroups = false)
 	{

 		//See if we have a cached version
 		$hash = self::getHash($userid);

 		if ($cmsperms = vB_Cache::instance()->read($hash, true))
 		{
 			return $cmsperms;
 		}

 		if (! $usergroups)
 		{
	 		$record = vB::$vbulletin->db->query_first("SELECT usergroupid, membergroupids FROM "
	 			. TABLE_PREFIX . "user WHERE userid = $userid");
	 		$usergroups = $record['usergroupid']
	 		. (strlen($record['membergroupids']) ? ',' . $record['membergroupids'] : '');
 		}

 		$cmsperms = array();
 		//We need to create four arrays
 		$cmsperms['canview'] = array();
 		$cmsperms['cancreate'] = array();
 		$cmsperms['canedit'] = array();
 		$cmsperms['canpublish'] = array();
 		$cmsperms['canusehtml'] = array();

		//The admin settings are all done by hooks, so we need to parse out the information
 		//ourselves manually.
 		$sql ="SELECT vbcmspermissions FROM " . TABLE_PREFIX .
 			"administrator WHERE userid = $userid";
			$record = vB::$vbulletin->db->query_first($sql);
 		if ($record AND $record['vbcmspermissions'])
 		{
 			$cmsperms['admin'] = $record['vbcmspermissions'];

 		}
 		else
 		{
 			$cmsperms['admin'] = 0;
 		}


 		if ($usergroups != '')
 		{
			$rst = vB::$vbulletin->db->query_read($sql = "SELECT nodeid,
			MAX(permissions & 1) AS canview, MAX(permissions & 2) AS cancreate , MAX(permissions & 4) AS canedit,
			MAX(permissions & 8) AS canpublish, MAX(permissions & 16) AS canusehtml
			FROM " . TABLE_PREFIX . "cms_permissions p
			WHERE usergroupid IN (" . $usergroups . ")
			GROUP BY nodeid; ");

			while($rst AND $result = vB::$vbulletin->db->fetch_array($rst))
	 		{

	 			if ($result['canview'] OR $result['canedit'] OR $result['canpublish'] OR $result['canusehtml'])
	 			{
	 				$cmsperms['canview'][] = $result['nodeid'];
	 			}

	 			if ($result['cancreate'] OR $result['canusehtml'] OR $result['canedit'])
	 			{
	 				$cmsperms['cancreate'][] = $result['nodeid'];
	 			}

	 			if ($result['canedit'] OR $result['canpublish'] OR $result['canusehtml'])
	 			{
	 				$cmsperms['canedit'][] = $result['nodeid'];
	 			}

	 			if ($result['canpublish'] OR $result['canusehtml'])
	 			{
	 				$cmsperms['canpublish'][] = $result['nodeid'];
	 			}

	 			if ($result['canusehtml'])
	 			{
	 				$cmsperms['canusehtml'][] = $result['nodeid'];
	 			}
	 		}
 		}
 		//when we use these in "where" clauses we'd better have at least one value.

 		if (!count($cmsperms['canview']))
 		{
 			$cmsperms['canview'][] = -1;
 		}

 		if (!count($cmsperms['cancreate']))
 		{
 			$cmsperms['cancreate'][] = -1;
 		}

 		if (!count($cmsperms['canedit']))
 		{
 			$cmsperms['canedit'][] = -1;
 		}

 		if (!count($cmsperms['canpublish']))
 		{
 			$cmsperms['canpublish'][] = -1;
 		}
 		if (!count($cmsperms['canusehtml']))
 		{
 			$cmsperms['canusehtml'][] = -1;
 		}


 		$cmsperms['alledit'] = $cmsperms['canedit'];

	   $cmsperms['viewonly'] =
 		   array_diff($cmsperms['canview'],
 		   $cmsperms['alledit']);

 		$cmsperms['allview'] = $cmsperms['canview'];
  		vB_Cache::instance()->write($hash, $cmsperms, self::$cache_ttl,
			array('cms_permissions_change', "permissions_$userid"));
 		return $cmsperms;
 	}

	/****
	 * This resets permissions for a node, and it's surrounding nodes, should they be unassigned.
	 *
	 ****/
	private static function repairPermissions($nodeid)
	{
		//we start by generating a list of this node's parents. We go up the tree until
		// either we find a node with assigned permissions, or we hit the top.
		//If we hit the top, we use that node.
		require_once DIR . '/includes/class_bootstrap_framework.php' ;
		vB_Bootstrap_Framework::init();

		$parents = array();
		$rst = vB::$vbulletin->db->query_read("SELECT parent.nodeid,
		parent.permissionsfrom FROM " . TABLE_PREFIX . "cms_node AS parent INNER JOIN
		" . TABLE_PREFIX . "cms_node AS node ON node.nodeleft BETWEEN parent.nodeleft AND parent.noderight
			AND parent.nodeid <> node.nodeid
		WHERE node.nodeid = $nodeid ORDER BY node.nodeleft DESC");
		$permissionsfrom = 1;

		while($record = vB::$vbulletin->db->fetch_array($rst))
		{
			$parents[] = $record;

			if (intval($record['permissionsfrom']))
			{
				$permissionsfrom = $record['permissionsfrom'];
				break;
			}
		}
		//Now we go back down the list. Assign the node to the children at each level;
		foreach ($parents as $parent)
		{
			vB::$vbulletin->db->query_write("UPDATE ". TABLE_PREFIX . "cms_node SET permissionsfrom = $permissionsfrom
				WHERE permissionsfrom IS NULL AND parentnode = " . $parent['nodeid']);
		}

	}

 	/****
 	* This determines if the user can view a node
 	*
 	****/
 	public static function canView($nodeid)
	{

 		require_once DIR . '/includes/class_bootstrap_framework.php' ;
 		vB_Bootstrap_Framework::init();

 		if (! isset(vB::$vbulletin->userinfo['permissions']['cms']) )
 		{
 			self::getUserPerms();
 		}

 		if (array_key_exists ($nodeid, self::$permissionsfrom))
 		{
 			return (in_array(self::$permissionsfrom[$nodeid], vB::$vbulletin->userinfo['permissions']['cms']['allview']));
 		}

 		//Sometimes - not often- the nodeid will be the permissionsfrom. In that case
 		// we can skip a database query.
 		if (in_array($nodeid, vB::$vbulletin->userinfo['permissions']['cms']['allview']))
 		{
 			return true;
 		}

 		if (! $record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " .
 			TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
 		{
 			return false;
 		}
 		if (intval($record['permissionsfrom']))
 		{
 			self::$permissionsfrom[$nodeid] = intval($record['permissionsfrom']);
 			return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['allview']));
 		}
 		//if we got here, there's a problem. Repair and do it again.
		self::repairPermissions($nodeid);
		if (! $record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " .
			TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
		{
			return false;
		}
		if (intval($record['permissionsfrom']))
		{
			self::$permissionsfrom[$nodeid] = intval($record['permissionsfrom']);
			return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['canview']));
		}
 		return false;
	}

	public static function canEdit($nodeid)
	{
		$nodeid = intval($nodeid);
		if (!$nodeid)
		{
			return false;
		}

		require_once DIR . '/includes/class_bootstrap_framework.php' ;
		vB_Bootstrap_Framework::init();

		if (!isset(vB::$vbulletin->userinfo['permissions']['cms']) )
		{
			self::getUserPerms();
		}

		if (array_key_exists ($nodeid, self::$permissionsfrom))
		{
			return (in_array(self::$permissionsfrom[$nodeid], vB::$vbulletin->userinfo['permissions']['cms']['alledit']));
		}

 		//Sometimes - not often- the nodeid will be the permissionsfrom. In that case
		// we can skip a database query.
		if (in_array($nodeid, vB::$vbulletin->userinfo['permissions']['cms']['alledit']))
		{
			return true;
		}

		if (!$record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " . TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
		{
			return false;
		}

		//If we got here, we need to pull a record from the database.
		if (intval($record['permissionsfrom']))
		{
			self::$permissionsfrom[$nodeid] = intval($record['permissionsfrom']);
			return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['alledit']));
		}
		//if we got here, there's a problem. Repair and do it again.
		self::repairPermissions($nodeid);

		if (!$record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " . TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
		{
			return false;
		}

		if (intval($record['permissionsfrom']))
		{
			self::$permissionsfrom[$nodeid] = intval($record['permissionsfrom']);
			return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['alledit']));
		}
		return false;
	}

 	/** This function tells whether we can create a content node.
 	* The rules are: if we have publish rights we can create any type of content
 	* If we have create or edit we can create non-section types.
 	***/
 	public static function canCreate($nodeid, $contenttype)
 	{
		$sectiontype = vB_Types::instance()->getContentTypeID('vBCms_Section');

 		if (array_key_exists ($nodeid, self::$permissionsfrom))
 		{
 			if ($contenttype == $sectiontype)
 			{
 				return (in_array(self::$permissionsfrom[$nodeid], vB::$vbulletin->userinfo['permissions']['cms']['canpublish']));
 			}
 			return (in_array(self::$permissionsfrom[$nodeid], vB::$vbulletin->userinfo['permissions']['cms']['alledit']));
 		}

 		require_once DIR . '/includes/class_bootstrap_framework.php' ;
 		vB_Bootstrap_Framework::init();

 		if (! isset(vB::$vbulletin->userinfo['permissions']['cms']) )
 		{
 			self::getUserPerms();
 		}

 		//Sometimes - not often- the nodeid will be the permissionsfrom. In that case
 		// we can skip a database query.
 		if (in_array($nodeid, vB::$vbulletin->userinfo['permissions']['cms']['cancreate']))
 		{
 			return true;
 		}

		if (! $record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " .
 			TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
 		{
 			return false;
 		}

 		if (intval($record['permissionsfrom']))
 		{
 			self::$permissionsfrom[$nodeid] = intval($record['permissionsfrom']);
 			if ($contenttype == $sectiontype)
 			{
 				return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['canpublish']));
 			}
 			return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['alledit']));
 		}

 		//if we got here, there's a problem. Repair and do it again.
 		self::repairPermissions($nodeid);

 		if (! $record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " .
 			TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
 		{
 			return false;
 		}

 		if (intval($record['permissionsfrom']))
 		{
 			self::$permissionsfrom[$nodeid] = intval($record['permissionsfrom']);
 			if ($contenttype == $sectiontype)
 			{
 				return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['canpublish']));
 			}
 			return (in_array($record['permissionsfrom'], vB::$vbulletin->userinfo['permissions']['cms']['alledit']));
 		}
 		return false;
 	}

 	/** This function tells whether this user can create a content node.
 	 * The rules are: if we have publish rights we can create any type of content
 	 * If we have create or edit we can create non-section types.
 	 ***/
 	public static function canUseHtml($nodeid, $contenttype, $userid)
 	{
  		require_once DIR . '/includes/class_bootstrap_framework.php' ;
 		vB_Bootstrap_Framework::init();

 		$sectiontype = vB_Types::instance()->getContentTypeID('vBCms_Section');

 		if (array_key_exists ($nodeid, self::$permissionsfrom))
 		{
 			$permissionsfrom = self::$permissionsfrom[$nodeid];
 		}
 		else
 		{
 			if (! $record = vB::$vbulletin->db->query_first("SELECT permissionsfrom FROM " .
 				TABLE_PREFIX . "cms_node WHERE nodeid = $nodeid"))
 			{
 				return false;
 			}
 			self::$permissionsfrom[$nodeid] = $permissionsfrom = $record['permissionsfrom'];
 		}

 		$perms = self::getPerms($userid);
 		$result = in_array($permissionsfrom, $perms['canusehtml']) ?  1 : 0;

 		return $result;
 	}

	/********* Get a hash so we can cache the data
	 *
	 ********/
	protected static function getHash($userid = null)
	{
		if ($userid == null)
		{
			$userid = vB::$vbulletin->userinfo['userid'];
		}
		$context = new vB_Context('cms_priv' , array('userid' => $userid));
		return strval($context);

	}


 }