xref: /dokuwiki/_test/tests/Remote/ApiCoreTest.php (revision 535851891f27d4edf214975656242cb81be5b6ac)
1<?php
2
3namespace dokuwiki\test\Remote;
4
5use dokuwiki\Extension\Event;
6use dokuwiki\Remote\Api;
7use dokuwiki\Remote\ApiCore;
8use dokuwiki\test\mock\AuthDeletePlugin;
9use dokuwiki\test\mock\AuthPlugin;
10
11/**
12 * Class remoteapicore_test
13 */
14class ApiCoreTest extends \DokuWikiTest
15{
16
17    protected $userinfo;
18    protected $oldAuthAcl;
19    /** @var  Api */
20    protected $remote;
21
22    public function setUp(): void
23    {
24        // we need a clean setup before each single test:
25        \DokuWikiTest::setUpBeforeClass();
26
27        parent::setUp();
28        global $conf;
29        global $USERINFO;
30        global $AUTH_ACL;
31        global $auth;
32        $this->oldAuthAcl = $AUTH_ACL;
33        $this->userinfo = $USERINFO;
34        $auth = new AuthPlugin();
35
36        $conf['remote'] = 1;
37        $conf['remoteuser'] = '@user';
38        $conf['useacl'] = 0;
39
40        $this->remote = new Api();
41    }
42
43    public function tearDown(): void
44    {
45        parent::tearDown();
46
47        global $USERINFO;
48        global $AUTH_ACL;
49
50        $USERINFO = $this->userinfo;
51        $AUTH_ACL = $this->oldAuthAcl;
52    }
53
54    /** Delay writes of old revisions by a second. */
55    public function handle_write(Event $event, $param)
56    {
57        if ($event->data[3] !== false) {
58            $this->waitForTick();
59        }
60    }
61
62    public function testGetVersion()
63    {
64        $this->assertEquals(getVersion(), $this->remote->call('dokuwiki.getVersion'));
65    }
66
67    public function testGetPageList()
68    {
69        $file1 = wikiFN('wiki:dokuwiki');
70        $file2 = wikiFN('wiki:syntax');
71        $expected = [
72            [
73                'id' => 'wiki:dokuwiki',
74                'rev' => filemtime($file1),
75                'mtime' => filemtime($file1),
76                'size' => filesize($file1),
77                'hash' => md5(trim(rawWiki('wiki:dokuwiki')))
78            ],
79            [
80                'id' => 'wiki:syntax',
81                'rev' => filemtime($file2),
82                'mtime' => filemtime($file2),
83                'size' => filesize($file2),
84                'hash' => md5(trim(rawWiki('wiki:syntax')))
85            ]
86        ];
87        $params = [
88            'wiki:',
89            [
90                'depth' => 0, // 0 for all
91                'hash' => 1,
92                'skipacl' => 1 // is ignored
93            ]
94        ];
95        $this->assertEquals($expected, $this->remote->call('dokuwiki.getPagelist', $params));
96    }
97
98    public function testSearch()
99    {
100        $id = 'wiki:syntax';
101        $file = wikiFN($id);
102
103        idx_addPage($id); //full text search depends on index
104        $expected = [
105            [
106                'id' => $id,
107                'score' => 1,
108                'rev' => filemtime($file),
109                'mtime' => filemtime($file),
110                'size' => filesize($file),
111                'snippet' => ' a footnote)) by using double parentheses.
112
113===== <strong class="search_hit">Sectioning</strong> =====
114
115You can use up to five different levels of',
116                'title' => 'wiki:syntax'
117            ]
118        ];
119        $params = ['Sectioning'];
120        $this->assertEquals($expected, $this->remote->call('dokuwiki.search', $params));
121    }
122
123    public function testGetTime()
124    {
125        $timeexpect = time();
126        $timeactual = $this->remote->call('dokuwiki.getTime');
127        $this->assertTrue(($timeexpect <= $timeactual) && ($timeactual <= $timeexpect + 1));
128    }
129
130    public function testSetLocks()
131    {
132        $expected = [
133            'locked' => ['wiki:dokuwiki', 'wiki:syntax', 'nonexisting'],
134            'lockfail' => [],
135            'unlocked' => [],
136            'unlockfail' => [],
137        ];
138        $params = [
139            [
140                'lock' => ['wiki:dokuwiki', 'wiki:syntax', 'nonexisting'],
141                'unlock' => []
142            ]
143        ];
144        $this->assertEquals($expected, $this->remote->call('dokuwiki.setLocks', $params));
145
146        $expected = [
147            'locked' => [],
148            'lockfail' => [],
149            'unlocked' => ['wiki:dokuwiki', 'wiki:syntax', 'nonexisting'],
150            'unlockfail' => ['nonexisting2'],
151        ];
152        $params = [
153            [
154                'lock' => [],
155                'unlock' => ['wiki:dokuwiki', 'wiki:syntax', 'nonexisting', 'nonexisting2']
156            ]
157        ];
158        $this->assertEquals($expected, $this->remote->call('dokuwiki.setLocks', $params));
159    }
160
161    public function testGetTitle()
162    {
163        global $conf;
164        $this->assertEquals($conf['title'], $this->remote->call('dokuwiki.getTitle'));
165    }
166
167    public function testPutPage()
168    {
169        $id = 'putpage';
170
171        $content = "====Title====\nText";
172        $params = [
173            $id,
174            $content,
175            [
176                'minor' => false,
177                'sum' => 'Summary of nice text'
178            ]
179        ];
180        $this->assertTrue($this->remote->call('wiki.putPage', $params));
181        $this->assertEquals($content, rawWiki($id));
182
183        //remove page
184        $params = [
185            $id,
186            '',
187            [
188                'minor' => false,
189            ]
190        ];
191        $this->assertTrue($this->remote->call('wiki.putPage', $params));
192        $this->assertFileNotExists(wikiFN($id));
193    }
194
195    public function testGetPage()
196    {
197        $id = 'getpage';
198        $content = 'a test';
199        saveWikiText($id, $content, 'test for getpage');
200
201        $params = [$id];
202        $this->assertEquals($content, $this->remote->call('wiki.getPage', $params));
203    }
204
205    public function testAppendPage()
206    {
207        $id = 'appendpage';
208        $content = 'a test';
209        $morecontent = "\nOther text";
210        saveWikiText($id, $content, 'local');
211
212        $params = [
213            $id,
214            $morecontent,
215            []
216        ];
217        $this->assertEquals(true, $this->remote->call('dokuwiki.appendPage', $params));
218        $this->assertEquals($content . $morecontent, rawWiki($id));
219    }
220
221    public function testGetPageVersion()
222    {
223        $id = 'pageversion';
224        $file = wikiFN($id);
225
226        saveWikiText($id, 'first version', 'first');
227        $rev1 = filemtime($file);
228        clearstatcache(false, $file);
229        $this->waitForTick(true);
230        saveWikiText($id, 'second version', 'second');
231        $rev2 = filemtime($file);
232
233        $params = [$id, ''];
234        $this->assertEquals('second version', $this->remote->call('wiki.getPageVersion', $params), 'no revision given');
235
236        $params = [$id, $rev1];
237        $this->assertEquals('first version', $this->remote->call('wiki.getPageVersion', $params), '1st revision given');
238
239        $params = [$id, $rev2];
240        $this->assertEquals('second version', $this->remote->call('wiki.getPageVersion', $params), '2nd revision given');
241
242        $params = [$id, 1234];
243        $this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Non existing revision given');
244
245        $params = ['foobar', 1234];
246        $this->assertEquals('', $this->remote->call('wiki.getPageVersion', $params), 'Non existing page given');
247    }
248
249    public function testGetPageHTML()
250    {
251        $id = 'htmltest';
252        $content = "====Title====\nText";
253        $html = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n</p>\n\n</div>\n";
254
255        saveWikiText($id, $content, 'htmltest');
256
257        $params = [$id];
258        $this->assertEquals($html, $this->remote->call('wiki.getPageHTML', $params));
259    }
260
261    public function testGetPageHTMLVersion()
262    {
263        $id = 'htmltest';
264        $file = wikiFN($id);
265
266        $content1 = "====Title====\nText";
267        $html1 = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n</p>\n\n</div>\n";
268        $content2 = "====Foobar====\nText Bamm";
269        $html2 = "\n<h3 class=\"sectionedit1\" id=\"foobar\">Foobar</h3>\n<div class=\"level3\">\n\n<p>\nText Bamm\n</p>\n\n</div>\n";
270
271        saveWikiText($id, $content1, 'first');
272        $rev1 = filemtime($file);
273        clearstatcache(false, $file);
274        $this->waitForTick(true);
275        saveWikiText($id, $content2, 'second');
276        $rev2 = filemtime($file);
277
278        $params = [$id, ''];
279        $this->assertEquals($html2, $this->remote->call('wiki.getPageHTMLVersion', $params), 'no revision given');
280
281        $params = [$id, $rev1];
282        $this->assertEquals($html1, $this->remote->call('wiki.getPageHTMLVersion', $params), '1st revision given');
283
284        $params = [$id, $rev2];
285        $this->assertEquals($html2, $this->remote->call('wiki.getPageHTMLVersion', $params), '2nd revision given');
286
287        $params = [$id, 1234];
288        $this->assertEquals('', $this->remote->call('wiki.getPageHTMLVersion', $params), 'Non existing revision given');
289
290        $params = ['foobar', 1234];
291        $this->assertEquals('', $this->remote->call('wiki.getPageHTMLVersion', $params), 'Non existing page given');
292    }
293
294    public function testGetAllPages()
295    {
296        // all pages depends on index
297        idx_addPage('wiki:syntax');
298        idx_addPage('wiki:dokuwiki');
299
300        $file1 = wikiFN('wiki:syntax');
301        $file2 = wikiFN('wiki:dokuwiki');
302
303        $expected = [
304            [
305                'id' => 'wiki:syntax',
306                'perms' => 8,
307                'size' => filesize($file1),
308                'lastModified' => filemtime($file1)
309            ],
310            [
311                'id' => 'wiki:dokuwiki',
312                'perms' => 8,
313                'size' => filesize($file2),
314                'lastModified' => filemtime($file2)
315            ]
316        ];
317        $this->assertEquals($expected, $this->remote->call('wiki.getAllPages'));
318    }
319
320    public function testGetBacklinks()
321    {
322        saveWikiText('linky', '[[wiki:syntax]]', 'test');
323        // backlinks need index
324        idx_addPage('wiki:syntax');
325        idx_addPage('linky');
326
327        $params = ['wiki:syntax'];
328        $result = $this->remote->call('wiki.getBackLinks', $params);
329        $this->assertTrue(count($result) > 0);
330        $this->assertEquals(ft_backlinks('wiki:syntax'), $result);
331    }
332
333    public function testGetPageInfo()
334    {
335        $id = 'pageinfo';
336        $file = wikiFN($id);
337
338        saveWikiText($id, 'test', 'test');
339
340        $expected = [
341            'name' => $id,
342            'lastModified' => filemtime($file),
343            'author' => clientIP(),
344            'version' => filemtime($file)
345        ];
346        $params = [$id];
347        $this->assertEquals($expected, $this->remote->call('wiki.getPageInfo', $params));
348    }
349
350    public function testGetPageInfoVersion()
351    {
352        $id = 'pageinfo';
353        $file = wikiFN($id);
354
355        saveWikiText($id, 'first version', 'first');
356        $rev1 = filemtime($file);
357        clearstatcache(false, $file);
358        $this->waitForTick(true);
359        saveWikiText($id, 'second version', 'second');
360        $rev2 = filemtime($file);
361
362        $expected = [
363            'name' => $id,
364            'lastModified' => $rev2,
365            'author' => clientIP(),
366            'version' => $rev2
367        ];
368        $params = [$id, ''];
369        $this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params), 'no revision given');
370
371        $expected = [
372            'name' => $id,
373            'lastModified' => $rev1,
374            'author' => clientIP(),
375            'version' => $rev1
376        ];
377        $params = [$id, $rev1];
378        $this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params), '1st revision given');
379
380        $expected = [
381            'name' => $id,
382            'lastModified' => $rev2,
383            'author' => clientIP(),
384            'version' => $rev2
385        ];
386        $params = [$id, $rev2];
387        $this->assertEquals($expected, $this->remote->call('wiki.getPageInfoVersion', $params), '2nd revision given');
388    }
389
390    public function testGetRecentChanges()
391    {
392
393        saveWikiText('pageone', 'test', 'test');
394        $rev1 = filemtime(wikiFN('pageone'));
395        saveWikiText('pagetwo', 'test', 'test');
396        $rev2 = filemtime(wikiFN('pagetwo'));
397
398        $expected = [
399            [
400                'name' => 'pageone',
401                'lastModified' => $rev1,
402                'author' => '',
403                'version' => $rev1,
404                'perms' => 8,
405                'size' => 4
406            ],
407            [
408                'name' => 'pagetwo',
409                'lastModified' => $rev2,
410                'author' => '',
411                'version' => $rev2,
412                'perms' => 8,
413                'size' => 4
414            ]
415        ];
416        $params = [strtotime("-1 year")];
417        $this->assertEquals($expected, $this->remote->call('wiki.getRecentChanges', $params));
418    }
419
420    public function testGetPageVersions()
421    {
422        /** @var $EVENT_HANDLER \dokuwiki\Extension\EventHandler */
423        global $EVENT_HANDLER;
424        $EVENT_HANDLER->register_hook('IO_WIKIPAGE_WRITE', 'BEFORE', $this, 'handle_write');
425        global $conf;
426
427        $id = 'revpage';
428        $file = wikiFN($id);
429
430        $rev = [];
431        for ($i = 0; $i < 6; $i++) {
432            $this->waitForTick();
433            saveWikiText($id, "rev$i", "rev$i");
434            clearstatcache(false, $file);
435            $rev[$i] = filemtime($file);
436        }
437
438        $params = [$id, 0];
439        $versions = $this->remote->call('wiki.getPageVersions', $params);
440        $this->assertEquals(6, count($versions));
441        $this->assertEquals($rev[5], $versions[0]['version']);
442        $this->assertEquals($rev[4], $versions[1]['version']);
443        $this->assertEquals($rev[3], $versions[2]['version']);
444        $this->assertEquals($rev[2], $versions[3]['version']);
445        $this->assertEquals($rev[1], $versions[4]['version']);
446        $this->assertEquals($rev[0], $versions[5]['version']);
447
448        $params = [$id, 1]; // offset 1
449        $versions = $this->remote->call('wiki.getPageVersions', $params);
450        $this->assertEquals(5, count($versions));
451        $this->assertEquals($rev[4], $versions[0]['version']);
452        $this->assertEquals($rev[3], $versions[1]['version']);
453        $this->assertEquals($rev[2], $versions[2]['version']);
454        $this->assertEquals($rev[1], $versions[3]['version']);
455        $this->assertEquals($rev[0], $versions[4]['version']);
456
457        $conf['recent'] = 3; //set number of results per page
458
459        $params = [$id, 0]; // first page
460        $versions = $this->remote->call('wiki.getPageVersions', $params);
461        $this->assertEquals(3, count($versions));
462        $this->assertEquals($rev[5], $versions[0]['version']);
463        $this->assertEquals($rev[4], $versions[1]['version']);
464        $this->assertEquals($rev[3], $versions[2]['version']);
465
466        $params = [$id, $conf['recent']]; // second page
467        $versions = $this->remote->call('wiki.getPageVersions', $params);
468        $this->assertEquals(3, count($versions));
469        $this->assertEquals($rev[2], $versions[0]['version']);
470        $this->assertEquals($rev[1], $versions[1]['version']);
471        $this->assertEquals($rev[0], $versions[2]['version']);
472
473        $params = [$id, $conf['recent'] * 2]; // third page
474        $versions = $this->remote->call('wiki.getPageVersions', $params);
475        $this->assertEquals(0, count($versions));
476    }
477
478    public function testDeleteUser()
479    {
480        global $conf, $auth;
481        $auth = new AuthDeletePlugin();
482        $conf['remote'] = 1;
483        $conf['remoteuser'] = 'testuser';
484        $_SERVER['REMOTE_USER'] = 'testuser';
485        $params = [
486            ['testuser']
487        ];
488        $actualCallResult = $this->remote->call('dokuwiki.deleteUsers', $params);
489        $this->assertTrue($actualCallResult);
490    }
491
492    public function testAclCheck()
493    {
494        $id = 'aclpage';
495
496        $params = [$id];
497        $this->assertEquals(AUTH_UPLOAD, $this->remote->call('wiki.aclCheck', $params));
498
499        global $conf;
500        global $AUTH_ACL, $USERINFO;
501        $conf['useacl'] = 1;
502        $_SERVER['REMOTE_USER'] = 'john';
503        $USERINFO['grps'] = ['user'];
504        $AUTH_ACL = [
505            '*                  @ALL           0',
506            '*                  @user          2', //edit
507        ];
508
509        $params = [$id];
510        $this->assertEquals(AUTH_EDIT, $this->remote->call('wiki.aclCheck', $params));
511    }
512
513    public function testGetXMLRPCAPIVersion()
514    {
515        $this->assertEquals(ApiCore::API_VERSION, $this->remote->call('dokuwiki.getXMLRPCAPIVersion'));
516    }
517
518    public function testGetRPCVersionSupported()
519    {
520        $this->assertEquals(2, $this->remote->call('wiki.getRPCVersionSupported'));
521    }
522
523    public function testListLinks()
524    {
525        $localdoku = [
526            'type' => 'local',
527            'page' => 'DokuWiki',
528            'href' => DOKU_BASE . DOKU_SCRIPT . '?id=DokuWiki'
529        ];
530        $expected = [  //no local links
531            $localdoku,
532            [
533                'type' => 'extern',
534                'page' => 'http://www.freelists.org',
535                'href' => 'http://www.freelists.org'
536            ],
537            [
538                'type' => 'extern',
539                'page' => 'https://tools.ietf.org/html/rfc1855',
540                'href' => 'https://tools.ietf.org/html/rfc1855'
541            ],
542            [
543                'type' => 'extern',
544                'page' => 'http://www.catb.org/~esr/faqs/smart-questions.html',
545                'href' => 'http://www.catb.org/~esr/faqs/smart-questions.html'
546            ],
547            $localdoku,
548            $localdoku
549        ];
550        $params = ['mailinglist'];
551        $this->assertEquals($expected, $this->remote->call('wiki.listLinks', $params));
552    }
553
554    public function testCoreattachments()
555    {
556        global $conf;
557        global $AUTH_ACL, $USERINFO;
558
559        $filecontent = io_readFile(mediaFN('wiki:dokuwiki-128.png'), false);
560        $params = ['test:dokuwiki-128_2.png', $filecontent, ['ow' => false]];
561        $this->assertEquals('test:dokuwiki-128_2.png', $this->remote->call('wiki.putAttachment', $params)); //prints a success div
562
563        $params = ['test:dokuwiki-128_2.png'];
564        $this->assertEquals($filecontent, $this->remote->call('wiki.getAttachment', $params));
565        $rev = filemtime(mediaFN('test:dokuwiki-128_2.png'));
566
567        $expected = [
568            'lastModified' => $rev,
569            'size' => 27895,
570        ];
571        $params = ['test:dokuwiki-128_2.png'];
572        $this->assertEquals($expected, $this->remote->call('wiki.getAttachmentInfo', $params));
573
574        $params = [strtotime("-5 year")];
575        $expected = [
576            [
577                'name' => 'test:dokuwiki-128_2.png',
578                'lastModified' => $rev,
579                'author' => '',
580                'version' => $rev,
581                'perms' => 8,
582                'size' => 27895 //actual size, not size change
583            ]
584        ];
585        $this->assertEquals($expected, $this->remote->call('wiki.getRecentMediaChanges', $params));
586
587        $this->waitForTick(true);
588        $conf['useacl'] = 1;
589        $_SERVER['REMOTE_USER'] = 'john';
590        $USERINFO['grps'] = ['user'];
591        $AUTH_ACL = [
592            '*                  @ALL           0',
593            '*                  @user          16',
594        ];
595
596        $params = ['test:dokuwiki-128_2.png'];
597        $this->assertEquals(0, $this->remote->call('wiki.deleteAttachment', $params));
598
599        $rev2 = filemtime($conf['media_changelog']);
600        $expected = [
601            'lastModified' => $rev2,
602            'size' => 0,
603        ];
604        $params = ['test:dokuwiki-128_2.png'];
605        $this->assertEquals($expected, $this->remote->call('wiki.getAttachmentInfo', $params));
606
607        $expected = [
608            'lastModified' => 0,
609            'size' => 0,
610        ];
611        $params = ['test:nonexisting.png'];
612        $this->assertEquals($expected, $this->remote->call('wiki.getAttachmentInfo', $params));
613
614        $media1 = mediaFN('wiki:dokuwiki-128.png');
615        $expected = [
616            [
617                'id' => 'wiki:dokuwiki-128.png',
618                'file' => 'dokuwiki-128.png',
619                'size' => filesize($media1),
620                'mtime' => filemtime($media1),
621                'writable' => 1,
622                'isimg' => 1,
623                'hash' => md5(io_readFile($media1, false)),
624                'perms' => 16,
625                'lastModified' => filemtime($media1)
626            ]
627        ];
628        $params = [
629            'wiki:',
630            [
631                'depth' => 0, // 0 for all
632                'hash' => 1,
633                'skipacl' => 1, // is ignored
634                'showmsg' => true, //useless??
635                'pattern' => '/128/' //filter
636            ]
637        ];
638        $this->assertEquals($expected, $this->remote->call('wiki.getAttachments', $params));
639    }
640
641}
642