Browse Source

minor: add a base controller and access to be derived from

Laurent Opprecht 12 years ago
parent
commit
dd55e0ab63
2 changed files with 401 additions and 0 deletions
  1. 203 0
      main/inc/lib/access.class.php
  2. 198 0
      main/inc/lib/controller.class.php

+ 203 - 0
main/inc/lib/access.class.php

@@ -0,0 +1,203 @@
+<?php
+
+/**
+ * Authorize or deny calls. 
+ * 
+ * 
+ * Note:
+ * 
+ * This class stores locally the security token so that the current call
+ * can still be validated after generating the new token.
+ * 
+ * The new security token is generated only on first call. Successive calls
+ * return the same token. This ensure that different parts of the application
+ * (form, javascript for javascript, etc) can get access to the same token.
+ * 
+ * @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Geneva
+ * @license /license.txt
+ */
+abstract class Access
+{
+
+    const SEC_TOKEN = 'sec_token';
+    
+    /**
+     * Return view and edit access.
+     * 
+     * @return  \Access
+     */
+    public static function all()
+    {
+        return AccessAll::instance();
+    }
+
+    /**
+     * Return no access.
+     * 
+     * @return  \Access
+     */
+    public static function forbidden()
+    {
+        AccessForbidden::instance();
+    }
+
+    protected $session_token;
+    protected $token;
+
+    /**
+     * Returns true if security token is valid, false otherwise.
+     * 
+     * @return bool
+     */
+    public function is_token_valid()
+    {
+        $call_token = Request::get_security_token();
+        if (empty($call_token)) {
+            return false;
+        }
+        $session_token = $this->get_session_token();
+        return $session_token == $call_token;
+    }
+
+    /**
+     * Returns the token contained in the session. 
+     * Stores the token for further reuse so that it can be changed in session.
+     * 
+     * @return string 
+     */
+    public function get_session_token()
+    {
+        if (empty($this->session_token)) {
+            $key = self::SEC_TOKEN;
+            $this->session_token = isset($_SESSION[$key]) ? $_SESSION[$key] : '';
+        }
+        return $this->session_token;
+    }
+
+    /*
+     * On first call generate a new security token and save it in session.
+     * On successful calls returns the same (new) token (function is repeatable).
+     * If user do not have the right to edit, returns a blank (invalid) token.
+     * 
+     * Stores the existing session token before saving the new one so that 
+     * the current call can still be validated after calling this function.
+     */
+
+    public function get_token()
+    {
+        if (!$this->can_edit()) {
+            return '';
+        }
+        if ($this->token) {
+            return $this->token;
+        }
+        $this->session_token = $this->get_session_token();
+
+
+        $this->token = \Security::get_token();
+    }
+
+    /**
+     * Returns true if the user has the right to edit.
+     * 
+     * @return boolean 
+     */
+    public abstract function can_edit();
+
+    /**
+     * Returns true if the current user has the right to view
+     * 
+     * @return boolean 
+     */
+    public abstract function can_view();
+
+    public function authorize()
+    {
+        return $this->can_view();
+    }
+
+}
+
+/**
+ * Authorize access and view access. 
+ */
+class AccessAll extends Access
+{
+
+    /**
+     * Return the instance.
+     * 
+     * @return  \Access
+     */
+    public static function instance()
+    {
+        static $result = null;
+        if (empty($result)) {
+            $result = new self();
+        }
+        return $result;
+    }
+
+    private function __construct()
+    {
+        
+    }
+
+    public function can_edit()
+    {
+        return true;
+    }
+
+    public function can_view()
+    {
+        return true;
+    }
+
+    public function authorize()
+    {
+        return true;
+    }
+
+}
+
+/**
+ * Authorizev view access only 
+ */
+class AccessForbidden extends Access
+{
+
+    /**
+     * Return the instance.
+     * 
+     * @return  \AccessView
+     */
+    public static function instance()
+    {
+        static $result = null;
+        if (empty($result)) {
+            $result = new self();
+        }
+        return $result;
+    }
+
+    private function __construct()
+    {
+        
+    }
+
+    public function can_edit()
+    {
+        return false;
+    }
+
+    public function can_view()
+    {
+        return false;
+    }
+
+    public function authorize()
+    {
+        return false;
+    }
+
+}

+ 198 - 0
main/inc/lib/controller.class.php

@@ -0,0 +1,198 @@
+<?php
+
+/**
+ * Controller
+ * 
+ * 
+ * 
+ * @author Laurent Opprecht <laurent@opprecht.info> for the Univesity of Genevas
+ * @license see /license.txt
+ */
+class Controller 	
+{
+
+    const PARAM_ACTION = 'action';
+    
+    protected $access;
+    
+    protected function __construct($access = null)
+    {
+        $access = $access ? $access : Access::all();
+        $this->access = $access;
+    }
+    
+    /**
+     *
+     * @return \Access
+     */
+    public function access()
+    {
+        return $this->access;
+    }
+
+    /**
+     * List of actions accepted by the controller.
+     * 
+     * @return array
+     */
+    public function get_actions()
+    {
+        $reflector = new ReflectionClass($this);
+        $constants = $reflector->getConstants();
+        $result = array();
+        foreach ($constants as $key => $value) {
+            if (strpos($key, 'ACTION') !== false) {
+                $result[$key] = $value;
+            }
+        }
+        return $result;
+    }
+
+    /**
+     * Action to perform. 
+     * Returns the request parameter.
+     * 
+     * @return string
+     */
+    public function get_action()
+    {
+        $result = Request::get(self::PARAM_ACTION);
+        $actions = $this->get_actions();
+        $result = in_array($result, $actions) ? $result : '';
+        return $result;
+    }
+
+    /**
+     * Set up the environment. Set up breadcrumps, raise tracking event, etc.
+     */
+    protected function prolog()
+    {
+        
+    }
+
+    /**
+     * Whether the call is authorized or not.
+     * 
+     * @return boolean 
+     */
+    public function authorize()
+    {
+        return $this->access()->authorize();
+    }
+
+    /**
+     * Returns a string containing dynamic javascript to be included in the template.
+     * This requires a {{javascript}} tag in a twigg template to appear.
+     * 
+     * Note:
+     * 
+     * A better approach to this method is to create a twigg "javascript"
+     * template and to include it where required.
+     * 
+     * @return string 
+     */
+    public function javascript()
+    {
+        return '';
+    }
+
+//    public function check_token()
+//    {
+//        return (bool) Security::check_token('get');
+//    }
+
+    /**
+     * Run the controller. Dispatch action and execute requested tasks.
+     */
+    public function run()
+    {
+        if (!$this->authorize()) {
+            $this->forbidden();
+            return false;
+        }
+
+        $this->prolog();
+        $action = $this->get_action();
+        if (empty($action)) {
+            $this->unknown();
+            return;
+        }
+        $f = array($this, $action);
+        if (is_callable($f)) {
+            call_user_func($f);
+        } else {
+            $this->missing();
+        }
+    }
+
+    /**
+     * Unknown action. I.e. the action has not been registered. 
+     * Possibly missing action declaration:
+     * 
+     *      const ACTION_XXX = 'XXX';
+     * 
+     * @return boolean 
+     */
+    public function unknown()
+    {
+        return false;
+    }
+
+    /**
+     * 
+     * @return boolean 
+     */
+    public function forbidden()
+    {
+        api_not_allowed();
+        return false;
+    }
+
+    /**
+     * Action exists but implementation is missing. 
+     */
+    public function missing()
+    {
+        echo 'No implementation';
+        return false;
+    }
+
+    /**
+     * Render a template using data. Adds a few common parameters to data.
+     * 
+     * @see /main/template/default/course_description/
+     * @param string $template
+     * @param array $data 
+     */
+    protected function render($template_name, $data)
+    {
+        $data = (object) $data;
+        $data->www = \Chamilo::url();
+        $data->messages = isset($data->messages) ? $data->messages : array();
+        $javascript = $this->javascript();
+        if ($javascript) {
+            $data->javascript = $javascript;
+        }
+
+        $tpl = new Template();
+        foreach ($data as $key => $value) {
+            $tpl->assign($key, $value);
+        }
+        $template = $tpl->get_template($template_name);
+        $content = $tpl->fetch($template);
+        $tpl->assign('content', $content);
+        $tpl->display_one_col_template();
+    }
+
+    /**
+     * Render data as JSON
+     * 
+     * @param any $data 
+     */
+    protected function render_json($data)
+    {
+        Header::content_type_json();
+        echo json_encode($data);
+    }
+
+}