# HG changeset patch # User Dan # Date 1207510239 14400 # Node ID 94214ec0871c91c8e1857151bbfcf5a88f33d001 # Parent 2b826f2640e931bcaf92e5a546650ac7e4986690 Started work on the new plugin manager and associated management code. Very incomplete at this point and not usable. diff -r 2b826f2640e9 -r 94214ec0871c includes/functions.php --- a/includes/functions.php Sun Apr 06 14:02:20 2008 -0400 +++ b/includes/functions.php Sun Apr 06 15:30:39 2008 -0400 @@ -4078,6 +4078,17 @@ } /** + * Trims a snippet of text to the first and last curly braces. Useful for JSON. + * @param string Text to trim + * @return string + */ + +function enano_trim_json($json) +{ + return preg_replace('/^([^{]+)\{/', '{', preg_replace('/\}([^}]+)$/', '}', $json)); +} + +/** * Starts the profiler. */ diff -r 2b826f2640e9 -r 94214ec0871c includes/lang.php --- a/includes/lang.php Sun Apr 06 14:02:20 2008 -0400 +++ b/includes/lang.php Sun Apr 06 15:30:39 2008 -0400 @@ -389,8 +389,7 @@ $contents =& $block[0]['value']; // Trim off all text before and after the starting and ending braces - $contents = preg_replace('/^([^{]+)\{/', '{', $contents); - $contents = preg_replace('/\}([^}]+)$/', '}', $contents); + $contents = enano_trim_json($contents); // Correct syntax to be nice to the json parser $contents = enano_clean_json($contents); diff -r 2b826f2640e9 -r 94214ec0871c includes/plugins.php --- a/includes/plugins.php Sun Apr 06 14:02:20 2008 -0400 +++ b/includes/plugins.php Sun Apr 06 15:30:39 2008 -0400 @@ -224,9 +224,22 @@ if ( is_string($type) && $blocks[1][$i] !== $type ) continue; + $value =& $blocks[4][$i]; + // parse includes + preg_match_all('/^!include [\'"]?(.+?)[\'"]?$/m', $value, $includes); + foreach ( $includes[0] as $i => $replace ) + { + $filename = ENANO_ROOT . '/' . $includes[1][$i]; + if ( @file_exists( $filename ) && @is_readable( $filename ) ) + { + $contents = @file_get_contents($filename); + $value = str_replace_once($replace, $contents, $value); + } + } + $el = self::parse_vars($blocks[2][$i]); $el['block'] = $blocks[1][$i]; - $el['value'] = $blocks[4][$i]; + $el['value'] = $value; $return[] = $el; } diff -r 2b826f2640e9 -r 94214ec0871c install/schemas/mysql_stage2.sql --- a/install/schemas/mysql_stage2.sql Sun Apr 06 14:02:20 2008 -0400 +++ b/install/schemas/mysql_stage2.sql Sun Apr 06 15:30:39 2008 -0400 @@ -318,6 +318,17 @@ PRIMARY KEY ( key_id ) ) CHARACTER SET `utf8` COLLATE `utf8_bin`; +-- Added in 1.1.4 +-- This is really honestly a better way to handle plugins. + +CREATE TABLE {{TABLE_PREFIX}}plugins ( + plugin_id int(12) NOT NULL auto_increment, + plugin_filename varchar(63), + plugin_flags int(12), + plugin_version varchar(16), + PRIMARY KEY ( plugin_id ) +) ENGINE `MyISAM` CHARACTER SET `utf8` COLLATE `utf8_bin`; + INSERT INTO {{TABLE_PREFIX}}config(config_name, config_value) VALUES ('site_name', '{{SITE_NAME}}'), ('main_page', 'Main_Page'), @@ -335,10 +346,6 @@ ('w3c_vcss', '0'), ('approve_comments', '0'), ('enable_comments', '1'), - ('plugin_SpecialAdmin.php', '1'), - ('plugin_SpecialPageFuncs.php', '1'), - ('plugin_SpecialUserFuncs.php', '1'), - ('plugin_SpecialCSS.php', '1'), ('copyright_notice', '{{COPYRIGHT}}'), ('wiki_edit_notice_text', '== Why can I edit this page? ==\n\nEveryone can edit almost any page in this website. This concept is called a wiki. It gives everyone the opportunity to make a change for the best. While some spam and vandalism may occur, it is believed that most contributions will be legitimate and helpful.\n\nFor security purposes, a history of all page edits is kept, and administrators are able to restore vandalized or spammed pages with just a few clicks.'), ('cache_thumbs', '{{ENABLE_CACHE}}'), diff -r 2b826f2640e9 -r 94214ec0871c install/schemas/postgresql_stage2.sql --- a/install/schemas/postgresql_stage2.sql Sun Apr 06 14:02:20 2008 -0400 +++ b/install/schemas/postgresql_stage2.sql Sun Apr 06 15:30:39 2008 -0400 @@ -315,6 +315,17 @@ PRIMARY KEY ( key_id ) ); +-- Added in 1.1.4 +-- This is really honestly a better way to handle plugins. + +CREATE TABLE {{TABLE_PREFIX}}plugins ( + plugin_id SERIAL, + plugin_filename varchar(63), + plugin_flags int, + plugin_version varchar(16), + PRIMARY KEY ( plugin_id ) +); + INSERT INTO {{TABLE_PREFIX}}config(config_name, config_value) VALUES ('site_name', '{{SITE_NAME}}'), ('main_page', 'Main_Page'), diff -r 2b826f2640e9 -r 94214ec0871c install/schemas/upgrade/1.1.3-1.1.4-mysql.sql --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/install/schemas/upgrade/1.1.3-1.1.4-mysql.sql Sun Apr 06 15:30:39 2008 -0400 @@ -0,0 +1,10 @@ +-- This is really honestly a better way to handle plugins. + +CREATE TABLE {{TABLE_PREFIX}}plugins ( + plugin_id int(12) NOT NULL auto_increment, + plugin_filename varchar(63), + plugin_flags int(12), + plugin_version varchar(16), + PRIMARY KEY ( plugin_id ) +) ENGINE `MyISAM` CHARACTER SET `utf8` COLLATE `utf8_bin`; + diff -r 2b826f2640e9 -r 94214ec0871c install/schemas/upgrade/1.1.3-1.1.4-postgresql.sql --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/install/schemas/upgrade/1.1.3-1.1.4-postgresql.sql Sun Apr 06 15:30:39 2008 -0400 @@ -0,0 +1,9 @@ +-- This is really honestly a better way to handle plugins. + +CREATE TABLE {{TABLE_PREFIX}}plugins ( + plugin_id SERIAL, + plugin_filename varchar(63), + plugin_flags int, + plugin_version varchar(16), + PRIMARY KEY ( plugin_id ) +); diff -r 2b826f2640e9 -r 94214ec0871c language/english/admin.json --- a/language/english/admin.json Sun Apr 06 14:02:20 2008 -0400 +++ b/language/english/admin.json Sun Apr 06 15:30:39 2008 -0400 @@ -382,24 +382,7 @@ msg_demo_mode: 'Hmm, enabling executables, are we? Tsk tsk. I\'d love to know what\'s in that EXE file you want to upload. OK, maybe you didn\'t enable EXEs. But nevertheless, changing allowed filetypes is disabled in the demo.', }, acppl: { - err_heading: 'Error disabling plugin', - err_demo_plugin: 'The demo lockdown plugin cannot be disabled in demo mode.', - err_system_plugin: 'The plugin you selected cannot be disabled because it is a system plugin.', - err_open_dir: 'The plugins/ directory could not be opened.', - err_missing_dir: 'The plugins/ directory is missing from your Enano installation.', - col_filename: 'Plugin filename', - col_name: 'Plugin name', - col_description: 'Description', - col_author: 'Author', - col_version: 'Version', - btn_enable: 'Enable', - btn_disable: 'Disable', - btn_reimport: 'Re-import', - btn_reimport_tip: 'Reloads all the language and meta data from this plugin file.', - msg_reimport_success: 'All language strings from this plugin have been re-imported.', - btn_hide_system: 'Hide system plugins', - btn_show_system: 'Show system plugins', - lbl_system_plugin: '[System]', + }, acppm: { heading_main: 'Edit page properties', diff -r 2b826f2640e9 -r 94214ec0871c plugins/PrivateMessages.php --- a/plugins/PrivateMessages.php Sun Apr 06 14:02:20 2008 -0400 +++ b/plugins/PrivateMessages.php Sun Apr 06 15:30:39 2008 -0400 @@ -1,12 +1,14 @@ '.$showhide_link.''; echo ''; } +*/ function page_Admin_DBBackup() { diff -r 2b826f2640e9 -r 94214ec0871c plugins/SpecialCSS.php --- a/plugins/SpecialCSS.php Sun Apr 06 14:02:20 2008 -0400 +++ b/plugins/SpecialCSS.php Sun Apr 06 15:30:39 2008 -0400 @@ -1,12 +1,14 @@ + /**!blocktype( param1 = "value1" [ param2 = "value2" ... ] )** + + ... block content ... + + **!* / (remove that last space) + + * The format inside blocks varies. Metadata and language strings will be in JSON; installation and upgrade schemas will be in + * SQL. You can include an external file into a block using the following syntax inside of a block: + + !include "path/to/file" + + * The file will always be relative to the Enano root. So if your plugin has a language file in ENANO_ROOT/plugins/fooplugin/, + * you would use "plugins/fooplugin/language.json". + * + * The format for plugin metadata is as follows: + + /**!info** + { + "Plugin Name" : "Foo plugin", + "Plugin URI" : "http://fooplugin.enanocms.org/", + "Description" : "Some short descriptive text", + "Author" : "John Doe", + "Version" : "0.1", + "Author URI" : "http://yourdomain.com/", + "Version list" : [ "0.1-alpha1", "0.1-alpha2", "0.1-beta1", "0.1" ] + } + **!* / + + * This is the format for language data: + + /**!language** + { + eng: { + categories: [ 'meta', 'foo', 'bar' ], + strings: { + meta: { + foo: "Foo strings", + bar: "Bar strings" + }, + foo: { + string_name: "string value", + string_name_2: "string value 2" + } + } + } + } + **!* / (once more, remove the space in there) + + * Here is the format for installation schemas: + + /**!install** + + CREATE TABLE {{TABLE_PREFIX}}foo_table( + ... + ) + + **!* / + + * And finally, the format for upgrade schemas: + + /**!upgrade from = "0.1-alpha1" to = "0.1-alpha2" ** + + **!* / + + * Remember that upgrades will always be done incrementally, so if the user is upgrading 0.1-alpha2 to 0.1, Enano's plugin + * engine will run the 0.1-alpha2 to 0.1-beta1 upgrader, then the 0.1-beta1 to 0.1 upgrader, going by the versions listed in + * the example metadata block above. + * + * All of this information is effective as of Enano 1.1.4. + */ + +// Plugin manager "2.0" + +function page_Admin_PluginManager() +{ + global $db, $session, $paths, $template, $plugins; // Common objects + global $lang; + if ( $session->auth_level < USER_LEVEL_ADMIN || $session->user_level < USER_LEVEL_ADMIN ) + { + $login_link = makeUrlNS('Special', 'Login/' . $paths->nslist['Special'] . 'Administration', 'level=' . USER_LEVEL_ADMIN, true); + echo '

' . $lang->get('adm_err_not_auth_title') . '

'; + echo '

' . $lang->get('adm_err_not_auth_body', array( 'login_link' => $login_link )) . '

'; + return; + } + + // Are we processing an AJAX request from the smartform? + if ( $paths->getParam(0) == 'action.json' ) + { + // Set to application/json to discourage advertisement scripts + header('Content-Type: application/json'); + + // Init return data + $return = array('mode' => 'error', 'error' => 'undefined'); + + // Start parsing process + try + { + // Is the request properly sent on POST? + if ( isset($_POST['r']) ) + { + // Try to decode the request + $request = enano_json_decode($_POST['r']); + // Is the action to perform specified? + if ( isset($request['mode']) ) + { + switch ( $request['mode'] ) + { + default: + // The requested action isn't something this script knows how to do + $return = array( + 'mode' => 'error', + 'error' => 'Unknown mode "' . $request['mode'] . '" sent in request' + ); + break; + } + } + else + { + // Didn't specify action + $return = array( + 'mode' => 'error', + 'error' => 'Missing key "mode" in request' + ); + } + } + else + { + // Didn't send a request + $return = array( + 'mode' => 'error', + 'error' => 'No request specified' + ); + } + } + catch ( Exception $e ) + { + // Sent a request but it's not valid JSON + $return = array( + 'mode' => 'error', + 'error' => 'Invalid request - JSON parsing failed' + ); + } + + echo enano_json_encode($return); + + return true; + } + + // + // Not a JSON request, output normal HTML interface + // + + // Scan all plugins + $plugin_list = array(); + + if ( $dirh = @opendir( ENANO_ROOT . '/plugins' ) ) + { + while ( $dh = @readdir($dirh) ) + { + if ( !preg_match('/\.php$/i', $dh) ) + continue; + $fullpath = ENANO_ROOT . "/plugins/$dh"; + // it's a PHP file, attempt to read metadata + // pass 1: try to read a !info block + $blockdata = $plugins->parse_plugin_blocks($fullpath, 'info'); + if ( empty($blockdata) ) + { + // no !info block, check for old header + $fh = @fopen($fullpath, 'r'); + if ( !$fh ) + // can't read, bail out + continue; + $plugin_data = array(); + for ( $i = 0; $i < 8; $i++ ) + { + $plugin_data[] = @fgets($fh, 8096); + } + // close our file handle + fclose($fh); + // is the header correct? + if ( trim($plugin_data[0]) != ' $value ) + { + $plugin_meta[ strtolower($key) ] = $value; + } + } + if ( !isset($plugin_meta) || !is_array(@$plugin_meta) ) + { + // parsing didn't work. + continue; + } + // check for required keys + $required_keys = array('plugin name', 'plugin uri', 'description', 'author', 'version', 'author uri'); + foreach ( $required_keys as $key ) + { + if ( !isset($plugin_meta[$key]) ) + // not set, skip this plugin + continue 2; + } + // all checks passed + $plugin_list[$dh] = $plugin_meta; + } + } + echo '
' . print_r($plugin_list, true) . '
'; +}