From df0658f7e10d2bf87460195f792398d16eee811e Mon Sep 17 00:00:00 2001 From: Kevin Chabowski Date: Fri, 23 Dec 2011 01:43:53 +0100 Subject: Added plugin management to bakend and fixed db models. --- ratatoeskr/backend.php | 264 ++++++++++++++++++++- ratatoeskr/main.php | 17 +- ratatoeskr/setup/create_tables.php | 6 +- ratatoeskr/sys/models.php | 67 ++++-- ratatoeskr/sys/plugin_api.php | 2 +- ratatoeskr/sys/pluginpackage.php | 31 ++- .../src/systemtemplates/confirminstall.html | 26 ++ .../templates/src/systemtemplates/pluginhelp.html | 4 + .../src/systemtemplates/plugininstall.html | 18 ++ .../templates/src/systemtemplates/pluginlist.html | 66 ++++++ ratatoeskr/translations/en.php | 25 +- 11 files changed, 494 insertions(+), 32 deletions(-) create mode 100644 ratatoeskr/templates/src/systemtemplates/confirminstall.html create mode 100644 ratatoeskr/templates/src/systemtemplates/pluginhelp.html create mode 100644 ratatoeskr/templates/src/systemtemplates/plugininstall.html create mode 100644 ratatoeskr/templates/src/systemtemplates/pluginlist.html (limited to 'ratatoeskr') diff --git a/ratatoeskr/backend.php b/ratatoeskr/backend.php index 2efe00c..c5ae9c9 100644 --- a/ratatoeskr/backend.php +++ b/ratatoeskr/backend.php @@ -1532,8 +1532,268 @@ $backend_subactions = url_action_subactions(array( echo $ste->exectemplate("systemtemplates/user.html"); } - )) - )) + )), + "repos" => function(&$data, $url_now, &$url_next) + { + global $ste, $translation, $languages, $rel_path_to_root; + + $url_next = array(); + + $ste->vars["section"] = "admin"; + $ste->vars["submenu"] = "repos"; + $ste->vars["pagetitle"] = $translation["menu_plugin_repos"]; + + + + echo $ste->exectemplate("systemtemplates/repos.html"); + } + )), + "plugin" => url_action_subactions(array( + "list" => function(&$data, $url_now, &$url_next) + { + global $ste, $translation, $languages, $rel_path_to_root, $plugin_objs; + + $url_next = array(); + + $ste->vars["section"] = "plugins"; + $ste->vars["submenu"] = "pluginlist"; + $ste->vars["pagetitle"] = $translation["menu_pluginlist"]; + + /* Delete plugins? */ + if(isset($_POST["delete"]) and ($_POST["really_delete"] == "yes") and (!empty($_POST["plugins_multiselect"]))) + { + foreach($_POST["plugins_multiselect"] as $pid) + { + try + { + $plugin = Plugin::by_id($pid); + if(!isset($plugin_objs[$pid])) + { + eval($plugin->code); + $plugin_objs[$pid] = new $plugin->classname($pid); + } + $plugin_objs[$pid]->uninstall(); + $plugin->delete(); + } + catch(DoesNotExistError $e) + { + continue; + } + } + + $ste->vars["success"] = $translation["successfully_deleted_plugins"]; + } + + /* Activate or deactivate plugins? */ + if((isset($_POST["activate"]) or isset($_POST["deactivate"])) and (!empty($_POST["plugins_multiselect"]))) + { + $newstatus = isset($_POST["activate"]); + foreach($_POST["plugins_multiselect"] as $pid) + { + try + { + $plugin = Plugin::by_id($pid); + if(!$plugin->installed) + continue; + $plugin->active = $newstatus; + $plugin->save(); + if($newstatus and(!isset($plugin_objs[$pid]))) + { + eval($plugin->code); + $plugin_objs[$pid] = new $plugin->classname($pid); + $plugin_objs[$pid]->init(); + } + } + catch(DoesNotExistError $e) + { + continue; + } + } + + $ste->vars["success"] = $translation[$newstatus ? "plugins_activated" : "plugins_deactivated"]; + } + + $stream_ctx = stream_context_create(array("http" => array("timeout" => 5))); + + /* Update plugins? */ + if(isset($_POST["update"]) and (!empty($_POST["plugins_multiselect"]))) + { + $updated = array(); + foreach($_POST["plugins_multiselect"] as $pid) + { + try + { + $plugin = Plugin::by_id($pid); + if(!empty($plugin->updatepath)) + { + $update_info = @unserialize(@file_get_contents($plugin->updatepath, False, $stream_ctx)); + if(is_array($update_info) and ($update_info["current-version"] > $plugin->versioncount)) + { + $pkg = PluginPackage::load(@file_get_contents($update_info["dl-path"], False, $stream_ctx)); + $plugin->fill_from_pluginpackage($pkg); + $plugin->update = True; + $plugin->save(); + $updated[] = $plugin->name; + } + } + } + catch(DoesNotExistError $e) + { + continue; + } + catch(InvalidPackage $e) + { + continue; + } + } + + if(empty($updated)) + $ste->vars["success"] = $translation["nothing_to_update"]; + else + $ste->vars["success"] = str_replace("[[PLUGINS]]", implode(", ", $updated), $translation["successfully_updated_plugins"]); + } + + /* Load plugin data */ + $all_plugins = Plugin::all(); + $ste->vars["plugins"] = array(); + foreach($all_plugins as $p) + { + if(!$p->installed) + continue; + + $ste->vars["plugins"][] = array( + "id" => $p->get_id(), + "name" => $p->name, + "versiontext" => $p->versiontext, + "active" => $p->active, + "description" => $p->short_description, + "web" => $p->web, + "author" => $p->author, + "help" => !empty($p->help) + ); + } + + echo $ste->exectemplate("systemtemplates/pluginlist.html"); + }, + "help" => function(&$data, $url_now, &$url_next) + { + global $ste, $translation, $languages, $rel_path_to_root; + + try + { + $plugin = Plugin::by_id($url_next[0]); + if(empty($plugin->help)) + throw new NotFoundError(); + } + catch(DoesNotExistError $e) + { + throw new NotFoundError(); + } + + $url_next = array(); + + $ste->vars["section"] = "plugins"; + $ste->vars["submenu"] = ""; + $ste->vars["pagetitle"] = $plugin->name; + $ste->vars["help"] = $plugin->help; + + echo $ste->exectemplate("systemtemplates/pluginhelp.html"); + }, + "install" => function(&$data, $url_now, &$url_next) + { + global $ste, $translation, $languages, $rel_path_to_root, $api_compat; + + $url_next = array(); + + $ste->vars["section"] = "plugins"; + $ste->vars["submenu"] = "installplugins"; + $ste->vars["pagetitle"] = $translation["menu_plugininstall"]; + + if(isset($_POST["installpackage"])) + { + if(is_uploaded_file($_FILES["pluginpackage"]["tmp_name"])) + { + try + { + $package = PluginPackage::load(file_get_contents($_FILES["pluginpackage"]["tmp_name"])); + unlink($_FILES["pluginpackage"]["tmp_name"]); + if(in_array($package->api, $api_compat)) + { + $plugin = Plugin::create(); + $plugin->fill_from_pluginpackage($package); + $plugin->installed = False; + $plugin->active = False; + $plugin->save(); + $url_next = array("confirminstall", (string) $plugin->get_id()); + return; + } + else + $ste->vars["error"] = str_replace("[[API]]", $package->api, $translation["incompatible_plugin"]); + } + catch(InvalidPackage $e) + { + $ste->vars["error"] = $translation["invalid_package"]; + unlink($_FILES["pluginpackage"]["tmp_name"]); + } + } + else + $ste->vars["error"] = $translation["upload_failed"]; + } + + echo $ste->exectemplate("systemtemplates/plugininstall.html"); + }, + "confirminstall" => function(&$data, $url_now, &$url_next) + { + global $ste, $translation, $languages, $rel_path_to_root; + + list($plugin_id) = $url_next; + $url_next = array(); + + $ste->vars["section"] = "plugins"; + $ste->vars["submenu"] = "installplugins"; + $ste->vars["pagetitle"] = $translation["menu_plugininstall"]; + + try + { + $plugin = Plugin::by_id($plugin_id); + } + catch(DoesNotExistError $e) + { + throw new NotFoundError(); + } + + if($plugin->installed) + throw new NotFoundError(); + + $ste->vars["plugin_id"] = $plugin->get_id(); + $ste->vars["name"] = $plugin->name; + $ste->vars["description"] = $plugin->short_description; + $ste->vars["code"] = $plugin->code; + $ste->vars["license"] = $plugin->license; + + if(isset($_POST["yes"])) + { + $plugin->installed = True; + $plugin->save(); + eval($plugin->code); + $plugin_instance = new $plugin->classname($plugin->get_id()); + $plugin_instance->install(); + $ste->vars["success"] = $translation["plugin_installed_successfully"]; + $url_next = array("list"); + return; + } + + if(isset($_POST["no"])) + { + $plugin->delete(); + $url_next = array("install"); + return; + } + + echo $ste->exectemplate("systemtemplates/confirminstall.html"); + } + )), + "pluginpages" => url_action_subactions($pluginpages_handlers) )); ?> diff --git a/ratatoeskr/main.php b/ratatoeskr/main.php index d3be695..2a31177 100644 --- a/ratatoeskr/main.php +++ b/ratatoeskr/main.php @@ -18,9 +18,11 @@ require_once(dirname(__FILE__) . "/sys/plugin_api.php"); require_once(dirname(__FILE__) . "/frontend.php"); require_once(dirname(__FILE__) . "/backend.php"); +$plugin_objs = array(); + function ratatoeskr() { - global $backend_subactions, $ste, $url_handlers, $ratatoeskr_settings; + global $backend_subactions, $ste, $url_handlers, $ratatoeskr_settings, $plugin_objs; session_start(); if(!CONFIG_FILLED_OUT) return setup(); @@ -30,13 +32,18 @@ function ratatoeskr() clean_database(); $activeplugins = array_filter(Plugin::all(), function($plugin) { return $plugin->active; }); - $plugin_objs = array(); foreach($activeplugins as $plugin) { - eval($plugin->phpcode); - $plugin_obj = new $plugin->class; + eval($plugin->code); + $plugin_obj = new $plugin->classname($plugin->get_id()); + if($plugin->update) + { + $plugin_obj->update(); + $plugin->update = False; + $plugin->save(); + } $plugin_obj->init(); - $plugin_objs[] = $plugin_obj; + $plugin_objs[$plugin->get_id()] = $plugin_obj; } /* Register URL handlers */ diff --git a/ratatoeskr/setup/create_tables.php b/ratatoeskr/setup/create_tables.php index 543a7e3..dd37d5a 100644 --- a/ratatoeskr/setup/create_tables.php +++ b/ratatoeskr/setup/create_tables.php @@ -61,7 +61,7 @@ CREATE TABLE `PREFIX_multilingual` ( PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; -CREATE TABLE `ratatoeskr_plugins` ( +CREATE TABLE `PREFIX_plugins` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` text COLLATE utf8_unicode_ci NOT NULL, `author` text COLLATE utf8_unicode_ci NOT NULL, @@ -70,14 +70,16 @@ CREATE TABLE `ratatoeskr_plugins` ( `short_description` text COLLATE utf8_unicode_ci NOT NULL, `updatepath` text COLLATE utf8_unicode_ci NOT NULL, `web` text COLLATE utf8_unicode_ci NOT NULL, + `license` text COLLATE utf8_unicode_ci NOT NULL, `help` text COLLATE utf8_unicode_ci NOT NULL, `code` text COLLATE utf8_unicode_ci NOT NULL, `classname` text COLLATE utf8_unicode_ci NOT NULL, `active` tinyint(4) NOT NULL, `installed` tinyint(4) NOT NULL, `added` bigint(20) NOT NULL, + `update` tinyint(4) NOT NULL, PRIMARY KEY (`id`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; +) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; CREATE TABLE `PREFIX_plugin_kvstorage` ( `plugin` int(11) NOT NULL, diff --git a/ratatoeskr/sys/models.php b/ratatoeskr/sys/models.php index f744fbf..a0a1fda 100644 --- a/ratatoeskr/sys/models.php +++ b/ratatoeskr/sys/models.php @@ -1179,6 +1179,7 @@ class Plugin * $help - Help page. * $license - License text. * $installed - Is this plugin installed? Used during the installation process. + * $update - Should the plugin be updated at next start? */ public $name; @@ -1194,6 +1195,7 @@ class Plugin public $help; public $license; public $installed; + public $update; private function __construct() { } @@ -1223,6 +1225,35 @@ class Plugin return $obj; } + /* + * Function: fill_from_pluginpackage + * Fills plugin data from an object. + * + * Parameters: + * $pkg - The object. + */ + public function fill_from_pluginpackage($pkg) + { + $this->name = $pkg->name; + $this->code = $pkg->code; + $this->classname = $pkg->classname; + $this->author = $pkg->author; + $this->versiontext = $pkg->versiontext; + $this->versioncount = $pkg->versioncount; + $this->short_description = $pkg->short_description; + $this->updatepath = $pkg->updatepath; + $this->web = $pkg->web; + $this->license = $pkg->license; + $this->help = $pkg->help; + + if(!empty($pkg->custompub)) + array2dir($pkg->custompub, dirname(__FILE__) . "/../plugin_extradata/public/" . $this->get_id()); + if(!empty($pkg->custompriv)) + array2dir($pkg->custompriv, dirname(__FILE__) . "/../plugin_extradata/private/" . $this->get_id()); + if(!empty($pkg->tpls)) + array2dir($pkg->tpls, dirname(__FILE__) . "/../templates/srv/plugintemplates/" . $this->get_id()); + } + /* * Constructor: by_id * Gets plugin by ID. @@ -1234,25 +1265,26 @@ class Plugin { $obj = new self; - $result = qdb("SELECT `name`, `author`, `versiontext`, `versioncount`, `short_description`, `updatepath`, `web`, `help`, `code`, `classname`, `active`, `license`, `installed` FROM `PREFIX_plugins` WHERE `id` = %d", $id); + $result = qdb("SELECT `name`, `author`, `versiontext`, `versioncount`, `short_description`, `updatepath`, `web`, `help`, `code`, `classname`, `active`, `license`, `installed`, `update` FROM `PREFIX_plugins` WHERE `id` = %d", $id); $sqlrow = mysql_fetch_assoc($result); if($sqlrow === False) throw new DoesNotExistError(); - $this->id = $id; - $this->name = $sqlrow["name"]; - $this->code = $sqlrow["code"]; - $this->classname = $sqlrow["classname"]; - $this->active = ($sqlrow["active"] == 1); - $this->author = $sqlrow["author"]; - $this->versiontext = $sqlrow["versiontext"]; - $this->versioncount = $sqlrow["versioncount"]; - $this->short_description = $sqlrow["short_description"]; - $this->updatepath = $sqlrow["updatepath"]; - $this->web = $sqlrow["web"]; - $this->help = $sqlrow["help"]; - $this->license = $sqlrow["license"]; - $this->installed = ($sqlrow["installed"] == 1); + $obj->id = $id; + $obj->name = $sqlrow["name"]; + $obj->code = $sqlrow["code"]; + $obj->classname = $sqlrow["classname"]; + $obj->active = ($sqlrow["active"] == 1); + $obj->author = $sqlrow["author"]; + $obj->versiontext = $sqlrow["versiontext"]; + $obj->versioncount = $sqlrow["versioncount"]; + $obj->short_description = $sqlrow["short_description"]; + $obj->updatepath = $sqlrow["updatepath"]; + $obj->web = $sqlrow["web"]; + $obj->help = $sqlrow["help"]; + $obj->license = $sqlrow["license"]; + $obj->installed = ($sqlrow["installed"] == 1); + $obj->update = ($sqlrow["update"] == 1); return $obj; } @@ -1278,8 +1310,8 @@ class Plugin */ public function save() { - qdb("UPDATE `PREFIX_plugins` SET `name` = '%s', `code` = '%s', `classname` = '%s', `active` = %d, `versiontext` = '%s', `versioncount` = %d, `short_description` = '%s', `updatepath` = '%s', `web` = '%s', `help` = '%s', `installed` = %d, `license` = '%s' WHERE `id` = %d", - $this->name, $this->code, $this->classname, ($this->active ? 1 : 0), $this->versiontext, $this->versioncount, $this->short_description, $this>updatepath, $this->web, $this->help, ($this->installed ? 1 : 0), $this->license, $this->id); + qdb("UPDATE `PREFIX_plugins` SET `name` = '%s', `author` = '%s', `code` = '%s', `classname` = '%s', `active` = %d, `versiontext` = '%s', `versioncount` = %d, `short_description` = '%s', `updatepath` = '%s', `web` = '%s', `help` = '%s', `installed` = %d, `update` = %d, `license` = '%s' WHERE `id` = %d", + $this->name, $this>author, $this->code, $this->classname, ($this->active ? 1 : 0), $this->versiontext, $this->versioncount, $this->short_description, $this->updatepath, $this->web, $this->help, ($this->installed ? 1 : 0), ($this->update ? 1 : 0), $this->license, $this->id); } /* @@ -1288,6 +1320,7 @@ class Plugin public function delete() { qdb("DELETE FROM `PREFIX_plugins` WHERE `id` = %d", $this->id); + qdb("DELETE FROM `PREFIX_plugin_kvstorage` WHERE `plugin` = %d", $this->id); if(is_dir(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/private/" . $this->id)) delete_directory(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/private/" . $this->id); if(is_dir(SITE_BASE_PATH . "/ratatoeskr/plugin_extradata/public/" . $this->id)) diff --git a/ratatoeskr/sys/plugin_api.php b/ratatoeskr/sys/plugin_api.php index 362fd9e..f34a42a 100644 --- a/ratatoeskr/sys/plugin_api.php +++ b/ratatoeskr/sys/plugin_api.php @@ -15,7 +15,7 @@ require_once(dirname(__FILE__) . "/../frontend.php"); /* * Constant: APIVERSION - * The current API version. + * The current API version (1). */ define("APIVERSION", 1); diff --git a/ratatoeskr/sys/pluginpackage.php b/ratatoeskr/sys/pluginpackage.php index 0200c79..d8ce170 100644 --- a/ratatoeskr/sys/pluginpackage.php +++ b/ratatoeskr/sys/pluginpackage.php @@ -38,6 +38,29 @@ function dir2array($dir) return $rv; } +/* + * Function: array2dir + * Unpack an array into a directory. + * + * Parameters: + * $a - Array to unpack. + * $dir - Directory to unpack to. + */ +function array2dir($a, $dir) +{ + if(!is_dir($dir)) + mkdir($dir); + + foreach($a as $k => $v) + { + $k = "$dir/$k"; + if(is_array($v)) + array2dir($v, $k); + else + file_put_contents($k, $v); + } +} + /* * Class: InvalidPackage * An Exception that 's function can throw, if the package is invalid. @@ -99,7 +122,7 @@ class PluginPackage */ public function validate() { - function validate_url ($u) { return preg_match("/^http[s]{0,1}://.*$/", $u) != 0; } + function validate_url ($u) { return preg_match("/^http[s]{0,1}:\\/\\/.*$/", $u) != 0; } function validate_arraydir($a) { if(!is_array($a)) @@ -177,7 +200,7 @@ class PluginPackage throw new InvalidPackage("Wrong SHA1 hash"); $plugin = @unserialize($pluginser); - if(!($plugin instanceof this)) + if(!($plugin instanceof self)) throw new InvalidPackage("Not the correct class or not unserializeable."); $plugin->validate(); @@ -198,8 +221,8 @@ class PluginPackage public function save() { $this->validate(); - $ser = serialize($self); - return this::$magic . sha1($ser, True) . gzcompress($ser, 9); + $ser = serialize($this); + return self::$magic . sha1($ser, True) . gzcompress($ser, 9); } /* diff --git a/ratatoeskr/templates/src/systemtemplates/confirminstall.html b/ratatoeskr/templates/src/systemtemplates/confirminstall.html new file mode 100644 index 0000000..fdd15af --- /dev/null +++ b/ratatoeskr/templates/src/systemtemplates/confirminstall.html @@ -0,0 +1,26 @@ + + +

$name

+ + $description + +

+
$code
+ + + $license + +

+
$license
+
+
+ +

+
+ +
+
+ + +
+
diff --git a/ratatoeskr/templates/src/systemtemplates/pluginhelp.html b/ratatoeskr/templates/src/systemtemplates/pluginhelp.html new file mode 100644 index 0000000..c1e748a --- /dev/null +++ b/ratatoeskr/templates/src/systemtemplates/pluginhelp.html @@ -0,0 +1,4 @@ + + + $help + diff --git a/ratatoeskr/templates/src/systemtemplates/plugininstall.html b/ratatoeskr/templates/src/systemtemplates/plugininstall.html new file mode 100644 index 0000000..039feef --- /dev/null +++ b/ratatoeskr/templates/src/systemtemplates/plugininstall.html @@ -0,0 +1,18 @@ + + + $success + +
$success
+
+
+ $error + +
$error
+
+
+ +

+
+ +
+
diff --git a/ratatoeskr/templates/src/systemtemplates/pluginlist.html b/ratatoeskr/templates/src/systemtemplates/pluginlist.html new file mode 100644 index 0000000..ea01335 --- /dev/null +++ b/ratatoeskr/templates/src/systemtemplates/pluginlist.html @@ -0,0 +1,66 @@ + + + $success + +
$success
+
+
+ $error + +
$error
+
+
+ +
+ + + + + + + + + + + + + + + + + ~{$plugins_n|gt|0} + + + + + + + + + + + + + + + + + + + +
 
$p[name]$p[versiontext]?{$p[active]||}$p[description]$p[author]?{$p[web]|$p[web]|}?{$p[help]||}
+
+ + + | + + | + + | + +
+
+
diff --git a/ratatoeskr/translations/en.php b/ratatoeskr/translations/en.php index 80b9806..fb96479 100644 --- a/ratatoeskr/translations/en.php +++ b/ratatoeskr/translations/en.php @@ -201,7 +201,30 @@ $translation = array( "mail_address" => "Mail Address", "new_password" => "New password", "successfully_modified_user" => "Successfully modified user.", - "successfully_set_new_password" => "Successfully set new password." + "successfully_set_new_password" => "Successfully set new password.", + "plugin_name" => "Name", + "plugin_version" => "Version", + "plugin_isactive" => "Active", + "plugin_description" => "Description", + "plugin_author" => "Author", + "plugin_web" => "Web", + "plugin_help" => "Help", + "plugin_update" => "Update", + "plugin_activate" => "Activate", + "plugin_deactivate" => "Deactivate", + "no_plugins" => "No plugins installed", + "install_from_package" => "Install from package", + "invalid_package" => "Invalid package", + "incompatible_plugin" => "This plugin is not comatible wit this version of Ratatöskr. It requires the API version [[API]] or a compatible one.", + "plugin_safety_warning" => "Never install plugins you do not trust! Plugins have a lot of power and could potentially destroy your Ratatöskr installation!", + "plugin_src" => "Source code", + "license" => "License", + "plugin_installed_successfully" => "Plugin successfully installed.", + "successfully_deleted_plugins" => "Successfully deleted plugins.", + "plugins_activated" => "Plugins activated.", + "plugins_deactivated" => "Plugins deactivated.", + "successfully_updated_plugins" => "These plugins were updated: [[PLUGINS]]", + "nothing_to_update" => "Nothing to update." ); ?> -- cgit v1.2.3-70-g09d2