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