Skip to content

Commit

Permalink
Merge branch 'master' into psr2
Browse files Browse the repository at this point in the history
* master:
  πŸ› (Draft) Fix exception when actually viewing a draft of a page
  πŸ’‘(Draft): Add doc block for constructor
  βœ… Add unittest for deleteUsers remote API call
  fix remote API call dokuwiki.deleteUsers
  translation update
  πŸ— Use json for the response to dw_locktimer
  ✨(dw_locktimer) plugins may reuse to add fields and callbacks
  πŸ’„ (editor) draft status is semantically not part of the toolbar
  πŸ— Create new Draft class and move draft handling there
  translation update
  correctly avoid notice in init.
  avoid creating expensive stacktrace in dbg_deprecated()
  add method to EventHandler to check if an event is actually handled
  introduce INFO_DEPRECATION_LOG event
  • Loading branch information
splitbrain committed Jun 15, 2018
2 parents 1a953a5 + e954c88 commit 9ddafce
Show file tree
Hide file tree
Showing 25 changed files with 463 additions and 146 deletions.
14 changes: 14 additions & 0 deletions _test/tests/inc/remoteapicore.test.php
Expand Up @@ -449,6 +449,20 @@ public function test_getPageVersions() {
$this->assertEquals(0, count($versions));
}

public function test_deleteUser()
{
global $conf, $auth;
$auth = new Mock_Auth_Plugin();
$conf['remote'] = 1;
$conf['remoteuser'] = 'testuser';
$_SERVER['REMOTE_USER'] = 'testuser';
$params = [
['testuser']
];
$actualCallResult = $this->remote->call('dokuwiki.deleteUsers', $params);
$this->assertTrue($actualCallResult);
}

public function test_aclCheck() {
$id = 'aclpage';

Expand Down
12 changes: 7 additions & 5 deletions inc/Action/Draftdel.php
Expand Up @@ -19,16 +19,18 @@ public function minimumPermission() {
}

/**
* Delete an existing draft if any
* Delete an existing draft for the current page and user if any
*
* Reads draft information from $INFO. Redirects to show, afterwards.
* Redirects to show, afterwards.
*
* @throws ActionAbort
*/
public function preProcess() {
global $INFO;
@unlink($INFO['draft']);
$INFO['draft'] = null;
global $INFO, $ID;
$draft = new \dokuwiki\Draft($ID, $INFO['client']);
if ($draft->isDraftAvailable()) {
$draft->deleteDraft();
}

throw new ActionAbort('redirect');
}
Expand Down
30 changes: 7 additions & 23 deletions inc/Action/Preview.php
Expand Up @@ -29,29 +29,13 @@ public function tplContent() {
* Saves a draft on preview
*/
protected function savedraft() {
global $INFO;
global $ID;
global $INPUT;
global $conf;

if(!$conf['usedraft']) return;
if(!$INPUT->post->has('wikitext')) return;

// ensure environment (safeguard when used via AJAX)
assert(isset($INFO['client']), 'INFO.client should have been set');
assert(isset($ID), 'ID should have been set');

$draft = array(
'id' => $ID,
'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
'text' => $INPUT->post->str('wikitext'),
'suffix' => $INPUT->post->str('suffix'),
'date' => $INPUT->post->int('date'),
'client' => $INFO['client'],
);
$cname = getCacheName($draft['client'] . $ID, '.draft');
if(io_saveFile($cname, serialize($draft))) {
$INFO['draft'] = $cname;
global $ID, $INFO;
$draft = new \dokuwiki\Draft($ID, $INFO['client']);
if (!$draft->saveDraft()) {
$errors = $draft->getErrors();
foreach ($errors as $error) {
msg(hsc($error), -1);
}
}
}

Expand Down
35 changes: 14 additions & 21 deletions inc/Ajax.php
Expand Up @@ -119,8 +119,6 @@ protected function call_suggestions() {
* Andreas Gohr <andi@splitbrain.org>
*/
protected function call_lock() {
global $conf;
global $lang;
global $ID;
global $INFO;
global $INPUT;
Expand All @@ -130,34 +128,29 @@ protected function call_lock() {

$INFO = pageinfo();

$response = [
'errors' => [],
'lock' => '0',
'draft' => '',
];
if(!$INFO['writable']) {
echo 'Permission denied';
$response['errors'][] = 'Permission to write this page has been denied.';
echo json_encode($response);
return;
}

if(!checklock($ID)) {
lock($ID);
echo 1;
$response['lock'] = '1';
}

if($conf['usedraft'] && $INPUT->post->str('wikitext')) {
$client = $_SERVER['REMOTE_USER'];
if(!$client) $client = clientIP(true);

$draft = array(
'id' => $ID,
'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
'text' => $INPUT->post->str('wikitext'),
'suffix' => $INPUT->post->str('suffix'),
'date' => $INPUT->post->int('date'),
'client' => $client,
);
$cname = getCacheName($draft['client'] . $ID, '.draft');
if(io_saveFile($cname, serialize($draft))) {
echo $lang['draftdate'] . ' ' . dformat();
}
$draft = new Draft($ID, $INFO['client']);
if ($draft->saveDraft()) {
$response['draft'] = $draft->getDraftMessage();
} else {
$response['errors'] = array_merge($response['errors'], $draft->getErrors());
}

echo json_encode($response);
}

/**
Expand Down
165 changes: 165 additions & 0 deletions inc/Draft.php
@@ -0,0 +1,165 @@
<?php

namespace dokuwiki;

/**
* Class Draft
*
* @package dokuwiki
*/
class Draft
{

protected $errors = [];
protected $cname;
protected $id;
protected $client;

/**
* Draft constructor.
*
* @param string $ID the page id for this draft
* @param string $client the client identification (username or ip or similar) for this draft
*/
public function __construct($ID, $client)
{
$this->id = $ID;
$this->client = $client;
$this->cname = getCacheName($client.$ID, '.draft');
if(file_exists($this->cname) && file_exists(wikiFN($ID))) {
if (filemtime($this->cname) < filemtime(wikiFN($ID))) {
// remove stale draft
$this->deleteDraft();
}
}
}

/**
* Get the filename for this draft (whether or not it exists)
*
* @return string
*/
public function getDraftFilename()
{
return $this->cname;
}

/**
* Checks if this draft exists on the filesystem
*
* @return bool
*/
public function isDraftAvailable()
{
return file_exists($this->cname);
}

/**
* Save a draft of a current edit session
*
* The draft will not be saved if
* - drafts are deactivated in the config
* - or the editarea is empty and there are no event handlers registered
* - or the event is prevented
*
* @triggers DRAFT_SAVE
*
* @return bool whether has the draft been saved
*/
public function saveDraft()
{
global $INPUT, $INFO, $EVENT_HANDLER, $conf;
if (!$conf['usedraft']) {
return false;
}
if (!$INPUT->post->has('wikitext') &&
!$EVENT_HANDLER->hasHandlerForEvent('DRAFT_SAVE')) {
return false;
}
$draft = [
'id' => $this->id,
'prefix' => substr($INPUT->post->str('prefix'), 0, -1),
'text' => $INPUT->post->str('wikitext'),
'suffix' => $INPUT->post->str('suffix'),
'date' => $INPUT->post->int('date'),
'client' => $this->client,
'cname' => $this->cname,
'errors' => [],
];
$event = new \Doku_Event('DRAFT_SAVE', $draft);
if ($event->advise_before()) {
$draft['hasBeenSaved'] = io_saveFile($draft['cname'], serialize($draft));
if ($draft['hasBeenSaved']) {
$INFO['draft'] = $draft['cname'];
}
} else {
$draft['hasBeenSaved'] = false;
}
$event->advise_after();

$this->errors = $draft['errors'];

return $draft['hasBeenSaved'];
}

/**
* Get the text from the draft file
*
* @throws \RuntimeException if the draft file doesn't exist
*
* @return string
*/
public function getDraftText()
{
if (!file_exists($this->cname)) {
throw new \RuntimeException(
"Draft for page $this->id and user $this->client doesn't exist at $this->cname."
);
}
$draft = unserialize(io_readFile($this->cname,false));
return cleanText(con($draft['prefix'],$draft['text'],$draft['suffix'],true));
}

/**
* Remove the draft from the filesystem
*
* Also sets $INFO['draft'] to null
*/
public function deleteDraft()
{
global $INFO;
@unlink($this->cname);
$INFO['draft'] = null;
}

/**
* Get a formatted message stating when the draft was saved
*
* @return string
*/
public function getDraftMessage()
{
global $lang;
return $lang['draftdate'] . ' ' . dformat(filemtime($this->cname));
}

/**
* Retrieve the errors that occured when saving the draft
*
* @return array
*/
public function getErrors()
{
return $this->errors;
}

/**
* Get the timestamp when this draft was saved
*
* @return int
*/
public function getDraftDate()
{
return filemtime($this->cname);
}
}
2 changes: 1 addition & 1 deletion inc/Remote/ApiCore.php
Expand Up @@ -596,7 +596,7 @@ public function deleteUsers($usernames)
}
/** @var DokuWiki_Auth_Plugin $auth */
global $auth;
return (bool)$auth->triggerUserMod('deleteUsers', $usernames);
return (bool)$auth->triggerUserMod('delete', array($usernames));
}

/**
Expand Down
11 changes: 3 additions & 8 deletions inc/common.php
Expand Up @@ -285,14 +285,9 @@ function pageinfo() {
}

// draft
$draft = getCacheName($info['client'].$ID, '.draft');
if(file_exists($draft)) {
if(@filemtime($draft) < @filemtime(wikiFN($ID))) {
// remove stale draft
@unlink($draft);
} else {
$info['draft'] = $draft;
}
$draft = new \dokuwiki\Draft($ID, $info['client']);
if ($draft->isDraftAvailable()) {
$info['draft'] = $draft->getDraftFilename();
}

return $info;
Expand Down
18 changes: 18 additions & 0 deletions inc/events.php
Expand Up @@ -236,6 +236,24 @@ public function process_event($event,$advise='') {
}
}
}

/**
* Check if an event has any registered handlers
*
* When $advise is empty, both BEFORE and AFTER events will be considered,
* otherwise only the given advisory is checked
*
* @param string $name Name of the event
* @param string $advise BEFORE, AFTER or empty
* @return bool
*/
public function hasHandlerForEvent($name, $advise = '') {
if($advise) {
return isset($this->_hooks[$name . '_' . $advise]);
} else {
return isset($this->_hooks[$name . '_BEFORE']) || isset($this->_hooks[$name . '_AFTER']);
}
}
}

/**
Expand Down

0 comments on commit 9ddafce

Please sign in to comment.