diff --git a/_test/mediamove.test.php b/_test/mediamove.test.php index d0be785..1612eba 100644 --- a/_test/mediamove.test.php +++ b/_test/mediamove.test.php @@ -30,10 +30,34 @@ public function test_movePageWithRelativeMedia() { $opts['newname'] = 'foo'; /** @var helper_plugin_pagemove $pagemove */ $pagemove = plugin_load('helper', 'pagemove'); - $pagemove->move_page($opts); + $this->assertTrue($pagemove->move_page($opts)); $this->assertEquals('{{ mediareltest:myimage.png}} [[:start|{{ mediareltest:testimage.png?200x800 }}]] [[mediareltest:bar|{{mediareltest:testimage.gif?400x200}}]] [[doku>wiki:dokuwiki|{{wiki:logo.png}}]] [[http://www.example.com|{{mediareltest:testimage.jpg}}]] [[doku>wiki:foo|{{mediareltest:foo.gif?200x3000}}]]', rawWiki('foo')); } + + public function test_moveSingleMedia() { + global $AUTH_ACL; + + $AUTH_ACL[] = "wiki:*\t@ALL\t16"; + $AUTH_ACL[] = "foobar:*\t@ALL\t8"; + + saveWikiText('wiki:movetest', '{{wiki:dokuwiki-128.png?200}}', 'Test initialized'); + idx_addPage('wiki:movetest'); + + $opts = array(); + $opts['ns'] = 'wiki'; + $opts['name'] = 'dokuwiki-128.png'; + $opts['newns'] = 'foobar'; + $opts['newname'] = 'logo.png'; + + /** @var helper_plugin_pagemove $pagemove */ + $pagemove = plugin_load('helper', 'pagemove'); + $this->assertTrue($pagemove->move_media($opts)); + + $this->assertTrue(@file_exists(mediaFn('foobar:logo.png'))); + + //$this->assertEquals('{{foobar:logo.png?200}}', 'wiki:movetest'); + } } diff --git a/helper.php b/helper.php index a9960ca..46c7044 100644 --- a/helper.php +++ b/helper.php @@ -134,7 +134,7 @@ public function move_page(&$opts, $checkonly = false) { // give plugins the option to add their own meta files to the list of files that need to be moved // to the oldfiles/newfiles array or to adjust their own metadata, database, ... // and to add other pages to the affected pages - // note that old_ids is in the form 'id' => timestamp of move and affected_pages is indexed by these ids + // note that old_ids is in the form 'id' => timestamp of move $event = new Doku_Event('PAGEMOVE_PAGE_RENAME', $data); if ($event->advise_before()) { // Open the old document and change forward links @@ -209,6 +209,149 @@ public function move_page(&$opts, $checkonly = false) { return true; } + /** + * Move media file + * + * @author Michael Hamann + * + * @param array $opts + * @param bool $checkonly Only execute the checks if the media file can be moved + * @return bool If the move was executed + */ + public function move_media(&$opts, $checkonly = false) { + $opts['id'] = cleanID($opts['ns'].':'.$opts['name']); + $opts['path'] = mediaFN($opts['id']); + + // Check we have rights to move this document + if ( !file_exists(mediaFN($opts['id']))) { + msg(sprintf($this->getLang('pm_medianotexist'), hsc($opts['id'])), -1); + return false; + } + + if ( auth_quickaclcheck($opts['ns'].':*') < AUTH_DELETE ) { + msg(sprintf($this->getLang('pm_nomediarights'), hsc($opts['id'])), -1); + return false; + } + + // Assemble media name and path + $opts['new_id'] = cleanID($opts['newns'].':'.$opts['newname']); + $opts['new_path'] = mediaFN($opts['new_id']); + + // Has the document name and/or namespace changed? + if ( $opts['newns'] == $opts['ns'] && $opts['newname'] == $opts['name'] ) { + msg($this->getLang('pm_nomediachange'), -1); + return false; + } + // Check the page does not already exist + if ( @file_exists($opts['new_path']) ) { + msg(sprintf($this->getLang('pm_mediaexisting'), $opts['newname'], ($opts['newns'] == '' ? $this->getLang('pm_root') : $opts['newns'])), -1); + return false; + } + + // Check if the current user can create the new page + if (auth_quickaclcheck($opts['new_ns'].':*') < AUTH_UPLOAD) { + msg(sprintf($this->getLang('pm_nomediatargetperms'), $opts['new_id']), -1); + return false; + } + + if ($checkonly) return true; + + /** + * End of init (checks) + */ + + $affected_pages = idx_get_indexer()->lookupKey('pagemove_media', $opts['id']); + + $data = array('opts' => &$opts, 'affected_pages' => &$affected_pages); + // give plugins the option to add their own meta files to the list of files that need to be moved + // to the oldfiles/newfiles array or to adjust their own metadata, database, ... + // and to add other pages to the affected pages + $event = new Doku_Event('PAGEMOVE_MEDIA_RENAME', $data); + if ($event->advise_before()) { + // Move the Subscriptions & Indexes + if (method_exists('Doku_Indexer', 'renamePage')) { // new feature since Spring 2013 release + $Indexer = idx_get_indexer(); + } else { + $Indexer = new helper_plugin_pagemove_indexer(); // copy of the new code + } + if (($idx_msg = $Indexer->renameMetaValue('pagemove_media', $opts['id'], $opts['new_id'])) !== true) { + msg('Error while updating the search index '.$idx_msg, -1); + return false; + } + if (!$this->movemediameta($opts)) { + msg('The meta files of the media file '.$opts['id'].' couldn\'t be moved', -1); + return false; + } + + // prepare directory + io_createNamespace($opts['new_id'], 'media'); + + if (!io_rename($opts['path'], $opts['new_path'])) { + msg('Moving the media file '.$opts['id'].' failed', -1); + return false; + } + + // Move the old revisions + if (!$this->movemediaattic($opts)) { + // it's too late to stop the move, so just display a message. + msg('The attic files of media file '.$opts['id'].' couldn\'t be moved. Please move them manually.', -1); + } + + foreach ($affected_pages as $id) { + if (!page_exists($id, '', false)) continue; + // we are only interested in persistent metadata, so no need to render anything. + $meta = p_get_metadata($id, 'plugin_pagemove', METADATA_DONT_RENDER); + if (!$meta) $meta = array('media_moves' => array()); + if (!isset($meta['media_moves'])) $meta['media_moves'] = array(); + $meta['media_moves'] = $this->resolve_moves($meta['media_moves'], '__'); + $meta['media_moves'][$opts['id']] = $opts['new_id']; + //if (empty($meta['moves'])) unset($meta['moves']); + p_set_metadata($id, array('plugin_pagemove' => $meta), false, true); + } + } + + $event->advise_after(); + return true; + } + + /** + * Move the old revisions of the media file that is specified in the options + * + * @param array $opts Pagemove options (used here: name, newname, ns, newns) + * @return bool If the attic files were moved successfully + */ + public function movemediaattic($opts) { + global $conf; + + $ext = mimetype($opts['name']); + if ($ext[0] !== false) + $name = substr($opts['name'],0, -1*strlen($ext[0])-1); + $newext = mimetype($opts['newname']); + if ($ext[0] !== false) + $newname = substr($opts['newname'],0, -1*strlen($ext[0])-1); + $regex = '\.\d+\.'.preg_quote((string)$ext[0], '/'); + + return $this->move_files($conf['mediaolddir'], array( + 'ns' => $opts['ns'], + 'newns' => $opts['newns'], + 'name' => $name, + 'newname' => $newname + ), $regex); + } + + /** + * Move the meta files of the page that is specified in the options. + * + * @param array $opts Pagemove options (used here: name, newname, ns, newns) + * @return bool If the meta files were moved successfully + */ + public function movemediameta($opts) { + global $conf; + + $regex = '\.[^.]+'; + return $this->move_files($conf['mediametadir'], $opts, $regex); + } + /** * Move the old revisions of the page that is specified in the options. * @@ -250,6 +393,8 @@ private function move_files($dir, $opts, $extregex) { if ($opts['newns'] != '') $new_path .= '/'.utf8_encodeFN(str_replace(':', '/', $opts['newns'])); $regex = '/^'.preg_quote(utf8_encodeFN($opts['name'])).'('.$extregex.')$/u'; + if (!is_dir($old_path)) return true; // no media files found + $dh = @opendir($old_path); if($dh) { while(($file = readdir($dh)) !== false) { diff --git a/lang/en/lang.php b/lang/en/lang.php index 235e13d..73f1375 100644 --- a/lang/en/lang.php +++ b/lang/en/lang.php @@ -16,11 +16,14 @@ $lang['desc'] = 'Page/Namespace Move/Rename Plugin'; $lang['pm_notexist'] = 'The page %s does not exist'; +$lang['pm_medianotexist'] = 'The media file %s does not exist'; $lang['pm_notwrite'] = 'You do not have sufficient permissions to modify this page'; $lang['pm_badns'] = 'Invalid characters in namespace.'; $lang['pm_badname'] = 'Invalid characters in pagename.'; $lang['pm_nochange'] = 'Page name and namespace are unchanged.'; +$lang['pm_nomediachange'] = 'Media file name and namespace are unchanged.'; $lang['pm_existing'] = 'A page called %s already exists in %s'; +$lang['pm_mediaexisting'] = 'A media file called %s already exists in %s'; $lang['pm_root'] = '[Root namespace]'; $lang['pm_current'] = '(Current)'; $lang['pm_renamed'] = 'Page name changed from %s to %s'; @@ -28,7 +31,9 @@ $lang['pm_move_rename'] = 'Page moved and renamed from %s to %s'; $lang['pm_delete'] = 'Deleted by PageMove plugin'; $lang['pm_norights'] = 'You have insufficient permissions to edit %s.'; -$lang['pm_notargetperms'] = 'You don\'t have the permission to create %s.'; +$lang['pm_nomediarights'] = 'You have insufficient permissions to delete %s.'; +$lang['pm_notargetperms'] = 'You don\'t have the permission to create the page %s.'; +$lang['pm_nomediatargetperms'] = 'You don\'t have the permission to create the media file %s.'; $lang['pm_filelocked'] = 'The page %s is locked. Try again later.'; $lang['pm_linkchange'] = 'Links to %s changed to %s'; // Form labels