From d912b2a083155dc22df17c690e4876e94e44253d Mon Sep 17 00:00:00 2001 From: Andrew Gosali Date: Fri, 13 Dec 2024 17:23:14 +0700 Subject: [PATCH] MDL-75745 mod_book: import chapters to parse anchor links --- mod/book/tool/importhtml/locallib.php | 12 ++- .../tests/fixtures/chapters_links.zip | Bin 0 -> 3345 bytes .../tool/importhtml/tests/locallib_test.php | 70 ++++++++++++++---- 3 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 mod/book/tool/importhtml/tests/fixtures/chapters_links.zip diff --git a/mod/book/tool/importhtml/locallib.php b/mod/book/tool/importhtml/locallib.php index 3f6714258f7..41da0870731 100644 --- a/mod/book/tool/importhtml/locallib.php +++ b/mod/book/tool/importhtml/locallib.php @@ -134,12 +134,18 @@ function toolbook_importhtml_import_chapters($package, $type, $book, $context, $ // it is either absolute or pluginfile link continue; } - $chapterpath = dirname($chapter->importsrc).'/'.$matches[2][$i]; + + [$path, $anchor] = array_pad(explode('#', $matches[2][$i], 2), 2, ''); + if (!empty($anchor)) { + $anchor = '#' . $anchor; + } + + $chapterpath = dirname($chapter->importsrc).'/'.$path; $chapterpath = toolbook_importhtml_fix_path($chapterpath); foreach ($allchapters as $target) { if ($target->importsrc === $chapterpath) { - $newcontent = str_replace($match, 'href="'.new moodle_url('/mod/book/view.php', - array('id'=>$context->instanceid, 'chapterid'=>$target->id)).'"', $newcontent); + $newcontent = str_replace($match, 'href="' . new moodle_url('/mod/book/view.php', + ['id' => $context->instanceid, 'chapterid' => $target->id]) . $anchor . '"', $newcontent); } } } diff --git a/mod/book/tool/importhtml/tests/fixtures/chapters_links.zip b/mod/book/tool/importhtml/tests/fixtures/chapters_links.zip new file mode 100644 index 0000000000000000000000000000000000000000..df9a046a8dcc00f0f76609e224df10905662fa7b GIT binary patch literal 3345 zcmWIWW@Zs#-~hsz)n-u)P~gDGz`)C(z>u7gSWuE$6s4C@lA9A6!pp$!v}Qtj;OYtK zAiA`In}Lz#D^M-a2nL4DCpAu<-S~Ku=PCb{EJ2cOW#=S2SyflM268FRRJB}b_RB$0 zZ?;Qo&!Q_P(MwZ0Qd;CZW)~&J6}i<-oHRE)Gq2Ifb01Skn4;4{o6RcDj7qtS=W`hC z=eRt@(bzx;tbh#z#3Vu`aM=xXV(T5%99vnU5jBo1J6Eyqpi^Kqr9Q9e~wG zEzArI5&0XDoDa}rAdKd@=^n|2@557KOANa#M0vebmNHD7l zNE;d$urp>V%-`ACsPRBTNQfn|vBY2+gDLj{&BW#o;}6CL9qP}Yzfu(wd9vhH>yof3 zJD#aNU!L-8Y4cP=GiJ^Oahff&<{Wu6>C&SsQ>Gl56!Nqop`);8a$^ho1&fwlcaA)f z>9~`tAeNdC;5x}$*OTRy|CUqVNzL{r>RV1- zxJAYH`k`AFZX7vr;m)N)OI~N0+}J*8{$GWCnJGn*r7U`<*#?LSJv=CW8$I7xeW!eNK7ynj0Ei@z?kA z@w}?*9HaS7-EBT{(Zo+jH#&?GqXs^!;@8&iSp~(p%7J#C5)a=Q~HJ_euTp zr%(F(Z1mOB3qI|$(KJZ=+zI{m841}drg8E_E?Chhb>oSW0<%bZ=7EGZBX6VPq6VLY z9I@18BDarm-w1x;!S{~$!j}Uayv%7^41RveoV@DT()>=}z~}1M>t;n>JacHLT4>y( zcHQMHmv1%n`jwsRbl1LCZ~Np^=JIg&)$hzF@?Y1x&3bK%-^=PMqXn<8$oyZzc`>^# z^z#(1dmC$KL@2KOZJ1Tw^?2IJ=Qo!$&HcY}p5@<^e`Wrf%Wr@0w=2DQSMST}vagrV z>ROxRrPhUuS;u`o_iTT6dqUK!ORQ&#C1y&9b)L_Eyzi^OFgX1lSues8#l*k>N~MVO zI~{k9j6~!}J7|ss(P)VlSB{)WX^zwY=14)jIg)v2nKovQMD`Kx9Es++(HwcmrS>e# zhJ4lUA3d8(&5d@>c{!Ey3xDp}8`rJ|{oOrjM}j-MC#&VmqpECd-4Zh&v5KWmnIaPL z^7Zp4>gvx@o`_G6h?Izscp*MrMeXU5W3weBUM&|_UAE+v_)@Va;!|IwGn76P4}F#X zZ0VA)7osU5H^i5ViKj0QyXCgSMY1*BqOH1R)zT-^pFe$~zU+pY`1F;j%Wg=m6it6J z-Pvb@X~=1oHl2Vg4!k)-};? zKet?7y*Tvy>=W(T)88^>M=k$iYb$x7G^?-vQp*d|{i`aySl{2U1E!HHeszwMk80wpe7^?ENQ$1WRlyUM79M~Eh1N#s2-REY!pB} zfL1etJbqNiQc;HLffN>O9ze4NM`lO11yqP27cZzDP-TaE0IeJWc>qfxiEcD< h#G`uPJJ4v%7(lZHrw3TsKyk?igwDW{eg_wb2LLM<2UP$7 literal 0 HcmV?d00001 diff --git a/mod/book/tool/importhtml/tests/locallib_test.php b/mod/book/tool/importhtml/tests/locallib_test.php index 959ab18442c..0f9be881d23 100644 --- a/mod/book/tool/importhtml/tests/locallib_test.php +++ b/mod/book/tool/importhtml/tests/locallib_test.php @@ -39,41 +39,79 @@ require_once($CFG->dirroot.'/mod/book/tool/importhtml/locallib.php'); */ final class locallib_test extends \advanced_testcase { + /** @var object */ + private object $book; + /** @var object */ + private object $context; + /** @var object */ + private object $record; + public function setUp(): void { parent::setUp(); $this->resetAfterTest(); + + $course = $this->getDataGenerator()->create_course(); + $this->book = $this->getDataGenerator()->create_module('book', ['course' => $course->id]); + $this->context = \context_module::instance($this->book->cmid); + $this->record = (object) [ + 'contextid' => $this->context->id, + 'component' => 'phpunit', + 'filearea' => 'test', + 'itemid' => 0, + 'filepath' => '/', + ]; } + /** + * Tests the events within toolbook_importhtml_import_chapters + * @covers ::toolbook_importhtml_import_chapters + */ public function test_import_chapters_events(): void { - $course = $this->getDataGenerator()->create_course(); - $book = $this->getDataGenerator()->create_module('book', array('course' => $course->id)); - $context = \context_module::instance($book->cmid); - $record = new \stdClass(); - $record->contextid = $context->id; - $record->component = 'phpunit'; - $record->filearea = 'test'; - $record->itemid = 0; - $record->filepath = '/'; - $record->filename = 'chapters.zip'; - - $fs = get_file_storage(); - $file = $fs->create_file_from_pathname($record, self::get_fixture_path(__NAMESPACE__, 'chapters.zip')); + $this->record->filename = 'chapters.zip'; + $file = get_file_storage()->create_file_from_pathname( + $this->record, + self::get_fixture_path(__NAMESPACE__, 'chapters.zip') + ); // Importing the chapters. $sink = $this->redirectEvents(); - toolbook_importhtml_import_chapters($file, 2, $book, $context, false); + toolbook_importhtml_import_chapters($file, 2, $this->book, $this->context, false); $events = $sink->get_events(); - // Checking the results. + // Checking the results up to the triggered event. $this->assertCount(5, $events); foreach ($events as $event) { $this->assertInstanceOf('\mod_book\event\chapter_created', $event); - $this->assertEquals($context, $event->get_context()); + $this->assertEquals($this->context, $event->get_context()); $chapter = $event->get_record_snapshot('book_chapters', $event->objectid); $this->assertNotEmpty($chapter); $this->assertEventContextNotUsed($event); } } + /** + * Tests the conversion of (anchored) links within toolbook_importhtml_import_chapters + * @covers ::toolbook_importhtml_import_chapters + */ + public function test_import_chapters_links(): void { + global $DB; + + $this->record->filename = 'chapters_links.zip'; + $file = get_file_storage()->create_file_from_pathname( + $this->record, + self::get_fixture_path(__NAMESPACE__, 'chapters_links.zip') + ); + + toolbook_importhtml_import_chapters($file, 2, $this->book, $this->context, false); + + $chapters = $DB->get_records('book_chapters', ['bookid' => $this->book->id]); + foreach ($chapters as $chapter) { + $this->assertStringNotContainsString('.html', $chapter->content); + $this->assertStringNotContainsString('.html#anchor', $chapter->content); + $this->assertMatchesRegularExpression('/chapterid=[0-9]*"/i', $chapter->content); + $this->assertMatchesRegularExpression('/chapterid=[0-9]*#anchor"/i', $chapter->content); + } + } + }