diff --git a/Client.php b/Client.php index 1ec6cf2..9aa0e9c 100644 --- a/Client.php +++ b/Client.php @@ -17,16 +17,16 @@ class Client extends \IXR_Client { * @param int $timeout */ public function __construct($server, $user, $pass, $timeout = 15) { - parent::__construct($server); - $this->timeout = $timeout; + parent::__construct($server, $path = false, $port = 80, $timeout); $this->login($user, $pass); } /** @inheritdoc */ - public function query() { + public function query(...$args) { $ok = call_user_func_array('parent::query', func_get_args()); - $code = $this->getErrorCode(); - if($code === -32300) $code = -1 * $this->status; // use http status on transport errors + $code = @$this->getErrorCode(); + $http = $this->getHTTPClient(); + if($code === -32300) $code = -1 * $http->status; // use http status on transport errors if(!$ok) { // when a file context is given include it in the exception if($this->filecontext) { diff --git a/Profile.php b/Profile.php index a6024c7..836349f 100644 --- a/Profile.php +++ b/Profile.php @@ -2,6 +2,8 @@ namespace dokuwiki\plugin\sync; +use dokuwiki\Utf8\Sort; + class Profile { const DIR_PULL = -1; @@ -31,6 +33,7 @@ public function __construct($config) { $this->config = $config; $this->syncoptions = [ + 'pattern' => '', 'depth' => (int) $config['depth'], 'hash' => true, ]; @@ -261,13 +264,14 @@ protected function setRemoteLock($id, $state) { */ protected function fetchRemoteFileList($type) { if($type === self::TYPE_PAGES) { - $cmd = 'dokuwiki.getPagelist'; + $cmd = 'core.listPages'; + $this->client->query($cmd, $this->config['ns'], $this->syncoptions['depth'], $this->syncoptions['hash']); } else { - $cmd = 'wiki.getAttachments'; + $cmd = 'core.listMedia'; + $this->client->query($cmd, $this->config['ns'], $this->syncoptions['pattern'], $this->syncoptions['depth'], $this->syncoptions['hash']); } - $this->client->query($cmd, $this->config['ns'], $this->syncoptions); - $remote = $this->client->getResponse(); + $remote = @$this->client->getResponse(); // put into synclist foreach($remote as $item) { @@ -291,9 +295,16 @@ protected function fetchLocalFileList($type) { $cmd = 'search_media'; } + $syncoptions = $this->syncoptions; + if($type === self::TYPE_PAGES) { + if($syncoptions['depth']) { + $syncoptions['depth'] += substr_count($this->config['ns'], ':') + 1; + } + } + $local = array(); $dir = utf8_encodeFN(str_replace(':', '/', $this->config['ns'])); - search($local, $basedir, $cmd, $this->syncoptions, $dir); + search($local, $basedir, $cmd, $syncoptions, $dir); // put into synclist foreach($local as $item) { @@ -308,7 +319,11 @@ protected function fetchLocalFileList($type) { * @return mixed */ protected function itemEnhance($item) { - $item['info'] = dformat($item['mtime']) . '' . filesize_h($item['size']); + if(isset($item['mtime'])) { + $item['info'] = dformat($item['mtime']) . '' . filesize_h($item['size']); + } else { + $item['info'] = dformat($item['revision']) . '' . filesize_h($item['size']); + } return $item; } @@ -317,42 +332,47 @@ protected function itemEnhance($item) { */ protected function consolidateSyncList() { // synctimes - $ltime = (int) $this->config['ltime']; - $rtime = (int) $this->config['rtime']; - $letime = (int) $this->config['letime']; - $retime = (int) $this->config['retime']; + $ltime = isset($this->config['ltime']) ? (int) $this->config['ltime'] : null; + $rtime = isset($this->config['rtime']) ? (int) $this->config['rtime'] : null; + $letime = isset($this->config['letime']) ? (int) $this->config['letime'] : null; + $retime = isset($this->config['retime']) ? (int) $this->config['retime'] : null; foreach([self::TYPE_PAGES, self::TYPE_MEDIA] as $type) { foreach($this->synclist[$type] as $id => $item) { // no sync if hashes match - if($item['remote']['hash'] == $item['local']['hash']) { - unset($this->synclist[$type][$id]); - continue; + if(isset($item['remote']['hash']) && isset($item['local']['hash'])) { + if($item['remote']['hash'] == $item['local']['hash']) { + unset($this->synclist[$type][$id]); + continue; + } } // check direction $dir = self::DIR_NONE; if($ltime && $rtime) { // synced before - if($item['remote']['mtime'] > $rtime && - $item['local']['mtime'] <= $letime - ) { - $dir = self::DIR_PULL; - } - if($item['remote']['mtime'] <= $retime && - $item['local']['mtime'] > $ltime - ) { - $dir = self::DIR_PUSH; + if(isset($item['local']['mtime']) && isset($item['remote']['revision'])) { + if($item['remote']['revision'] > $rtime && + $item['local']['mtime'] <= $letime + ) { + $dir = self::DIR_PULL; + } + if($item['remote']['revision'] <= $retime && + $item['local']['mtime'] > $ltime + ) { + $dir = self::DIR_PUSH; + } } } else { // never synced - if(!$item['local']['mtime'] && $item['remote']['mtime']) { + if(!isset($item['local']['mtime']) && $item['remote']['revision']) { $dir = self::DIR_PULL; } - if($item['local']['mtime'] && !$item['remote']['mtime']) { + if((isset($item['local']['mtime']) && $item['local']['mtime']) && !isset($item['remote']['revision'])) { $dir = self::DIR_PUSH; } } $this->synclist[$type][$id]['dir'] = $dir; } + Sort::ksort($this->synclist[$type]); } } diff --git a/SyncException.php b/SyncException.php index 843d9e2..d0f4f70 100644 --- a/SyncException.php +++ b/SyncException.php @@ -23,6 +23,6 @@ public function __construct($message = '', $code = 0, $previous = null) { if($code === -403) $message = $plugin->getLang('autherr'); - parent::__construct($message, $code, $previous); + parent::__construct(html_entity_decode($message), $code, $previous); } } diff --git a/SyncFileException.php b/SyncFileException.php index 54d2a8a..ea84f4e 100644 --- a/SyncFileException.php +++ b/SyncFileException.php @@ -28,6 +28,6 @@ public function __construct($message, $id, $code = 0) { // append file name $message = $message . ' ' . $id; - parent::__construct($message, $code); + parent::__construct(html_entity_decode($message), $code); } } diff --git a/admin.php b/admin.php index 9e93a8a..0f80d9b 100644 --- a/admin.php +++ b/admin.php @@ -55,11 +55,11 @@ function handle() { $this->profileManager->deleteProfileConfig($this->profno); $this->profno = false; $INPUT->remove('prf'); - msg('profile deleted', 1); + msg($this->getLang('profiledeleted'), 1); } else { // profile add/edit $this->profno = $this->profileManager->setProfileConfig($this->profno, $profile); - msg('profile saved', 1); + msg($this->getLang('profilesaved'), 1); } } catch(SyncException $e) { msg(hsc($e->getMessage()), -1); diff --git a/lang/en/lang.php b/lang/en/lang.php index 12bb6e8..ab99872 100644 --- a/lang/en/lang.php +++ b/lang/en/lang.php @@ -40,6 +40,9 @@ $lang['lockfail'] = 'couldn\'t lock and will skip:'; $lang['localdelfail'] = 'local delete failed:'; +$lang['profilesaved'] = 'profile saved.'; +$lang['profiledeleted'] = 'profile deleted.'; + $lang['js']['list'] = 'A list of files that differ between your local and the remote wiki is shown below. You need to decide which revisions you want to keep.'; #from list.txt $lang['js']['file'] = 'Page or Media File'; diff --git a/lang/pt-br/intro.txt b/lang/pt-br/intro.txt new file mode 100644 index 0000000..d87bda1 --- /dev/null +++ b/lang/pt-br/intro.txt @@ -0,0 +1,4 @@ +====== Sincronização do Wiki ====== + +Esta ferramenta permite sincronizar o conteúdo do seu wiki com outros wikis. Vários outros wikis podem ser configurados usando perfis de sincronização. A sincronização pode ser restrita a determinados namespaces. + diff --git a/lang/pt-br/lang.php b/lang/pt-br/lang.php new file mode 100644 index 0000000..2f00995 --- /dev/null +++ b/lang/pt-br/lang.php @@ -0,0 +1,70 @@ + label.push input { + &:checked::before { + content: url(pix/arrow-right-bold-circle-outline.svg); + } + } + + th.dir > label.skip input { + &:checked::before { + content: url(pix/pause-circle-outline.svg); + } + } + + th.dir > label.pull input { + &:checked::before { + content: url(pix/arrow-left-bold-circle-outline.svg); + } + } } } diff --git a/sync.js b/sync.js index 8a9e49e..b9bcb2f 100644 --- a/sync.js +++ b/sync.js @@ -32,6 +32,7 @@ jQuery(function () { }); }); $output.append($table); + jQuery('input[name="dir"]').click(function(e){ sync_select(this.value); this.value = 0; }); var $lbl = jQuery(''); $lbl.text(LANG.plugins.sync.summary + ': '); @@ -59,6 +60,12 @@ jQuery(function () { var $th = jQuery(''); $th.addClass(l); $th.text(LANG.plugins.sync[l]); + if(l == 'dir') { + $th.append(''); + $th.append(''); + $th.append(''); + $th.append(''); + } $tr.append($th); }); return $tr; @@ -177,13 +184,31 @@ jQuery(function () { return $html; } + function sync_select(type) { + switch(type) { + case "1": + type = "push"; + break; + case "0": + type = "skip"; + break; + case "-1": + type = "pull"; + break; + } + const types = ["push", "skip", "pull"]; + if(types.includes(type)) { + jQuery('label[class='+type+'] input').prop('checked',true); + } + } + /** * Start the sync process */ function beginsync() { SYNC_DATA.items = []; - $output.find('tr').each(function (idx, tr) { + $output.find('tr[class^="type"]').each(function (idx, tr) { var $tr = jQuery(tr); var id = $tr.find('td').first().text(); var dir = parseInt($tr.find('input:checked').val(), 10); @@ -193,6 +218,7 @@ jQuery(function () { SYNC_DATA.items.push([id, type, dir]); } }); + SYNC_DATA.items = SYNC_DATA.items.reverse(); SYNC_DATA.summary = $sum.val(); @@ -278,7 +304,7 @@ jQuery(function () { */ function error(error) { var $err = jQuery(''); - $err.text(error); + $err.text(error.responseText); $output.append($err); }