Compare commits

..

No commits in common. "master" and "v1.9" have entirely different histories.
master ... v1.9

17 changed files with 387 additions and 406 deletions

View File

@ -1,16 +1,3 @@
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,22 +1,26 @@
# README # README
[![Release](https://img.shields.io/badge/release-1.11-a2cbe9.svg)](https://git.dotclear.watch/JcDenis/alias/releases) [![Release](https://img.shields.io/github/v/release/JcDenis/alias)](https://github.com/JcDenis/alias/releases)
![Date](https://img.shields.io/badge/date-2023.10.23-c44d58.svg) [![Date](https://img.shields.io/github/release-date/JcDenis/alias)](https://github.com/JcDenis/alias/releases)
[![Dotclear](https://img.shields.io/badge/dotclear-v2.28-137bbb.svg)](https://fr.dotclear.org/download) [![Issues](https://img.shields.io/github/issues/JcDenis/alias)](https://github.com/JcDenis/alias/issues)
[![Dotaddict](https://img.shields.io/badge/dotaddict-official-9ac123.svg)](https://plugins.dotaddict.org/dc2/details/alias) [![Dotclear](https://img.shields.io/badge/dotclear-v2.27-blue.svg)](https://fr.dotclear.org/download)
[![License](https://img.shields.io/badge/license-GPL--2.0-ececec.svg)](https://git.dotclear.watch/JcDenis/alias/src/branch/master/LICENSE) [![Dotaddict](https://img.shields.io/badge/dotaddict-official-green.svg)](https://plugins.dotaddict.org/dc2/details/alias)
[![License](https://img.shields.io/github/license/JcDenis/alias)](https://github.com/JcDenis/alias/blob/master/LICENSE)
## ABOUT ## WHAT IS ALIAS ?
_alias_ is a plugin for the open-source web publishing software called [Dotclear](https://www.dotclear.org). _alias_ is a plugin for the open-source
web publishing software called Dotclear.
> Create aliases of your blog's URLs. This plugin creates public aliases of your blog's URLs.
## REQUIREMENTS ## REQUIREMENTS
* Dotclear 2.28 _alias_ requires:
* PHP 8.1+
* Dotclear admin permission for management * admin permissions for management
* Dotclear 2.27
* PHP 7.4+
## USAGE ## USAGE
@ -27,26 +31,27 @@ 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/" by replacing it by destination "post" into requesting URL. (Even if it's not at the begining of the URL!) - It can redirect all URLs that content "plop" using alias "/plop/"
* It can not redirect an alias to another alias. by replacing it by destination "post" into requesting URL. (Even if it's not at the begining of the URL!)
* 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 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.
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](https://git.dotclear.watch/JcDenis/alias/src/branch/master/LICENSE) * License : [GNU GPL v2](https://www.gnu.org/licenses/old-licenses/lgpl-2.0.html)
* [Packages & details](https://git.dotclear.watch/JcDenis/alias/releases) (or on [Dotaddict](https://plugins.dotaddict.org/dc2/details/alias)) * Source & contribution : [Gitea Page](https://git.dotclear.watch/JcDenis/alias) or [GitHub Page](https://github.com/JcDenis/alias)
* [Sources & contributions](https://git.dotclear.watch/JcDenis/alias) (or on [GitHub](https://github.com/JcDenis/alias)) * Packages & details: [Gitea Page](https://git.dotclear.watch/JcDenis/alias/releases) or [Dotaddict Page](https://plugins.dotaddict.org/dc2/details/alias)
* [Issues & security](https://git.dotclear.watch/JcDenis/alias/issues) (or on [GitHub](https://github.com/JcDenis/alias/issues))
## CONTRIBUTORS ## CONTRIBUTORS
* Olivier Meunier (author) * Olivier Meunier
* Franck-paul * Franck-paul
* Jean-Christian Denis (latest) * Jean-Christian Denis
You are welcome to contribute to this code. You are welcome to contribute to this code.

View File

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

20
_init.php Normal file
View File

@ -0,0 +1,20 @@
<?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.11</version> <version>1.9</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://git.dotclear.watch/JcDenis/alias/releases/download/v1.11/plugin-alias.zip</file> <file>https://gitea.dotclear.watch/JcDenis/alias/releases/download/v1.9/plugin-alias.zip</file>
<da:dcmin>2.28</da:dcmin> <da:dcmin>2.27</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,11 +1,17 @@
<?php <?php
/** /**
* @file * @brief alias, a plugin for Dotclear 2
* @brief The plugin alias resources
* @ingroup alias
* *
* @author Olivier Meunier (author) * @package Dotclear
* @author Jean-Christian Denis (latest) * @subpackage Plugin
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html *
* @author Olivier Meunier and contributors
*
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
\Dotclear\App::backend()->resources()->set('help', 'alias', __DIR__ . '/help/help.html'); if (!defined('DC_RC_PATH')) {
return;
}
dcCore::app()->resources['help']['alias'] = __DIR__ . '/help/help.html';

View File

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

View File

@ -1,10 +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 Dotclear\App; use dcCore;
use Dotclear\Database\Statement\{ use Dotclear\Database\Statement\{
DeleteStatement, DeleteStatement,
SelectStatement SelectStatement
@ -12,33 +22,17 @@ use Dotclear\Database\Statement\{
use Exception; use Exception;
/** /**
* @brief alias main class. * plugin 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<int, AliasRow> Stack of aliases * @return array Stack of aliases
*/ */
public function getAliases(): array public function getAliases(): array
{ {
@ -46,23 +40,24 @@ 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(App::con()->prefix() . Alias::ALIAS_TABLE_NAME) $rs = $sql->from(dcCore::app()->prefix . My::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(App::blog()->id())) ->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog->id))
->order('alias_position ASC') ->order('alias_position ASC')
->select(); ->select();
if (!is_null($rs)) { $this->aliases = is_null($rs) ? [] : $rs->rows();
while ($rs->fetch()) {
$this->aliases[] = AliasRow::newFromRecord($rs);
}
}
return $this->aliases; return $this->aliases;
} }
@ -70,30 +65,30 @@ class Alias
/** /**
* Update aliases stack. * Update aliases stack.
* *
* @param array<int, AliasRow> $aliases The alias stack * @param array $aliases The alias stack
*/ */
public function updateAliases(array $aliases): void public function updateAliases(array $aliases): void
{ {
foreach ($aliases as $row) { usort($aliases, fn ($a, $b) => (int) $a['alias_position'] <=> (int) $b['alias_position']);
if (!is_a($row, AliasRow::class)) { foreach ($aliases as $v) {
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);
App::con()->begin(); dcCore::app()->con->begin();
try { try {
$this->deleteAliases(); $this->deleteAliases();
foreach ($aliases as $k => $alias) { foreach ($aliases as $k => $v) {
if (!empty($alias->url) && !empty($alias->destination)) { if (!empty($v['alias_url']) && !empty($v['alias_destination'])) {
$this->createAlias(new AliasRow($alias->url, $alias->destination, $k + 1, $alias->redirect)); $this->createAlias($v['alias_url'], $v['alias_destination'], $k + 1, !empty($v['alias_redirect']));
} }
} }
App::con()->commit(); dcCore::app()->con->commit();
} catch (Exception $e) { } catch (Exception $e) {
App::con()->rollback(); dcCore::app()->con->rollback();
throw $e; throw $e;
} }
@ -102,16 +97,20 @@ class Alias
/** /**
* Create an alias. * Create an alias.
* *
* @param AliasRow $alias The new Alias descriptor * @param string $url The URL
* @param string $destination The destination
* @param int $position The position
* @param bool $redirect Do redirection
*/ */
public function createAlias(AliasRow $alias): void public function createAlias(string $url, string $destination, int $position, bool $redirect): void
{ {
if (!App::blog()->isDefined()) { // nullsafe
if (is_null(dcCore::app()->blog)) {
return; return;
} }
$url = self::removeBlogUrl($alias->url); $url = self::removeBlogUrl($url);
$destination = self::removeBlogUrl($alias->destination); $destination = self::removeBlogUrl($destination);
if (empty($url)) { if (empty($url)) {
throw new Exception(__('Alias URL is empty.')); throw new Exception(__('Alias URL is empty.'));
@ -120,12 +119,12 @@ class Alias
throw new Exception(__('Alias destination is empty.')); throw new Exception(__('Alias destination is empty.'));
} }
$cur = App::con()->openCursor(App::con()->prefix() . Alias::ALIAS_TABLE_NAME); $cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . My::ALIAS_TABLE_NAME);
$cur->setField('blog_id', App::blog()->id()); $cur->setField('blog_id', (string) dcCore::app()->blog->id);
$cur->setField('alias_url', $url); $cur->setField('alias_url', (string) $url);
$cur->setField('alias_destination', $destination); $cur->setField('alias_destination', (string) $destination);
$cur->setField('alias_position', $alias->position); $cur->setField('alias_position', abs((int) $position));
$cur->setField('alias_redirect', (int) $alias->redirect); $cur->setField('alias_redirect', (int) $redirect);
$cur->insert(); $cur->insert();
} }
@ -136,9 +135,14 @@ 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(App::con()->prefix() . Alias::ALIAS_TABLE_NAME) $sql->from(dcCore::app()->prefix . My::ALIAS_TABLE_NAME)
->where('blog_id = ' . $sql->quote(App::blog()->id())) ->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog->id))
->and('alias_url = ' . $sql->quote($url)) ->and('alias_url = ' . $sql->quote($url))
->delete(); ->delete();
} }
@ -148,9 +152,14 @@ 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(App::con()->prefix() . Alias::ALIAS_TABLE_NAME) $sql->from(dcCore::app()->prefix . My::ALIAS_TABLE_NAME)
->where('blog_id = ' . $sql->quote(App::blog()->id())) ->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog->id))
->delete(); ->delete();
} }
@ -163,6 +172,6 @@ class Alias
*/ */
public static function removeBlogUrl(string $url): string public static function removeBlogUrl(string $url): string
{ {
return str_replace(App::blog()->url(), '', trim($url)); return is_null(dcCore::app()->blog) ? trim($url) : str_replace(dcCore::app()->blog->url, '', trim($url));
} }
} }

View File

@ -1,41 +0,0 @@
<?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,20 +1,27 @@
<?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 Dotclear\App; use dcCore;
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
@ -30,11 +37,47 @@ class Backend extends Process
My::addBackendMenuItem(); My::addBackendMenuItem();
App::behavior()->addBehaviors([ dcCore::app()->addBehaviors([
'exportFullV2' => PluginImportExportBehaviors::exportFullV2(...), 'exportFullV2' => function (FlatExport $exp): void {
'importInitV2' => PluginImportExportBehaviors::importInitV2(...), $exp->exportTable(My::ALIAS_TABLE_NAME);
'importFullV2' => PluginImportExportBehaviors::importFullV2(...), },
'importSingleV2' => PluginImportExportBehaviors::importSingleV2(...), 'exportSingleV2' => function (FlatExport $exp, ?string $blog_id): void {
$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;

View File

@ -1,82 +0,0 @@
<?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,22 +1,24 @@
<?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 Dotclear\App; use dcCore;
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
@ -31,8 +33,8 @@ class Install extends Process
} }
try { try {
$s = new Structure(App::con(), App::con()->prefix()); $s = new Structure(dcCore::app()->con, dcCore::app()->prefix);
$s->__get(Alias::ALIAS_TABLE_NAME) $s->__get(My::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)
@ -47,11 +49,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(App::con(), App::con()->prefix()))->synchronize($s); (new Structure(dcCore::app()->con, dcCore::app()->prefix))->synchronize($s);
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
App::error()->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
return false; return false;
} }

View File

@ -1,10 +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 Dotclear\App; use dcCore;
use Dotclear\Core\Process; use Dotclear\Core\Process;
use Dotclear\Core\Backend\{ use Dotclear\Core\Backend\{
Notices, Notices,
@ -27,12 +37,7 @@ use Dotclear\Helper\Html\Html;
use Exception; use Exception;
/** /**
* @brief alias manage class. * Manage contributions list
* @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
{ {
@ -51,37 +56,28 @@ class Manage extends Process
return true; return true;
} }
$utils = new Alias(); $alias = new Alias();
$aliases = $utils->getAliases(); $aliases = $alias->getAliases();
# Update aliases # Update aliases
if (isset($_POST['a']) && is_array($_POST['a'])) { if (isset($_POST['a']) && is_array($_POST['a'])) {
try { try {
$stack = []; $alias->updateAliases($_POST['a']);
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) {
App::error()->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
} }
} }
# New alias # New alias
if (isset($_POST['alias_url'])) { if (isset($_POST['alias_url'])) {
try { try {
$utils->createAlias(new AliasRow($_POST['alias_url'], $_POST['alias_destination'], count($aliases) + 1, !empty($_POST['alias_redirect']))); $alias->createAlias($_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) {
App::error()->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
} }
} }
@ -94,7 +90,8 @@ class Manage extends Process
return; return;
} }
$aliases = (new Alias())->getAliases(); $alias = new Alias();
$aliases = $alias->getAliases();
Page::openModule(My::name()); Page::openModule(My::name());
@ -109,16 +106,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(App::backend()->getPageURL())->fields([ (new Form(My::id() . '_form'))->method('post')->action(dcCore::app()->admin->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)->maxlength(255), (new Input('alias_url'))->size(50)->maxlenght(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)->maxlength(255), (new Input('alias_destination'))->size(50)->maxlenght(255),
]), ]),
(new Note())->class('form-note')->text(sprintf(__('Do not put blog URL "%s" in fields.'), App::blog()->url())), (new Note())->class('form-note')->text(sprintf(__('Do not put blog URL "%s" in fields.'), dcCore::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'),
@ -146,7 +143,7 @@ class Manage extends Process
echo '<p>' . __('No alias') . '</p>'; echo '<p>' . __('No alias') . '</p>';
} else { } else {
echo echo
'<form action="' . App::backend()->getPageURL() . '" method="post">' . '<form action="' . dcCore::app()->admin->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>' .
@ -160,17 +157,17 @@ class Manage extends Process
'</tr>' . '</tr>' .
'</thead><tbody>'; '</thead><tbody>';
foreach ($aliases as $k => $alias) { foreach ($aliases as $k => $v) {
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)->maxlength(255)->value(Html::escapeHTML($alias->url))->render() . '</td>' . (new Input(['a[' . $k . '][alias_url]']))->size(50)->maxlenght(255)->value(Html::escapeHTML($v['alias_url']))->render() . '</td>' .
'<td class="minimal">' . '<td class="minimal">' .
(new Input(['a[' . $k . '][alias_destination]']))->size(50)->maxlength(255)->value(Html::escapeHTML($alias->destination))->render() . '</td>' . (new Input(['a[' . $k . '][alias_destination]']))->size(50)->maxlenght(255)->value(Html::escapeHTML($v['alias_destination']))->render() . '</td>' .
'<td class="minimal">' . '<td class="minimal">' .
(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>' . (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>' .
'<td class="maximal">' . '<td class="maximal">' .
(new Checkbox(['a[' . $k . '][alias_redirect]'], $alias->redirect))->title(sprintf(__('visible redirection to %s'), Html::escapeHTML(App::blog()->url() . $alias->destination)))->render() . '</td>' . (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>' .
'</tr>'; '</tr>';
} }

View File

@ -1,20 +1,36 @@
<?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;
/** /**
* @brief alias My helper. * This module definitions.
* @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
{ {
// Use default permissions /** @var string Plugin table name */
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

@ -1,75 +0,0 @@
<?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')));
}
}
}

83
src/Prepend.php Normal file
View File

@ -0,0 +1,83 @@
<?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,20 +1,23 @@
<?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
@ -24,7 +27,7 @@ class Uninstall extends Process
public static function process(): bool public static function process(): bool
{ {
if (!self::status()) { if (!self::status() || !dcCore::app()->plugins->moduleExists('Uninstaller')) {
return false; return false;
} }
@ -32,7 +35,7 @@ class Uninstall extends Process
->addUserAction( ->addUserAction(
'tables', 'tables',
'delete', 'delete',
Alias::ALIAS_TABLE_NAME My::ALIAS_TABLE_NAME
) )
->addUserAction( ->addUserAction(
'plugins', 'plugins',
@ -48,7 +51,7 @@ class Uninstall extends Process
->addDirectAction( ->addDirectAction(
'tables', 'tables',
'delete', 'delete',
Alias::ALIAS_TABLE_NAME My::ALIAS_TABLE_NAME
) )
->addDirectAction( ->addDirectAction(
'plugins', 'plugins',