From afd0f8e4d8ff0a37d1a337f160eeae642a2f07d6 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 12:51:36 +0200 Subject: [PATCH 01/20] load $a->config from db --- index.php | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/index.php b/index.php index 534cb93f7c..9bca1527bf 100644 --- a/index.php +++ b/index.php @@ -29,7 +29,6 @@ $install = ((file_exists('.htconfig.php') && filesize('.htconfig.php')) ? false @include(".htconfig.php"); - $lang = get_language(); load_translation_table($lang); @@ -45,6 +44,20 @@ $db = new dba($db_host, $db_user, $db_pass, $db_data, $install); unset($db_host, $db_user, $db_pass, $db_data); +/** + * Load configs from db. Overwrite configs from .htconfig.php + */ +$r = q("SELECT * FROM `config` WHERE `cat` IN ('system', 'config')"); +foreach ($r as $c) { + if ($c['cat']=='config') { + $a->config[$c['k']] = $c['v']; + } else { + $a->config[$c['cat']][$c['k']] = $c['v']; + } +} +unset($r); + + /** * * Important stuff we always need to do. From 3364c2a2d8ab88703c5566a39df13ef1042f8644 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 12:52:29 +0200 Subject: [PATCH 02/20] Initial admin page --- mod/admin.php | 105 +++++++++++++++++++++++++++++++++++++++++ view/admin_aside.tpl | 20 ++++++++ view/admin_summary.tpl | 33 +++++++++++++ 3 files changed, 158 insertions(+) create mode 100644 mod/admin.php create mode 100644 view/admin_aside.tpl create mode 100644 view/admin_summary.tpl diff --git a/mod/admin.php b/mod/admin.php new file mode 100644 index 0000000000..13131f0135 --- /dev/null +++ b/mod/admin.php @@ -0,0 +1,105 @@ + Array($a->get_baseurl()."/admin/site/", t("Site") , "site"), + 'users' => Array($a->get_baseurl()."/admin/users/", t("Users") , "users"), + 'plugins'=> Array($a->get_baseurl()."/admin/plugins/", t("Plugins") , "plugins") + ); + + /* get plugins admin page */ + + $r = q("SELECT * FROM `hook` WHERE `hook`='plugin_admin'"); + $aside['plugins_admin']=Array(); + foreach ($r as $h){ + $plugin = explode("/",$h['file']); $plugin = $plugin[1]; + $aside['plugins_admin'][] = Array($a->get_baseurl()."/admin/plugins/".$plugin, $plugin, "plugin"); + } + + $aside['logs'] = Array($a->get_baseurl()."/admin/logs/", t("Logs"), "logs"); + + $t = get_markup_template("admin_aside.tpl"); + $a->page['aside'] = replace_macros( $t, array('$admin' => $aside) ); + + + + /** + * Page content + */ + $o = ''; + + // urls + if ($a->argc > 1){ + switch ($a->argv[1]){ + case 'site': { + $o = admin_page_site($a); + break; + } + default: + notice( t("Item not found.") ); + } + } else { + $o = admin_page_summary($a); + } + return $o; +} + + +/** + * Admin Summary Page + */ +function admin_page_summary(&$a) { + $r = q("SELECT `page-flags`, COUNT(uid) as `count` FROM `user` GROUP BY `page-flags`"); + $accounts = Array( + Array( t('Normal Account'), 0), + Array( t('Soapbox Account'), 0), + Array( t('Community/Celebrity Account'), 0), + Array( t('Automatic Friend Account'), 0) + ); + $users=0; + foreach ($r as $u){ $accounts[$u['page-flags']][1] = $u['count']; $users+=$u['count']; } + + //echo "
"; var_dump($a->plugins); die("
"); + + + $r = q("SELECT COUNT(id) as `count` FROM `register`"); + $pending = $r[0]['count']; + + + + + + $t = get_markup_template("admin_summary.tpl"); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Summary'), + '$users' => Array( t('Registered users'), $users), + '$accounts' => $accounts, + '$pending' => Array( t('Pending registrations'), $pending), + '$version' => Array( t('Version'), FRIENDIKA_VERSION), + '$build' => get_config('system','build'), + '$plugins' => Array( t('Active plugins'), $a->plugins ) + )); +} diff --git a/view/admin_aside.tpl b/view/admin_aside.tpl new file mode 100644 index 0000000000..24aafa7751 --- /dev/null +++ b/view/admin_aside.tpl @@ -0,0 +1,20 @@ +

Admin

+ + + +{{ if $admin.plugins_admin }}

Plugins

{{ endif }} + + + +

Logs

+ diff --git a/view/admin_summary.tpl b/view/admin_summary.tpl new file mode 100644 index 0000000000..cbd659d071 --- /dev/null +++ b/view/admin_summary.tpl @@ -0,0 +1,33 @@ +

$title - $page

+ +
+
$users.0
+
$users.1
+
+{{ for $accounts as $p }} +
+
$p.0
+
$p.1
+
+{{ endfor }} + +
+
$pending.0
+
$pending.1 +
+ +
+
$version.0
+
$version.1 - $build +
+ + + +
+
$plugins.0
+ + {{ for $plugins.1 as $p }} +
$p
+ {{ endfor }} + +
From 494288ab9f9370bdf4f7b4ab9990b64f05adbd9d Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 12:52:52 +0200 Subject: [PATCH 03/20] Add admin page in nav --- include/nav.php | 9 +++++++-- view/nav.tpl | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/include/nav.php b/include/nav.php index 66fdbc49b2..5e50a8b79a 100644 --- a/include/nav.php +++ b/include/nav.php @@ -107,10 +107,15 @@ function nav(&$a) { $nav['settings'] = array('settings', t('Settings'),""); $nav['profiles'] = array('profiles', t('Profiles'),""); $nav['contacts'] = array('contacts', t('Contacts'),""); - - } + /** + * Admin page + */ + if (is_site_admin()){ + $nav['admin'] = array('admin/', t('Admin'), ""); + } + /** * diff --git a/view/nav.tpl b/view/nav.tpl index 7e76811d9e..79114749ad 100644 --- a/view/nav.tpl +++ b/view/nav.tpl @@ -16,6 +16,8 @@ $langselector $nav.search.1 $nav.directory.1 +{{ if $nav.admin }}$nav.admin.1{{ endif }} + {{ if $nav.network }} $nav.network.1 From a1c59d6011138ca2a0d366d1ea6f6369e679df81 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 12:53:03 +0200 Subject: [PATCH 04/20] Fix it strings --- view/it/strings.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/it/strings.php b/view/it/strings.php index 75459e23a0..32092a3f19 100644 --- a/view/it/strings.php +++ b/view/it/strings.php @@ -123,7 +123,7 @@ $a->strings["Administrator"] = "Amministratore"; $a->strings["Friend/Connection Request"] = "Richieste di Amicizia/Connessione"; $a->strings["Examples: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, testuser@identi.ca"] = "Esempi: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, testuser@identi.ca"; $a->strings["Please answer the following:"] = "Rispondi al seguente:"; -$a->strings["Does \$name know you?"] = "$name ti conosce?"; +$a->strings["Does \$name know you?"] = "\$name ti conosce?"; $a->strings["Yes"] = "Si"; $a->strings["No"] = "No"; $a->strings["Add a personal note:"] = "Aggiungi una nota personale:"; From e14d5851a76e73675800787dcbcc7582b4dbd5ed Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 12:53:41 +0200 Subject: [PATCH 05/20] fix template's {{ for }} variable lookup --- include/template_processor.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/template_processor.php b/include/template_processor.php index d8dfbaedb1..3dc249c403 100644 --- a/include/template_processor.php +++ b/include/template_processor.php @@ -58,7 +58,8 @@ list($keyname, $varname) = explode("=>",$m[1]); if (is_null($varname)) { $varname=$keyname; $keyname=""; } if ($m[0]=="" || $varname=="" || is_null($varname)) die("template error: 'for ".$m[0]." as ".$varname."'") ; - $vals = $this->r[$m[0]]; + //$vals = $this->r[$m[0]]; + $vals = $this->_get_var($m[0]); $ret=""; if (!is_array($vals)) return $ret; foreach ($vals as $k=>$v){ From f80521923d35d15dfd2f0ea24359a08a02638845 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 18:02:40 +0200 Subject: [PATCH 06/20] Add {{ if a==b }} and {{ if a!=b }} to templates --- include/template_processor.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/include/template_processor.php b/include/template_processor.php index 3dc249c403..a2c24b00bc 100644 --- a/include/template_processor.php +++ b/include/template_processor.php @@ -41,9 +41,24 @@ * IF node * * {{ if <$var> }}...{{ endif }} + * {{ if <$var>== }}...{{ endif }} + * {{ if <$var>!= }}...{{ endif }} */ private function _replcb_if($args){ - $val = $this->_get_var($args[2]); + + if (strpos($args[2],"==")>0){ + list($a,$b) = array_map("trim",explode("==",$args[2])); + $a = $this->_get_var($a); + if ($b[0]=="$") $b = $this->_get_var($b); + $val = ($a == $b); + } else if (strpos($args[2],"!=")>0){ + list($a,$b) = explode("!=",$args[2]); + $a = $this->_get_var($a); + if ($b[0]=="$") $b = $this->_get_var($b); + $val = ($a != $b); + } else { + $val = $this->_get_var($args[2]); + } return ($val?$args[3]:""); } From ab27f1393e72e8fa6c05db5948413beef9e0367f Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Mon, 13 Jun 2011 18:03:06 +0200 Subject: [PATCH 07/20] Admin site page --- mod/admin.php | 191 +++++++++++++++++++++++++++++- view/admin_aside.tpl | 2 +- view/admin_site.tpl | 45 +++++++ view/admin_summary.tpl | 59 ++++----- view/field.tpl | 4 + view/field_checkbox.tpl | 6 + view/field_input.tpl | 6 + view/field_select.tpl | 8 ++ view/field_textarea.tpl | 6 + view/theme/duepuntozero/style.css | 52 ++++++++ 10 files changed, 347 insertions(+), 32 deletions(-) create mode 100644 view/admin_site.tpl create mode 100644 view/field.tpl create mode 100644 view/field_checkbox.tpl create mode 100644 view/field_input.tpl create mode 100644 view/field_select.tpl create mode 100644 view/field_textarea.tpl diff --git a/mod/admin.php b/mod/admin.php index 13131f0135..70720f5d88 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -11,6 +11,24 @@ function admin_init(&$a) { } } +function admin_post(&$a){ + if(!is_site_admin()) { + return login(false); + } + + // urls + if ($a->argc > 1){ + switch ($a->argv[1]){ + case 'site': { + admin_page_site_post($a); + break; + } + } + } + + goaway($a->get_baseurl() . '/admin' ); + return; // NOTREACHED +} function admin_content(&$a) { @@ -41,7 +59,10 @@ function admin_content(&$a) { $aside['logs'] = Array($a->get_baseurl()."/admin/logs/", t("Logs"), "logs"); $t = get_markup_template("admin_aside.tpl"); - $a->page['aside'] = replace_macros( $t, array('$admin' => $aside) ); + $a->page['aside'] = replace_macros( $t, array( + '$admin' => $aside, + '$admurl'=> $a->get_baseurl()."/admin/" + )); @@ -81,8 +102,6 @@ function admin_page_summary(&$a) { $users=0; foreach ($r as $u){ $accounts[$u['page-flags']][1] = $u['count']; $users+=$u['count']; } - //echo "
"; var_dump($a->plugins); die("
"); - $r = q("SELECT COUNT(id) as `count` FROM `register`"); $pending = $r[0]['count']; @@ -103,3 +122,169 @@ function admin_page_summary(&$a) { '$plugins' => Array( t('Active plugins'), $a->plugins ) )); } + + +/** + * Admin Site Page + */ +function admin_page_site_post(&$a){ + if (!x($_POST,"page_site")){ + return; + } + + + $sitename = ((x($_POST,'sitename')) ? notags(trim($_POST['sitename'])) : ''); + $banner = ((x($_POST,'banner')) ? trim($_POST['banner']) : false); + $language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : ''); + $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : ''); + $maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0); + $allowed_sites = ((x($_POST,'allowed_sites')) ? notags(trim($_POST['allowed_sites'])) : ''); + $allowed_email = ((x($_POST,'allowed_email')) ? notags(trim($_POST['allowed_email'])) : ''); + $block_public = ((x($_POST,'block_public')) ? True : False); + $force_publish = ((x($_POST,'publish_all')) ? True : False); + $global_directory = ((x($_POST,'directory_submit_url')) ? notags(trim($_POST['directory_submit_url'])) : ''); + $global_search_url = ((x($_POST,'directory_search_url'))? notags(trim($_POST['directory_search_url'])) : ''); + $no_multi_reg = ((x($_POST,'no_multi_reg')) ? True : False); + $no_openid = ((x($_POST,'no_openid')) ? True : False); + $no_gravatar = ((x($_POST,'no_gravatar')) ? True : False); + $no_regfullname = ((x($_POST,'no_regfullname')) ? True : False); + $no_utf = ((x($_POST,'no_utf')) ? True : False); + $rino_enc = ((x($_POST,'rino_enc')) ? True : False); + $verifyssl = ((x($_POST,'verifyssl')) ? True : False); + $proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['global_search_url'])) : ''); + $proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['global_search_url'])) : ''); + $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['maximagesize'])) : 60); + + + $a->config['sitename'] = $sitename; + if ($banner==""){ + // don't know why, but del_config doesn't work... + q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", + dbesc("system"), + dbesc("banner") + ); + } else { + set_config('system','banner', $banner); + } + set_config('system','language', $language); + set_config('system','theme', $theme); + set_config('system','maximagesize', $maximagesize); + set_config('system','allowed_sites', $allowed_sites); + set_config('system','allowed_email', $allowed_email); + set_config('system','block_public', $block_public); + set_config('system','publish_all', $force_publish); + if ($global_directory==""){ + // don't know why, but del_config doesn't work... + q("DELETE FROM `config` WHERE `cat` = '%s' AND `k` = '%s' LIMIT 1", + dbesc("system"), + dbesc("directory_submit_url") + ); + } else { + set_config('system','directory_submit_url', $global_directory); + } + set_config('system','directory_search_url', $global_search_url); + set_config('system','block_extended_register', $no_multi_reg); + set_config('system','no_openid', $no_openid); + set_config('system','no_gravatar', $no_gravatar); + set_config('system','no_regfullname', $no_regfullname); + set_config('system','proxy', $no_utf); + set_config('system','rino_encrypt', $rino_enc); + set_config('system','verifyssl', $verifyssl); + set_config('system','proxyuser', $proxyuser); + set_config('system','proxy', $proxy); + set_config('system','curl_timeout', $timeout); + + $r = q("SELECT * FROM `config` WHERE `cat`='config' AND `k`='sitename'"); + if (count($r)>0){ + q("UPDATE `config` SET `v`='%s' WHERE `cat`='config' AND `k`='sitename'", + dbesc($a->config['sitename']) + ); + } else { + q("INSERT INTO `config` ( `cat`, `k`, `v` ) VALUES ( 'config', 'sitename', '%s' )", + dbesc($a->config['sitename']) + ); + } + + + + goaway($a->get_baseurl() . '/admin/site' ); + return; // NOTREACHED + +} + +function admin_page_site(&$a) { + + /* Installed langs */ + $lang_choices = array(); + $langs = glob('view/*/strings.php'); + + if(is_array($langs) && count($langs)) { + if(! in_array('view/en/strings.php',$langs)) + $langs[] = 'view/en/'; + asort($langs); + foreach($langs as $l) { + $t = explode("/",$l); + $lang_choices[$t[1]] = $t[1]; + } + } + + /* Installed themes */ + $theme_choices = array(); + $files = glob('view/theme/*'); + if($files) { + foreach($files as $file) { + $f = basename($file); + $theme_name = ((file_exists($file . '/experimental')) ? sprintf("%s - \x28Experimental\x29", $f) : $f); + $theme_choices[$f] = $theme_name; + } + } + + + /* Banner */ + $banner = get_config('system','banner'); + if($banner == false) + $banner = htmlspecialchars('logoFriendika'); + + //echo "
"; var_dump($lang_choices); die("
"); + + + + $t = get_markup_template("admin_site.tpl"); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Site'), + '$submit' => t('Submit'), + '$baseurl' => $a->get_baseurl(), + + // name, label, value, help string, extra data... + '$sitename' => array('sitename', t("Site name"), $a->config['sitename'], ""), + '$banner' => array('banner', t("Banner/Logo"), $banner, ""), + '$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices), + '$theme' => array('theme', t("System theme"), get_config('system','theme'), "Default system theme (which may be over-ridden by user profiles)", $theme_choices), + + '$maximagesize' => array('maximagesize', t("Maximum image size"), get_config('system','maximagesize'), "Maximum size in bytes of uploaded images. Default is 0, which means no limits."), + + '$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), "Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"), + '$allowed_email' => array('allowed_email', t("Allowed email domains"), get_config('system','allowed_email'), "Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"), + '$block_public' => array('block_public', t("Block public"), get_config('system','block_public'), "Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."), + '$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), "Check to force all profiles on this site to be listed in the site directory."), + '$global_directory' => array('directory_submit_url', t("Global directory update URL"), get_config('system','directory_submit_url'), "URL to update the global directory. If this is not set, the global directory is completely unavailable to the application."), + '$global_search_url'=> array('directory_search_url', t("Global directory search URL"), get_config('system','directory_search_url'), ""), + + + '$no_multi_reg' => array('no_multi_reg', t("Block multiple registrations"), get_config('system','block_extended_register'), "Disallow users to register additional accounts for use as pages."), + '$no_openid' => array('no_openid', t("No OpenID support"), get_config('system','no_openid'), "Disable OpenID support for registration and logins."), + '$no_gravatar' => array('no_gravatar', t("No Gravatar support"), get_config('system','no_gravatar'), ""), + '$no_regfullname' => array('no_regfullname', t("No fullname check"), get_config('system','no_regfullname'), "If unchecked, force users to registrate with a space between his firsname and lastname in Full name, as an antispam measure"), + '$no_utf' => array('no_utf', t("No UTF-8 Regular expressions"), get_config('system','proxy'), "Default is false (meaning UTF8 regular expressions are supported and working)"), + + '$rino_enc' => array('rino_enc', t("Enable Rino encrypt"), get_config('system','rino_encrypt'),""), + '$verifyssl' => array('verifyssl', t("Verify SSL"), get_config('system','verifyssl'), "If you wish, you can turn on strict certificate checking. This will mean you cannot connect (at all) to self-signed SSL sites."), + '$proxyuser' => array('proxyuser', t("Proxy user"), get_config('system','proxyuser'), ""), + '$proxy' => array('proxy', t("Proxy URL"), get_config('system','proxy'), ""), + '$timeout' => array('timeout', t("Network timeout"), (x(get_config('system','curl_timeout'))?get_config('system','curl_timeout'):60), "Value is in seconds. Set to 0 for unlimited (not recommended)."), + + + )); + +} diff --git a/view/admin_aside.tpl b/view/admin_aside.tpl index 24aafa7751..dd81a6fee3 100644 --- a/view/admin_aside.tpl +++ b/view/admin_aside.tpl @@ -1,4 +1,4 @@ -

Admin

+

Admin

    diff --git a/view/admin_site.tpl b/view/admin_site.tpl new file mode 100644 index 0000000000..f120461aa5 --- /dev/null +++ b/view/admin_site.tpl @@ -0,0 +1,45 @@ +
    +

    $title - $page

    + +
    + + {{ inc field_input.tpl with $field=$sitename }}{{ endinc }} + {{ inc field_textarea.tpl with $field=$banner }}{{ endinc }} + {{ inc field_select.tpl with $field=$language }}{{ endinc }} + {{ inc field_select.tpl with $field=$theme }}{{ endinc }} + +
    + +

    Upload

    + {{ inc field_input.tpl with $field=$maximagesize }}{{ endinc }} + +

    Corporate/Edu

    + {{ inc field_input.tpl with $field=$allowed_sites }}{{ endinc }} + {{ inc field_input.tpl with $field=$allowed_email }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$block_public }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$force_publish }}{{ endinc }} + {{ inc field_input.tpl with $field=$global_directory }}{{ endinc }} + {{ inc field_input.tpl with $field=$global_search_url }}{{ endinc }} + +
    + +

    Registration

    + {{ inc field_checkbox.tpl with $field=$no_multi_reg }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$no_openid }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$no_gravatar }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$no_regfullname }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$no_utf }}{{ endinc }} + +
    + +

    Advanced

    + {{ inc field_checkbox.tpl with $field=$rino_enc }}{{ endinc }} + {{ inc field_checkbox.tpl with $field=$verifyssl }}{{ endinc }} + {{ inc field_input.tpl with $field=$proxy }}{{ endinc }} + {{ inc field_input.tpl with $field=$proxyuser }}{{ endinc }} + {{ inc field_input.tpl with $field=$timeout }}{{ endinc }} + +
    + +
    +
    diff --git a/view/admin_summary.tpl b/view/admin_summary.tpl index cbd659d071..59428986a1 100644 --- a/view/admin_summary.tpl +++ b/view/admin_summary.tpl @@ -1,33 +1,36 @@ -

    $title - $page

    +
    +

    $title - $page

    -
    -
    $users.0
    -
    $users.1
    -
    -{{ for $accounts as $p }}
    -
    $p.0
    -
    $p.1
    +
    $pending.0
    +
    $pending.1
    -{{ endfor }} -
    -
    $pending.0
    -
    $pending.1 -
    - -
    -
    $version.0
    -
    $version.1 - $build -
    - - - -
    -
    $plugins.0
    - - {{ for $plugins.1 as $p }} -
    $p
    +
    +
    $users.0
    +
    $users.1
    +
    + {{ for $accounts as $p }} +
    +
    $p.0
    +
    $p.1
    +
    {{ endfor }} - -
    + + +
    +
    $plugins.0
    + + {{ for $plugins.1 as $p }} +
    $p
    + {{ endfor }} + +
    + +
    +
    $version.0
    +
    $version.1 - $build +
    + + +
    diff --git a/view/field.tpl b/view/field.tpl new file mode 100644 index 0000000000..35f5afd39c --- /dev/null +++ b/view/field.tpl @@ -0,0 +1,4 @@ + + {{ if $field.0==select }} + {{ inc field_select.tpl }}{{ endinc }} + {{ endif }} diff --git a/view/field_checkbox.tpl b/view/field_checkbox.tpl new file mode 100644 index 0000000000..4a86da7eaf --- /dev/null +++ b/view/field_checkbox.tpl @@ -0,0 +1,6 @@ + +
    + + + $field.3 +
    diff --git a/view/field_input.tpl b/view/field_input.tpl new file mode 100644 index 0000000000..748d93f3ee --- /dev/null +++ b/view/field_input.tpl @@ -0,0 +1,6 @@ + +
    + + + $field.3 +
    diff --git a/view/field_select.tpl b/view/field_select.tpl new file mode 100644 index 0000000000..d79eb48e0d --- /dev/null +++ b/view/field_select.tpl @@ -0,0 +1,8 @@ + +
    + + + $field.3 +
    diff --git a/view/field_textarea.tpl b/view/field_textarea.tpl new file mode 100644 index 0000000000..2425cdd3b7 --- /dev/null +++ b/view/field_textarea.tpl @@ -0,0 +1,6 @@ + +
    + + + $field.3 +
    diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index 8928148042..294a86690a 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -2468,6 +2468,58 @@ a.mail-list-link { filter:alpha(opacity=100); } +/** + * ADMIN + */ + +#adminpage dl { + clear: left; + margin-bottom: 2px; + padding-bottom: 2px; + border-bottom: 1px solid black; +} +#adminpage dt { + width: 200px; + float: left; + font-weight: bold; +} +#adminpage dd { + margin-left: 200px; +} + +#adminpage .field { + clear: left; + margin-bottom: 5px; + padding-bottom: 5px; +} + +#adminpage .field label { + float: left; + width: 200px; + font-weight: bold; +} + +#adminpage .field input, +#adminpage .field textarea { + width: 400px; +} +#adminpage .field textarea { height: 100px; } +#adminpage .field_help { + display: block; + margin-left: 200px; + color: #666666; + +} + +#adminpage h3 { + border-bottom: 1px solid #cccccc; +} + +#adminpage .submit { + clear:left; + text-align: right; +} + /** * ICONS From 4ba23df20a46bec640177df0555b5d98486c8540 Mon Sep 17 00:00:00 2001 From: fabrixxm Date: Mon, 13 Jun 2011 18:29:14 +0200 Subject: [PATCH 08/20] fix a typo in site settings page --- mod/admin.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mod/admin.php b/mod/admin.php index 70720f5d88..73da3814ba 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -153,7 +153,7 @@ function admin_page_site_post(&$a){ $verifyssl = ((x($_POST,'verifyssl')) ? True : False); $proxyuser = ((x($_POST,'proxyuser')) ? notags(trim($_POST['global_search_url'])) : ''); $proxy = ((x($_POST,'proxy')) ? notags(trim($_POST['global_search_url'])) : ''); - $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['maximagesize'])) : 60); + $timeout = ((x($_POST,'timeout')) ? intval(trim($_POST['timeout'])) : 60); $a->config['sitename'] = $sitename; From 5882d8d022c14a12ba7b314c96289061bd195ed4 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Tue, 14 Jun 2011 10:35:56 +0200 Subject: [PATCH 09/20] Initial plugins admin page --- mod/admin.php | 51 +++++++++++++++++++++++++++++-- view/admin_plugins.tpl | 14 +++++++++ view/theme/duepuntozero/style.css | 18 ++++++++++- 3 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 view/admin_plugins.tpl diff --git a/mod/admin.php b/mod/admin.php index 73da3814ba..f9d248210d 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -74,10 +74,15 @@ function admin_content(&$a) { // urls if ($a->argc > 1){ switch ($a->argv[1]){ - case 'site': { + case 'site': $o = admin_page_site($a); break; - } + case 'users': + $o = admin_page_users($a); + break; + case 'plugins': + $o = admin_page_plugins($a); + break; default: notice( t("Item not found.") ); } @@ -288,3 +293,45 @@ function admin_page_site(&$a) { )); } + + +/** + * Users admin page + */ + +function admin_page_users(&$a){ + return ":)"; +} + + +/* + * Plugins admin page + */ + +function admin_page_plugins(&$a){ + + /* all plugins */ + $plugins = array(); + $files = glob("addon/*/"); + if($files) { + foreach($files as $file) { + if (is_dir($file)){ + list($tmp, $id)=array_map("trim", explode("/",$file)); + // TODO: plugins info + $name=$author=$description=$homepage=""; + $plugins[] = array( $id, (in_array($id, $a->plugins)?"on":"off") , $name, $author, $description, $homepage); + } + } + } + + $t = get_markup_template("admin_plugins.tpl"); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Plugins'), + '$submit' => t('Submit'), + '$baseurl' => $a->get_baseurl(), + + '$plugins' => $plugins + )); +} + diff --git a/view/admin_plugins.tpl b/view/admin_plugins.tpl new file mode 100644 index 0000000000..d29665a064 --- /dev/null +++ b/view/admin_plugins.tpl @@ -0,0 +1,14 @@ +
    +

    $title - $page

    + +
      + {{ for $plugins as $p }} +
    • + + + $p.0 + +
    • + {{ endfor }} +
    +
    diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index 294a86690a..8799726c7b 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -2520,6 +2520,21 @@ a.mail-list-link { text-align: right; } +#adminpage #pluginslist { + margin: 0px; padding: 0px; +} +#adminpage .plugin { + list-style: none; + display: block; + border: 1px solid #888888; + padding: 1em; + margin-bottom: 5px; + clear: left; +} +#adminpage .plugin .toggle { + float:left; + margin-right: 1em; +} /** * ICONS @@ -2557,7 +2572,8 @@ a.mail-list-link { .youtube { background-position: -64px -32px;} .attach { background-position: -80px -32px; } .language { background-position: -96px -32px; } - +.on { background-position: -112px -32px; } +.off { background-position: -128px -32px; } .attachtype { display: block; width: 20px; height: 23px; From 5dc8fbccb29169601ad5fed2b5289631e32e5ac5 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Tue, 14 Jun 2011 11:16:27 +0200 Subject: [PATCH 10/20] enable/disable plugins from admin page --- boot.php | 54 +++++++++++++++++++++++++++++------------------ images/icons.png | Bin 10126 -> 10702 bytes mod/admin.php | 53 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 85 insertions(+), 22 deletions(-) diff --git a/boot.php b/boot.php index 8edc749109..42b0ca41e6 100644 --- a/boot.php +++ b/boot.php @@ -453,6 +453,37 @@ function system_unavailable() { killme(); }} + +// install and uninstall plugin +if (! function_exists('uninstall_plugin')){ +function uninstall_plugin($plugin){ + logger("Addons: uninstalling " . $plugin); + q("DELETE FROM `addon` WHERE `name` = '%s' LIMIT 1", + dbesc($plugin) + ); + + @include_once('addon/' . $plugin . '/' . $plugin . '.php'); + if(function_exists($plugin . '_uninstall')) { + $func = $plugin . '_uninstall'; + $func(); + } +}} + +if (! function_exists('install_plugin')){ +function install_plugin($plugin){ + logger("Addons: installing " . $plugin); + $t = filemtime('addon/' . $plugin . '/' . $plugin . '.php'); + @include_once('addon/' . $plugin . '/' . $plugin . '.php'); + if(function_exists($plugin . '_install')) { + $func = $plugin . '_install'; + $func(); + $r = q("INSERT INTO `addon` (`name`, `installed`, `timestamp`) VALUES ( '%s', 1, %d ) ", + dbesc($plugin), + intval($t) + ); + } +}} + // Primarily involved with database upgrade, but also sets the // base url for use in cmdline programs which don't have // $_SERVER variables, and synchronising the state of installed plugins. @@ -538,16 +569,7 @@ function check_config(&$a) { if(count($installed)) { foreach($installed as $i) { if(! in_array($i['name'],$plugins_arr)) { - logger("Addons: uninstalling " . $i['name']); - q("DELETE FROM `addon` WHERE `id` = %d LIMIT 1", - intval($i['id']) - ); - - @include_once('addon/' . $i['name'] . '/' . $i['name'] . '.php'); - if(function_exists($i['name'] . '_uninstall')) { - $func = $i['name'] . '_uninstall'; - $func(); - } + uninstall_plugin($i['name']); } else $installed_arr[] = $i['name']; @@ -557,17 +579,7 @@ function check_config(&$a) { if(count($plugins_arr)) { foreach($plugins_arr as $p) { if(! in_array($p,$installed_arr)) { - logger("Addons: installing " . $p); - $t = filemtime('addon/' . $p . '/' . $p . '.php'); - @include_once('addon/' . $p . '/' . $p . '.php'); - if(function_exists($p . '_install')) { - $func = $p . '_install'; - $func(); - $r = q("INSERT INTO `addon` (`name`, `installed`, `timestamp`) VALUES ( '%s', 1, %d ) ", - dbesc($p), - intval($t) - ); - } + install_plugin($p); } } } diff --git a/images/icons.png b/images/icons.png index 4c4c00b8a5e2065d3c88408157b526bcdff06402..fee7781c84240db21d26cd62837a82fb0b99a1ea 100644 GIT binary patch literal 10702 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 vaVS2{fX_kep4-*FmH=5vutd3-LE!%Y`u4?= literal 10126 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 diff --git a/mod/admin.php b/mod/admin.php index f9d248210d..054b49a211 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -310,7 +310,58 @@ function admin_page_users(&$a){ function admin_page_plugins(&$a){ - /* all plugins */ + /** + * Single plugin + */ + if ($a->argc == 3){ + $plugin = $a->argv[2]; + if (!is_file("addon/$plugin/$plugin.php")){ + notice( t("Item not found.") ); + return; + } + + if (x($_GET,"a") && $_GET['a']=="t"){ + // Toggle plugin status + $idx = array_search($plugin, $a->plugins); + if ($idx){ + unset($a->plugins[$idx]); + uninstall_plugin($plugin); + } else { + $a->plugins[] = $plugin; + install_plugin($plugin); + } + set_config("system","addon", implode(", ",$a->plugins)); + goaway($a->get_baseurl() . '/admin/plugins' ); + return; // NOTREACHED + } + // display plugin details + + + if (in_array($plugin, $a->plugins)){ + $status="on"; $action= t("Disable"); + } else { + $status="off"; $action= t("Enable"); + } + + $t = get_markup_template("admin_plugins_details.tpl"); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Plugins'), + '$toggle' => t('Toggle'), + '$baseurl' => $a->get_baseurl(), + + '$plugin' => $plugin, + '$status' => $status, + '$action' => $action + )); + } + + + + /** + * List plugins + */ + $plugins = array(); $files = glob("addon/*/"); if($files) { From 25d1637ec4b980d6ac8daf2f028f0ff579d5c977 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Tue, 14 Jun 2011 11:54:14 +0200 Subject: [PATCH 11/20] simple plugin details and log view in admin --- mod/admin.php | 58 ++++++++++++++++++++++++++++++++-- view/admin_logs.tpl | 17 ++++++++++ view/admin_plugins_details.tpl | 7 ++++ 3 files changed, 80 insertions(+), 2 deletions(-) create mode 100644 view/admin_logs.tpl create mode 100644 view/admin_plugins_details.tpl diff --git a/mod/admin.php b/mod/admin.php index 054b49a211..e40c503962 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -19,10 +19,12 @@ function admin_post(&$a){ // urls if ($a->argc > 1){ switch ($a->argv[1]){ - case 'site': { + case 'site': admin_page_site_post($a); break; - } + case 'logs': + admin_page_logs_post($a); + break; } } @@ -83,6 +85,9 @@ function admin_content(&$a) { case 'plugins': $o = admin_page_plugins($a); break; + case 'logs': + $o = admin_page_logs($a); + break; default: notice( t("Item not found.") ); } @@ -386,3 +391,52 @@ function admin_page_plugins(&$a){ )); } + +/** + * Logs admin page + */ + +function admin_page_logs_post(&$a) { + if (x($_POST,"page_logs")) { + + $logfile = ((x($_POST,'logfile')) ? notags(trim($_POST['logfile'])) : ''); + $debugging = ((x($_POST,'debugging')) ? true : false); + $loglevel = ((x($_POST,'loglevel')) ? intval(trim($_POST['loglevel'])) : 0); + + set_config('system','logfile', $logfile); + set_config('system','debugging', $debugging); + set_config('system','loglevel', $loglevel); + + + } + + goaway($a->get_baseurl() . '/admin/logs' ); + return; // NOTREACHED +} + +function admin_page_logs(&$a){ + + $log_choices = Array( + LOGGER_NORMAL => 'Normal', + LOGGER_TRACE => 'Trace', + LOGGER_DEBUG => 'Debug', + LOGGER_DATA => 'Data', + LOGGER_ALL => 'All' + ); + + $t = get_markup_template("admin_logs.tpl"); + return replace_macros($t, array( + '$title' => t('Administration'), + '$page' => t('Logs'), + '$submit' => t('Submit'), + '$clear' => t('Clear'), + '$baseurl' => $a->get_baseurl(), + '$logname' => get_config('system','logfile'), + + // name, label, value, help string, extra data... + '$debugging' => array('debugging', t("Debugging"),get_config('system','debugging'), ""), + '$logfile' => array('logfile', t("Log file"), get_config('system','logfile'), "Must be writable by web server. Relative to your Friendika index.php."), + '$loglevel' => array('loglevel', t("Log level"), get_config('system','loglevel'), "", $log_choices), + )); +} + diff --git a/view/admin_logs.tpl b/view/admin_logs.tpl new file mode 100644 index 0000000000..f2939a7ac3 --- /dev/null +++ b/view/admin_logs.tpl @@ -0,0 +1,17 @@ +
    +

    $title - $page

    + +
    + + {{ inc field_checkbox.tpl with $field=$debugging }}{{ endinc }} + {{ inc field_input.tpl with $field=$logfile }}{{ endinc }} + {{ inc field_select.tpl with $field=$loglevel }}{{ endinc }} + +
    + +
    + +

    $logname

    + + +
    diff --git a/view/admin_plugins_details.tpl b/view/admin_plugins_details.tpl new file mode 100644 index 0000000000..7e2e955210 --- /dev/null +++ b/view/admin_plugins_details.tpl @@ -0,0 +1,7 @@ +
    +

    $title - $page

    + +

    $plugin

    + +

    $action

    +
    From 283160901fcb5670b48c7897ccce615872cb956e Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Tue, 14 Jun 2011 14:21:00 +0200 Subject: [PATCH 12/20] update styles --- view/theme/duepuntozero/style.css | 3 +- view/theme/loozah/style.css | 70 +++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index 5632342388..c2fb9700ca 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -2545,7 +2545,8 @@ a.mail-list-link { margin-bottom: 5px; clear: left; } -#adminpage .plugin .toggle { +#adminpage .plugin .desc { margin-left: 2.5em;} +#adminpage .toggleplugin { float:left; margin-right: 1em; } diff --git a/view/theme/loozah/style.css b/view/theme/loozah/style.css index a566acadcb..db53cb6782 100644 --- a/view/theme/loozah/style.css +++ b/view/theme/loozah/style.css @@ -2497,6 +2497,73 @@ a.mail-list-link { top: 0px; } +/** + * ADMIN + */ + +#adminpage dl { + clear: left; + margin-bottom: 2px; + padding-bottom: 2px; + border-bottom: 1px solid black; +} +#adminpage dt { + width: 200px; + float: left; + font-weight: bold; +} +#adminpage dd { + margin-left: 200px; +} + +#adminpage .field { + clear: left; + margin-bottom: 5px; + padding-bottom: 5px; +} + +#adminpage .field label { + float: left; + width: 200px; + font-weight: bold; +} + +#adminpage .field input, +#adminpage .field textarea { + width: 400px; +} +#adminpage .field textarea { height: 100px; } +#adminpage .field_help { + display: block; + margin-left: 200px; + color: #666666; + +} + +#adminpage h3 { + border-bottom: 1px solid #cccccc; +} + +#adminpage .submit { + clear:left; +} + +#adminpage #pluginslist { + margin: 0px; padding: 0px; +} +#adminpage .plugin { + list-style: none; + display: block; + border: 1px solid #888888; + padding: 1em; + margin-bottom: 5px; + clear: left; +} +#adminpage .plugin .toggle { + float:left; + margin-right: 1em; +} + /** * ICONS */ @@ -2535,6 +2602,9 @@ a.mail-list-link { .language { background-position: -96px -32px; } .prev { background-position: -112px -32px; } .next { background-position: -128px -32px; } +.on { background-position: -144px -32px; } + +.off { background-position: 0px -48px; } .attachtype { display: block; width: 20px; height: 23px; From 00e142e4f753005a8b4003585c6a88548f006315 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Tue, 14 Jun 2011 14:21:43 +0200 Subject: [PATCH 13/20] Load plugin info from plugin file. Show README.md or README from plugin dir in plugin details page --- addon/oembed/oembed.php | 9 +++--- boot.php | 52 ++++++++++++++++++++++++++++++++++ mod/admin.php | 20 +++++++++---- view/admin_plugins.tpl | 7 ++--- view/admin_plugins_details.tpl | 16 +++++++++-- 5 files changed, 88 insertions(+), 16 deletions(-) diff --git a/addon/oembed/oembed.php b/addon/oembed/oembed.php index a0a0239aaf..f5be44194c 100644 --- a/addon/oembed/oembed.php +++ b/addon/oembed/oembed.php @@ -1,10 +1,9 @@ */ require_once('include/oembed.php'); diff --git a/boot.php b/boot.php index 42b0ca41e6..5d45de36f1 100644 --- a/boot.php +++ b/boot.php @@ -2828,3 +2828,55 @@ function is_site_admin() { return false; }} +/* + * parse plugin comment in search of plugin infos. + * like + * + * * Name: Plugin + * * Description: A plugin which plugs in + * * Version: 1.2.3 + * * Author: John + * * Author: Jane + * * + */ + +if (! function_exists('get_plugin_info')){ +function get_plugin_info($plugin){ + if (!is_file("addon/$plugin/$plugin.php")) return false; + + $f = file_get_contents("addon/$plugin/$plugin.php"); + $r = preg_match("|/\*.*\*/|msU", $f, $m); + + $info=Array( + 'name' => $plugin, + 'description' => "", + 'author' => array(), + 'version' => "" + ); + + if ($r){ + $ll = explode("\n", $m[0]); + foreach( $ll as $l ) { + $l = trim($l,"\t\n\r */"); + if ($l!=""){ + list($k,$v) = array_map("trim", explode(":",$l,2)); + $k= strtolower($k); + if ($k=="author"){ + $r=preg_match("|([^<]+)<([^>]+)>|", $v, $m); + if ($r) { + $info['author'][] = array('name'=>$m[1], 'link'=>$m[2]); + } else { + $info['author'][] = array('name'=>$v); + } + } else { + if (array_key_exists($k,$info)){ + $info[$k]=$v; + } + } + + } + } + + } + return $info; +}} diff --git a/mod/admin.php b/mod/admin.php index e40c503962..6386e6ebce 100644 --- a/mod/admin.php +++ b/mod/admin.php @@ -340,7 +340,7 @@ function admin_page_plugins(&$a){ return; // NOTREACHED } // display plugin details - + require_once('library/markdown.php'); if (in_array($plugin, $a->plugins)){ $status="on"; $action= t("Disable"); @@ -348,6 +348,14 @@ function admin_page_plugins(&$a){ $status="off"; $action= t("Enable"); } + $readme=Null; + if (is_file("addon/$plugin/README.md")){ + $readme = file_get_contents("addon/$plugin/README.md"); + $readme = Markdown($readme); + } else if (is_file("addon/$plugin/README")){ + $readme = "
    ". file_get_contents("addon/$plugin/README") ."
    "; + } + $t = get_markup_template("admin_plugins_details.tpl"); return replace_macros($t, array( '$title' => t('Administration'), @@ -357,7 +365,10 @@ function admin_page_plugins(&$a){ '$plugin' => $plugin, '$status' => $status, - '$action' => $action + '$action' => $action, + '$info' => get_plugin_info($plugin), + + '$readme' => $readme )); } @@ -373,9 +384,8 @@ function admin_page_plugins(&$a){ foreach($files as $file) { if (is_dir($file)){ list($tmp, $id)=array_map("trim", explode("/",$file)); - // TODO: plugins info - $name=$author=$description=$homepage=""; - $plugins[] = array( $id, (in_array($id, $a->plugins)?"on":"off") , $name, $author, $description, $homepage); + $info = get_plugin_info($id); + $plugins[] = array( $id, (in_array($id, $a->plugins)?"on":"off") , $info); } } } diff --git a/view/admin_plugins.tpl b/view/admin_plugins.tpl index d29665a064..ee0fa67e6f 100644 --- a/view/admin_plugins.tpl +++ b/view/admin_plugins.tpl @@ -4,10 +4,9 @@
      {{ for $plugins as $p }}
    • - - - $p.0 - + + $p.2.name - $p.2.version +
      $p.2.description
    • {{ endfor }}
    diff --git a/view/admin_plugins_details.tpl b/view/admin_plugins_details.tpl index 7e2e955210..acb3d28628 100644 --- a/view/admin_plugins_details.tpl +++ b/view/admin_plugins_details.tpl @@ -1,7 +1,19 @@

    $title - $page

    -

    $plugin

    +

    $info.name - $info.version : $action

    +

    $info.description

    +

    + {{ for $info.author as $a }} + $a.name + {{ endfor }} +

    -

    $action

    + + {{ if $readme }} +

    Readme

    +
    + $readme +
    + {{ endif }}
    From b7dc9f8867e783a0db109cce4cb0db90500129eb Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Tue, 14 Jun 2011 15:08:03 +0200 Subject: [PATCH 14/20] Update info comments in all plugins --- addon/calc/calc.php | 7 +++++++ addon/convert/convert.php | 7 ++++++- addon/facebook/README | 33 +++++++++++++++++++++++++++++++ addon/facebook/facebook.php | 5 +++++ addon/fortunate/fortunate.php | 9 ++++++--- addon/java_upload/java_upload.php | 9 ++++++++- addon/js_upload/js_upload.php | 7 +++++++ addon/ldapauth/README | 17 ++++++++++++++++ addon/ldapauth/ldapauth.php | 8 +++++++- addon/piwik/piwik.php | 7 +++++++ addon/poormancron/poormancron.php | 8 ++++---- addon/randplace/randplace.php | 17 ++++++++-------- addon/sniper/sniper.php | 8 +++++++- addon/statusnet/statusnet.php | 7 ++++++- addon/tictac/tictac.php | 6 ++++++ addon/twitter/twitter.php | 6 ++++++ addon/widgets/widgets.php | 13 ++++++------ view/admin_plugins_details.tpl | 6 +++--- view/theme/duepuntozero/style.css | 1 + 19 files changed, 151 insertions(+), 30 deletions(-) create mode 100644 addon/facebook/README create mode 100644 addon/ldapauth/README diff --git a/addon/calc/calc.php b/addon/calc/calc.php index a095e3960d..8c079dc7a5 100644 --- a/addon/calc/calc.php +++ b/addon/calc/calc.php @@ -1,4 +1,11 @@ + */ + function calc_install() { register_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); diff --git a/addon/convert/convert.php b/addon/convert/convert.php index a3448ce01e..7a4c90a530 100644 --- a/addon/convert/convert.php +++ b/addon/convert/convert.php @@ -1,5 +1,10 @@ + */ function convert_install() { register_hook('app_menu', 'addon/convert/convert.php', 'convert_app_menu'); diff --git a/addon/facebook/README b/addon/facebook/README new file mode 100644 index 0000000000..42ec01383c --- /dev/null +++ b/addon/facebook/README @@ -0,0 +1,33 @@ +Installing the Friendika/Facebook connector + +1. register an API key for your site from developer.facebook.com + a. We'd be very happy if you include "Friendika" in the application name + to increase name recognition. The Friendika icons are also present + in the images directory and may be uploaded as a Facebook app icon. + Use images/friendika-16.jpg for the Icon and images/friendika-128.jpg for the Logo. + b. The url should be your site URL with a trailing slash. + You may use http://portal.friendika.com/privacy as the privacy policy + URL unless your site has different requirements, and + http://portal.friendika.com as the Terms of Service URL unless + you have different requirements. (Friendika is a software application + and does not require Terms of Service, though your installation of it might). + c. Set the following values in your .htconfig.php file + $a->config['facebook']['appid'] = 'xxxxxxxxxxx'; + $a->config['facebook']['appsecret'] = 'xxxxxxxxxxxxxxx'; + Replace with the settings Facebook gives you. +2. Enable the facebook plugin by including it in .htconfig.php - e.g. + $a->config['system']['addon'] = 'plugin1,plugin2,facebook'; +3. Visit the Facebook Settings section of the "Settings->Plugin Settings" page. + and click 'Install Facebook Connector'. +4. This will ask you to login to Facebook and grant permission to the + plugin to do its stuff. Allow it to do so. +5. You're done. To turn it off visit the Plugin Settings page again and + 'Remove Facebook posting'. + +Vidoes and embeds will not be posted if there is no other content. Links +and images will be converted to a format suitable for the Facebook API and +long posts truncated - with a link to view the full post. + +Facebook contacts will not be able to view private photos, as they are not able to +authenticate to your site to establish identity. We will address this +in a future release. diff --git a/addon/facebook/facebook.php b/addon/facebook/facebook.php index 545779cd5f..5d86c66c2c 100644 --- a/addon/facebook/facebook.php +++ b/addon/facebook/facebook.php @@ -1,4 +1,9 @@ + */ /** * Installing the Friendika/Facebook connector diff --git a/addon/fortunate/fortunate.php b/addon/fortunate/fortunate.php index b91080f516..5a6302e58d 100644 --- a/addon/fortunate/fortunate.php +++ b/addon/fortunate/fortunate.php @@ -1,7 +1,10 @@ + */ function fortunate_install() { diff --git a/addon/java_upload/java_upload.php b/addon/java_upload/java_upload.php index 8b8a57604c..09e321f0a8 100644 --- a/addon/java_upload/java_upload.php +++ b/addon/java_upload/java_upload.php @@ -1,5 +1,12 @@ + */ + /** * * Java photo uploader, uses Jumploader @@ -93,4 +100,4 @@ function java_upload_photo_post_end(&$a,&$b) { if(x($a->data,'java_upload') && $a->data['java_upload']) killme(); -} \ No newline at end of file +} diff --git a/addon/js_upload/js_upload.php b/addon/js_upload/js_upload.php index 9f3fa96009..042e9a988a 100644 --- a/addon/js_upload/js_upload.php +++ b/addon/js_upload/js_upload.php @@ -1,5 +1,12 @@ + */ + /** * * JavaScript Photo/Image Uploader diff --git a/addon/ldapauth/README b/addon/ldapauth/README new file mode 100644 index 0000000000..cf28ef1e06 --- /dev/null +++ b/addon/ldapauth/README @@ -0,0 +1,17 @@ +Authenticate a user against an LDAP directory +Useful for Windows Active Directory and other LDAP-based organisations +to maintain a single password across the organisation. + +Optionally authenticates only if a member of a given group in the directory. + +The person must have registered with Friendika using the normal registration +procedures in order to have a Friendika user record, contact, and profile. + +Note when using with Windows Active Directory: you may need to set TLS_CACERT in your site +ldap.conf file to the signing cert for your LDAP server. + +The required configuration options for this module may be set in the .htconfig.php file +e.g.: + +$a->config['ldapauth']['ldap_server'] = 'host.example.com'; +...etc. diff --git a/addon/ldapauth/ldapauth.php b/addon/ldapauth/ldapauth.php index 2ec30caad7..7230302e9d 100644 --- a/addon/ldapauth/ldapauth.php +++ b/addon/ldapauth/ldapauth.php @@ -1,5 +1,11 @@ + */ + /** * Friendika addon * diff --git a/addon/piwik/piwik.php b/addon/piwik/piwik.php index 52bdaeb0d1..032f84f4bb 100644 --- a/addon/piwik/piwik.php +++ b/addon/piwik/piwik.php @@ -1,4 +1,11 @@ + */ + /* Piwik Analytics Plugin for Friendika * diff --git a/addon/poormancron/poormancron.php b/addon/poormancron/poormancron.php index 830c10ddfe..9a8dc1e33f 100644 --- a/addon/poormancron/poormancron.php +++ b/addon/poormancron/poormancron.php @@ -1,9 +1,9 @@ */ function poormancron_install() { diff --git a/addon/randplace/randplace.php b/addon/randplace/randplace.php index fa38de3776..bae8e7c690 100644 --- a/addon/randplace/randplace.php +++ b/addon/randplace/randplace.php @@ -1,13 +1,12 @@ + * + * + * * * Addons are registered with the system in the * .htconfig.php file. @@ -178,4 +177,4 @@ function randplace_settings(&$a,&$s) { $s .= '
    '; -} \ No newline at end of file +} diff --git a/addon/sniper/sniper.php b/addon/sniper/sniper.php index 79d7daad21..bb4eace304 100644 --- a/addon/sniper/sniper.php +++ b/addon/sniper/sniper.php @@ -1,4 +1,10 @@ + */ function sniper_install() { register_hook('app_menu', 'addon/sniper/sniper.php', 'sniper_app_menu'); @@ -28,4 +34,4 @@ $o .= <<< EOT EOT; return $o; -} \ No newline at end of file +} diff --git a/addon/statusnet/statusnet.php b/addon/statusnet/statusnet.php index 39df7d9620..e24ebc1ee0 100644 --- a/addon/statusnet/statusnet.php +++ b/addon/statusnet/statusnet.php @@ -1,5 +1,10 @@ + */ + /* StatusNet Plugin for Friendika * * Author: Tobias Diekershoff diff --git a/addon/tictac/tictac.php b/addon/tictac/tictac.php index a69cda132b..d6cec08a06 100644 --- a/addon/tictac/tictac.php +++ b/addon/tictac/tictac.php @@ -1,4 +1,10 @@ + */ function tictac_install() { diff --git a/addon/twitter/twitter.php b/addon/twitter/twitter.php index c59d1b9e5c..fef6583f6b 100644 --- a/addon/twitter/twitter.php +++ b/addon/twitter/twitter.php @@ -1,4 +1,10 @@ + */ + /* Twitter Plugin for Friendika * diff --git a/addon/widgets/widgets.php b/addon/widgets/widgets.php index af17d9e9af..f5f8682223 100644 --- a/addon/widgets/widgets.php +++ b/addon/widgets/widgets.php @@ -1,10 +1,11 @@ + */ + function widgets_install() { register_hook('plugin_settings', 'addon/widgets/widgets.php', 'widgets_settings'); diff --git a/view/admin_plugins_details.tpl b/view/admin_plugins_details.tpl index acb3d28628..85ee8dfb40 100644 --- a/view/admin_plugins_details.tpl +++ b/view/admin_plugins_details.tpl @@ -3,11 +3,11 @@

    $info.name - $info.version : $action

    $info.description

    -

    + {{ for $info.author as $a }} - $a.name +

    {{ if $a.link }}{{ endif }}$a.name

    {{ endfor }} -

    + {{ if $readme }} diff --git a/view/theme/duepuntozero/style.css b/view/theme/duepuntozero/style.css index c2fb9700ca..78e02681a5 100644 --- a/view/theme/duepuntozero/style.css +++ b/view/theme/duepuntozero/style.css @@ -2550,6 +2550,7 @@ a.mail-list-link { float:left; margin-right: 1em; } +#adminpage .author .icon { float: left;} /** * ICONS From 63390aa8001a9d8f28f66c8e8686f406b28d6cbc Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Thu, 16 Jun 2011 12:02:05 +0200 Subject: [PATCH 15/20] {{ if }} {{ else }} support in templates --- include/template_processor.php | 39 ++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/include/template_processor.php b/include/template_processor.php index a2c24b00bc..be40a31ab5 100644 --- a/include/template_processor.php +++ b/include/template_processor.php @@ -8,6 +8,18 @@ var $nodes = array(); var $done = false; + private function _preg_error(){ + switch(preg_last_error()){ + case PREG_INTERNAL_ERROR: die('PREG_INTERNAL_ERROR'); break; + case PREG_BACKTRACK_LIMIT_ERROR: die('PREG_BACKTRACK_LIMIT_ERROR'); break; + case PREG_RECURSION_LIMIT_ERROR: die('PREG_RECURSION_LIMIT_ERROR'); break; + case PREG_BAD_UTF8_ERROR: die('PREG_BAD_UTF8_ERROR'); break; + case PREG_BAD_UTF8_OFFSET_ERROR: die('PREG_BAD_UTF8_OFFSET_ERROR'); break; + default: + die("Unknown preg error."); + } + } + private function _build_replace($r, $prefix){ if(is_array($r) && count($r)) { @@ -40,9 +52,9 @@ /** * IF node * - * {{ if <$var> }}...{{ endif }} - * {{ if <$var>== }}...{{ endif }} - * {{ if <$var>!= }}...{{ endif }} + * {{ if <$var> }}...[{{ else }} ...] {{ endif }} + * {{ if <$var>== }}...[{{ else }} ...]{{ endif }} + * {{ if <$var>!= }}...[{{ else }} ...]{{ endif }} */ private function _replcb_if($args){ @@ -59,7 +71,13 @@ } else { $val = $this->_get_var($args[2]); } - return ($val?$args[3]:""); + if (isset($args[4])) { + list($strue, $sfalse)= explode($args[4], $args[3]); + } else { + $strue = $args[3]; $sfalse = ""; + } + + return ($val?$strue:$sfalse); } /** @@ -112,13 +130,17 @@ private function _replcb_node($m) { $node = $this->nodes[$m[1]]; if (method_exists($this, "_replcb_".$node[1])){ - return call_user_func(array($this, "_replcb_".$node[1]), $node); + $s = call_user_func(array($this, "_replcb_".$node[1]), $node); } else { - return ""; + $s = ""; } + $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s); + if ($s==Null) $this->_preg_error() + return $s; } private function _replcb($m){ + //var_dump(array_map('htmlspecialchars', $m)); $this->done = false; $this->nodes[] = (array) $m; return "||". (count($this->nodes)-1) ."||"; @@ -128,8 +150,10 @@ $this->done = false; while (!$this->done){ $this->done=true; - $s = preg_replace_callback('|{{ *([a-z]*) *([^}]*)}}([^{]*){{ *end\1 *}}|', array($this, "_replcb"), $s); + $s = preg_replace_callback('|{{ *([a-z]*) *([^}]*)}}([^{]*({{ *else *}}[^{]*)?){{ *end\1 *}}|', array($this, "_replcb"), $s); + if ($s==Null) $this->_preg_error(); } + //({{ *else *}}[^{]*)? krsort($this->nodes); return $s; } @@ -144,6 +168,7 @@ #$s = str_replace(array("\n","\r"),array("§n§","§r§"),$s); $s = $this->_build_nodes($s); $s = preg_replace_callback('/\|\|([0-9]+)\|\|/', array($this, "_replcb_node"), $s); + if ($s==Null) $this->_preg_error() $s = str_replace($this->search,$this->replace, $s); return $s; From ffee5dd69e424f33c0ceb9cf8b0cfe78e4025794 Mon Sep 17 00:00:00 2001 From: Fabio Comuni Date: Thu, 16 Jun 2011 12:04:27 +0200 Subject: [PATCH 16/20] ping updates trigger 'nav-update' custom event from