code review

This commit is contained in:
Jean-Christian Denis 2023-11-04 18:53:06 +01:00
parent cda97ddad4
commit 7bb71e2de9
Signed by: JcDenis
GPG key ID: 1B5B8C5B90B6C951
25 changed files with 395 additions and 259 deletions

View file

@ -39,11 +39,12 @@ class Backend extends Process
'adminPostHeaders' => BackendBehaviors::adminPostHeaders(...), 'adminPostHeaders' => BackendBehaviors::adminPostHeaders(...),
'adminPostFormItems' => BackendBehaviors::adminPostFormItems(...), 'adminPostFormItems' => BackendBehaviors::adminPostFormItems(...),
'adminAfterPostUpdate' => BackendBehaviors::adminAfterPostUpdate(...), // update existing short url 'adminAfterPostUpdate' => BackendBehaviors::adminAfterPostUpdate(...), // update existing short url
'adminAfterPostUpdate' => BackendBehaviors::adminAfterPostCreate(...), // create new short url
'adminAfterPostCreate' => BackendBehaviors::adminAfterPostCreate(...), 'adminAfterPostCreate' => BackendBehaviors::adminAfterPostCreate(...),
'adminBeforePostDelete' => BackendBehaviors::adminBeforePostDelete(...), 'adminBeforePostDelete' => BackendBehaviors::adminBeforePostDelete(...),
'adminPostsActions' => BackendBehaviors::adminPostsActions(...), 'adminPostsActions' => BackendBehaviors::adminPostsActions(...),
]); ]);
// hate duplicate key!
App::behavior()->addBehavior('adminAfterPostUpdate', BackendBehaviors::adminAfterPostCreate(...)); // create new short url
} }
App::behavior()->addBehaviors([ App::behavior()->addBehaviors([

View file

@ -51,6 +51,9 @@ class BackendBehaviors
); );
} }
/**
* @param ArrayObject<string, mixed> $cols
*/
public static function adminColumnsListsV2(ArrayObject $cols): void public static function adminColumnsListsV2(ArrayObject $cols): void
{ {
$cols[My::id()] = [ $cols[My::id()] = [
@ -63,6 +66,9 @@ class BackendBehaviors
]; ];
} }
/**
* @param ArrayObject<string, mixed> $sorts
*/
public static function adminFiltersListsV2(ArrayObject $sorts): void public static function adminFiltersListsV2(ArrayObject $sorts): void
{ {
$sorts[My::id()] = [ $sorts[My::id()] = [
@ -79,12 +85,15 @@ class BackendBehaviors
return My::jsLoad('posts'); return My::jsLoad('posts');
} }
/**
* @param ArrayObject<string, mixed> $main_items
* @param ArrayObject<string, mixed> $sidebar_items
*/
public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?MetaRecord $post): void public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?MetaRecord $post): void
{ {
$s = My::settings(); $s = My::settings();
if (!$s->get('active') if (!$s->get('active')
|| !$s->get('active')
|| null === ($kut = Utils::quickPlace('admin')) || null === ($kut = Utils::quickPlace('admin'))
) { ) {
return; return;
@ -114,7 +123,7 @@ class BackendBehaviors
->for('kutrl_create'), ->for('kutrl_create'),
]); ]);
if ($kut->allow_custom_hash) { if ($kut->get('allow_custom_hash')) {
$items[] = (new Para()) $items[] = (new Para())
->class('classic') ->class('classic')
->items([ ->items([
@ -136,7 +145,7 @@ class BackendBehaviors
} else { } else {
$title = sprintf(__('followed %s times'), $count); $title = sprintf(__('followed %s times'), $count);
} }
$href = $kut->url_base . $rs->hash; $href = $kut->get('url_base') . $rs->hash;
$items[] = (new Para()) $items[] = (new Para())
->items([ ->items([
@ -199,11 +208,15 @@ class BackendBehaviors
$kut->remove($old_post_url); $kut->remove($old_post_url);
$rs = $kut->hash($new_post_url, '');//$custom); // better to update (not yet implemented) if (false === ($rs = $kut->hash($new_post_url, ''))) {
$url = $kut->url_base . $rs->hash; ;//$custom); // better to update (not yet implemented)
return;
}
$url = $kut->get('url_base') . $rs->hash;
# ex: Send new url to messengers # ex: Send new url to messengers
if (!empty($rs)) { if (!$rs->isEmpty()) {
App::behavior()->callBehavior('adminAfterKutrlCreate', $rs, $title); App::behavior()->callBehavior('adminAfterKutrlCreate', $rs, $title);
} }
} }
@ -224,14 +237,16 @@ class BackendBehaviors
} }
$title = Html::escapeHTML($rs->post_title); $title = Html::escapeHTML($rs->post_title);
$custom = !empty($_POST['kutrl_create_custom']) && $kut->allow_custom_hash ? $custom = !empty($_POST['kutrl_create_custom']) && $kut->get('allow_custom_hash') ?
$_POST['kutrl_create_custom'] : null; $_POST['kutrl_create_custom'] : null;
$rs = $kut->hash($rs->getURL(), $custom); if (false === ($rs = $kut->hash($rs->getURL(), $custom))) {
$url = $kut->url_base . $rs->hash; return;
}
$url = $kut->get('url_base') . $rs->hash;
# ex: Send new url to messengers # ex: Send new url to messengers
if (!empty($rs)) { if (!$rs->isEmpty()) {
App::behavior()->callBehavior('adminAfterKutrlCreate', $rs, $title); App::behavior()->callBehavior('adminAfterKutrlCreate', $rs, $title);
} }
} }
@ -269,6 +284,9 @@ class BackendBehaviors
); );
} }
/**
* @param ArrayObject<int|string, int|string> $post
*/
public static function callbackCreate(ActionsPosts $pa, ArrayObject $post): void public static function callbackCreate(ActionsPosts $pa, ArrayObject $post): void
{ {
# No entry # No entry
@ -296,6 +314,9 @@ class BackendBehaviors
$pa->redirect(true); $pa->redirect(true);
} }
/**
* @param ArrayObject<int|string, int|string> $post
*/
public static function callbackDelete(ActionsPosts $pa, ArrayObject $post): void public static function callbackDelete(ActionsPosts $pa, ArrayObject $post): void
{ {
# No entry # No entry

View file

@ -33,8 +33,11 @@ class Combo
{ {
$services_combo = []; $services_combo = [];
foreach (Utils::getServices() as $service_id => $service) { foreach (Utils::getServices() as $service_id => $service) {
$o = new $service(); if (!is_subclass_of($service, Service::class)) {
$services_combo[__($o->name)] = $o->id; continue;
}
$o = new $service();
$services_combo[__($o->get('name'))] = $o->get('id');
} }
if ($with_none) { if ($with_none) {
$services_combo = array_merge([__('Disabled') => ''], $services_combo); $services_combo = array_merge([__('Disabled') => ''], $services_combo);

View file

@ -82,8 +82,10 @@ class Config extends Process
# services # services
foreach (Utils::getServices() as $service_id => $service) { foreach (Utils::getServices() as $service_id => $service) {
$o = new $service(); if (is_subclass_of($service, Service::class)) {
$o->saveSettings(); $o = new $service();
$o->saveSettings();
}
} }
App::blog()->triggerBlog(); App::blog()->triggerBlog();
@ -148,37 +150,40 @@ class Config extends Process
$i_config = []; $i_config = [];
foreach (Utils::getServices() as $service_id => $service) { foreach (Utils::getServices() as $service_id => $service) {
if (!is_subclass_of($service, Service::class)) {
continue;
}
$o = new $service(); $o = new $service();
$s_items = []; $s_items = [];
if (!empty($_REQUEST['chk'])) { if (!empty($_REQUEST['chk'])) {
$img_chk = $img_red . ' ' . sprintf(__('Failed to test %s API.'), $o->name); $img_chk = $img_red . ' ' . sprintf(__('Failed to test %s API.'), $o->get('name'));
try { try {
if ($o->testService()) { if ($o->testService()) {
$img_chk = $img_green . ' ' . sprintf(__('%s API is well configured and runing.'), $o->name); $img_chk = $img_green . ' ' . sprintf(__('%s API is well configured and runing.'), $o->get('name'));
} }
} catch (Exception $e) { } catch (Exception $e) {
App::error()->add(sprintf(__('Failed to test service %s: %s'), $o->name, $e->getMessage())); App::error()->add(sprintf(__('Failed to test service %s: %s'), $o->get('name'), $e->getMessage()));
} }
$s_items[] = (new Text(null, sprintf('<p><em>%s</em></p>', $img_chk) . $o->error->toHTML())); $s_items[] = (new Text(null, sprintf('<p><em>%s</em></p>', $img_chk) . $o->error->toHTML()));
} }
if ($o->home != '') { if ($o->get('home') != '') {
$s_items[] = (new Para()) $s_items[] = (new Para())
->items([ ->items([
(new Link()) (new Link())
->href($o->home) ->href($o->get('home'))
->title(__('homepage')) ->title(__('homepage'))
->text(sprintf(__('Learn more about %s.'), $o->name)), ->text(sprintf(__('Learn more about %s.'), $o->get('name'))),
]); ]);
} }
$i_config[] = (new Text('hr')); $i_config[] = (new Text('hr'));
$i_config[] = (new Div('settings-' . $service_id)) $i_config[] = (new Div('settings-' . $service_id))
->items([ ->items([
(new Text('h5', $o->name)), (new Text('h5', $o->get('name'))),
... $s_items, ... $s_items,
$o->settingsForm(), $o->settingsForm(),
]); ]);

View file

@ -17,7 +17,11 @@ use Dotclear\Helper\Html\Html;
*/ */
class FrontendBehaviors class FrontendBehaviors
{ {
# Disable URL shoretning on filtered tag /**
* Disable URL shoretning on filtered tag.
*
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function templateBeforeValueV2(string $tag, ArrayObject $attr): ?string public static function templateBeforeValueV2(string $tag, ArrayObject $attr): ?string
{ {
if (!empty($attr['disable_kutrl']) && in_array($tag, My::USED_TAGS)) { if (!empty($attr['disable_kutrl']) && in_array($tag, My::USED_TAGS)) {
@ -27,7 +31,11 @@ class FrontendBehaviors
return null; return null;
} }
# Re unable it after tag /**
* Re unable it after tag.
*
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function templateAfterValueV2(string $tag, ArrayObject $attr): ?string public static function templateAfterValueV2(string $tag, ArrayObject $attr): ?string
{ {
if (!empty($attr['disable_kutrl']) && in_array($tag, My::USED_TAGS)) { if (!empty($attr['disable_kutrl']) && in_array($tag, My::USED_TAGS)) {
@ -37,7 +45,11 @@ class FrontendBehaviors
return null; return null;
} }
# Replace long urls on the fly (on filter) for default tags /**
* Replace long urls on the fly (on filter) for default tags.
*
* @param array<int|string, mixed> $args The attributes
*/
public static function publicBeforeContentFilterV2(string $tag, array $args): ?string public static function publicBeforeContentFilterV2(string $tag, array $args): ?string
{ {
# Unknow tag # Unknow tag
@ -66,6 +78,8 @@ class FrontendBehaviors
} }
} }
} }
return null;
} }
public static function publicBeforeDocumentV2(): void public static function publicBeforeDocumentV2(): void
@ -85,7 +99,7 @@ class FrontendBehaviors
App::frontend()->context()->kutrl = $kut; App::frontend()->context()->kutrl = $kut;
} }
public static function publicHeadContent($_): void public static function publicHeadContent(): void
{ {
$css = My::settings()->get('srv_local_css'); $css = My::settings()->get('srv_local_css');
if (!empty($css)) { if (!empty($css)) {

View file

@ -16,6 +16,9 @@ use Dotclear\App;
*/ */
class FrontendTemplate class FrontendTemplate
{ {
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function pageURL(ArrayObject$attr): string public static function pageURL(ArrayObject$attr): string
{ {
$f = App::frontend()->template()->getFilters($attr); $f = App::frontend()->template()->getFilters($attr);
@ -23,6 +26,9 @@ class FrontendTemplate
return '<?php echo ' . sprintf($f, 'App::blog()->url().App::url()->getBase("kutrl")') . '; ?>'; return '<?php echo ' . sprintf($f, 'App::blog()->url().App::url()->getBase("kutrl")') . '; ?>';
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function pageIf(ArrayObject $attr, string $content): string public static function pageIf(ArrayObject $attr, string $content): string
{ {
$operator = isset($attr['operator']) ? App::frontend()->template()->getOperator($attr['operator']) : '&&'; $operator = isset($attr['operator']) ? App::frontend()->template()->getOperator($attr['operator']) : '&&';
@ -41,6 +47,9 @@ class FrontendTemplate
"<?php endif; unset(\$s);?>\n"; "<?php endif; unset(\$s);?>\n";
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function pageMsgIf(ArrayObject$attr, string $content): string public static function pageMsgIf(ArrayObject$attr, string $content): string
{ {
$operator = isset($attr['operator']) ? App::frontend()->template()->getOperator($attr['operator']) : '&&'; $operator = isset($attr['operator']) ? App::frontend()->template()->getOperator($attr['operator']) : '&&';
@ -59,16 +68,25 @@ class FrontendTemplate
"<?php endif; ?>\n"; "<?php endif; ?>\n";
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function pageMsg(ArrayObject$attr): string public static function pageMsg(ArrayObject$attr): string
{ {
return '<?php echo App::frontend()->context()->kutrl_msg; ?>'; return '<?php echo App::frontend()->context()->kutrl_msg; ?>';
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function humanField(ArrayObject $attr): string public static function humanField(ArrayObject $attr): string
{ {
return "<?php echo sprintf(__('Confirm by writing \"%s\" in next field:'),App::frontend()->context()->kutrl_hmf); ?>"; return "<?php echo sprintf(__('Confirm by writing \"%s\" in next field:'),App::frontend()->context()->kutrl_hmf); ?>";
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function humanFieldProtect(ArrayObject $attr): string public static function humanFieldProtect(ArrayObject $attr): string
{ {
return return
@ -76,69 +94,107 @@ class FrontendTemplate
'<?php echo App::nonce()->getFormNonce(); ?>'; '<?php echo App::nonce()->getFormNonce(); ?>';
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function AttachmentKutrlIf(ArrayObject$attr, string $content): string public static function AttachmentKutrlIf(ArrayObject$attr, string $content): string
{ {
return self::genericKutrlIf('$attach_f->file_url', $attr, $content); return self::genericKutrlIf('$attach_f->file_url', $attr, $content);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function AttachmentKutrl(ArrayObject $attr): string public static function AttachmentKutrl(ArrayObject $attr): string
{ {
return self::genericKutrl('$attach_f->file_url', $attr); return self::genericKutrl('$attach_f->file_url', $attr);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function MediaKutrlIf(ArrayObject$attr, string $content): string public static function MediaKutrlIf(ArrayObject$attr, string $content): string
{ {
return self::genericKutrlIf('App::frontend()->context()->file_url', $attr, $content); return self::genericKutrlIf('App::frontend()->context()->file_url', $attr, $content);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function MediaKutrl(ArrayObject $attr): string public static function MediaKutrl(ArrayObject $attr): string
{ {
return self::genericKutrl('App::frontend()->context()->file_url', $attr); return self::genericKutrl('App::frontend()->context()->file_url', $attr);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function EntryAuthorKutrlIf(ArrayObject$attr, string $content): string public static function EntryAuthorKutrlIf(ArrayObject$attr, string $content): string
{ {
return self::genericKutrlIf('App::frontend()->context()->posts->user_url', $attr, $content); return self::genericKutrlIf('App::frontend()->context()->posts->user_url', $attr, $content);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function EntryAuthorKutrl(ArrayObject $attr): string public static function EntryAuthorKutrl(ArrayObject $attr): string
{ {
return self::genericKutrl('App::frontend()->context()->posts->user_url', $attr); return self::genericKutrl('App::frontend()->context()->posts->user_url', $attr);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function EntryKutrlIf(ArrayObject $attr, string $content): string public static function EntryKutrlIf(ArrayObject $attr, string $content): string
{ {
return self::genericKutrlIf('App::frontend()->context()->posts->getURL()', $attr, $content); return self::genericKutrlIf('App::frontend()->context()->posts->getURL()', $attr, $content);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function EntryKutrl(ArrayObject $attr): string public static function EntryKutrl(ArrayObject $attr): string
{ {
return self::genericKutrl('App::frontend()->context()->posts->getURL()', $attr); return self::genericKutrl('App::frontend()->context()->posts->getURL()', $attr);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function CommentAuthorKutrlIf(ArrayObject $attr, string $content): string public static function CommentAuthorKutrlIf(ArrayObject $attr, string $content): string
{ {
return self::genericKutrlIf('App::frontend()->context()->comments->getAuthorURL()', $attr, $content); return self::genericKutrlIf('App::frontend()->context()->comments->getAuthorURL()', $attr, $content);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function CommentAuthorKutrl(ArrayObject $attr): string public static function CommentAuthorKutrl(ArrayObject $attr): string
{ {
return self::genericKutrl('App::frontend()->context()->comments->getAuthorURL()', $attr); return self::genericKutrl('App::frontend()->context()->comments->getAuthorURL()', $attr);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function CommentPostKutrlIf(ArrayObject $attr, string $content): string public static function CommentPostKutrlIf(ArrayObject $attr, string $content): string
{ {
return self::genericKutrlIf('App::frontend()->context()->comments->getPostURL()', $attr, $content); return self::genericKutrlIf('App::frontend()->context()->comments->getPostURL()', $attr, $content);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
public static function CommentPostKutrl(ArrayObject $attr): string public static function CommentPostKutrl(ArrayObject $attr): string
{ {
return self::genericKutrl('App::frontend()->context()->comments->getPostURL()', $attr); return self::genericKutrl('App::frontend()->context()->comments->getPostURL()', $attr);
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
protected static function genericKutrlIf(string $str, ArrayObject $attr, string $content): string protected static function genericKutrlIf(string $str, ArrayObject $attr, string $content): string
{ {
$operator = isset($attr['operator']) ? App::fontend()->template()->getOperator($attr['operator']) : '&&'; $operator = isset($attr['operator']) ? App::frontend()->template()->getOperator($attr['operator']) : '&&';
if (isset($attr['is_active'])) { if (isset($attr['is_active'])) {
$sign = (bool) $attr['is_active'] ? '' : '!'; $sign = (bool) $attr['is_active'] ? '' : '!';
@ -162,6 +218,9 @@ class FrontendTemplate
"<?php endif; ?>\n"; "<?php endif; ?>\n";
} }
/**
* @param ArrayObject<string, mixed> $attr The attributes
*/
protected static function genericKutrl(string $str, ArrayObject $attr): string protected static function genericKutrl(string $str, ArrayObject $attr): string
{ {
$f = App::frontend()->template()->getFilters($attr); $f = App::frontend()->template()->getFilters($attr);

View file

@ -24,11 +24,9 @@ class FrontendUrl extends Url
# Not active, go to default 404 # Not active, go to default 404
if (!My::settings()->get('active')) { if (!My::settings()->get('active')) {
self::p404(); self::p404();
return;
} }
# Not a valid url, go to kutrl 404 # Not a valid url, go to kutrl 404
if (!preg_match('#^(|(/(.*?)))$#', $args, $m)) { if (!preg_match('#^(|(/(.*?)))$#', (string) $args, $m)) {
self::kutrl404(); self::kutrl404();
return; return;
@ -83,8 +81,6 @@ class FrontendUrl extends Url
# Not active, go to default 404 # Not active, go to default 404
if (!$s->get('active')) { if (!$s->get('active')) {
self::p404(); self::p404();
return;
} }
# Public page not active, go to kutrl 404 # Public page not active, go to kutrl 404
if (!$s->get('srv_local_public')) { if (!$s->get('srv_local_public')) {
@ -99,11 +95,9 @@ class FrontendUrl extends Url
$hmfu = !empty($_POST['hmfp']) ? FrontendUtils::unprotect($_POST['hmfp']) : '?'; $hmfu = !empty($_POST['hmfp']) ? FrontendUtils::unprotect($_POST['hmfp']) : '?';
$err = false; $err = false;
if (!$err) { if ($hmf != $hmfu) {
if ($hmf != $hmfu) { $err = true;
$err = true; App::frontend()->context()->kutrl_msg = __('Failed to verify protected field.');
App::frontend()->context()->kutrl_msg = __('Failed to verify protected field.');
}
} }
if (!$err) { if (!$err) {
if (!$kut->testService()) { if (!$kut->testService()) {
@ -131,7 +125,7 @@ class FrontendUrl extends Url
} }
if (!$err) { if (!$err) {
if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) { if (!$kut->get('allow_external_url') && !$kut->isBlogUrl($url)) {
$err = true; $err = true;
App::frontend()->context()->kutrl_msg = __('Short links are limited to this blog URL.'); App::frontend()->context()->kutrl_msg = __('Short links are limited to this blog URL.');
} }
@ -147,7 +141,7 @@ class FrontendUrl extends Url
$err = true; $err = true;
$url = $rs->url; $url = $rs->url;
$new_url = $kut->url_base . $rs->hash; $new_url = $kut->get('url_base') . $rs->hash;
App::frontend()->context()->kutrl_msg = sprintf( App::frontend()->context()->kutrl_msg = sprintf(
__('Short link for %s is %s'), __('Short link for %s is %s'),
@ -162,7 +156,7 @@ class FrontendUrl extends Url
App::frontend()->context()->kutrl_msg = __('Failed to create short link.'); App::frontend()->context()->kutrl_msg = __('Failed to create short link.');
} else { } else {
$url = $rs->url; $url = $rs->url;
$new_url = $kut->url_base . $rs->hash; $new_url = $kut->get('url_base') . $rs->hash;
App::frontend()->context()->kutrl_msg = sprintf( App::frontend()->context()->kutrl_msg = sprintf(
__('Short link for %s is %s'), __('Short link for %s is %s'),
@ -172,7 +166,7 @@ class FrontendUrl extends Url
App::blog()->triggerBlog(); App::blog()->triggerBlog();
# ex: Send new url to messengers # ex: Send new url to messengers
if (!empty($rs)) { if (!$rs->isEmpty()) {
App::behavior()->callBehavior('publicAfterKutrlCreate', $rs, __('New public short URL')); App::behavior()->callBehavior('publicAfterKutrlCreate', $rs, __('New public short URL'));
} }
} }
@ -185,10 +179,8 @@ class FrontendUrl extends Url
protected static function kutrl404(): void protected static function kutrl404(): void
{ {
if (!My::settigns()->get('srv_local_404_active')) { if (!My::settings()->get('srv_local_404_active')) {
self::p404(); self::p404();
return;
} }
App::frontend()->template()->appendPath(My::path() . '/default-templates'); App::frontend()->template()->appendPath(My::path() . '/default-templates');

View file

@ -13,9 +13,9 @@ namespace Dotclear\Plugin\kUtRL;
*/ */
class FrontendUtils class FrontendUtils
{ {
public static $chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'; public static string $chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
public static function create($len = 6) public static function create(int $len = 6): string
{ {
$res = ''; $res = '';
$chars = self::$chars; $chars = self::$chars;
@ -26,7 +26,7 @@ class FrontendUtils
return $res; return $res;
} }
public static function protect($str) public static function protect(string $str): string
{ {
$res = ''; $res = '';
$chars = self::$chars; $chars = self::$chars;
@ -37,7 +37,7 @@ class FrontendUtils
return $res; return $res;
} }
public static function unprotect($str) public static function unprotect(string $str): string
{ {
$res = ''; $res = '';
for ($i = 0; $i < strlen($str); $i++) { for ($i = 0; $i < strlen($str); $i++) {

View file

@ -60,7 +60,7 @@ class Install extends Process
); );
while ($record->fetch()) { while ($record->fetch()) {
if (preg_match('/^kutrl_(.*?)$/', $record->setting_id, $match)) { if (preg_match('/^kutrl_(.*?)$/', $record->setting_id, $match)) {
$cur = App::blogWorkspace()->openBlogWorkspace(); $cur = App::blogWorkspace()->openBlogWorkspaceCursor();
// avoid the use of serialize function // avoid the use of serialize function
if (in_array($record->setting_id, ['kutrl_srv_custom'])) { if (in_array($record->setting_id, ['kutrl_srv_custom'])) {
$cur->setting_value = json_encode(@unserialize(base64_decode((string) $record->setting_value))); $cur->setting_value = json_encode(@unserialize(base64_decode((string) $record->setting_value)));

View file

@ -49,7 +49,7 @@ class LinksListing extends Listing
} }
} }
$pager = new Pager((int) $filter->value('page'), $this->rs_count, (int) $filter->nb, 10); $pager = new Pager((int) $filter->value('page'), (int) $this->rs_count, (int) $filter->value('nb'), 10);
$cols = new ArrayObject([ $cols = new ArrayObject([
'kut_url' => (new Text('th', __('Link'))) 'kut_url' => (new Text('th', __('Link')))
@ -67,7 +67,7 @@ class LinksListing extends Listing
$lines = []; $lines = [];
while ($this->rs->fetch()) { while ($this->rs->fetch()) {
$lines[] = $this->linkLine(isset($links[$this->rs->kut_id])); $lines[] = $this->linkLine(isset($links[$this->rs->f('kut_id')]));
} }
echo echo
@ -103,13 +103,13 @@ class LinksListing extends Listing
if (null !== ($o = Utils::quickService($type))) { if (null !== ($o = Utils::quickService($type))) {
$type = (new Link()) $type = (new Link())
->href($o->home) ->href($o->get('home'))
->title($o->name) ->title($o->get('name'))
->text($o->name) ->text($o->get('name'))
->render(); ->render();
$hash = (new Link()) $hash = (new Link())
->href($o->url_base . $hash) ->href($o->get('url_base') . $hash)
->title($o->url_base . $hash) ->title($o->get('url_base') . $hash)
->text($hash) ->text($hash)
->render(); ->render();
} }
@ -125,7 +125,7 @@ class LinksListing extends Listing
->class('maximal') ->class('maximal')
->items([ ->items([
(new Link()) (new Link())
->href($o->home) ->href((string) $o?->get('home'))
->title($this->rs->kut_url) ->title($this->rs->kut_url)
->text($this->rs->kut_url), ->text($this->rs->kut_url),
]), ]),

View file

@ -12,6 +12,8 @@ use Dotclear\Database\Statement\{
SelectStatement, SelectStatement,
UpdateStatement UpdateStatement
}; };
use Dotclear\Interface\Core\ConnectionInterface;
use Exception;
/** /**
* @brief kUtRL logs class. * @brief kUtRL logs class.
@ -22,8 +24,8 @@ use Dotclear\Database\Statement\{
*/ */
class Logs class Logs
{ {
public $table; public string $table;
public $con; public ConnectionInterface $con;
public function __construct() public function __construct()
{ {
@ -35,11 +37,12 @@ class Logs
{ {
$sql = new SelectStatement(); $sql = new SelectStatement();
return $sql $rs = $sql
->column($sql->max('kut_id')) ->column($sql->max('kut_id'))
->from($this->table) ->from($this->table)
->select() ->select();
->f(0) + 1;
return is_null($rs) || $rs->isEmpty() ? 1 : (int) $rs->f(0) + 1;
} }
/** /**
@ -76,8 +79,6 @@ class Logs
throw $e; throw $e;
} }
return [];
} }
/** /**
@ -110,13 +111,12 @@ class Logs
$sql->and('kut_type = ' . $sql->quote($type)); $sql->and('kut_type = ' . $sql->quote($type));
} }
$sql $rs = $sql
->order('kut_dt DESC') ->order('kut_dt DESC')
->limit(1); ->limit(1)
->select();
$rs = $sql->select(); return is_null($rs) || $rs->isEmpty() ? false : $rs;
return $rs->isEmpty() ? false : $rs;
} }
public function clear(int $id): bool public function clear(int $id): bool
@ -141,8 +141,6 @@ class Logs
throw $e; throw $e;
} }
return false;
} }
public function delete(int $id): bool public function delete(int $id): bool
@ -167,7 +165,7 @@ class Logs
->and('kut_id = ' . $id) ->and('kut_id = ' . $id)
->select(); ->select();
$counter = $rs->isEmpty() ? 0 : (int) $rs->kut_counter; $counter = is_null($rs) || $rs->isEmpty() ? 0 : (int) $rs->kut_counter;
if ('get' == $do) { if ('get' == $do) {
return $counter; return $counter;
@ -190,6 +188,9 @@ class Logs
return $counter; return $counter;
} }
/**
* @param array<string, mixed> $params
*/
public function getLogs(array $params, bool $count_only = false): MetaRecord public function getLogs(array $params, bool $count_only = false): MetaRecord
{ {
$sql = new SelectStatement(); $sql = new SelectStatement();
@ -259,6 +260,6 @@ class Logs
$sql->limit($params['limit']); $sql->limit($params['limit']);
} }
return $sql->select(); return $sql->select() ?? MetaRecord::newFromArray([]);
} }
} }

View file

@ -21,6 +21,7 @@ use Dotclear\Helper\Html\Form\{
Text, Text,
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Exception;
/** /**
* @brief kUtRL manage class. * @brief kUtRL manage class.
@ -65,7 +66,7 @@ class Manage extends Process
if (!$kut->testService()) { if (!$kut->testService()) {
throw new Exception(__('Service is not well configured.')); throw new Exception(__('Service is not well configured.'));
} }
if (null !== $hash && !$kut->allow_custom_hash) { if (null !== $hash && !$kut->get('allow_custom_hash')) {
throw new Exception(__('This service does not allowed custom hash.')); throw new Exception(__('This service does not allowed custom hash.'));
} }
if (!$kut->isValidUrl($url)) { if (!$kut->isValidUrl($url)) {
@ -77,7 +78,7 @@ class Manage extends Process
if (!$kut->isProtocolUrl($url)) { if (!$kut->isProtocolUrl($url)) {
throw new Exception(__('This type of link is not allowed.')); throw new Exception(__('This type of link is not allowed.'));
} }
if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) { if (!$kut->get('allow_external_url') && !$kut->isBlogUrl($url)) {
throw new Exception(__('Short links are limited to this blog URL.')); throw new Exception(__('Short links are limited to this blog URL.'));
} }
if ($kut->isServiceUrl($url)) { if ($kut->isServiceUrl($url)) {
@ -88,7 +89,7 @@ class Manage extends Process
} }
if (false !== ($rs = $kut->isKnowUrl($url))) { if (false !== ($rs = $kut->isKnowUrl($url))) {
$url = $rs->url; $url = $rs->url;
$new_url = $kut->url_base . $rs->hash; $new_url = $kut->get('url_base') . $rs->hash;
Notices::addSuccessNotice(sprintf( Notices::addSuccessNotice(sprintf(
__('Short link for %s is %s'), __('Short link for %s is %s'),
@ -104,7 +105,7 @@ class Manage extends Process
throw new Exception(__('Failed to create short link. This could be caused by a service failure.')); throw new Exception(__('Failed to create short link. This could be caused by a service failure.'));
} else { } else {
$url = $rs->url; $url = $rs->url;
$new_url = $kut->url_base . $rs->hash; $new_url = $kut->get('url_base') . $rs->hash;
Notices::addSuccessNotice(sprintf( Notices::addSuccessNotice(sprintf(
__('Short link for %s is %s'), __('Short link for %s is %s'),
@ -113,7 +114,7 @@ class Manage extends Process
)); ));
# ex: Send new url to messengers # ex: Send new url to messengers
if (!empty($rs)) { if (!$rs->isEmpty()) {
App::behavior()->callBehavior('adminAfterKutrlCreate', $rs, __('New short URL')); App::behavior()->callBehavior('adminAfterKutrlCreate', $rs, __('New short URL'));
} }
} }
@ -149,14 +150,13 @@ class Manage extends Process
]) . ]) .
Notices::getNotices(); Notices::getNotices();
if (!isset($kut) || null === $kut) { if (null === $kut) {
echo (new Para()) echo (new Text('p', __('You must set an admin service.')))
->text(__('You must set an admin service.'))
->render(); ->render();
} else { } else {
$fields = []; $fields = [];
if ($kut->allow_custom_hash) { if ($kut->get('allow_custom_hash')) {
$fields[] = (new Para()) $fields[] = (new Para())
->items([ ->items([
(new Label(__('Custom short link:'), Label::OUTSIDE_LABEL_BEFORE)) (new Label(__('Custom short link:'), Label::OUTSIDE_LABEL_BEFORE))
@ -170,7 +170,7 @@ class Manage extends Process
->class('form-note') ->class('form-note')
->text(__('Only if you want a custom short link.')); ->text(__('Only if you want a custom short link.'));
if ($kut->admin_service == 'local') { if ($kut->get('admin_service') == 'local') {
$fields[] = (new Note()) $fields[] = (new Note())
->class('form-note') ->class('form-note')
->text(__('You can use "bob!!" if you want a semi-custom link, it starts with "bob" and "!!" will be replaced by an increment value.')); ->text(__('You can use "bob!!" if you want a semi-custom link, it starts with "bob" and "!!" will be replaced by an increment value.'));
@ -179,7 +179,7 @@ class Manage extends Process
echo (new Div()) echo (new Div())
->items([ ->items([
(new Text('h4', sprintf(__('Shorten link using service "%s"'), $kut->name))), (new Text('h4', sprintf(__('Shorten link using service "%s"'), $kut->get('name')))),
(new Form('create-link')) (new Form('create-link'))
->method('post') ->method('post')
->action(My::manageUrl()) ->action(My::manageUrl())

View file

@ -23,6 +23,7 @@ use Dotclear\Helper\Html\Form\{
Submit, Submit,
Text Text
}; };
use Exception;
/** /**
* @brief kUtRL manage links class. * @brief kUtRL manage links class.
@ -34,7 +35,7 @@ use Dotclear\Helper\Html\Form\{
class ManageLinks extends Process class ManageLinks extends Process
{ {
private static Filters $kutrl_filter; private static Filters $kutrl_filter;
private static Linkslisting $kutrl_listing; private static LinksListing $kutrl_listing;
public static function init(): bool public static function init(): bool
{ {

View file

@ -25,7 +25,7 @@ class My extends MyPlugin
/** /**
* List of template tag which content URL that can be shorten. * List of template tag which content URL that can be shorten.
* *
* @var array USED_TAGS * @var array<int, string> USED_TAGS
*/ */
public const USED_TAGS = [ public const USED_TAGS = [
'AttachmentURL', 'AttachmentURL',

View file

@ -21,10 +21,24 @@ use Dotclear\Helper\Network\HttpClient;
*/ */
class Service class Service
{ {
/**
* @var \Dotclear\Interface\Core\ErrorInterface $error
*/
public $error; public $error;
/**
* @var \Dotclear\Interface\Core\BlogWorkspaceInterface $settings
*/
public $settings; public $settings;
/**
* @var Logs $log
*/
public $log; public $log;
/**
* @var array<string, mixed> $config
*/
protected $config = []; protected $config = [];
public function __construct() public function __construct()
@ -37,7 +51,7 @@ class Service
$this->init(); $this->init();
// Force setting // Force setting
$allow_external_url = $this->settings?->get('allow_external_url'); $allow_external_url = $this->settings->get('allow_external_url');
$this->config['allow_external_url'] = null === $allow_external_url ? $this->config['allow_external_url'] = null === $allow_external_url ?
true : $allow_external_url; true : $allow_external_url;
@ -60,14 +74,22 @@ class Service
); );
} }
# Magic get for config values /**
public function __get($k) * Magic get for config values.
*
* @return mixed
*/
public function __get(string $k)
{ {
return $this->get($k); return $this->get($k);
} }
# get config value /**
public function get($k) * Get config value.
*
* @return mixed
*/
public function get(string $k)
{ {
return $this->config[$k] ?? null; return $this->config[$k] ?? null;
} }
@ -110,19 +132,19 @@ class Service
# Test if an url contents know prefix # Test if an url contents know prefix
public function isServiceUrl(string $url): bool public function isServiceUrl(string $url): bool
{ {
return strpos($url, $this->url_base) === 0; return strpos($url, $this->get('url_base')) === 0;
} }
# Test if an url is long enoutgh # Test if an url is long enoutgh
public function isLongerUrl(string $url): bool public function isLongerUrl(string $url): bool
{ {
return (strlen($url) >= (int) $this->url_min_len); return (strlen($url) >= (int) $this->get('url_min_len'));
} }
# Test if an url protocol (eg: http://) is allowed # Test if an url protocol (eg: http://) is allowed
public function isProtocolUrl(string $url): bool public function isProtocolUrl(string $url): bool
{ {
foreach ($this->allow_protocols as $protocol) { foreach ($this->get('allow_protocols') as $protocol) {
if (empty($protocol)) { if (empty($protocol)) {
continue; continue;
} }
@ -150,7 +172,7 @@ class Service
*/ */
public function isKnowUrl(string $url) public function isKnowUrl(string $url)
{ {
return $this->log->select($url, null, $this->id, 'kutrl'); return $this->log->select($url, null, $this->get('id'), 'kutrl');
} }
/** /**
@ -160,7 +182,7 @@ class Service
*/ */
public function isKnowHash(string $hash) public function isKnowHash(string $hash)
{ {
return $this->log->select(null, $hash, $this->id, 'kutrl'); return $this->log->select(null, $hash, $this->get('id'), 'kutrl');
} }
/** /**
@ -171,10 +193,10 @@ class Service
public function hash(string $url, ?string $hash = null) public function hash(string $url, ?string $hash = null)
{ {
$url = trim(App::con()->escapeStr((string) $url)); $url = trim(App::con()->escapeStr((string) $url));
if ('undefined' === $this->id) { if ('undefined' === $this->get('id')) {
return false; return false;
} }
if ($hash && !$this->allow_custom_hash) { if ($hash && !$this->get('allow_custom_hash')) {
return false; return false;
} }
if ($this->isServiceUrl($url)) { if ($this->isServiceUrl($url)) {
@ -183,7 +205,7 @@ class Service
if (!$this->isLongerUrl($url)) { if (!$this->isLongerUrl($url)) {
return false; return false;
} }
if (!$this->allow_external_url && $this->isBlogUrl($url)) { if (!$this->get('allow_external_url') && $this->isBlogUrl($url)) {
return false; return false;
} }
if ($hash && false !== ($rs = $this->isKnowHash($hash))) { if ($hash && false !== ($rs = $this->isKnowHash($hash))) {
@ -262,14 +284,21 @@ class Service
/** /**
* Post request. * Post request.
*
* @param array<int, string> $headers
* @return mixed
*/ */
public static function post(string $url, $data, bool $verbose = true, bool $get = false, $headers = []) public static function post(string $url, mixed $data, bool $verbose = true, bool $get = false, array $headers = [])
{ {
$client = HttpClient::initClient($url, $url); $client = HttpClient::initClient($url, $url);
if (false === $client) {
return false;
}
$client->setUserAgent('kUtRL - https://github.com/JcDenis/kUtRL'); $client->setUserAgent('kUtRL - https://github.com/JcDenis/kUtRL');
$client->setPersistReferers(false); $client->setPersistReferers(false);
if (is_array($headers) && !empty($headers)) { if (!empty($headers)) {
foreach ($headers as $header) { foreach ($headers as $header) {
$client->setMoreHeader($header); $client->setMoreHeader($header);
} }

View file

@ -7,7 +7,7 @@ namespace Dotclear\Plugin\kUtRL\Service;
use Dotclear\Helper\Html\Form\{ use Dotclear\Helper\Html\Form\{
Div, Div,
Input, Input,
label, Label,
Note, Note,
Para Para
}; };
@ -22,21 +22,22 @@ use Dotclear\Plugin\kUtRL\Service;
*/ */
class ServiceBilbolinks extends Service class ServiceBilbolinks extends Service
{ {
protected $config = [
'id' => 'bilbolinks',
'name' => 'BilboLinks',
'home' => 'http://www.tux-planet.fr/bilbobox/',
];
protected function init(): void protected function init(): void
{ {
$base = (string) $this->settings->get('srv_bilbolinks_base'); $base = (string) $this->settings->get('srv_bilbolinks_base');
if (!empty($base) && substr($base, -1, 1) != '/') { if (!empty($base) && substr($base, -1, 1) != '/') {
$base .= '/'; $base .= '/';
} }
$this->config['url_api'] = $base . 'api.php';
$this->config['url_base'] = $base; $this->config = [
$this->config['url_min_len'] = 25; 'id' => 'bilbolinks',
'name' => 'BilboLinks',
'home' => 'http://www.tux-planet.fr/bilbobox/',
'url_api' => $base . 'api.php',
'url_base' => $base,
'url_min_len' => 25,
];
} }
public function saveSettings(): void public function saveSettings(): void
@ -72,14 +73,14 @@ class ServiceBilbolinks extends Service
public function testService(): bool public function testService(): bool
{ {
if (empty($this->url_base)) { if (empty($this->get('url_base'))) {
$this->error->add(__('Service is not well configured.')); $this->error->add(__('Service is not well configured.'));
return false; return false;
} }
$arg = ['longurl' => urlencode($this->url_test)]; $arg = ['longurl' => urlencode($this->get('url_test'))];
if (!self::post($this->url_api, $arg, true, true)) { if (!self::post($this->get('url_api'), $arg, true, true)) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -92,7 +93,7 @@ class ServiceBilbolinks extends Service
{ {
$arg = ['longurl' => $url]; $arg = ['longurl' => $url];
if (!($response = self::post($this->url_api, $arg, true, true))) { if (!($response = self::post($this->get('url_api'), $arg, true, true))) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -102,10 +103,11 @@ class ServiceBilbolinks extends Service
return false; return false;
} }
return $this->fromValue( return $this->fromValue(
str_replace($this->url_base, '', $response), (string) str_replace($this->get('url_base'), '', $response),
$url, $url,
$this->id $this->get('id')
); );
} }
} }

View file

@ -7,7 +7,7 @@ namespace Dotclear\Plugin\kUtRL\Service;
use Dotclear\Helper\Html\Form\{ use Dotclear\Helper\Html\Form\{
Div, Div,
Input, Input,
label, Label,
Note, Note,
Para Para
}; };
@ -22,24 +22,27 @@ use Dotclear\Plugin\kUtRL\Service;
*/ */
class ServiceBitly extends Service class ServiceBitly extends Service
{ {
protected $config = [ /**
'id' => 'bitly', * @var array<string, mixed> $args
'name' => 'bit.ly', */
'home' => 'https://bit.ly',
'url_api' => 'https://api-ssl.bitly.com/v4/',
'url_base' => 'https://bit.ly/',
'url_min_len' => 25,
'allow_protocols' => ['http://', 'https://'],
];
private $args = [ private $args = [
'apiKey' => '', 'apiKey' => '',
]; ];
protected function init(): void protected function init(): void
{ {
$this->config = [
'id' => 'bitly',
'name' => 'bit.ly',
'home' => 'https://bit.ly',
'url_api' => 'https://api-ssl.bitly.com/v4/',
'url_base' => 'https://bit.ly/',
'url_min_len' => 25,
'allow_protocols' => ['http://', 'https://'],
];
$this->args['apiKey'] = $this->settings->get('srv_bitly_apikey'); $this->args['apiKey'] = $this->settings->get('srv_bitly_apikey');
} }
@ -76,7 +79,7 @@ class ServiceBitly extends Service
} }
$args = json_encode(['domain' => 'bit.ly', 'bitlink_id' => 'bit.ly/WP9vc'], JSON_UNESCAPED_SLASHES); $args = json_encode(['domain' => 'bit.ly', 'bitlink_id' => 'bit.ly/WP9vc'], JSON_UNESCAPED_SLASHES);
if (!($response = self::post($this->url_api . 'expand', $args, true, false, $this->headers()))) { if (!($response = self::post($this->get('url_api') . 'expand', $args, true, false, $this->headers()))) {
$this->error->add(__('Failed to call service.')); $this->error->add(__('Failed to call service.'));
return false; return false;
@ -89,7 +92,7 @@ class ServiceBitly extends Service
{ {
$args = json_encode(['domain' => 'bit.ly', 'long_url' => $url]); $args = json_encode(['domain' => 'bit.ly', 'long_url' => $url]);
if (!($response = self::post($this->url_api . 'shorten', $args, true, false, $this->headers()))) { if (!($response = self::post($this->get('url_api') . 'shorten', $args, true, false, $this->headers()))) {
$this->error->add(__('Failed to call service.')); $this->error->add(__('Failed to call service.'));
return false; return false;
@ -98,12 +101,15 @@ class ServiceBitly extends Service
$rsp = json_decode($response); $rsp = json_decode($response);
return $this->fromValue( return $this->fromValue(
str_replace($this->url_base, '', (string) $rsp->link), str_replace($this->get('url_base'), '', (string) $rsp->link),
(string) $rsp->long_url, (string) $rsp->long_url,
$this->id $this->get('id')
); );
} }
/**
* @return array<int, string>
*/
private function headers() private function headers()
{ {
return ['Authorization: Bearer ' . $this->args['apiKey'], 'Content-Type: application/json']; return ['Authorization: Bearer ' . $this->args['apiKey'], 'Content-Type: application/json'];

View file

@ -10,7 +10,8 @@ use Dotclear\Helper\Html\Form\{
Input, Input,
Label, Label,
Note, Note,
Para Para,
Text
}; };
use Dotclear\Plugin\kUtRL\Service; use Dotclear\Plugin\kUtRL\Service;
@ -23,11 +24,6 @@ use Dotclear\Plugin\kUtRL\Service;
*/ */
class ServiceCustom extends Service class ServiceCustom extends Service
{ {
protected $config = [
'id' => 'custom',
'name' => 'Custom',
];
protected function init(): void protected function init(): void
{ {
$config = json_decode((string) $this->settings->get('srv_custom'), true); $config = json_decode((string) $this->settings->get('srv_custom'), true);
@ -35,12 +31,17 @@ class ServiceCustom extends Service
$config = []; $config = [];
} }
$this->config['url_api'] = $config['url_api'] ?? ''; $this->config = [
$this->config['url_base'] = $config['url_base'] ?? ''; 'id' => 'custom',
$this->config['url_param'] = $config['url_param'] ?? ''; 'name' => 'Custom',
$this->config['url_encode'] = !empty($config['url_api']);
$this->config['url_min_length'] = strlen($this->url_base) + 2; 'url_api' => $config['url_api'] ?? '',
'url_base' => $config['url_base'] ?? '',
'url_param' => $config['url_param'] ?? '',
'url_encode' => !empty($config['url_api']),
'url_min_length' => strlen($config['url_base'] ?? '') + 2,
];
} }
public function saveSettings(): void public function saveSettings(): void
@ -70,13 +71,13 @@ class ServiceCustom extends Service
return (new Div()) return (new Div())
->items([ ->items([
(new Para()) (new Text(
->text( 'p',
__('You can set a configurable service.') . '<br />' . __('You can set a configurable service.') . '<br />' .
__('It consists on a simple query to an URL with only one param.') . '<br />' . __('It consists on a simple query to an URL with only one param.') . '<br />' .
__('It must respond with a http code 200 on success.') . '<br />' . __('It must respond with a http code 200 on success.') . '<br />' .
__('It must returned the short URL (or only hash) in clear text.') __('It must returned the short URL (or only hash) in clear text.')
), )),
(new Para()) (new Para())
->items([ ->items([
(new Label(__('API URL:'), Label::OUTSIDE_LABEL_BEFORE)) (new Label(__('API URL:'), Label::OUTSIDE_LABEL_BEFORE))
@ -126,12 +127,12 @@ class ServiceCustom extends Service
public function testService(): bool public function testService(): bool
{ {
if (empty($this->url_api)) { if (empty($this->get('url_api'))) {
return false; return false;
} }
$url = $this->url_encode ? urlencode($this->url_test) : $this->url_test; $url = $this->get('url_encode') ? urlencode($this->get('url_test')) : $this->get('url_test');
$arg = [$this->url_param => $url]; $arg = [$this->get('url_param') => $url];
if (!self::post($this->url_api, $arg, true, true)) { if (!self::post($this->get('url_api'), $arg, true, true)) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -142,19 +143,19 @@ class ServiceCustom extends Service
public function createHash(string $url, ?string $hash = null) public function createHash(string $url, ?string $hash = null)
{ {
$enc = $this->url_encode ? urlencode($url) : $url; $enc = $this->get('url_encode') ? urlencode($url) : $url;
$arg = [$this->url_param => $enc]; $arg = [$this->get('url_param') => $enc];
if (!($response = self::post($this->url_api, $arg, true, true))) { if (!($response = self::post($this->get('url_api'), $arg, true, true))) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
} }
return $this->fromValue( return $this->fromValue(
str_replace($this->url_base, '', $response), (string) str_replace($this->get('url_base'), '', $response),
$url, $url,
$this->id $this->get('id')
); );
} }
} }

View file

@ -7,7 +7,6 @@ namespace Dotclear\Plugin\kUtRL\Service;
use Dotclear\Helper\Html\Form\{ use Dotclear\Helper\Html\Form\{
Div, Div,
Note, Note,
Para,
Text Text
}; };
use Dotclear\Plugin\kUtRL\Service; use Dotclear\Plugin\kUtRL\Service;
@ -49,8 +48,7 @@ class ServiceDefault extends Service
(new Note()) (new Note())
->class('form-note') ->class('form-note')
->text(__('There is nothing to configure for this service.')), ->text(__('There is nothing to configure for this service.')),
(new Para()) (new Text('p', __('There is nothing to configure for this service.'))),
->text(__('There is nothing to configure for this service.')),
(new Text( (new Text(
'', '',
'<dl>' . '<dl>' .
@ -71,10 +69,10 @@ class ServiceDefault extends Service
public function testService(): bool public function testService(): bool
{ {
$url = $this->url_encode ? urlencode($this->url_test) : $this->url_test; $url = $this->get('url_encode') ? urlencode($this->get('url_test')) : $this->get('url_test');
$arg = [$this->url_param => urlencode($this->url_test)]; $arg = [$this->get('url_param') => urlencode($this->get('url_test'))];
if (!self::post($this->url_api, $arg, true, true)) { if (!self::post($this->get('url_api'), $arg, true, true)) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -85,19 +83,19 @@ class ServiceDefault extends Service
public function createHash(string $url, ?string $hash = null) public function createHash(string $url, ?string $hash = null)
{ {
$enc = $this->url_encode ? urlencode($url) : $url; $enc = $this->get('url_encode') ? urlencode($url) : $url;
$arg = [$this->url_param => $url]; $arg = [$this->get('url_param') => $url];
if (!($response = self::post($this->url_api, $arg, true, true))) { if (!($response = self::post($this->get('url_api'), $arg, true, true))) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
} }
return $this->fromValue( return $this->fromValue(
str_replace($this->url_base, '', $response), (string) str_replace($this->get('url_base'), '', $response),
$url, $url,
$this->id $this->get('id')
); );
} }
} }

View file

@ -15,20 +15,23 @@ use Dotclear\Plugin\kUtRL\Service;
*/ */
class ServiceIsgd extends Service class ServiceIsgd extends Service
{ {
protected $config = [ protected function init(): void
'id' => 'isgd', {
'name' => 'is.gd', $this->config = [
'home' => 'http://is.gd/', 'id' => 'isgd',
'name' => 'is.gd',
'home' => 'http://is.gd/',
'url_api' => 'http://is.gd/api.php', 'url_api' => 'http://is.gd/api.php',
'url_base' => 'http://is.gd/', 'url_base' => 'http://is.gd/',
'url_min_length' => 25, 'url_min_length' => 25,
]; ];
}
public function testService(): bool public function testService(): bool
{ {
$arg = ['longurl' => urlencode($this->url_test)]; $arg = ['longurl' => urlencode($this->get('url_test'))];
if (!self::post($this->url_api, $arg, true, true)) { if (!self::post($this->get('url_api'), $arg, true, true)) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -41,16 +44,16 @@ class ServiceIsgd extends Service
{ {
$arg = ['longurl' => $url]; $arg = ['longurl' => $url];
if (!($response = self::post($this->url_api, $arg, true, true))) { if (!($response = self::post($this->get('url_api'), $arg, true, true))) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
} }
return $this->fromValue( return $this->fromValue(
str_replace($this->url_base, '', $response), (string) str_replace($this->get('url_base'), '', $response),
$url, $url,
$this->id $this->get('id')
); );
} }
} }

View file

@ -17,6 +17,7 @@ use Dotclear\Helper\Html\Form\{
}; };
use Dotclear\Helper\Html\Html; use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\kUtRL\Service; use Dotclear\Plugin\kUtRL\Service;
use Exception;
/** /**
* @brief kUtRL local service class. * @brief kUtRL local service class.
@ -27,21 +28,21 @@ use Dotclear\Plugin\kUtRL\Service;
*/ */
class ServiceLocal extends Service class ServiceLocal extends Service
{ {
protected $config = [
'id' => 'local',
'name' => 'kUtRL',
'home' => 'https://github.com/JcDenis/kUtRL',
'allow_custom_hash' => true,
];
protected function init(): void protected function init(): void
{ {
$protocols = (string) $this->settings->get('srv_local_protocols'); $protocols = (string) $this->settings->get('srv_local_protocols');
$this->config['allow_protocols'] = empty($protocols) ? [] : explode(',', $protocols);
$this->config['url_base'] = App::blog()->url() . App::url()->getBase('kutrl') . '/'; $this->config = [
$this->config['url_min_len'] = strlen($this->url_base) + 2; 'id' => 'local',
'name' => 'kUtRL',
'home' => 'https://github.com/JcDenis/kUtRL',
'allow_custom_hash' => true,
'allow_protocols' => empty($protocols) ? [] : explode(',', $protocols),
'url_base' => App::blog()->url() . App::url()->getBase('kutrl') . '/',
'url_min_len' => strlen(App::blog()->url() . App::url()->getBase('kutrl') . '/') + 2,
];
} }
public function saveSettings(): void public function saveSettings(): void
@ -115,13 +116,13 @@ class ServiceLocal extends Service
(new Text( (new Text(
'p', 'p',
__('This service use your own Blog to shorten and serve URL.') . '<br />' . __('This service use your own Blog to shorten and serve URL.') . '<br />' .
sprintf(__('This means that with this service short links start with "%s".'), $this->url_base) sprintf(__('This means that with this service short links start with "%s".'), $this->get('url_base'))
)), )),
(new Text( (new Text(
'p', 'p',
__("You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog.") . __("You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog.") .
( (
preg_match('/index\.php/', $this->url_base) ? preg_match('/index\.php/', $this->get('url_base')) ?
' ' . ' ' .
__("We recommand that you use a rewrite engine in order to remove 'index.php' from your blog's URL.") . __("We recommand that you use a rewrite engine in order to remove 'index.php' from your blog's URL.") .
'<br /><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters">' . '<br /><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters">' .
@ -143,7 +144,7 @@ class ServiceLocal extends Service
public function testService(): bool public function testService(): bool
{ {
$ap = $this->allow_protocols; $ap = $this->get('allow_protocols');
if (!empty($ap)) { if (!empty($ap)) {
return true; return true;
} }
@ -161,13 +162,13 @@ class ServiceLocal extends Service
# Normal link # Normal link
if ($hash === null) { if ($hash === null) {
$type = 'localnormal'; $type = 'localnormal';
$rs_hash = $this->next($this->last('localnormal')); $rs_hash = $this->next($this->last('localnormal'));
# Mixed custom link # Mixed custom link
} elseif (preg_match('/^([A-Za-z0-9]{2,})\!\!$/', $hash, $m)) { } elseif (preg_match('/^([A-Za-z0-9]{2,})\!\!$/', $hash, $m)) {
$type = 'localmix'; $type = 'localmix';
$rs_hash = $m[1] . $this->next(-1, $m[1]); $rs_hash = $m[1] . $this->next('-1', $m[1]);
# Custom link # Custom link
} elseif (preg_match('/^[A-Za-z0-9\.\-\_]{2,}$/', $hash)) { } elseif (preg_match('/^[A-Za-z0-9\.\-\_]{2,}$/', $hash)) {
@ -176,7 +177,7 @@ class ServiceLocal extends Service
return false; return false;
} }
$type = 'localcustom'; $type = 'localcustom';
$rs_hash = $hash; $rs_hash = $hash;
# Wrong char in custom hash # Wrong char in custom hash
@ -195,23 +196,23 @@ class ServiceLocal extends Service
$rs_url, $rs_url,
$rs_type $rs_type
); );
} catch (Exception $e) { } catch (Exception) {
$this->error->add(__('Failed to save link.')); $this->error->add(__('Failed to save link.'));
} }
return false; return false;
} }
protected function last($type) protected function last(string $type): string
{ {
return false === ($rs = $this->log->select(null, null, $type, 'local')) ? return false === ($rs = $this->log->select(null, null, $type, 'local')) ?
-1 : $rs->hash; '-1' : $rs->hash;
} }
protected function next($last_id, $prefix = '') protected function next(string $last_id, string $prefix = ''): string
{ {
if ($last_id == -1) { if ($last_id == '-1') {
$next_id = 0; $next_id = '0';
} else { } else {
for ($x = 1; $x <= strlen($last_id); $x++) { for ($x = 1; $x <= strlen($last_id); $x++) {
$pos = strlen($last_id) - $x; $pos = strlen($last_id) - $x;
@ -231,7 +232,7 @@ class ServiceLocal extends Service
$next_id : $this->next($next_id, $prefix); $next_id : $this->next($next_id, $prefix);
} }
protected function append($id) protected function append(string $id): string
{ {
$id = str_split($id); $id = str_split($id);
for ($x = 0; $x < count($id); $x++) { for ($x = 0; $x < count($id); $x++) {
@ -241,7 +242,7 @@ class ServiceLocal extends Service
return implode($id) . '0'; return implode($id) . '0';
} }
protected function increment($id, $pos) protected function increment(string $id, int $pos): string
{ {
$id = str_split($id); $id = str_split($id);
$char = $id[$pos]; $char = $id[$pos];
@ -262,7 +263,7 @@ class ServiceLocal extends Service
return implode($id); return implode($id);
} }
public function getUrl(string $hash) public function getUrl(string $hash): bool|string
{ {
if (false === ($rs = $this->log->select(null, $hash, null, 'local'))) { if (false === ($rs = $this->log->select(null, $hash, null, 'local'))) {
return false; return false;

View file

@ -22,12 +22,9 @@ use Dotclear\Plugin\kUtRL\Service;
*/ */
class ServiceYourls extends Service class ServiceYourls extends Service
{ {
protected $config = [ /**
'id' => 'yourls', * @var array<string, string> $args
'name' => 'YOURLS', */
'home' => 'http://yourls.org',
];
private $args = [ private $args = [
'username' => '', 'username' => '',
'password' => '', 'password' => '',
@ -43,9 +40,15 @@ class ServiceYourls extends Service
$base = (string) $this->settings->get('srv_yourls_base'); $base = (string) $this->settings->get('srv_yourls_base');
//if (!empty($base) && substr($base,-1,1) != '/') $base .= '/'; //if (!empty($base) && substr($base,-1,1) != '/') $base .= '/';
$this->config['url_api'] = $base; $this->config = [
$this->config['url_base'] = $base; 'id' => 'yourls',
$this->config['url_min_len'] = strlen($base) + 3; 'name' => 'YOURLS',
'home' => 'http://yourls.org',
'url_api' => $base,
'url_base' => $base,
'url_min_len' => strlen($base) + 3,
];
} }
public function saveSettings(): void public function saveSettings(): void
@ -108,9 +111,9 @@ class ServiceYourls extends Service
} }
$args = $this->args; $args = $this->args;
$args['url'] = $this->url_test; $args['url'] = $this->get('url_test');
if (!($response = self::post($this->url_api, $this->args, true))) { if (!($response = self::post($this->get('url_api'), $this->args, true))) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -129,7 +132,7 @@ class ServiceYourls extends Service
{ {
$args = array_merge($this->args, ['url' => $url]); $args = array_merge($this->args, ['url' => $url]);
if (!($response = self::post($this->url_api, $args, true))) { if (!($response = self::post($this->get('url_api'), $args, true))) {
$this->error->add(__('Service is unavailable.')); $this->error->add(__('Service is unavailable.'));
return false; return false;
@ -141,7 +144,7 @@ class ServiceYourls extends Service
return $this->fromValue( return $this->fromValue(
$rsp->url[0]->keyword, $rsp->url[0]->keyword,
$url, $url,
$this->id $this->get('id')
); );
} }
$this->error->add(__('Unreadable service response.')); $this->error->add(__('Unreadable service response.'));

View file

@ -21,7 +21,7 @@ class Utils
* *
* @return array<string,string> The services list * @return array<string,string> The services list
*/ */
public static function getServices(): ?array public static function getServices(): array
{ {
$list = App::behavior()->getBehavior('kutrlService'); $list = App::behavior()->getBehavior('kutrlService');
@ -54,7 +54,7 @@ class Utils
return null; return null;
} }
$services = self::getServices(); $services = self::getServices();
if (isset($services[$id])) { if (isset($services[$id]) && is_subclass_of($services[$id], Service::class)) {
return new $services[$id](); return new $services[$id]();
} }
} catch (Exception $e) { } catch (Exception $e) {
@ -66,9 +66,9 @@ class Utils
/** /**
* Silently try to load a service according to its place. * Silently try to load a service according to its place.
* *
* @param string The execution context * @param string $place The execution context
* *
* @return Service The service or null on error * @return null|Service The service or null on error
*/ */
public static function quickPlace(string $place = 'plugin'): ?Service public static function quickPlace(string $place = 'plugin'): ?Service
{ {
@ -89,11 +89,11 @@ class Utils
/** /**
* Silently try to reduce url (using 'plugin' place). * Silently try to reduce url (using 'plugin' place).
* *
* @param string $url The long URL * @param string $url The long URL
* @param string $cutom The custom short URI * @param string $custom The custom short URI
* @param string $place The context * @param string $place The context
* *
* @return string The short url on success else the long url * @return string The short url on success else the long url
*/ */
public static function quickReduce(string $url, ?string $custom = null, string $place = 'plugin'): string public static function quickReduce(string $url, ?string $custom = null, string $place = 'plugin'): string
{ {
@ -107,7 +107,7 @@ class Utils
return $url; return $url;
} }
return $srv->url_base . $rs->hash; return $srv->get('url_base') . $rs->hash;
} catch (Exception $e) { } catch (Exception $e) {
} }

View file

@ -177,23 +177,23 @@ class Widgets
return ''; return '';
} }
$type = in_array($w->type, ['localnormal', 'localmix', 'localcustom']) ? $type = in_array($w->get('type'), ['localnormal', 'localmix', 'localcustom']) ?
"AND kut_type ='" . $w->type . "' " : "AND kut_type ='" . $w->get('type') . "' " :
'AND kut_type ' . App::con()->in(['localnormal', 'localmix', 'localcustom']) . ' '; 'AND kut_type ' . App::con()->in(['localnormal', 'localmix', 'localcustom']) . ' ';
$hide = (bool) $w->hideempty ? 'AND kut_counter > 0 ' : ''; $hide = (bool) $w->get('hideempty') ? 'AND kut_counter > 0 ' : '';
$more = ''; $more = '';
if ($w->type == 'localmix' && '' != $w->mixprefix) { if ($w->get('type') == 'localmix' && '' != $w->get('mixprefix')) {
$more = "AND kut_hash LIKE '" . App::con()->escapeStr((string) $w->mixprefix) . "%' "; $more = "AND kut_hash LIKE '" . App::con()->escapeStr((string) $w->get('mixprefix')) . "%' ";
} }
$order = ($w->sortby && in_array($w->sortby, ['kut_dt', 'kut_counter', 'kut_hash'])) ? $order = ($w->get('sortby') && in_array($w->get('sortby'), ['kut_dt', 'kut_counter', 'kut_hash'])) ?
$w->sortby : 'kut_dt'; $w->get('sortby') : 'kut_dt';
$order .= $w->sort == 'desc' ? ' DESC' : ' ASC'; $order .= $w->get('sort') == 'desc' ? ' DESC' : ' ASC';
$limit = App::con()->limit(abs((int) $w->limit)); $limit = App::con()->limit(abs((int) $w->get('limit')));
$rs = App::con()->select( $rs = App::con()->select(
'SELECT kut_counter, kut_hash ' . 'SELECT kut_counter, kut_hash ' .
@ -215,16 +215,12 @@ class Widgets
$hash = $rs->kut_hash; $hash = $rs->kut_hash;
$url = App::blog()->url() . App::url()->getBase('kutrl') . '/' . $hash; $url = App::blog()->url() . App::url()->getBase('kutrl') . '/' . $hash;
$cut_len = - abs((int) $w->urllen); $cut_len = abs((int) $w->get('urllen'));
if (strlen($url) > $cut_len) { if (strlen($url) > $cut_len) {
$url = '...' . substr($url, $cut_len); $url = '...' . substr($url, 0, $cut_len);
} }
/*
if (strlen($hash) > $cut_len) {
$url = '...'.substr($hash, $cut_len);
}
//*/
if ($rs->kut_counter == 0) { if ($rs->kut_counter == 0) {
$counttext = __('never followed'); $counttext = __('never followed');
} elseif ($rs->kut_counter == 1) { } elseif ($rs->kut_counter == 1) {
@ -239,7 +235,7 @@ class Widgets
str_replace( str_replace(
['%rank%', '%hash%', '%url%', '%count%', '%counttext%'], ['%rank%', '%hash%', '%url%', '%count%', '%counttext%'],
[$rank, $hash, $url, $rs->kut_counter, $counttext], [$rank, $hash, $url, $rs->kut_counter, $counttext],
$w->text $w->get('text')
) . ) .
'</a></li>'; '</a></li>';
} }

View file

@ -21,14 +21,14 @@ class Wiki
# Do nothing on comment preview and post preview # Do nothing on comment preview and post preview
if (!empty($_POST['preview']) if (!empty($_POST['preview'])
|| (App::task()->checkContext('FRONTEND') && App::frontend()->context()->preview) || (App::task()->checkContext('FRONTEND') && App::frontend()->context()->preview)
|| !My::settings()?->get('active') || !My::settings()->get('active')
) { ) {
return; return;
} }
if (null === ($kut = Utils::quickPlace('wiki'))) { if (null === ($kut = Utils::quickPlace('wiki'))) {
return; return;
} }
foreach ($kut->allow_protocols as $protocol) { foreach ($kut->get('allow_protocols') as $protocol) {
$wiki2xhtml->registerFunction( $wiki2xhtml->registerFunction(
'url:' . $protocol, 'url:' . $protocol,
self::transform(...) self::transform(...)
@ -41,7 +41,7 @@ class Wiki
*/ */
public static function transform(string $url, string $content): ?array public static function transform(string $url, string $content): ?array
{ {
if (!My::settings()?->get('active')) { if (!My::settings()->get('active')) {
return null; return null;
} }
if (null === ($kut = Utils::quickPlace('wiki'))) { if (null === ($kut = Utils::quickPlace('wiki'))) {
@ -59,8 +59,8 @@ class Wiki
} }
$res = []; $res = [];
$testurl = strlen($rs->url) > 35 ? substr($rs->url, 0, 35) . '...' : $rs->url; $testurl = strlen($rs->url) > 35 ? substr($rs->url, 0, 35) . '...' : $rs->url;
$res['url'] = $kut->url_base . $rs->hash; $res['url'] = $kut->get('url_base') . $rs->hash;
$res['title'] = sprintf(__('%s (Shorten with %s)'), $rs->url, __($kut->name)); $res['title'] = sprintf(__('%s (Shorten with %s)'), $rs->url, __($kut->get('name')));
if ($testurl == $content) { if ($testurl == $content) {
$res['content'] = $res['url']; $res['content'] = $res['url'];
} }