<?php
/**
 * Template_access_control - This library is for supporting user access control for all unit/template objects.
 * 								  This includes the typical unit_* objects and all the objects in the uph folder.
 *
 * @author $Author: dtong $
 * @version $Id: handle_user_role.php,v 1.1 2010/07/19 04:25:56 dtong Exp $
 * @copyright Copyright (c) 2010, Tiller Software Co., Ltd.
*/
require_once('handle_base.php');

Class handle_user_role extends handle_base {
	Const HANDLE_PARAM_LIST = '_allusers_access_read,_owner_access_edit,_owner_access_read,_roles_access_edit,_roles_access_read';
	//Checks the access control, returns false if no access, ture otherwise
	//In the case that a readonly access is granted for edit action then
	//the action variable in $params will be changed to read from edit
	//Note, the params parameter is passed in by reference since it is an object
	/*
	 * The behavior is to ignore all access unless specified by the following conditions:
	 *
	 * Valid template parameters:
	 *		_allusers_access_read - All users can read
	 *		_owner_access_edit - Owner can write, this implies read access also
	 *		_owner_access_read - Owner can read. Not necessary if write access is already granted.
	 *		_roles_access_edit - List of roles like '5' or '5,6,7' (user_role table, column type) can write, implies read access
	 *		_roles_access_read - List of roles like '5' or '5,6,7' (user_role table, column type) can read.
	 */
	function invoke() {
		//Check the handle parameters from the template and make sure they are valid
		//Browser would get error message if invalid parameter is found
		$this->valid_handle_params(self::HANDLE_PARAM_LIST);
		//We do the simple checking without DB access first
		//Admin unit write can do anything
		if ( $this->CI->access_model->checkaccess_any('admin_unit_write', FALSE, FALSE, FALSE) )
			return TRUE;
		if ( $this->is_action_read() && $this->CI->access_model->checkaccess_any('admin_unit_read', FALSE, FALSE, FALSE) )
			return TRUE;
		$has_read_access = (osa_value($this->handle_data, '_allusers_access_read', FALSE) === TRUE);
		if ( $this->is_action_read() &&  $has_read_access)
			return TRUE;
		//Looks like we have to access the DB to go further so load the model here
		//The code here calls the same DB functions many times but since we use cache in the model so it is OK and efficient
		$this->CI->load->model('unit/event/handle_user_role_model');

		//don't care about action here since it should return true for read or edit
		if ( osa_value($this->handle_data, '_owner_access_edit', FALSE) ) {
			if ( $this->is_owner() )
				return TRUE;
		}
		//don't care about action here since it should return true for read or edit
		if ( $roles = osa_value($this->handle_data, '_roles_access_edit', FALSE) ) {
			if ( $this->valid_role_string($roles) ) {
				if ( $this->has_role($roles) )
					return TRUE;
			}
		}

		//At this point if action is edit then we know the user has no write access
		if ( $this->is_action_edit() ) {
			if ( !$has_read_access ) {
				$roles=osa_value($this->handle_data, '_roles_access_read', FALSE);
				$has_read_access = ( (osa_value($this->handle_data, '_owner_access_read', FALSE) && $this->is_owner()) ||
											 ($roles !== FALSE) && $this->has_role($roles) );
			}
			if ( $has_read_access ) {
				//Edit action but user only has read access so change the action to read
				//This actually changes the action for Unitmain
				$this->change_action2read();
				return TRUE;
			}
			return FALSE; //We know this is edit action and the user can't read or write so return FALSE
		}

		//At this point, the action has to be read. TODO: But, there is a edit_goal action and it has to be elimnated?
		if ( osa_value($this->handle_data, '_owner_access_read', FALSE) && $this->is_action_read() ) {
			if ( $this->is_owner() )
				return TRUE;
		}
		$roles = osa_value($this->handle_data, '_roles_access_read', FALSE);
		if ( $roles !== FALSE && $this->is_action_read() ) {
			if ( $this->valid_role_string($roles) ) {
				if ( $this->has_role($roles) )
					return TRUE;
			}
		}
		//Any action other than read and edit will end up here
		return FALSE;
	}

	//Function to make sure the role list from the template is valid
	private function valid_role_string($roles) {
		$ret = preg_match('/^[123456789][,1234567890]*$/', $roles);
		if ( !$ret ) {
			osa_errorlog(__METHOD__ . ' - Invalid _roles_access_edit/read value', $this->handle_data);
			$this->error_flag = TRUE;
		}
		return $ret;
	}

	//Function to see is the current unit/goal/survey belong to the current login user
	private function is_owner() {
		$table = $this->template_identifier; //template_identifier and table name are always the same
		$column = 'creatorid'; //Make sure all the tables to be created has this column
		$user = $this->CI->login_model->getLogin();
		if ( !$user )
			return FALSE;
		return $this->CI->handle_user_role_model->is_owner($user->id, $this->unitid, $table, $column);
	}

	//Function to check the roles (user_role table) for the current login user
	private function has_role($roles) {
		$user = $this->CI->login_model->getLogin();
		return $this->CI->handle_user_role_model->has_roles($user->id, $roles);
	}
}