From b69f8d3b4263c5ec8b75ecc68eb3c0d80b56611c Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Wed, 24 May 2023 10:34:30 +0200 Subject: [PATCH 01/14] add page version property --- app/class/Config.php | 23 ++++++++++++++++++++++- app/class/Page.php | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/app/class/Config.php b/app/class/Config.php index e5053f30..dab7d948 100644 --- a/app/class/Config.php +++ b/app/class/Config.php @@ -50,6 +50,11 @@ abstract class Config /** @var string $lang Default string for pages */ protected static $lang = "en"; + /** Page version during creation */ + protected static int $pageversion = Page::V1; + + + public const LANG_MIN = 2; public const LANG_MAX = 16; @@ -75,12 +80,16 @@ public static function hydrate(array $datas) } } - public static function readconfig() + public static function readconfig(): bool { if (file_exists(Model::CONFIG_FILE)) { $current = file_get_contents(Model::CONFIG_FILE); $datas = json_decode($current, true); self::hydrate($datas); + // Setup old config file to user page version 1 + if (isset($datas['pageaversion'])) { + self::$pageversion = Page::V1; + } return true; } else { return false; @@ -316,6 +325,11 @@ public static function disablejavascript(): bool return self::$disablejavascript; } + public static function pageversion(): int + { + return self::$pageversion; + } + // __________________________________________ S E T ______________________________________ @@ -534,4 +548,11 @@ public static function setdisablejavascript($disablejavascript) { self::$disablejavascript = boolval($disablejavascript); } + + public static function setpageversion($pageversion): void + { + if (in_array($pageversion, Page::VERSIONS)) { + self::$pageversion = $pageversion; + } + } } diff --git a/app/class/Page.php b/app/class/Page.php index 5fdfdf88..929425f6 100644 --- a/app/class/Page.php +++ b/app/class/Page.php @@ -51,11 +51,18 @@ class Page extends Item protected $password; protected $postprocessaction; + protected int $version; + public const LATITUDE_MIN = -90; public const LATITUDE_MAX = 90; public const LONGITUDE_MIN = -180; public const LONGITUDE_MAX = 180; + public const V1 = 1; + public const V2 = 2; + + public const VERSIONS = [self::V1, self::V2]; + public const PUBLIC = 0; public const PRIVATE = 1; public const NOT_PUBLISHED = 2; @@ -131,6 +138,7 @@ public function reset() $this->setrefresh(0); $this->setpassword(''); $this->postprocessaction = false; + $this->version = Config::pageversion(); } public function ispublic(): bool @@ -430,6 +438,11 @@ public function postprocessaction($type = 'int'): bool return $this->postprocessaction; } + public function version($type = 'int'): int + { + return $this->version; + } + @@ -834,6 +847,13 @@ public function setpostprocessaction($postprocessaction): void $this->postprocessaction = boolval($postprocessaction); } + public function setversion($version): void + { + if (in_array($version, self::VERSIONS)) { + $this->version = $version; + } + } + // __________________________________ C O U N T E R S ______________________________ From af32957bb0d9de9a35aec1ba4473020e9c2c2dfd Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Mon, 29 May 2023 23:56:31 +0200 Subject: [PATCH 02/14] split Page class Page is now abstract created Pagev1 class created Pagev2 class --- app/class/Controllerapipage.php | 8 +-- app/class/Controllerpage.php | 29 +++----- app/class/Modelpage.php | 89 +++++++++++++++++++---- app/class/Opt.php | 3 +- app/class/Page.php | 122 ++++++++------------------------ app/class/Pagev1.php | 101 ++++++++++++++++++++++++++ app/class/Pagev2.php | 38 ++++++++++ app/class/Servicerender.php | 8 +-- app/class/Servicerss.php | 10 +-- tests/ServicerenderTest.php | 4 +- 10 files changed, 270 insertions(+), 142 deletions(-) create mode 100644 app/class/Pagev1.php create mode 100644 app/class/Pagev2.php diff --git a/app/class/Controllerapipage.php b/app/class/Controllerapipage.php index 8ff81c26..c86a7dea 100644 --- a/app/class/Controllerapipage.php +++ b/app/class/Controllerapipage.php @@ -76,8 +76,7 @@ public function update(string $page) } } $oldpage = clone $this->page; - $update = new Page($datas); - if (!is_null($update->id()) && $update->id() !== $this->page->id()) { + if (isset($datas['id']) && $datas['id'] !== $this->page->id()) { $this->shortresponse(400, "Page ID and datas ID doesn't match"); } $this->page->hydrate($datas); @@ -114,7 +113,8 @@ public function add(string $page) http_response_code(405); exit; } - $this->page = new Page(["id" => $page]); + + $this->page = $this->pagemanager->newpage(["id" => $page]); $this->page->reset(); $this->page->addauthor($this->user->id()); if ($this->pagemanager->add($this->page)) { @@ -136,7 +136,7 @@ public function put(string $page) if ($exist && !$this->canedit()) { $this->shortresponse(401, 'Page already exist but user cannot update it'); } - $this->page = new Page(array_merge($this->recievejson(), ['id' => $page])); + $this->page = $this->pagemanager->newpage(array_merge($this->recievejson(), ['id' => $page])); $this->page->addauthor($this->user->id()); if ($this->pagemanager->update($this->page)) { http_response_code($exist ? 200 : 201); diff --git a/app/class/Controllerpage.php b/app/class/Controllerpage.php index 4b74b8a8..61c8330a 100644 --- a/app/class/Controllerpage.php +++ b/app/class/Controllerpage.php @@ -31,7 +31,7 @@ public function setpage(string $id, string $route) http_response_code(308); $this->routedirect($route, ['page' => $cleanid]); } else { - $this->page = new Page(['id' => $cleanid]); + $this->page = $this->pagemanager->newpage(['id' => $cleanid]); } } @@ -42,17 +42,17 @@ public function setpage(string $id, string $route) */ public function importpage(): bool { - if (isset($_SESSION['pageupdate']['id']) && $_SESSION['pageupdate']['id'] == $this->page->id()) { - $this->page = new Page($_SESSION['pageupdate']); - unset($_SESSION['pageupdate']); - return true; - } else { - try { + try { + if (isset($_SESSION['pageupdate']['id']) && $_SESSION['pageupdate']['id'] == $this->page->id()) { + $this->page = $this->pagemanager->parsepage($_SESSION['pageupdate']); + unset($_SESSION['pageupdate']); + return true; + } else { $this->page = $this->pagemanager->get($this->page); return true; - } catch (RuntimeException $e) { - return false; } + } catch (RuntimeException $e) { + return false; } } @@ -233,16 +233,7 @@ public function edit($page) if ($this->importpage() && $this->canedit()) { - $datas['tablist'] = [ - 'main' => $this->page->main(), - 'css' => $this->page->css(), - 'header' => $this->page->header(), - 'nav' => $this->page->nav(), - 'aside' => $this->page->aside(), - 'footer' => $this->page->footer(), - 'body' => $this->page->body(), - 'javascript' => $this->page->javascript() - ]; + $datas['tablist'] = $this->page->tabs(); $datas['faviconlist'] = $this->mediamanager->listfavicon(); $datas['thumbnaillist'] = $this->mediamanager->listthumbnail(); diff --git a/app/class/Modelpage.php b/app/class/Modelpage.php index 95654abe..4c7e7e7f 100644 --- a/app/class/Modelpage.php +++ b/app/class/Modelpage.php @@ -6,7 +6,9 @@ use JamesMoss\Flywheel\Document; use DateTimeImmutable; use DateTimeInterface; +use DomainException; use InvalidArgumentException; +use RangeException; use RuntimeException; class Modelpage extends Modeldb @@ -37,7 +39,12 @@ public function pagelist(): array if (empty($this->pagelist)) { $list = $this->repo->findAll(); foreach ($list as $pagedata) { - $this->pagelist[$pagedata->id] = new Page($pagedata); + $id = $pagedata->id; + try { + $this->pagelist[$id] = $this->parsepage($pagedata); + } catch (RuntimeException $e) { + Logger::error("Could not load Page with ID \"$id\" : $e"); + } } } return $this->pagelist; @@ -59,7 +66,11 @@ public function pagelistbyid(array $idlist = []): array $pagelist = []; foreach ($pagedatalist as $id => $pagedata) { - $pagelist[$id] = new Page($pagedata); + try { + $this->pagelist[$id] = $this->parsepage($pagedata); + } catch (RuntimeException $e) { + Logger::error("Could not load Page with ID \"$id\" : $e"); + } } return $pagelist; } @@ -98,11 +109,14 @@ public function get($id): Page } if (is_string($id)) { $pagedata = $this->repo->findById($id); - if ($pagedata !== false) { - return new Page($pagedata); - } else { + if ($pagedata === false) { throw new RuntimeException("Could not find Page with the following ID: \"$id\""); } + try { + return $this->parsepage($pagedata); + } catch (RuntimeException $e) { + throw new RuntimeException("Could not load Page with ID \"$id\": $e"); + } } else { throw new InvalidArgumentException("argument of Modelpage->get() should be a ID string or Page"); } @@ -141,8 +155,6 @@ public function getfromfile() return false; } - $files = $_FILES; - $json = file_get_contents($_FILES['pagefile']['tmp_name']); $pagedata = json_decode($json, true); @@ -150,9 +162,11 @@ public function getfromfile() return false; } - $page = new Page($pagedata); - - return $page; + try { + return $this->parsepage($pagedata); + } catch (RuntimeException $e) { + return false; + } } /** @@ -674,11 +688,9 @@ protected function deepsearch(array $pagelist, string $regex, array $options): a foreach ($pagelist as $page) { $count = 0; if ($options['content']) { - $count += preg_match($regex, $page->main()); - $count += preg_match($regex, $page->nav()); - $count += preg_match($regex, $page->aside()); - $count += preg_match($regex, $page->header()); - $count += preg_match($regex, $page->footer()); + foreach ($page->contents() as $content) { + $count += preg_match($regex, $page->$content()); + } } if ($options['other']) { $count += preg_match($regex, $page->body()); @@ -700,4 +712,51 @@ protected function deepsearch(array $pagelist, string $regex, array $options): a } return $pageselected; } + + /** + * Create a page + * + * @param array $datas Page's datas + * @return Page V1 or V2 depending of config file setting + */ + public function newpage(array $datas = []): Page + { + $pageversion = Config::pageversion(); + switch ($pageversion) { + case Page::V1: + return new Pagev1($datas); + + case Page::V2: + return new Pagev2($datas); + } + throw new DomainException("Invalid page version allowed to be set in config"); + } + + + /** + * This function will check for page version in datas and will retrun coresponding page version object + * If no version is specified and Markdown field is not used, it will return Pagev1 + * + * @param array|object $datas Page's datas + * @return Page V1 or V2 + * @throws RangeException If page version is defined but out of range + */ + public function parsepage($datas = []): Page + { + $metadatas = is_object($datas) ? get_object_vars($datas) : $datas; + if (isset($metadatas['version'])) { + switch ($metadatas['version']) { + case Page::V1: + return new Pagev1($datas); + + case Page::V2: + return new Pagev1($datas); + } + throw new RangeException('Version is specified but out of range'); + } elseif (isset($metadatas['markdown'])) { + return new Pagev2($datas); + } else { + return new Pagev1($datas); + } + } } diff --git a/app/class/Opt.php b/app/class/Opt.php index 5cc8517c..a89978c5 100644 --- a/app/class/Opt.php +++ b/app/class/Opt.php @@ -71,8 +71,7 @@ class Opt extends Item public function __construct(array $data = []) { - $page = new Page(); - $this->pagevarlist = ($page->getobjectvars()); + $this->pagevarlist = Page::getclassvars(); $this->hydrate($data); } diff --git a/app/class/Page.php b/app/class/Page.php index 929425f6..7601b0e2 100644 --- a/app/class/Page.php +++ b/app/class/Page.php @@ -6,7 +6,7 @@ use DateTimeImmutable; use DateTimeZone; -class Page extends Item +abstract class Page extends Item { protected $id; protected $title; @@ -22,11 +22,6 @@ class Page extends Item protected $css; protected $javascript; protected $body; - protected $header; - protected $main; - protected $nav; - protected $aside; - protected $footer; protected $externalcss; protected $customhead; protected $secure; @@ -68,7 +63,7 @@ class Page extends Item public const NOT_PUBLISHED = 2; public const SECUREMAX = 2; - public const TABS = ['main', 'css', 'header', 'body', 'nav', 'aside', 'footer', 'javascript']; + public const TABS = ['css', 'body', 'javascript']; public const VAR_DATE = ['date', 'datecreation', 'datemodif', 'daterender']; public const TEMPLATE_OPTIONS = ['externalcss', 'externaljavascript', 'favicon', 'thumbnail', 'recursivecss']; @@ -83,13 +78,13 @@ public function __construct($datas = []) } /** - * Return a list of all object vars name as strings + * Return a list of all class vars name as strings * * @return string[] */ - public function getobjectvars(): array + public static function getclassvars(): array { - return array_keys(get_object_vars($this)); + return array_keys(get_class_vars(self::class)); } public function reset() @@ -110,15 +105,9 @@ public function reset() $this->setcss(''); $this->setjavascript(''); $this->setbody(Config::defaultbody()); - $this->setheader(''); - $this->setmain(''); - $this->setnav(''); - $this->setaside(''); - $this->setfooter(''); $this->setexternalcss([]); $this->setcustomhead(''); $this->setsecure(Config::defaultprivacy()); - $this->setinterface('main'); $this->setlinkto([]); $this->settemplatebody(''); $this->settemplatecss(''); @@ -138,7 +127,6 @@ public function reset() $this->setrefresh(0); $this->setpassword(''); $this->postprocessaction = false; - $this->version = Config::pageversion(); } public function ispublic(): bool @@ -164,6 +152,26 @@ public function isgeo(): bool return (!is_null($this->latitude) && !is_null($this->longitude)); } + /** + * @return string[] Page fields containting content + */ + public function contents(): array + { + return array_diff($this::TABS, Page::TABS); + } + + /** + * @return string[] Tabs contents to be included in edit page + */ + public function tabs(): array + { + $tabs = []; + foreach ($this::TABS as $tab) { + $tabs[$tab] = $this->$tab; + } + return $tabs; + } + // _____________________________________________________ G E T ____________________________________________________ public function id($type = 'string') @@ -236,6 +244,11 @@ public function daterender($option = 'date') return $this->datetransform('daterender', $option); } + public function primary($type = ''): string + { + return ''; + } + public function css($type = 'string') { return $this->css; @@ -250,27 +263,6 @@ public function body($type = 'string') { return $this->body; } - - public function header($type = 'string') - { - return $this->header; - } - - public function main($type = 'string') - { - return $this->main; - } - - public function nav($type = "string") - { - return $this->nav; - } - - public function aside($type = "string") - { - return $this->aside; - } - public function externalcss($type = "array") { return $this->externalcss; @@ -285,11 +277,6 @@ public function customhead($type = "string") } } - public function footer($type = "string") - { - return $this->footer; - } - public function secure($type = 'int') { if ($type == 'string') { @@ -621,38 +608,6 @@ public function setbody($body) } } - public function setheader($header) - { - if (strlen($header) < self::LENGTH_LONG_TEXT && is_string($header)) { - $header = crlf2lf($header); - $this->header = $header; - } - } - - public function setmain($main) - { - if (strlen($main) < self::LENGTH_LONG_TEXT and is_string($main)) { - $main = crlf2lf($main); - $this->main = $main; - } - } - - public function setnav($nav) - { - if (strlen($nav) < self::LENGTH_LONG_TEXT and is_string($nav)) { - $nav = crlf2lf($nav); - $this->nav = $nav; - } - } - - public function setaside($aside) - { - if (strlen($aside) < self::LENGTH_LONG_TEXT and is_string($aside)) { - $aside = crlf2lf($aside); - $this->aside = $aside; - } - } - public function setexternalcss($externalcss) { if (is_array($externalcss)) { @@ -668,14 +623,6 @@ public function setcustomhead(string $customhead) } } - public function setfooter($footer) - { - if (strlen($footer) < self::LENGTH_LONG_TEXT and is_string($footer)) { - $footer = crlf2lf($footer); - $this->footer = $footer; - } - } - public function setsecure($secure) { if ($secure >= 0 and $secure <= self::SECUREMAX) { @@ -685,7 +632,7 @@ public function setsecure($secure) public function setinterface($interface) { - if (in_array($interface, self::TABS)) { + if (in_array($interface, $this::TABS)) { $this->interface = $interface; } } @@ -847,13 +794,6 @@ public function setpostprocessaction($postprocessaction): void $this->postprocessaction = boolval($postprocessaction); } - public function setversion($version): void - { - if (in_array($version, self::VERSIONS)) { - $this->version = $version; - } - } - // __________________________________ C O U N T E R S ______________________________ diff --git a/app/class/Pagev1.php b/app/class/Pagev1.php new file mode 100644 index 00000000..4f4a7d32 --- /dev/null +++ b/app/class/Pagev1.php @@ -0,0 +1,101 @@ +setheader(''); + $this->setmain(''); + $this->setnav(''); + $this->setaside(''); + $this->setfooter(''); + + $this->setinterface('main'); + } + + + public function header($type = 'string') + { + return $this->header; + } + + public function main($type = 'string') + { + return $this->main; + } + + public function primary($type = ''): string + { + return $this->main; + } + + public function nav($type = "string") + { + return $this->nav; + } + + public function aside($type = "string") + { + return $this->aside; + } + + public function footer($type = "string") + { + return $this->footer; + } + + + public function setheader($header) + { + if (strlen($header) < self::LENGTH_LONG_TEXT && is_string($header)) { + $header = crlf2lf($header); + $this->header = $header; + } + } + + public function setmain($main) + { + if (strlen($main) < self::LENGTH_LONG_TEXT and is_string($main)) { + $main = crlf2lf($main); + $this->main = $main; + } + } + + public function setnav($nav) + { + if (strlen($nav) < self::LENGTH_LONG_TEXT and is_string($nav)) { + $nav = crlf2lf($nav); + $this->nav = $nav; + } + } + + public function setaside($aside) + { + if (strlen($aside) < self::LENGTH_LONG_TEXT and is_string($aside)) { + $aside = crlf2lf($aside); + $this->aside = $aside; + } + } + + public function setfooter($footer) + { + if (strlen($footer) < self::LENGTH_LONG_TEXT and is_string($footer)) { + $footer = crlf2lf($footer); + $this->footer = $footer; + } + } +} diff --git a/app/class/Pagev2.php b/app/class/Pagev2.php new file mode 100644 index 00000000..9a4f8de6 --- /dev/null +++ b/app/class/Pagev2.php @@ -0,0 +1,38 @@ +setmarkdown(''); + + $this->setinterface('markdown'); + } + + public function markdown($type = ''): string + { + return $this->markdown; + } + + public function primary($type = ''): string + { + return $this->markdown; + } + + public function setmarkdown($markdown) + { + if (is_string($markdown)) { + $this->markdown = $markdown; + } + } +} diff --git a/app/class/Servicerender.php b/app/class/Servicerender.php index 4f3be648..5a173d6e 100644 --- a/app/class/Servicerender.php +++ b/app/class/Servicerender.php @@ -82,18 +82,18 @@ public function render(Page $page): string } /** - * Render a page MAIN content to be used in RSS feed + * Render page's primary content to be used in RSS feed * * @param Page $page Page to render * - * @return string HTML Parsed MAIN content of a page + * @return string HTML Parsed primary content of a page * * @todo render absolute media links */ - public function rendermain(Page $page): string + public function renderprimary(Page $page): string { $this->page = $page; - $element = new Element($page->id(), ['content' => $page->main(), 'type' => "main"]); + $element = new Element($page->id(), ['content' => $page->primary(), 'type' => 'main']); $html = $this->elementparser($element); return $this->bodyparser($html); } diff --git a/app/class/Servicerss.php b/app/class/Servicerss.php index 8f5f5496..54398166 100644 --- a/app/class/Servicerss.php +++ b/app/class/Servicerss.php @@ -175,7 +175,7 @@ protected function render(array $pagelist, Bookmark $bookmark): string $content = $xml->createElement("content"); $content->appendChild( - new DOMText(html_entity_decode($this->mainhtml($page), ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8")) + new DOMText(html_entity_decode($this->primaryhtml($page), ENT_QUOTES | ENT_SUBSTITUTE, "UTF-8")) ); $content->setAttribute("type", "html"); $entry->appendChild($content); @@ -199,15 +199,15 @@ protected function href(Page $page): string } /** - * Get the HTML output of a page + * Get the HTML output of the primary content of a page * * @param Page $page - * @return string HTML content parsed from page MAIN + * @return string HTML content parsed from page primary field */ - protected function mainhtml(Page $page): string + protected function primaryhtml(Page $page): string { $render = new Servicerender($this->router, $this->pagemanager); - return $render->rendermain($page); + return $render->renderprimary($page); } /** diff --git a/tests/ServicerenderTest.php b/tests/ServicerenderTest.php index c8870a27..763b983f 100644 --- a/tests/ServicerenderTest.php +++ b/tests/ServicerenderTest.php @@ -9,7 +9,7 @@ use Wcms\Fs; use Wcms\Modelpage; use Wcms\Servicerender; -use Wcms\Page; +use Wcms\Pagev1; class ServicerenderTest extends TestCase { @@ -50,7 +50,7 @@ public function renderTest(string $name, bool $requireslinux = false): void $this->markTestSkipped(); } $pagedata = json_decode(file_get_contents(__DIR__ . "/data/ServicerenderTest/$name.json"), true); - $page = new Page($pagedata); + $page = new Pagev1($pagedata); $html = $this->renderengine->render($page); $expected = __DIR__ . "/data/ServicerenderTest/$name.html"; From eb9c7e439f3b100cab9e1f56548cb9a02afbfb0d Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Sun, 13 Aug 2023 22:16:36 +0200 Subject: [PATCH 03/14] filter by page version Co-authored-by: Nicolas Peugnet --- app/class/Modelpage.php | 12 +++++++++++- app/class/Opt.php | 16 ++++++++++++++++ app/view/templates/homeopt.php | 20 ++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/app/class/Modelpage.php b/app/class/Modelpage.php index 4c7e7e7f..3a44b9a4 100644 --- a/app/class/Modelpage.php +++ b/app/class/Modelpage.php @@ -465,7 +465,8 @@ protected function filter(array $pagelist, Opt $opt): array $this->flinkto($page, $opt->linkto()) && $this->fsince($page, $opt->since()) && $this->funtil($page, $opt->until()) && - $this->fgeo($page, $opt->geo()) + $this->fgeo($page, $opt->geo()) && + $this->fversion($page, $opt->version()) ) { $filter[] = $page->id(); } @@ -666,6 +667,15 @@ protected function fgeo(Page $page, bool $geo) } } + protected function fversion(Page $page, int $version) + { + if ($version === 0) { + return true; + } else { + return $page->version() === $version; + } + } + /** * Search for regex and count occurences diff --git a/app/class/Opt.php b/app/class/Opt.php index a89978c5..0cb13a32 100644 --- a/app/class/Opt.php +++ b/app/class/Opt.php @@ -37,6 +37,8 @@ class Opt extends Item protected bool $geo = false; + protected int $version = 0; + protected $pageidlist = []; /** @var array $pagevarlist List fo every properties of an Page object */ @@ -63,6 +65,7 @@ class Opt extends Item 'since', 'until', 'geo', + 'version', 'invert', 'limit' ]; @@ -371,6 +374,11 @@ public function geo(): bool return $this->geo; } + public function version(): int + { + return $this->version; + } + public function invert(): bool { return $this->invert; @@ -547,6 +555,14 @@ public function setgeo($geo) $this->geo = boolval($geo); } + public function setversion($version): void + { + $version = intval($version); + if ($version === 0 || in_array($version, Page::VERSIONS)) { + $this->version = $version; + } + } + public function setinvert($invert) { $this->invert = boolval($invert); diff --git a/app/view/templates/homeopt.php b/app/view/templates/homeopt.php index 7a262215..e0984b31 100644 --- a/app/view/templates/homeopt.php +++ b/app/view/templates/homeopt.php @@ -178,6 +178,26 @@ +
+ Version +
+
    +
  • + version() === 0 ? "checked" : "" ?> /> + +
  • +
  • + version() === Wcms\Page::V1 ? "checked" : "" ?> /> + +
  • +
  • + version() === Wcms\Page::V2 ? "checked" : "" ?> /> + +
  • +
+
+
+
From 494e049c717a0896dd1da0e7b0a2d5dec5744ccd Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Tue, 30 May 2023 00:27:47 +0200 Subject: [PATCH 04/14] sort by version + display column --- app/class/Model.php | 3 ++- app/view/templates/home.php | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/app/class/Model.php b/app/class/Model.php index ffe7cafe..37d813eb 100644 --- a/app/class/Model.php +++ b/app/class/Model.php @@ -59,7 +59,8 @@ abstract class Model 'linkto', 'visitcount', 'displaycount', - 'editcount' + 'editcount', + 'version', ]; public const HTML_ELEMENTS = ['header', 'nav', 'main', 'aside', 'footer']; diff --git a/app/view/templates/home.php b/app/view/templates/home.php index 1e0b2882..4bd88545 100644 --- a/app/view/templates/home.php +++ b/app/view/templates/home.php @@ -229,6 +229,11 @@ display insert('macro_tablesort', ['opt' => $opt, 'th' => 'displaycount']) ?> + + + version + insert('macro_tablesort', ['opt' => $opt, 'th' => 'version']) ?> + @@ -321,6 +326,8 @@ displaycount() ?> + + version() ?> From ed05000cd8f7eed44ae3e43a70bd6e0cb4d7fd38 Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Tue, 30 May 2023 17:29:33 +0200 Subject: [PATCH 05/14] page v2 and v1 can be rendered --- app/class/Controllerinfo.php | 2 +- app/class/Element.php | 72 +------------- app/class/Elementv1.php | 69 ++++++++++++++ app/class/Elementv2.php | 40 ++++++++ app/class/Model.php | 2 - app/class/Modelpage.php | 15 ++- app/class/Pagev1.php | 1 + app/class/Servicerender.php | 170 +++++++++------------------------- app/class/Servicerenderv1.php | 136 +++++++++++++++++++++++++++ app/class/Servicerenderv2.php | 116 +++++++++++++++++++++++ app/class/Servicerss.php | 22 ++++- app/class/Summary.php | 2 +- tests/ServicerenderTest.php | 3 +- 13 files changed, 444 insertions(+), 206 deletions(-) create mode 100644 app/class/Elementv1.php create mode 100644 app/class/Elementv2.php create mode 100644 app/class/Servicerenderv1.php create mode 100644 app/class/Servicerenderv2.php diff --git a/app/class/Controllerinfo.php b/app/class/Controllerinfo.php index 5ffa5b93..a26f3490 100644 --- a/app/class/Controllerinfo.php +++ b/app/class/Controllerinfo.php @@ -16,7 +16,7 @@ public function desktop() { if ($this->user->isinvite()) { if (file_exists(Model::MAN_FILE)) { - $render = new Servicerender($this->router, $this->pagemanager, true); + $render = new Servicerenderv2($this->router, $this->pagemanager, true); $htmlman = file_get_contents(Model::MAN_FILE); $htmlman = $render->rendermanual($htmlman); diff --git a/app/class/Element.php b/app/class/Element.php index 53a814bd..fc84fba6 100644 --- a/app/class/Element.php +++ b/app/class/Element.php @@ -2,17 +2,13 @@ namespace Wcms; -use DomainException; - /** * HTML Element used in pages */ -class Element extends Item +abstract class Element extends Item { - protected $fullmatch; - protected string $type; - protected $options; - protected $sources = []; + protected string $fullmatch; + protected string $options; protected int $everylink = 0; protected bool $markdown = true; protected string $content = ''; @@ -23,8 +19,6 @@ class Element extends Item protected bool $urllinker; protected int $headeranchor = self::NOHEADERANCHOR; - /** @var bool Include element with HTML tags */ - protected bool $tag; public const NOHEADERANCHOR = 0; public const HEADERANCHORLINK = 1; @@ -37,32 +31,7 @@ class Element extends Item - public function __construct($pageid, $datas = []) - { - $this->urllinker = Config::urllinker(); - $this->tag = Config::htmltag(); - $this->hydrate($datas); - $this->analyse($pageid); - } - - private function analyse(string $pageid) - { - if (!empty($this->options)) { - $this->options = str_replace('*', $pageid, $this->options); - parse_str($this->options, $datas); - if (isset($datas['id'])) { - $this->sources = explode(' ', $datas['id']); - } else { - $this->sources = [$pageid]; - } - $this->hydrate($datas); - } else { - $this->sources = [$pageid]; - } - } - - - + abstract protected function analyse(string $pageid); // ______________________________________________ G E T ________________________________________________________ @@ -73,21 +42,11 @@ public function fullmatch(): string return $this->fullmatch; } - public function type(): string - { - return $this->type; - } - public function options(): string { return $this->options; } - public function sources(): array - { - return $this->sources; - } - public function everylink(): int { return $this->everylink; @@ -128,11 +87,6 @@ public function urllinker(): bool return $this->urllinker; } - public function tag(): bool - { - return $this->tag; - } - @@ -146,19 +100,6 @@ public function setfullmatch(string $fullmatch) $this->fullmatch = $fullmatch; } - /** - * @throws DomainException if given type is not an HTML element - */ - public function settype(string $type) - { - $type = strtolower($type); - if (in_array($type, Model::HTML_ELEMENTS)) { - $this->type = $type; - } else { - throw new DomainException("$type is not a valid Page HTML Element Type"); - } - } - public function setoptions(string $options) { if (!empty($options)) { @@ -208,9 +149,4 @@ public function seturllinker($urllinker) { $this->urllinker = boolval($urllinker); } - - public function settag($tag) - { - $this->tag = boolval($tag); - } } diff --git a/app/class/Elementv1.php b/app/class/Elementv1.php new file mode 100644 index 00000000..1f330ad3 --- /dev/null +++ b/app/class/Elementv1.php @@ -0,0 +1,69 @@ +tag = Config::htmltag(); + $this->urllinker = Config::urllinker(); + $this->fullmatch = $fullmatch; + $type = strtolower($type); + if (in_array($type, Pagev1::HTML_ELEMENTS)) { + $this->type = $type; + } else { + throw new DomainException("$type is not a valid Page HTML Element Type"); + } + $this->options = $options; + $this->analyse($pageid); + } + + protected function analyse(string $pageid) + { + if (!empty($this->options)) { + $this->options = str_replace('*', $pageid, $this->options); + parse_str($this->options, $datas); + if (isset($datas['id'])) { + $this->sources = explode(' ', $datas['id']); + } else { + $this->sources = [$pageid]; + } + $this->hydrate($datas); + } else { + $this->sources = [$pageid]; + } + } + + + // ______________________________________________ G E T ________________________________________________________ + + public function sources(): array + { + return $this->sources; + } + + public function type(): string + { + return $this->type; + } + + public function tag(): bool + { + return $this->tag; + } + + public function settag($tag) + { + $this->tag = boolval($tag); + } +} diff --git a/app/class/Elementv2.php b/app/class/Elementv2.php new file mode 100644 index 00000000..d606bd5c --- /dev/null +++ b/app/class/Elementv2.php @@ -0,0 +1,40 @@ +urllinker = Config::urllinker(); + $this->fullmatch = $fullmatch; + $this->options = $options; + $this->analyse($pageid); + } + + protected function analyse(string $pageid) + { + if (!empty($this->options)) { + parse_str($this->options, $datas); + $this->hydrate($datas); + } else { + $this->id = $pageid; + } + } + + + + // ______________________________________________ G E T ________________________________________________________ + + public function id(): string + { + return $this->id; + } + + public function setid($id): void + { + $this->id = $id; + } +} diff --git a/app/class/Model.php b/app/class/Model.php index 37d813eb..3ec6136c 100644 --- a/app/class/Model.php +++ b/app/class/Model.php @@ -63,8 +63,6 @@ abstract class Model 'version', ]; - public const HTML_ELEMENTS = ['header', 'nav', 'main', 'aside', 'footer']; - public const ID_REGEX = "%[^a-z0-9-_]%"; public const MAX_ID_LENGTH = 64; public const PASSWORD_MIN_LENGTH = 4; diff --git a/app/class/Modelpage.php b/app/class/Modelpage.php index 3a44b9a4..20e58cdd 100644 --- a/app/class/Modelpage.php +++ b/app/class/Modelpage.php @@ -391,7 +391,18 @@ public function renderpage(Page $page, AltoRouter $router): Page { $now = new DateTimeImmutable("now", timezone_open("Europe/Paris")); - $renderengine = new Servicerender($router, $this, Config::externallinkblank(), Config::internallinkblank()); + $params = [$router, $this, Config::externallinkblank(), Config::internallinkblank()]; + + switch ($page->version()) { + case Page::V1: + $renderengine = new Servicerenderv1(...$params); + break; + case Page::V2: + $renderengine = new Servicerenderv2(...$params); + break; + default: + throw new DomainException('Page version is out of range'); + } try { $html = $renderengine->render($page); @@ -760,7 +771,7 @@ public function parsepage($datas = []): Page return new Pagev1($datas); case Page::V2: - return new Pagev1($datas); + return new Pagev2($datas); } throw new RangeException('Version is specified but out of range'); } elseif (isset($metadatas['markdown'])) { diff --git a/app/class/Pagev1.php b/app/class/Pagev1.php index 4f4a7d32..ff3ca5b2 100644 --- a/app/class/Pagev1.php +++ b/app/class/Pagev1.php @@ -13,6 +13,7 @@ class Pagev1 extends Page protected $footer; public const TABS = ['main', 'css', 'header', 'nav', 'aside', 'footer','body', 'javascript']; + public const HTML_ELEMENTS = ['header', 'nav', 'main', 'aside', 'footer']; public function reset() { diff --git a/app/class/Servicerender.php b/app/class/Servicerender.php index 5a173d6e..0022fa06 100644 --- a/app/class/Servicerender.php +++ b/app/class/Servicerender.php @@ -15,7 +15,7 @@ use VStelmakh\UrlHighlight\UrlHighlight; use VStelmakh\UrlHighlight\Validator\Validator; -class Servicerender +abstract class Servicerender { /** @var AltoRouter */ protected ?AltoRouter $router; @@ -23,10 +23,7 @@ class Servicerender /** @var Modelpage */ protected Modelpage $pagemanager; - /** - * @var Page Actual page being rendered - * */ - protected $page; + protected Page $page; /** @var string[] */ protected $linkto = []; @@ -90,13 +87,7 @@ public function render(Page $page): string * * @todo render absolute media links */ - public function renderprimary(Page $page): string - { - $this->page = $page; - $element = new Element($page->id(), ['content' => $page->primary(), 'type' => 'main']); - $html = $this->elementparser($element); - return $this->bodyparser($html); - } + abstract public function renderprimary(Page $page): string; /** * Used to convert the markdown user manual to html document @@ -107,7 +98,7 @@ public function renderprimary(Page $page): string public function rendermanual(string $text): string { $text = $this->markdown($text); - $text = $this->headerid($text, 1, 5, 'main', 0); + $text = $this->headerid($text, 1, 5, 0); return $text; } @@ -117,7 +108,7 @@ public function rendermanual(string $text): string * * @return string html string */ - private function gethmtl() + protected function gethmtl() { $body = $this->bodyconstructor($this->readbody()); @@ -134,7 +125,7 @@ private function gethmtl() } - private function readbody() + protected function readbody() { if (!empty($this->page->templatebody())) { $templateid = $this->page->templatebody(); @@ -153,41 +144,22 @@ private function readbody() /** - * Analyse BODY, call the corresponding CONTENTs and render everything + * Analyse BODY, include basic inclusions * * @param string $body as the string BODY of the page * * @return string as the full rendered BODY of the page */ - private function bodyconstructor(string $body): string + protected function bodyconstructor(string $body): string { $body = $this->basicinclusions($body); - - // Elements that can be detected - $types = array_map("strtoupper", Model::HTML_ELEMENTS); - - // First level regex - $regex = implode("|", $types); - - $matches = $this->match($body, $regex); - - // First, analyse the synthax and call the corresponding methods - if (!empty($matches)) { - foreach ($matches as $match) { - $element = new Element($this->page->id(), $match); - $element->setcontent($this->getelementcontent($element->sources(), $element->type())); - $element->setcontent($this->elementparser($element)); - $body = str_replace($element->fullmatch(), $element->content(), $body); - } - } - return $body; } /** * Return HEAD html element of a page */ - private function gethead(): string + protected function gethead(): string { $id = $this->page->id(); $globalpath = Model::dirtopath(Model::GLOBAL_CSS_FILE); @@ -284,7 +256,7 @@ private function gethead(): string * @param Page $page Page being rendered * @return string HTML to insert into of page */ - private function recursivecss(Page $page): string + protected function recursivecss(Page $page): string { $head = ""; try { @@ -305,38 +277,10 @@ private function recursivecss(Page $page): string } - /** - * Foreach $sources (pages), this will get the corresponding $type element content - * - * @param string[] $sources Array of pages ID - * @param string $type Type of element - */ - private function getelementcontent(array $sources, string $type) - { - if (!in_array($type, Model::HTML_ELEMENTS)) { - throw new InvalidArgumentException(); - } - $content = ''; - $subseparator = "\n\n"; - foreach ($sources as $source) { - if ($source !== $this->page->id()) { - try { - $subcontent = $this->pagemanager->get($source)->$type(); - } catch (RuntimeException $e) { - $subcontent = $this->page->$type(); - } - } else { - $subcontent = $this->page->$type(); - } - $content .= $subseparator . $subcontent; - } - return $content . $subseparator; - } - /** * Perfom W's syntax basic inclusions */ - private function basicinclusions($text) + protected function basicinclusions($text) { $text = $this->date($text); $text = $this->thumbnail($text); @@ -348,38 +292,7 @@ private function basicinclusions($text) return $text; } - private function elementparser(Element $element) - { - $content = $element->content(); - $content = $this->basicinclusions($content); - if ($element->everylink() > 0) { - $content = $this->everylink($content, $element->everylink()); - } - if ($element->markdown()) { - $content = $this->markdown($content); - } - if ($element->headerid()) { - $content = $this->headerid( - $content, - $element->minheaderid(), - $element->maxheaderid(), - $element->type(), - $element->headeranchor() - ); - } - if ($element->urllinker()) { - $content = $this->autourl($content); - } - if ($element->tag()) { - $type = $element->type(); - $content = "\n<{$type}>\n{$content}\n\n"; - } - - return $content; - } - - - private function bodyparser(string $html) + protected function bodyparser(string $html) { $html = $this->automedialist($html); $html = $this->pageoptlist($html); @@ -404,7 +317,7 @@ private function bodyparser(string $html) /** * Replace `%TITLE%` code with page's title */ - private function title($text) + protected function title($text) { return str_replace('%TITLE%', $this->page->title(), $text); } @@ -413,7 +326,7 @@ private function title($text) /** * Replace `%DESCRIPTION%` code with page's description */ - private function description($text) + protected function description($text) { return str_replace('%DESCRIPTION%', $this->page->description(), $text); } @@ -423,7 +336,7 @@ private function description($text) * * @param string $text the page text as html */ - private function richlink(string $text): string + protected function richlink(string $text): string { $text = preg_replace('#\2#', "$3", $text); return $text; @@ -434,7 +347,7 @@ private function richlink(string $text): string * * This will also include `target=_blank` and `class=external` attributes. */ - private function autourl($text): string + protected function autourl($text): string { $options = ["class" => "external"]; if ($this->externallinkblank) { @@ -458,7 +371,7 @@ private function autourl($text): string * * Keep existing class and remove duplicates or useless spaces in class attribute */ - private function htmlparser(string $html): string + protected function htmlparser(string $html): string { $dom = new DOMDocument('1.0', 'UTF-8'); /** Force UTF-8 encoding for loadHTML by defining it in the content itself with an XML tag that need to be removed later */ @@ -535,7 +448,7 @@ private function htmlparser(string $html): string /** * Edit `src` attributes in media HTML tags */ - private function sourceparser(DOMNodeList $sourcables): void + protected function sourceparser(DOMNodeList $sourcables): void { foreach ($sourcables as $sourcable) { assert($sourcable instanceof DOMElement); @@ -565,7 +478,7 @@ private function sourceparser(DOMNodeList $sourcables): void /** * Replace wiki links [[page_id]] with HTML link */ - private function wikiurl(string $text): string + protected function wikiurl(string $text): string { $rend = $this; $text = preg_replace_callback( @@ -593,14 +506,17 @@ function ($matches) use ($rend) { * @param string $text Input html document to scan * @param int $min Maximum header deepness to look for. Min = 1 Max = 6 Default = 1 * @param int $max Maximum header deepness to look for. Min = 1 Max = 6 Default = 6 - * @param string $element Name of element being analysed + * @param string $element Name of element being analysed. Leave empty if using Markdown field * @param int $anchormode Mode of anchor link display. see Element HEADERANCHORMODES * * @return string text with id in header */ - private function headerid(string $text, int $min, int $max, string $element, int $anchormode): string + protected function headerid(string $text, int $min, int $max, int $anchormode, string $element = ''): string { + if (empty($element)) { + $element = md5($text); + } if ($min > 6 || $min < 1) { $min = 6; } @@ -637,7 +553,7 @@ function ($matches) use ($element, $anchormode) { return $text; } - private function markdown($text) + protected function markdown($text) { $fortin = new MarkdownExtra(); // id in headers @@ -657,7 +573,7 @@ private function markdown($text) * * @return array Ordered array containing an array of `fullmatch`, `type` and `options` */ - private function match(string $text, string $include): array + protected function match(string $text, string $include): array { preg_match_all('~\%(' . $include . ')(\?([a-zA-Z0-9:\[\]\&=\-_\/\%\+\*\;]*))?\%~', $text, $out); @@ -675,7 +591,7 @@ private function match(string $text, string $include): array * * @return string Output text */ - private function automedialist(string $text): string + protected function automedialist(string $text): string { $matches = $this->match($text, 'MEDIA'); @@ -695,7 +611,7 @@ private function automedialist(string $text): string * * @return string Output text */ - private function summary(string $text): string + protected function summary(string $text): string { $matches = $this->match($text, 'SUMMARY'); @@ -714,7 +630,7 @@ private function summary(string $text): string /** * Render pages list */ - private function pageoptlist(string $text): string + protected function pageoptlist(string $text): string { $matches = $this->match($text, 'LIST'); foreach ($matches as $match) { @@ -744,7 +660,7 @@ private function pageoptlist(string $text): string /** * Render page maps */ - private function pageoptmap(string $text): string + protected function pageoptmap(string $text): string { $matches = $this->match($text, 'MAP'); foreach ($matches as $match) { @@ -777,7 +693,7 @@ private function pageoptmap(string $text): string /** * Render Random links */ - private function randomopt(string $text): string + protected function randomopt(string $text): string { $matches = $this->match($text, 'RANDOM'); foreach ($matches as $match) { @@ -812,7 +728,7 @@ private function randomopt(string $text): string * * @return string Text with replaced valid %RSS% inclusions */ - private function rss(string $text): string + protected function rss(string $text): string { $this->rsslist = $this->rssmatch($text); foreach ($this->rsslist as $fullmatch => $bookmark) { @@ -829,7 +745,7 @@ private function rss(string $text): string * * @return Bookmark[] Associative array of bookmarks, using fullmatch as key */ - private function rssmatch(string $text): array + protected function rssmatch(string $text): array { $rsslist = []; $matches = $this->match($text, "RSS"); @@ -852,7 +768,7 @@ private function rssmatch(string $text): array - private function date(string $text): string + protected function date(string $text): string { $dateregex = implode('|', array_keys(Clock::TYPES)); $matches = $this->match($text, $dateregex); @@ -879,7 +795,7 @@ private function date(string $text): string * * @return string The rendered output */ - private function thumbnail(string $text): string + protected function thumbnail(string $text): string { $src = Model::thumbnailpath() . $this->page->thumbnail(); $alt = $this->page->title(); @@ -895,7 +811,7 @@ private function thumbnail(string $text): string * @param string $text input text * @return string output text with replaced elements */ - private function pageid(string $text): string + protected function pageid(string $text): string { return str_replace(['%PAGEID%', '%ID%'], $this->page->id(), $text); } @@ -905,7 +821,7 @@ private function pageid(string $text): string * @param string $text input text * @return string output text with replaced elements */ - private function url(string $text): string + protected function url(string $text): string { return str_replace('%URL%', Config::domain() . $this->upage($this->page->id()), $text); } @@ -915,7 +831,7 @@ private function url(string $text): string * @param string $text input text * @return string output text with replaced elements */ - private function path(string $text): string + protected function path(string $text): string { return str_replace('%PATH%', $this->upage($this->page->id()), $text); } @@ -923,7 +839,7 @@ private function path(string $text): string /** * Replace `%AUTHORS%` with a rendered list of authors */ - private function authors(string $text): string + protected function authors(string $text): string { $page = $this->page; return preg_replace_callback("~\%AUTHORS\%~", function () use ($page) { @@ -936,7 +852,7 @@ private function authors(string $text): string /** * Check if the page need post processing by looking for patterns */ - private function checkpostprocessaction(string $text): bool + protected function checkpostprocessaction(string $text): bool { $counterpaterns = Servicepostprocess::COUNTERS; $pattern = implode('|', $counterpaterns); @@ -950,7 +866,7 @@ private function checkpostprocessaction(string $text): bool * * @return string Conversion output */ - private function everylink(string $text, int $limit): string + protected function everylink(string $text, int $limit): string { $regex = '~([\w\-_éêèùïüîçà]{' . $limit . ',})(?![^<]*>|[^<>]*<\/)~'; $text = preg_replace_callback($regex, function ($matches) { @@ -966,7 +882,7 @@ private function everylink(string $text, int $limit): string * * @return string text ouput */ - private function authenticate(string $text): string + protected function authenticate(string $text): string { $id = $this->page->id(); $regex = '~\%CONNECT(\?dir=([a-zA-Z0-9-_]+))?\%~'; @@ -1013,7 +929,7 @@ public function user(User $user): string * @param User[] $users List of User * @return string List of user in HTML */ - private function userlist(array $users): string + protected function userlist(array $users): string { $html = ""; foreach ($users as $user) { diff --git a/app/class/Servicerenderv1.php b/app/class/Servicerenderv1.php new file mode 100644 index 00000000..e46247b7 --- /dev/null +++ b/app/class/Servicerenderv1.php @@ -0,0 +1,136 @@ +page = $page; + $html = $this->bodyconstructor('%MAIN%'); + return $this->bodyparser($html); + } + + /** + * Analyse BODY, call the corresponding CONTENTs and render everything + * + * @param string $body as the string BODY of the page + * + * @return string as the full rendered BODY of the page + */ + protected function bodyconstructor(string $body): string + { + $body = parent::bodyconstructor($body); + + // Elements that can be detected + $types = array_map("strtoupper", Pagev1::HTML_ELEMENTS); + + // First level regex + $regex = implode("|", $types); + + $matches = $this->match($body, $regex); + + // First, analyse the synthax and call the corresponding methods + if (!empty($matches)) { + foreach ($matches as $match) { + $element = new Elementv1($this->page->id(), $match['fullmatch'], $match['type'], $match['options']); + $element->setcontent($this->getelementcontent($element->sources(), $element->type())); + $element->setcontent($this->elementparser($element)); + $body = str_replace($element->fullmatch(), $element->content(), $body); + } + } + + return $body; + } + + protected function elementparser(Elementv1 $element) + { + $content = $element->content(); + $content = $this->basicinclusions($content); + if ($element->everylink() > 0) { + $content = $this->everylink($content, $element->everylink()); + } + if ($element->markdown()) { + $content = $this->markdown($content); + } + if ($element->headerid()) { + $content = $this->headerid( + $content, + $element->minheaderid(), + $element->maxheaderid(), + $element->headeranchor(), + $element->type() + ); + } + if ($element->urllinker()) { + $content = $this->autourl($content); + } + if ($element->tag()) { + $type = $element->type(); + $content = "\n<{$type}>\n{$content}\n\n"; + } + + return $content; + } + + + /** + * Foreach $sources (pages), this will get the corresponding $type element content + * If ID is not used or if Page is not version 1: fallback to current page Markdown field + * + * @param string[] $sources Array of pages ID + * @param string $type Type of element + */ + protected function getelementcontent(array $sources, string $type): string + { + if (!in_array($type, Pagev1::HTML_ELEMENTS)) { + throw new DomainException("$type is not a valid HTML element type"); + } + $content = ''; + $subseparator = "\n\n"; + foreach ($sources as $source) { + if ($source !== $this->page->id()) { + try { + $page = $this->pagemanager->get($source); + if ($page instanceof Pagev1) { + $subcontent = $page->$type(); + } else { + $subcontent = $this->page->$type(); + } + } catch (RuntimeException $e) { + // Page ID is not used + $subcontent = $this->page->$type(); + } + } else { + $subcontent = $this->page->$type(); + } + $content .= $subseparator . $subcontent; + } + return $content . $subseparator; + } +} diff --git a/app/class/Servicerenderv2.php b/app/class/Servicerenderv2.php new file mode 100644 index 00000000..447c3246 --- /dev/null +++ b/app/class/Servicerenderv2.php @@ -0,0 +1,116 @@ +page = $page; + $html = $this->bodyconstructor('%INCLUDE%'); + return $this->bodyparser($html); + } + + + /** + * Analyse BODY, call the corresponding CONTENTs and render everything + * + * @param string $body as the string BODY of the page + * + * @return string as the full rendered BODY of the page + */ + protected function bodyconstructor(string $body): string + { + $body = parent::bodyconstructor($body); + + $matches = $this->match($body, 'INCLUDE'); + + // First, analyse the synthax and call the corresponding methods + if (!empty($matches)) { + foreach ($matches as $match) { + $element = new Elementv2($this->page->id(), $match['fullmatch'], $match['options']); + $element->setcontent($this->getelementcontent($element->id())); + $element->setcontent($this->elementparser($element)); + $body = str_replace($element->fullmatch(), $element->content(), $body); + } + } + + return $body; + } + + protected function elementparser(Elementv2 $element) + { + $content = $element->content(); + $content = $this->basicinclusions($content); + if ($element->everylink() > 0) { + $content = $this->everylink($content, $element->everylink()); + } + if ($element->markdown()) { + $content = $this->markdown($content); + } + if ($element->headerid()) { + $content = $this->headerid( + $content, + $element->minheaderid(), + $element->maxheaderid(), + $element->headeranchor(), + ); + } + if ($element->urllinker()) { + $content = $this->autourl($content); + } + + return $content; + } + + + /** + * Get element content by looking for source page ID. + * If ID is not used: return empty string + * If source page is V1, it will use the MAIN content. + * + * @param string $source Source Page ID + * + * @return string Source Page primary content or empty string + * + * @todo Log errors somewhere + */ + protected function getelementcontent(string $source): string + { + if ($source === $this->page->id()) { + return $this->page->markdown(); + } else { + try { + $page = $this->pagemanager->get($source); + return $page->primary(); + } catch (RuntimeException $e) { + // page ID is not used + return ''; + } + } + } +} diff --git a/app/class/Servicerss.php b/app/class/Servicerss.php index 54398166..28385f2f 100644 --- a/app/class/Servicerss.php +++ b/app/class/Servicerss.php @@ -4,9 +4,11 @@ use AltoRouter; use DateTime; +use DomainException; use DOMDocument; use DOMException; use DOMText; +use Exception; use LogicException; use RuntimeException; use Wcms\Exception\Database\Notfoundexception; @@ -15,7 +17,6 @@ class Servicerss { protected AltoRouter $router; - protected Servicerender $render; protected Modelpage $pagemanager; protected Modelbookmark $bookmarkmanager; @@ -24,7 +25,6 @@ public function __construct(AltoRouter $router) $this->router = $router; $this->pagemanager = new Modelpage(Config::pagetable()); $this->bookmarkmanager = new Modelbookmark(); - $this->render = new Servicerender($this->router, $this->pagemanager); } /** @@ -195,7 +195,12 @@ protected function render(array $pagelist, Bookmark $bookmark): string */ protected function href(Page $page): string { - return Config::domain() . $this->render->upage($page->id()); + try { + $path = $this->router->generate('pageread', ['page' => $page->id()]); + return Config::domain() . $path; + } catch (Exception $e) { + throw new LogicException($e->getMessage(), $e->getCode(), $e); + } } /** @@ -206,7 +211,16 @@ protected function href(Page $page): string */ protected function primaryhtml(Page $page): string { - $render = new Servicerender($this->router, $this->pagemanager); + switch ($page->version()) { + case Page::V1: + $render = new Servicerenderv1($this->router, $this->pagemanager); + break; + case Page::V2: + $render = new Servicerenderv2($this->router, $this->pagemanager); + break; + default: + throw new DomainException('Page version is out of range'); + } return $render->renderprimary($page); } diff --git a/app/class/Summary.php b/app/class/Summary.php index 2c890640..74c69bac 100644 --- a/app/class/Summary.php +++ b/app/class/Summary.php @@ -142,7 +142,7 @@ public function setsum(array $sum) public function setelement(string $element) { - if (in_array($element, Model::HTML_ELEMENTS)) { + if (in_array($element, Pagev1::HTML_ELEMENTS)) { $this->element = $element; } } diff --git a/tests/ServicerenderTest.php b/tests/ServicerenderTest.php index 763b983f..330df769 100644 --- a/tests/ServicerenderTest.php +++ b/tests/ServicerenderTest.php @@ -10,6 +10,7 @@ use Wcms\Modelpage; use Wcms\Servicerender; use Wcms\Pagev1; +use Wcms\Servicerenderv1; class ServicerenderTest extends TestCase { @@ -31,7 +32,7 @@ public function setUp(): void $router = new AltoRouter([ ['GET', '/[cid:page]', 'Controllerpage#read', 'pageread'], ]); - $this->renderengine = new Servicerender($router, new Modelpage(Config::pagetable()), true, false); + $this->renderengine = new Servicerenderv1($router, new Modelpage(Config::pagetable()), true, false); } public function tearDown(): void From 4cc1238596604639017b0033611ff454add5443e Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Sun, 23 Jul 2023 11:21:53 +0200 Subject: [PATCH 06/14] admin view update with page version - add page version selector button - Config now got BODY default V1 and V2 --- app/class/Config.php | 49 ++++++++++++++++++++++++++++++------ app/class/Page.php | 5 +++- app/view/templates/admin.php | 16 ++++++++++-- 3 files changed, 59 insertions(+), 11 deletions(-) diff --git a/app/class/Config.php b/app/class/Config.php index dab7d948..ab348e87 100644 --- a/app/class/Config.php +++ b/app/class/Config.php @@ -19,7 +19,8 @@ abstract class Config protected static $privatepass = false; protected static $notpublishedpass = false; protected static $alertcss = false; - protected static $defaultbody = "%HEADER%\n\n%NAV%\n\n%ASIDE%\n\n%MAIN%\n\n%FOOTER%"; + protected static $defaultv1body = "%HEADER%\n\n%NAV%\n\n%ASIDE%\n\n%MAIN%\n\n%FOOTER%"; + protected static $defaultv2body = "%INCLUDE%"; protected static $defaultfavicon = ''; protected static $defaultthumbnail = ''; protected static string $suffix = ""; @@ -51,9 +52,7 @@ abstract class Config protected static $lang = "en"; /** Page version during creation */ - protected static int $pageversion = Page::V1; - - + protected static int $pageversion = Page::V2; public const LANG_MIN = 2; public const LANG_MAX = 16; @@ -230,9 +229,23 @@ public static function alertcss() return self::$alertcss; } - public static function defaultbody() + /** + * @return string Default BODY corrsponding to current Config's page version + */ + public static function defaultbody(): string + { + $fn = 'defaultv' . self::$pageversion . 'body'; + return self::$$fn; + } + + public static function defaultv1body(): string + { + return self::$defaultv1body; + } + + public static function defaultv2body(): string { - return self::$defaultbody; + return self::$defaultv2body; } public static function defaultfavicon() @@ -422,11 +435,31 @@ public static function setalertcss($alertcss) self::$alertcss = boolval($alertcss); } + /** + * Used to convert old Config version. Save + * `defaultbody` param as `defaultv1body`. + */ public static function setdefaultbody($defaultbody) { if (is_string($defaultbody)) { $defaultbody = crlf2lf($defaultbody); - self::$defaultbody = $defaultbody; + self::$defaultv1body = $defaultbody; + } + } + + public static function setdefaultv1body($defaultbody) + { + if (is_string($defaultbody)) { + $defaultbody = crlf2lf($defaultbody); + self::$defaultv1body = $defaultbody; + } + } + + public static function setdefaultv2body($defaultbody) + { + if (is_string($defaultbody)) { + $defaultbody = crlf2lf($defaultbody); + self::$defaultv2body = $defaultbody; } } @@ -551,7 +584,7 @@ public static function setdisablejavascript($disablejavascript) public static function setpageversion($pageversion): void { - if (in_array($pageversion, Page::VERSIONS)) { + if (key_exists($pageversion, Page::VERSIONS)) { self::$pageversion = $pageversion; } } diff --git a/app/class/Page.php b/app/class/Page.php index 7601b0e2..38699575 100644 --- a/app/class/Page.php +++ b/app/class/Page.php @@ -56,7 +56,10 @@ abstract class Page extends Item public const V1 = 1; public const V2 = 2; - public const VERSIONS = [self::V1, self::V2]; + public const VERSIONS = [ + self::V1 => "version 1", + self::V2 => "version 2" + ]; public const PUBLIC = 0; public const PRIVATE = 1; diff --git a/app/view/templates/admin.php b/app/view/templates/admin.php index 33d99d30..671bfb9f 100644 --- a/app/view/templates/admin.php +++ b/app/view/templates/admin.php @@ -74,6 +74,8 @@

Page creation

What really happend when you create a new page

+ +

Privacy of new pages

+

Page version

+ +

Choose W page version you want to use when a new page is created.

+ + + +

Default BODY

- - + + + From 20f6be62b5012ea24d4e6d328c09c81c1f398477 Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Sun, 23 Jul 2023 11:47:19 +0200 Subject: [PATCH 07/14] fix version filtering --- app/class/Opt.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/class/Opt.php b/app/class/Opt.php index 0cb13a32..58017d8f 100644 --- a/app/class/Opt.php +++ b/app/class/Opt.php @@ -558,7 +558,7 @@ public function setgeo($geo) public function setversion($version): void { $version = intval($version); - if ($version === 0 || in_array($version, Page::VERSIONS)) { + if ($version === 0 || key_exists($version, Page::VERSIONS)) { $this->version = $version; } } From 21581db9903323d92325744bec81d341aa9770d7 Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Sun, 23 Jul 2023 12:01:05 +0200 Subject: [PATCH 08/14] fix element rendering options setting --- app/class/Elementv2.php | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/app/class/Elementv2.php b/app/class/Elementv2.php index d606bd5c..c1d9fc16 100644 --- a/app/class/Elementv2.php +++ b/app/class/Elementv2.php @@ -10,18 +10,15 @@ public function __construct($pageid, string $fullmatch, string $options) { $this->urllinker = Config::urllinker(); $this->fullmatch = $fullmatch; + $this->id = $pageid; $this->options = $options; $this->analyse($pageid); } protected function analyse(string $pageid) { - if (!empty($this->options)) { - parse_str($this->options, $datas); - $this->hydrate($datas); - } else { - $this->id = $pageid; - } + parse_str($this->options, $datas); + $this->hydrate($datas); } From c4446b78b35c8381116d333a2d8364f96247eb4c Mon Sep 17 00:00:00 2001 From: vincent-peugnet Date: Mon, 24 Jul 2023 12:58:30 +0200 Subject: [PATCH 09/14] make JS work for pagesV2 in edit view --- app/view/templates/edit.php | 1 + src/edit.js | 158 +++++++++++++++++++++++------------- 2 files changed, 102 insertions(+), 57 deletions(-) diff --git a/app/view/templates/edit.php b/app/view/templates/edit.php index 3ee97b8a..2a991c41 100644 --- a/app/view/templates/edit.php +++ b/app/view/templates/edit.php @@ -29,6 +29,7 @@ + +
<a href="https://club1.fr" class="total  shell">dans un codeblock</a>
+
+ + diff --git a/tests/data/Servicerenderv2Test/external-links-test-v2.json b/tests/data/Servicerenderv2Test/external-links-test-v2.json new file mode 100644 index 00000000..cb114679 --- /dev/null +++ b/tests/data/Servicerenderv2Test/external-links-test-v2.json @@ -0,0 +1,49 @@ +{ + "id": "external-links-test-v2", + "title": "external-links-test-v2", + "description": "", + "lang": "", + "tag": [], + "latitude": null, + "longitude": null, + "date": "2023-08-06T19:33:00+0200", + "datecreation": "2023-08-06T19:33:34+0200", + "datemodif": "2023-08-06T19:33:37+0200", + "daterender": "2023-08-06T19:33:38+0200", + "css": "", + "javascript": "", + "body": "%INCLUDE%", + "externalcss": [], + "customhead": "", + "secure": 0, + "interface": "content", + "linkto": [], + "templatebody": "", + "templatecss": "", + "templatejavascript": "", + "templateoptions": [ + "thumbnail", + "recursivecss", + "externalcss", + "favicon", + "externaljavascript" + ], + "favicon": "", + "thumbnail": "", + "authors": [ + "vincent" + ], + "invites": [], + "readers": [], + "displaycount": 1, + "visitcount": 0, + "editcount": 1, + "editby": [], + "sleep": 0, + "redirection": "", + "refresh": 0, + "password": null, + "postprocessaction": false, + "version": 2, + "content": "\r\n\r\n[link to my external life using Michel Fortin's Markdown extra](https:\/\/club1.fr) {.testclass#testid}\r\n\r\nhttps:\/\/club1.fr\r\n\r\ntest de lien vers CLUB1<\/a>\r\n\r\ntest de lien vers CLUB1<\/a>\r\n\r\n