]> git.mxchange.org Git - friendica.git/commitdiff
First test for friendika "live" update
authorFabio Comuni <fabrix.xm@gmail.com>
Fri, 8 Jul 2011 15:12:08 +0000 (17:12 +0200)
committerFabio Comuni <fabrix.xm@gmail.com>
Fri, 8 Jul 2011 15:12:08 +0000 (17:12 +0200)
include/jquery.htmlstream.js [new file with mode: 0644]
include/remoteupdate.php [new file with mode: 0644]
mod/admin.php
view/admin_aside.tpl
view/admin_remoteupdate.tpl [new file with mode: 0644]
view/theme/duepuntozero/style.css

diff --git a/include/jquery.htmlstream.js b/include/jquery.htmlstream.js
new file mode 100644 (file)
index 0000000..c62c538
--- /dev/null
@@ -0,0 +1,157 @@
+/* jQuery ajax stream plugin
+* Version 0.1
+* Copyright (C) 2009 Chris Tarquini
+* Licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License (http://creativecommons.org/licenses/by-sa/3.0/)
+* Permissions beyond the scope of this license may be available by contacting petros000[at]hotmail.com.
+*/
+
+(function($) {
+
+// Save the original AJAX function
+var ajax_old = $.ajax;
+var get_old = $.get;
+var post_old =  $.post;
+var active = true;
+// Add our settings
+$.ajaxSetup({stream: false,pollInterval: 500/*, onDataRecieved: function(){}*/ });
+$.enableAjaxStream = function(enable)
+{
+if(typeof enable == 'undefined') enable = !active;
+if(!enable)
+{
+$.ajax = ajax_old;
+$.get = get_old;
+$.post = post_old;
+active = false;
+}
+else
+{
+$.ajax = ajax_stream;
+$.get = ajax_get_stream;
+$.post = ajax_post_stream;
+active = true;
+}
+
+}
+var ajax_stream = $.ajax = function(options)
+{
+//copied from original ajax function
+        options  = jQuery.extend(true, options, jQuery.extend(true, {}, jQuery.ajaxSettings, options));
+if(options.stream)
+{
+var timer = 0;
+var offset = 0;
+var xmlhttp = null;
+var lastlen = 0;
+var done = false;
+var hook = function(xhr)
+{
+xmlhttp = xhr;
+checkagain();
+}
+var fix = function(){ check('stream'); };// fixes weird bug with random numbers as arg
+var checkagain = function(){if(!done) timer = setTimeout(fix,options.pollInterval);}
+var check = function(status)
+{
+if(typeof status == 'undefined') status = "stream";
+if(xmlhttp.status < 3) return; //only get the latest packet if data has been sent
+var text = xmlhttp.responseText;
+if(status == 'stream') //if we arent streaming then just flush the buffer
+{
+if(text.length <= lastlen) { checkagain(); return;}
+lastlength = text.length;
+if(offset == text.length) { checkagain(); return;}
+}
+var pkt = text.substr(offset);
+offset =  text.length;
+if($.isFunction(options.OnDataRecieved))
+{
+options.OnDataRecieved(pkt, status, xmlhttp.responseText, xmlhttp);
+}
+if(xmlhttp.status != 4)
+checkagain();
+}
+var complete = function(xhr,s)
+{
+clearTimeout(timer);//done..stop polling
+done = true;
+// send final call
+check(s);
+}
+// If the complete callback is set create a new callback that calls the users and outs
+if($.isFunction(options.success))
+{
+var oc = options.success;
+options.success = function(xhr,s){ complete(xhr,s); oc(xhr,s);};
+
+}
+else options.success = complete;
+// Set up our hook on the beforeSend
+if($.isFunction(options.beforeSend))
+{
+var obs = options.beforeSend;
+options.beforeSend = function(xhr){ obs(xhr); hook(xhr);};
+}
+else options.beforeSend = hook;
+
+}
+ajax_old(options);
+}
+
+var ajax_get_stream = $.get = function(url,data,callback,type,stream)
+{
+       if($.isFunction(data))
+       {
+               var orgcb = callback;
+               callback = data;
+               if($.isFunction(orgcb))
+               {
+                       stream = orgcb;
+               }
+               data = null;
+       }
+       if($.isFunction(type))
+       {
+               stream = type;
+               type = undefined;
+       }
+       var dostream = $.isFunction(stream);
+       return jQuery.ajax({
+                                       type: "GET",
+                                       url: url,
+                                       data: data,
+                                       success: callback,
+                                       dataType: type,
+                                       stream: dostream,
+                                       OnDataRecieved: stream
+                       });
+
+}
+
+var ajax_post_stream = $.post = function(url,data,callback,type,stream)
+{
+        if($.isFunction(data))
+        {
+                               var orgcb = callback;
+                callback = data;
+        }
+               if($.isFunction(type))
+               {
+                       stream = type;
+                       type = undefined;
+               }
+               var dostream = $.isFunction(stream);
+               return jQuery.ajax({
+                               type: "POST",
+                               url: url,
+                               data: data,
+                               success: callback,
+                               dataType: type,
+                               stream: dostream,
+                               OnDataRecieved: stream
+               });
+
+}
+
+})(jQuery);    
+       
diff --git a/include/remoteupdate.php b/include/remoteupdate.php
new file mode 100644 (file)
index 0000000..aa30da0
--- /dev/null
@@ -0,0 +1,261 @@
+<?php
+/* update friendika */
+define('APIBASE', 'http://github.com/api/v2/');
+define('F9KREPO', 'friendika/friendika');
+
+$up_totalfiles = 0;
+$up_countfiles = 0;
+$up_lastp = -1;
+
+function checkUpdate(){
+       $r = fetch_url( APIBASE."json/repos/show/".F9KREPO."/tags" );
+       $tags = json_decode($r);
+       
+       $tag = 0.0;
+       foreach ($tags->tags as $i=>$v){
+               $i = (float)$i;
+               if ($i>$tag) $tag=$i;
+       }
+       
+       if ($tag==0.0) return false;
+       $f = fetch_url("https://raw.github.com/".F9KREPO."/".$tag."/boot.php","r");
+       preg_match("|'FRIENDIKA_VERSION', *'([^']*)'|", $f, $m);
+       $version =  $m[1];
+       
+       $lv = explode(".", FRIENDIKA_VERSION);
+       $rv = explode(".",$version);
+       foreach($lv as $i=>$v){
+               if ((int)$lv[$i] < (int)$rv[$i]) {
+                       return array($tag, $version, "https://github.com/friendika/friendika/zipball/".$tag);
+                       break;
+               }
+       }
+       return false;
+}
+function canWeWrite(){
+       $bd = dirname(dirname(__file__));
+       return is_writable( $bd."/boot.php" );
+}
+
+function out($txt){ echo "§".$txt."§"; ob_end_flush(); flush();}
+
+function up_count($path){
+    $file_count = 0;
+    $dir_handle = opendir($path);
+    if (!$dir_handle) return -1;
+    while ($file = readdir($dir_handle)) {
+        if ($file == '.' || $file == '..') continue;
+               $file_count++;
+        
+        if (is_dir($path . $file)){      
+            $file_count += up_count($path . $file . DIRECTORY_SEPARATOR);
+        }
+        
+    }
+    closedir($dir_handle);
+    return $file_count;
+}
+
+
+
+function up_unzip($file, $folder="/tmp"){
+       $folder.="/";
+       $zip = zip_open($file);
+       if ($zip) {
+         while ($zip_entry = zip_read($zip)) {
+               $zip_entry_name = zip_entry_name($zip_entry);
+               if (substr($zip_entry_name,strlen($zip_entry_name)-1,1)=="/"){
+                       mkdir($folder.$zip_entry_name,0777, true);
+               } else {
+                       $fp = fopen($folder.$zip_entry_name, "w");
+                       if (zip_entry_open($zip, $zip_entry, "r")) {
+                         $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
+                         fwrite($fp,"$buf");
+                         zip_entry_close($zip_entry);
+                         fclose($fp);
+                       }
+               }
+         }
+         zip_close($zip);
+       }       
+}
+
+/**
+ * Walk recoursively in a folder and call a callback function on every
+ * dir entry.
+ * args:
+ *     $dir            string          base dir to walk
+ *     $callback       function        callback function
+ *  $sort              int                     0: ascending, 1: descending
+ *     $cb_argv        any                     extra value passed to callback
+ * 
+ * callback signature:
+ * function name($fn, $dir [, $argv])
+ *     $fn             string          full dir entry name
+ *     $dir    string          start dir path
+ *  $argv      any                     user value to callback
+ * 
+ */
+function up_walktree($dir, $callback=Null, $sort=0, $cb_argv=Null ,  $startdir=Null){
+       if (is_null($callback)) return;
+       if (is_null($startdir)) $startdir = $dir;
+       $res = scandir($dir, $sort);
+       foreach($res as $i=>$v){
+               if ($v!="." && $v!=".."){
+                       $fn = $dir."/".$v;
+                       if ($sort==0) $callback($fn, $startdir, $cb_argv);      
+                       if (is_dir($fn)) up_walktree($fn, $callback, $sort, $cb_argv, $startdir);
+                       if ($sort==1) $callback($fn, $startdir, $cb_argv);      
+               }
+       }
+       
+}
+
+function up_copy($fn, $dir){
+       global $up_countfiles, $up_totalfiles, $up_lastp;
+       $up_countfiles++; $prc=(int)(((float)$up_countfiles/(float)$up_totalfiles)*100);
+       
+       if (strpos($fn, ".gitignore")>-1 || strpos($fn, ".htaccess")>-1) return;  
+       $ddest = dirname(dirname(__file__));
+       $fd = str_replace($dir, $ddest, $fn);
+       
+       if (is_dir($fn) && !is_dir($fd)) {
+               $re=mkdir($fd,0777,true);
+       }
+       if (!is_dir($fn)){
+               $re=copy($fn, $fd);
+       }
+       
+       if ($re===false) { 
+               out("ERROR. Abort."); 
+               killme();
+       }
+       out("copy@Copy@$prc%");
+}
+
+function up_ftp($fn, $dir, $argv){
+       global $up_countfiles, $up_totalfiles, $up_lastp;
+       $up_countfiles++; $prc=(int)(((float)$up_countfiles/(float)$up_totalfiles)*100);
+
+       if (strpos($fn, ".gitignore")>-1 || strpos($fn, ".htaccess")>-1) return;
+       
+       list($ddest, $conn_id) = $argv;
+       $l = strlen($ddest)-1;
+       if (substr($ddest,$l,1)=="/") $ddest = substr($ddest,0,$l);
+       $fd = str_replace($dir, $ddest, $fn);
+       
+       if (is_dir($fn)){
+               if (ftp_nlist($conn_id, $fd)===false) { 
+                       $ret = ftp_mkdir($conn_id, $fd);
+               } else {
+                       $ret=true;
+               }
+       } else {
+               $ret = ftp_put($conn_id, $fd, $fn, FTP_BINARY); 
+       }
+       if (!$ret) { 
+               out("ERROR. Abort."); 
+               killme();
+       } 
+       out("copy@Copy@$prc%");
+}
+
+function up_rm($fn, $dir){
+       if (is_dir($fn)){
+               rmdir($fn);
+       } else {
+               unlink($fn);
+       }
+}
+
+function up_dlfile($url, $file) {
+       $in = fopen ($url, "r");
+       $out = fopen ($file, "w");
+       
+       $fs = filesize($url);
+       
+
+       if (!$in || !$out) return false;
+       
+       $s=0; $count=0;
+       while (!feof ($in)) {
+               $line = fgets ($in, 1024);
+               fwrite( $out, $line);
+               
+               $count++; $s += strlen($line);
+               if ($count==50){
+                       $count=0;
+                       $sp=$s/1024.0; $ex="Kb";
+                       if ($sp>1024) { $sp=$sp/1024; $ex="Mb"; }
+                       if ($sp>1024) { $sp=$sp/1024; $ex="Gb"; }
+                       $sp = ((int)($sp*100))/100;
+                       out("dwl@Download@".$sp.$ex);
+               }
+       }
+       fclose($in);
+       return true;
+}
+
+function doUpdate($remotefile, $ftpdata=false){
+       global $up_totalfiles;
+       
+       
+       $localtmpfile = tempnam("/tmp", "fk");
+       out("dwl@Download@starting...");
+       $rt= up_dlfile($remotefile, $localtmpfile);
+       if ($rt==false || filesize($localtmpfile)==0){
+               out("dwl@Download@ERROR.");
+               unlink($localtmpfile);
+               return;
+       }
+       out("dwl@Download@Ok.");
+       
+       out("unzip@Unzip@");
+       $tmpdirname = $localfile."ex";
+       mkdir($tmpdirname);
+       up_unzip($localtmpfile, $tmpdirname);
+       $basedir = glob($tmpdirname."/*"); $basedir=$basedir[0];
+       out ("unzip@Unzip@Ok.");
+       
+       $up_totalfiles = up_count($basedir."/");
+       
+       if (canWeWrite()){
+               out("copy@Copy@");
+               up_walktree($basedir, 'up_copy');
+       }
+       if ($ftpdata!==false && is_array($ftpdata) && $ftpdata['ftphost']!="" ){
+               out("ftpcon@Connect to FTP@");
+               $conn_id = ftp_connect($ftpdata['ftphost']);
+               $login_result = ftp_login($conn_id, $ftpdata['ftpuser'], $ftpdata['ftppwd']);
+               
+               if ((!$conn_id) || (!$login_result)) { 
+                       out("ftpcon@Connect to FTP@FAILED");
+                       up_clean($tmpdirname, $localtmpfile); 
+                       return;
+               } else {
+                       out("ftpcon@Connect to FTP@Ok.");
+               }
+               out("copy@Copy@");
+               up_walktree($basedir, 'up_ftp', 0, array( $ftpdata['ftppath'], $conn_id));
+               ftp_close($conn_id);
+       }
+
+       up_clean($tmpdirname, $localtmpfile); 
+       
+}
+
+function up_clean($tmpdirname, $localtmpfile){
+       out("clean@Clean up@");
+       unlink($localtmpfile);
+       up_walktree($tmpdirname, 'up_rm', 1);
+       rmdir($tmpdirname);
+       out("clean@Clean up@Ok.");
+}
index 203d4873f8ca35d70bf45062eae32a2f2633f635..f7dde7bcbecb25117e7cf011d3b42c3fcb62e08c 100644 (file)
@@ -3,7 +3,7 @@
  /**
   * Friendika admin
   */
-  
+require_once("include/remoteupdate.php");
  
 function admin_init(&$a) {
        if(!is_site_admin()) {
@@ -36,11 +36,14 @@ function admin_post(&$a){
                                                }
                                }
                                goaway($a->get_baseurl() . '/admin/plugins/' . $a->argv[2] );
-                               return; // NOTREACHED                                                   
+                               return; // NOTREACHED
                                break;
                        case 'logs':
                                admin_page_logs_post($a);
                                break;
+                       case 'update':
+                               admin_page_remoteupdate_post($a);
+                               break;
                }
        }
 
@@ -62,7 +65,8 @@ function admin_content(&$a) {
        $aside = Array(
                'site'   =>     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")
+               'plugins'=>     Array($a->get_baseurl()."/admin/plugins/", t("Plugins") , "plugins"),
+               'update' =>     Array($a->get_baseurl()."/admin/update/", t("Update") , "update")
        );
        
        /* get plugins admin page */
@@ -106,7 +110,10 @@ function admin_content(&$a) {
                                break;
                        case 'logs':
                                $o = admin_page_logs($a);
-                               break;                          
+                               break;
+                       case 'update':
+                               $o = admin_page_remoteupdate($a);
+                               break;
                        default:
                                notice( t("Item not found.") );
                }
@@ -655,3 +662,54 @@ function admin_page_logs(&$a){
        ));
 }
 
+function admin_page_remoteupdate_post(&$a) {
+       // this function should be called via ajax post
+       if(!is_site_admin()) {
+               return login(false);
+       }
+
+       
+       if (x($_POST,'remotefile') && $_POST['remotefile']!=""){
+               $remotefile = $_POST['remotefile'];
+               $ftpdata = (x($_POST['ftphost'])?$_POST:false);
+               doUpdate($remotefile, $ftpdata);
+       } else {
+               echo "No remote file to download. Abort!";
+       }
+
+       killme();
+}
+
+function admin_page_remoteupdate(&$a) {
+       if(!is_site_admin()) {
+               return login(false);
+       }
+
+       $canwrite = canWeWrite();
+       $canftp = function_exists('ftp_connect');
+       
+       $needupdate = true;
+       $u = checkUpdate();
+       if (!is_array($u)){
+               $needupdate = false;
+               $u = array('','','');
+       }
+       
+       $tpl = get_markup_template("admin_remoteupdate.tpl");
+       return replace_macros($tpl, array(
+               '$baseurl' => $a->get_baseurl(),
+               '$submit' => t("Update now"),
+               '$close' => t("Close"),
+               '$localversion' => FRIENDIKA_VERSION,
+               '$remoteversion' => $u[1],
+               '$needupdate' => $needupdate,
+               '$canwrite' => $canwrite,
+               '$canftp'       => $canftp,
+               '$ftphost'      => array('ftphost', t("FTP Host"), '',''),
+               '$ftppath'      => array('ftppath', t("FTP Path"), '/',''),
+               '$ftpuser'      => array('ftpuser', t("FTP User"), '',''),
+               '$ftppwd'       => array('ftppwd', t("FTP Password"), '',''),
+               '$remotefile'=>array('remotefile','', $u['2'],'')
+       ));
+       
+}
index c9ab17aa5d2e8bbdfd42b06b74d1e6595b3c844e..1cf431bec2af0bdbf93fcceb3a827e30ed403833 100644 (file)
@@ -30,3 +30,8 @@
 <ul class='admin linklist'>
        <li class='admin link $admin.logs.2'><a href='$admin.logs.0'>$admin.logs.1</a></li>
 </ul>
+
+
+<ul class='admin linklist'>
+       <li class='admin link $admin.update.2'><a href='$admin.update.0'>$admin.update.1</a></li>
+</ul>
diff --git a/view/admin_remoteupdate.tpl b/view/admin_remoteupdate.tpl
new file mode 100644 (file)
index 0000000..0c15692
--- /dev/null
@@ -0,0 +1,98 @@
+<script src="include/jquery.htmlstream.js"></script>
+<script>
+       /* ajax updater */
+       function updateEnd(data){
+               //$("#updatepopup .panel_text").html(data);
+               $("#remoteupdate_form").find("input").removeAttr('disabled');
+               $(".panel_action_close").fadeIn()       
+       }
+       function updateOn(data){
+               
+               var patt=/§([^§]*)§/g; 
+               var matches = data.match(patt);
+               $(matches).each(function(id,data){
+                       data = data.replace(/§/g,"");
+                       d = data.split("@");
+                       console.log(d);
+                       elm = $("#updatepopup .panel_text #"+d[0]);
+                       html = "<div id='"+d[0]+"' class='progress'>"+d[1]+"<span>"+d[2]+"</span></div>";
+                       if (elm.length==0){
+                               $("#updatepopup .panel_text").append(html);
+                       } else {
+                               $(elm).replaceWith(html);
+                       }
+               });
+               
+               
+       }
+       
+       $(function(){
+               $("#remoteupdate_form").submit(function(){
+                       var data={};
+                       $(this).find("input").each(function(i, e){
+                               name = $(e).attr('name');
+                               value = $(e).val();
+                               e.disabled = true;
+                               data[name]=value;
+                       });
+
+                       $("#updatepopup .panel_text").html("");
+                       $("#updatepopup").show();
+                       $("#updatepopup .panel").hide().slideDown(500);
+                       $(".panel_action_close").hide().click(function(){
+                               $("#updatepopup .panel").slideUp(500, function(){
+                                       $("#updatepopup").hide();
+                               });                             
+                       });
+
+                       $.post(
+                               $(this).attr('action'), 
+                               data, 
+                               updateEnd,
+                               'text',
+                               updateOn
+                       );
+
+                       
+                       return false;
+               })
+       });
+</script>
+<div id="updatepopup" class="popup">
+       <div class="background"></div>
+       <div class="panel">
+               <div class="panel_in">
+                       <h1>Friendika Update</h1>
+                       <div class="panel_text"></div>
+                       <div class="panel_actions">
+                               <input type="button" value="$close" class="panel_action_close">
+                       </div>
+               </div>
+       </div>
+</div>
+<div id="adminpage">
+       <dl> <dt>Your version:</dt><dd>$localversion</dd> </dl>
+{{ if $needupdate }}
+       <dl> <dt>New version:</dt><dd>$remoteversion</dd> </dl>
+
+       <form id="remoteupdate_form" method="POST" action="$baseurl/admin/update">
+       <input type="hidden" name="$remotefile.0" value="$remotefile.2">
+
+       {{ if $canwrite }}
+               <div class="submit"><input type="submit" name="remoteupdate" value="$submit" /></div>
+       {{ else }}
+               <h3>Your friendika installation is not writable by web server.</h3>
+               {{ if $canftp }}
+                       <p>You can try to update via FTP</p>
+                       {{ inc field_input.tpl with $field=$ftphost }}{{ endinc }}
+                       {{ inc field_input.tpl with $field=$ftppath }}{{ endinc }}
+                       {{ inc field_input.tpl with $field=$ftpuser }}{{ endinc }}
+                       {{ inc field_password.tpl with $field=$ftppwd }}{{ endinc }}
+                       <div class="submit"><input type="submit" name="remoteupdate" value="$submit" /></div>
+               {{ endif }}
+       {{ endif }}
+       </form>
+{{ else }}
+<h4>No updates</h4>
+{{ endif }}
+</div>
index bbaa43b57bde2700701e38ffb2b8708e365ea931..78a0bff5bedbe0a9cdec194adc056fe12a87ad8d 100644 (file)
@@ -1943,7 +1943,6 @@ a.mail-list-link {
 #install-dbuser-label,
 #install-dbpass-label,
 #install-dbdata-label,
-#install-admin-label,
 #install-tz-desc {
        float: left;
        width: 250px;
@@ -1955,8 +1954,7 @@ a.mail-list-link {
 #install-dbhost,
 #install-dbuser,
 #install-dbpass,
-#install-dbdata,
-#install-admin {
+#install-dbdata {
        float: left;
        width: 200px;
        margin-left: 20px;
@@ -1966,7 +1964,6 @@ a.mail-list-link {
 #install-dbuser-end,
 #install-dbpass-end,
 #install-dbdata-end,
-#install-admin-end,
 #install-tz-end {
        clear: both;
 }
@@ -2573,6 +2570,38 @@ a.mail-list-link {
 #adminpage table#users img { width: 16px; height: 16px; }
 #adminpage table tr:hover { background-color: #bbc7d7; }
 #adminpage .selectall { text-align: right; }
+
+/*
+ * UPDATE
+ */
+.popup {       
+       width: 100%; height: 100%;
+       top:0px; left:0px;
+       position: absolute;
+       display: none;
+}
+
+.popup .background {
+       background-color: rgba(0,0,0,128);
+       opacity: 0.5;
+       width: 100%; height: 100%;
+       position: absolute;
+       top:0px; left:0px;
+}
+.popup .panel {
+       top:25%;left:25%;width:50%;height:50%;
+       padding: 1em;
+       position: absolute;
+       border: 4px solid #000000;
+       background-color: #FFFFFF;
+}
+.popup .panel .panel_text { display: block; overflow: auto; height: 80%; } 
+.popup .panel .panel_in { width: 100%; height: 100%;   position: relative; }
+.popup .panel .panel_actions {  width: 100%; bottom: 4px; left: 0px; position: absolute; }
+.panel_text .progress { width: 50%; overflow: hidden; height: auto; border: 1px solid #cccccc; margin-bottom: 5px}
+.panel_text .progress span {float: right; display: block; width: 25%; background-color: #eeeeee; text-align: right;}
+
+
 /**
  * ICONS
  */