aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpatdenice <patdenice@piwigo.org>2011-04-20 14:52:52 +0000
committerpatdenice <patdenice@piwigo.org>2011-04-20 14:52:52 +0000
commit491e8adc7467de9f9aa6dbbebfcb8b82c676b46a (patch)
treeaad72cf4b73fa2bd6ffb6e91c174d18547410741
parentfede13ce419b40ca22cf58b76f74d44d6d564dac (diff)
feature:2271
Merge autoupdate plugin into piwigo core. git-svn-id: http://piwigo.org/svn/trunk@10511 68402e56-0260-453c-a942-63ccdbb3a9ee
-rw-r--r--admin.php1
-rw-r--r--admin/include/functions.php1
-rw-r--r--admin/include/mysqldump.php421
-rw-r--r--admin/include/updates.class.php481
-rw-r--r--admin/themes/default/images/ajax-loader-bar.gifbin0 -> 10819 bytes
-rw-r--r--admin/themes/default/template/admin.tpl1
-rw-r--r--admin/themes/default/template/updates_ext.tpl272
-rw-r--r--admin/themes/default/template/updates_pwg.tpl99
-rw-r--r--admin/updates.php44
-rw-r--r--admin/updates_ext.php86
-rw-r--r--admin/updates_pwg.php166
-rw-r--r--include/ws_functions.inc.php136
-rw-r--r--install/config.sql1
-rw-r--r--install/db/103-database.php42
-rw-r--r--language/en_UK/admin.lang.php26
-rw-r--r--language/fr_FR/admin.lang.php26
-rw-r--r--ws.php27
17 files changed, 1830 insertions, 0 deletions
diff --git a/admin.php b/admin.php
index 16177900a..08156d151 100644
--- a/admin.php
+++ b/admin.php
@@ -168,6 +168,7 @@ $template->assign(
'U_ADD_PHOTOS' => $link_start.'photos_add',
'U_CHANGE_THEME' => PHPWG_ROOT_PATH.'admin.php?change_theme=1',
'U_PENDING_COMMENTS' => $link_start.'comments',
+ 'U_UPDATES' => $link_start.'updates',
)
);
diff --git a/admin/include/functions.php b/admin/include/functions.php
index f5afa9633..3d32e7b0e 100644
--- a/admin/include/functions.php
+++ b/admin/include/functions.php
@@ -2085,6 +2085,7 @@ function get_active_menu($menu_page)
case 'maintenance':
case 'thumbnail':
case 'comments':
+ case 'updates':
return 4;
case 'configuration':
diff --git a/admin/include/mysqldump.php b/admin/include/mysqldump.php
new file mode 100644
index 000000000..515d86ae9
--- /dev/null
+++ b/admin/include/mysqldump.php
@@ -0,0 +1,421 @@
+<?php
+/**
+* Dump MySQL database
+*
+* Here is an inline example:
+* <code>
+* $connection = @mysql_connect($dbhost,$dbuser,$dbpsw);
+* $dumper = new MySQLDump($dbname,'filename.sql',false,false);
+* $dumper->doDump();
+* </code>
+*
+* Special thanks to:
+* - Andrea Ingaglio <andrea@coders4fun.com> helping in development of all class code
+* - Dylan Pugh for precious advices halfing the size of the output file and for helping in debug
+*
+* @name MySQLDump
+* @author Daniele Viganò - CreativeFactory.it <daniele.vigano@creativefactory.it>
+* @version 2.20 - 02/11/2007
+* @license http://opensource.org/licenses/gpl-license.php GNU Public License
+*/
+
+class MySQLDump {
+ /**
+ * @access private
+ */
+ var $database = null;
+
+ /**
+ * @access private
+ */
+ var $compress = false;
+
+ /**
+ * @access private
+ */
+ var $hexValue = false;
+
+ /**
+ * The output filename
+ * @access private
+ */
+ var $filename = null;
+
+ /**
+ * The pointer of the output file
+ * @access private
+ */
+ var $file = null;
+
+ /**
+ * @access private
+ */
+ var $isWritten = false;
+
+ /**
+ * Class constructor
+ * @param string $db The database name
+ * @param string $filepath The file where the dump will be written
+ * @param boolean $compress It defines if the output file is compress (gzip) or not
+ * @param boolean $hexValue It defines if the outup values are base-16 or not
+ */
+ function MYSQLDump($db = null, $filepath = 'dump.sql', $compress = false, $hexValue = false){
+ $this->compress = $compress;
+ if ( !$this->setOutputFile($filepath) )
+ return false;
+ return $this->setDatabase($db);
+ }
+
+ /**
+ * Sets the database to work on
+ * @param string $db The database name
+ */
+ function setDatabase($db){
+ $this->database = $db;
+ if ( !@mysql_select_db($this->database) )
+ return false;
+ return true;
+ }
+
+ /**
+ * Returns the database where the class is working on
+ * @return string
+ */
+ function getDatabase(){
+ return $this->database;
+ }
+
+ /**
+ * Sets the output file type (It can be made only if the file hasn't been already written)
+ * @param boolean $compress If it's true, the output file will be compressed
+ */
+ function setCompress($compress){
+ if ( $this->isWritten )
+ return false;
+ $this->compress = $compress;
+ $this->openFile($this->filename);
+ return true;
+ }
+
+ /**
+ * Returns if the output file is or not compressed
+ * @return boolean
+ */
+ function getCompress(){
+ return $this->compress;
+ }
+
+ /**
+ * Sets the output file
+ * @param string $filepath The file where the dump will be written
+ */
+ function setOutputFile($filepath){
+ if ( $this->isWritten )
+ return false;
+ $this->filename = $filepath;
+ $this->file = $this->openFile($this->filename);
+ return $this->file;
+ }
+
+ /**
+ * Returns the output filename
+ * @return string
+ */
+ function getOutputFile(){
+ return $this->filename;
+ }
+
+ /**
+ * Writes to file the $table's structure
+ * @param string $table The table name
+ */
+ function getTableStructure($table){
+ if ( !$this->setDatabase($this->database) )
+ return false;
+ // Structure Header
+ $structure = "-- \n";
+ $structure .= "-- Table structure for table `{$table}` \n";
+ $structure .= "-- \n\n";
+ // Dump Structure
+ $structure .= 'DROP TABLE IF EXISTS `'.$table.'`;'."\n";
+ $structure .= "CREATE TABLE `".$table."` (\n";
+ $records = @mysql_query('SHOW FIELDS FROM `'.$table.'`');
+ if ( @mysql_num_rows($records) == 0 )
+ return false;
+ while ( $record = mysql_fetch_assoc($records) ) {
+ $structure .= '`'.$record['Field'].'` '.$record['Type'];
+ if ( isset($record['Default']) )
+ $structure .= ' DEFAULT \''.$record['Default'].'\'';
+ if ( @strcmp($record['Null'],'YES') != 0 )
+ $structure .= ' NOT NULL';
+ elseif ( is_null($record['Default']) )
+ $structure .= ' DEFAULT NULL';
+ if ( !empty($record['Extra']) )
+ $structure .= ' '.$record['Extra'];
+ $structure .= ",\n";
+ }
+ $structure = @ereg_replace(",\n$", null, $structure);
+
+ // Save all Column Indexes
+ $structure .= $this->getSqlKeysTable($table);
+ $structure .= "\n)";
+
+ //Save table engine
+ $records = @mysql_query("SHOW TABLE STATUS LIKE '".$table."'");
+
+ if ( $record = @mysql_fetch_assoc($records) ) {
+ if ( !empty($record['Engine']) )
+ $structure .= ' ENGINE='.$record['Engine'];
+ if ( !empty($record['Auto_increment']) )
+ $structure .= ' AUTO_INCREMENT='.$record['Auto_increment'];
+ }
+
+ $structure .= ";\n\n-- --------------------------------------------------------\n\n";
+ $this->saveToFile($this->file,$structure);
+ }
+
+ /**
+ * Writes to file the $table's data
+ * @param string $table The table name
+ * @param boolean $hexValue It defines if the output is base 16 or not
+ */
+ function getTableData($table,$hexValue = true) {
+ if ( !$this->setDatabase($this->database) )
+ return false;
+ // Header
+ $data = "-- \n";
+ $data .= "-- Dumping data for table `$table` \n";
+ $data .= "-- \n\n";
+
+ $records = mysql_query('SHOW FIELDS FROM `'.$table.'`');
+ $num_fields = @mysql_num_rows($records);
+ if ( $num_fields == 0 )
+ return false;
+ // Field names
+ $selectStatement = "SELECT ";
+ $insertStatement = "INSERT INTO `$table` (";
+ $hexField = array();
+ for ($x = 0; $x < $num_fields; $x++) {
+ $record = @mysql_fetch_assoc($records);
+ if ( ($hexValue) && ($this->isTextValue($record['Type'])) ) {
+ $selectStatement .= 'HEX(`'.$record['Field'].'`)';
+ $hexField [$x] = true;
+ }
+ else
+ $selectStatement .= '`'.$record['Field'].'`';
+ $insertStatement .= '`'.$record['Field'].'`';
+ $insertStatement .= ", ";
+ $selectStatement .= ", ";
+ }
+ $insertStatement = @substr($insertStatement,0,-2).') VALUES'."\n";
+ $selectStatement = @substr($selectStatement,0,-2).' FROM `'.$table.'`';
+
+ $records = @mysql_query($selectStatement);
+ $num_rows = @mysql_num_rows($records);
+ $num_fields = @mysql_num_fields($records);
+ // Dump data
+ if ( $num_rows > 0 ) {
+ $data .= $insertStatement;
+ for ($i = 0; $i < $num_rows; $i++) {
+ $record = @mysql_fetch_assoc($records);
+ $data .= ' (';
+ for ($j = 0; $j < $num_fields; $j++) {
+ $field_name = @mysql_field_name($records, $j);
+ if ( @$hexField[$j] && (@strlen($record[$field_name]) > 0) )
+ $data .= "0x".$record[$field_name];
+ elseif (is_null($record[$field_name]))
+ $data .= "NULL";
+ else
+ $data .= "'".@str_replace('\"','"',@mysql_real_escape_string($record[$field_name]))."'";
+ $data .= ',';
+ }
+ $data = @substr($data,0,-1).")";
+ $data .= ( $i < ($num_rows-1) ) ? ',' : ';';
+ $data .= "\n";
+ //if data in greather than 1MB save
+ if (strlen($data) > 1048576) {
+ $this->saveToFile($this->file,$data);
+ $data = '';
+ }
+ }
+ $data .= "\n-- --------------------------------------------------------\n\n";
+ $this->saveToFile($this->file,$data);
+ }
+ }
+
+ /**
+ * Writes to file all the selected database tables structure
+ * @return boolean
+ */
+ function getDatabaseStructure(){
+ $records = @mysql_query('SHOW TABLES');
+ if ( @mysql_num_rows($records) == 0 )
+ return false;
+ $structure = '';
+ while ( $record = @mysql_fetch_row($records) ) {
+ $structure .= $this->getTableStructure($record[0]);
+ }
+ return true;
+ }
+
+ /**
+ * Writes to file all the selected database tables data
+ * @param boolean $hexValue It defines if the output is base-16 or not
+ */
+ function getDatabaseData($hexValue = true){
+ $records = @mysql_query('SHOW TABLES');
+ if ( @mysql_num_rows($records) == 0 )
+ return false;
+ while ( $record = @mysql_fetch_row($records) ) {
+ $this->getTableData($record[0],$hexValue);
+ }
+ }
+
+ /**
+ * Writes to file the selected database dump
+ */
+ function doDump() {
+ $this->saveToFile($this->file,"SET FOREIGN_KEY_CHECKS = 0;\n\n");
+ $this->getDatabaseStructure();
+ $this->getDatabaseData($this->hexValue);
+ $this->saveToFile($this->file,"SET FOREIGN_KEY_CHECKS = 1;\n\n");
+ $this->closeFile($this->file);
+ return true;
+ }
+
+ /**
+ * @deprecated Look at the doDump() method
+ */
+ function writeDump($filename) {
+ if ( !$this->setOutputFile($filename) )
+ return false;
+ $this->doDump();
+ $this->closeFile($this->file);
+ return true;
+ }
+
+ /**
+ * @access private
+ */
+ function getSqlKeysTable ($table) {
+ $primary = "";
+ $unique = array();
+ $index = array();
+ $fulltext = array();
+ $results = mysql_query("SHOW KEYS FROM `{$table}`");
+ if ( @mysql_num_rows($results) == 0 )
+ return false;
+ while($row = mysql_fetch_object($results)) {
+ if (($row->Key_name == 'PRIMARY') AND ($row->Index_type == 'BTREE')) {
+ if ( $primary == "" )
+ $primary = " PRIMARY KEY (`{$row->Column_name}`";
+ else
+ $primary .= ", `{$row->Column_name}`";
+ }
+ if (($row->Key_name != 'PRIMARY') AND ($row->Non_unique == '0') AND ($row->Index_type == 'BTREE')) {
+ if ( (empty($unique)) OR (empty($unique[$row->Key_name])) )
+ $unique[$row->Key_name] = " UNIQUE KEY `{$row->Key_name}` (`{$row->Column_name}`";
+ else
+ $unique[$row->Key_name] .= ", `{$row->Column_name}`";
+ }
+ if (($row->Key_name != 'PRIMARY') AND ($row->Non_unique == '1') AND ($row->Index_type == 'BTREE')) {
+ if ( (empty($index)) OR (empty($index[$row->Key_name])) )
+ $index[$row->Key_name] = " KEY `{$row->Key_name}` (`{$row->Column_name}`";
+ else
+ $index[$row->Key_name] .= ", `{$row->Column_name}`";
+ }
+ if (($row->Key_name != 'PRIMARY') AND ($row->Non_unique == '1') AND ($row->Index_type == 'FULLTEXT')) {
+ if ( (empty($fulltext)) OR (empty($fulltext[$row->Key_name])) )
+ $fulltext[$row->Key_name] = " FULLTEXT `{$row->Key_name}` (`{$row->Column_name}`";
+ else
+ $fulltext[$row->Key_name] .= ", `{$row->Column_name}`";
+ }
+ }
+ $sqlKeyStatement = '';
+ // generate primary, unique, key and fulltext
+ if ( $primary != "" ) {
+ $sqlKeyStatement .= ",\n";
+ $primary .= ")";
+ $sqlKeyStatement .= $primary;
+ }
+ if (!empty($unique)) {
+ foreach ($unique as $keyName => $keyDef) {
+ $sqlKeyStatement .= ",\n";
+ $keyDef .= ")";
+ $sqlKeyStatement .= $keyDef;
+
+ }
+ }
+ if (!empty($index)) {
+ foreach ($index as $keyName => $keyDef) {
+ $sqlKeyStatement .= ",\n";
+ $keyDef .= ")";
+ $sqlKeyStatement .= $keyDef;
+ }
+ }
+ if (!empty($fulltext)) {
+ foreach ($fulltext as $keyName => $keyDef) {
+ $sqlKeyStatement .= ",\n";
+ $keyDef .= ")";
+ $sqlKeyStatement .= $keyDef;
+ }
+ }
+ return $sqlKeyStatement;
+ }
+
+ /**
+ * @access private
+ */
+ function isTextValue($field_type) {
+ switch ($field_type) {
+ case "tinytext":
+ case "text":
+ case "mediumtext":
+ case "longtext":
+ case "binary":
+ case "varbinary":
+ case "tinyblob":
+ case "blob":
+ case "mediumblob":
+ case "longblob":
+ return True;
+ break;
+ default:
+ return False;
+ }
+ }
+
+ /**
+ * @access private
+ */
+ function openFile($filename) {
+ $file = false;
+ if ( $this->compress )
+ $file = @gzopen($filename, "w9");
+ else
+ $file = @fopen($filename, "w");
+ return $file;
+ }
+
+ /**
+ * @access private
+ */
+ function saveToFile($file, $data) {
+ if ( $this->compress )
+ @gzwrite($file, $data);
+ else
+ @fwrite($file, $data);
+ $this->isWritten = true;
+ }
+
+ /**
+ * @access private
+ */
+ function closeFile($file) {
+ if ( $this->compress )
+ @gzclose($file);
+ else
+ @fclose($file);
+ }
+}
+?> \ No newline at end of file
diff --git a/admin/include/updates.class.php b/admin/include/updates.class.php
new file mode 100644
index 000000000..b53001488
--- /dev/null
+++ b/admin/include/updates.class.php
@@ -0,0 +1,481 @@
+<?php
+
+if (!defined('PHPWG_ROOT_PATH')) die('Hacking attempt!');
+
+class updates
+{
+ var $types = array();
+ var $plugins;
+ var $themes;
+ var $languages;
+ var $missing = array();
+ var $default_plugins = array();
+ var $default_themes = array();
+ var $default_languages = array();
+ var $merged_extensions = array();
+ var $merged_extension_url = 'http://piwigo.org/download/merged_extensions.txt';
+
+ function __construct()
+ {
+ $this->types = array('plugins', 'themes', 'languages');
+ $this->default_themes = array('clear', 'dark', 'Sylvia');
+ $this->default_plugins = array('admin_multi_view', 'c13y_upgrade', 'language_switch', 'LocalFilesEditor');
+
+ foreach ($this->types as $type)
+ {
+ include_once(PHPWG_ROOT_PATH.'admin/include/'.$type.'.class.php');
+ $this->$type = new $type();
+ }
+ }
+
+ function check_piwigo_upgrade()
+ {
+ $_SESSION['need_update'] = null;
+
+ if (preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches)
+ and @fetchRemote(PHPWG_URL.'/download/all_versions.php', $result))
+ {
+ $all_versions = @explode("\n", $result);
+ $new_version = trim($all_versions[0]);
+ $_SESSION['need_update'] = version_compare(PHPWG_VERSION, $new_version, '<');
+ }
+ }
+
+ function get_server_extensions($version=PHPWG_VERSION)
+ {
+ global $user;
+
+ $get_data = array(
+ 'format' => 'php',
+ );
+
+ // Retrieve PEM versions
+ $versions_to_check = array();
+ $url = PEM_URL . '/api/get_version_list.php';
+ if (fetchRemote($url, $result, $get_data) and $pem_versions = @unserialize($result))
+ {
+ if (!preg_match('/^\d+\.\d+\.\d+/', $version))
+ {
+ $version = $pem_versions[0]['name'];
+ }
+ $branch = substr($version, 0, strrpos($version, '.'));
+ foreach ($pem_versions as $pem_version)
+ {
+ if (strpos($pem_version['name'], $branch) === 0)
+ {
+ $versions_to_check[] = $pem_version['id'];
+ }
+ }
+ }
+ if (empty($versions_to_check))
+ {
+ return false;
+ }
+
+ // Extensions to check
+ $ext_to_check = array();
+ foreach ($this->types as $type)
+ {
+ $fs = 'fs_'.$type;
+ foreach ($this->$type->$fs as $ext)
+ {
+ if (isset($ext['extension']))
+ {
+ $ext_to_check[$ext['extension']] = $type;
+ }
+ }
+ }
+
+ // Retrieve PEM plugins infos
+ $url = PEM_URL . '/api/get_revision_list.php';
+ $get_data = array_merge($get_data, array(
+ 'last_revision_only' => 'true',
+ 'version' => implode(',', $versions_to_check),
+ 'lang' => substr($user['language'], 0, 2),
+ 'get_nb_downloads' => 'true',
+ )
+ );
+
+ $post_data = array();
+ if (!empty($ext_to_check))
+ {
+ $post_data['extension_include'] = implode(',', array_keys($ext_to_check));
+ }
+
+ if (fetchRemote($url, $result, $get_data, $post_data))
+ {
+ $pem_exts = @unserialize($result);
+ if (!is_array($pem_exts))
+ {
+ return false;
+ }
+ foreach ($pem_exts as $ext)
+ {
+ if (isset($ext_to_check[$ext['extension_id']]))
+ {
+ $server = 'server_'.$ext_to_check[$ext['extension_id']];
+ $this->$ext_to_check[$ext['extension_id']]->$server += array($ext['extension_id'] => $ext);
+ unset($ext_to_check[$ext['extension_id']]);
+ }
+ }
+ $this->check_missing_extensions($ext_to_check);
+ return true;
+ }
+ return false;
+ }
+
+ // Check all extensions upgrades
+ function check_extensions()
+ {
+ global $conf;
+
+ if (!$this->get_server_extensions())
+ {
+ autoupdate_error();
+ }
+
+ $_SESSION['extensions_need_update'] = array();
+
+ foreach ($this->types as $type)
+ {
+ $fs = 'fs_'.$type;
+ $server = 'server_'.$type;
+ $server_ext = $this->$type->$server;
+ $fs_ext = $this->$type->$fs;
+
+ $ignore_list = array();
+ $need_upgrade = array();
+
+ foreach($fs_ext as $ext_id => $fs_ext)
+ {
+ if (isset($fs_ext['extension']) and isset($server_ext[$fs_ext['extension']]))
+ {
+ $ext_info = $server_ext[$fs_ext['extension']];
+
+ if (!$this->version_compare($fs_ext['version'], $ext_info['revision_name'], $type))
+ {
+ if (in_array($ext_id, $conf['updates_ignored'][$type]))
+ {
+ array_push($ignore_list, $ext_id);
+ }
+ else
+ {
+ $_SESSION['extensions_need_update'][$type][$ext_id] = $ext_info['revision_name'];
+ }
+ }
+ }
+ }
+ $conf['updates_ignored'][$type] = $ignore_list;
+ }
+ conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
+ }
+
+ // Check if extension have been upgraded since last check
+ function check_updated_extensions()
+ {
+ foreach ($this->types as $type)
+ {
+ if (!empty($_SESSION['extensions_need_update'][$type]))
+ {
+ $fs = 'fs_'.$type;
+ foreach($this->$type->$fs as $ext_id => $fs_ext)
+ {
+ if (isset($_SESSION['extensions_need_update'][$type][$ext_id])
+ and $this->version_compare($fs_ext['version'], $_SESSION['extensions_need_update'][$type][$ext_id], $type))
+ {
+ // Extension have been upgraded
+ $this->check_extensions();
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ function check_missing_extensions($missing)
+ {
+ foreach ($missing as $id => $type)
+ {
+ $fs = 'fs_'.$type;
+ $default = 'default_'.$type;
+ foreach ($this->$type->$fs as $ext_id => $ext)
+ {
+ if (isset($ext['extension']) and $id == $ext['extension']
+ and !in_array($ext_id, $this->$default)
+ and !in_array($ext['extension'], $this->merged_extensions))
+ {
+ $this->missing[$type][] = $ext;
+ break;
+ }
+ }
+ }
+ }
+
+ function get_merged_extensions($version)
+ {
+ if (fetchRemote($this->merged_extension_url, $result))
+ {
+ $rows = explode("\n", $result);
+ foreach ($rows as $row)
+ {
+ if (preg_match('/^(\d+\.\d+): *(.*)$/', $row, $match))
+ {
+ if (version_compare($version, $match[1], '>='))
+ {
+ $extensions = explode(',', trim($match[2]));
+ $this->merged_extensions = array_merge($this->merged_extensions, $extensions);
+ }
+ }
+ }
+ }
+ }
+
+ function version_compare($a, $b, $type)
+ {
+ $version_compare = rtrim($type, 's').'_version_compare';
+
+ return $this->$type->$version_compare($a, $b);
+ }
+
+ function deltree($path, $move_to_trash=false)
+ {
+ if (is_dir($path))
+ {
+ $fh = opendir($path);
+ while ($file = readdir($fh))
+ {
+ if ($file != '.' and $file != '..')
+ {
+ $pathfile = $path . '/' . $file;
+ if (is_dir($pathfile))
+ {
+ self::deltree($pathfile, $move_to_trash);
+ }
+ else
+ {
+ @unlink($pathfile);
+ }
+ }
+ }
+ closedir($fh);
+ if (@rmdir($path))
+ {
+ return true;
+ }
+ elseif ($move_to_trash)
+ {
+ $trash = PHPWG_ROOT_PATH.'_trash';
+ if (!is_dir($trash))
+ {
+ @mkgetdir($trash);
+ }
+ return @rename($path, $trash . '/'.md5(uniqid(rand(), true)));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ function process_obsolete_list($file)
+ {
+ if (file_exists(PHPWG_ROOT_PATH.$file)
+ and $old_files = file(PHPWG_ROOT_PATH.$file, FILE_IGNORE_NEW_LINES)
+ and !empty($old_files))
+ {
+ array_push($old_files, $file);
+ foreach($old_files as $old_file)
+ {
+ $path = PHPWG_ROOT_PATH.$old_file;
+ if (is_file($path))
+ {
+ @unlink($path);
+ }
+ elseif (is_dir($path))
+ {
+ self::deltree($path, true);
+ }
+ }
+ }
+ }
+
+ function dump_database($include_history=false)
+ {
+ global $page, $conf, $cfgBase;
+
+ if (version_compare(PHPWG_VERSION, '2.1', '<'))
+ {
+ $conf['db_base'] = $cfgBase;
+ }
+
+ include(PHPWG_ROOT_PATH.'admin/include/mysqldump.php');
+
+ $path = $conf['local_data_dir'].'/update';
+
+ if (@mkgetdir($path)
+ and ($backupFile = tempnam($path, 'sql'))
+ and ($dumper = new MySQLDump($conf['db_base'],$backupFile,false,false)))
+ {
+ foreach (get_defined_constants() as $constant => $value)
+ {
+ if (preg_match('/_TABLE$/', $constant))
+ {
+ $dumper->getTableStructure($value);
+ if ($constant == 'HISTORY_TABLE' and !$include_history)
+ {
+ continue;
+ }
+ $dumper->getTableData($value);
+ }
+ }
+ }
+
+ if (@filesize($backupFile))
+ {
+ $http_headers = array(
+ 'Content-Length: '.@filesize($backupFile),
+ 'Content-Type: text/x-sql',
+ 'Content-Disposition: attachment; filename="database.sql";',
+ 'Content-Transfer-Encoding: binary',
+ );
+
+ foreach ($http_headers as $header) {
+ header($header);
+ }
+
+ @readfile($backupFile);
+ self::deltree($conf['local_data_dir'].'/update');
+ exit();
+ }
+ else
+ {
+ array_push($page['errors'], l10n('Unable to dump database.'));
+ }
+ }
+
+ function upgrade_to($upgrade_to, &$step)
+ {
+ global $page, $conf, $template;
+
+ if (!version_compare($_POST['upgrade_to'], PHPWG_VERSION, '>'))
+ {
+ redirect(get_root_url().'admin.php?page=plugin-'.basename(dirname(__FILE__)));
+ }
+
+ if ($step == 2)
+ {
+ preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches);
+ $code = $matches[1].'.x_to_'.$_POST['upgrade_to'];
+ $dl_code = str_replace(array('.', '_'), '', $code);
+ $remove_path = $code;
+ $obsolete_list = 'obsolete.list';
+ }
+ else
+ {
+ $code = $_POST['upgrade_to'];
+ $dl_code = $code;
+ $remove_path = version_compare($code, '2.0.8', '>=') ? 'piwigo' : 'piwigo-'.$code;
+ $obsolete_list = PHPWG_ROOT_PATH.'install/obsolete.list';
+ }
+
+ if (empty($page['errors']))
+ {
+ $path = $conf['local_data_dir'].'/update';
+ $filename = $path.'/'.$code.'.zip';
+ @mkgetdir($path);
+
+ $chunk_num = 0;
+ $end = false;
+ $zip = @fopen($filename, 'w');
+ while (!$end)
+ {
+ $chunk_num++;
+ if (@fetchRemote(PHPWG_URL.'/download/dlcounter.php?code='.$dl_code.'&chunk_num='.$chunk_num, $result)
+ and $input = @unserialize($result))
+ {
+ if (0 == $input['remaining'])
+ {
+ $end = true;
+ }
+ @fwrite($zip, base64_decode($input['data']));
+ }
+ else
+ {
+ $end = true;
+ }
+ }
+ @fclose($zip);
+
+ if (@filesize($filename))
+ {
+ $zip = new PclZip($filename);
+ if ($result = $zip->extract(PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
+ PCLZIP_OPT_REMOVE_PATH, $remove_path,
+ PCLZIP_OPT_SET_CHMOD, 0755,
+ PCLZIP_OPT_REPLACE_NEWER))
+ {
+ //Check if all files were extracted
+ $error = '';
+ foreach($result as $extract)
+ {
+ if (!in_array($extract['status'], array('ok', 'filtered', 'already_a_directory')))
+ {
+ // Try to change chmod and extract
+ if (@chmod(PHPWG_ROOT_PATH.$extract['filename'], 0777)
+ and ($res = $zip->extract(PCLZIP_OPT_BY_NAME, $remove_path.'/'.$extract['filename'],
+ PCLZIP_OPT_PATH, PHPWG_ROOT_PATH,
+ PCLZIP_OPT_REMOVE_PATH, $remove_path,
+ PCLZIP_OPT_SET_CHMOD, 0755,
+ PCLZIP_OPT_REPLACE_NEWER))
+ and isset($res[0]['status'])
+ and $res[0]['status'] == 'ok')
+ {
+ continue;
+ }
+ else
+ {
+ $error .= $extract['filename'].': '.$extract['status']."\n";
+ }
+ }
+ }
+
+ if (empty($error))
+ {
+ self::obsolete_list($obsolete_list);
+ self::deltree($conf['local_data_dir'].'/update');
+ invalidate_user_cache(true);
+ $template->delete_compiled_templates();
+ unset($_SESSION['need_update']);
+ if ($step == 2)
+ {
+ array_push($page['infos'], sprintf(l10n('autoupdate_success'), $upgrade_to));
+ $step = -1;
+ }
+ else
+ {
+ redirect(PHPWG_ROOT_PATH.'upgrade.php?now=');
+ }
+ }
+ else
+ {
+ file_put_contents($conf['local_data_dir'].'/update/log_error.txt', $error);
+ $relative_path = trim(str_replace(dirname(dirname(dirname(dirname(__FILE__)))), '', $conf['local_data_dir']), '/\\');
+ array_push($page['errors'], sprintf(l10n('autoupdate_extract_fail'), PHPWG_ROOT_PATH.$relative_path.'/update/log_error.txt'));
+ }
+ }
+ else
+ {
+ self::deltree($conf['local_data_dir'].'/update');
+ array_push($page['errors'], l10n('autoupdate_fail'));
+ }
+ }
+ else
+ {
+ array_push($page['errors'], l10n('Piwigo cannot retrieve upgrade file from server'));
+ }
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/admin/themes/default/images/ajax-loader-bar.gif b/admin/themes/default/images/ajax-loader-bar.gif
new file mode 100644
index 000000000..d84f65378
--- /dev/null
+++ b/admin/themes/default/images/ajax-loader-bar.gif
Binary files differ
diff --git a/admin/themes/default/template/admin.tpl b/admin/themes/default/template/admin.tpl
index 2daad8118..56a92a75e 100644
--- a/admin/themes/default/template/admin.tpl
+++ b/admin/themes/default/template/admin.tpl
@@ -75,6 +75,7 @@ jQuery(document).ready(function(){ldelim}
{/if}
<li><a href="{$U_MAINTENANCE}">{'Maintenance'|@translate}</a></li>
<li><a href="{$U_PENDING_COMMENTS}">{'Pending Comments'|@translate}</a></li>
+ <li><a href="{$U_UPDATES}">{'Updates'|@translate}</a></li>
</ul>
</dd>
</dl>
diff --git a/admin/themes/default/template/updates_ext.tpl b/admin/themes/default/template/updates_ext.tpl
new file mode 100644
index 000000000..d0cd7a2a7
--- /dev/null
+++ b/admin/themes/default/template/updates_ext.tpl
@@ -0,0 +1,272 @@
+{combine_script id='jquery.ajaxmanager' load='footer' require='jquery' path='themes/default/js/plugins/jquery.ajaxmanager.js'}
+{combine_script id='jquery.jgrowl' load='footer' require='jquery' path='themes/default/js/plugins/jquery.jgrowl_minimized.js'}
+{combine_css path="admin/themes/default/uploadify.jGrowl.css"}
+
+{footer_script require='jquery.effects.blind,jquery.ajaxmanager,jquery.jgrowl'}
+var pwg_token = '{$PWG_TOKEN}';
+var extList = new Array();
+var confirmMsg = '{'Are you sure?'|@translate|@escape:'javascript'}';
+var errorHead = '{'ERROR'|@translate|@escape:'javascript'}';
+var successHead = '{'Update Complete'|@translate|@escape:'javascript'}';
+var errorMsg = '{'an error happened'|@translate|@escape:'javascript'}';
+var restoreMsg = '{'Reset ignored updates'|@translate|@escape:'javascript'}';
+
+{literal}
+var todo = 0;
+var queuedManager = $.manageAjax.create('queued', {
+ queue: true,
+ maxRequests: 1,
+ beforeSend: function() { autoupdate_bar_toggle(1); },
+ complete: function() { autoupdate_bar_toggle(-1); }
+});
+
+function updateAll() {
+ if (confirm(confirmMsg)) {
+ jQuery('.updateExtension').each( function() {
+ if (jQuery(this).parents('div').css('display') == 'block')
+ jQuery(this).click();
+ });
+ }
+};
+
+function resetIgnored() {
+ jQuery.ajax({
+ type: 'GET',
+ url: 'ws.php',
+ dataType: 'json',
+ data: { method: 'pwg.extensions.ignoreUpdate', reset: true, pwg_token: pwg_token, format: 'json' },
+ success: function(data) {
+ if (data['stat'] == 'ok') {
+ jQuery(".pluginBox, fieldset").show();
+ jQuery("#update_all").show();
+ jQuery("#up_to_date").hide();
+ jQuery("#reset_ignore").hide();
+ jQuery("#ignored").hide();
+ checkFieldsets();
+ }
+ }
+ });
+};
+
+function checkFieldsets() {
+ var types = new Array('plugins', 'themes', 'languages');
+ var total = 0;
+ var ignored = 0;
+ for (i=0;i<3;i++) {
+ nbExtensions = 0;
+ jQuery("div[id^='"+types[i]+"_']").each(function(index) {
+ if (jQuery(this).css('display') == 'block')
+ nbExtensions++;
+ else
+ ignored++;
+ });
+ total = total + nbExtensions;
+ if (nbExtensions == 0)
+ jQuery("#"+types[i]).hide();
+ }
+
+ if (total == 0) {
+ jQuery("#update_all").hide();
+ jQuery("#up_to_date").show();
+ }
+ if (ignored > 0) {
+ jQuery("#reset_ignore").val(restoreMsg + ' (' + ignored + ')');
+ }
+};
+
+function updateExtension(type, id, revision) {
+ queuedManager.add({
+ type: 'GET',
+ dataType: 'json',
+ url: 'ws.php',
+ data: { method: 'pwg.extensions.update', type: type, id: id, revision: revision, pwg_token: pwg_token, format: 'json' },
+ success: function(data) {
+ if (data['stat'] == 'ok') {
+ jQuery.jGrowl( data['result'], { theme: 'success', header: successHead, life: 4000, sticky: false });
+ jQuery("#"+type+"_"+id).remove();
+ checkFieldsets();
+ } else {
+ jQuery.jGrowl( data['result'], { theme: 'error', header: errorHead, sticky: true });
+ }
+ },
+ error: function(data) {
+ jQuery.jGrowl( errorMsg, { theme: 'error', header: errorHead, sticky: true });
+ }
+ });
+};
+
+function ignoreExtension(type, id) {
+ jQuery.ajax({
+ type: 'GET',
+ url: 'ws.php',
+ dataType: 'json',
+ data: { method: 'pwg.extensions.ignoreUpdate', type: type, id: id, pwg_token: pwg_token, format: 'json' },
+ success: function(data) {
+ if (data['stat'] == 'ok') {
+ jQuery("#"+type+"_"+id).hide();
+ jQuery("#reset_ignore").show();
+ checkFieldsets();
+ }
+ }
+ });
+};
+
+function autoupdate_bar_toggle(i) {
+ todo = todo + i;
+ if ((i == 1 && todo == 1) || (i == -1 && todo == 0))
+ jQuery('.autoupdate_bar').toggle();
+}
+
+jQuery(document).ready(function() {
+ jQuery("td[id^='desc_'], p[id^='revdesc_']").click(function() {
+ id = this.id.split('_');
+ jQuery("#revdesc_"+id[1]).toggle('blind');
+ jQuery(".button_"+id[1]).toggle();
+ return false;
+ });
+});
+
+checkFieldsets();
+{/literal}
+{/footer_script}
+
+<div class="titrePage">
+ <h2>{'Updates'|@translate}</h2>
+</div>
+
+<div class="autoupdate_bar">
+<br>
+<input type="submit" id="update_all" value="{'Update All'|@translate}" onClick="updateAll(); return false;">
+<input type="submit" id="reset_ignore" value="{'Reset ignored updates'|@translate}" onClick="resetIgnored(); return false;" {if !$SHOW_RESET}style="display:none;"{/if}>
+</div>
+<div class="autoupdate_bar" style="display:none;">
+{'Update in progress... Please wait.'|@translate}<br><img src="admin/themes/default/images/ajax-loader-bar.gif">
+</div>
+
+<p id="up_to_date" style="display:none; text-align:left; margin-left:20px;">{'All extensions are up to date.'|@translate}</p>
+
+{if not empty($update_plugins)}
+<div>
+<fieldset id="plugins">
+<legend>{'Plugins'|@translate}</legend>
+{foreach from=$update_plugins item=plugin name=plugins_loop}
+<div class="pluginBox" id="plugins_{$plugin.EXT_ID}" {if $plugin.IGNORED}style="display:none;"{/if}>
+ <table>
+ <tr>
+ <td class="pluginBoxNameCell">
+ {$plugin.EXT_NAME}
+ </td>
+ <td>
+ <a href="#" onClick="updateExtension('plugins', '{$plugin.EXT_ID}', {$plugin.REVISION_ID});" class="updateExtension">{'Install'|@translate}</a>
+ | <a href="{$plugin.URL_DOWNLOAD}">{'Download'|@translate}</a>
+ | <a href="#" onClick="ignoreExtension('plugins', '{$plugin.EXT_ID}'); return false;">{'Ignore this update'|@translate}</a>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {'Version'|@translate} {$plugin.CURRENT_VERSION}
+ </td>
+ <td class="pluginDesc" id="desc_{$plugin.ID}">
+ <em>{'Downloads'|@translate}: {$plugin.DOWNLOADS}</em>
+ <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/plus.gif" alt="" class="button_{$plugin.ID}">
+ <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/minus.gif" alt="" class="button_{$plugin.ID}" style="display:none;">
+ {'New Version'|@translate} : {$plugin.NEW_VERSION}
+ | {'By %s'|@translate|@sprintf:$plugin.AUTHOR}
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="pluginDesc">
+ <p id="revdesc_{$plugin.ID}" style="display:none;">{$plugin.REV_DESC|htmlspecialchars|nl2br}</p>
+ </td>
+ </tr>
+ </table>
+</div>
+{/foreach}
+</fieldset>
+</div>
+{/if}
+
+{if not empty($update_themes)}
+<div>
+<fieldset id="themes">
+<legend>{'Themes'|@translate}</legend>
+{foreach from=$update_themes item=theme name=themes_loop}
+<div class="pluginBox" id="themes_{$theme.EXT_ID}" {if $theme.IGNORED}style="display:none;"{/if}>
+ <table>
+ <tr>
+ <td class="pluginBoxNameCell">
+ {$theme.EXT_NAME}
+ </td>
+ <td>
+ <a href="#" onClick="updateExtension('themes', '{$theme.EXT_ID}', {$theme.REVISION_ID});" class="updateExtension">{'Install'|@translate}</a>
+ | <a href="{$theme.URL_DOWNLOAD}">{'Download'|@translate}</a>
+ | <a href="#" onClick="ignoreExtension('themes', '{$theme.EXT_ID}'); return false;">{'autoupdate_ignore'|@translate}</a>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {'Version'|@translate} {$theme.CURRENT_VERSION}
+ </td>
+ <td class="pluginDesc" id="desc_{$theme.ID}">
+ <em>{'Downloads'|@translate}: {$theme.DOWNLOADS}</em>
+ <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/plus.gif" alt="" class="button_{$theme.ID}">
+ <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/minus.gif" alt="" class="button_{$theme.ID}" style="display:none;">
+ {'New Version'|@translate} : {$theme.NEW_VERSION}
+ | {'By %s'|@translate|@sprintf:$theme.AUTHOR}
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="pluginDesc">
+ <p id="revdesc_{$theme.ID}" style="display:none;">{$theme.REV_DESC|htmlspecialchars|nl2br}</p>
+ </td>
+ </tr>
+ </table>
+</div>
+{/foreach}
+</fieldset>
+</div>
+{/if}
+
+{if not empty($update_languages)}
+<div>
+<fieldset id="languages">
+<legend>{'Languages'|@translate}</legend>
+{foreach from=$update_languages item=language name=languages_loop}
+<div class="pluginBox" id="languages_{$language.EXT_ID}" {if $language.IGNORED}style="display:none;"{/if}>
+ <table>
+ <tr>
+ <td class="pluginBoxNameCell">
+ {$language.EXT_NAME}
+ </td>
+ <td>
+ <a href="#" onClick="updateExtension('languages', '{$language.EXT_ID}', {$language.REVISION_ID});" class="updateExtension">{'Install'|@translate}</a>
+ | <a href="{$language.URL_DOWNLOAD}">{'Download'|@translate}</a>
+ | <a href="#" onClick="ignoreExtension('languages', '{$language.EXT_ID}'); return false;">{'autoupdate_ignore'|@translate}</a>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ {'Version'|@translate} {$language.CURRENT_VERSION}
+ </td>
+ <td class="pluginDesc" id="desc_{$language.ID}">
+ <em>{'Downloads'|@translate}: {$language.DOWNLOADS}</em>
+ <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/plus.gif" alt="" class="button_{$language.ID}">
+ <img src="{$ROOT_URL}{$themeconf.admin_icon_dir}/minus.gif" alt="" class="button_{$language.ID}" style="display:none;">
+ {'New Version'|@translate} : {$language.NEW_VERSION}
+ | {'By %s'|@translate|@sprintf:$language.AUTHOR}
+ </td>
+ </tr>
+ <tr>
+ <td></td>
+ <td class="pluginDesc">
+ <p id="revdesc_{$language.ID}" style="display:none;">{$language.REV_DESC|htmlspecialchars|nl2br}</p>
+ </td>
+ </tr>
+ </table>
+</div>
+{/foreach}
+</fieldset>
+</div>
+{/if}
diff --git a/admin/themes/default/template/updates_pwg.tpl b/admin/themes/default/template/updates_pwg.tpl
new file mode 100644
index 000000000..c85e1fb6b
--- /dev/null
+++ b/admin/themes/default/template/updates_pwg.tpl
@@ -0,0 +1,99 @@
+{footer_script}
+jQuery(document).ready(function() {ldelim}
+ jQuery('input[name="submit"]').click(function() {ldelim}
+ if(!confirm('{'autoupdate_alert'|@translate}'))
+ return false;
+ jQuery(this).hide();
+ jQuery('.autoupdate_bar').show();
+ });
+ jQuery('[name="understand"]').click(function() {ldelim}
+ jQuery('[name="submit"]').attr('disabled', !this.checked);
+ });
+});
+{/footer_script}
+
+{html_head}
+{literal}
+<style type="text/css">
+form { width: 750px; }
+fieldset { padding-bottom: 30px; }
+p, form p { text-align: left; margin-left:20px; }
+li { margin: 5px; }
+</style>
+{/literal}
+{/html_head}
+
+<div class="titrePage">
+<h2>{'Updates'|@translate}</h2>
+</div>
+
+{if $STEP == 0}
+ {if $CHECK_VERSION}
+ <p>{'You are running the latest version of Piwigo.'|@translate}</p>
+ {elseif $DEV_VERSION}
+ <p>{'You are running on development sources, no check possible.'|@translate}</p>
+ {else}
+ <p>{'Check for update failed for unknown reasons.'|@translate}</p>
+ {/if}
+{/if}
+
+{if $STEP == 1}
+<h4>{'Two updates are available'|@translate}:</h4>
+<p>
+<ul>
+ <li><a href="admin.php?page=updates&amp;step=2&amp;to={$MINOR_VERSION}"><strong>{'Update to Piwigo %s'|@translate|@sprintf:$MINOR_VERSION}</strong></a>: {'This is a minor update, with only bug corrections.'|@translate}</li>
+ <li><a href="admin.php?page=updates&amp;step=3&amp;to={$MAJOR_VERSION}"><strong>{'Update to Piwigo %s'|@translate|@sprintf:$MAJOR_VERSION}</strong></a>: {'This is a major update, with <a href="%s">new exciting features</a>.'|@translate|@sprintf:$RELEASE_URL} {'Some themes and plugins may be not available yet.'|@translate}</li>
+</ul>
+</p>
+<p>{'You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'|@translate|@sprintf:$MAJOR_VERSION:$MINOR_VERSION}</p>
+{/if}
+
+{if $STEP == 2}
+<p>
+ {'A new version of Piwigo is available.'|@translate}<br>
+ {'This is a minor update, with only bug corrections.'|@translate}
+</p>
+<form action="" method="post">
+<p><input type="submit" name="submit" value="{'Update to Piwigo %s'|@translate|@sprintf:$UPGRADE_TO}"></p>
+<p class="autoupdate_bar" style="display:none;">&nbsp; {'Update in progress...'|@translate}<br><img src="admin/themes/default/images/ajax-loader-bar.gif"></p>
+<p><input type="hidden" name="upgrade_to" value="{$UPGRADE_TO}"></p>
+</form>
+{/if}
+
+{if $STEP == 3}
+<p>
+ {'A new version of Piwigo is available.'|@translate}<br>
+ {'This is a major update, with <a href="%s">new exciting features</a>.'|@translate|@sprintf:$RELEASE_URL} {'Some themes and plugins may be not available yet.'|@translate}
+</p>
+<form action="" method="post">
+
+{counter assign=i}
+<fieldset>
+ <legend>{'Dump Database'|@translate}</legend>
+ <p><input type="checkbox" name="includeHistory"> &nbsp; {'Include history data (Warning: server memory limit may be exceeded)'|@translate}</p>
+ <p><input type="submit" name="dumpDatabase" value="{'Dump Database'|@translate}"></p>
+</fieldset>
+
+{counter assign=i}
+<fieldset>
+ <legend>{'Update to Piwigo %s'|@translate|@sprintf:$UPGRADE_TO}</legend>
+ {if !empty($missing.plugins)}
+ <p><i>{'Following plugins may not be compatible with the new version of Piwigo:'|@translate}</i></p>
+ <p><ul>{foreach from=$missing.plugins item=plugin}<li><a href="{$plugin.uri}" class="externalLink">{$plugin.name}</a></li>{/foreach}</ul><br></p>
+ {/if}
+ {if !empty($missing.themes)}
+ <p><i>{'Following themes may not be compatible with the new version of Piwigo:'|@translate}</i></p>
+ <p><ul>{foreach from=$missing.themes item=theme}<li><a href="{$theme.uri}" class="externalLink">{$theme.name}</a></li>{/foreach}</ul><br></p>
+ {/if}
+ <p>
+ {if !empty($missing.plugins) or !empty($missing.themes)}
+ <p><label><input type="checkbox" name="understand"> &nbsp;{'I decide to update anyway'|@translate}</label></p>
+ {/if}
+ <p><input type="submit" name="submit" value="{'Update to Piwigo %s'|@translate|@sprintf:$UPGRADE_TO}" {if !empty($missing.plugins) or !empty($missing.themes)}disabled="disabled"{/if}>
+ </p>
+ <p class="autoupdate_bar" style="display:none;">&nbsp; {'Update in progress...'|@translate}<br><img src="admin/themes/default/images/ajax-loader-bar.gif"></p>
+</fieldset>
+
+<p><input type="hidden" name="upgrade_to" value="{$UPGRADE_TO}"></p>
+</form>
+{/if} \ No newline at end of file
diff --git a/admin/updates.php b/admin/updates.php
new file mode 100644
index 000000000..97c56a2cd
--- /dev/null
+++ b/admin/updates.php
@@ -0,0 +1,44 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2010 Pierrick LE GALL http://piwigo.org |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+ die ("Hacking attempt!");
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/tabsheet.class.php');
+
+$my_base_url = get_root_url().'admin.php?page=updates';
+
+if (isset($_GET['tab']))
+ $page['tab'] = $_GET['tab'];
+else
+ $page['tab'] = 'pwg';
+
+$tabsheet = new tabsheet();
+$tabsheet->add('pwg', l10n('Piwigo Update'), $my_base_url);
+$tabsheet->add('ext', l10n('Extensions Update'), $my_base_url.'&amp;tab=ext');
+$tabsheet->select($page['tab']);
+$tabsheet->assign();
+
+include(PHPWG_ROOT_PATH.'admin/updates_'.$page['tab'].'.php');
+
+?> \ No newline at end of file
diff --git a/admin/updates_ext.php b/admin/updates_ext.php
new file mode 100644
index 000000000..4ce47b83f
--- /dev/null
+++ b/admin/updates_ext.php
@@ -0,0 +1,86 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2010 Pierrick LE GALL http://piwigo.org |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+ die ("Hacking attempt!");
+}
+
+$conf['updates_ignored'] = unserialize($conf['updates_ignored']);
+
+include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
+$autoupdate = new updates();
+
+if (!$autoupdate->get_server_extensions())
+{
+ array_push($page['errors'], l10n('Can\'t connect to server.'));
+ return;
+}
+
+foreach ($autoupdate->types as $type)
+{
+ $fs = 'fs_'.$type;
+ $server = 'server_'.$type;
+ $server_ext = $autoupdate->$type->$server;
+ $fs_ext = $autoupdate->$type->$fs;
+
+ if (empty($server_ext))
+ {
+ continue;
+ }
+
+ foreach($fs_ext as $ext_id => $fs_ext)
+ {
+ if (!isset($fs_ext['extension']) or !isset($server_ext[$fs_ext['extension']]))
+ {
+ continue;
+ }
+
+ $ext_info = $server_ext[$fs_ext['extension']];
+
+ if (!$autoupdate->version_compare($fs_ext['version'], $ext_info['revision_name'], $type))
+ {
+ $template->append('update_'.$type, array(
+ 'ID' => $ext_info['extension_id'],
+ 'REVISION_ID' => $ext_info['revision_id'],
+ 'EXT_ID' => $ext_id,
+ 'EXT_NAME' => $fs_ext['name'],
+ 'EXT_URL' => PEM_URL.'/extension_view.php?eid='.$ext_info['extension_id'],
+ 'EXT_DESC' => trim($ext_info['extension_description'], " \n\r"),
+ 'REV_DESC' => trim($ext_info['revision_description'], " \n\r"),
+ 'CURRENT_VERSION' => $fs_ext['version'],
+ 'NEW_VERSION' => $ext_info['revision_name'],
+ 'AUTHOR' => $ext_info['author_name'],
+ 'DOWNLOADS' => $ext_info['extension_nb_downloads'],
+ 'URL_DOWNLOAD' => $ext_info['download_url'] . '&amp;origin=piwigo_download',
+ 'IGNORED' => in_array($ext_id, $conf['updates_ignored'][$type]),
+ )
+ );
+ }
+ }
+}
+
+$template->assign('SHOW_RESET', (!empty($conf['updates_ignored']['plugins']) or !empty($conf['updates_ignored']['themes']) or !empty($conf['updates_ignored']['languages'])));
+$template->assign('PWG_TOKEN', get_pwg_token());
+$template->set_filename('plugin_admin_content', 'updates_ext.tpl');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+
+?> \ No newline at end of file
diff --git a/admin/updates_pwg.php b/admin/updates_pwg.php
new file mode 100644
index 000000000..016deeecd
--- /dev/null
+++ b/admin/updates_pwg.php
@@ -0,0 +1,166 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2010 Pierrick LE GALL http://piwigo.org |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if( !defined("PHPWG_ROOT_PATH") )
+{
+ die ("Hacking attempt!");
+}
+
+include_once(PHPWG_ROOT_PATH.'admin/include/updates.class.php');
+include_once(PHPWG_ROOT_PATH.'admin/include/pclzip.lib.php');
+
+/*
+STEP:
+0 = check is needed. If version is latest or check fail, we stay on step 0
+1 = new version on same branch AND new branch are available => user may choose upgrade.
+2 = upgrade on same branch
+3 = upgrade on different branch
+*/
+$step = isset($_GET['step']) ? $_GET['step'] : 0;
+$upgrade_to = isset($_GET['to']) ? $_GET['to'] : '';
+
+// +-----------------------------------------------------------------------+
+// | Step 0 |
+// +-----------------------------------------------------------------------+
+if ($step == 0)
+{
+ $template->assign(array(
+ 'CHECK_VERSION' => false,
+ 'DEV_VERSION' => false,
+ )
+ );
+
+ if (preg_match('/(\d+\.\d+)\.(\d+)/', PHPWG_VERSION, $matches))
+ {
+ $url = PHPWG_URL.'/download/all_versions.php';
+ $url .= '?rand='.md5(uniqid(rand(), true)); // Avoid server cache
+
+ if (@fetchRemote($url, $result)
+ and $all_versions = @explode("\n", $result)
+ and is_array($all_versions))
+ {
+ $template->assign('CHECK_VERSION', true);
+
+ $last_version = trim($all_versions[0]);
+ $upgrade_to = $last_version;
+
+ if (version_compare(PHPWG_VERSION, $last_version, '<'))
+ {
+ $new_branch = preg_replace('/(\d+\.\d+)\.\d+/', '$1', $last_version);
+ $actual_branch = $matches[1];
+
+ if ($new_branch == $actual_branch)
+ {
+ $step = 2;
+ }
+ else
+ {
+ $step = 3;
+
+ // Check if new version exists in same branch
+ foreach ($all_versions as $version)
+ {
+ $new_branch = preg_replace('/(\d+\.\d+)\.\d+/', '$1', $version);
+
+ if ($new_branch == $actual_branch)
+ {
+ if (version_compare(PHPWG_VERSION, $version, '<'))
+ {
+ $step = 1;
+ }
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ $template->assign('DEV_VERSION', true);
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | Step 1 |
+// +-----------------------------------------------------------------------+
+if ($step == 1)
+{
+ $template->assign(array(
+ 'MINOR_VERSION' => $version,
+ 'MAJOR_VERSION' => $last_version,
+ )
+ );
+}
+
+// +-----------------------------------------------------------------------+
+// | Step 2 |
+// +-----------------------------------------------------------------------+
+if ($step == 2 and is_webmaster())
+{
+ if (isset($_POST['submit']) and isset($_POST['upgrade_to']))
+ {
+ updates::upgrade_to($_POST['upgrade_to'], $step);
+ }
+}
+
+// +-----------------------------------------------------------------------+
+// | Step 3 |
+// +-----------------------------------------------------------------------+
+if ($step == 3 and is_webmaster())
+{
+ if (isset($_POST['dumpDatabase']))
+ {
+ updates::dump_database(isset($_POST['includeHistory']));
+ }
+
+ if (isset($_POST['submit']) and isset($_POST['upgrade_to']))
+ {
+ updates::upgrade_to($_POST['upgrade_to'], $step);
+ }
+
+ $updates = new updates();
+ $updates->get_merged_extensions($upgrade_to);
+ $updates->get_server_extensions($upgrade_to);
+ $template->assign('missing', $updates->missing);
+}
+
+// +-----------------------------------------------------------------------+
+// | Process template |
+// +-----------------------------------------------------------------------+
+
+if (!is_webmaster())
+{
+ array_push($page['errors'], l10n('Webmaster status is required.'));
+}
+
+$template->assign(array(
+ 'STEP' => $step,
+ 'PHPWG_VERSION' => PHPWG_VERSION,
+ 'UPGRADE_TO' => $upgrade_to,
+ 'RELEASE_URL' => PHPWG_URL.'/releases/'.$upgrade_to,
+ )
+);
+
+$template->set_filename('plugin_admin_content', 'updates_pwg.tpl');
+$template->assign_var_from_handle('ADMIN_CONTENT', 'plugin_admin_content');
+
+?> \ No newline at end of file
diff --git a/include/ws_functions.inc.php b/include/ws_functions.inc.php
index 0bf39d61b..0aaa5f561 100644
--- a/include/ws_functions.inc.php
+++ b/include/ws_functions.inc.php
@@ -2735,4 +2735,140 @@ WHERE id = '.(int)$params['image_id'].'
}
return false;
}
+
+function ws_extensions_update($params, &$service)
+{
+ if (!is_webmaster())
+ {
+ return new PwgError(401, l10n('Webmaster status is required.'));
+ }
+
+ if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ if (empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
+ {
+ return new PwgError(403, "invalid extension type");
+ }
+
+ if (empty($params['id']) or empty($params['revision']))
+ {
+ return new PwgError(null, 'Wrong parameters');
+ }
+
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+ include_once(PHPWG_ROOT_PATH.'admin/include/'.$params['type'].'.class.php');
+
+ $type = $params['type'];
+ $extension_id = $params['id'];
+ $revision = $params['revision'];
+
+ $extension = new $type();
+
+ if ($type == 'plugins')
+ {
+ if (isset($extension->db_plugins_by_id[$extension_id]) and $extension->db_plugins_by_id[$extension_id]['state'] == 'active')
+ {
+ $extension->perform_action('deactivate', $extension_id);
+
+ redirect(PHPWG_ROOT_PATH
+ . 'ws.php'
+ . '?method=pwg.extensions.update'
+ . '&type=plugins'
+ . '&id=' . $extension_id
+ . '&revision=' . $revision
+ . '&reactivate=true'
+ . '&pwg_token=' . get_pwg_token()
+ . '&format=json'
+ );
+ }
+
+ $upgrade_status = $extension->extract_plugin_files('upgrade', $revision, $extension_id);
+ $extension_name = $extension->fs_plugins[$extension_id]['name'];
+
+ if (isset($params['reactivate']))
+ {
+ $extension->perform_action('activate', $extension_id);
+ }
+ }
+ elseif ($type == 'themes')
+ {
+ $upgrade_status = $extension->extract_theme_files('upgrade', $revision, $extension_id);
+ $extension_name = $extension->fs_themes[$extension_id]['name'];
+ }
+ elseif ($type == 'languages')
+ {
+ $upgrade_status = $extension->extract_language_files('upgrade', $revision, $extension_id);
+ $extension_name = $extension->fs_languages[$extension_id]['name'];
+ }
+
+ global $template;
+ $template->delete_compiled_templates();
+
+ switch ($upgrade_status)
+ {
+ case 'ok':
+ return sprintf(l10n('%s has been successfully updated.'), $extension_name);
+
+ case 'temp_path_error':
+ return new PwgError(null, l10n('Can\'t create temporary file.'));
+
+ case 'dl_archive_error':
+ return new PwgError(null, l10n('Can\'t download archive.'));
+
+ case 'archive_error':
+ return new PwgError(null, l10n('Can\'t read or extract archive.'));
+
+ default:
+ return new PwgError(null, sprintf(l10n('An error occured during extraction (%s).'), $upgrade_status));
+ }
+}
+
+function ws_extensions_ignoreupdate($params, &$service)
+{
+ global $conf;
+
+ define('IN_ADMIN', true);
+ include_once(PHPWG_ROOT_PATH.'admin/include/functions.php');
+
+ if (!is_webmaster())
+ {
+ return new PwgError(401, 'Access denied');
+ }
+
+ if (empty($params['pwg_token']) or get_pwg_token() != $params['pwg_token'])
+ {
+ return new PwgError(403, 'Invalid security token');
+ }
+
+ $conf['updates_ignored'] = unserialize($conf['updates_ignored']);
+
+ if ($params['reset'])
+ {
+ $conf['updates_ignored'] = array(
+ 'plugins'=>array(),
+ 'themes'=>array(),
+ 'languages'=>array()
+ );
+ conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
+ unset($_SESSION['extensions_need_update']);
+ return true;
+ }
+
+ if (empty($params['id']) or empty($params['type']) or !in_array($params['type'], array('plugins', 'themes', 'languages')))
+ {
+ return new PwgError(403, 'Invalid parameters');
+ }
+
+ // Add or remove extension from ignore list
+ if (!in_array($params['id'], $conf['updates_ignored'][$params['type']]))
+ {
+ array_push($conf['updates_ignored'][$params['type']], $params['id']);
+ }
+ conf_update_param('updates_ignored', pwg_db_real_escape_string(serialize($conf['updates_ignored'])));
+ unset($_SESSION['extensions_need_update']);
+ return true;
+}
?>
diff --git a/install/config.sql b/install/config.sql
index dd8c94c67..205e06481 100644
--- a/install/config.sql
+++ b/install/config.sql
@@ -49,3 +49,4 @@ INSERT INTO piwigo_config (param,value,comment)
'Information displayed on picture page'
);
INSERT INTO piwigo_config (param,value,comment) VALUES ('week_starts_on','monday','Monday may not be the first day of the week');
+INSERT INTO piwigo_config (param,value,comment) VALUES ('updates_ignored','a:3:{s:7:"plugins";a:0:{}s:6:"themes";a:0:{}s:9:"languages";a:0:{}}','Extensions ignored for update');
diff --git a/install/db/103-database.php b/install/db/103-database.php
new file mode 100644
index 000000000..15424370d
--- /dev/null
+++ b/install/db/103-database.php
@@ -0,0 +1,42 @@
+<?php
+// +-----------------------------------------------------------------------+
+// | Piwigo - a PHP based photo gallery |
+// +-----------------------------------------------------------------------+
+// | Copyright(C) 2008-2011 Piwigo Team http://piwigo.org |
+// | Copyright(C) 2003-2008 PhpWebGallery Team http://phpwebgallery.net |
+// | Copyright(C) 2002-2003 Pierrick LE GALL http://le-gall.net/pierrick |
+// +-----------------------------------------------------------------------+
+// | This program is free software; you can redistribute it and/or modify |
+// | it under the terms of the GNU General Public License as published by |
+// | the Free Software Foundation |
+// | |
+// | This program is distributed in the hope that it will be useful, but |
+// | WITHOUT ANY WARRANTY; without even the implied warranty of |
+// | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
+// | General Public License for more details. |
+// | |
+// | You should have received a copy of the GNU General Public License |
+// | along with this program; if not, write to the Free Software |
+// | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, |
+// | USA. |
+// +-----------------------------------------------------------------------+
+
+if (!defined('PHPWG_ROOT_PATH'))
+{
+ die('Hacking attempt!');
+}
+
+$upgrade_description = 'Extensions ignored for update';
+
+$query = '
+INSERT INTO '.PREFIX_TABLE.'config (param,value,comment)
+ VALUES (\'updates_ignored\',\'a:3:{s:7:"plugins";a:0:{}s:6:"themes";a:0:{}s:9:"languages";a:0:{}}\', \''.$upgrade_description.'\')
+;';
+pwg_query($query);
+
+echo
+"\n"
+. $upgrade_description
+."\n"
+;
+?> \ No newline at end of file
diff --git a/language/en_UK/admin.lang.php b/language/en_UK/admin.lang.php
index 3b8459058..5b70871c3 100644
--- a/language/en_UK/admin.lang.php
+++ b/language/en_UK/admin.lang.php
@@ -796,4 +796,30 @@ $lang['%s thumbnails can not be regenerated'] = '%s thumbnails can not be regene
$lang['%s photos have been regenerated'] = '%s photos have been regenerated';
$lang['%s photos can not be regenerated'] = '%s photos can not be regenerated';
$lang['Only photos with HD can be regenerated!'] = 'Only photos with HD can be regenerated!';
+
+$lang['Updates'] = 'Updates';
+$lang['Update in progress... Please wait.'] = 'Update in progress... Please wait.';
+$lang['Ignore this update'] = 'Ignore this update';
+$lang['Reset ignored updates'] = 'Reset ignored updates';
+$lang['Update All'] = 'Update All';
+$lang['ERROR'] = 'ERROR';
+$lang['Update Complete'] = 'Update Complete';
+$lang['Piwigo Update'] = 'Piwigo Update';
+$lang['Extensions Update'] = 'Extensions Update';
+$lang['All extensions are up to date.'] = 'All extensions are up to date.';
+$lang['Following plugins may not be compatible with the new version of Piwigo:'] = 'Following plugins may not be compatible with the new version of Piwigo:';
+$lang['Following themes may not be compatible with the new version of Piwigo:'] = 'Following themes may not be compatible with the new version of Piwigo:';
+$lang['I decide to update anyway'] = 'I decide to update anyway';
+$lang['Update to Piwigo %s'] = 'Update to Piwigo %s';
+$lang['Two updates are available'] = 'Two updates are available';
+$lang['This is a minor update, with only bug corrections.'] = 'This is a minor update, with only bug corrections.';
+$lang['This is a major update, with <a href="%s">new exciting features</a>.'] = 'This is a major update, with <a href="%s">new exciting features</a>.';
+$lang['Some themes and plugins may be not available yet.'] = 'Some themes and plugins may be not available yet.';
+$lang['You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'] = 'You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).';
+$lang['Save Template Directory'] = 'Save template directory';
+$lang['Dump Database'] = 'Dump Database';
+$lang['Include history data (Warning: server memory limit may be exceeded)'] = 'Include history data (Warning: server memory limit may be exceeded)';
+$lang['Unable to write new local directory.'] = 'Unable to write new local directory.';
+$lang['Unable to send template directory.'] = 'Unable to send template directory.';
+$lang['Unable to dump database.'] = 'Unable to dump database.';
?> \ No newline at end of file
diff --git a/language/fr_FR/admin.lang.php b/language/fr_FR/admin.lang.php
index 298a0b56c..92239633c 100644
--- a/language/fr_FR/admin.lang.php
+++ b/language/fr_FR/admin.lang.php
@@ -807,4 +807,30 @@ $lang['%s thumbnails can not be regenerated'] = '%s miniatures ne peuvent pas ĂȘ
$lang['%s photos have been regenerated'] = '%s photos ont été régénérées';
$lang['%s photos can not be regenerated'] = '%s photos ne peuvent pas ĂȘtre rĂ©gĂ©nĂ©rĂ©es';
$lang['Only photos with HD can be regenerated!'] = 'Seules les photos avec HD peuvent ĂȘtre rĂ©gĂ©nĂ©rĂ©es';
+
+$lang['Updates'] = 'Mises Ă  jour';
+$lang['Update in progress... Please wait.'] = 'Mise Ă  jour en cours... Veuillez patienter.';
+$lang['Ignore this update'] = 'Ignorer cette mise Ă  jour';
+$lang['Reset ignored updates'] = 'Réinitialiser les mises à jour ignorées';
+$lang['Update All'] = 'Tout mettre Ă  jour';
+$lang['ERROR'] = 'ERREUR';
+$lang['Update Complete'] = 'Mise à jour effectuée';
+$lang['Piwigo Update'] = 'Mise Ă  jour de Piwigo';
+$lang['Extensions Update'] = 'Mise Ă  jour des extensions';
+$lang['All extensions are up to date.'] = 'Toutes les extensions sont Ă  jour.';
+$lang['Following plugins may not be compatible with the new version of Piwigo:'] = 'Les plugins suivants ne seront peut-ĂȘtre pas compatibles avec la nouvelle version de Piwigo:';
+$lang['Following themes may not be compatible with the new version of Piwigo:'] = 'Les thĂšmes suivants ne seront peut-ĂȘtre pas compatibles avec la nouvelle version de Piwigo:';
+$lang['I decide to update anyway'] = 'Je dĂ©cide de migrer quand mĂȘme';
+$lang['Update to Piwigo %s'] = 'Mettre Ă  jour vers Piwigo %s';
+$lang['Two updates are available'] = 'Deux mises Ă  jour sont disponibles';
+$lang['This is a minor update, with only bug corrections.'] = 'Ceci est une mise Ă  jour mineure, avec uniquement des corrections de bugs.';
+$lang['This is a major update, with <a href="%s">new exciting features</a>.'] = 'Ceci est une mise à jour majeure, qui contient <a href="%s">un tas de nouveautés</a>.';
+$lang['Some themes and plugins may be not available yet.'] = 'Certains thĂšmes ou plugins ne sont peut-ĂȘtre pas encore disponibles.';
+$lang['You can update to Piwigo %s directly, without upgrading to Piwigo %s (recommended).'] = 'Vous pouvez mettre à jour vers Piwigo %s directement, sans passer par Piwigo %s (recommandé).';
+$lang['Save Template Directory'] = 'Sauvegarder le dossier template';
+$lang['Dump Database'] = 'Sauvegarder la base de données';
+$lang['Include history data (Warning: server memory limit may be exceeded)'] = 'Inclure les données de l\'historique (Attention: risque de dépassement de la limite mémoire du serveur)';
+$lang['Unable to write new local directory.'] = 'Impossible d\'Ă©crire le nouveau dossier local.';
+$lang['Unable to send template directory.'] = 'Impossible d\'envoyer le dossier template.';
+$lang['Unable to dump database.'] = 'Impossible de sauvegarder la base de données.';
?> \ No newline at end of file
diff --git a/ws.php b/ws.php
index 0df265783..046ee4743 100644
--- a/ws.php
+++ b/ws.php
@@ -418,6 +418,33 @@ function ws_addDefaultMethods( $arr )
<br>Argument "type" can be "thumbnail" or "websize". Default is "thumbnail".
<br>If maxwidth, maxheight or quality are missing, default parameters of upload will be used.'
);
+
+ $service->addMethod(
+ 'pwg.extensions.update',
+ 'ws_extensions_update',
+ array(
+ 'type' => array(),
+ 'id' => array(),
+ 'revision'=> array(),
+ 'pwg_token' => array(),
+ ),
+ 'Update an extension. Webmaster only.
+<br>Parameter type must be "plugins", "languages" or "themes".'
+ );
+
+ $service->addMethod(
+ 'pwg.extensions.ignoreUpdate',
+ 'ws_extensions_ignoreupdate',
+ array(
+ 'type' => array('default'=>null),
+ 'id' => array('default'=>null),
+ 'reset' => array('default'=>null),
+ 'pwg_token' => array(),
+ ),
+ 'Ignore an extension if it need update.
+<br>Parameter type must be "plugins", "languages" or "themes".
+<br>If reset parameter is true, all ignored extensions will be reinitilized.'
+ );
}
add_event_handler('ws_add_methods', 'ws_addDefaultMethods');