Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactored into template and base controllers, resolved #20

  • Loading branch information...
commit 87871f1ff8c343e0a68078e75be0ed8c90d91a21 1 parent 321d8ef
@vimofthevine authored
Showing with 879 additions and 961 deletions.
  1. +19 −0 LICENSE.md
  2. +22 −0 README.md
  3. +3 −0  RELEASENOTES.md
  4. +3 −0  classes/controller/admin.php
  5. +56 −75 classes/controller/admin/auth.php
  6. +178 −0 classes/controller/admin/base.php
  7. +70 −44 classes/controller/admin/main.php
  8. +1 −0  classes/controller/admin/media.php
  9. +0 −46 classes/controller/admin/support.php
  10. +94 −314 classes/controller/admin/users.php
  11. +14 −92 classes/controller/template/admin.php
  12. +3 −2 classes/{message/core.php → kohana/message.php}
  13. +1 −1  classes/message.php
  14. +0 −46 config/a1.php
  15. +0 −15 config/admin-example.php
  16. +17 −0 config/admin.php
  17. +7 −23 config/{auth-example.php → auth.php}
  18. +43 −0 guide/admin.acl.md
  19. +19 −0 guide/admin.dependencies.md
  20. +33 −0 guide/admin.layout.md
  21. +13 −0 guide/admin.overview.md
  22. +40 −0 guide/admin.resources.md
  23. +25 −0 guide/admin.template.md
  24. +8 −0 guide/menu.admin.md
  25. +4 −28 init.php
  26. +21 −0 messages/a2.php
  27. +16 −0 messages/admin.php
  28. +0 −10 messages/auth.php
  29. +0 −26 views/admin/auth/hmvc/login.php
  30. +26 −5 views/admin/auth/login.php
  31. +3 −29 views/admin/dashboard.php
  32. +3 −0  views/admin/layout/full_width.php
  33. +7 −0 views/admin/layout/narrow_column.php
  34. +9 −0 views/admin/layout/narrow_column_with_menu.php
  35. +1 −0  views/admin/layout/none.php
  36. +7 −0 views/admin/layout/wide_column_with_menu.php
  37. +0 −9 views/admin/support/widget/menu.php
  38. +4 −4 views/admin/themes/default/footer.php
  39. +19 −43 views/admin/themes/default/header.php
  40. +9 −18 views/admin/themes/default/menu.php
  41. +15 −6 views/admin/themes/default/template.php
  42. +0 −6 views/admin/themes/tpd/footer.php
  43. +0 −20 views/admin/themes/tpd/header.php
  44. +0 −9 views/admin/themes/tpd/menu.php
  45. +0 −16 views/admin/themes/tpd/template.php
  46. +13 −7 views/admin/users/delete.php
  47. +13 −7 views/admin/users/form.php
  48. +0 −11 views/admin/users/hmvc/delete.php
  49. +0 −15 views/admin/users/hmvc/form.php
  50. +0 −2  views/admin/users/hmvc/list.php
  51. +0 −5 views/admin/users/hmvc/none.php
  52. +0 −11 views/admin/users/hmvc/view.php
  53. +25 −6 views/admin/users/list.php
  54. +4 −4 views/admin/users/menu.php
  55. +11 −6 views/admin/users/view.php
View
19 LICENSE.md
@@ -0,0 +1,19 @@
+Copyright (c) 2010 Kyle Treubig
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
View
22 README.md
@@ -0,0 +1,22 @@
+# Admin Overview
+
+The admin module is meant to facilitate the rapid development of an end-user
+administration site. There are essentially two aspects provided by the module,
+the template and the framework.
+
+## Features
+ - Template integration, courtesy of Colonel-Rosa
+ - Resource handling
+ - Access control
+ - Automated differentiation between external requests (full layout)
+ and internal requests (partial layout)
+
+### The Admin Framework
+
+The admin module also provides a framework for creating administration pages.
+The abstract base admin controller, `Controller_Admin`, may be extended to make
+use of the template and other common functions. The common functions provided
+by the base admin controller are ACL checking (using Wouter's A2 library) and
+request handling (differentiating between main/external requests and ajax/internal
+requests).
+
View
3  RELEASENOTES.md
@@ -0,0 +1,3 @@
+# Admin Module Release Notes
+
+* June 15, 2010 - **API change** - Refactored functions into separate template and base controllers (issue #20)
View
3  classes/controller/admin.php
@@ -0,0 +1,3 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+class Controller_Admin extends Controller_Admin_Base { }
View
131 classes/controller/admin/auth.php
@@ -1,19 +1,21 @@
-<?php defined('SYSPATH') OR die('No direct script access.');
+<?php defined('SYSPATH') or die('No direct script access.');
/**
- * @package Controller
+ * Authentication Controller
+ *
+ * @package Admin
+ * @category Controller
* @author Kyle Treubig
* @copyright (c) 2010 Kyle Treubig
* @license MIT
*/
-class Controller_Admin_Auth extends Controller_Template_Admin {
+class Controller_Admin_Auth extends Controller_Admin {
- /**
- * Register controller as an admin controller
- */
- public function before() {
- parent::before();
- }
+ protected $_view_map = array(
+ 'login' => 'admin/layout/narrow_column',
+ );
+
+ protected $_current_nav = 'admin/login';
/**
* Display login form and perform login
@@ -21,84 +23,56 @@ public function before() {
public function action_login() {
Kohana::$log->add(Kohana::DEBUG, 'Executing Controller_Auth::action_login');
+ // If user is already logged in, redirect to admin main
if ($this->a2->logged_in())
{
Kohana::$log->add('ACCESS', "Attempt to login made by logged-in user");
- $message = __('You are already logged in.');
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri() );
- }
+ Kohana::$log->add(Kohana::DEBUG, "Attempt to login made by logged-in user");
+ Message::instance()->error(Kohana::message('a2', 'login.already'));
+ $this->request->redirect( Route::get('admin')->uri() );
}
+ $this->template->content = View::factory('admin/auth/login')
+ ->bind('post', $post)
+ ->bind('errors', $errors);
+
$post = Validate::factory($_POST)
->filter(TRUE, 'trim')
->rule('username', 'not_empty')
- ->rule('password', 'not_empty');
+ ->rule('password', 'not_empty')
+ ->callback('username', array($this, 'check_username'));
if ($post->check())
{
- $user = Sprig::factory('user', array('username'=>$post['username']))->load();
-
- $remember = isset($post['remember']) ? (bool) $post['remember'] : FALSE;
-
- if ( ! $user->loaded())
- {
- Kohana::$log->add('ACCESS', 'Attempt to login made with unknown username, '.$post['username']);
- $post->error('username', 'not_found');
- }
- elseif ($this->a1->login($post['username'], $post['password'], $remember))
+ if ($this->a1->login($post['username'], $post['password'],
+ ! empty($post['remember'])))
{
- Kohana::$log->add('ACCESS', 'Successful login made with username, '.$user->username);
- $message = __('Welcome back, :name!', array(':name'=>$user->username));
-
- // Get referring URI, if any
- $referrer = $this->session->get('referrer');
- $referrer = empty($referrer) ? Route::get('admin_main')->uri() : $referrer;
- $this->session->delete('referrer');
+ Kohana::$log->add('ACCESS', 'Successful login made with username, '
+ .$post['username']);
+ Message::instance()->info(Kohana::message('a2', 'login.success'),
+ array(':name' => $post['username']));
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
+ // If external request, redirect to referring URL or admin main
+ if ( ! $this->_internal)
{
- Message::instance()->info($message);
- Request::instance()->redirect($referrer);
+ // Get referring URI, if any
+ $referrer = $this->session->get('referrer')
+ ? $this->session->get('referrer')
+ : Route::get('admin')->uri();
+ $this->session->delete('referrer');
+
+ $this->request->redirect($referrer);
}
}
else
{
- Kohana::$log->add('ACCESS', 'Unsuccessful login attempt made with username, '.$post['username']);
+ Kohana::$log->add('ACCESS', 'Unsuccessful login attempt made with username, '
+ .$post['username']);
$post->error('password', 'incorrect');
}
}
- $form = $errors = array(
- 'username' => '',
- 'password' => '',
- 'remember' => '',
- );
-
- $hmvc = View::factory('admin/auth/hmvc/login')
- ->set('form', Arr::overwrite($form, $post->as_array()))
- ->set('errors', Arr::overwrite($errors, $post->errors('auth')));
-
- $view = View::factory('admin/auth/login')
- ->set('form', $hmvc);
-
- // Set request response
- $this->template->content = $this->internal_request ? $hmvc : $view;
+ $errors = $post->errors('admin');
}
/**
@@ -109,20 +83,27 @@ public function action_logout() {
$this->a1->logout();
Kohana::$log->add('ACCESS', 'Successful logout made by user.');
- $message = __('You have been logged out. Goodbye!');
+ Message::instance()->info(Kohana::message('a2', 'logout.success'));
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
+ if ( ! $this->_internal)
{
- Message::instance()->info($message);
- Request::instance()->redirect( Route::get('admin_main')->uri() );
+ $this->request->redirect( Route::get('admin')->uri() );
}
}
+ /**
+ * Username callback to check if username is valid
+ */
+ public function check_username(Validate $array, $field)
+ {
+ $exists = (bool) DB::select(array('COUNT("*")', 'total_count'))
+ ->from('users')
+ ->where('username', '=', $array[$field])
+ ->execute()->get('total_count');
+
+ if ( ! $exists)
+ $array->error($field, 'not_found', array($array[$field]));
+ }
+
}
View
178 classes/controller/admin/base.php
@@ -0,0 +1,178 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+/**
+ * Base Admin Controller
+ *
+ * @package Admin
+ * @category Base
+ * @author Kyle Treubig
+ * @copyright (c) 2010 Kyle Treubig
+ * @license MIT
+ */
+abstract class Controller_Admin_Base extends Controller_Template_Admin {
+
+ /*
+ * @var array Action-to-privilege ACL map
+ */
+ protected $_acl_map = array('default' => NULL);
+
+ /**
+ * @var array Actions requiring ACL checking
+ */
+ protected $_acl_required = array();
+
+ /**
+ * @var mixed ACL resource
+ */
+ protected $_resource = 'resource';
+
+ /**
+ * @var array Actions requiring a loaded resource
+ */
+ protected $_resource_required = array();
+
+ /**
+ * @var array Actions accessible as internal-only
+ */
+ protected $_internal_only = array();
+
+ /**
+ * @var boolean Internal or external request
+ */
+ protected $_internal = FALSE;
+
+ /**
+ * @var array Action-to-layout view map
+ */
+ protected $_view_map = array('default' => 'admin/layout/narrow_column');
+
+ /**
+ * Sets up admin framework controllers
+ *
+ * - Redirects invalid internal-only access requests to the admin main
+ * - Loads resources if required, and redirects if invalid
+ * - Performs ACL checking, and redirects if denied
+ */
+ public function before() {
+ parent::before();
+
+ // Set common variables
+ $this->a2 = A2::instance('auth');
+ $this->a1 = $this->a2->a1;
+ $this->session = Session::instance();
+
+ // Check if internal request
+ if ($this->request !== Request::instance() OR Request::$is_ajax)
+ {
+ $this->_internal = TRUE;
+ }
+
+ // Check if internal-only request
+ if (in_array($this->request->action, $this->_internal_only)
+ AND ! $this->_internal)
+ {
+ Kohana::$log->add(Kohana::INFO, 'Attempt to access internal URL, '
+ .$this->request->uri.', externally');
+ Request::instance()->redirect( Route::get('admin')->uri() );
+ }
+
+ // Perform resource loads and ACL check
+ try
+ {
+ if (in_array($this->request->action, $this->_resource_required))
+ {
+ $this->_load_resource();
+ }
+
+ if ($this->_acl_required === 'all' OR in_array($this->request->action, $this->_acl_required))
+ {
+ $privilege = isset($this->_acl_map[$this->request->action])
+ ? $this->_acl_map[$this->request->action]
+ : $this->_acl_map['default'];
+ $this->a2->allowed($this->_resource, $privilege, TRUE);
+ }
+ }
+ catch (A2_Exception $ae)
+ {
+ // Redirect to login form if not logged in
+ if ( ! $user = $this->a2->get_user())
+ {
+ $this->session->set('referrer', Request::instance()->uri);
+ Message::instance()->error(Kohana::message('a2', 'login.required'));
+ $this->request->redirect( Route::get('admin/auth')->uri() );
+ }
+
+ Kohana::$log->add('ACCESS', 'Failed attempt to access resource, '
+ .$this->_resource.', by user, '.$user->username.', with url, '
+ .$this->request->uri);
+
+ Message::instance()->error($ae->getMessage(),
+ array(':resource' => $this->_resource));
+
+ // If controller-level access is denied, redirect to admin main
+ if ($this->request->action == 'index')
+ {
+ Request::instance()->redirect(Route::get('admin')->uri());
+ }
+ // Else action-level access is denied, redirect to default action
+ else
+ {
+ $this->request->redirect( $this->request->uri(
+ array('action' => 'index', 'id' => NULL)) );
+ }
+ }
+ catch (Kohana_Exception $ke)
+ {
+ // Catch 404 exceptions triggered by invalid resource loads
+ if ($ke->getCode() == 404)
+ {
+ Message::instance()->error($ke->getMessage());
+ $this->request->redirect( $this->request->uri(
+ array('action' => '', 'id' => NULL)) );
+ }
+ else
+ {
+ throw $ke;
+ }
+ }
+ }
+
+ /**
+ * Handles internal/external request-specific view settings
+ */
+ public function after() {
+ $content = $this->template->content;
+
+ // If external request, insert into layout template
+ if ( ! $this->_internal)
+ {
+ $view = isset($this->_view_map[$this->request->action])
+ ? $this->_view_map[$this->request->action]
+ : $this->_view_map['default'];
+ $this->template->content = View::factory($view)
+ ->set('menu', $this->_menu())
+ ->set('content', $content);
+ }
+ // Else append current info/error messages to internal response
+ // and replace template with content
+ else
+ {
+ $messages = Message::instance()->get();
+ $this->template = $messages.$content;
+ }
+
+ parent::after();
+ }
+
+ /**
+ * Load a specific resource
+ */
+ protected function _load_resource() { }
+
+ /**
+ * Generate menu
+ */
+ protected function _menu() { }
+
+} // End of Controller_Admin_Base
+
View
114 classes/controller/admin/main.php
@@ -1,43 +1,77 @@
<?php defined('SYSPATH') OR die('No direct script access.');
-class Controller_Admin_Main extends Controller_Template_Admin {
+/**
+ * Main Admin Controller (dashboard)
+ *
+ * @package Admin
+ * @category Controller
+ * @author Kyle Treubig
+ * @copyright (c) 2010 Kyle Treubig
+ * @license MIT
+ */
+class Controller_Admin_Main extends Controller_Admin {
+ protected $_view_map = array(
+ 'index' => 'admin/layout/none',
+ );
+
+ protected $_current_nav = 'admin';
+
+ /**
+ * Display administration dashboard
+ */
public function action_index() {
if ($this->a1->get_user() === FALSE)
{
- Request::instance()->redirect( Route::get('admin_auth')->uri(array('action'=>'login')) );
+ $this->request->redirect( Route::get('admin/auth')->uri() );
}
- unset($this->template->menu->menu['Home'][0]);
-
- $this->template->scripts[] = Route::get('admin_media')->uri(array('file'=>'ThePixelDeveloper_Admin-Template/js/glow/1.7.0/core/core.js'));
- $this->template->scripts[] = Route::get('admin_media')->uri(array('file'=>'ThePixelDeveloper_Admin-Template/js/glow/1.7.0/widgets/widgets.js'));
+ $this->template->scripts[] = Route::get('admin/media')->uri(array('file'=>'ThePixelDeveloper_Admin-Template/js/glow/1.7.0/core/core.js'));
+ $this->template->scripts[] = Route::get('admin/media')->uri(array('file'=>'ThePixelDeveloper_Admin-Template/js/glow/1.7.0/widgets/widgets.js'));
$this->template->scripts[] = Route::get('media')->uri(array('file'=>'js/dashboard_widgets.js'));
- $this->template->styles[ Route::get('admin_media')->uri(array('file'=>'ThePixelDeveloper_Admin-Template/js/glow/1.7.0/widgets/widgets.css')) ] = 'screen';
- $this->template->content = new View('admin/dashboard');
- }
+ $this->template->styles[ Route::get('admin/media')->uri(array('file'=>'ThePixelDeveloper_Admin-Template/js/glow/1.7.0/widgets/widgets.css')) ] = 'screen';
- public function action_user_info() {
- if ( ! $this->internal_request)
- {
- Request::instance()->redirect( Route::get('admin_main')->uri() );
- }
+ $this->template->content = View::factory('admin/dashboard')
+ ->set('user_info', $this->user_info())
+ ->set('system_info', $this->system_info())
+ ->set('updates', $this->updates());
+ }
- $view = new View('admin/dashboard/user_info');
- $view->user = $this->a1->get_user();
- $view->ip = isset($_SERVER['HTTP_X_FORWARD_FOR'])
- ? $_SERVER['HTTP_X_FORWARD_FOR']
- : $_SERVER['REMOTE_ADDR'];
- $this->template->content = $view;
+ /**
+ * Display current user information
+ */
+ private function user_info() {
+ return View::factory('admin/dashboard/user_info')
+ ->set('user', $this->a2->get_user())
+ ->set('ip', Request::$client_ip);
}
- public function action_system_info() {
- if ( ! $this->internal_request)
+ /**
+ * Display system information
+ */
+ private function system_info() {
+ $view = View::factory('admin/dashboard/system_info')
+ ->bind('apache_version', $apache_version)
+ ->bind('php_version', $php_version)
+ ->bind('mod_ssl_version', $mod_ssl_version)
+ ->bind('openssl_version', $openssl_version)
+ ->bind('dav_version', $dav_version)
+ ->bind('mysql_version', $mysql_version)
+ ->bind('app_version', $app_version)
+ ->set('kohana_version', Kohana::VERSION);
+
+ $app_version = defined('APP_VERSION') ? APP_VERSION : '0.1';
+
+ try
{
- Request::instance()->redirect( Route::get('admin_main')->uri() );
+ Database::instance()->connect();
+ $mysql_version = mysql_get_server_info();
+ $mysql_version = $mysql_version ? $mysql_version : 'unavailable';
+ }
+ catch (Database_Exception $e)
+ {
+ $view->mysql_version = 'unavailable';
}
-
- $view = new View('admin/dashboard/system_info');
$sw = preg_split("/[\/ ]/", $_SERVER['SERVER_SOFTWARE']);
for ($i=0; $i<count($sw); $i++)
@@ -46,43 +80,35 @@ public function action_system_info() {
{
case 'APACHE':
$i++;
- $view->apache_version = $sw[$i];
+ $apache_version = $sw[$i];
break;
case 'PHP':
$i++;
- $view->php_version = $sw[$i];
+ $php_version = $sw[$i];
break;
case 'MOD_SSL':
$i++;
- $view->mod_ssl_version = $sw[$i];
+ $mod_ssl_version = $sw[$i];
break;
case 'OPENSSL':
$i++;
- $view->openssl_version = $sw[$i];
+ $openssl_version = $sw[$i];
break;
case 'DAV':
$i++;
- $view->dav_version = $sw[$i];
+ $dav_version = $sw[$i];
break;
}
}
- $mysql_version = mysql_get_server_info();
- $view->mysql_version = $mysql_version ? $mysql_version : 'unavailable';
- $view->app_version = defined('APP_VERSION') ? APP_VERSION : '0.1';
- $view->kohana_version = Kohana::VERSION;
-
- $this->template->content = $view;
+ return $view;
}
- public function action_updates() {
- if ( ! $this->internal_request)
- {
- Request::instance()->redirect( Route::get('admin_main')->uri() );
- }
-
- $view = new View('admin/updates');
- $this->template->content = $view;
+ /**
+ * Show recent updates
+ */
+ private function updates() {
+ return View::factory('admin/updates');
}
}
View
1  classes/controller/admin/media.php
@@ -4,6 +4,7 @@
* Admin media controller
*
* @package Admin
+ * @category Controller
* @author Kyle Treubig
* @copyright (c) 2010 Kyle Treubig
* @license MIT
View
46 classes/controller/admin/support.php
@@ -1,46 +0,0 @@
-<?php defined('SYSPATH') OR die('No direct script access.');
-
-/**
- * @package Controller
- * @author Kyle Treubig
- * @copyright (c) 2010 Kyle Treubig
- * @license MIT
- */
-class Controller_Admin_Support extends Controller_Template_Admin {
-
- /**
- * Register controller as an admin controller
- */
- public function before() {
- parent::before();
- }
-
- /**
- * Display support menu
- */
- public function action_menu() {
- if ( ! $this->internal_request)
- {
- Request::instance()->redirect(Route::get('admin_main')->uri());
- }
- $this->template->content = new View('admin/support/widget/menu');
- }
-
- /**
- * Create a bug report
- */
- public function action_bug() {
- Message::instance()->info('Bug report functionality is coming in a future version.');
- Request::instance()->redirect( Route::get('admin_main')->uri() );
- }
-
- /**
- * Open a support ticket
- */
- public function action_contact() {
- Message::instance()->info('Support ticket functionality is coming in a future version.');
- Request::instance()->redirect( Route::get('admin_main')->uri() );
- }
-
-}
-
View
408 classes/controller/admin/users.php
@@ -1,47 +1,61 @@
<?php defined('SYSPATH') OR die('No direct script access.');
/**
- * @package Controller
+ * @package Admin
+ * @category Controller
* @author Kyle Treubig
* @copyright (c) 2010 Kyle Treubig
* @license MIT
*/
-class Controller_Admin_Users extends Controller_Template_Admin {
+class Controller_Admin_Users extends Controller_Admin {
- /**
- * Register controller as an admin controller
- */
- public function before() {
- parent::before();
+ protected $_resource = 'user';
- $this->restrict('user', 'manage');
- unset($this->template->menu->menu['Users'][0]);
- }
+ protected $_acl_map = array(
+ 'view' => 'view',
+ 'new' => 'create',
+ 'edit' => 'edit',
+ 'delete' => 'delete',
+ 'default' => 'manage',
+ );
- /**
- * Default action to list
- */
- public function action_index() {
- $this->action_list();
- }
+ protected $_acl_required = 'all';
+
+ protected $_view_map = array(
+ 'new' => 'admin/layout/narrow_column_with_menu',
+ 'edit' => 'admin/layout/narrow_column_with_menu',
+ 'default' => 'admin/layout/wide_column_with_menu',
+ );
+
+ protected $_resource_required = array('view', 'edit', 'delete');
+
+ protected $_current_nav = 'admin/users';
/**
* Generate menu for user management
*/
- private function menu() {
+ protected function _menu() {
return View::factory('admin/users/menu');
}
/**
- * Display menu for user management
+ * Load a specified user
*/
- public function action_menu() {
- if ( ! $this->internal_request)
+ protected function _load_resource() {
+ $id = $this->request->param('id', 0);
+ $this->_resource = Sprig::factory('user', array('id'=>$id))->load();
+ if ( ! $this->_resource->loaded())
{
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
+ throw new Kohana_Exception('That user does not exist.', NULL, 404);
}
+ }
- $this->template->content = $this->menu();
+ /**
+ * Redirect index action to list
+ */
+ public function action_index() {
+ $this->request->redirect( $this->request->uri(
+ array('action' => 'list')), 301);
}
/**
@@ -49,46 +63,9 @@ public function action_menu() {
*/
public function action_list() {
Kohana::$log->add(Kohana::DEBUG, 'Executing Controller_Users::action_list');
-
+ $this->template->content = View::factory('admin/users/list')
+ ->bind('users', $users);
$users = Sprig::factory('user')->load(NULL, FALSE);
-
- // Check if there are any users to display
- if (count($users) == 0)
- {
- $hmvc = View::factory('admin/users/hmvc/none');
-
- $view = View::factory('admin/users/list')
- ->set('menu', $this->menu())
- ->set('list', $hmvc);
-
- $this->template->content = $this->internal_request ? $hmvc : $view;
- return;
- }
-
- // Create user list
- $grid = new Grid;
- $grid->column()->field('id')->title('ID');
- $grid->column('action')->title('Username')->text('{username}')
- ->route(Route::get('admin_main'))->params(array('controller'=>'users', 'action'=>'view'));
- $grid->column()->field('role')->title('Role');
- $grid->column()->field('email')->title('Email');
- $grid->column('action')->title('Actions')->text('Edit')->class('edit')
- ->route(Route::get('admin_main'))->params(array('controller'=>'users', 'action'=>'edit'));
- $grid->column('action')->title('')->text('Delete')->class('delete')
- ->route(Route::get('admin_main'))->params(array('controller'=>'users', 'action'=>'delete'));
- $grid->data($users);
-
- // Setup HMVC view with data
- $hmvc = View::factory('admin/users/hmvc/list')
- ->set('grid', $grid);
-
- // Setup template view
- $view = View::factory('admin/users/list')
- ->set('menu', $this->menu())
- ->set('list', $hmvc);
-
- // Set request response
- $this->template->content = $this->internal_request ? $hmvc : $view;
}
/**
@@ -96,57 +73,8 @@ public function action_list() {
*/
public function action_view() {
Kohana::$log->add(Kohana::DEBUG, 'Executing Controller_Users::action_view');
-
- $id = Request::instance()->param('id');
- $user = Sprig::factory('user', array('id'=>$id))->load();
-
- // If user is invalid, return to list
- if ( ! $user->loaded())
- {
- $message = __('That user does not exist.');
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
-
- // Restrict access
- if ( ! $this->a2->allowed($user, 'view'))
- {
- $message = __('You do not have permission to view :name\'s details.', array(':name'=>$user->username));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
-
- // Setup HMVC view with data
- $hmvc = View::factory('admin/users/hmvc/view')
- ->set('user', $user);
-
- // Setup template view
- $view = View::factory('admin/users/view')
- ->set('menu', $this->menu())
- ->set('details', $hmvc);
-
- // Set request response
- $this->template->content = $this->internal_request ? $hmvc : $view;
+ $this->template->content = View::factory('admin/users/view')
+ ->bind('user', $this->_resource);
}
/**
@@ -154,61 +82,31 @@ public function action_view() {
*/
public function action_new() {
Kohana::$log->add(Kohana::DEBUG, 'Executing Controller_Users::action_new');
-
- // Restrict access
- if ( ! $this->a2->allowed('user', 'create'))
- {
- $message = __('You do not have permission to create new users.');
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
+ $this->template->content = View::factory('admin/users/form')
+ ->set('legend', __('Create User'))
+ ->set('submit', __('Create'))
+ ->bind('user', $user)
+ ->bind('errors', $errors);
$user = Sprig::factory('user')->values($_POST);
- try
+ if ($_POST)
{
- $user->create();
- $message = __('The user, :name, has been created.', array(':name'=>$user->username));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
+ try
{
- $this->template->content = $message;
+ $user->create();
+
+ Message::instance()->info('The user, :name, has been created.',
+ array(':name' => $user->username));
+
+ if ( ! $this->_internal)
+ $this->request->redirect( $this->request->uri(array('action'=>'list')) );
}
- // Else set flash message and redirect
- else
+ catch (Validate_Exception $e)
{
- Message::instance()->info($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
+ $errors = $e->array->errors('admin');
}
}
- catch (Validate_Exception $e)
- {
- // Setup HMVC view with data
- $hmvc = View::factory('admin/users/hmvc/form')
- ->set('legend', __('Create User'))
- ->set('submit', __('Create'))
- ->set('user', $user)
- ->set('errors', count($_POST) ? $e->array->errors('admin') : array() );
-
- // Setup template view
- $view = View::factory('admin/users/form')
- ->set('menu', $this->menu())
- ->set('form', $hmvc);
-
- // Set request response
- $this->template->content = $this->internal_request ? $hmvc : $view;
- }
}
/**
@@ -216,45 +114,14 @@ public function action_new() {
*/
public function action_edit() {
Kohana::$log->add(Kohana::DEBUG, 'Executing Controller_Users::action_edit');
+ $this->template->content = View::factory('admin/users/form')
+ ->set('legend', __('Modify User'))
+ ->set('submit', __('Save'))
+ ->bind('user', $this->_resource)
+ ->bind('errors', $errors);
- $id = Request::instance()->param('id');
- $user = Sprig::factory('user', array('id'=>$id))->load();
-
- // If user is invalid, return to list
- if ( ! $user->loaded())
- {
- $message = __('That user does not exist.');
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
-
- // Restrict access
- if ( ! $this->a2->allowed($user, 'edit'))
- {
- $message = __('You do not have permission to modify :name.', array(':name'=>$user->username));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
+ // Bind locally
+ $user = & $this->_resource;
// Restrict promotion (change in role)
if ( ! $this->a2->allowed($user, 'promote'))
@@ -275,46 +142,25 @@ public function action_edit() {
unset($_POST['password_confirm']);
}
- $user->values($_POST);
-
- // Setup HMVC view with data
- $hmvc = View::factory('admin/users/hmvc/form')
- ->set('legend', __('Modify User'))
- ->set('submit', __('Save'))
- ->set('user', $user);
-
- if (count($_POST))
+ if ($_POST)
{
+ $user->values($_POST);
+
try
{
$user->update();
- $message = __('The user, :name, has been modified.', array(':name'=>$user->username));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->info($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
+
+ Message::instance()->info('The user, :name, has been modified.',
+ array(':name' => $user->username));
+
+ if ( ! $this->_internal)
+ $this->request->redirect( $this->request->uri(array('action'=>'list')) );
}
catch (Validate_Exception $e)
{
- $hmvc->errors = count($_POST) ? $e->array->errors('admin') : array();
+ $errors = $e->array->errors('admin');
}
}
-
- // Setup template view
- $view = View::factory('admin/users/form')
- ->set('menu', $this->menu())
- ->set('form', $hmvc);
-
- // Set request response
- $this->template->content = $this->internal_request ? $hmvc : $view;
}
/**
@@ -327,18 +173,15 @@ public function action_profile() {
if ($user !== FALSE)
{
- Request::instance()->redirect( Route::get('admin_main')
- ->uri(array(
- 'controller' => 'users',
- 'action' => 'edit',
- 'id' => $user->id,
- ))
- );
+ $this->request->redirect( $this->request->uri(array(
+ 'action' => 'edit',
+ 'id' => $user->id,
+ )) );
}
else
{
Message::instance()->error('You must be logged in to do that.');
- Request::instance()->redirect( Route::get('admin_auth')
+ $this->request->redirect( Route::get('admin/auth')
->uri(array('action'=>'login'))
);
}
@@ -352,49 +195,14 @@ public function action_delete() {
// If deletion is not desired, redirect to list
if (isset($_POST['no']))
- {
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
-
- $id = Request::instance()->param('id');
- $user = Sprig::factory('user', array('id'=>$id))->load();
- $name = $user->username;
+ $this->request->redirect( $this->request->uri(array('action'=>'list')) );
- // If user is invalid, return to list
- if ( ! $user->loaded())
- {
- $message = __('That user does not exist.');
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
+ $this->template->content = View::factory('admin/users/delete')
+ ->bind('user', $this->_resource);
- // Restrict access
- if ( ! $this->a2->allowed($user, 'delete'))
- {
- $message = __('You do not have permission to delete :name.', array(':name'=>$name));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
- }
+ // Bind locally
+ $user = & $this->_resource;
+ $name = $user->username;
// If deletion is confirmed
if (isset($_POST['yes']))
@@ -402,50 +210,22 @@ public function action_delete() {
try
{
$user->delete();
- $message = __('The user, :name, has been deleted.', array(':name'=>$name));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->info($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
+ Message::instance()->info('The user, :name, has been deleted.',
+ array(':name' => $name));
+
+ if ( ! $this->_internal)
+ $this->request->redirect( $this->request->uri(array('action'=>'list')) );
}
catch (Exception $e)
{
Kohana::$log->add(Kohana::ERROR, 'Error occured deleting user, id='.$user->id.', '.$e->getMessage());
- $message = __('An error occured deleting user, :name.', array(':name'=>$name));
-
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = $message;
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error($message);
- Request::instance()->redirect( Route::get('admin_main')->uri(array('controller'=>'users')) );
- }
+ Message::instance()->error('An error occured deleting user, :name.',
+ array(':name' => $name));
+
+ if ( ! $this->_internal)
+ $this->request->redirect( $this->request->uri(array('action'=>'list')) );
}
}
-
- // Setup HMVC view with data
- $hmvc = View::factory('admin/users/hmvc/delete')
- ->set('user', $user);
-
- // Setup template view
- $view = View::factory('admin/users/delete')
- ->set('menu', $this->menu())
- ->set('confirm', $hmvc);
-
- // Set request response
- $this->template->content = $this->internal_request ? $hmvc : $view;
}
} // End of Controller_Admin_Users
View
106 classes/controller/template/admin.php
@@ -1,7 +1,10 @@
-<?php defined('SYSPATH') OR die('No direct script access.');
+<?php defined('SYSPATH') or die('No direct script access.');
/**
+ * Admin Template Controller
+ *
* @package Admin
+ * @category Base
* @author Kyle Treubig
* @copyright (c) 2010 Kyle Treubig
* @license MIT
@@ -19,9 +22,9 @@
protected $_config;
/**
- * @var Internal request
+ * @var Current navigation item
*/
- protected $internal_request = FALSE;
+ protected $_current_nav = NULL;
/**
* Configure admin controller
@@ -32,17 +35,6 @@ public function before() {
// Load admin config
$this->_config = Kohana::config('admin');
- // Set common variables
- $this->a2 = A2::instance('auth');
- $this->a1 = $this->a2->a1;
- $this->session = Session::instance();
-
- // Check if internal request
- if ($this->request !== Request::instance() OR Request::$is_ajax)
- {
- $this->internal_request = TRUE;
- }
-
if ($this->auto_render)
{
// Prepare templates
@@ -50,99 +42,29 @@ public function before() {
$this->template->header = View::factory($this->_config['template'].'/header');
$this->template->menu = View::factory($this->_config['template'].'/menu');
$this->template->footer = View::factory($this->_config['template'].'/footer');
+ $this->template->content = '';
// Bind menu items
- $this->template->menu->bind('menu', $this->_config['menu']);
+ $this->template->menu->bind('links', $this->_config['menu']);
// Prepare media arrays
- $this->template->styles = array();
- $this->template->scripts = array();
+ $this->template->set_global('styles', array());
+ $this->template->set_global('scripts', array());
}
}
/**
- * Perform pre-render actions on admin controller
+ * Unset current navigation item
*/
public function after() {
- if ($this->auto_render)
+ $key = array_search($this->_current_nav, $this->_config['menu']);
+ if ($key)
{
- $styles = array();
- $scripts = array();
-
- $this->template->header->styles = array_merge($this->template->styles, $styles);
- $this->template->header->scripts = array_merge($this->template->scripts, $scripts);
- }
-
- if ($this->internal_request)
- {
- $content = $this->template->content;
- $this->template = $content;
+ $this->_config['menu'][$key] = NULL;
}
parent::after();
}
- /**
- * Perform an ACL check against a resource and privilege.
- * <ul>
- * <li>If the current user is not allowed access, redirect
- * to the main page.</li>
- * <li>If the current user is not logged in, redirect to
- * the login page, setting the referrer url.</li>
- * </ul>
- *
- * @param string An ACL resource
- * @param string Privilege on the resource
- * @param string [optional] error message string
- * @param string Redirect URL
- */
- protected function restrict($resource=NULL, $privilege=NULL) {
- if ( ! $this->a2->allowed($resource, $privilege))
- {
- if ($this->a2->get_user() === FALSE)
- {
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = __('You must be logged in to do that.');
- }
- // Else set flash message and redirect
- else
- {
- $this->session->set('referrer', Request::instance()->uri);
- Message::instance()->error('You must be logged in to do that.');
- Request::instance()->redirect( Route::get('admin_auth')->uri(array('action'=>'login')) );
- }
- }
- else
- {
- // Return message if an ajax request
- if (Request::$is_ajax)
- {
- $this->template->content = __('You do not have permission to do that.');
- }
- // Else set flash message and redirect
- else
- {
- Message::instance()->error('You do not have permission to do that.');
- Request::instance()->redirect( Route::get('admin_main')->uri() );
- }
- }
- }
- }
-
- /**
- * Add items to the admin menu template
- *
- * @param string the menu item key
- * @param string an array for the menu item
- */
- protected function add_menu($key, $menu) {
- if (array_key_exists($key, $this->_config['menu']))
- {
- $this->_config['menu'][$key][1] = $menu;
- }
- }
-
} // End of Controller_Template_Admin
View
5 classes/message/core.php → classes/kohana/message.php
@@ -3,12 +3,13 @@
/**
* Flash message handler
*
- * @package Message
+ * @package Kohana
+ * @category Base
* @author Kyle Treubig
* @copyright (c) 2010 Kyle Treubig
* @license MIT
*/
-abstract class Message_Core {
+abstract class Kohana_Message {
/** Config */
private $_config;
View
2  classes/message.php
@@ -1,3 +1,3 @@
<?php defined('SYSPATH') OR die('No direct script access.');
-class Message extends Message_Core { }
+class Message extends Kohana_Message { }
View
46 config/a1.php
@@ -1,46 +0,0 @@
-<?php
-
-return array(
-
- /**
- * Type of hash to use for passwords. Any algorithm supported by the hash function
- * can be used here. Note that the length of your password is determined by the
- * hash type + the number of salt characters.
- * @see http://php.net/hash
- * @see http://php.net/hash_algos
- */
- 'hash_method' => 'sha1',
-
- /**
- * Defines the hash offsets to insert the salt at. The password hash length
- * will be increased by the total number of offsets.
- */
- 'salt_pattern' => '3, 6, 9, 10, 11, 20, 22, 25, 28, 30',
-
- /**
- * Set the auto-login (remember me) cookie lifetime, in seconds. The default
- * lifetime is two weeks.
- */
- 'lifetime' => 1209600,
-
- /**
- * User model
- */
- 'user_model' => 'user',
-
- /**
- * Table column names
- */
- 'columns' => array(
- 'username' => 'username', //username
- 'password' => 'password', //password
- 'token' => 'token', //token
- 'last_login'=> 'last_login', //last login (optional)
- 'logins' => 'logins' //login count (optional)
- ),
-
- /**
- * Session type - native or database
- */
- 'session_type' => 'native'
-);
View
15 config/admin-example.php
@@ -1,15 +0,0 @@
-<?php defined('SYSPATH') OR die('No direct script access.');
-
-return array(
- // Admin template folder path
- 'template' => 'admin/themes/tpd',
-
- // Admin menu hierarchy array
- 'menu' => array(
- 'Home' => array('admin/main'),
- 'Users' => array('admin/users'),
- 'Logout' => array('admin/logout'),
- ),
-
-);
-
View
17 config/admin.php
@@ -0,0 +1,17 @@
+<?php defined('SYSPATH') OR die('No direct script access.');
+
+return array(
+ // Admin template folder path
+ 'template' => 'admin/themes/default',
+
+ // Admin menu links
+ 'menu' => array(
+ /*
+ 'Home' => 'admin',
+ 'Users' => 'admin/users',
+ 'Logout' => 'admin/logout',
+ */
+ ),
+
+);
+
View
30 config/auth-example.php → config/auth.php
@@ -27,8 +27,10 @@
*/
'roles' => array
(
+ /*
'user' => 'guest',
'admin' => 'user'
+ */
),
/*
@@ -43,9 +45,9 @@
*/
'resources' => array
(
- 'page' => NULL,
- 'asset' => NULL,
+ /*
'user' => NULL,
+ */
),
/*
@@ -62,12 +64,6 @@
'allow' => array
(
/*
- 'acl_disable' => array(
- 'role' => NULL,
- 'resource' => NULL,
- 'privilege' => NULL,
- ),
- */
'user_management' => array(
'role' => 'user',
'resource' => 'user',
@@ -84,24 +80,11 @@
'resource' => 'user',
'privilege' => NULL,
),
- 'page_management' => array(
- 'role' => 'admin',
- 'resource' => 'page',
- 'privilege' => NULL,
- ),
- 'asset_management' => array(
- 'role' => 'admin',
- 'resource' => 'asset',
- 'privilege' => NULL,
- ),
- 'blog_management' => array(
- 'role' => 'admin',
- 'resource' => 'blog',
- 'privilege' => NULL,
- ),
+ */
),
'deny' => array
(
+ /*
'user_promotion' => array(
'role' => 'admin',
'resource' => 'user',
@@ -114,6 +97,7 @@
'privilege' => 'delete',
'assertion' => array('Acl_Assert_Argument', array('id'=>'id')),
),
+ */
)
)
);
View
43 guide/admin.acl.md
@@ -0,0 +1,43 @@
+# The Admin Framework - Access Control
+
+The admin module also provides a framework for creating administration pages.
+The abstract base admin controller, `Controller_Admin`, may be extended to make
+use of the template and other common functions. The common functions provided
+by the base admin controller are ACL checking (using Wouter's A2 library) and
+request handling (differentiating between main/external requests and ajax/internal
+requests).
+
+## Access Control
+
+The base admin controller will perform an ACL check using Wouter's A2 library in the
+`before()` method if the given action is defined in the protected variable,
+`$this->_acl_required`. The resource to check against is the value of the protected
+`$this->_resource` variable (either the default string or the loaded resource).
+The privilege to check against is the value derived from the request action to ACL
+privilege array in the protected variable `$this->_acl_map`. For example,
+
+ protected $_resource = 'user';
+ protected $_acl_required = array('list', 'edit', 'delete');
+ protected $_acl_map = array(
+ 'list' => 'view',
+ 'edit' => 'edit',
+ 'delete' => 'edit',
+ 'default' => 'view',
+ );
+
+Will check if the current user is allowed...
+
+ - "view" privilege on a "user" resource when accessing action_list
+ - "edit" privilege on a "user" resource when accessing action_edit
+ - "edit" privilege on a "user" resource when accessing action_delete
+ - "view" privilege on a "user" resource for everything else
+
+If no mapping is found, the default mapping will be used.
+
+If the user is not allowed the specified privilege on the resource, the base
+admin controller will redirect to
+
+ - a login page if the user is not logged in already
+ - the default method of the current controller
+ - or the admin home page if the user cannot access the default method of the current controller (controller-level access denied)
+
View
19 guide/admin.dependencies.md
@@ -0,0 +1,19 @@
+# Dependencies
+
+The admin module depends on the following modules
+
+ - The official [Database module](http://github.com/kohana/database)
+ - Wouter's [A2](http://github.com/Wouterrr/A2) and
+ [ACL](http://github.com/Wouterrr/ACL) modules (for authorization)
+
+Out of the box, the admin module depends on the following modules, but for
+features that are "customizable"
+
+ - Wouter's [A1 module](http://github.com/Wouterrr/A1) (for authentication)
+ - My [Sentry module](http://github.com/vimofthevine/sentry) (modifies A1 to be Sprig-compatible)
+ - Shadowhand's [Sprig module](http://github.com/shadowhand/sprig) (for user management)
+ - My [Grid module](http://github.com/vimofthevine/grid) (for user management)
+
+**Note:** Future versions will have support for ORM, Jelly, and Sprig. This will
+eliminate the dependencies on A1/Sentry and Sprig. At that point, any authentication
+library compatible with A2 will suffice.
View
33 guide/admin.layout.md
@@ -0,0 +1,33 @@
+# The Admin Framework - Layout Integration
+
+The admin module also provides a framework for creating administration pages.
+The abstract base admin controller, `Controller_Admin`, may be extended to make
+use of the template and other common functions. The common functions provided
+by the base admin controller are ACL checking (using Wouter's A2 library) and
+request handling (differentiating between main/external requests and ajax/internal
+requests).
+
+## Request Handling and Layout Integration
+
+Methods of admin controllers should create a view with minimal HTML and no concern
+for the 960 grid used by the admin template. This view should be assigned to
+`$this->template->content`. The `after()` method of the base admin controller will
+insert the view in `$this->template->content` into a pre-defined layout view, which
+integrates with the 960 CSS grid.
+
+The layout view to use for each admin controller's methods can be defined in the
+protected variable `$this->_view_map`. Custom layout views may be created and used.
+The base admin controller will set the `menu` and `content` variables for each layout
+view. The default map will be used if no mapping is defined. For example,
+
+ protected $_view_map = array(
+ 'list' => 'admin/layout/narrow_column_with_menu',
+ 'edit' => 'admin/layout/wide_column_with_menu',
+ 'history' => 'admin/layout/custom_layout',
+ 'default' => 'admin/layout/narrow_column',
+ );
+
+Admin controllers may define a private `_menu()` function to create a custom
+sidebar-style menu which will be included with any layouts ending in "_with_menu".
+The `_menu()` function should return either a string or View object.
+
View
13 guide/admin.overview.md
@@ -0,0 +1,13 @@
+# Admin Overview
+
+The admin module is meant to facilitate the rapid development of an end-user
+administration site. There are essentially two aspects provided by the module,
+the template and the framework.
+
+## Features
+ - Template integration, courtesy of Colonel-Rosa
+ - Resource handling
+ - Access control
+ - Automated differentiation between external requests (full layout)
+ and internal requests (partial layout)
+
View
40 guide/admin.resources.md
@@ -0,0 +1,40 @@
+# The Admin Framework - Loading Resources
+
+The admin module also provides a framework for creating administration pages.
+The abstract base admin controller, `Controller_Admin`, may be extended to make
+use of the template and other common functions. The common functions provided
+by the base admin controller are ACL checking (using Wouter's A2 library) and
+request handling (differentiating between main/external requests and ajax/internal
+requests).
+
+## Loading Resources
+
+As many back-end CRUD functions require a specific resource (object, database record, etc.)
+to be specified and loaded, the base admin controller provides a hook for loading resources.
+Additionally, the A2 authorization library allows object-level access, thus the loading
+of a resource allows the A2 library to perform an ACL check on the loaded object.
+
+Controllers can define the protected variable `$this->_resource_required` to trigger the
+execution of a private function, `_load_resource()` in the `before()` method.
+`$this->_resource_required` should be an array of request actions which require a specific
+resource to be loaded. The `_load_resource()` function should store the loaded resource
+in the protected variable `$this->_resource`. For example,
+
+ protected $_resource = 'user'; // default string value
+ protected $_resource_required = array('edit', 'delete'); // edit and delete actions require a specific user to be loaded
+
+ private function _load_resource() {
+ $id = $this->request->param('id', 0);
+ if ($id === 0) return;
+
+ $this->_resource = Sprig::factory('user', array('id' => $id))->load();
+
+ if ( ! $this->_resource->loaded())
+ {
+ throw new Kohana_Exception('That user does not exist.', NULL, 404);
+ }
+ }
+
+If a 404 exception is thrown, the base admin controller will set an error message
+with the exception message, and redirect to the default method of the current controller.
+
View
25 guide/admin.template.md
@@ -0,0 +1,25 @@
+# The Admin Template
+
+The front-end style used for the admin site is the admin template created by
+[Colonel-Rosa](http://github.com/ThePixelDeveloper/Admin-Template). All controllers
+extending the `Controller_Template_Admin` class should put their views in
+`$this->template->content`. Colonel-Rosa used the 960 CSS grid, so the contents of
+`$this->template->content` should contain the appropriate 960 grid classes (ie,
+`<div class="grid_8">`).
+
+The only configurable aspect of the template is the main navigation. The config file,
+`admin.php`, should be modified to specifiy the navigation menu.
+
+ // admin.php example
+ return array(
+ 'menu' => array(
+ 'Home' => 'admin/main',
+ 'Display text' => 'url',
+ ),
+ );
+
+A controller may designate any of the links in the navigation as the active page by
+including the following line, replacing "Display text" with the appropriate value.
+
+ $this->_config['menu']['Display text'] = NULL;
+
View
8 guide/menu.admin.md
@@ -0,0 +1,8 @@
+1. **Admin**
+ - [Overview](admin.overview)
+ - [The Template](admin.template)
+ - [Working with Resources](admin.resources)
+ - [Access Control](admin.acl)
+ - [Layout Integration](admin.layout)
+ - [Dependencies](admin.dependencies)
+
View
32 init.php
@@ -1,14 +1,15 @@
<?php defined('SYSPATH') or die('No direct script access.');
-Route::set('admin_auth', 'admin/<action>', array(
+Route::set('admin/auth', 'admin/<action>', array(
'action' => 'login|logout',
))
->defaults(array(
'directory' => 'admin',
'controller' => 'auth',
+ 'action' => 'login',
));
-Route::set('admin_media', 'admin/media(/<file>)', array('file'=>'.+'))
+Route::set('admin/media', 'admin/media(/<file>)', array('file'=>'.+'))
->defaults(array(
'directory' => 'admin',
'controller' => 'media',
@@ -16,35 +17,10 @@
'file' => NULL,
));
-Route::set('admin_main', 'admin(/<controller>(/<action>(/<id>)))')
+Route::set('admin', 'admin(/<controller>(/<action>(/<id>)))')
->defaults(array(
'directory' => 'admin',
'controller' => 'main',
'action' => 'index',
));
-// Static file serving (CSS, JS, images)
-//Route::set('docs/media', 'guide/media(/<file>)', array('file' => '.+'))
- //->defaults(array(
- //'controller' => 'userguide',
- //'action' => 'media',
- //'file' => NULL,
- //));
-
-// API Browser
-//Route::set('docs/api', 'guide/api(/<class>)', array('class' => '[a-zA-Z0-9_]+'))
- //->defaults(array(
- //'controller' => 'userguide',
- //'action' => 'api',
- //'class' => NULL,
- //));
-
-// Translated user guide
-//Route::set('docs/guide', 'guide(/<page>)', array(
- //'page' => '.+',
- //))
- //->defaults(array(
- //'controller' => 'userguide',
- //'action' => 'docs',
- //));
-
View
21 messages/a2.php
@@ -0,0 +1,21 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+return array(
+ // Authentication messages
+ 'login' => array(
+ 'already' => 'You are already logged in.',
+ 'required' => 'You must be logged in to do that.',
+ 'success' => 'Welcome back, :name!',
+ ),
+ 'logout' => array(
+ 'success' => 'You have been logged out. Goodbye!',
+ ),
+ // Resource=>privilege denial messages
+ 'user' => array(
+ 'view' => 'You do not have permission to view :resource\'s details.',
+ 'create' => 'You do not have permission to create new users.',
+ 'edit' => 'You do not have permission to modify :resource.',
+ 'delete' => 'You do not have permission to delete :resource.',
+ 'manage' => 'You do not have permission to manage users.',
+ ),
+);
View
16 messages/admin.php
@@ -0,0 +1,16 @@
+<?php defined('SYSPATH') or die('No direct script access.');
+
+return array(
+ 'email' => array(
+ 'email' => 'You must specify a valid email address.',
+ 'unique' => 'That email is already registered. Please use a different email address.',
+ ),
+ 'password' => array(
+ 'incorrect' => 'The password provided is incorrect.',
+ ),
+ 'username' => array(
+ 'not_found' => 'The username provided is incorrect.',
+ 'username_available' => 'That username is already registered. Please choose another.',
+ ),
+);
+
View
10 messages/auth.php
@@ -1,10 +0,0 @@
-<?php defined('SYSPATH') or die('No direct script access.');
-
-return array(
- 'username' => array(
- 'not_found' => 'The username is incorrect',
- ),
- 'password' => array(
- 'incorrect' => 'The password is incorrect',
- ),
-);
View
26 views/admin/auth/hmvc/login.php
@@ -1,26 +0,0 @@
-<h2>Login</h2>
-<?php echo Form::open(); ?>
-
-<?php echo empty($errors['username']) ? '' : '<p class="error">'.$errors['username'].'</p>'; ?>
-<p>
- <?php echo Form::label('username', 'Username'); ?>
- <?php echo Form::input('username', $form['username']); ?>
-</p>
-
-<?php echo empty($errors['password']) ? '' : '<p class="error">'.$errors['password'].'</p>'.PHP_EOL; ?>
-<p>
- <?php echo Form::label('password', 'Password'); ?>
- <?php echo Form::password('password', $form['password']), PHP_EOL; ?>
-</p>
-
-<?php echo empty($errors['remember']) ? '' : '<p class="error">'.$errors['remember'].'</p>'.PHP_EOL; ?>
-<p>
- <?php echo Form::label('remember', 'Remember Me'); ?>
- <?php echo Form::checkbox('remember', 'true', (bool) $form['remember']); ?>
-</p>
-
-<p class="submit">
- <?php echo Form::submit('submit', 'Login'); ?>
-</p>
-
-<?php echo Form::close(); ?>
View
31 views/admin/auth/login.php
@@ -1,5 +1,26 @@
-<div class="grid_4">&nbsp;</div>
-<div class="grid_8">
-<?php echo $form ?>
-</div>
-<div class="grid_4">&nbsp;</div>
+<h2>Login</h2>
+<?php echo Form::open(); ?>
+
+<?php echo isset($errors['username']) ? '<p class="error">'.$errors['username'].'</p>' : NULL ?>
+<p>
+ <?php echo Form::label('username', 'Username'); ?>
+ <?php echo Form::input('username', $post['username']); ?>
+</p>
+
+<?php echo isset($errors['password']) ? '<p class="error">'.$errors['password'].'</p>'.PHP_EOL : NULL ?>
+<p>
+ <?php echo Form::label('password', 'Password'); ?>
+ <?php echo Form::password('password', $post['password']), PHP_EOL; ?>
+</p>
+
+<?php echo isset($errors['remember']) ? '<p class="error">'.$errors['remember'].'</p>'.PHP_EOL : NULL ?>
+<p>
+ <?php echo Form::label('remember', 'Remember Me'); ?>
+ <?php echo Form::checkbox('remember', 'true'); ?>
+</p>
+
+<p class="submit">
+ <?php echo Form::submit('submit', 'Login'); ?>
+</p>
+
+<?php echo Form::close(); ?>
View
32 views/admin/dashboard.php
@@ -1,44 +1,18 @@
<div class="grid_5">
<div class="box">
-<?php
- $url = Route::get('admin_main')->uri(array('action' => 'user_info'));
- echo Request::factory($url)->execute()->response;
-?>
- </div>
- <div class="box">
-<?php
- $url = Route::get('admin_main')->uri(array('action' => 'system_info'));
- echo Request::factory($url)->execute()->response;
-?>
+ <?php echo $user_info ?>
</div>
</div>
<div class="grid_6">
<div class="box">
-<?php
- $url = Route::get('admin_main')->uri(array('action' => 'updates'));
- echo Request::factory($url)->execute()->response;
-?>
- </div>
- <div class="box">
-<?php
- $url = Route::get('admin_main')->uri(array(
- 'controller' => 'page',
- 'action' => 'list_widget'));
- echo Request::factory($url)->execute()->response;
-?>
+ <?php echo $system_info ?>
</div>
</div>
<div class="grid_5">
<div class="box">
-<?php
- $url = Route::get('admin_main')->uri(array(
- 'controller' => 'support',
- 'action' => 'menu',
- ));
- echo Request::factory($url)->execute()->response;
-?>
+ <?php echo $updates ?>
</div>
</div>
View
3 