Compare commits

...

7 Commits
v1.9 ... master

Author SHA1 Message Date
fe90f8da3d
oups 2023-10-24 11:44:09 +02:00
35b0d4a0bc
code review 2023-10-24 11:43:11 +02:00
de46d49d77
code review 2023-10-24 11:38:06 +02:00
53f72a8748
upgrade to Dotclear 2.28 2023-10-15 12:07:19 +02:00
39df98dcd8
Use new README style 2023-08-21 20:50:22 +02:00
0e389ad6b4
fix ZIP URL 2023-08-07 23:09:26 +02:00
fa2f872ef5
use static badge 2023-08-07 00:51:49 +02:00
17 changed files with 406 additions and 387 deletions

View File

@ -1,3 +1,16 @@
alias 1.11 - 2023.10.23
===========================================================
* Require Dotclear 2.28
* Require PHP 8.1
* Use class for alias row
* Code review
alias 1.10 - 2023.10.15
===========================================================
* require Dotclear 2.28
* require PHP 8.1
* Upgrade to Dotclear 2.28
alias 1.9 - 2023.08.06 alias 1.9 - 2023.08.06
=========================================================== ===========================================================
* require Dotclear 2.27 * require Dotclear 2.27

View File

@ -1,26 +1,22 @@
# README # README
[![Release](https://img.shields.io/github/v/release/JcDenis/alias)](https://github.com/JcDenis/alias/releases) [![Release](https://img.shields.io/badge/release-1.11-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/alias/releases)
[![Date](https://img.shields.io/github/release-date/JcDenis/alias)](https://github.com/JcDenis/alias/releases) ![Date](https://img.shields.io/badge/date-2023.10.23-c44d58.svg)
[![Issues](https://img.shields.io/github/issues/JcDenis/alias)](https://github.com/JcDenis/alias/issues) [![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.27-blue.svg)](https://fr.dotclear.org/download) [![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/alias)
[![Dotaddict](https://img.shields.io/badge/dotaddict-official-green.svg)](https://plugins.dotaddict.org/dc2/details/alias) [![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/JcDenis/alias/src/branch/master/LICENSE)
[![License](https://img.shields.io/github/license/JcDenis/alias)](https://github.com/JcDenis/alias/blob/master/LICENSE)
## WHAT IS ALIAS ? ## ABOUT
_alias_ is a plugin for the open-source _alias_ is a plugin for the open-source web publishing software called [Dotclear](https://www.dotclear.org).
web publishing software called Dotclear.
This plugin creates public aliases of your blog's URLs. > Create aliases of your blog's URLs.
## REQUIREMENTS ## REQUIREMENTS
_alias_ requires: * Dotclear 2.28
* PHP 8.1+
* admin permissions for management * Dotclear admin permission for management
* Dotclear 2.27
* PHP 7.4+
## USAGE ## USAGE
@ -31,27 +27,26 @@ You can manage your aliases from menu ''Alias'' on admin dashboard sidebar.
## RULES ## RULES
- Only blog URLs can be redirected. * Only blog URLs can be redirected.
- It can redirect a specific URL "plop" to another one "post/2023/04/24/my-post". * It can redirect a specific URL "plop" to another one "post/2023/04/24/my-post".
- It can redirect all URLs that content "plop" using alias "/plop/" * It can redirect all URLs that content "plop" using alias "/plop/" by replacing it by destination "post" into requesting URL. (Even if it's not at the begining of the URL!)
by replacing it by destination "post" into requesting URL. (Even if it's not at the begining of the URL!) * It can not redirect an alias to another alias.
- It can not redirect an alias to another alias. * It has priority on all ohters URLs handlers, so if you create an alias of an existing page, the destination from plugin _alias_ will be used.
- It has priority on all ohters URLs handlers, so if you create an alias of an existing page,
the destination from plugin _alias_ will be used.
Keep in mind, plugin _alias_ loads all registered aliases to test them on each page load, Keep in mind, plugin _alias_ loads all registered aliases to test them on each page load,
so more there are aliases, more page load is slow. so more there are aliases, more page load is slow.
## LINKS ## LINKS
* License : [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html) * [License](https://git.dotclear.watch/JcDenis/alias/src/branch/master/LICENSE)
* Source & contribution : [Gitea Page](https://git.dotclear.watch/JcDenis/alias) or [GitHub Page](https://github.com/JcDenis/alias) * [Packages & details](https://git.dotclear.watch/JcDenis/alias/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/alias))
* Packages & details: [Gitea Page](https://git.dotclear.watch/JcDenis/alias/releases) or [Dotaddict Page](https://plugins.dotaddict.org/dc2/details/alias) * [Sources & contributions](https://git.dotclear.watch/JcDenis/alias) (or on [GitHub](https://github.com/JcDenis/alias))
* [Issues & security](https://git.dotclear.watch/JcDenis/alias/issues) (or on [GitHub](https://github.com/JcDenis/alias/issues))
## CONTRIBUTORS ## CONTRIBUTORS
* Olivier Meunier * Olivier Meunier (author)
* Franck-paul * Franck-paul
* Jean-Christian Denis * Jean-Christian Denis (latest)
You are welcome to contribute to this code. You are welcome to contribute to this code.

View File

@ -1,33 +1,31 @@
<?php <?php
/** /**
* @brief alias, a plugin for Dotclear 2 * @file
* @brief The plugin alias definition
* @ingroup alias
* *
* @package Dotclear * @defgroup alias Plugin alias.
* @subpackage Plugin
* *
* @author Olivier Meunier and contributors * Create aliases of your blog's URLs.
* *
* @copyright Jean-Christian Denis * @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return null;
}
$this->registerModule( $this->registerModule(
'alias', 'alias',
"Create aliases of your blog's URLs", "Create aliases of your blog's URLs",
'Olivier Meunier and contributors', 'Olivier Meunier and contributors',
'1.9', '1.11',
[ [
'requires' => [['core', '2.27']], 'requires' => [['core', '2.28']],
'permissions' => dcCore::app()->auth->makePermissions([ 'permissions' => 'My',
dcCore::app()->auth::PERMISSION_ADMIN,
]),
'type' => 'plugin', 'type' => 'plugin',
'priority' => 2, 'priority' => 2,
'support' => 'https://git.dotclear.watch/JcDenis/alias/issues', 'support' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/issues',
'details' => 'https://git.dotclear.watch/JcDenis/alias/src/branch/master/README.md', 'details' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/src/branch/master/README.md',
'repository' => 'https://git.dotclear.watch/JcDenis/alias/raw/branch/master/dcstore.xml', 'repository' => 'https://git.dotclear.watch/JcDenis/' . basename(__DIR__) . '/raw/branch/master/dcstore.xml',
] ]
); );

View File

@ -1,20 +0,0 @@
<?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
class initAlias
{
public const ALIAS_TABLE_NAME = 'alias';
}

View File

@ -2,11 +2,11 @@
<modules xmlns:da="http://dotaddict.org/da/"> <modules xmlns:da="http://dotaddict.org/da/">
<module id="alias"> <module id="alias">
<name>alias</name> <name>alias</name>
<version>1.9</version> <version>1.11</version>
<author>Olivier Meunier and contributors</author> <author>Olivier Meunier and contributors</author>
<desc>Create aliases of your blog's URLs</desc> <desc>Create aliases of your blog's URLs</desc>
<file>https://gitea.dotclear.watch/JcDenis/alias/releases/download/v1.9/plugin-alias.zip</file> <file>https://git.dotclear.watch/JcDenis/alias/releases/download/v1.11/plugin-alias.zip</file>
<da:dcmin>2.27</da:dcmin> <da:dcmin>2.28</da:dcmin>
<da:details>https://git.dotclear.watch/JcDenis/alias/src/branch/master/README.md</da:details> <da:details>https://git.dotclear.watch/JcDenis/alias/src/branch/master/README.md</da:details>
<da:support>https://git.dotclear.watch/JcDenis/alias/issues</da:support> <da:support>https://git.dotclear.watch/JcDenis/alias/issues</da:support>
</module> </module>

View File

@ -1,17 +1,11 @@
<?php <?php
/** /**
* @brief alias, a plugin for Dotclear 2 * @file
* @brief The plugin alias resources
* @ingroup alias
* *
* @package Dotclear * @author Olivier Meunier (author)
* @subpackage Plugin * @author Jean-Christian Denis (latest)
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { \Dotclear\App::backend()->resources()->set('help', 'alias', __DIR__ . '/help/help.html');
return;
}
dcCore::app()->resources['help']['alias'] = __DIR__ . '/help/help.html';

View File

@ -1,17 +1,11 @@
<?php <?php
/** /**
* @brief alias, a plugin for Dotclear 2 * @file
* @brief The plugin alias resources
* @ingroup alias
* *
* @package Dotclear * @author Olivier Meunier (author)
* @subpackage Plugin * @author Jean-Christian Denis (latest)
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { \Dotclear\App::backend()->resources()->set('help', 'alias', __DIR__ . '/help/help.html');
return;
}
dcCore::app()->resources['help']['alias'] = __DIR__ . '/help/help.html';

View File

@ -1,20 +1,10 @@
<?php <?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use dcCore; use Dotclear\App;
use Dotclear\Database\Statement\{ use Dotclear\Database\Statement\{
DeleteStatement, DeleteStatement,
SelectStatement SelectStatement
@ -22,17 +12,33 @@ use Dotclear\Database\Statement\{
use Exception; use Exception;
/** /**
* plugin Alias main class * @brief alias main class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class Alias class Alias
{ {
/** @var array $aliases Stak of aliases */ /**
* Alias table name.
*
* @var string ALIAS_TABLE_NAME
*/
public const ALIAS_TABLE_NAME = 'alias';
/**
* Stack of aliases.
*
* @var array<int, AliasRow> $aliases
*/
protected array $aliases = []; protected array $aliases = [];
/** /**
* Get aliases. * Get aliases.
* *
* @return array Stack of aliases * @return array<int, AliasRow> Stack of aliases
*/ */
public function getAliases(): array public function getAliases(): array
{ {
@ -40,24 +46,23 @@ class Alias
return $this->aliases; return $this->aliases;
} }
// nullsafe
if (is_null(dcCore::app()->blog)) {
return [];
}
$sql = new SelectStatement(); $sql = new SelectStatement();
$rs = $sql->from(dcCore::app()->prefix . My::ALIAS_TABLE_NAME) $rs = $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME)
->columns([ ->columns([
'alias_url', 'alias_url',
'alias_destination', 'alias_destination',
'alias_position', 'alias_position',
'alias_redirect', 'alias_redirect',
]) ])
->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog->id)) ->where('blog_id = ' . $sql->quote(App::blog()->id()))
->order('alias_position ASC') ->order('alias_position ASC')
->select(); ->select();
$this->aliases = is_null($rs) ? [] : $rs->rows(); if (!is_null($rs)) {
while ($rs->fetch()) {
$this->aliases[] = AliasRow::newFromRecord($rs);
}
}
return $this->aliases; return $this->aliases;
} }
@ -65,30 +70,30 @@ class Alias
/** /**
* Update aliases stack. * Update aliases stack.
* *
* @param array $aliases The alias stack * @param array<int, AliasRow> $aliases The alias stack
*/ */
public function updateAliases(array $aliases): void public function updateAliases(array $aliases): void
{ {
usort($aliases, fn ($a, $b) => (int) $a['alias_position'] <=> (int) $b['alias_position']); foreach ($aliases as $row) {
foreach ($aliases as $v) { if (!is_a($row, AliasRow::class)) {
if (!isset($v['alias_url']) || !isset($v['alias_destination'])) {
throw new Exception(__('Invalid aliases definitions')); throw new Exception(__('Invalid aliases definitions'));
} }
} }
usort($aliases, fn ($a, $b) => $a->position <=> $b->position);
dcCore::app()->con->begin(); App::con()->begin();
try { try {
$this->deleteAliases(); $this->deleteAliases();
foreach ($aliases as $k => $v) { foreach ($aliases as $k => $alias) {
if (!empty($v['alias_url']) && !empty($v['alias_destination'])) { if (!empty($alias->url) && !empty($alias->destination)) {
$this->createAlias($v['alias_url'], $v['alias_destination'], $k + 1, !empty($v['alias_redirect'])); $this->createAlias(new AliasRow($alias->url, $alias->destination, $k + 1, $alias->redirect));
} }
} }
dcCore::app()->con->commit(); App::con()->commit();
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->con->rollback(); App::con()->rollback();
throw $e; throw $e;
} }
@ -97,20 +102,16 @@ class Alias
/** /**
* Create an alias. * Create an alias.
* *
* @param string $url The URL * @param AliasRow $alias The new Alias descriptor
* @param string $destination The destination
* @param int $position The position
* @param bool $redirect Do redirection
*/ */
public function createAlias(string $url, string $destination, int $position, bool $redirect): void public function createAlias(AliasRow $alias): void
{ {
// nullsafe if (!App::blog()->isDefined()) {
if (is_null(dcCore::app()->blog)) {
return; return;
} }
$url = self::removeBlogUrl($url); $url = self::removeBlogUrl($alias->url);
$destination = self::removeBlogUrl($destination); $destination = self::removeBlogUrl($alias->destination);
if (empty($url)) { if (empty($url)) {
throw new Exception(__('Alias URL is empty.')); throw new Exception(__('Alias URL is empty.'));
@ -119,12 +120,12 @@ class Alias
throw new Exception(__('Alias destination is empty.')); throw new Exception(__('Alias destination is empty.'));
} }
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . My::ALIAS_TABLE_NAME); $cur = App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME);
$cur->setField('blog_id', (string) dcCore::app()->blog->id); $cur->setField('blog_id', App::blog()->id());
$cur->setField('alias_url', (string) $url); $cur->setField('alias_url', $url);
$cur->setField('alias_destination', (string) $destination); $cur->setField('alias_destination', $destination);
$cur->setField('alias_position', abs((int) $position)); $cur->setField('alias_position', $alias->position);
$cur->setField('alias_redirect', (int) $redirect); $cur->setField('alias_redirect', (int) $alias->redirect);
$cur->insert(); $cur->insert();
} }
@ -135,14 +136,9 @@ class Alias
*/ */
public function deleteAlias(string $url): void public function deleteAlias(string $url): void
{ {
// nullsafe
if (is_null(dcCore::app()->blog)) {
return;
}
$sql = new DeleteStatement(); $sql = new DeleteStatement();
$sql->from(dcCore::app()->prefix . My::ALIAS_TABLE_NAME) $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME)
->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog->id)) ->where('blog_id = ' . $sql->quote(App::blog()->id()))
->and('alias_url = ' . $sql->quote($url)) ->and('alias_url = ' . $sql->quote($url))
->delete(); ->delete();
} }
@ -152,14 +148,9 @@ class Alias
*/ */
public function deleteAliases(): void public function deleteAliases(): void
{ {
// nullsafe
if (is_null(dcCore::app()->blog)) {
return;
}
$sql = new DeleteStatement(); $sql = new DeleteStatement();
$sql->from(dcCore::app()->prefix . My::ALIAS_TABLE_NAME) $sql->from(App::con()->prefix() . Alias::ALIAS_TABLE_NAME)
->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog->id)) ->where('blog_id = ' . $sql->quote(App::blog()->id()))
->delete(); ->delete();
} }
@ -172,6 +163,6 @@ class Alias
*/ */
public static function removeBlogUrl(string $url): string public static function removeBlogUrl(string $url): string
{ {
return is_null(dcCore::app()->blog) ? trim($url) : str_replace(dcCore::app()->blog->url, '', trim($url)); return str_replace(App::blog()->url(), '', trim($url));
} }
} }

41
src/AliasRow.php Normal file
View File

@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\alias;
use Dotclear\Database\MetaRecord;
/**
* @brief alias decriptor class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class AliasRow
{
public readonly string $url;
public readonly string $destination;
public readonly int $position;
public readonly bool $redirect;
public function __construct(?string $url, ?string $destination, null|string|int $position, null|int|string|bool $redirect)
{
$this->url = (string) $url;
$this->destination = (string) $destination;
$this->position = (int) $position;
$this->redirect = !empty($redirect);
}
public static function newFromRecord(MetaRecord $rs): AliasRow
{
return new self(
(string) $rs->field('alias_url'),
(string) $rs->field('alias_destination'),
(int) $rs->field('alias_position'),
!empty($rs->field('alias_redirect'))
);
}
}

View File

@ -1,27 +1,20 @@
<?php <?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use dcCore; use Dotclear\App;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Plugin\importExport\{
FlatBackupItem,
FlatExport,
FlatImportV2
};
/**
* @brief alias backend class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Backend extends Process class Backend extends Process
{ {
public static function init(): bool public static function init(): bool
@ -37,47 +30,11 @@ class Backend extends Process
My::addBackendMenuItem(); My::addBackendMenuItem();
dcCore::app()->addBehaviors([ App::behavior()->addBehaviors([
'exportFullV2' => function (FlatExport $exp): void { 'exportFullV2' => PluginImportExportBehaviors::exportFullV2(...),
$exp->exportTable(My::ALIAS_TABLE_NAME); 'importInitV2' => PluginImportExportBehaviors::importInitV2(...),
}, 'importFullV2' => PluginImportExportBehaviors::importFullV2(...),
'exportSingleV2' => function (FlatExport $exp, ?string $blog_id): void { 'importSingleV2' => PluginImportExportBehaviors::importSingleV2(...),
$exp->export(
'alias',
'SELECT alias_url, alias_destination, alias_position ' .
'FROM ' . dcCore::app()->prefix . My::ALIAS_TABLE_NAME . ' A ' .
"WHERE A.blog_id = '" . $blog_id . "'"
);
},
'importInitV2' => function (FlatImportV2 $bk): void {
$bk->cur_alias = dcCore::app()->con->openCursor(dcCore::app()->prefix . My::ALIAS_TABLE_NAME);
$bk->alias = new Alias();
$bk->aliases = $bk->alias->getAliases();
},
'importFullV2' => function (/*bool|FlatBackupItem */$line, FlatImportV2 $bk): void {
if ($line->__name == My::ALIAS_TABLE_NAME) {
$bk->cur_alias->clean();
$bk->cur_alias->setField('blog_id', (string) $line->blog_id);
$bk->cur_alias->setField('alias_url', (string) $line->alias_url);
$bk->cur_alias->setField('alias_destination', (string) $line->alias_destination);
$bk->cur_alias->setField('alias_position', (int) $line->alias_position);
$bk->cur_alias->insert();
}
},
'importSingleV2' => function (/*bool|FlatBackupItem */$line, FlatImportV2 $bk): void {
if ($line->__name == My::ALIAS_TABLE_NAME) {
$found = false;
foreach ($bk->aliases as $v) {
if ($v['alias_url'] == $line->alias_url) {
$found = true;
}
}
if ($found) {
$bk->alias->deleteAlias($line->alias_url);
}
$bk->alias->createAlias($line->alias_url, $line->alias_destination, $line->alias_position);
}
},
]); ]);
return true; return true;

82
src/Frontend.php Normal file
View File

@ -0,0 +1,82 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\alias;
use Dotclear\App;
use Dotclear\Core\Frontend\Url;
use Dotclear\Core\Process;
use Dotclear\Helper\Network\Http;
/**
* @brief alias frontend class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Frontend extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::FRONTEND));
}
public static function process(): bool
{
if (!self::status()) {
return false;
}
App::behavior()->addBehavior('urlHandlerGetArgsDocument', function (Url $handler): void {
$found = $redir = false;
$type = '';
$part = $args = $_SERVER['URL_REQUEST_PART'];
// load all Aliases
foreach ((new Alias())->getAliases() as $alias) {
// multi alias using "/url/" to "destination"
if (@preg_match('#^/.*/$#', $alias->url) && @preg_match($alias->url, $args)) {
$part = preg_replace($alias->url, $alias->destination, $args);
$found = true;
$redir = !empty($alias->redirect);
break;
// single alias using "url" to "destination"
} elseif ($alias->url == $args) {
$part = $alias->destination;
$found = true;
$redir = !empty($alias->redirect);
break;
}
}
// no URLs found
if (!$found) {
return;
}
// Use visible redirection
if ($redir) {
Http::redirect(App::blog()->url() . $part);
}
// regain URL type
$_SERVER['URL_REQUEST_PART'] = $part;
$handler->getArgs($part, $type, $args);
// call real handler
if (!$type) {
$handler->callDefaultHandler($args);
} else {
$handler->callHandler($type, $args);
}
exit;
});
return true;
}
}

View File

@ -1,24 +1,22 @@
<?php <?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use dcCore; use Dotclear\App;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Database\Structure; use Dotclear\Database\Structure;
use Exception; use Exception;
/**
* @brief alias install class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Install extends Process class Install extends Process
{ {
public static function init(): bool public static function init(): bool
@ -33,8 +31,8 @@ class Install extends Process
} }
try { try {
$s = new Structure(dcCore::app()->con, dcCore::app()->prefix); $s = new Structure(App::con(), App::con()->prefix());
$s->__get(My::ALIAS_TABLE_NAME) $s->__get(Alias::ALIAS_TABLE_NAME)
->field('blog_id', 'varchar', 32, false) ->field('blog_id', 'varchar', 32, false)
->field('alias_url', 'varchar', 255, false) ->field('alias_url', 'varchar', 255, false)
->field('alias_destination', 'varchar', 255, false) ->field('alias_destination', 'varchar', 255, false)
@ -49,11 +47,11 @@ class Install extends Process
->reference('fk_alias_blog', 'blog_id', 'blog', 'blog_id', 'cascade', 'cascade') ->reference('fk_alias_blog', 'blog_id', 'blog', 'blog_id', 'cascade', 'cascade')
; ;
(new Structure(dcCore::app()->con, dcCore::app()->prefix))->synchronize($s); (new Structure(App::con(), App::con()->prefix()))->synchronize($s);
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); App::error()->add($e->getMessage());
return false; return false;
} }

View File

@ -1,20 +1,10 @@
<?php <?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use dcCore; use Dotclear\App;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Core\Backend\{ use Dotclear\Core\Backend\{
Notices, Notices,
@ -37,7 +27,12 @@ use Dotclear\Helper\Html\Html;
use Exception; use Exception;
/** /**
* Manage contributions list * @brief alias manage class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class Manage extends Process class Manage extends Process
{ {
@ -56,28 +51,37 @@ class Manage extends Process
return true; return true;
} }
$alias = new Alias(); $utils = new Alias();
$aliases = $alias->getAliases(); $aliases = $utils->getAliases();
# Update aliases # Update aliases
if (isset($_POST['a']) && is_array($_POST['a'])) { if (isset($_POST['a']) && is_array($_POST['a'])) {
try { try {
$alias->updateAliases($_POST['a']); $stack = [];
foreach ($_POST['a'] as $alias) {
$stack[] = new AliasRow(
$alias['alias_url'] ?? '',
$alias['alias_destination'] ?? '',
(int) ($alias['alias_position'] ?? 0),
!empty($alias['alias_redirect']),
);
}
$utils->updateAliases($stack);
Notices::addSuccessNotice(__('Aliases successfully updated.')); Notices::addSuccessNotice(__('Aliases successfully updated.'));
My::redirect(); My::redirect();
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); App::error()->add($e->getMessage());
} }
} }
# New alias # New alias
if (isset($_POST['alias_url'])) { if (isset($_POST['alias_url'])) {
try { try {
$alias->createAlias($_POST['alias_url'], $_POST['alias_destination'], count($aliases) + 1, !empty($_POST['alias_redirect'])); $utils->createAlias(new AliasRow($_POST['alias_url'], $_POST['alias_destination'], count($aliases) + 1, !empty($_POST['alias_redirect'])));
Notices::addSuccessNotice(__('Alias successfully created.')); Notices::addSuccessNotice(__('Alias successfully created.'));
My::redirect(); My::redirect();
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); App::error()->add($e->getMessage());
} }
} }
@ -90,8 +94,7 @@ class Manage extends Process
return; return;
} }
$alias = new Alias(); $aliases = (new Alias())->getAliases();
$aliases = $alias->getAliases();
Page::openModule(My::name()); Page::openModule(My::name());
@ -106,16 +109,16 @@ class Manage extends Process
(new Div())->items([ (new Div())->items([
(new Text('h3', __('New alias'))), (new Text('h3', __('New alias'))),
(new Form(My::id() . '_form'))->method('post')->action(dcCore::app()->admin->getPageURL())->fields([ (new Form(My::id() . '_form'))->method('post')->action(App::backend()->getPageURL())->fields([
(new Para())->class('field')->items([ (new Para())->class('field')->items([
(new Label(__('Alias URL:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_url'), (new Label(__('Alias URL:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_url'),
(new Input('alias_url'))->size(50)->maxlenght(255), (new Input('alias_url'))->size(50)->maxlength(255),
]), ]),
(new Para())->class('field')->items([ (new Para())->class('field')->items([
(new Label(__('Alias destination:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_destination'), (new Label(__('Alias destination:'), Label::OUTSIDE_LABEL_BEFORE))->for('alias_destination'),
(new Input('alias_destination'))->size(50)->maxlenght(255), (new Input('alias_destination'))->size(50)->maxlength(255),
]), ]),
(new Note())->class('form-note')->text(sprintf(__('Do not put blog URL "%s" in fields.'), dcCore::app()->blog->url)), (new Note())->class('form-note')->text(sprintf(__('Do not put blog URL "%s" in fields.'), App::blog()->url())),
(new Para())->items([ (new Para())->items([
(new Checkbox('alias_redirect', false))->value(1), (new Checkbox('alias_redirect', false))->value(1),
(new Label(__('Do visible redirection to destination'), Label::OUTSIDE_LABEL_AFTER))->for('alias_redirect')->class('classic'), (new Label(__('Do visible redirection to destination'), Label::OUTSIDE_LABEL_AFTER))->for('alias_redirect')->class('classic'),
@ -143,7 +146,7 @@ class Manage extends Process
echo '<p>' . __('No alias') . '</p>'; echo '<p>' . __('No alias') . '</p>';
} else { } else {
echo echo
'<form action="' . dcCore::app()->admin->getPageURL() . '" method="post">' . '<form action="' . App::backend()->getPageURL() . '" method="post">' .
'<p>' . sprintf(__('There is %s alias.', 'There are %s aliases.', count($aliases)), count($aliases)) . '</p>' . '<p>' . sprintf(__('There is %s alias.', 'There are %s aliases.', count($aliases)), count($aliases)) . '</p>' .
'<div class="table-outer">' . '<div class="table-outer">' .
'<table>' . '<table>' .
@ -157,17 +160,17 @@ class Manage extends Process
'</tr>' . '</tr>' .
'</thead><tbody>'; '</thead><tbody>';
foreach ($aliases as $k => $v) { foreach ($aliases as $k => $alias) {
echo echo
'<tr class="line" id="l_' . $k . '">' . '<tr class="line" id="l_' . $k . '">' .
'<td class="minimal">' . '<td class="minimal">' .
(new Input(['a[' . $k . '][alias_url]']))->size(50)->maxlenght(255)->value(Html::escapeHTML($v['alias_url']))->render() . '</td>' . (new Input(['a[' . $k . '][alias_url]']))->size(50)->maxlength(255)->value(Html::escapeHTML($alias->url))->render() . '</td>' .
'<td class="minimal">' . '<td class="minimal">' .
(new Input(['a[' . $k . '][alias_destination]']))->size(50)->maxlenght(255)->value(Html::escapeHTML($v['alias_destination']))->render() . '</td>' . (new Input(['a[' . $k . '][alias_destination]']))->size(50)->maxlength(255)->value(Html::escapeHTML($alias->destination))->render() . '</td>' .
'<td class="minimal">' . '<td class="minimal">' .
(new Number(['a[' . $k . '][alias_position]']))->min(1)->max(count($aliases))->default((int) $v['alias_position'])->class('position')->title(sprintf(__('position of %s'), Html::escapeHTML($v['alias_url'])))->render() . '</td>' . (new Number(['a[' . $k . '][alias_position]']))->min(1)->max(count($aliases))->default($alias->position)->class('position')->title(sprintf(__('position of %s'), Html::escapeHTML($alias->url)))->render() . '</td>' .
'<td class="maximal">' . '<td class="maximal">' .
(new Checkbox(['a[' . $k . '][alias_redirect]'], (bool) $v['alias_redirect']))->title(sprintf(__('visible redirection to %s'), Html::escapeHTML(dcCore::app()->blog->url . $v['alias_destination'])))->render() . '</td>' . (new Checkbox(['a[' . $k . '][alias_redirect]'], $alias->redirect))->title(sprintf(__('visible redirection to %s'), Html::escapeHTML(App::blog()->url() . $alias->destination)))->render() . '</td>' .
'</tr>'; '</tr>';
} }

View File

@ -1,36 +1,20 @@
<?php <?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use dcCore;
use Dotclear\Module\MyPlugin; use Dotclear\Module\MyPlugin;
/** /**
* This module definitions. * @brief alias My helper.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class My extends MyPlugin class My extends MyPlugin
{ {
/** @var string Plugin table name */ // Use default permissions
public const ALIAS_TABLE_NAME = 'alias';
public static function checkCustomContext(int $context): ?bool
{
return !in_array($context, [My::BACKEND, My::MANAGE, My::MENU]) ? null :
defined('DC_CONTEXT_ADMIN')
&& dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
dcCore::app()->auth::PERMISSION_ADMIN,
]), dcCore::app()->blog->id);
}
} }

View File

@ -0,0 +1,75 @@
<?php
declare(strict_types=1);
namespace Dotclear\Plugin\alias;
use Dotclear\App;
use Dotclear\Database\Statement\SelectStatement;
use Dotclear\Plugin\importExport\{
FlatBackupItem,
FlatExport,
FlatImportV2
};
/**
* @brief alias plugin importExport features class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class PluginImportExportBehaviors
{
public static function exportFullV2(FlatExport $exp): void
{
$exp->exportTable(Alias::ALIAS_TABLE_NAME);
}
public static function exportSingleV2(FlatExport $exp, ?string $blog_id): void
{
$sql = new SelectStatement();
$sql->columns(['alias_url', 'alias_destination', 'alias_position', 'alias_redirect'])
->from($sql->as(App::con()->prefix() . Alias::ALIAS_TABLE_NAME, 'A'))
->where('blog_id = ' . $sql->quote((string) $blog_id));
$exp->export('alias', $sql->statement());
}
public static function importInitV2(FlatImportV2 $bk): void
{
$bk->__set('cur_alias', App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME));
$bk->__set('alias', new Alias());
$bk->__set('aliases', $bk->__get('alias')->getAliases());
}
public static function importFullV2(bool|FlatBackupItem $line, FlatImportV2 $bk): void
{
if (!is_bool($line) && $line->__name == Alias::ALIAS_TABLE_NAME) {
$bk->__get('cur_alias')->clean();
$bk->__get('cur_alias')->setField('blog_id', (string) $line->f('blog_id'));
$bk->__get('cur_alias')->setField('alias_url', (string) $line->f('alias_url'));
$bk->__get('cur_alias')->setField('alias_destination', (string) $line->f('alias_destination'));
$bk->__get('cur_alias')->setField('alias_position', (int) $line->f('alias_position'));
$bk->__get('cur_alias')->setField('alias_redirect', (int) $line->f('alias_redirect'));
$bk->__get('cur_alias')->insert();
}
}
public static function importSingleV2(bool|FlatBackupItem $line, FlatImportV2 $bk): void
{
if (!is_bool($line) && $line->__name == Alias::ALIAS_TABLE_NAME) {
$found = false;
foreach ($bk->__get('aliases') as $alias) {
if ($alias->url == $line->f('alias_url')) {
$found = true;
}
}
if ($found) {
$bk->__get('alias')->deleteAlias($line->f('alias_url'));
}
$bk->__get('alias')->createAlias(new AliasRow($line->f('alias_url'), $line->f('alias_destination'), $line->f('alias_position'), $line->f('alias_redirect')));
}
}
}

View File

@ -1,83 +0,0 @@
<?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1);
namespace Dotclear\Plugin\alias;
use dcCore;
use dcUrlHandlers;
use Dotclear\Core\Process;
use Dotclear\Helper\Network\Http;
class Prepend extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::PREPEND));
}
public static function process(): bool
{
if (!self::status()) {
return false;
}
dcCore::app()->addBehavior('urlHandlerGetArgsDocument', function (dcUrlHandlers $handler): void {
$found = $redir = false;
$type = '';
$part = $args = $_SERVER['URL_REQUEST_PART'];
// load all Aliases
foreach ((new Alias())->getAliases() as $v) {
// multi alias using "/url/" to "destination"
if (@preg_match('#^/.*/$#', $v['alias_url']) && @preg_match($v['alias_url'], $args)) {
$part = preg_replace($v['alias_url'], $v['alias_destination'], $args);
$found = true;
$redir = !empty($v['alias_redirect']);
break;
// single alias using "url" to "destination"
} elseif ($v['alias_url'] == $args) {
$part = $v['alias_destination'];
$found = true;
$redir = !empty($v['alias_redirect']);
break;
}
}
// no URLs found
if (!$found) {
return;
}
// Use visible redirection
if ($redir) {
Http::redirect(dcCore::app()->blog->url . $part);
}
// regain URL type
$_SERVER['URL_REQUEST_PART'] = $part;
dcCore::app()->url->getArgs($part, $type, $args);
// call real handler
if (!$type) {
dcCore::app()->url->callDefaultHandler($args);
} else {
dcCore::app()->url->callHandler($type, $args);
}
});
return true;
}
}

View File

@ -1,23 +1,20 @@
<?php <?php
/**
* @brief alias, a plugin for Dotclear 2
*
* @package Dotclear
* @subpackage Plugin
*
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
declare(strict_types=1); declare(strict_types=1);
namespace Dotclear\Plugin\alias; namespace Dotclear\Plugin\alias;
use dcCore;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Plugin\Uninstaller\Uninstaller; use Dotclear\Plugin\Uninstaller\Uninstaller;
/**
* @brief alias uninstall class.
* @ingroup alias
*
* @author Olivier Meunier (author)
* @author Jean-Christian Denis (latest)
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class Uninstall extends Process class Uninstall extends Process
{ {
public static function init(): bool public static function init(): bool
@ -27,7 +24,7 @@ class Uninstall extends Process
public static function process(): bool public static function process(): bool
{ {
if (!self::status() || !dcCore::app()->plugins->moduleExists('Uninstaller')) { if (!self::status()) {
return false; return false;
} }
@ -35,7 +32,7 @@ class Uninstall extends Process
->addUserAction( ->addUserAction(
'tables', 'tables',
'delete', 'delete',
My::ALIAS_TABLE_NAME Alias::ALIAS_TABLE_NAME
) )
->addUserAction( ->addUserAction(
'plugins', 'plugins',
@ -51,7 +48,7 @@ class Uninstall extends Process
->addDirectAction( ->addDirectAction(
'tables', 'tables',
'delete', 'delete',
My::ALIAS_TABLE_NAME Alias::ALIAS_TABLE_NAME
) )
->addDirectAction( ->addDirectAction(
'plugins', 'plugins',