Compare commits
10 Commits
76b78278e0
...
cde1aa319a
Author | SHA1 | Date |
---|---|---|
Jean-Christian Paul Denis | cde1aa319a | |
Jean-Christian Paul Denis | 5b5010edbc | |
Jean-Christian Paul Denis | 9690644d9e | |
Jean-Christian Paul Denis | 5dcc345e17 | |
Jean-Christian Paul Denis | 047413f71f | |
Jean-Christian Paul Denis | c3f11fca39 | |
Jean-Christian Paul Denis | 2011665b7e | |
Jean-Christian Paul Denis | e124d25b53 | |
Jean-Christian Paul Denis | 44994905aa | |
Jean-Christian Paul Denis | 6e656d65f8 |
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -1,3 +1,21 @@
|
||||||
|
1.3.1 - 2023.06.17
|
||||||
|
- require dotclear 2.26
|
||||||
|
- fix php7.4 compatibility
|
||||||
|
|
||||||
|
1.3 - 2023.05.13
|
||||||
|
- require dotclear 2.26
|
||||||
|
- some fixes for dotclear 2.26 stable
|
||||||
|
|
||||||
|
1.2.1 - 2023.04.23
|
||||||
|
- require dotclear 2.26
|
||||||
|
- use lastest dotclear namespace (database)
|
||||||
|
|
||||||
|
1.2 - 2023.04.22
|
||||||
|
- require dotclear 2.26
|
||||||
|
- use lastest dotclear namespace
|
||||||
|
- fix cosmetic nullsafe warnings
|
||||||
|
- add plugin Uninstaller features
|
||||||
|
|
||||||
1.1 - 2023.03.26
|
1.1 - 2023.03.26
|
||||||
- require dotclear 2.26
|
- require dotclear 2.26
|
||||||
- use namespace
|
- use namespace
|
||||||
|
|
|
@ -18,7 +18,7 @@ $this->registerModule(
|
||||||
'Feed after content',
|
'Feed after content',
|
||||||
'Add RSS/Atom feeds after entries content',
|
'Add RSS/Atom feeds after entries content',
|
||||||
'Jean-Christian Denis and Contributors',
|
'Jean-Christian Denis and Contributors',
|
||||||
'1.1',
|
'1.3.1',
|
||||||
[
|
[
|
||||||
'requires' => [['core', '2.26']],
|
'requires' => [['core', '2.26']],
|
||||||
'permissions' => dcCore::app()->auth->makePermissions([
|
'permissions' => dcCore::app()->auth->makePermissions([
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
<modules xmlns:da="http://dotaddict.org/da/">
|
<modules xmlns:da="http://dotaddict.org/da/">
|
||||||
<module id="fac">
|
<module id="fac">
|
||||||
<name>Feed after content</name>
|
<name>Feed after content</name>
|
||||||
<version>1.1</version>
|
<version>1.3.1</version>
|
||||||
<author>Jean-Christian Denis and Contributors</author>
|
<author>Jean-Christian Denis and Contributors</author>
|
||||||
<desc>Add RSS/Atom feeds after entries content</desc>
|
<desc>Add RSS/Atom feeds after entries content</desc>
|
||||||
<file>https://github.com/JcDenis/fac/releases/download/v1.1/plugin-fac.zip</file>
|
<file>https://github.com/JcDenis/fac/releases/download/v1.3.1/plugin-fac.zip</file>
|
||||||
<da:dcmin>2.26</da:dcmin>
|
<da:dcmin>2.26</da:dcmin>
|
||||||
<da:details>https://plugins.dotaddict.org/dc2/details/fac</da:details>
|
<da:details>https://plugins.dotaddict.org/dc2/details/fac</da:details>
|
||||||
<da:support>https://github.com/JcDenis/fac</da:support>
|
<da:support>https://github.com/JcDenis/fac</da:support>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
$(function(){
|
/*global $, dotclear, datePicker */
|
||||||
/* toogle admin form sidebar */
|
'use strict';
|
||||||
|
|
||||||
|
$(() => {
|
||||||
$('#fac h5').toggleWithLegend(
|
$('#fac h5').toggleWithLegend(
|
||||||
$('#fac').children().not('h5'),
|
$('#fac').children().not('h5'),
|
||||||
{cookie:'dcx_fac_admin_form_sidebar',legend_click:true}
|
{user_pref:'dcx_fac_admin_form_sidebar',legend_click:true}
|
||||||
);
|
);
|
||||||
});
|
});
|
|
@ -9,51 +9,53 @@
|
||||||
# DOT NOT MODIFY THIS FILE !
|
# DOT NOT MODIFY THIS FILE !
|
||||||
#
|
#
|
||||||
|
|
||||||
l10n::$locales['home page'] = 'la page d\'accueil';
|
use Dotclear\Helper\L10n;
|
||||||
l10n::$locales['post pages'] = 'la page d\'un billet';
|
|
||||||
l10n::$locales['tags pages'] = 'les pages d\'un tag';
|
L10n::$locales['home page'] = 'la page d\'accueil';
|
||||||
l10n::$locales['archives pages'] = 'les pages des archives';
|
L10n::$locales['post pages'] = 'la page d\'un billet';
|
||||||
l10n::$locales['category pages'] = 'les pages de catégorie';
|
L10n::$locales['tags pages'] = 'les pages d\'un tag';
|
||||||
l10n::$locales['entries feed'] = 'le flux des billets';
|
L10n::$locales['archives pages'] = 'les pages des archives';
|
||||||
l10n::$locales['"%s" pages from extension muppet'] = 'la page de type "%s" de l\'extension muppet';
|
L10n::$locales['category pages'] = 'les pages de catégorie';
|
||||||
l10n::$locales['To add feed to an entry edit this entry and put in sidebar the url of the feed and select a format.'] = 'Pour ajouter un flux à un billet, modifier ce billet et dans son menu latéral ajouter l\'URL du flux et le format.';
|
L10n::$locales['entries feed'] = 'le flux des billets';
|
||||||
l10n::$locales['Configure formats'] = 'Configurer les formats';
|
L10n::$locales['"%s" pages from extension muppet'] = 'la page de type "%s" de l\'extension muppet';
|
||||||
l10n::$locales['Enable "fac" extension'] = 'Activer l\'extension "fac"';
|
L10n::$locales['To add feed to an entry edit this entry and put in sidebar the url of the feed and select a format.'] = 'Pour ajouter un flux à un billet, modifier ce billet et dans son menu latéral ajouter l\'URL du flux et le format.';
|
||||||
l10n::$locales['You can manage related feed to display for each post with a predefined format.'] = 'Vous pouvez gérer les flux a afficher pour chaque billet avec un format prédéfini.';
|
L10n::$locales['Configure formats'] = 'Configurer les formats';
|
||||||
l10n::$locales['Feed'] = 'Flux';
|
L10n::$locales['Enable "fac" extension'] = 'Activer l\'extension "fac"';
|
||||||
l10n::$locales['Default title'] = 'Titre par défaut';
|
L10n::$locales['You can manage related feed to display for each post with a predefined format.'] = 'Vous pouvez gérer les flux a afficher pour chaque billet avec un format prédéfini.';
|
||||||
l10n::$locales['Use %T to insert title of feed.'] = 'Utiliser %T pour insérer le titre du flux.';
|
L10n::$locales['Feed'] = 'Flux';
|
||||||
l10n::$locales['Show description of feed'] = 'Afficher la description';
|
L10n::$locales['Default title'] = 'Titre par défaut';
|
||||||
l10n::$locales['Show feed after content on:'] = 'Afficher le flux après le contenu sur :';
|
L10n::$locales['Use %T to insert title of feed.'] = 'Utiliser %T pour insérer le titre du flux.';
|
||||||
l10n::$locales['Linked feed'] = 'Flux lié';
|
L10n::$locales['Show description of feed'] = 'Afficher la description';
|
||||||
l10n::$locales['Add feed'] = 'Ajouter un flux';
|
L10n::$locales['Show feed after content on:'] = 'Afficher le flux après le contenu sur :';
|
||||||
l10n::$locales['Remove feed'] = 'Retirer un flux';
|
L10n::$locales['Linked feed'] = 'Flux lié';
|
||||||
l10n::$locales['Linked feed deleted.'] = 'Flux lié effacé.';
|
L10n::$locales['Add feed'] = 'Ajouter un flux';
|
||||||
l10n::$locales['Linked feed added.'] = 'Flux lié ajouté.';
|
L10n::$locales['Remove feed'] = 'Retirer un flux';
|
||||||
l10n::$locales['Linked feed to this selection'] = 'Lié un flux a cette selection';
|
L10n::$locales['Linked feed deleted.'] = 'Flux lié effacé.';
|
||||||
l10n::$locales['view feed'] = 'Voir le flux';
|
L10n::$locales['Linked feed added.'] = 'Flux lié ajouté.';
|
||||||
l10n::$locales['Format %s'] = 'Format %s';
|
L10n::$locales['Linked feed to this selection'] = 'Lié un flux a cette selection';
|
||||||
l10n::$locales['In order to remove a format, leave its name empty.'] = 'Pour retirer un format, laisser son nom vide.';
|
L10n::$locales['view feed'] = 'Voir le flux';
|
||||||
l10n::$locales['Use date format of Dotclear or leave empty to use default date format of blog.'] = 'Utiliser le formatage des dates de Dotclear ou laisser vide pour utiliser le format par défaut du blog.';
|
L10n::$locales['Format %s'] = 'Format %s';
|
||||||
l10n::$locales['Leave lengh empty for no limit.'] = 'Laisser vide pour ne pas mettre de limite.';
|
L10n::$locales['In order to remove a format, leave its name empty.'] = 'Pour retirer un format, laisser son nom vide.';
|
||||||
l10n::$locales['Title format:'] = 'Format du titre :';
|
L10n::$locales['Use date format of Dotclear or leave empty to use default date format of blog.'] = 'Utiliser le formatage des dates de Dotclear ou laisser vide pour utiliser le format par défaut du blog.';
|
||||||
l10n::$locales['Format can be:'] = 'Le format peut-être :';
|
L10n::$locales['Leave lengh empty for no limit.'] = 'Laisser vide pour ne pas mettre de limite.';
|
||||||
l10n::$locales['Over title format:'] = 'Format au survole du titre :';
|
L10n::$locales['Title format:'] = 'Format du titre :';
|
||||||
l10n::$locales['Maximum length of title:'] = 'Longueur maximum du titre :';
|
L10n::$locales['Format can be:'] = 'Le format peut-être :';
|
||||||
l10n::$locales['Show description of entries'] = 'Afficher la description des billets';
|
L10n::$locales['Over title format:'] = 'Format au survole du titre :';
|
||||||
l10n::$locales['Remove html of description'] = 'Retirer le code HTML de la description';
|
L10n::$locales['Maximum length of title:'] = 'Longueur maximum du titre :';
|
||||||
l10n::$locales['Maximum length of description:'] = 'Longueur maximum de la description :';
|
L10n::$locales['Show description of entries'] = 'Afficher la description des billets';
|
||||||
l10n::$locales['Show content of entries'] = 'Afficher le contenu du flux';
|
L10n::$locales['Remove html of description'] = 'Retirer le code HTML de la description';
|
||||||
l10n::$locales['Remove html of content'] = 'Retirer le code HTML du contenu';
|
L10n::$locales['Maximum length of description:'] = 'Longueur maximum de la description :';
|
||||||
l10n::$locales['Maximum length of content:'] = 'Longueur maximum du contenu :';
|
L10n::$locales['Show content of entries'] = 'Afficher le contenu du flux';
|
||||||
l10n::$locales['New format'] = 'Nouveau format';
|
L10n::$locales['Remove html of content'] = 'Retirer le code HTML du contenu';
|
||||||
l10n::$locales['Informations'] = 'Informations';
|
L10n::$locales['Maximum length of content:'] = 'Longueur maximum du contenu :';
|
||||||
l10n::$locales['Theme'] = 'Thème';
|
L10n::$locales['New format'] = 'Nouveau format';
|
||||||
l10n::$locales['Theme must have behavoir publicEntryAfterContent.'] = 'Le thème doit avoir le behavior pulicEnryAfterContent.';
|
L10n::$locales['Informations'] = 'Informations';
|
||||||
l10n::$locales['Structure'] = 'Structure';
|
L10n::$locales['Theme'] = 'Thème';
|
||||||
l10n::$locales['Title of feed'] = 'Titre du flux';
|
L10n::$locales['Theme must have behavoir publicEntryAfterContent.'] = 'Le thème doit avoir le behavior pulicEnryAfterContent.';
|
||||||
l10n::$locales['Description of feed'] = 'Descritpion du flux';
|
L10n::$locales['Structure'] = 'Structure';
|
||||||
l10n::$locales['Title of entry'] = 'Titre du billet';
|
L10n::$locales['Title of feed'] = 'Titre du flux';
|
||||||
l10n::$locales['Description of entry'] = 'Description du billet';
|
L10n::$locales['Description of feed'] = 'Descritpion du flux';
|
||||||
l10n::$locales['a related feed'] = 'un flux lié';
|
L10n::$locales['Title of entry'] = 'Titre du billet';
|
||||||
l10n::$locales['Add RSS/Atom feeds after entries content'] = 'Ajouter des flux RSS/Atom après le contenu des billets';
|
L10n::$locales['Description of entry'] = 'Description du billet';
|
||||||
|
L10n::$locales['a related feed'] = 'un flux lié';
|
||||||
|
L10n::$locales['Add RSS/Atom feeds after entries content'] = 'Ajouter des flux RSS/Atom après le contenu des billets';
|
||||||
|
|
|
@ -15,20 +15,18 @@ declare(strict_types=1);
|
||||||
namespace Dotclear\Plugin\fac;
|
namespace Dotclear\Plugin\fac;
|
||||||
|
|
||||||
use dcCore;
|
use dcCore;
|
||||||
use dcNsProcess;
|
use Dotclear\Core\Process;
|
||||||
|
|
||||||
class Backend extends dcNsProcess
|
class Backend extends Process
|
||||||
{
|
{
|
||||||
public static function init(): bool
|
public static function init(): bool
|
||||||
{
|
{
|
||||||
static::$init = defined('DC_CONTEXT_ADMIN');
|
return self::status(My::checkContext(My::BACKEND));
|
||||||
|
|
||||||
return static::$init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function process(): bool
|
public static function process(): bool
|
||||||
{
|
{
|
||||||
if (!static::$init) {
|
if (!self::status()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,18 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Dotclear\Plugin\fac;
|
namespace Dotclear\Plugin\fac;
|
||||||
|
|
||||||
use cursor;
|
|
||||||
use ArrayObject;
|
use ArrayObject;
|
||||||
use dcAuth;
|
|
||||||
use dcCore;
|
use dcCore;
|
||||||
use dcPage;
|
|
||||||
use dcPostsActions;
|
|
||||||
use dcRecord;
|
|
||||||
use dcSettings;
|
use dcSettings;
|
||||||
|
use Dotclear\Core\Backend\{
|
||||||
|
Notices,
|
||||||
|
Page
|
||||||
|
};
|
||||||
|
use Dotclear\Core\Backend\Action\ActionsPosts;
|
||||||
|
use Dotclear\Database\{
|
||||||
|
Cursor,
|
||||||
|
MetaRecord
|
||||||
|
};
|
||||||
use Dotclear\Helper\Html\Html;
|
use Dotclear\Helper\Html\Html;
|
||||||
use Dotclear\Helper\Html\Form\{
|
use Dotclear\Helper\Html\Form\{
|
||||||
Checkbox,
|
Checkbox,
|
||||||
|
@ -60,7 +64,7 @@ class BackendBehaviors
|
||||||
__('category pages') => 'category',
|
__('category pages') => 'category',
|
||||||
__('entries feed') => 'feed',
|
__('entries feed') => 'feed',
|
||||||
];
|
];
|
||||||
if (dcCore::app()->plugins->moduleExists('muppet') && class_exists('\muppet')) {
|
if (dcCore::app()->plugins->getDefine('muppet')->isDefined() && class_exists('\muppet')) {
|
||||||
foreach (\muppet::getPostTypes() as $k => $v) {
|
foreach (\muppet::getPostTypes() as $k => $v) {
|
||||||
$types[sprintf(
|
$types[sprintf(
|
||||||
__('"%s" pages from extension muppet'),
|
__('"%s" pages from extension muppet'),
|
||||||
|
@ -92,15 +96,15 @@ class BackendBehaviors
|
||||||
}
|
}
|
||||||
|
|
||||||
echo
|
echo
|
||||||
'<div class="fieldset"><h4 id="fac_params">Feed after content</h4>' .
|
'<div class="fieldset"><h4 id="' . My::id() . '_params">Feed after content</h4>' .
|
||||||
'<p class="form-note">' .
|
'<p class="form-note">' .
|
||||||
__('To add feed to an entry edit this entry and put in sidebar the url of the feed and select a format.') .
|
__('To add feed to an entry edit this entry and put in sidebar the url of the feed and select a format.') .
|
||||||
'</p>';
|
'</p>';
|
||||||
if (dcCore::app()->auth->isSuperAdmin()) {
|
if (dcCore::app()->auth->isSuperAdmin()) {
|
||||||
echo '<p><a href="' . dcCore::app()->adminurl->get('admin.plugins', [
|
echo '<p><a href="' . dcCore::app()->admin->url->get('admin.plugins', [
|
||||||
'module' => My::id(),
|
'module' => My::id(),
|
||||||
'conf' => 1,
|
'conf' => 1,
|
||||||
'redir' => dcCore::app()->adminurl->get('admin.blog.pref') . '#fac_params',
|
'redir' => dcCore::app()->admin->url->get('admin.blog.pref') . '#params.' . My::id() . '_params',
|
||||||
]) . '">' . __('Configure formats') . '</a></p>';
|
]) . '">' . __('Configure formats') . '</a></p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +160,7 @@ class BackendBehaviors
|
||||||
*/
|
*/
|
||||||
public static function adminPostHeaders(): string
|
public static function adminPostHeaders(): string
|
||||||
{
|
{
|
||||||
return dcPage::jsModuleLoad(My::id() . '/js/backend.js');
|
return My::jsLoad('backend');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -164,11 +168,11 @@ class BackendBehaviors
|
||||||
*
|
*
|
||||||
* @param ArrayObject $main_items Main items
|
* @param ArrayObject $main_items Main items
|
||||||
* @param ArrayObject $sidebar_items Sidebar items
|
* @param ArrayObject $sidebar_items Sidebar items
|
||||||
* @param null|dcRecord $post Post record or null
|
* @param null|MetaRecord $post Post record or null
|
||||||
*/
|
*/
|
||||||
public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?dcRecord $post): void
|
public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?MetaRecord $post): void
|
||||||
{
|
{
|
||||||
if (!dcCore::app()->blog->settings->get(My::id())->get('active')) {
|
if (is_null(dcCore::app()->blog) || !My::settings()->get('active')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -197,10 +201,10 @@ class BackendBehaviors
|
||||||
/**
|
/**
|
||||||
* Save linked feed
|
* Save linked feed
|
||||||
*
|
*
|
||||||
* @param cursor $cur Current post cursor
|
* @param Cursor $cur Current post Cursor
|
||||||
* @param integer $post_id Post id
|
* @param integer $post_id Post id
|
||||||
*/
|
*/
|
||||||
public static function adminAfterPostSave(cursor $cur, int $post_id): void
|
public static function adminAfterPostSave(Cursor $cur, int $post_id): void
|
||||||
{
|
{
|
||||||
if (!isset($_POST['fac_url'])
|
if (!isset($_POST['fac_url'])
|
||||||
|| !isset($_POST['fac_format'])) {
|
|| !isset($_POST['fac_format'])) {
|
||||||
|
@ -227,11 +231,11 @@ class BackendBehaviors
|
||||||
/**
|
/**
|
||||||
* Add actions to posts page combo
|
* Add actions to posts page combo
|
||||||
*
|
*
|
||||||
* @param dcPostsActions $pa dcPostsActionsPage instance
|
* @param ActionsPosts $pa ActionsPostsPage instance
|
||||||
*/
|
*/
|
||||||
public static function adminPostsActions(dcPostsActions $pa): void
|
public static function adminPostsActions(ActionsPosts $pa): void
|
||||||
{
|
{
|
||||||
if (!dcCore::app()->blog->settings->get(My::id())->get('active')) {
|
if (is_null(dcCore::app()->blog) || !My::settings()->get('active')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,8 +245,8 @@ class BackendBehaviors
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
|
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
|
||||||
dcAuth::PERMISSION_DELETE,
|
dcCore::app()->auth::PERMISSION_DELETE,
|
||||||
dcAuth::PERMISSION_CONTENT_ADMIN,
|
dcCore::app()->auth::PERMISSION_CONTENT_ADMIN,
|
||||||
]), dcCore::app()->blog->id)) {
|
]), dcCore::app()->blog->id)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -255,11 +259,14 @@ class BackendBehaviors
|
||||||
/**
|
/**
|
||||||
* Posts actions callback to remove linked feed
|
* Posts actions callback to remove linked feed
|
||||||
*
|
*
|
||||||
* @param dcPostsActions $pa dcPostsActions instance
|
* @param ActionsPosts $pa ActionsPosts instance
|
||||||
* @param ArrayObject $post _POST actions
|
* @param ArrayObject $post _POST actions
|
||||||
*/
|
*/
|
||||||
public static function callbackRemove(dcPostsActions $pa, ArrayObject $post): void
|
public static function callbackRemove(ActionsPosts $pa, ArrayObject $post): void
|
||||||
{
|
{
|
||||||
|
if (is_null(dcCore::app()->blog)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
# No entry
|
# No entry
|
||||||
$posts_ids = $pa->getIDs();
|
$posts_ids = $pa->getIDs();
|
||||||
if (empty($posts_ids)) {
|
if (empty($posts_ids)) {
|
||||||
|
@ -268,8 +275,8 @@ class BackendBehaviors
|
||||||
|
|
||||||
# No right
|
# No right
|
||||||
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
|
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([
|
||||||
dcAuth::PERMISSION_DELETE,
|
dcCore::app()->auth::PERMISSION_DELETE,
|
||||||
dcAuth::PERMISSION_CONTENT_ADMIN,
|
dcCore::app()->auth::PERMISSION_CONTENT_ADMIN,
|
||||||
]), dcCore::app()->blog->id)) {
|
]), dcCore::app()->blog->id)) {
|
||||||
throw new Exception(__('No enough right'));
|
throw new Exception(__('No enough right'));
|
||||||
}
|
}
|
||||||
|
@ -279,18 +286,21 @@ class BackendBehaviors
|
||||||
self::delFeed($post_id);
|
self::delFeed($post_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
dcPage::addSuccessNotice(__('Linked feed deleted.'));
|
Notices::addSuccessNotice(__('Linked feed deleted.'));
|
||||||
$pa->redirect(true);
|
$pa->redirect(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Posts actions callback to add linked feed
|
* Posts actions callback to add linked feed
|
||||||
*
|
*
|
||||||
* @param dcPostsActions $pa dcPostsActions instance
|
* @param ActionsPosts $pa ActionsPosts instance
|
||||||
* @param ArrayObject $post _POST actions
|
* @param ArrayObject $post _POST actions
|
||||||
*/
|
*/
|
||||||
public static function callbackAdd(dcPostsActions $pa, ArrayObject $post): void
|
public static function callbackAdd(ActionsPosts $pa, ArrayObject $post): void
|
||||||
{
|
{
|
||||||
|
if (is_null(dcCore::app()->blog)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
# No entry
|
# No entry
|
||||||
$posts_ids = $pa->getIDs();
|
$posts_ids = $pa->getIDs();
|
||||||
if (empty($posts_ids)) {
|
if (empty($posts_ids)) {
|
||||||
|
@ -305,13 +315,13 @@ class BackendBehaviors
|
||||||
self::addFeed($post_id, $post);
|
self::addFeed($post_id, $post);
|
||||||
}
|
}
|
||||||
|
|
||||||
dcPage::addSuccessNotice(__('Linked feed added.'));
|
Notices::addSuccessNotice(__('Linked feed added.'));
|
||||||
$pa->redirect(true);
|
$pa->redirect(true);
|
||||||
|
|
||||||
# Display form
|
# Display form
|
||||||
} else {
|
} else {
|
||||||
$pa->beginPage(
|
$pa->beginPage(
|
||||||
dcPage::breadcrumb([
|
Page::breadcrumb([
|
||||||
Html::escapeHTML(dcCore::app()->blog->name) => '',
|
Html::escapeHTML(dcCore::app()->blog->name) => '',
|
||||||
$pa->getCallerTitle() => $pa->getRedirection(true),
|
$pa->getCallerTitle() => $pa->getRedirection(true),
|
||||||
__('Linked feed to this selection') => '',
|
__('Linked feed to this selection') => '',
|
||||||
|
@ -341,7 +351,7 @@ class BackendBehaviors
|
||||||
*/
|
*/
|
||||||
protected static function formFeed(string $url = '', string $format = ''): string
|
protected static function formFeed(string $url = '', string $format = ''): string
|
||||||
{
|
{
|
||||||
if (!dcCore::app()->blog->settings->get(My::id())->get('active')) {
|
if (is_null(dcCore::app()->blog) || !My::settings()->get('active')) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,7 +379,10 @@ class BackendBehaviors
|
||||||
*/
|
*/
|
||||||
protected static function comboFac(): array
|
protected static function comboFac(): array
|
||||||
{
|
{
|
||||||
$formats = json_decode(dcCore::app()->blog->settings->get(My::id())->get('formats'), true);
|
if (is_null(dcCore::app()->blog)) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
$formats = json_decode((string) My::settings()->get('formats'), true);
|
||||||
if (!is_array($formats) || empty($formats)) {
|
if (!is_array($formats) || empty($formats)) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -400,7 +413,7 @@ class BackendBehaviors
|
||||||
* @param integer $post_id Post id
|
* @param integer $post_id Post id
|
||||||
* @param array|ArrayObject $options Feed options
|
* @param array|ArrayObject $options Feed options
|
||||||
*/
|
*/
|
||||||
protected static function addFeed(int $post_id, array|ArrayObject $options): void
|
protected static function addFeed(int $post_id, $options): void
|
||||||
{
|
{
|
||||||
if (empty($options['fac_url'])
|
if (empty($options['fac_url'])
|
||||||
|| empty($options['fac_format'])) {
|
|| empty($options['fac_format'])) {
|
||||||
|
|
|
@ -15,8 +15,11 @@ declare(strict_types=1);
|
||||||
namespace Dotclear\Plugin\fac;
|
namespace Dotclear\Plugin\fac;
|
||||||
|
|
||||||
use dcCore;
|
use dcCore;
|
||||||
use dcPage;
|
use Dotclear\Core\Process;
|
||||||
use dcNsProcess;
|
use Dotclear\Core\Backend\{
|
||||||
|
Notices,
|
||||||
|
Page
|
||||||
|
};
|
||||||
use Dotclear\Helper\Html\Html;
|
use Dotclear\Helper\Html\Html;
|
||||||
use Dotclear\Helper\Html\Form\{
|
use Dotclear\Helper\Html\Form\{
|
||||||
Checkbox,
|
Checkbox,
|
||||||
|
@ -30,19 +33,21 @@ use Dotclear\Helper\Html\Form\{
|
||||||
};
|
};
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Config extends dcNsProcess
|
class Config extends Process
|
||||||
{
|
{
|
||||||
public static function init(): bool
|
public static function init(): bool
|
||||||
{
|
{
|
||||||
static::$init == defined('DC_CONTEXT_ADMIN')
|
return self::status(My::checkContext(My::CONFIG));
|
||||||
&& dcCore::app()->auth?->isSuperAdmin();
|
|
||||||
|
|
||||||
return static::$init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function process(): bool
|
public static function process(): bool
|
||||||
{
|
{
|
||||||
if (!static::$init) {
|
if (!self::status()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//nullsafe
|
||||||
|
if (is_null(dcCore::app()->blog)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +55,7 @@ class Config extends dcNsProcess
|
||||||
dcCore::app()->admin->__get('list')->getURL() . '#plugins' : $_REQUEST['redir'];
|
dcCore::app()->admin->__get('list')->getURL() . '#plugins' : $_REQUEST['redir'];
|
||||||
|
|
||||||
# -- Get settings --
|
# -- Get settings --
|
||||||
$s = dcCore::app()->blog->settings->get(My::id());
|
$s = My::settings();
|
||||||
|
|
||||||
$fac_formats = json_decode($s->get('formats'), true);
|
$fac_formats = json_decode($s->get('formats'), true);
|
||||||
|
|
||||||
|
@ -82,10 +87,10 @@ class Config extends dcNsProcess
|
||||||
|
|
||||||
dcCore::app()->blog->triggerBlog();
|
dcCore::app()->blog->triggerBlog();
|
||||||
|
|
||||||
dcPage::addSuccessNotice(
|
Notices::addSuccessNotice(
|
||||||
__('Configuration successfully updated.')
|
__('Configuration successfully updated.')
|
||||||
);
|
);
|
||||||
dcCore::app()->adminurl?->redirect(
|
dcCore::app()->admin->url->redirect(
|
||||||
'admin.plugins',
|
'admin.plugins',
|
||||||
['module' => My::id(), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()]
|
['module' => My::id(), 'conf' => 1, 'redir' => dcCore::app()->admin->__get('list')->getRedir()]
|
||||||
);
|
);
|
||||||
|
@ -99,10 +104,11 @@ class Config extends dcNsProcess
|
||||||
|
|
||||||
public static function render(): void
|
public static function render(): void
|
||||||
{
|
{
|
||||||
if (!static::$init) {
|
if (!self::status()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$s = dcCore::app()->blog->settings->get(My::id());
|
|
||||||
|
$s = My::settings();
|
||||||
|
|
||||||
$fac_formats = json_decode($s->get('formats'), true);
|
$fac_formats = json_decode($s->get('formats'), true);
|
||||||
|
|
||||||
|
@ -136,7 +142,7 @@ class Config extends dcNsProcess
|
||||||
|
|
||||||
echo '
|
echo '
|
||||||
<div class="fieldset">
|
<div class="fieldset">
|
||||||
<h4>' . __('Informations') . '</h4>
|
<h4 id="' . My::id() . 'Params">' . __('Informations') . '</h4>
|
||||||
|
|
||||||
<div class="two-boxes">
|
<div class="two-boxes">
|
||||||
|
|
||||||
|
@ -164,7 +170,7 @@ class Config extends dcNsProcess
|
||||||
|
|
||||||
</div>';
|
</div>';
|
||||||
|
|
||||||
dcPage::helpBlock('fac');
|
Page::helpBlock('fac');
|
||||||
}
|
}
|
||||||
|
|
||||||
private static function displayFacFormat(string $title, string $uid, array $format): void
|
private static function displayFacFormat(string $title, string $uid, array $format): void
|
||||||
|
|
|
@ -16,41 +16,44 @@ namespace Dotclear\Plugin\fac;
|
||||||
|
|
||||||
use context;
|
use context;
|
||||||
use dcCore;
|
use dcCore;
|
||||||
use dcNsProcess;
|
use Dotclear\Core\Process;
|
||||||
use Dotclear\Helper\Date;
|
use Dotclear\Helper\Date;
|
||||||
use Dotclear\Helper\Html\Html;
|
use Dotclear\Helper\Html\Html;
|
||||||
use Dotclear\Helper\Network\Feed\Reader;
|
use Dotclear\Helper\Network\Feed\Reader;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Frontend extends dcNsProcess
|
class Frontend extends Process
|
||||||
{
|
{
|
||||||
public static function init(): bool
|
public static function init(): bool
|
||||||
{
|
{
|
||||||
static::$init = defined('DC_RC_PATH');
|
return self::status(My::checkContext(My::FRONTEND));
|
||||||
|
|
||||||
return static::$init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function process(): bool
|
public static function process(): bool
|
||||||
{
|
{
|
||||||
if (!static::$init || !dcCore::app()->blog->settings->get(My::id())->get('active')) {
|
if (!self::status() || is_null(dcCore::app()->blog) || !My::settings()->get('active')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
dcCore::app()->addBehavior('publicEntryAfterContent', function (dcCore $core, context $_ctx): void {
|
dcCore::app()->addBehavior('publicEntryAfterContent', function (dcCore $core, context $_ctx): void {
|
||||||
# Not a post
|
//nullsafe
|
||||||
|
if (is_null(dcCore::app()->blog) || is_null(dcCore::app()->ctx)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not a post
|
||||||
if (!dcCore::app()->ctx->exists('posts')) {
|
if (!dcCore::app()->ctx->exists('posts')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Not in page to show
|
// Not in page to show
|
||||||
$types = json_decode((string) dcCore::app()->blog->settings->get(My::id())->get('public_tpltypes'), true);
|
$types = json_decode((string) My::settings()->get('public_tpltypes'), true);
|
||||||
if (!is_array($types)
|
if (!is_array($types)
|
||||||
|| !in_array(dcCore::app()->url->type, $types)) {
|
|| !in_array(dcCore::app()->url->type, $types)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get related feed
|
// Get related feed
|
||||||
$fac_url = dcCore::app()->meta->getMetadata([
|
$fac_url = dcCore::app()->meta->getMetadata([
|
||||||
'meta_type' => 'fac',
|
'meta_type' => 'fac',
|
||||||
'post_id' => dcCore::app()->ctx->__get('posts')->f('post_id'),
|
'post_id' => dcCore::app()->ctx->__get('posts')->f('post_id'),
|
||||||
|
@ -60,7 +63,7 @@ class Frontend extends dcNsProcess
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get related format
|
// Get related format
|
||||||
$fac_format = dcCore::app()->meta->getMetadata([
|
$fac_format = dcCore::app()->meta->getMetadata([
|
||||||
'meta_type' => 'facformat',
|
'meta_type' => 'facformat',
|
||||||
'post_id' => dcCore::app()->ctx->__get('posts')->f('post_id'),
|
'post_id' => dcCore::app()->ctx->__get('posts')->f('post_id'),
|
||||||
|
@ -70,7 +73,7 @@ class Frontend extends dcNsProcess
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Get format info
|
// Get format info
|
||||||
$default_format = [
|
$default_format = [
|
||||||
'name' => 'default',
|
'name' => 'default',
|
||||||
'dateformat' => '',
|
'dateformat' => '',
|
||||||
|
@ -86,7 +89,7 @@ class Frontend extends dcNsProcess
|
||||||
'linescontentnohtml' => '1',
|
'linescontentnohtml' => '1',
|
||||||
];
|
];
|
||||||
|
|
||||||
$formats = json_decode((string) dcCore::app()->blog->settings->get(My::id())->get('formats'), true);
|
$formats = json_decode((string) My::settings()->get('formats'), true);
|
||||||
if (empty($formats)
|
if (empty($formats)
|
||||||
|| !is_array($formats)
|
|| !is_array($formats)
|
||||||
|| !isset($formats[$fac_format->f('meta_id')])) {
|
|| !isset($formats[$fac_format->f('meta_id')])) {
|
||||||
|
@ -98,7 +101,7 @@ class Frontend extends dcNsProcess
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read feed url
|
// Read feed url
|
||||||
$cache = is_dir(DC_TPL_CACHE . '/fac') ? DC_TPL_CACHE . '/fac' : null;
|
$cache = is_dir(DC_TPL_CACHE . '/fac') ? DC_TPL_CACHE . '/fac' : null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
@ -107,32 +110,32 @@ class Frontend extends dcNsProcess
|
||||||
$feed = null;
|
$feed = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
# No entries
|
// No entries
|
||||||
if (!$feed) {
|
if (!$feed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Feed title
|
// Feed title
|
||||||
$feedtitle = '';
|
$feedtitle = '';
|
||||||
if ('' != dcCore::app()->blog->settings->get(My::id())->get('defaultfeedtitle')) {
|
if ('' != My::settings()->get('defaultfeedtitle')) {
|
||||||
$feedtitle = '<h3>' . Html::escapeHTML(
|
$feedtitle = '<h3>' . Html::escapeHTML(
|
||||||
empty($feed->title) ?
|
empty($feed->title) ?
|
||||||
str_replace(
|
str_replace(
|
||||||
'%T',
|
'%T',
|
||||||
__('a related feed'),
|
__('a related feed'),
|
||||||
dcCore::app()->blog->settings->get(My::id())->get('defaultfeedtitle')
|
(string) My::settings()->get('defaultfeedtitle')
|
||||||
) :
|
) :
|
||||||
str_replace(
|
str_replace(
|
||||||
'%T',
|
'%T',
|
||||||
$feed->title,
|
$feed->title,
|
||||||
dcCore::app()->blog->settings->get(My::id())->get('defaultfeedtitle')
|
(string) My::settings()->get('defaultfeedtitle')
|
||||||
)
|
)
|
||||||
) . '</h3>';
|
) . '</h3>';
|
||||||
}
|
}
|
||||||
|
|
||||||
# Feed desc
|
// Feed desc
|
||||||
$feeddesc = '';
|
$feeddesc = '';
|
||||||
if (dcCore::app()->blog->settings->get(My::id())->get('showfeeddesc')
|
if (My::settings()->get('showfeeddesc')
|
||||||
&& '' != $feed->description) {
|
&& '' != $feed->description) {
|
||||||
$feeddesc = '<p>' . context::global_filters(
|
$feeddesc = '<p>' . context::global_filters(
|
||||||
$feed->description,
|
$feed->description,
|
||||||
|
@ -140,12 +143,12 @@ class Frontend extends dcNsProcess
|
||||||
) . '</p>';
|
) . '</p>';
|
||||||
}
|
}
|
||||||
|
|
||||||
# Date format
|
// Date format
|
||||||
$dateformat = '' != $format['dateformat'] ?
|
$dateformat = '' != $format['dateformat'] ?
|
||||||
$format['dateformat'] :
|
$format['dateformat'] :
|
||||||
dcCore::app()->blog->settings->get('system')->get('date_format') . ',' . dcCore::app()->blog->settings->get('system')->get('time_format');
|
dcCore::app()->blog->settings->get('system')->get('date_format') . ',' . dcCore::app()->blog->settings->get('system')->get('time_format');
|
||||||
|
|
||||||
# Enrties limit
|
// Enrties limit
|
||||||
$entrieslimit = abs((int) $format['lineslimit']);
|
$entrieslimit = abs((int) $format['lineslimit']);
|
||||||
$uselimit = $entrieslimit > 0 ? true : false;
|
$uselimit = $entrieslimit > 0 ? true : false;
|
||||||
|
|
||||||
|
@ -159,7 +162,7 @@ class Frontend extends dcNsProcess
|
||||||
# Format date
|
# Format date
|
||||||
$date = Date::dt2str($dateformat, $item->pubdate);
|
$date = Date::dt2str($dateformat, $item->pubdate);
|
||||||
|
|
||||||
# Entries title
|
// Entries title
|
||||||
$title = context::global_filters(
|
$title = context::global_filters(
|
||||||
str_replace(
|
str_replace(
|
||||||
[
|
[
|
||||||
|
@ -181,7 +184,7 @@ class Frontend extends dcNsProcess
|
||||||
['remove_html', 'cut_string' => abs((int) $format['linestitlelength'])],
|
['remove_html', 'cut_string' => abs((int) $format['linestitlelength'])],
|
||||||
);
|
);
|
||||||
|
|
||||||
# Entries over title
|
// Entries over title
|
||||||
$overtitle = context::global_filters(
|
$overtitle = context::global_filters(
|
||||||
str_replace(
|
str_replace(
|
||||||
[
|
[
|
||||||
|
@ -203,7 +206,7 @@ class Frontend extends dcNsProcess
|
||||||
['remove_html', 'cut_string' => 350],
|
['remove_html', 'cut_string' => 350],
|
||||||
);
|
);
|
||||||
|
|
||||||
# Entries description
|
// Entries description
|
||||||
$description = '';
|
$description = '';
|
||||||
if ($format['showlinesdescription']
|
if ($format['showlinesdescription']
|
||||||
&& '' != $item->description) {
|
&& '' != $item->description) {
|
||||||
|
@ -214,7 +217,7 @@ class Frontend extends dcNsProcess
|
||||||
) . '</dd>';
|
) . '</dd>';
|
||||||
}
|
}
|
||||||
|
|
||||||
# Entries content
|
// Entries content
|
||||||
$content = '';
|
$content = '';
|
||||||
if ($format['showlinescontent']
|
if ($format['showlinescontent']
|
||||||
&& '' != $item->content) {
|
&& '' != $item->content) {
|
||||||
|
|
|
@ -16,22 +16,19 @@ namespace Dotclear\Plugin\fac;
|
||||||
|
|
||||||
use dcCore;
|
use dcCore;
|
||||||
use dcNamespace;
|
use dcNamespace;
|
||||||
use dcNsProcess;
|
use Dotclear\Core\Process;
|
||||||
use Exception;
|
use Exception;
|
||||||
|
|
||||||
class Install extends dcNsProcess
|
class Install extends Process
|
||||||
{
|
{
|
||||||
public static function init(): bool
|
public static function init(): bool
|
||||||
{
|
{
|
||||||
static::$init = defined('DC_CONTEXT_ADMIN')
|
return self::status(My::checkContext(My::INSTALL));
|
||||||
&& dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version'));
|
|
||||||
|
|
||||||
return static::$init;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function process(): bool
|
public static function process(): bool
|
||||||
{
|
{
|
||||||
if (!static::$init) {
|
if (!self::status()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +103,7 @@ class Install extends dcNsProcess
|
||||||
|
|
||||||
// Set module settings
|
// Set module settings
|
||||||
foreach ($mod_conf as $v) {
|
foreach ($mod_conf as $v) {
|
||||||
dcCore::app()->blog->settings->get(My::id())->put(
|
My::settings()->put(
|
||||||
$v[0],
|
$v[0],
|
||||||
$v[2],
|
$v[2],
|
||||||
$v[3],
|
$v[3],
|
||||||
|
|
22
src/My.php
22
src/My.php
|
@ -14,23 +14,11 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace Dotclear\Plugin\fac;
|
namespace Dotclear\Plugin\fac;
|
||||||
|
|
||||||
use dcCore;
|
use Dotclear\Module\MyPlugin;
|
||||||
|
|
||||||
class My
|
/**
|
||||||
|
* This module definitions.
|
||||||
|
*/
|
||||||
|
class My extends MyPlugin
|
||||||
{
|
{
|
||||||
/**
|
|
||||||
* This module id
|
|
||||||
*/
|
|
||||||
public static function id(): string
|
|
||||||
{
|
|
||||||
return basename(dirname(__DIR__));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This module name
|
|
||||||
*/
|
|
||||||
public static function name(): string
|
|
||||||
{
|
|
||||||
return __((string) dcCore::app()->plugins->moduleInfo(self::id(), 'name'));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @brief fac, a plugin for Dotclear 2
|
||||||
|
*
|
||||||
|
* @package Dotclear
|
||||||
|
* @subpackage Plugin
|
||||||
|
*
|
||||||
|
* @author Jean-Christian Denis 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\fac;
|
||||||
|
|
||||||
|
use dcCore;
|
||||||
|
use Dotclear\Core\Process;
|
||||||
|
use Dotclear\Plugin\Uninstaller\Uninstaller;
|
||||||
|
|
||||||
|
class Uninstall extends Process
|
||||||
|
{
|
||||||
|
public static function init(): bool
|
||||||
|
{
|
||||||
|
return self::status(My::checkContext(My::UNINSTALL));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function process(): bool
|
||||||
|
{
|
||||||
|
if (!self::status() || !dcCore::app()->plugins->moduleExists('Uninstaller')) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Uninstaller::instance()
|
||||||
|
->addUserAction(
|
||||||
|
'settings',
|
||||||
|
'delete_all',
|
||||||
|
My::id()
|
||||||
|
)
|
||||||
|
->addUserAction(
|
||||||
|
'plugins',
|
||||||
|
'delete',
|
||||||
|
My::id()
|
||||||
|
)
|
||||||
|
->addUserAction(
|
||||||
|
'versions',
|
||||||
|
'delete',
|
||||||
|
My::id()
|
||||||
|
)
|
||||||
|
->addDirectAction(
|
||||||
|
'settings',
|
||||||
|
'delete_all',
|
||||||
|
My::id()
|
||||||
|
)
|
||||||
|
->addDirectAction(
|
||||||
|
'plugins',
|
||||||
|
'delete',
|
||||||
|
My::id()
|
||||||
|
)
|
||||||
|
->addDirectAction(
|
||||||
|
'versions',
|
||||||
|
'delete',
|
||||||
|
My::id()
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
|
// no custom action
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue