diff --git a/classes/Controller/TemplateDefault.php b/classes/Controller/TemplateDefault.php new file mode 100644 index 0000000..ec90f96 --- /dev/null +++ b/classes/Controller/TemplateDefault.php @@ -0,0 +1,4 @@ + diff --git a/classes/Request.php b/classes/Request.php new file mode 100644 index 0000000..a7eedf9 --- /dev/null +++ b/classes/Request.php @@ -0,0 +1,4 @@ + diff --git a/classes/lnApp/Controller/TemplateDefault.php b/classes/lnApp/Controller/TemplateDefault.php index b726431..cfd9fe9 100644 --- a/classes/lnApp/Controller/TemplateDefault.php +++ b/classes/lnApp/Controller/TemplateDefault.php @@ -35,6 +35,9 @@ abstract class lnApp_Controller_TemplateDefault extends Kohana_Controller_Templa */ protected $secure_actions = array(); + // Our acccount object + protected $ao; + public function __construct(Request $request, Response $response) { if (Config::theme()) $this->template = Config::theme().'/page'; @@ -69,6 +72,16 @@ abstract class lnApp_Controller_TemplateDefault extends Kohana_Controller_Templa * @uses meta */ public function before() { + if ($this->auth_required) { + if (! count($this->secure_actions) OR (! isset($this->secure_actions[Request::current()->action()]))) + throw HTTP_Exception::factory(403,'Class has no security defined :class, or no security configured for :method',array(':class'=>get_class($this),':method'=>Request::current()->action())); + + $this->ao = Auth::instance()->get_user(); + + if (! is_null($this->ao) AND (is_string($this->ao) OR ! $this->ao->loaded())) + throw HTTP_Exception::factory(501,'Account doesnt exist :account ?',array(':account'=>(is_string($this->ao) OR is_null($this->ao)) ? $this->ao : Auth::instance()->get_user()->id)); + } + // Actions that start with ajax, should only be ajax if (! Kohana::$config->load('debug')->ajax AND preg_match('/^ajax/',Request::current()->action()) AND ! Request::current()->is_ajax()) throw HTTP_Exception::factory(412,_('Unable to fulfil request.')); diff --git a/classes/lnApp/ORM.php b/classes/lnApp/ORM.php index 3c1f793..8b525e2 100644 --- a/classes/lnApp/ORM.php +++ b/classes/lnApp/ORM.php @@ -76,6 +76,56 @@ abstract class lnApp_ORM extends Kohana_ORM { return $result; } + /** + * This function is our AJAX helper, used by module list_autocomplete() + */ + public function list_autocomplete($term,$index,$value,array $label,array $limit=array(),array $options=NULL) { + $result = array(); + + $query = empty($options['object']) ? $this : $options['object']; + + foreach ($limit as $w) { + list($k,$s,$v) = $w; + + $query->and_where($k,$s,$v); + } + + $c = 0; + foreach ((empty($options['object']) ? $query->find_all() : $query->execute()) as $o) { + // If we got here via a DB query, we need to reload our ORM object from the result. + if (! is_object($o)) { + if (empty($options['key'])) + throw new Kohana_Exception('Missing key for non object'); + + $o = $this->clear()->where($options['key'],'=',$o[$options['key']])->find(); + } + + switch ($index) { + case 'url': + if (empty($options['urlprefix'])) + throw new Kohana_Exception('Missing URL Prefix'); + + $v = $options['urlprefix'].$o->resolve($value); + + break; + + default: $v = $o->resolve($value); + } + + $k = ''; + foreach ($label as $k => $details) + foreach ($details as $lvalue) + $k = preg_replace('/%s/',$o->resolve($lvalue),$k,1); + + $result[$c++] = array( + 'value'=>$v, + 'label'=>$k, + ); + } + + return $result; + } + /** * Return an array of data that can be used in a SELECT statement. * The ID and VALUE is defined in the model for the select. @@ -84,7 +134,7 @@ abstract class lnApp_ORM extends Kohana_ORM { $result = array(); if ($blank) - $result[] = ''; + $result[NULL] = ''; if ($this->_form AND array_intersect(array('id','value'),$this->_form)) foreach ($this->find_all() as $o) diff --git a/classes/lnApp/Request.php b/classes/lnApp/Request.php new file mode 100644 index 0000000..dd48c30 --- /dev/null +++ b/classes/lnApp/Request.php @@ -0,0 +1,31 @@ +a,reseller=>r. + * + * @param string $directory Directory to execute the controller from + * @return mixed + */ + public function directory($directory = NULL) { + // If $directory is NULL, we are a getter and see if we need to expand the directory + if ($directory === NULL AND $this->_directory) + $this->_directory = URL::dir($this->_directory); + + return parent::directory($directory); + } +} +?> diff --git a/classes/lnApp/Table.php b/classes/lnApp/Table.php index d8a1883..511371b 100644 --- a/classes/lnApp/Table.php +++ b/classes/lnApp/Table.php @@ -63,7 +63,11 @@ abstract class lnApp_Table { $x = $d; else - $x = $d->display($key); + $x = isset($d->{$key}) ? $d->display($key) : ''; + + // We cant display array values + if (is_array($x)) + $x = array_shift($x); if (isset($this->prepend[$key]) AND $x) { foreach ($this->prepend[$key] as $act => $data) { diff --git a/classes/lnApp/URL.php b/classes/lnApp/URL.php index 234d1d9..d895e8d 100644 --- a/classes/lnApp/URL.php +++ b/classes/lnApp/URL.php @@ -9,7 +9,7 @@ * @copyright (c) 2014 Deon George * @license http://dev.leenooks.net/license.html */ -class lnApp_URL extends Kohana_URL { +abstract class lnApp_URL extends Kohana_URL { // Our method paths for different functions public static $method_directory = array( 'admin'=>'a', diff --git a/media/img/spinner.gif b/media/img/spinner.gif new file mode 100644 index 0000000..b780128 Binary files /dev/null and b/media/img/spinner.gif differ diff --git a/media/js/search.js b/media/js/search.js new file mode 100644 index 0000000..979890e --- /dev/null +++ b/media/js/search.js @@ -0,0 +1,53 @@ +$(document).ready(function() { + $("input[name=search-query]").typeahead({ + minLength: 2, + source: function (query,process) { + if(query.length==0) return false; + + search('u/search/ajaxlist',query,process); + }, + + matcher: function () { return true; }, + + updater: function (item) { + window.parent.location.href = site_url+users[item]; + }, + }); +}); + +var c=0; +var search = _.debounce(function(url,query,process){ + $.ajax({ + url : site_url+url, + type : 'GET', + data : 'term=' + query, + dataType : 'JSON', + async : true, + cache : false, + beforeSend : function() { + if (c++ == 0) + $('img[name=searching]').css('visibility', 'visible'); + }, + success : function(data) { + // if json is null, means no match, won't do again. + if(data==null || (data.length===0)) return; + + users = {}; + userLabels = []; + + _.each(data,function(item,ix,list) { + if (_.contains(users,item.label)) + item.label = item.label + ' #' + item.value; + + userLabels.push(item.label); + users[item.label] = item.value; + }); + + process(userLabels); + }, + complete : function() { + if (--c == 0) + $('img[name=searching]').css('visibility', 'hidden'); + } +}) +}, 500); diff --git a/media/theme/baseadmin/css/custom.css b/media/theme/baseadmin/css/custom.css index 3927bd4..ace2c48 100644 --- a/media/theme/baseadmin/css/custom.css +++ b/media/theme/baseadmin/css/custom.css @@ -67,3 +67,24 @@ table .text-right { content: ""; clear: both; } + +.navbar .navbar-search .left-inner-addon { + position: relative; +} +.navbar .navbar-search .navbar-search-addon input.search-query { + padding-left: 30px; + padding-right: 30px; + width: 150px; +} +.navbar .navbar-search .navbar-search-addon i { + position: absolute; + padding: 8px 10px; + pointer-events: none; +} +.navbar .navbar-search .navbar-search-addon img { + position: absolute; + padding: 6px 10px; + pointer-events: none; + right: 0px; + visibility: hidden; +} diff --git a/views/theme/baseadmin/page.php b/views/theme/baseadmin/page.php index b7f6107..06b2dce 100644 --- a/views/theme/baseadmin/page.php +++ b/views/theme/baseadmin/page.php @@ -46,9 +46,13 @@ -
+