<commit_before><?php

/**
 * A service interface to functionality related to getting and setting
 * permission information for nodes
 *
 * @author <EMAIL>
 * @license BSD License http://silverstripe.org/bsd-license/
 */
class PermissionService {
	
	const SOURCES_MAP = 'sources_map';
	
	public function __construct() {
	}
	
	/**
	 * 
	 * Allow this service to be accessed from the web
	 *
	 * @return array
	 */
	public function webEnabledMethods() {
		return array(
			'removeAuthority'		=> 'POST',
			'grantTo'				=> 'POST',
			'checkPerm'				=> 'GET',
			'getPermissionsFor'		=> 'GET',
			'getPermissionDetails'	=> 'GET'
		);
	}

	/**
	 * @var Zend_Cache_Core 
	 */
	protected $cache;
	
	protected $parents = array();
	
	protected $groups = array();

	/**
	 *
	 * @return Zend_Cache_Core
	 */
	public function getCache() {
		if (!$this->cache) {
			$this->cache = SS_Cache::factory('restricted_perms', 'Output', array('automatic_serialization' => true));
		}
		return $this->cache;
	}

	
	public function getAllRoles() {
		return DataObject::get('AccessRole');
	}

	public function getPermissionDetails() {
		return array(
			'roles'				=> $this->getAllRoles(),
			'permissions'		=> $this->allPermissions(),
//			'users'				=> DataObject::get('Member'),
//			'groups'			=> DataObject::get('Group')
		);
	}
	

	protected $allPermissions;

	public function allPermissions() {
		if (!$this->allPermissions) {
			$options = array();
			$definers = ClassInfo::implementorsOf('PermissionDefiner');
			$perms = array();
			foreach ($definers as $definer) {
				$cls = new $definer();
				$perms = array_merge($perms, $cls->definePermissions());
			}

			$this->allPermissions = $perms;
		}

		return $this->allPermissions;
	}
	
	public function flushCache() {
		$this->parents = array();
		$this->groups = array();
	}

	/**
	 * Alternative grant method using group name or email address
	 *
	 * @param DataObject $node
	 * @param type $perm
	 * @param DataObject $to
	 * @param type $grant 
	 */
	public function grantTo(DataObject $node, $perm, $email, $group, $grant = 'GRANT') {
		$userObj = $groupObj = null;
		if (strlen($email)) {
			$userObj = DataObject::get_one('Member', '"Email" = \''. Convert::raw2sql($email).'\'');
		} else if (strlen($group)) {
			$groupObj = DataObject::get_one('Group', '"Title" = \'' . Convert::raw2sql($group).'\'');
		}

		$to = $userObj ? $userObj : $groupObj;
		
		if (!$to) {
			return array('status' => false, 'message' => 'Unknown authority');
		}
		
		return $this->grant($node, $perm, $to, $grant);
	}
	
	/**
	 * Delete an authority
	 *
	 * @param DataObject $node 
	 *			The node to delete from
	 * @param DataObject $authority
	 *			The AccessAuthority we're removing
	 */
	public function removeAuthority(DataObject $node, DataObject $authority) {
		if (!$this->checkPerm($node, 'DeletePermissions')) {
			throw new PermissionDeniedException("You do not have permission to do that");
		}

		if ($authority) {
			$authority->delete();
		}
		
		return $node;
	}
	
	/**
	 * Grants a specific permission to a given user or group
	 *
	 * @param string $perm
	 * @param Member|Group $to
	 */
	public function grant(DataObject $node, $perm, DataObject $to, $grant = 'GRANT') {
		// make sure we can !!
		if (!$this->checkPerm($node, 'ChangePermissions')) {
			throw new PermissionDeniedException("You do not have permission to do that");
		}

		$role = DataObject::get_one('AccessRole', '"Title" = \'' . Convert::raw2sql($perm) . '\'');

		$composedOf = array($perm);
		if ($role && $role->exists()) {
			$composedOf = $role->Composes->getValues();
		}

		$type = $to instanceof Member ? 'Member' : get_class($to);
		$filter = array(
			'Type'			=> $type,
			'AuthorityID'	=> $to->ID,
			'ItemID'		=> $node->ID,
			'ItemType'		=> $node->class,
			'Grant'			=> $grant,
		);
		
		$list = DataList::create('AccessAuthority')->filter($filter);
		$existing = $list->first();
		if (!$existing || !$existing->exists()) {
			$existing = new AccessAuthority;
			$existing->Type = $type;
			$existing->AuthorityID = $to->ID;
			$existing->ItemID = $node->ID;
			$existing->ItemType = $node->class;
			$existing->Grant = $grant;
			$existing->Role = $role ? $role->Title : '';
		}

		$currentRoles = $existing->Perms->getValues();
		if (!$currentRoles) {
			$new = $composedOf;
		} else {
			$new = array_merge($currentRoles, $composedOf);
		}

		$new = array_unique($new);
		$existing->Perms = $new;
		$existing->write();

		foreach ($new as $perm) {
			$this->clearPermCacheFor($node, $perm);
		}

		return $existing;
	}
	
	/**
	 * Check for the presence of ALL permissions in a given role for the user to an object
	 *
	 * @param DataObject $node
	 *			The object to check perms on
	 * @param string $role
	 *			The role to check against
	 * @param Member $member 
	 *			The member to check -if not set, the current user is used<commit_msg>Remove unnecessary per-permission cache clear<commit_after><?php

/**
 * A service interface to functionality related to getting and setting
 * permission information for nodes
 *
 * @author <EMAIL>
 * @license BSD License http://silverstripe.org/bsd-license/
 */
class PermissionService {
	
	const SOURCES_MAP = 'sources_map';
	
	public function __construct() {
	}
	
	/**
	 * 
	 * Allow this service to be accessed from the web
	 *
	 * @return array
	 */
	public function webEnabledMethods() {
		return array(
			'removeAuthority'		=> 'POST',
			'grantTo'				=> 'POST',
			'checkPerm'				=> 'GET',
			'getPermissionsFor'		=> 'GET',
			'getPermissionDetails'	=> 'GET'
		);
	}

	/**
	 * @var Zend_Cache_Core 
	 */
	protected $cache;
	
	protected $parents = array();
	
	protected $groups = array();

	/**
	 *
	 * @return Zend_Cache_Core
	 */
	public function getCache() {
		if (!$this->cache) {
			$this->cache = SS_Cache::factory('restricted_perms', 'Output', array('automatic_serialization' => true));
		}
		return $this->cache;
	}

	
	public function getAllRoles() {
		return DataObject::get('AccessRole');
	}

	public function getPermissionDetails() {
		return array(
			'roles'				=> $this->getAllRoles(),
			'permissions'		=> $this->allPermissions(),
//			'users'				=> DataObject::get('Member'),
//			'groups'			=> DataObject::get('Group')
		);
	}
	

	protected $allPermissions;

	public function allPermissions() {
		if (!$this->allPermissions) {
			$options = array();
			$definers = ClassInfo::implementorsOf('PermissionDefiner');
			$perms = array();
			foreach ($definers as $definer) {
				$cls = new $definer();
				$perms = array_merge($perms, $cls->definePermissions());
			}

			$this->allPermissions = $perms;
		}

		return $this->allPermissions;
	}
	
	public function flushCache() {
		$this->parents = array();
		$this->groups = array();
	}

	/**
	 * Alternative grant method using group name or email address
	 *
	 * @param DataObject $node
	 * @param type $perm
	 * @param DataObject $to
	 * @param type $grant 
	 */
	public function grantTo(DataObject $node, $perm, $email, $group, $grant = 'GRANT') {
		$userObj = $groupObj = null;
		if (strlen($email)) {
			$userObj = DataObject::get_one('Member', '"Email" = \''. Convert::raw2sql($email).'\'');
		} else if (strlen($group)) {
			$groupObj = DataObject::get_one('Group', '"Title" = \'' . Convert::raw2sql($group).'\'');
		}

		$to = $userObj ? $userObj : $groupObj;
		
		if (!$to) {
			return array('status' => false, 'message' => 'Unknown authority');
		}
		
		return $this->grant($node, $perm, $to, $grant);
	}
	
	/**
	 * Delete an authority
	 *
	 * @param DataObject $node 
	 *			The node to delete from
	 * @param DataObject $authority
	 *			The AccessAuthority we're removing
	 */
	public function removeAuthority(DataObject $node, DataObject $authority) {
		if (!$this->checkPerm($node, 'DeletePermissions')) {
			throw new PermissionDeniedException("You do not have permission to do that");
		}

		if ($authority) {
			$authority->delete();
		}
		
		return $node;
	}
	
	/**
	 * Grants a specific permission to a given user or group
	 *
	 * @param string $perm
	 * @param Member|Group $to
	 */
	public function grant(DataObject $node, $perm, DataObject $to, $grant = 'GRANT') {
		// make sure we can !!
		if (!$this->checkPerm($node, 'ChangePermissions')) {
			throw new PermissionDeniedException("You do not have permission to do that");
		}

		$role = DataObject::get_one('AccessRole', '"Title" = \'' . Convert::raw2sql($perm) . '\'');

		$composedOf = array($perm);
		if ($role && $role->exists()) {
			$composedOf = $role->Composes->getValues();
		}

		$type = $to instanceof Member ? 'Member' : get_class($to);
		$filter = array(
			'Type'			=> $type,
			'AuthorityID'	=> $to->ID,
			'ItemID'		=> $node->ID,
			'ItemType'		=> $node->class,
			'Grant'			=> $grant,
		);
		
		$list = DataList::create('AccessAuthority')->filter($filter);
		$existing = $list->first();
		if (!$existing || !$existing->exists()) {
			$existing = new AccessAuthority;
			$existing->Type = $type;
			$existing->AuthorityID = $to->ID;
			$existing->ItemID = $node->ID;
			$existing->ItemType = $node->class;
			$existing->Grant = $grant;
			$existing->Role = $role ? $role->Title : '';
		}

		$currentRoles = $existing->Perms->getValues();
		if (!$currentRoles) {
			$new = $composedOf;
		} else {
			$new = array_merge($currentRoles, $composedOf);
		}

		$new = array_unique($new);
		$existing->Perms = $new;
		$existing->write();

		$this->clearPermCacheFor($node);

		return $existing;
	}
	
	/**
	 * Check for the presence of ALL permissions in a given role for the user to an object
	 *
	 * @param DataObject $node
	 *			The object to check perms on
	 * @param string $role
	 *			The role to check against
	 * @param Member $member 
	 *			The member to check -if not set, the current user is used
{'fraction_non_alphanumeric': 0.1709498355263158, 'fraction_numerical': 0.0006167763157894736, 'mean_word_length': 3.5, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4607516', 'n_tokens_mistral': 3674, 'n_tokens_neox': 3186, 'n_words': 802}