1<?php
2
3namespace dokuwiki\test\Remote;
4
5use dokuwiki\Remote\AccessDeniedException;
6use dokuwiki\Remote\Api;
7use dokuwiki\Remote\ApiCore;
8use dokuwiki\Remote\RemoteException;
9use dokuwiki\test\mock\AuthPlugin;
10
11
12/**
13 * Class remoteapicore_test
14 */
15class ApiCoreTest extends \DokuWikiTest
16{
17
18    protected $userinfo;
19    protected $oldAuthAcl;
20    /** @var  Api */
21    protected $remote;
22
23    public function setUp(): void
24    {
25        // we need a clean setup before each single test:
26        \DokuWikiTest::setUpBeforeClass();
27
28        parent::setUp();
29        global $conf;
30        global $USERINFO;
31        global $AUTH_ACL;
32        global $auth;
33        $this->oldAuthAcl = $AUTH_ACL;
34        $this->userinfo = $USERINFO;
35        $auth = new AuthPlugin();
36
37        $conf['remote'] = 1;
38        $conf['remoteuser'] = '@user';
39        $conf['useacl'] = 0;
40
41        $this->remote = new Api();
42    }
43
44    public function tearDown(): void
45    {
46        parent::tearDown();
47
48        global $USERINFO;
49        global $AUTH_ACL;
50
51        $USERINFO = $this->userinfo;
52        $AUTH_ACL = $this->oldAuthAcl;
53    }
54
55    /**
56     * Do an assertion that converts to JSON inbetween
57     *
58     * This lets us compare result objects with arrays
59     */
60    protected function assertEqualResult($expected, $actual, $msg = '')
61    {
62        // sort object arrays
63        if (is_array($actual) && array_key_exists(0, $actual) && is_object($actual[0])) {
64            sort($actual);
65            sort($expected);
66        }
67
68        $expected = json_decode(json_encode($expected), true);
69        $actual = json_decode(json_encode($actual), true);
70        $this->assertEquals($expected, $actual, $msg);
71    }
72
73    // region info
74
75    // core.getAPIVersion
76    public function testGetAPIVersion()
77    {
78        $this->assertEqualResult(
79            ApiCore::API_VERSION,
80            $this->remote->call('core.getAPIVersion')
81        );
82    }
83
84    // core.getWikiVersion
85    public function testGetWikiVersion()
86    {
87        $this->assertEqualResult(
88            getVersion(),
89            $this->remote->call('core.getWikiVersion')
90        );
91    }
92
93    // core.getWikiTitle
94    public function testGetWikiTitle()
95    {
96        global $conf;
97        $this->assertEqualResult(
98            $conf['title'],
99            $this->remote->call('core.getWikiTitle')
100        );
101    }
102
103    // core.getWikiTime
104    public function testGetWikiTime()
105    {
106        $this->assertEqualsWithDelta(
107            time(),
108            $this->remote->call('core.getWikiTime'),
109            1 // allow 1 second difference
110        );
111    }
112
113    // endregion
114
115    // region user
116
117    // core.login
118    public function testLogin()
119    {
120        $this->markTestIncomplete('Missing test for core.login API Call');
121    }
122
123    // core.logoff
124    public function testLogoff()
125    {
126        $this->markTestIncomplete('Missing test for core.logoff API Call');
127    }
128
129    // core.whoAmI
130    public function testWhoAmI()
131    {
132        $this->markTestIncomplete('Missing test for core.whoAmI API Call');
133    }
134
135    // core.aclCheck -> See also ApiCoreAclCheckTest.php
136    public function testAclCheck()
137    {
138        $id = 'aclpage';
139
140        $this->assertEquals(AUTH_UPLOAD, $this->remote->call('core.aclCheck', ['page' => $id]));
141
142        global $conf;
143        global $AUTH_ACL;
144        global $USERINFO;
145        $conf['useacl'] = 1;
146        $_SERVER['REMOTE_USER'] = 'john';
147        $USERINFO['grps'] = ['user'];
148        $AUTH_ACL = [
149            '*                  @ALL           0',
150            '*                  @user          2', //edit
151        ];
152
153        $this->assertEquals(AUTH_EDIT, $this->remote->call('core.aclCheck', ['page' => $id]));
154    }
155
156
157    // endregion
158
159    // region pages
160
161    // core.listPages
162    public function testlistPagesAll()
163    {
164        // all pages depends on index
165        idx_addPage('wiki:syntax');
166        idx_addPage('wiki:dokuwiki');
167
168        $file1 = wikiFN('wiki:syntax');
169        $file2 = wikiFN('wiki:dokuwiki');
170
171        $expected = [
172            [
173                'id' => 'wiki:syntax',
174                'title' => 'wiki:syntax',
175                'permission' => 8,
176                'size' => filesize($file1),
177                'revision' => filemtime($file1),
178                'hash' => md5(trim(io_readFile($file1))),
179                'author' => '',
180            ],
181            [
182                'id' => 'wiki:dokuwiki',
183                'title' => 'wiki:dokuwiki',
184                'permission' => 8,
185                'size' => filesize($file2),
186                'revision' => filemtime($file2),
187                'hash' => md5(trim(io_readFile($file2))),
188                'author' => '',
189            ]
190        ];
191        $this->assertEqualResult(
192            $expected,
193            $this->remote->call(
194                'core.listPages',
195                [
196                    'namespace' => '',
197                    'depth' => 0, // 0 for all
198                    'hash' => true
199                ]
200            )
201        );
202    }
203
204    // core.listPages
205    public function testListPagesNamespace()
206    {
207        $file1 = wikiFN('wiki:syntax');
208        $file2 = wikiFN('wiki:dokuwiki');
209        // no indexing needed here
210
211        global $conf;
212        $conf['useheading'] = 1;
213
214        $expected = [
215            [
216                'id' => 'wiki:syntax',
217                'title' => 'Formatting Syntax',
218                'permission' => 8,
219                'size' => filesize($file1),
220                'revision' => filemtime($file1),
221                'hash' => '',
222                'author' => '',
223            ],
224            [
225                'id' => 'wiki:dokuwiki',
226                'title' => 'DokuWiki',
227                'permission' => 8,
228                'size' => filesize($file2),
229                'revision' => filemtime($file2),
230                'hash' => '',
231                'author' => '',
232            ],
233        ];
234
235        $this->assertEqualResult(
236            $expected,
237            $this->remote->call(
238                'core.listPages',
239                [
240                    'namespace' => 'wiki:',
241                    'depth' => 1,
242                ]
243            )
244        );
245    }
246
247    // core.searchPages
248    public function testSearchPages()
249    {
250        $id = 'wiki:syntax';
251        $file = wikiFN($id);
252
253        idx_addPage($id); //full text search depends on index
254        $expected = [
255            [
256                'id' => $id,
257                'score' => 1,
258                'revision' => filemtime($file),
259                'permission' => 8,
260                'size' => filesize($file),
261                'snippet' => ' a footnote)) by using double parentheses.
262
263===== <strong class="search_hit">Sectioning</strong> =====
264
265You can use up to five different levels of',
266                'title' => 'wiki:syntax',
267                'author' => '',
268                'hash' => '',
269            ]
270        ];
271
272        $this->assertEqualResult(
273            $expected,
274            $this->remote->call(
275                'core.searchPages',
276                [
277                    'query' => 'Sectioning'
278                ]
279            )
280        );
281    }
282
283    //core.getRecentPageChanges
284    public function testGetRecentPageChanges()
285    {
286        $_SERVER['REMOTE_USER'] = 'testuser';
287
288        saveWikiText('pageone', 'test', 'test one');
289        $rev1 = filemtime(wikiFN('pageone'));
290        saveWikiText('pagetwo', 'test', 'test two');
291        $rev2 = filemtime(wikiFN('pagetwo'));
292
293        $expected = [
294            [
295                'id' => 'pageone',
296                'revision' => $rev1,
297                'author' => 'testuser',
298                'sizechange' => 4,
299                'summary' => 'test one',
300                'type' => 'C',
301                'ip' => clientIP(),
302            ],
303            [
304                'id' => 'pagetwo',
305                'revision' => $rev2,
306                'author' => 'testuser',
307                'sizechange' => 4,
308                'summary' => 'test two',
309                'type' => 'C',
310                'ip' => clientIP(),
311            ]
312        ];
313
314        $this->assertEqualResult(
315            $expected,
316            $this->remote->call(
317                'core.getRecentPageChanges',
318                [
319                    'timestamp' => 0 // all recent changes
320                ]
321            )
322        );
323    }
324
325    // core.getPage
326    public function testGetPage()
327    {
328        $id = 'pageversion';
329        $file = wikiFN($id);
330
331        saveWikiText($id, 'first version', 'first');
332        $rev1 = filemtime($file);
333        clearstatcache(false, $file);
334        $this->waitForTick(true);
335        saveWikiText($id, 'second version', 'second');
336        $rev2 = filemtime($file);
337
338        $this->assertEqualResult(
339            'second version',
340            $this->remote->call('core.getPage', ['page' => $id, 'rev' => 0]),
341            'no revision given -> current'
342        );
343
344        $this->assertEqualResult(
345            'first version',
346            $this->remote->call('core.getPage', ['page' => $id, 'rev' => $rev1]),
347            '1st revision given'
348        );
349
350        $this->assertEqualResult(
351            'second version',
352            $this->remote->call('core.getPage', ['page' => $id, 'rev' => $rev2]),
353            '2nd revision given'
354        );
355
356        $this->assertEqualResult(
357            '',
358            $this->remote->call('core.getPage', ['page' => $id, 'rev' => 1234]),
359            'Non existing revision given'
360        );
361
362        $this->assertEqualResult(
363            '',
364            $this->remote->call('core.getPage', ['page' => 'foobar', 'rev' => 1234]),
365            'Non existing page given'
366        );
367    }
368
369    //core.getPageHTML
370    public function testGetPageHTMLVersion()
371    {
372        $id = 'htmltest';
373        $file = wikiFN($id);
374
375        $content1 = "====Title====\nText";
376        $html1 = "\n<h3 class=\"sectionedit1\" id=\"title\">Title</h3>\n<div class=\"level3\">\n\n<p>\nText\n</p>\n\n</div>\n";
377        $content2 = "====Foobar====\nText Bamm";
378        $html2 = "\n<h3 class=\"sectionedit1\" id=\"foobar\">Foobar</h3>\n<div class=\"level3\">\n\n<p>\nText Bamm\n</p>\n\n</div>\n";
379
380        saveWikiText($id, $content1, 'first');
381        $rev1 = filemtime($file);
382        clearstatcache(false, $file);
383        $this->waitForTick(true);
384        saveWikiText($id, $content2, 'second');
385        $rev2 = filemtime($file);
386
387        $this->assertEqualResult(
388            $html2,
389            $this->remote->call('core.getPageHTML', ['page' => $id, 'rev' => 0]),
390            'no revision given -> current'
391        );
392
393        $this->assertEqualResult(
394            $html1,
395            $this->remote->call('core.getPageHTML', ['page' => $id, 'rev' => $rev1]),
396            '1st revision given'
397        );
398
399        $this->assertEqualResult(
400            $html2,
401            $this->remote->call('core.getPageHTML', ['page' => $id, 'rev' => $rev2]),
402            '2nd revision given'
403        );
404
405        $e = null;
406        try {
407            $this->remote->call('core.getPageHTML', ['page' => $id, 'rev' => 1234]);
408        } catch (RemoteException $e) {
409        }
410        $this->assertInstanceOf(RemoteException::class, $e);
411        $this->assertEquals(121, $e->getCode(), 'Non existing revision given');
412
413        $e = null;
414        try {
415            $this->remote->call('core.getPageHTML', ['page' => 'foobar', 'rev' => 1234]);
416        } catch (RemoteException $e) {
417        }
418        $this->assertInstanceOf(RemoteException::class, $e);
419        $this->assertEquals(121, $e->getCode(), 'Non existing page given');
420    }
421
422    //core.getPageInfo
423    public function testGetPageInfo()
424    {
425        $id = 'pageinfo';
426        $file = wikiFN($id);
427
428        $_SERVER['REMOTE_USER'] = 'testuser';
429
430        saveWikiText($id, 'first version', 'first');
431        $rev1 = filemtime($file);
432        clearstatcache(false, $file);
433        $this->waitForTick(true);
434        saveWikiText($id, 'second version', 'second');
435        $rev2 = filemtime($file);
436
437        $expected = [
438            'id' => $id,
439            'revision' => $rev2,
440            'author' => 'testuser',
441            'hash' => md5(trim(io_readFile($file))),
442            'title' => $id,
443            'size' => filesize($file),
444            'permission' => 8,
445        ];
446        $this->assertEqualResult(
447            $expected,
448            $this->remote->call('core.getPageInfo', ['page' => $id, 'rev' => 0, 'hash' => true, 'author' => true]),
449            'no revision given -> current'
450        );
451
452        $expected = [
453            'id' => $id,
454            'revision' => $rev1,
455            'author' => '',
456            'hash' => '',
457            'title' => $id,
458            'size' => filesize(wikiFN($id, $rev1)),
459            'permission' => 8,
460        ];
461        $this->assertEqualResult(
462            $expected,
463            $this->remote->call('core.getPageInfo', ['page' => $id, 'rev' => $rev1]),
464            '1st revision given'
465        );
466
467        $expected = [
468            'id' => $id,
469            'revision' => $rev2,
470            'author' => '',
471            'hash' => '',
472            'title' => $id,
473            'size' => filesize(wikiFN($id, $rev2)),
474            'permission' => 8,
475        ];
476        $this->assertEqualResult(
477            $expected,
478            $this->remote->call('core.getPageInfo', ['page' => $id, 'rev' => $rev2]),
479            '2nd revision given'
480        );
481
482        $e = null;
483        try {
484            $this->remote->call('core.getPageInfo', ['page' => $id, 'rev' => 1234]);
485        } catch (RemoteException $e) {
486        }
487        $this->assertInstanceOf(RemoteException::class, $e);
488        $this->assertEquals(121, $e->getCode(), 'Non existing revision given');
489
490        $e = null;
491        try {
492            $this->remote->call('core.getPageInfo', ['page' => 'foobar', 'rev' => 1234]);
493        } catch (RemoteException $e) {
494        }
495        $this->assertInstanceOf(RemoteException::class, $e);
496        $this->assertEquals(121, $e->getCode(), 'Non existing page given');
497    }
498
499    //core.getPageHistory
500    public function testGetPageHistory()
501    {
502        global $conf;
503
504        $id = 'revpage';
505        $file = wikiFN($id);
506
507        $rev = [];
508        for ($i = 0; $i < 6; $i++) {
509            $this->waitForTick();
510            saveWikiText($id, "rev$i", "rev$i");
511            clearstatcache(false, $file);
512            $rev[$i] = filemtime($file);
513        }
514
515        $params = ['page' => $id, 'first' => 0];
516        $versions = $this->remote->call('core.getPageHistory', $params);
517        $versions = json_decode(json_encode($versions), true);
518        $this->assertEquals(6, count($versions));
519        $this->assertEquals($rev[5], $versions[0]['revision']);
520        $this->assertEquals($rev[4], $versions[1]['revision']);
521        $this->assertEquals($rev[3], $versions[2]['revision']);
522        $this->assertEquals($rev[2], $versions[3]['revision']);
523        $this->assertEquals($rev[1], $versions[4]['revision']);
524        $this->assertEquals($rev[0], $versions[5]['revision']);
525
526        $params = ['page' => $id, 'first' => 1]; // offset 1
527        $versions = $this->remote->call('core.getPageHistory', $params);
528        $versions = json_decode(json_encode($versions), true);
529        $this->assertEquals(5, count($versions));
530        $this->assertEquals($rev[4], $versions[0]['revision']);
531        $this->assertEquals($rev[3], $versions[1]['revision']);
532        $this->assertEquals($rev[2], $versions[2]['revision']);
533        $this->assertEquals($rev[1], $versions[3]['revision']);
534        $this->assertEquals($rev[0], $versions[4]['revision']);
535
536        $conf['recent'] = 3; //set number of results per page
537
538        $params = ['page' => $id, 'first' => 0]; // first page
539        $versions = $this->remote->call('core.getPageHistory', $params);
540        $versions = json_decode(json_encode($versions), true);
541        $this->assertEquals(3, count($versions));
542        $this->assertEquals($rev[5], $versions[0]['revision']);
543        $this->assertEquals($rev[4], $versions[1]['revision']);
544        $this->assertEquals($rev[3], $versions[2]['revision']);
545
546        $params = ['page' => $id, 'first' => $conf['recent']]; // second page
547        $versions = $this->remote->call('core.getPageHistory', $params);
548        $versions = json_decode(json_encode($versions), true);
549        $this->assertEquals(3, count($versions));
550        $this->assertEquals($rev[2], $versions[0]['revision']);
551        $this->assertEquals($rev[1], $versions[1]['revision']);
552        $this->assertEquals($rev[0], $versions[2]['revision']);
553
554        $params = ['page' => $id, 'first' => $conf['recent'] * 2]; // third page
555        $versions = $this->remote->call('core.getPageHistory', $params);
556        $versions = json_decode(json_encode($versions), true);
557        $this->assertEquals(0, count($versions));
558    }
559
560    //core.getPageLinks
561    public function testGetPageLinks()
562    {
563        $localdoku = [
564            'type' => 'local',
565            'page' => 'DokuWiki',
566            'href' => DOKU_BASE . DOKU_SCRIPT . '?id=DokuWiki'
567        ];
568        $expected = [
569            $localdoku,
570            [
571                'type' => 'extern',
572                'page' => 'http://www.freelists.org',
573                'href' => 'http://www.freelists.org'
574            ],
575            [
576                'type' => 'interwiki',
577                'page' => 'rfc>1855',
578                'href' => 'https://tools.ietf.org/html/rfc1855'
579            ],
580            [
581                'type' => 'extern',
582                'page' => 'http://www.catb.org/~esr/faqs/smart-questions.html',
583                'href' => 'http://www.catb.org/~esr/faqs/smart-questions.html'
584            ],
585            $localdoku,
586            $localdoku
587        ];
588
589        $this->assertEqualResult(
590            $expected,
591            $this->remote->call('core.getPageLinks', ['page' => 'mailinglist'])
592        );
593
594        $this->expectExceptionCode(121);
595        $this->remote->call('core.getPageLinks', ['page' => 'foobar']);
596    }
597
598    //core.getPageBackLinks
599    public function testGetPageBackLinks()
600    {
601        saveWikiText('linky', '[[wiki:syntax]]', 'test');
602        // backlinks need index
603        idx_addPage('wiki:syntax');
604        idx_addPage('linky');
605
606        $result = $this->remote->call('core.getPageBackLinks', ['page' => 'wiki:syntax']);
607        $this->assertTrue(count($result) > 0);
608        $this->assertEqualResult(ft_backlinks('wiki:syntax'), $result);
609
610        $this->assertEquals([], $this->remote->call('core.getPageBackLinks', ['page' => 'foobar']));
611    }
612
613    //core.lockPages
614    public function testLockPages()
615    {
616        // lock a first set of pages
617        $_SERVER['REMOTE_USER'] = 'testuser1';
618        $tolock = ['wiki:dokuwiki', 'nonexisting'];
619        $this->assertEquals(
620            $tolock,
621            $this->remote->call('core.lockPages', ['pages' => $tolock]),
622            'all pages should lock'
623        );
624
625        // now we're someone else
626        $_SERVER['REMOTE_USER'] = 'testuser2';
627        $tolock = ['wiki:dokuwiki', 'nonexisting', 'wiki:syntax', 'another'];
628        $expected = ['wiki:syntax', 'another'];
629        $this->assertEquals(
630            $expected,
631            $this->remote->call('core.lockPages', ['pages' => $tolock]),
632            'only half the pages should lock'
633        );
634    }
635
636    // core.unlockPages
637    public function testUnlockPages()
638    {
639        $_SERVER['REMOTE_USER'] = 'testuser1';
640        lock('wiki:dokuwiki');
641        lock('nonexisting');
642
643        $_SERVER['REMOTE_USER'] = 'testuser2';
644        lock('wiki:syntax');
645        lock('another');
646
647        $tounlock = ['wiki:dokuwiki', 'nonexisting', 'wiki:syntax', 'another', 'notlocked'];
648        $expected = ['wiki:syntax', 'another'];
649
650        $this->assertEquals(
651            $expected,
652            $this->remote->call('core.unlockPages', ['pages' => $tounlock])
653        );
654    }
655
656    //core.savePage
657    public function testSavePage()
658    {
659        $id = 'putpage';
660
661        $content = "====Title====\nText";
662        $params = [
663            'page' => $id,
664            'text' => $content,
665            'isminor' => false,
666            'summary' => 'Summary of nice text'
667        ];
668        $this->assertTrue($this->remote->call('core.savePage', $params));
669        $this->assertEquals($content, rawWiki($id));
670
671        // remove page
672        $params = [
673            'page' => $id,
674            'text' => '',
675        ];
676        $this->assertTrue($this->remote->call('core.savePage', $params));
677        $this->assertFileDoesNotExist(wikiFN($id));
678
679        // remove non existing page (reusing above params)
680        $e = null;
681        try {
682            $this->remote->call('core.savePage', $params);
683        } catch (RemoteException $e) {
684        }
685        $this->assertInstanceOf(RemoteException::class, $e);
686        $this->assertEquals(132, $e->getCode());
687    }
688
689    //core.appendPage
690    public function testAppendPage()
691    {
692        $id = 'appendpage';
693        $content = 'a test';
694        $morecontent = "\nOther text";
695        saveWikiText($id, $content, 'local');
696
697        $params = [
698            'page' => $id,
699            'text' => $morecontent,
700        ];
701        $this->assertEquals(true, $this->remote->call('core.appendPage', $params));
702        $this->assertEquals($content . $morecontent, rawWiki($id));
703    }
704
705    // endregion
706
707    // region media
708
709    // core.listMedia
710    public function testListMedia()
711    {
712        $id = 'wiki:dokuwiki-128.png';
713        $file = mediaFN($id);
714        $content = file_get_contents($file);
715
716        $expected = [
717            [
718                'id' => $id,
719                'size' => filesize($file),
720                'revision' => filemtime($file),
721                'isimage' => true,
722                'hash' => md5($content),
723                'permission' => 8,
724                'author' => '',
725            ]
726        ];
727        $this->assertEqualResult(
728            $expected,
729            $this->remote->call(
730                'core.listMedia',
731                [
732                    'namespace' => 'wiki',
733                    'pattern' => '/128/',
734                    'hash' => true,
735                ]
736            )
737        );
738    }
739
740    //core.getRecentMediaChanges
741    public function testGetRecentMediaChanges()
742    {
743        global $conf;
744
745        $_SERVER['REMOTE_USER'] = 'testuser';
746
747        $orig = mediaFN('wiki:dokuwiki-128.png');
748        $tmp = $conf['tmpdir'] . 'test.png';
749
750        $target1 = 'test:image1.png';
751        $file1 = mediaFN($target1);
752        copy($orig, $tmp);
753        media_save(['name' => $tmp], $target1, true, AUTH_UPLOAD, 'rename');
754
755        $target2 = 'test:image2.png';
756        $file2 = mediaFN($target2);
757        copy($orig, $tmp);
758        media_save(['name' => $tmp], $target2, true, AUTH_UPLOAD, 'rename');
759
760        $expected = [
761            [
762                'id' => $target1,
763                'revision' => filemtime($file1),
764                'author' => 'testuser',
765                'ip' => clientIP(),
766                'sizechange' => filesize($file1),
767                'summary' => 'created',
768                'type' => 'C',
769            ],
770            [
771                'id' => $target2,
772                'revision' => filemtime($file2),
773                'author' => 'testuser',
774                'ip' => clientIP(),
775                'sizechange' => filesize($file2),
776                'summary' => 'created',
777                'type' => 'C',
778            ]
779        ];
780
781        $this->assertEqualResult(
782            $expected,
783            $this->remote->call(
784                'core.getRecentMediaChanges',
785                [
786                    'timestamp' => 0 // all recent changes
787                ]
788            )
789        );
790    }
791
792    //core.getMedia
793    public function testGetMedia()
794    {
795        $id = 'wiki:dokuwiki-128.png';
796        $file = mediaFN($id);
797        $base64 = base64_encode(file_get_contents($file));
798
799        $this->assertEquals(
800            $base64,
801            $this->remote->call('core.getMedia', ['media' => $id])
802        );
803
804        $e = null;
805        try {
806            $this->remote->call('core.getMedia', ['media' => $id, 'rev' => 1234]);
807        } catch (RemoteException $e) {
808        }
809        $this->assertInstanceOf(RemoteException::class, $e);
810        $this->assertEquals(221, $e->getCode(), 'Non existing revision given');
811
812        $e = null;
813        try {
814            $this->remote->call('core.getMedia', ['media' => 'foobar.png']);
815        } catch (RemoteException $e) {
816        }
817        $this->assertInstanceOf(RemoteException::class, $e);
818        $this->assertEquals(221, $e->getCode(), 'Non existing media id given');
819    }
820
821
822    //core.getMediaInfo
823    public function testGetMediaInfo()
824    {
825        $id = 'wiki:dokuwiki-128.png';
826        $file = mediaFN($id);
827
828        $expected = [
829            'id' => $id,
830            'revision' => filemtime($file),
831            'author' => '',
832            'hash' => md5(file_get_contents($file)),
833            'size' => filesize($file),
834            'permission' => 8,
835            'isimage' => true,
836        ];
837        $this->assertEqualResult(
838            $expected,
839            $this->remote->call('core.getMediaInfo', ['media' => $id, 'hash' => true, 'author' => false])
840        );
841
842        $e = null;
843        try {
844            $this->remote->call('core.getMediaInfo', ['media' => $id, 'rev' => 1234]);
845        } catch (RemoteException $e) {
846        }
847        $this->assertInstanceOf(RemoteException::class, $e);
848        $this->assertEquals(221, $e->getCode(), 'Non existing revision given');
849
850        $e = null;
851        try {
852            $this->remote->call('core.getMediaInfo', ['media' => 'foobar.png']);
853        } catch (RemoteException $e) {
854        }
855        $this->assertInstanceOf(RemoteException::class, $e);
856        $this->assertEquals(221, $e->getCode(), 'Non existing media id given');
857    }
858
859    //core.getMediaHistory
860    public function testGetMediaHistory()
861    {
862        global $conf;
863
864        $_SERVER['REMOTE_USER'] = 'testuser';
865
866        //image to be uploaded
867        $orig = mediaFN('wiki:dokuwiki-128.png');
868        $tmp = $conf['tmpdir'] . 'test.png';
869
870        //create image to be revised
871        $id = 'test:image3.png';
872        $media = mediaFN($id);
873
874        $rev = [];
875        for ($i = 0; $i < 2; $i++) {
876            $this->waitForTick();
877            copy($orig, $tmp);
878            media_save(['name' => $tmp], $id, true, AUTH_UPLOAD, 'rename');
879            $rev[$i] = filemtime($media);
880        }
881
882        $params = ['media' => $id, 'first' => 0]; // offset 0
883        $versions = $this->remote->call('core.getMediaHistory', $params);
884        $versions = json_decode(json_encode($versions), true);
885        $this->assertEquals(2, count($versions));
886        $this->assertEquals($rev[1], $versions[0]['revision']);
887        $this->assertEquals($rev[0], $versions[1]['revision']);
888
889        $params = ['media' => $id, 'first' => 1]; // offset 1
890        $versions = $this->remote->call('core.getMediaHistory', $params);
891        $versions = json_decode(json_encode($versions), true);
892        $this->assertEquals(1, count($versions));
893        $this->assertEquals($rev[0], $versions[0]['revision']);
894
895        $params = ['media' => $id, 'first' => 2]; // offset 2
896        $versions = $this->remote->call('core.getMediaHistory', $params);
897        $versions = json_decode(json_encode($versions), true);
898        $this->assertEquals(0, count($versions));
899
900        $params = ['media' => $id, 'first' => 2]; // offset 3
901        $versions = $this->remote->call('core.getMediaHistory', $params);
902        $versions = json_decode(json_encode($versions), true);
903        $this->assertEquals(0, count($versions));
904    }
905
906    //core.saveMedia
907    public function testSaveMedia()
908    {
909        $orig = mediaFN('wiki:dokuwiki-128.png');
910        $base64 = base64_encode(file_get_contents($orig));
911
912        $target = 'test:putimage.png';
913        $targetfile = mediaFN($target);
914
915        $this->assertTrue($this->remote->call('core.saveMedia', ['media' => $target, 'base64' => $base64]));
916        $this->assertFileExists($targetfile);
917        $this->assertFileEquals($orig, $targetfile);
918    }
919
920    //core.deleteMedia
921    public function testDeleteMedia()
922    {
923        global $conf;
924        global $AUTH_ACL;
925        global $USERINFO;
926
927        $id = 'wiki:dokuwiki-128.png';
928        $file = mediaFN($id);
929
930        // deletion should fail, we only have AUTH_UPLOAD
931        $e = null;
932        try {
933            $this->remote->call('core.deleteMedia', ['media' => $id]);
934        } catch (AccessDeniedException $e) {
935        }
936        $this->assertInstanceOf(AccessDeniedException::class, $e);
937        $this->assertEquals(212, $e->getCode(), 'No permission to delete');
938        $this->assertFileExists($file);
939
940        // setup new ACLs
941        $conf['useacl'] = 1;
942        $_SERVER['REMOTE_USER'] = 'john';
943        $USERINFO['grps'] = array('user');
944        $AUTH_ACL = array(
945            '*                  @ALL           0',
946            '*                  @user          16',
947        );
948
949        // deletion should work now
950        $this->assertTrue($this->remote->call('core.deleteMedia', ['media' => $id]));
951        $this->assertFileDoesNotExist($file);
952
953        clearstatcache(false, $file);
954
955        // deleting the file again should not work
956        $e = null;
957        try {
958            $this->remote->call('core.deleteMedia', ['media' => $id]);
959        } catch (RemoteException $e) {
960        }
961        $this->assertInstanceOf(RemoteException::class, $e);
962        $this->assertEquals(221, $e->getCode(), 'Non existing media id given');
963    }
964    // endregion
965}
966