Index: application/controllers/AdministrationController.class.php =================================================================== --- application/controllers/AdministrationController.class.php (revision 146) +++ application/controllers/AdministrationController.class.php (working copy) @@ -245,6 +245,67 @@ } // try } // if } // tool_mass_mailer + + function plugins() { + + $plugins = Plugins::getAllPlugins(); + tpl_assign('plugins',$plugins); + + } // index + + function update_plugins() { + + $plugins = array_var($_POST,'plugins'); + $reference = Plugins::getAllPlugins(); + $errors = array(); + + foreach($plugins as $name => $yes_no) { + // get existing id + $id = $reference[$name]; + $nicename = ucwords(str_replace('_',' ',$name)); + if($yes_no && '-' == $id) { + try { + $plugin = new Plugin(); + $plugin->setName($name); + DB::beginWork(); + // get the file loaded here + include_once(APPLICATION_PATH.'/plugins/plugin.'.$name.'.php'); + // get activation routine ready + $activate = $name.'_activate'; + if( function_exists($activate) ) { + $activate(); + } + // save to db now + $plugin->save(); + DB::commit(); + } catch(Exception $e) { + DB::rollback(); + $errors[] = $nicename.' ('.$e->getMessage().')'; + } + } + elseif(!$yes_no && '-' != $id) { + try + { + $plugin = Plugins::findById($id); + DB::beginWork(); + $deactivate = $name.'_deactivate'; + if( function_exists($deactivate) ) + $deactivate(); + $plugin->delete(); + DB::commit(); + } catch(Exception $e) { + DB::rollback(); + $errors[] = $nicename.' ('.$e->getMessage().')'; + } + } + } + if( count($errors) ) + flash_error(lang('plugin activation failed', implode(", ",$errors))); + else + flash_error(lang('plugins updated')); + $this->redirectTo('administration','plugins'); + + } // update } // AdministrationController Index: application/controllers/LinkController.class.php =================================================================== --- application/controllers/LinkController.class.php (revision 0) +++ application/controllers/LinkController.class.php (revision 0) @@ -0,0 +1,164 @@ +addHelper('textile'); + $links = ProjectLinks::getAllProjectLinks(active_project()); + tpl_assign('links', $links); + + } // index + + function add_link() { + + $this->setTemplate('edit_link'); + + if (!ProjectLink::canAdd(logged_user(), active_project())) { + flash_error(lang('no access permissions')); + $this->redirectTo('link','index'); + } // if + + $project_link = new ProjectLink(); + $project_link_data = array_var($_POST, 'project_link'); + + if (is_array(array_var($_POST, 'project_link'))) { + $project_link->setFromAttributes($project_link_data); + $project_link->setCreatedById(logged_user()->getId()); + $project_link->setProjectId(active_project()->getId()); + + try { + DB::beginWork(); + $project_link->save(); + ApplicationLogs::createLog($project_link, active_project(), ApplicationLogs::ACTION_ADD); + DB::commit(); + + flash_success(lang('success add link')); + $this->redirectTo('link'); + } catch(Exception $e) { + DB::rollback(); + tpl_assign('error', $e); + } // try + } + + tpl_assign('project_link', $project_link); + tpl_assign('project_link_data', $project_link_data); + + } // add_link + + /** + * Edit project link + * + * @param void + * @return null + */ + function edit_link() { + + $this->setTemplate('edit_link'); + $project_link = ProjectLinks::findById(get_id()); + + if (!ProjectLink::canEdit(logged_user())) { + flash_error(lang('no access permissions')); + $this->redirectTo('link','index'); + } // if + + if (!($project_link instanceof ProjectLink)) { + flash_error(lang('project link dnx')); + $this->redirectTo('link'); + } // if + + $project_link_data = array_var($_POST, 'project_link'); + + if (!is_array($project_link_data)) { + $project_link_data = array( + 'title' => $project_link->getTitle(), + 'url' => $project_link->getUrl(), + ); // array + } // if + + tpl_assign('project_link_data', $project_link_data); + tpl_assign('project_link', $project_link); + + if (is_array(array_var($_POST, 'project_link'))) { + $project_link->setFromAttributes($project_link_data); + $project_link->setProjectId(active_project()->getId()); + + try { + DB::beginWork(); + $project_link->save(); + ApplicationLogs::createLog($project_link, active_project(), ApplicationLogs::ACTION_EDIT); + DB::commit(); + + flash_success(lang('success edit link')); + $this->redirectTo('link'); + } catch(Exception $e) { + DB::rollback(); + tpl_assign('error', $e); + } // try + } + tpl_assign('project_link', $project_link); + tpl_assign('project_link_data', $project_link_data); + } // edit_link + + /** + * Delete project link + * + * @param void + * @return null + */ + function delete_link() { + + $project_link = ProjectLinks::findById(get_id()); + + if (!ProjectLink::canEdit(logged_user())) { + flash_error(lang('no access permissions')); + $this->redirectTo('link','index'); + } // if + + if (!($project_link instanceof ProjectLink)) { + flash_error(lang('project link dnx')); + $this->redirectTo('link'); + } // if + + try { + DB::beginWork(); + $project_link->delete(); + ApplicationLogs::createLog($project_link, active_project(), ApplicationLogs::ACTION_DELETE); + DB::commit(); + + flash_success(lang('success delete link', $project_link->getTitle())); + $this->redirectTo('link'); + } catch(Exception $e) { + DB::rollback(); + tpl_assign('error', $e); + } // try + + } // delete_link + + } // LinkController + +?> Index: application/helpers/company_website.php =================================================================== --- application/helpers/company_website.php (revision 146) +++ application/helpers/company_website.php (working copy) @@ -51,6 +51,10 @@ get_url('dashboard', 'my_tasks') )); + // PLUGIN HOOK + plugin_manager()->do_action('add_dashboard_tab'); + // PLUGIN HOOK + tabbed_navigation_set_selected($selected); } // dashboard_tabbed_navigation @@ -86,6 +90,7 @@ define('ADMINISTRATION_TAB_CONFIGURATION', 'config'); define('ADMINISTRATION_TAB_TOOLS', 'tools'); define('ADMINISTRATION_TAB_UPGRADE', 'upgrade'); + define('ADMINISTRATION_TAB_PLUGINS', 'plugins'); /** * Prepare administration tabbed navigation @@ -135,6 +140,16 @@ lang('upgrade'), get_url('administration', 'upgrade') )); + add_tabbed_navigation_item(new TabbedNavigationItem( + ADMINISTRATION_TAB_PLUGINS, + lang('plugins'), + get_url('administration','plugins') + )); + + // PLUGIN HOOK + plugin_manager()->do_action('add_administration_tab'); + // PLUGIN HOOK + tabbed_navigation_set_selected($selected); } // administration_tabbed_navigation @@ -177,6 +192,11 @@ lang('my account'), get_url('account', 'index') )); + + // PLUGIN HOOK + plugin_manager()->do_action('add_my_account_tab'); + // PLUGIN HOOK + tabbed_navigation_set_selected($selected); } // account_tabbed_navigation Index: application/helpers/project_website.php =================================================================== --- application/helpers/project_website.php (revision 146) +++ application/helpers/project_website.php (working copy) @@ -78,6 +78,11 @@ lang('people'), get_url('project', 'people') )); + + // PLUGIN HOOK + plugin_manager()->do_action('add_project_tab'); + // PLUGIN HOOK + tabbed_navigation_set_selected($selected); } // dashboard_tabbed_navigation Index: application/helpers/tabbednavigation.php =================================================================== --- application/helpers/tabbednavigation.php (revision 146) +++ application/helpers/tabbednavigation.php (working copy) @@ -7,7 +7,10 @@ * @return array */ function tabbed_navigation_items() { - return TabbedNavigation::instance()->getItems(); + // PLUGIN HOOK + return plugin_manager()->apply_filters('tabbed_navigation_items', + TabbedNavigation::instance()->getItems()); + // PLUGIN HOOK } // tabbed_navigation_items /** Index: application/models/PluginManager.class.php =================================================================== --- application/models/PluginManager.class.php (revision 0) +++ application/models/PluginManager.class.php (revision 0) @@ -0,0 +1,148 @@ +filter_table= array(); + + $activated_plugins = Plugins::getActivatedPlugins(); + + // now load each plugin + foreach(array_keys($activated_plugins) as $name) { + include_once 'plugins/plugin.'.$name.'.php'; + } + + // TODO : cleanup up old activated plugins without valid file?? + + } else { + PluginManager::instance()->init(); + } // if + } + + function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { + + if ( isset($this->filter_table[$tag][$priority]) ) { + foreach($this->filter_table[$tag][$priority] as $filter) { + if ( $filter['function'] == $function_to_add ) { + return false; + } + } + } + $this->filter_table[$tag][$priority][] = array( + 'function'=>$function_to_add, + 'accepted_args'=>$accepted_args); + return true; + } + + function remove_filter($tag, $function_to_remove, $priority = 10) { + + + $toret = false; + + if ( isset($this->filter_table[$tag][$priority]) ) { + foreach($this->filter_table[$tag][$priority] as $filter) { + if ( $filter['function'] != $function_to_remove ) { + $new_function_list[] = $filter; + } + else { + $toret = true; + } + } + $this->filter_table[$tag][$priority] = $new_function_list; + } + return $toret; + } + + function do_action($tag,$arg='') { + + if ( !isset($this->filter_table[$tag]) ) { + return; + } + else { + ksort($this->filter_table[$tag]); + } + + $args = array(); + if ( is_array($arg) && 1 == count($arg) && is_object($arg[0]) ) + $args[] =& $arg[0]; + else + $args[] = $arg; + for ( $a = 2; $a < func_num_args(); $a++ ) + $args[] = func_get_arg($a); + + foreach ($this->filter_table[$tag] as $priority => $functions) { + if ( !is_null($functions) ) { + foreach($functions as $f) { + call_user_func_array($f['function'], array_slice($args, 0, (int)$f['accepted_args'])); + } + } + } + } + function apply_filters($tag,$value) { + + $args = func_get_args(); + + if ( !isset($this->filter_table[$tag]) ) { + return $value; + } + else { + ksort($this->filter_table[$tag]); + } + + foreach ($this->filter_table[$tag] as $priority => $functions) { + if ( !is_null($functions) ) { + foreach($functions as $f) { + $args[1] = $value; + $value = call_user_func_array($f['function'], array_slice($args, 1,(int)$f['accepted_args'])); + } + } + } + return $value; + } + + /** + * Return single PluginManager instance + * + * @access public + * @param void + * @return PluginManager + */ + static function instance() { + static $instance; + if (!($instance instanceof PluginManager )) { + $instance = new PluginManager(); + } // if + return $instance; + } // instance + + } +?> \ No newline at end of file Index: application/models/plugins/Plugin.class.php =================================================================== --- application/models/plugins/Plugin.class.php (revision 0) +++ application/models/plugins/Plugin.class.php (revision 0) @@ -0,0 +1,12 @@ + Index: application/models/plugins/Plugins.class.php =================================================================== --- application/models/plugins/Plugins.class.php (revision 0) +++ application/models/plugins/Plugins.class.php (revision 0) @@ -0,0 +1,81 @@ +getName(),$results) ) { + $results[$plugin->getName()] = $plugin->getPluginId(); + } else { + // TODO : remove from DB here?? + } + } + + return $results; + + } // getAllPlugins + + /** + * Return array of all activated plugins based on plugin files on filesystem + * + * @param none + * @return array + */ + static function getActivatedPlugins() { + + $results = Plugins::getAllPlugins(); + + foreach($results as $name => $id) { + if( '-' == $id ) + unset($results[$name]); + } + + return $results; + + } // getActivatedPlugins + + /** + * Return array of all activated plugins + * + * @param none + * @return array + */ + static function getNamesFromDB() { + $names = array(); + $plugins = Plugins::findAll(array()); // findAll + if (is_array($plugins)) { + foreach ($plugins as $plugin) { + $names[] = $plugin->getName(); + } // foreach + } // if + return $names; + } // getActivatedPlugins + + } // Plugins + +?> Index: application/models/plugins/base/BasePlugin.class.php =================================================================== --- application/models/plugins/base/BasePlugin.class.php (revision 0) +++ application/models/plugins/base/BasePlugin.class.php (revision 0) @@ -0,0 +1,75 @@ +getColumnValue('plugin_id'); + } // getPluginId() + + /** + * Set value of 'plugin_id' field + * + * @access public + * @param integer $value + * @return boolean + */ + function setPluginId($value) { + return $this->setColumnValue('plugin_id', $value); + } // setPluginId() + + /** + * Return value of 'name' field + * + * @access public + * @param void + * @return integer + */ + function getName() { + return $this->getColumnValue('name'); + } // getName() + + /** + * Set value of 'name' field + * + * @access public + * @param integer $value + * @return boolean + */ + function setName($value) { + return $this->setColumnValue('name', $value); + } // setName() + + + /** + * Return manager instance + * + * @access protected + * @param void + * @return Plugins + */ + function manager() { + if (!($this->manager instanceof Plugins)) { + $this->manager = Plugins::instance(); + } + return $this->manager; + } // manager + + } // BasePlugin + +?> Index: application/models/plugins/base/BasePlugins.class.php =================================================================== --- application/models/plugins/base/BasePlugins.class.php (revision 0) +++ application/models/plugins/base/BasePlugins.class.php (revision 0) @@ -0,0 +1,234 @@ + Column type map + * + * @var array + * @static + */ + static private $columns = array('plugin_id' => DATA_TYPE_INTEGER, 'name' => DATA_TYPE_STRING); + + /** + * Construct + * + * @return BasePlugins + */ + function __construct() { + parent::__construct('Plugin', 'plugins', true); + } // __construct + + // ------------------------------------------------------- + // Description methods + // ------------------------------------------------------- + + /** + * Return array of object columns + * + * @access public + * @param void + * @return array + */ + function getColumns() { + return array_keys(self::$columns); + } // getColumns + + /** + * Return column type + * + * @access public + * @param string $column_name + * @return string + */ + function getColumnType($column_name) { + if (isset(self::$columns[$column_name])) { + return self::$columns[$column_name]; + } else { + return DATA_TYPE_STRING; + } // if + } // getColumnType + + /** + * Return array of PK columns. If only one column is PK returns its name as string + * + * @access public + * @param void + * @return array or string + */ + function getPkColumns() { + return 'plugin_id'; + } // getPkColumns + + /** + * Return name of first auto_incremenent column if it exists + * + * @access public + * @param void + * @return string + */ + function getAutoIncrementColumn() { + return NULL; + } // getAutoIncrementColumn + + // ------------------------------------------------------- + // Finders + // ------------------------------------------------------- + + /** + * Do a SELECT query over database with specified arguments + * + * @access public + * @param array $arguments Array of query arguments. Fields: + * + * - one - select first row + * - conditions - additional conditions + * - order - order by string + * - offset - limit offset, valid only if limit is present + * - limit + * + * @return one or Plugins objects + * @throws DBQueryError + */ + function find($arguments = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::find($arguments); + } else { + return Plugins::instance()->find($arguments); + //$instance =& Plugins::instance(); + //return $instance->find($arguments); + } // if + } // find + + /** + * Find all records + * + * @access public + * @param array $arguments + * @return one or Plugins objects + */ + function findAll($arguments = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::findAll($arguments); + } else { + return Plugins::instance()->findAll($arguments); + //$instance =& Plugins::instance(); + //return $instance->findAll($arguments); + } // if + } // findAll + + /** + * Find one specific record + * + * @access public + * @param array $arguments + * @return Plugin + */ + function findOne($arguments = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::findOne($arguments); + } else { + return Plugins::instance()->findOne($arguments); + //$instance =& Plugins::instance(); + //return $instance->findOne($arguments); + } // if + } // findOne + + /** + * Return object by its PK value + * + * @access public + * @param mixed $id + * @param boolean $force_reload If true cache will be skipped and data will be loaded from database + * @return Plugin + */ + function findById($id, $force_reload = false) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::findById($id, $force_reload); + } else { + return Plugins::instance()->findById($id, $force_reload); + //$instance =& Plugins::instance(); + //return $instance->findById($id, $force_reload); + } // if + } // findById + + /** + * Return number of rows in this table + * + * @access public + * @param string $conditions Query conditions + * @return integer + */ + function count($condition = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::count($condition); + } else { + return Plugins::instance()->count($condition); + //$instance =& Plugins::instance(); + //return $instance->count($condition); + } // if + } // count + + /** + * Delete rows that match specific conditions. If $conditions is NULL all rows from table will be deleted + * + * @access public + * @param string $conditions Query conditions + * @return boolean + */ + function delete($condition = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::delete($condition); + } else { + return Plugins::instance()->delete($condition); + //$instance =& Plugins::instance(); + //return $instance->delete($condition); + } // if + } // delete + + /** + * This function will return paginated result. Result is an array where first element is + * array of returned object and second populated pagination object that can be used for + * obtaining and rendering pagination data using various helpers. + * + * Items and pagination array vars are indexed with 0 for items and 1 for pagination + * because you can't use associative indexing with list() construct + * + * @access public + * @param array $arguments Query argumens (@see find()) Limit and offset are ignored! + * @param integer $items_per_page Number of items per page + * @param integer $current_page Current page number + * @return array + */ + function paginate($arguments = null, $items_per_page = 10, $current_page = 1) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::paginate($arguments, $items_per_page, $current_page); + } else { + return Plugins::instance()->paginate($arguments, $items_per_page, $current_page); + //$instance =& Plugins::instance(); + //return $instance->paginate($arguments, $items_per_page, $current_page); + } // if + } // paginate + + /** + * Return manager instance + * + * @return Plugins + */ + function instance() { + static $instance; + if (!instance_of($instance, 'Plugins')) { + $instance = new Plugins(); + } // if + return $instance; + } // instance + + } // Plugins + +?> Index: application/models/plugins/base/BasePlugin.class.php =================================================================== --- application/models/plugins/base/BasePlugin.class.php (revision 0) +++ application/models/plugins/base/BasePlugin.class.php (revision 0) @@ -0,0 +1,75 @@ +getColumnValue('plugin_id'); + } // getPluginId() + + /** + * Set value of 'plugin_id' field + * + * @access public + * @param integer $value + * @return boolean + */ + function setPluginId($value) { + return $this->setColumnValue('plugin_id', $value); + } // setPluginId() + + /** + * Return value of 'name' field + * + * @access public + * @param void + * @return integer + */ + function getName() { + return $this->getColumnValue('name'); + } // getName() + + /** + * Set value of 'name' field + * + * @access public + * @param integer $value + * @return boolean + */ + function setName($value) { + return $this->setColumnValue('name', $value); + } // setName() + + + /** + * Return manager instance + * + * @access protected + * @param void + * @return Plugins + */ + function manager() { + if (!($this->manager instanceof Plugins)) { + $this->manager = Plugins::instance(); + } + return $this->manager; + } // manager + + } // BasePlugin + +?> Index: application/models/plugins/base/BasePlugins.class.php =================================================================== --- application/models/plugins/base/BasePlugins.class.php (revision 0) +++ application/models/plugins/base/BasePlugins.class.php (revision 0) @@ -0,0 +1,234 @@ + Column type map + * + * @var array + * @static + */ + static private $columns = array('plugin_id' => DATA_TYPE_INTEGER, 'name' => DATA_TYPE_STRING); + + /** + * Construct + * + * @return BasePlugins + */ + function __construct() { + parent::__construct('Plugin', 'plugins', true); + } // __construct + + // ------------------------------------------------------- + // Description methods + // ------------------------------------------------------- + + /** + * Return array of object columns + * + * @access public + * @param void + * @return array + */ + function getColumns() { + return array_keys(self::$columns); + } // getColumns + + /** + * Return column type + * + * @access public + * @param string $column_name + * @return string + */ + function getColumnType($column_name) { + if (isset(self::$columns[$column_name])) { + return self::$columns[$column_name]; + } else { + return DATA_TYPE_STRING; + } // if + } // getColumnType + + /** + * Return array of PK columns. If only one column is PK returns its name as string + * + * @access public + * @param void + * @return array or string + */ + function getPkColumns() { + return 'plugin_id'; + } // getPkColumns + + /** + * Return name of first auto_incremenent column if it exists + * + * @access public + * @param void + * @return string + */ + function getAutoIncrementColumn() { + return NULL; + } // getAutoIncrementColumn + + // ------------------------------------------------------- + // Finders + // ------------------------------------------------------- + + /** + * Do a SELECT query over database with specified arguments + * + * @access public + * @param array $arguments Array of query arguments. Fields: + * + * - one - select first row + * - conditions - additional conditions + * - order - order by string + * - offset - limit offset, valid only if limit is present + * - limit + * + * @return one or Plugins objects + * @throws DBQueryError + */ + function find($arguments = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::find($arguments); + } else { + return Plugins::instance()->find($arguments); + //$instance =& Plugins::instance(); + //return $instance->find($arguments); + } // if + } // find + + /** + * Find all records + * + * @access public + * @param array $arguments + * @return one or Plugins objects + */ + function findAll($arguments = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::findAll($arguments); + } else { + return Plugins::instance()->findAll($arguments); + //$instance =& Plugins::instance(); + //return $instance->findAll($arguments); + } // if + } // findAll + + /** + * Find one specific record + * + * @access public + * @param array $arguments + * @return Plugin + */ + function findOne($arguments = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::findOne($arguments); + } else { + return Plugins::instance()->findOne($arguments); + //$instance =& Plugins::instance(); + //return $instance->findOne($arguments); + } // if + } // findOne + + /** + * Return object by its PK value + * + * @access public + * @param mixed $id + * @param boolean $force_reload If true cache will be skipped and data will be loaded from database + * @return Plugin + */ + function findById($id, $force_reload = false) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::findById($id, $force_reload); + } else { + return Plugins::instance()->findById($id, $force_reload); + //$instance =& Plugins::instance(); + //return $instance->findById($id, $force_reload); + } // if + } // findById + + /** + * Return number of rows in this table + * + * @access public + * @param string $conditions Query conditions + * @return integer + */ + function count($condition = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::count($condition); + } else { + return Plugins::instance()->count($condition); + //$instance =& Plugins::instance(); + //return $instance->count($condition); + } // if + } // count + + /** + * Delete rows that match specific conditions. If $conditions is NULL all rows from table will be deleted + * + * @access public + * @param string $conditions Query conditions + * @return boolean + */ + function delete($condition = null) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::delete($condition); + } else { + return Plugins::instance()->delete($condition); + //$instance =& Plugins::instance(); + //return $instance->delete($condition); + } // if + } // delete + + /** + * This function will return paginated result. Result is an array where first element is + * array of returned object and second populated pagination object that can be used for + * obtaining and rendering pagination data using various helpers. + * + * Items and pagination array vars are indexed with 0 for items and 1 for pagination + * because you can't use associative indexing with list() construct + * + * @access public + * @param array $arguments Query argumens (@see find()) Limit and offset are ignored! + * @param integer $items_per_page Number of items per page + * @param integer $current_page Current page number + * @return array + */ + function paginate($arguments = null, $items_per_page = 10, $current_page = 1) { + if (isset($this) && instance_of($this, 'Plugins')) { + return parent::paginate($arguments, $items_per_page, $current_page); + } else { + return Plugins::instance()->paginate($arguments, $items_per_page, $current_page); + //$instance =& Plugins::instance(); + //return $instance->paginate($arguments, $items_per_page, $current_page); + } // if + } // paginate + + /** + * Return manager instance + * + * @return Plugins + */ + function instance() { + static $instance; + if (!instance_of($instance, 'Plugins')) { + $instance = new Plugins(); + } // if + return $instance; + } // instance + + } // Plugins + +?> Index: application/models/plugins/Plugin.class.php =================================================================== --- application/models/plugins/Plugin.class.php (revision 0) +++ application/models/plugins/Plugin.class.php (revision 0) @@ -0,0 +1,12 @@ + Index: application/models/plugins/Plugins.class.php =================================================================== --- application/models/plugins/Plugins.class.php (revision 0) +++ application/models/plugins/Plugins.class.php (revision 0) @@ -0,0 +1,81 @@ +getName(),$results) ) { + $results[$plugin->getName()] = $plugin->getPluginId(); + } else { + // TODO : remove from DB here?? + } + } + + return $results; + + } // getAllPlugins + + /** + * Return array of all activated plugins based on plugin files on filesystem + * + * @param none + * @return array + */ + static function getActivatedPlugins() { + + $results = Plugins::getAllPlugins(); + + foreach($results as $name => $id) { + if( '-' == $id ) + unset($results[$name]); + } + + return $results; + + } // getActivatedPlugins + + /** + * Return array of all activated plugins + * + * @param none + * @return array + */ + static function getNamesFromDB() { + $names = array(); + $plugins = Plugins::findAll(array()); // findAll + if (is_array($plugins)) { + foreach ($plugins as $plugin) { + $names[] = $plugin->getName(); + } // foreach + } // if + return $names; + } // getActivatedPlugins + + } // Plugins + +?> Index: application/models/project_links/ProjectLinks.class.php =================================================================== --- application/models/project_links/ProjectLinks.class.php (revision 0) +++ application/models/project_links/ProjectLinks.class.php (revision 0) @@ -0,0 +1,29 @@ +getId()); + + return self::findAll(array( + 'conditions' => $conditions, + 'order' => '`created_on` DESC', + )); // findAll + + } // getAllProjectLinks + + } // ProjectLinks + +?> Index: application/models/project_links/ProjectLink.class.php =================================================================== --- application/models/project_links/ProjectLink.class.php (revision 0) +++ application/models/project_links/ProjectLink.class.php (revision 0) @@ -0,0 +1,111 @@ +project)) { + $this->project = Projects::findById($this->getProjectId()); + } // if + return $this->project; + } // getProject + + /** + * Add new link + * + * @param void + * @return null + */ + function canAdd(User $user, Project $project) { + return $user->isAdministrator() || $user->isMemberOfOwnerCompany(); + } + + /** + * Edit link + * + * @param void + * @return null + */ + function canEdit(User $user) { + return $user->isAdministrator() || $user->isMemberOfOwnerCompany(); + } + + /** + * Delete link + * + * @param void + * @return null + */ + function canDelete(User $user) { + return $user->isAdministrator() || $user->isMemberOfOwnerCompany(); + } + + /** + * Does user have view access + * + * @param void + * @return boolean + */ + function canView(User $user) { + if ($user->isAdministrator() || $user->isMemberOfOwnerCompany()) { + return true; + } // if + if ($user->isProjectUser($this->getProject())) { + return true; + } // if + return false; + } // canView + + /** + * Return edit link URL + * + * @param void + * @return string + */ + function getEditUrl() { + return get_url('link', 'edit_link', array('id' => $this->getId(), 'active_project' => active_project()->getId())); + } // getEditUrl + + /** + * Return delete link URL + * + * @param void + * @return string + */ + function getDeleteUrl() { + return get_url('link', 'delete_link', array('id' => $this->getId(), 'active_project' => active_project()->getId())); + } // getEditUrl + + /** + * Return object name + * + * @param void + * @return string + */ + function getObjectName() { + return $this->getTitle(); + } + + /** + * Return object type name + * + * @param void + * @return string + */ + function getObjectTypeName() { + return lang('link'); + } // getObjectTypeName + + } // ProjectLink + +?> Index: application/models/project_links/base/BaseProjectLink.class.php =================================================================== --- application/models/project_links/base/BaseProjectLink.class.php (revision 0) +++ application/models/project_links/base/BaseProjectLink.class.php (revision 0) @@ -0,0 +1,59 @@ +getColumnValue('id'); + } // getObjectId() + + // ----------------------------------------------------- + // Magic access method + // NB: this replaces the need for other setters/getters + // ----------------------------------------------------- + function __call($method, $args) { + if( preg_match('/(set|get)(_)?/', $method) ) { + if(substr($method, 0, 3) == "get") { + $col = substr(strtolower(preg_replace('([A-Z])', '_$0', $method)), 4); + if( $col ) { + return $this->getColumnValue($col); + } + } elseif(substr($method, 0, 3) == "set" && count($args)) { + $col = substr(strtolower(preg_replace('([A-Z])', '_$0', $method)), 4); + if( $col ) { + return $this->setColumnValue($col, $args[0]); + } + } + } + // me no understand! + return false; + } + + /** + * Return manager instance + * + * @access protected + * @param void + * @return ProjectLinks + */ + function manager() { + if (!($this->manager instanceof ProjectLinks)) { + $this->manager = ProjectLinks::instance(); + } + return $this->manager; + } // manager + + } // BaseProjectLink + +?> Index: application/models/project_links/base/BaseProjectLinks.class.php =================================================================== --- application/models/project_links/base/BaseProjectLinks.class.php (revision 0) +++ application/models/project_links/base/BaseProjectLinks.class.php (revision 0) @@ -0,0 +1,224 @@ + Column type map + * + * @var array + * @static + */ + static private $columns = array('id' => DATA_TYPE_INTEGER, + 'project_id' => DATA_TYPE_INTEGER, + 'title' => DATA_TYPE_STRING, + 'url' => DATA_TYPE_STRING, + 'created_on' => DATA_TYPE_DATETIME, + 'created_by_id' => DATA_TYPE_INTEGER); + + /** + * Construct + * + * @return BaseProjectLinks + */ + function __construct() { + parent::__construct('ProjectLink', 'project_links', true); + } // __construct + + // ------------------------------------------------------- + // Description methods + // ------------------------------------------------------- + + /** + * Return array of object columns + * + * @access public + * @param void + * @return array + */ + function getColumns() { + return array_keys(self::$columns); + } // getColumns + + /** + * Return column type + * + * @access public + * @param string $column_name + * @return string + */ + function getColumnType($column_name) { + if (isset(self::$columns[$column_name])) { + return self::$columns[$column_name]; + } else { + return DATA_TYPE_STRING; + } // if + } // getColumnType + + /** + * Return array of PK columns. If only one column is PK returns its name as string + * + * @access public + * @param void + * @return array or string + */ + function getPkColumns() { + return 'id'; + } // getPkColumns + + /** + * Return name of first auto_increment column if it exists + * + * @access public + * @param void + * @return string + */ + function getAutoIncrementColumn() { + return 'id'; + } // getAutoIncrementColumn + + // ------------------------------------------------------- + // Finders + // ------------------------------------------------------- + + /** + * Do a SELECT query over database with specified arguments + * + * @access public + * @param array $arguments Array of query arguments. Fields: + * + * - one - select first row + * - conditions - additional conditions + * - order - order by string + * - offset - limit offset, valid only if limit is present + * - limit + * + * @return one or ProjectLinks objects + * @throws DBQueryError + */ + function find($arguments = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::find($arguments); + } else { + return ProjectLinks::instance()->find($arguments); + } // if + } // find + + /** + * Find all records + * + * @access public + * @param array $arguments + * @return one or ProjectLinks objects + */ + function findAll($arguments = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::findAll($arguments); + } else { + return ProjectLinks::instance()->findAll($arguments); + } // if + } // findAll + + /** + * Find one specific record + * + * @access public + * @param array $arguments + * @return ProjectLink + */ + function findOne($arguments = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::findOne($arguments); + } else { + return ProjectLinks::instance()->findOne($arguments); + } // if + } // findOne + + /** + * Return object by its PK value + * + * @access public + * @param mixed $id + * @param boolean $force_reload If true cache will be skipped and data will be loaded from database + * @return ProjectLink + */ + function findById($id, $force_reload = false) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::findById($id, $force_reload); + } else { + return ProjectLinks::instance()->findById($id, $force_reload); + } // if + } // findById + + /** + * Return number of rows in this table + * + * @access public + * @param string $conditions Query conditions + * @return integer + */ + function count($condition = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::count($condition); + } else { + return ProjectLinks::instance()->count($condition); + } // if + } // count + + /** + * Delete rows that match specific conditions. If $conditions is NULL all rows from table will be deleted + * + * @access public + * @param string $conditions Query conditions + * @return boolean + */ + function delete($condition = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::delete($condition); + } else { + return ProjectLinks::instance()->delete($condition); + } // if + } // delete + + /** + * This function will return paginated result. Result is an array where first element is + * array of returned object and second populated pagination object that can be used for + * obtaining and rendering pagination data using various helpers. + * + * Items and pagination array vars are indexed with 0 for items and 1 for pagination + * because you can't use associative indexing with list() construct + * + * @access public + * @param array $arguments Query argumens (@see find()) Limit and offset are ignored! + * @param integer $items_per_page Number of items per page + * @param integer $current_page Current page number + * @return array + */ + function paginate($arguments = null, $items_per_page = 10, $current_page = 1) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::paginate($arguments, $items_per_page, $current_page); + } else { + return ProjectLinks::instance()->paginate($arguments, $items_per_page, $current_page); + } // if + } // paginate + + /** + * Return manager instance + * + * @return ProjectLinks + */ + function instance() { + static $instance; + if (!instance_of($instance, 'ProjectLinks')) { + $instance = new ProjectLinks(); + } // if + return $instance; + } // instance + + } // ProjectLinks + +?> Index: application/models/project_links/base/BaseProjectLink.class.php =================================================================== --- application/models/project_links/base/BaseProjectLink.class.php (revision 0) +++ application/models/project_links/base/BaseProjectLink.class.php (revision 0) @@ -0,0 +1,59 @@ +getColumnValue('id'); + } // getObjectId() + + // ----------------------------------------------------- + // Magic access method + // NB: this replaces the need for other setters/getters + // ----------------------------------------------------- + function __call($method, $args) { + if( preg_match('/(set|get)(_)?/', $method) ) { + if(substr($method, 0, 3) == "get") { + $col = substr(strtolower(preg_replace('([A-Z])', '_$0', $method)), 4); + if( $col ) { + return $this->getColumnValue($col); + } + } elseif(substr($method, 0, 3) == "set" && count($args)) { + $col = substr(strtolower(preg_replace('([A-Z])', '_$0', $method)), 4); + if( $col ) { + return $this->setColumnValue($col, $args[0]); + } + } + } + // me no understand! + return false; + } + + /** + * Return manager instance + * + * @access protected + * @param void + * @return ProjectLinks + */ + function manager() { + if (!($this->manager instanceof ProjectLinks)) { + $this->manager = ProjectLinks::instance(); + } + return $this->manager; + } // manager + + } // BaseProjectLink + +?> Index: application/models/project_links/base/BaseProjectLinks.class.php =================================================================== --- application/models/project_links/base/BaseProjectLinks.class.php (revision 0) +++ application/models/project_links/base/BaseProjectLinks.class.php (revision 0) @@ -0,0 +1,224 @@ + Column type map + * + * @var array + * @static + */ + static private $columns = array('id' => DATA_TYPE_INTEGER, + 'project_id' => DATA_TYPE_INTEGER, + 'title' => DATA_TYPE_STRING, + 'url' => DATA_TYPE_STRING, + 'created_on' => DATA_TYPE_DATETIME, + 'created_by_id' => DATA_TYPE_INTEGER); + + /** + * Construct + * + * @return BaseProjectLinks + */ + function __construct() { + parent::__construct('ProjectLink', 'project_links', true); + } // __construct + + // ------------------------------------------------------- + // Description methods + // ------------------------------------------------------- + + /** + * Return array of object columns + * + * @access public + * @param void + * @return array + */ + function getColumns() { + return array_keys(self::$columns); + } // getColumns + + /** + * Return column type + * + * @access public + * @param string $column_name + * @return string + */ + function getColumnType($column_name) { + if (isset(self::$columns[$column_name])) { + return self::$columns[$column_name]; + } else { + return DATA_TYPE_STRING; + } // if + } // getColumnType + + /** + * Return array of PK columns. If only one column is PK returns its name as string + * + * @access public + * @param void + * @return array or string + */ + function getPkColumns() { + return 'id'; + } // getPkColumns + + /** + * Return name of first auto_increment column if it exists + * + * @access public + * @param void + * @return string + */ + function getAutoIncrementColumn() { + return 'id'; + } // getAutoIncrementColumn + + // ------------------------------------------------------- + // Finders + // ------------------------------------------------------- + + /** + * Do a SELECT query over database with specified arguments + * + * @access public + * @param array $arguments Array of query arguments. Fields: + * + * - one - select first row + * - conditions - additional conditions + * - order - order by string + * - offset - limit offset, valid only if limit is present + * - limit + * + * @return one or ProjectLinks objects + * @throws DBQueryError + */ + function find($arguments = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::find($arguments); + } else { + return ProjectLinks::instance()->find($arguments); + } // if + } // find + + /** + * Find all records + * + * @access public + * @param array $arguments + * @return one or ProjectLinks objects + */ + function findAll($arguments = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::findAll($arguments); + } else { + return ProjectLinks::instance()->findAll($arguments); + } // if + } // findAll + + /** + * Find one specific record + * + * @access public + * @param array $arguments + * @return ProjectLink + */ + function findOne($arguments = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::findOne($arguments); + } else { + return ProjectLinks::instance()->findOne($arguments); + } // if + } // findOne + + /** + * Return object by its PK value + * + * @access public + * @param mixed $id + * @param boolean $force_reload If true cache will be skipped and data will be loaded from database + * @return ProjectLink + */ + function findById($id, $force_reload = false) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::findById($id, $force_reload); + } else { + return ProjectLinks::instance()->findById($id, $force_reload); + } // if + } // findById + + /** + * Return number of rows in this table + * + * @access public + * @param string $conditions Query conditions + * @return integer + */ + function count($condition = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::count($condition); + } else { + return ProjectLinks::instance()->count($condition); + } // if + } // count + + /** + * Delete rows that match specific conditions. If $conditions is NULL all rows from table will be deleted + * + * @access public + * @param string $conditions Query conditions + * @return boolean + */ + function delete($condition = null) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::delete($condition); + } else { + return ProjectLinks::instance()->delete($condition); + } // if + } // delete + + /** + * This function will return paginated result. Result is an array where first element is + * array of returned object and second populated pagination object that can be used for + * obtaining and rendering pagination data using various helpers. + * + * Items and pagination array vars are indexed with 0 for items and 1 for pagination + * because you can't use associative indexing with list() construct + * + * @access public + * @param array $arguments Query argumens (@see find()) Limit and offset are ignored! + * @param integer $items_per_page Number of items per page + * @param integer $current_page Current page number + * @return array + */ + function paginate($arguments = null, $items_per_page = 10, $current_page = 1) { + if (isset($this) && instance_of($this, 'ProjectLinks')) { + return parent::paginate($arguments, $items_per_page, $current_page); + } else { + return ProjectLinks::instance()->paginate($arguments, $items_per_page, $current_page); + } // if + } // paginate + + /** + * Return manager instance + * + * @return ProjectLinks + */ + function instance() { + static $instance; + if (!instance_of($instance, 'ProjectLinks')) { + $instance = new ProjectLinks(); + } // if + return $instance; + } // instance + + } // ProjectLinks + +?> Index: application/models/project_links/ProjectLink.class.php =================================================================== --- application/models/project_links/ProjectLink.class.php (revision 0) +++ application/models/project_links/ProjectLink.class.php (revision 0) @@ -0,0 +1,111 @@ +project)) { + $this->project = Projects::findById($this->getProjectId()); + } // if + return $this->project; + } // getProject + + /** + * Add new link + * + * @param void + * @return null + */ + function canAdd(User $user, Project $project) { + return $user->isAdministrator() || $user->isMemberOfOwnerCompany(); + } + + /** + * Edit link + * + * @param void + * @return null + */ + function canEdit(User $user) { + return $user->isAdministrator() || $user->isMemberOfOwnerCompany(); + } + + /** + * Delete link + * + * @param void + * @return null + */ + function canDelete(User $user) { + return $user->isAdministrator() || $user->isMemberOfOwnerCompany(); + } + + /** + * Does user have view access + * + * @param void + * @return boolean + */ + function canView(User $user) { + if ($user->isAdministrator() || $user->isMemberOfOwnerCompany()) { + return true; + } // if + if ($user->isProjectUser($this->getProject())) { + return true; + } // if + return false; + } // canView + + /** + * Return edit link URL + * + * @param void + * @return string + */ + function getEditUrl() { + return get_url('link', 'edit_link', array('id' => $this->getId(), 'active_project' => active_project()->getId())); + } // getEditUrl + + /** + * Return delete link URL + * + * @param void + * @return string + */ + function getDeleteUrl() { + return get_url('link', 'delete_link', array('id' => $this->getId(), 'active_project' => active_project()->getId())); + } // getEditUrl + + /** + * Return object name + * + * @param void + * @return string + */ + function getObjectName() { + return $this->getTitle(); + } + + /** + * Return object type name + * + * @param void + * @return string + */ + function getObjectTypeName() { + return lang('link'); + } // getObjectTypeName + + } // ProjectLink + +?> Index: application/models/project_links/ProjectLinks.class.php =================================================================== --- application/models/project_links/ProjectLinks.class.php (revision 0) +++ application/models/project_links/ProjectLinks.class.php (revision 0) @@ -0,0 +1,29 @@ +getId()); + + return self::findAll(array( + 'conditions' => $conditions, + 'order' => '`created_on` DESC', + )); // findAll + + } // getAllProjectLinks + + } // ProjectLinks + +?> Index: application/plugins/plugin.invoices.php =================================================================== --- application/plugins/plugin.invoices.php (revision 0) +++ application/plugins/plugin.invoices.php (revision 0) @@ -0,0 +1,36 @@ + $item) { + if( in_array($item->getID(),$remove) ) { + unset($items[$idx]); + } + } + return $items; + } +?> \ No newline at end of file Index: application/plugins/plugin.project_links.php =================================================================== --- application/plugins/plugin.project_links.php (revision 0) +++ application/plugins/plugin.project_links.php (revision 0) @@ -0,0 +1,78 @@ +_ + * i.e. for the hook in 'add_dashboard_tab' use 'links_add_dashboard_tab' + */ + + // add project tab + define('PROJECT_TAB_PROJECT_LINKS', 'project_links'); + add_action('add_project_tab', 'links_add_project_tab'); + function links_add_project_tab() { + add_tabbed_navigation_item(new TabbedNavigationItem( + PROJECT_TAB_PROJECT_LINKS, + lang('links'), + get_url('link') + )); + } + + // removed unneeded tabs + add_action('tabbed_navigation_items','links_tabbed_navigation_items'); + function links_tabbed_navigation_items($items) { + // check for unneeded tabs + $remove = array('tags','forms','people'); + foreach((array)$items as $idx => $item) { + if( in_array($item->getID(),$remove) ) { + unset($items[$idx]); + } + } + return $items; + } + + // overview page + add_action('project_overview_page_actions','links_project_overview_page_actions'); + function links_project_overview_page_actions() { + if (ProjectLink::canAdd(logged_user(), active_project())) { + add_page_action(lang('add link'), get_url('link', 'add_link')); + } // if + } + + /** + * If you need an activation routine run from the admin panel + * use the following pattern for the function: + * + * _activate + * + * This is good for creation of database tables etc. + */ + function project_links_activate() { + $sql = "CREATE TABLE IF NOT EXISTS `".TABLE_PREFIX."project_links` ( + `id` int(10) unsigned NOT NULL auto_increment, + `project_id` int(10) unsigned NOT NULL default '0', + `title` varchar(100) NOT NULL default '', + `url` text, + `created_on` datetime NOT NULL default '0000-00-00 00:00:00', + `created_by_id` int(10) unsigned default NULL, + PRIMARY KEY (`id`), + KEY `created_on` (`created_on`), + KEY `project_id` (`project_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=".DB_CHARSET."; "; + // create table + DB::execute($sql); + } + + /** + * If you need an de-activation routine run from the admin panel + * use the following pattern for the function: + * + * _deactivate + * + * This is good for deletion of database tables etc. + */ + function project_links_deactivate() { + // sample drop table + DB::execute("DROP TABLE IF EXISTS `".TABLE_PREFIX."project_links`"); + } \ No newline at end of file Index: application/plugins.php =================================================================== --- application/plugins.php (revision 0) +++ application/plugins.php (revision 0) @@ -0,0 +1,50 @@ +init(); + /* + * Convenience function for instance of PluginManager used by hooks throughout + */ + function plugin_manager() { + return PluginManager::instance(); + } + /* + * Convenience functions for plugin writers + */ + function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) { + return plugin_manager()->add_filter($tag,$function_to_add,$priority,$accepted_args); + } + function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { + return plugin_manager()->add_filter($tag,$function_to_add,$priority,$accepted_args); + } + function remove_action($tag, $function_to_remove, $priority = 10) { + return plugin_manager()->remove_filter($tag,$function_to_remove,$priority); + } + function remove_filter($tag, $function_to_remove, $priority = 10) { + return plugin_manager()->remove_filter($tag,$function_to_remove,$priority); + } + +?> \ No newline at end of file Index: application/plugins/plugin.invoices.php =================================================================== --- application/plugins/plugin.invoices.php (revision 0) +++ application/plugins/plugin.invoices.php (revision 0) @@ -0,0 +1,36 @@ + $item) { + if( in_array($item->getID(),$remove) ) { + unset($items[$idx]); + } + } + return $items; + } +?> \ No newline at end of file Index: application/plugins/plugin.project_links.php =================================================================== --- application/plugins/plugin.project_links.php (revision 0) +++ application/plugins/plugin.project_links.php (revision 0) @@ -0,0 +1,78 @@ +_ + * i.e. for the hook in 'add_dashboard_tab' use 'links_add_dashboard_tab' + */ + + // add project tab + define('PROJECT_TAB_PROJECT_LINKS', 'project_links'); + add_action('add_project_tab', 'links_add_project_tab'); + function links_add_project_tab() { + add_tabbed_navigation_item(new TabbedNavigationItem( + PROJECT_TAB_PROJECT_LINKS, + lang('links'), + get_url('link') + )); + } + + // removed unneeded tabs + add_action('tabbed_navigation_items','links_tabbed_navigation_items'); + function links_tabbed_navigation_items($items) { + // check for unneeded tabs + $remove = array('tags','forms','people'); + foreach((array)$items as $idx => $item) { + if( in_array($item->getID(),$remove) ) { + unset($items[$idx]); + } + } + return $items; + } + + // overview page + add_action('project_overview_page_actions','links_project_overview_page_actions'); + function links_project_overview_page_actions() { + if (ProjectLink::canAdd(logged_user(), active_project())) { + add_page_action(lang('add link'), get_url('link', 'add_link')); + } // if + } + + /** + * If you need an activation routine run from the admin panel + * use the following pattern for the function: + * + * _activate + * + * This is good for creation of database tables etc. + */ + function project_links_activate() { + $sql = "CREATE TABLE IF NOT EXISTS `".TABLE_PREFIX."project_links` ( + `id` int(10) unsigned NOT NULL auto_increment, + `project_id` int(10) unsigned NOT NULL default '0', + `title` varchar(100) NOT NULL default '', + `url` text, + `created_on` datetime NOT NULL default '0000-00-00 00:00:00', + `created_by_id` int(10) unsigned default NULL, + PRIMARY KEY (`id`), + KEY `created_on` (`created_on`), + KEY `project_id` (`project_id`) + ) ENGINE=InnoDB DEFAULT CHARSET=".DB_CHARSET."; "; + // create table + DB::execute($sql); + } + + /** + * If you need an de-activation routine run from the admin panel + * use the following pattern for the function: + * + * _deactivate + * + * This is good for deletion of database tables etc. + */ + function project_links_deactivate() { + // sample drop table + DB::execute("DROP TABLE IF EXISTS `".TABLE_PREFIX."project_links`"); + } \ No newline at end of file Index: application/views/administration/index.php =================================================================== --- application/views/administration/index.php (revision 146) +++ application/views/administration/index.php (working copy) @@ -17,6 +17,7 @@
  • ()
  • +
  • Index: application/views/administration/plugins.php =================================================================== --- application/views/administration/plugins.php (revision 0) +++ application/views/administration/plugins.php (revision 0) @@ -0,0 +1,95 @@ + + + +
    +
    +
    + + + + +$id): ?> + +
    +
    +
    +
    + + +

    +
    +
    +
    + + + +

    + + + +

    DEMO NOTES ONLY - To be removed

    +

    Features of the demo Project Links plugin
      - Adds new menu tab in project view +
      - Adds new option to 'Add link' in project overview page +
      - Allows admin/owner company member to add to list of 'hyperlinks' to project +
      - Removes three project menu tabs; Forms, Tags and People +
      - On activate; adds new table to DB +
      - On de-activate; removes table from DB

    +

    Anatomy of the demo Project Links plugin (bold represents plugin files).

    +
      +
    • application +
        +
      • controllers +
          +
        • ProjectLinkController.php
        • +
        +
      • +
      • models +
          +
        • project_links + +
            +
          • base +
              +
            • BaseProjectLinks.class.php
            • +
            • BaseProjectLink.class.php
            • +
            +
          • +
          • ProjectLinks.class.php
          • +
          • ProjectLink.class.php
          • +
          +
        • +
        +
      • +
      • plugins +
          +
        • plugin.project_links.php
        • +
        +
      • +
      • views +
          +
        • links +
            +
          • index.php
          • +
          • edit_link.php
          • +
          +
        • +
        +
      • +
      +
    • +
    • language +
        +
      • en_us +
          +
        • project_links.php
        • +
        +
      • +
      +
    • +
    Index: application/views/application/user_box.php =================================================================== --- application/views/application/user_box.php (revision 146) +++ application/views/application/user_box.php (working copy) @@ -54,6 +54,7 @@
  • +