upgrade to dotclear 2.27

master
Jean-Christian Paul Denis 2023-08-21 16:55:06 +02:00
parent 83cb803b64
commit adc711f877
Signed by: JcDenis
GPG Key ID: 1B5B8C5B90B6C951
36 changed files with 3157 additions and 2739 deletions

View File

@ -1,7 +1,10 @@
$(function(){
/*global $, dotclear */
'use strict';
$(() => {
/* toogle admin form sidebar */
$('#kUtRL h5').toggleWithLegend(
$('#kUtRL').children().not('h5'),
{cookie:'dcx_kUtRL_admin_form_sidebar',legend_click:true}
{user_pref:'dcx_kUtRL_admin_form_sidebar',legend_click:true}
);
});

View File

@ -9,155 +9,157 @@
# DOT NOT MODIFY THIS FILE !
#
l10n::$locales['Links shortener'] = 'Réducteur de liens';
l10n::$locales['Short link'] = 'Lien court';
l10n::$locales['Long link'] = 'Lien long';
l10n::$locales['Service'] = 'Service';
l10n::$locales['Hash'] = 'Hash';
l10n::$locales['links per page'] = 'liens par page';
l10n::$locales['Create short link'] = 'Créer un lien court';
l10n::$locales['Custom short link:'] = 'Lien court personnalisé :';
l10n::$locales['never followed'] = 'jamais suivi';
l10n::$locales['followed one time'] = 'suivi une fois';
l10n::$locales['followed %s times'] = 'suivi %s fois';
l10n::$locales['Delete short link'] = 'Effacer un lien court';
l10n::$locales['No enough right'] = 'Privilèges insuffisants';
l10n::$locales['Posts short links have been created.'] = 'Les liens courts des billets ont été créé.';
l10n::$locales['Disabled'] = 'Désactiver';
l10n::$locales['Enable plugin'] = 'Activer le plugin';
l10n::$locales['Behaviors'] = 'Comportements';
l10n::$locales['Allow short link for external URL'] = 'Autoriser les liens court sur des URLs externes';
l10n::$locales['Not only link started with this blog URL could be shortened.'] = 'Ne pas limiter la création de liens courts aux liens commençant par l\'URL du blog.';
l10n::$locales['Passive mode'] = 'Mode passif';
l10n::$locales['If this extension is disabled and the passive mode is enabled, "kutrl" tags (like EntryKurl) will display long urls instead of nothing on templates.'] = 'Si cette extension est désactivée et que le mode passif est activé, les balises "kutrl" (comme EntryKutrl) afficheront les liens longs au lieu de rien.';
l10n::$locales['Active mode'] = 'Mode actif';
l10n::$locales['If the active mode is enabled, all know default template tags (like EntryURL) will display short urls instead of long ones on templates.'] = 'Si le mode actif est acitvé, les balises de thème (comme EntryURL) afficheront les liens court au lieu des longs.';
l10n::$locales['You can disable URL shortening for a specific template tag by adding attribute disable_kutrl="1" to it .'] = 'Vous pouvez désactiver le raccourcissement pour un tag de template spécifique en lui ajoutant l\'attribue disable_kutrl="1"';
l10n::$locales['We strongly discourage using active mode as it crashes public post form and complex url if theme is not customize for kUtRL.'] = 'Nous décourageons fortement l\'utilisation du mode actif car il casse les formulaires en pages publiques et les liens complexe si le thème n\'est pas personnalisé pour utiliser kUtRL.';
l10n::$locales['Create short link for new entries'] = 'Créer un lien court pour les nouveaux billets';
l10n::$locales['This can be changed on page of creation/edition of an entry.'] = 'Ceci peut être changé sur la page d\'édition / création d\'un billet.';
l10n::$locales['Default services'] = 'Services par défaut';
l10n::$locales['Administration:'] = 'Administration :';
l10n::$locales['Service to use in this admin page and on edit page of an entry.'] = 'Service à utiliser sur cette page d\'administration ou sur la page d\'édition d\'un billet.';
l10n::$locales['Extensions:'] = 'Extensions :';
l10n::$locales['Service to use on third part plugins.'] = 'Service à utiliser par les plugins tiers';
l10n::$locales['Templates:'] = 'Templates :';
l10n::$locales['Shorten links automatically when using template value like "EntryKutrl".'] = 'Réduit automatiquement les liens des templates utilisant les balises telles que "EntryKutrl".';
l10n::$locales['Contents:'] = 'Contenus :';
l10n::$locales['Shorten links automatically found in contents using wiki synthax.'] = 'Réduit automatiquement les liens des contenus utilisant la syntax wiki.';
l10n::$locales['List of services you can use to shorten links with pkugin kUtRL.'] = 'Liste des services que vous pouvez utiliser pour réduire des liens à l\'aide du plugin kUtRL.';
l10n::$locales['Failed to test %s API.'] = 'Impossible de tester l\'API %s.';
l10n::$locales['%s API is well configured and runing.'] = 'L\'API %s est correctement configurée et est fonctionnelle.';
l10n::$locales['Failed to test service %s: %s'] = 'Impossible de tester le service %s : %s';
l10n::$locales['homepage'] = 'page d\'accueil';
l10n::$locales['Learn more about %s.'] = 'En savoir plus à propos de %s.';
l10n::$locales['Failed to verify protected field.'] = 'Impossible de vérifier le champs de protection.';
l10n::$locales['Service is not well configured.'] = 'Le service n\'est pas correctement configuré.';
l10n::$locales['This string is not a valid URL.'] = 'Cette chaine n\'est pas un lien valide.';
l10n::$locales['This link is too short.'] = 'Ce lien est trop court.';
l10n::$locales['This type of link is not allowed.'] = 'Ce type de lien n\'est pas autorisé.';
l10n::$locales['Short links are limited to this blog URL.'] = 'Les liens courts sont limités à l\'URL de ce blog.';
l10n::$locales['This link is already a short link.'] = 'Ce lien est dèjà un lien court.';
l10n::$locales['Short link for %s is %s'] = 'Le lien court pour %s est %s';
l10n::$locales['Failed to create short link.'] = 'Impossible de créer le lien court.';
l10n::$locales['New public short URL'] = 'Nouvelle URL courte';
l10n::$locales['Confirm by writing "%s" in next field:'] = 'Confirmez en écrivant "%s" dans le champs suivant :';
l10n::$locales['Shorten link'] = 'Réduire un lien';
l10n::$locales['Top of short links'] = 'Top des liens courts';
l10n::$locales['Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)'] = 'Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)';
l10n::$locales['URL length (if truncate)'] = 'Longueur de l\'URL (si tronqué)';
l10n::$locales['All'] = 'Tous';
l10n::$locales['Mini URL'] = 'Mini URL';
l10n::$locales['Custom URL'] = 'URL personnalisé';
l10n::$locales['Semi-custom'] = 'Semi-personnalisé';
l10n::$locales['Semi-custom prefix: (only if you want limit to a particular prefix)'] = 'Préfixe des liens semi-personnalisé : (Seulement si vous voulez limiter à un préfixe particulier)';
l10n::$locales['Sort by:'] = 'Trier par :';
l10n::$locales['Rank'] = 'Rang';
l10n::$locales['Limit:'] = 'Limite :';
l10n::$locales['Hide no followed links'] = 'Cacher les liens non suivis';
l10n::$locales['Long link:'] = 'Lien long :';
l10n::$locales['Rewrite "%s" in next field to show that you are not a robot:'] = 'Recopier "%s" dans le champs suivant pour montrer que vous n\'êtes pas une machine :';
l10n::$locales['Shorten'] = 'Raccourir';
l10n::$locales['Plugin kUtRL'] = 'Extension kUtRL';
l10n::$locales['Short link creation'] = 'Création de lien court';
l10n::$locales['New short link of type "%s" and hash "%s" was created.'] = 'Un nouveau lien court de type "%s" et de hash "%s" a été créé.';
l10n::$locales['No short link matches the filter'] = 'Aucun lien correspondant au filtre';
l10n::$locales['No short link'] = 'Pas de lien court';
l10n::$locales['List of %s links matching the filter.'] = 'Liste des %s liens correspondant au filtre.';
l10n::$locales['List of links (%s)'] = 'Listes des liens (%s)';
l10n::$locales['There is nothing to configure for this service.'] = 'Il n\'y a rien à configurer pour ce service.';
l10n::$locales['%s (Shorten with %s)'] = '%s (réduit avec %s)';
l10n::$locales['New short URL'] = 'Nouvelle URL courte';
l10n::$locales['Url of the service:'] = 'URL du service :';
l10n::$locales['This is the root URL of the "bilbolinks" service you want to use. Ex: "http://tux-pla.net/".'] = 'Ceci est l\'URL du service bilbolinks que vous souhaitez utiliser. Ex: "http://tux-pla.net/".';
l10n::$locales['Service is unavailable.'] = 'Le service n\'est pas disponible.';
l10n::$locales['Service rate limit exceeded.'] = 'La limitation d\'envoie au service est atteinte.';
l10n::$locales['API Key:'] = 'Clé API :';
l10n::$locales['This is your personnal %s API key. You can find it on your account page.'] = 'C\'est votre clé personnelle de l\'API %s. Vous pouvez la trouver sur la page de votre compte.';
l10n::$locales['Failed to call service.'] = 'Impossible d\'appeler le service.';
l10n::$locales['You can set a configurable service.'] = 'Vous pouvez configurer un service particulier.';
l10n::$locales['It consists on a simple query to an URL with only one param.'] = 'Il effectue une simple requête à une URL avec un seul paramètre.';
l10n::$locales['It must respond with a http code 200 on success.'] = 'Il doit répondre avec un code HTTP de 200 en cas de succès';
l10n::$locales['It must returned the short URL (or only hash) in clear text.'] = 'Il doit retourner l\'URL courte (ou seulement le hash) en texte clair.';
l10n::$locales['API URL:'] = 'URL de l\'API:';
l10n::$locales['Full path to API of the URL shortener. ex: "http://is.gd/api.php"'] = 'Chemin complet vers l\'API. ex: "http://is.gd.php"';
l10n::$locales['Short URL domain:'] = 'Domaine des URLs courtes:';
l10n::$locales['Common part of the short URL. ex: "http://is.gd/"'] = 'Partie commune aux URLs courtes. ex: "http://is.gd/"';
l10n::$locales['API URL param:'] = 'Paramètre de l\'URL';
l10n::$locales['Param of the query. ex: "longurl"'] = 'Paramètre de la raquête. ex: "longurl"';
l10n::$locales['Encode URL'] = 'Encoder l\'URL à raccourcir';
l10n::$locales['This service is set to:'] = 'Ce service est règlé comme suit:';
l10n::$locales['Full API URL:'] = 'URL complet vers l\'API:';
l10n::$locales['Query param:'] = 'Paramètre de la requête:';
l10n::$locales['Encode URL:'] = 'Encodage des URLs à raccourcir:';
l10n::$locales['Settings:'] = 'Paramètres :';
l10n::$locales['Allowed protocols:'] = 'Protocoles autorisés :';
l10n::$locales['Use comma seperated list like: "http:,https:,ftp:"'] = 'Utiliser une virgule pour séparer la liste des protocoles. Ex: "http:,https:,ftp:"';
l10n::$locales['Enable public page for visitors to shorten links'] = 'Activer la page publique pour que les visiteurs puissent réduire des liens';
l10n::$locales['CSS:'] = 'CSS :';
l10n::$locales['You can add here special cascading style sheet. Body of page has class "dc-kutrl" and widgets have class "shortenkutrlwidget" and "rankkutrlwidget".'] = 'Vous pouvez ajouter des styles ici. La balise "body" a la class "dc-kutrl" et les widgets ont les class "shortenkutrlwidget" et "rankkutrlwidget".';
l10n::$locales['Enable special 404 error public page for unknow urls'] = 'Activer la page spéciale d\'erreur 404 pour les liens inconnus';
l10n::$locales['If this is not activated, the default 404 page of the theme will be display.'] = 'Si cette option est désactivée, la page d\'erreur 404 par défaut du thème sera utilisée.';
l10n::$locales['Note:'] = 'Note :';
l10n::$locales['This service use your own Blog to shorten and serve URL.'] = 'Ce service utilise votre propre blog pour réduire et servir des liens.';
l10n::$locales['This means that with this service short links start with "%s".'] = 'Cela signifie qu\'avec ce service vos liens courts commencent par "%s".';
l10n::$locales['You can use Dotclear\'s plugin called myUrlHandlers to change short links prefix on your blog.'] = 'Vous pouvez utiliser l\'extension myUrlHandlers pour Dotclear afin de changer le prefix de vos liens courts depuis votre blog.';
l10n::$locales['We recommand that you use a rewrite engine in order to remove \'index.php\' from your blog\'s URL.'] = 'Nous vous recommandons d\'utiliser la réécriture d\'URL pour supprimer \'index.php de l\'URL de votre blog.';
l10n::$locales['You can find more about this on the Dotclear\'s documentation.'] = 'Vous trouverez plus d\'information à ce sujet dans la documentation Dotclear.';
l10n::$locales['There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.'] = 'Il y a deux templates livrés avec kUtRL, si vous n\'utilisez pas le thème par défaut, vous devrez peut-être les adapter au votre.';
l10n::$locales['Files are in plugin directory /default-templates, just copy them into your theme and edit them.'] = 'Les fichiers sont dans le répertoire /default-templates du plugin, copiez les dans votre thème et modifiez les.';
l10n::$locales['Custom short link is already taken.'] = 'Le lien court personnalisé est déjà pris.';
l10n::$locales['Custom short link is not valid.'] = 'Le lien court personnalisé n\'est pas valide.';
l10n::$locales['Failed to save link.'] = 'Impossible d\'enregistrer le lien.';
l10n::$locales['Login:'] = 'Identifiant :';
l10n::$locales['This is your login to sign up to %s'] = 'C\'est votre identifiant pour vous connecter sur %s';
l10n::$locales['An error occured with code %s and message "%s"'] = 'Une erreur est survenu avec le code "%s" et le message "%s"';
l10n::$locales['This is your login to sign up to tr.im.'] = 'Ceci est votre login d\'inscription sur tr.im.';
l10n::$locales['This is your password to sign up to tr.im.'] = 'Ceci est votre mot de passe d\'inscription sur tr.im.';
l10n::$locales['Prevent service rate limit.'] = 'Prévention de la limitation d\'envoie du service.';
l10n::$locales['Authentication to service failed.'] = 'Authentification au service échoué.';
l10n::$locales['Unreadable service response.'] = 'La réponse du service n\'est pas lisible.';
l10n::$locales['This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".'] = 'Ceci est l\'URL du service YOURLS que vous voulez utiliser. Ex: "http://www.smaller.org/api.php".';
l10n::$locales['This is your user name to sign up to this YOURLS service.'] = 'Ceci est votre nom d\'utilisateur pour vous connecter à ce service YOURLS.';
l10n::$locales['This is your password to sign up to this YOURLS service.'] = 'Ceci est votre mot de passe pour vous connecter à ce service YOURLS.';
l10n::$locales['There is nothing to shorten.'] = 'I n\'y a rien à réduire.';
l10n::$locales['This service does not allowed custom hash.'] = 'Ce service n\'accepte pas les liens court personnalisés.';
l10n::$locales['This link is not a valid URL.'] = 'Ce lien n\'est pas valide.';
l10n::$locales['This custom short url is already taken.'] = 'Ce lien court personnalisé est déjà pris.';
l10n::$locales['Failed to create short link. This could be caused by a service failure.'] = 'Impossible de créé un lien court. Ceci peut être causé par un problème du service.';
l10n::$locales['Service:'] = 'Service :';
l10n::$locales['Links successfully deleted'] = 'Liens supprimés avec succès';
l10n::$locales['New link'] = 'Nouveau lien';
l10n::$locales['You must set an admin service.'] = 'Vous devez définir un service admin.';
l10n::$locales['Shorten link using service "%s"'] = 'Raccourcir un lien en utilisant le service "%s"';
l10n::$locales['Only if you want a custom short link.'] = 'Uniquement si vous souhaitez un lien court personnalisé.';
l10n::$locales['You can use "bob!!" if you want a semi-custom link, it starts with "bob" and "!!" will be replaced by an increment value.'] = 'Vous pouvez utiliser "bob!!" si vous souhaitez un lien semi-personnalisé, il commencera par "bob" et "!!" sera remplacé par une valeur incrémentale.';
l10n::$locales['Delete selected short links'] = 'Effacer les liens court sélectionnés';
l10n::$locales['Configuration successfully saved'] = 'Configuration sauvegardée avec succès';
l10n::$locales['Plugin activation'] = 'Activation';
l10n::$locales['URL not found'] = 'Lien non trouvé';
l10n::$locales['The URL you are looking for does not exist.'] = 'Le liens que vous recherchez n\'existe pas.';
l10n::$locales['Create your own short URL'] = 'Créer votre propre lien court';
l10n::$locales['Publish history'] = 'Publier l\'historique';
l10n::$locales['This publish all short links on your bit.ly public page.'] = 'Ceci publie tous vos liens sur votre page public bit.ly';
l10n::$locales['Use, create and serve short url on your blog'] = 'Utiliser, créer et servir des liens court sur votre blog';
use Dotclear\Helper\L10n;
L10n::$locales['Links shortener'] = 'Réducteur de liens';
L10n::$locales['Long link:'] = 'Lien long :';
L10n::$locales['Shorten'] = 'Raccourir';
L10n::$locales['URL not found'] = 'Lien non trouvé';
L10n::$locales['The URL you are looking for does not exist.'] = 'Le liens que vous recherchez n\'existe pas.';
L10n::$locales['Create your own short URL'] = 'Créer votre propre lien court';
L10n::$locales['Plugin kUtRL'] = 'Extension kUtRL';
L10n::$locales['Short link creation'] = 'Création de lien court';
L10n::$locales['New short link of type "%s" and hash "%s" was created.'] = 'Un nouveau lien court de type "%s" et de hash "%s" a été créé.';
L10n::$locales['Hash'] = 'Hash';
L10n::$locales['Service'] = 'Service';
L10n::$locales['links per page'] = 'liens par page';
L10n::$locales['Create short link'] = 'Créer un lien court';
L10n::$locales['Custom short link:'] = 'Lien court personnalisé :';
L10n::$locales['never followed'] = 'jamais suivi';
L10n::$locales['followed one time'] = 'suivi une fois';
L10n::$locales['followed %s times'] = 'suivi %s fois';
L10n::$locales['Delete short link'] = 'Effacer un lien court';
L10n::$locales['Short link'] = 'Lien court';
L10n::$locales['No enough right'] = 'Privilèges insuffisants';
L10n::$locales['Posts short links have been created.'] = 'Les liens courts des billets ont été créé.';
L10n::$locales['Long link'] = 'Lien long';
L10n::$locales['Disabled'] = 'Désactiver';
L10n::$locales['Failed to test %s API.'] = 'Impossible de tester l\'API %s.';
L10n::$locales['%s API is well configured and runing.'] = 'L\'API %s est correctement configurée et est fonctionnelle.';
L10n::$locales['Failed to test service %s: %s'] = 'Impossible de tester le service %s : %s';
L10n::$locales['homepage'] = 'page d\'accueil';
L10n::$locales['Learn more about %s.'] = 'En savoir plus à propos de %s.';
L10n::$locales['Enable plugin'] = 'Activer le plugin';
L10n::$locales['Behaviors'] = 'Comportements';
L10n::$locales['Allow short link for external URL'] = 'Autoriser les liens court sur des URLs externes';
L10n::$locales['Not only link started with this blog URL could be shortened.'] = 'Ne pas limiter la création de liens courts aux liens commençant par l\'URL du blog.';
L10n::$locales['Passive mode'] = 'Mode passif';
L10n::$locales['If this extension is disabled and the passive mode is enabled, "kutrl" tags (like EntryKurl) will display long urls instead of nothing on templates.'] = 'Si cette extension est désactivée et que le mode passif est activé, les balises "kutrl" (comme EntryKutrl) afficheront les liens longs au lieu de rien.';
L10n::$locales['Active mode'] = 'Mode actif';
L10n::$locales['If the active mode is enabled, all know default template tags (like EntryURL) will display short urls instead of long ones on templates.'] = 'Si le mode actif est acitvé, les balises de thème (comme EntryURL) afficheront les liens court au lieu des longs.';
L10n::$locales['You can disable URL shortening for a specific template tag by adding attribute disable_kutrl="1" to it .'] = 'Vous pouvez désactiver le raccourcissement pour un tag de template spécifique en lui ajoutant l\'attribue disable_kutrl="1"';
L10n::$locales['We strongly discourage using active mode as it crashes public post form and complex url if theme is not customize for kUtRL.'] = 'Nous décourageons fortement l\'utilisation du mode actif car il casse les formulaires en pages publiques et les liens complexe si le thème n\'est pas personnalisé pour utiliser kUtRL.';
L10n::$locales['Create short link for new entries'] = 'Créer un lien court pour les nouveaux billets';
L10n::$locales['This can be changed on page of creation/edition of an entry.'] = 'Ceci peut être changé sur la page d\'édition / création d\'un billet.';
L10n::$locales['Default services'] = 'Services par défaut';
L10n::$locales['Administration:'] = 'Administration :';
L10n::$locales['Service to use in this admin page and on edit page of an entry.'] = 'Service à utiliser sur cette page d\'administration ou sur la page d\'édition d\'un billet.';
L10n::$locales['Extensions:'] = 'Extensions :';
L10n::$locales['Service to use on third part plugins.'] = 'Service à utiliser par les plugins tiers';
L10n::$locales['Templates:'] = 'Templates :';
L10n::$locales['Shorten links automatically when using template value like "EntryKutrl".'] = 'Réduit automatiquement les liens des templates utilisant les balises telles que "EntryKutrl".';
L10n::$locales['Contents:'] = 'Contenus :';
L10n::$locales['Shorten links automatically found in contents using wiki synthax.'] = 'Réduit automatiquement les liens des contenus utilisant la syntax wiki.';
L10n::$locales['List of services you can use to shorten links with pkugin kUtRL.'] = 'Liste des services que vous pouvez utiliser pour réduire des liens à l\'aide du plugin kUtRL.';
L10n::$locales['New public short URL'] = 'Nouvelle URL courte';
L10n::$locales['Confirm by writing "%s" in next field:'] = 'Confirmez en écrivant "%s" dans le champs suivant :';
L10n::$locales['Failed to verify protected field.'] = 'Impossible de vérifier le champs de protection.';
L10n::$locales['Service is not well configured.'] = 'Le service n\'est pas correctement configuré.';
L10n::$locales['This string is not a valid URL.'] = 'Cette chaine n\'est pas un lien valide.';
L10n::$locales['This link is too short.'] = 'Ce lien est trop court.';
L10n::$locales['This type of link is not allowed.'] = 'Ce type de lien n\'est pas autorisé.';
L10n::$locales['Short links are limited to this blog URL.'] = 'Les liens courts sont limités à l\'URL de ce blog.';
L10n::$locales['This link is already a short link.'] = 'Ce lien est dèjà un lien court.';
L10n::$locales['Short link for %s is %s'] = 'Le lien court pour %s est %s';
L10n::$locales['Failed to create short link.'] = 'Impossible de créer le lien court.';
L10n::$locales['No short link matches the filter'] = 'Aucun lien correspondant au filtre';
L10n::$locales['No short link'] = 'Pas de lien court';
L10n::$locales['List of %s links matching the filter.'] = 'Liste des %s liens correspondant au filtre.';
L10n::$locales['List of links. (%s)'] = 'Liste des liens. (%s)';
L10n::$locales['There is nothing to shorten.'] = 'Il n\'y a rien à réduire.';
L10n::$locales['This service does not allowed custom hash.'] = 'Ce service n\'accepte pas les liens court personnalisés.';
L10n::$locales['This link is not a valid URL.'] = 'Ce lien n\'est pas valide.';
L10n::$locales['This custom short url is already taken.'] = 'Ce lien court personnalisé est déjà pris.';
L10n::$locales['Failed to create short link. This could be caused by a service failure.'] = 'Impossible de créé un lien court. Ceci peut être causé par un problème du service.';
L10n::$locales['New short URL'] = 'Nouvelle URL courte';
L10n::$locales['New link'] = 'Nouveau lien';
L10n::$locales['You must set an admin service.'] = 'Vous devez définir un service admin.';
L10n::$locales['Only if you want a custom short link.'] = 'Uniquement si vous souhaitez un lien court personnalisé.';
L10n::$locales['You can use "bob!!" if you want a semi-custom link, it starts with "bob" and "!!" will be replaced by an increment value.'] = 'Vous pouvez utiliser "bob!!" si vous souhaitez un lien semi-personnalisé, il commencera par "bob" et "!!" sera remplacé par une valeur incrémentale.';
L10n::$locales['Shorten link using service "%s"'] = 'Raccourcir un lien en utilisant le service "%s"';
L10n::$locales['Service:'] = 'Service :';
L10n::$locales['Links successfully deleted'] = 'Liens supprimés avec succès';
L10n::$locales['Delete selected short links'] = 'Effacer les liens court sélectionnés';
L10n::$locales['Url of the service:'] = 'URL du service :';
L10n::$locales['This is the root URL of the "bilbolinks" service you want to use. Ex: "http://tux-pla.net/".'] = 'Ceci est l\'URL du service bilbolinks que vous souhaitez utiliser. Ex: "http://tux-pla.net/".';
L10n::$locales['Service is unavailable.'] = 'Le service n\'est pas disponible.';
L10n::$locales['Service rate limit exceeded.'] = 'La limitation d\'envoie au service est atteinte.';
L10n::$locales['API Key:'] = 'Clé API :';
L10n::$locales['This is your personnal %s API key. You can find it on your account page.'] = 'C\'est votre clé personnelle de l\'API %s. Vous pouvez la trouver sur la page de votre compte.';
L10n::$locales['Failed to call service.'] = 'Impossible d\'appeler le service.';
L10n::$locales['You can set a configurable service.'] = 'Vous pouvez configurer un service particulier.';
L10n::$locales['It consists on a simple query to an URL with only one param.'] = 'Il effectue une simple requête à une URL avec un seul paramètre.';
L10n::$locales['It must respond with a http code 200 on success.'] = 'Il doit répondre avec un code HTTP de 200 en cas de succès';
L10n::$locales['It must returned the short URL (or only hash) in clear text.'] = 'Il doit retourner l\'URL courte (ou seulement le hash) en texte clair.';
L10n::$locales['API URL:'] = 'URL de l\'API:';
L10n::$locales['Full path to API of the URL shortener. ex: "http://is.gd/api.php"'] = 'Chemin complet vers l\'API. ex: "http://is.gd.php"';
L10n::$locales['Short URL domain:'] = 'Domaine des URLs courtes:';
L10n::$locales['Common part of the short URL. ex: "http://is.gd/"'] = 'Partie commune aux URLs courtes. ex: "http://is.gd/"';
L10n::$locales['API URL param:'] = 'Paramètre de l\'URL';
L10n::$locales['Param of the query. ex: "longurl"'] = 'Paramètre de la raquête. ex: "longurl"';
L10n::$locales['Encode URL'] = 'Encoder l\'URL à raccourcir';
L10n::$locales['There is nothing to configure for this service.'] = 'Il n\'y a rien à configurer pour ce service.';
L10n::$locales['Full API URL:'] = 'URL complet vers l\'API:';
L10n::$locales['Query param:'] = 'Paramètre de la requête:';
L10n::$locales['Encode URL:'] = 'Encodage des URLs à raccourcir:';
L10n::$locales['Settings:'] = 'Paramètres :';
L10n::$locales['Allowed protocols:'] = 'Protocoles autorisés :';
L10n::$locales['Use comma seperated list like: "http:,https:,ftp:"'] = 'Utiliser une virgule pour séparer la liste des protocoles. Ex: "http:,https:,ftp:"';
L10n::$locales['Enable public page for visitors to shorten links'] = 'Activer la page publique pour que les visiteurs puissent réduire des liens';
L10n::$locales['CSS:'] = 'CSS :';
L10n::$locales['You can add here special cascading style sheet. Body of page has class "dc-kutrl" and widgets have class "shortenkutrlwidget" and "rankkutrlwidget".'] = 'Vous pouvez ajouter des styles ici. La balise "body" a la class "dc-kutrl" et les widgets ont les class "shortenkutrlwidget" et "rankkutrlwidget".';
L10n::$locales['Enable special 404 error public page for unknow urls'] = 'Activer la page spéciale d\'erreur 404 pour les liens inconnus';
L10n::$locales['If this is not activated, the default 404 page of the theme will be display.'] = 'Si cette option est désactivée, la page d\'erreur 404 par défaut du thème sera utilisée.';
L10n::$locales['Note:'] = 'Note :';
L10n::$locales['This service use your own Blog to shorten and serve URL.'] = 'Ce service utilise votre propre blog pour réduire et servir des liens.';
L10n::$locales['This means that with this service short links start with "%s".'] = 'Cela signifie qu\'avec ce service vos liens courts commencent par "%s".';
L10n::$locales['You can use Dotclear\'s plugin called myUrlHandlers to change short links prefix on your blog.'] = 'Vous pouvez utiliser l\'extension myUrlHandlers pour Dotclear afin de changer le prefix de vos liens courts depuis votre blog.';
L10n::$locales['We recommand that you use a rewrite engine in order to remove \'index.php\' from your blog\'s URL.'] = 'Nous vous recommandons d\'utiliser la réécriture d\'URL pour supprimer \'index.php de l\'URL de votre blog.';
L10n::$locales['You can find more about this on the Dotclear\'s documentation.'] = 'Vous trouverez plus d\'information à ce sujet dans la documentation Dotclear.';
L10n::$locales['There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.'] = 'Il y a deux templates livrés avec kUtRL, si vous n\'utilisez pas le thème par défaut, vous devrez peut-être les adapter au votre.';
L10n::$locales['Files are in plugin directory /default-templates, just copy them into your theme and edit them.'] = 'Les fichiers sont dans le répertoire /default-templates du plugin, copiez les dans votre thème et modifiez les.';
L10n::$locales['Custom short link is already taken.'] = 'Le lien court personnalisé est déjà pris.';
L10n::$locales['Custom short link is not valid.'] = 'Le lien court personnalisé n\'est pas valide.';
L10n::$locales['Failed to save link.'] = 'Impossible d\'enregistrer le lien.';
L10n::$locales['This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".'] = 'Ceci est l\'URL du service YOURLS que vous voulez utiliser. Ex: "http://www.smaller.org/api.php".';
L10n::$locales['Login:'] = 'Identifiant :';
L10n::$locales['This is your user name to sign up to this YOURLS service.'] = 'Ceci est votre nom d\'utilisateur pour vous connecter à ce service YOURLS.';
L10n::$locales['This is your password to sign up to this YOURLS service.'] = 'Ceci est votre mot de passe pour vous connecter à ce service YOURLS.';
L10n::$locales['Authentication to service failed.'] = 'Authentification au service échoué.';
L10n::$locales['Unreadable service response.'] = 'La réponse du service n\'est pas lisible.';
L10n::$locales['Shorten link'] = 'Réduire un lien';
L10n::$locales['Top of short links'] = 'Top des liens courts';
L10n::$locales['Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)'] = 'Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)';
L10n::$locales['URL length (if truncate)'] = 'Longueur de l\'URL (si tronqué)';
L10n::$locales['All'] = 'Tous';
L10n::$locales['Mini URL'] = 'Mini URL';
L10n::$locales['Custom URL'] = 'URL personnalisé';
L10n::$locales['Semi-custom'] = 'Semi-personnalisé';
L10n::$locales['Semi-custom prefix: (only if you want limit to a particular prefix)'] = 'Préfixe des liens semi-personnalisé : (Seulement si vous voulez limiter à un préfixe particulier)';
L10n::$locales['Sort by:'] = 'Trier par :';
L10n::$locales['Rank'] = 'Rang';
L10n::$locales['Limit:'] = 'Limite :';
L10n::$locales['Hide no followed links'] = 'Cacher les liens non suivis';
L10n::$locales['Rewrite "%s" in next field to show that you are not a robot:'] = 'Recopier "%s" dans le champs suivant pour montrer que vous n\'êtes pas une machine :';
L10n::$locales['%s (Shorten with %s)'] = '%s (réduit avec %s)';
L10n::$locales['List of links (%s)'] = 'Listes des liens (%s)';
L10n::$locales['This service is set to:'] = 'Ce service est règlé comme suit:';
L10n::$locales['This is your login to sign up to %s'] = 'C\'est votre identifiant pour vous connecter sur %s';
L10n::$locales['An error occured with code %s and message "%s"'] = 'Une erreur est survenu avec le code "%s" et le message "%s"';
L10n::$locales['This is your login to sign up to tr.im.'] = 'Ceci est votre login d\'inscription sur tr.im.';
L10n::$locales['This is your password to sign up to tr.im.'] = 'Ceci est votre mot de passe d\'inscription sur tr.im.';
L10n::$locales['Prevent service rate limit.'] = 'Prévention de la limitation d\'envoie du service.';
L10n::$locales['Configuration successfully saved'] = 'Configuration sauvegardée avec succès';
L10n::$locales['Publish history'] = 'Publier l\'historique';
L10n::$locales['This publish all short links on your bit.ly public page.'] = 'Ceci publie tous vos liens sur votre page public bit.ly';
L10n::$locales['Use, create and serve short url on your blog'] = 'Utiliser, créer et servir des liens court sur votre blog';

View File

@ -1,10 +1,10 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: kUtRL 2022.11.12\n"
"Project-Id-Version: kUtRL 2022.08.21\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2022-11-20T16:20:38+00:00\n"
"Last-Translator: Jean-Crhistian Denis\n"
"PO-Revision-Date: 2023-08-21T14:43:14+00:00\n"
"Last-Translator: Jean-Christain Denis\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
@ -13,18 +13,36 @@ msgstr ""
msgid "Links shortener"
msgstr "Réducteur de liens"
msgid "Short link"
msgstr "Lien court"
msgid "Long link:"
msgstr "Lien long :"
msgid "Long link"
msgstr "Lien long"
msgid "Shorten"
msgstr "Raccourir"
msgid "Service"
msgstr "Service"
msgid "URL not found"
msgstr "Lien non trouvé"
msgid "The URL you are looking for does not exist."
msgstr "Le liens que vous recherchez n'existe pas."
msgid "Create your own short URL"
msgstr "Créer votre propre lien court"
msgid "Plugin kUtRL"
msgstr "Extension kUtRL"
msgid "Short link creation"
msgstr "Création de lien court"
msgid "New short link of type \"%s\" and hash \"%s\" was created."
msgstr "Un nouveau lien court de type \"%s\" et de hash \"%s\" a été créé."
msgid "Hash"
msgstr "Hash"
msgid "Service"
msgstr "Service"
msgid "links per page"
msgstr "liens par page"
@ -46,15 +64,36 @@ msgstr "suivi %s fois"
msgid "Delete short link"
msgstr "Effacer un lien court"
msgid "Short link"
msgstr "Lien court"
msgid "No enough right"
msgstr "Privilèges insuffisants"
msgid "Posts short links have been created."
msgstr "Les liens courts des billets ont été créé."
msgid "Long link"
msgstr "Lien long"
msgid "Disabled"
msgstr "Désactiver"
msgid "Failed to test %s API."
msgstr "Impossible de tester l'API %s."
msgid "%s API is well configured and runing."
msgstr "L'API %s est correctement configurée et est fonctionnelle."
msgid "Failed to test service %s: %s"
msgstr "Impossible de tester le service %s : %s"
msgid "homepage"
msgstr "page d'accueil"
msgid "Learn more about %s."
msgstr "En savoir plus à propos de %s."
msgid "Enable plugin"
msgstr "Activer le plugin"
@ -121,20 +160,11 @@ msgstr "Réduit automatiquement les liens des contenus utilisant la syntax wiki.
msgid "List of services you can use to shorten links with pkugin kUtRL."
msgstr "Liste des services que vous pouvez utiliser pour réduire des liens à l'aide du plugin kUtRL."
msgid "Failed to test %s API."
msgstr "Impossible de tester l'API %s."
msgid "New public short URL"
msgstr "Nouvelle URL courte"
msgid "%s API is well configured and runing."
msgstr "L'API %s est correctement configurée et est fonctionnelle."
msgid "Failed to test service %s: %s"
msgstr "Impossible de tester le service %s : %s"
msgid "homepage"
msgstr "page d'accueil"
msgid "Learn more about %s."
msgstr "En savoir plus à propos de %s."
msgid "Confirm by writing \"%s\" in next field:"
msgstr "Confirmez en écrivant \"%s\" dans le champs suivant :"
msgid "Failed to verify protected field."
msgstr "Impossible de vérifier le champs de protection."
@ -163,69 +193,6 @@ msgstr "Le lien court pour %s est %s"
msgid "Failed to create short link."
msgstr "Impossible de créer le lien court."
msgid "New public short URL"
msgstr "Nouvelle URL courte"
msgid "Confirm by writing \"%s\" in next field:"
msgstr "Confirmez en écrivant \"%s\" dans le champs suivant :"
msgid "Shorten link"
msgstr "Réduire un lien"
msgid "Top of short links"
msgstr "Top des liens courts"
msgid "Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)"
msgstr "Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)"
msgid "URL length (if truncate)"
msgstr "Longueur de l'URL (si tronqué)"
msgid "All"
msgstr "Tous"
msgid "Mini URL"
msgstr "Mini URL"
msgid "Custom URL"
msgstr "URL personnalisé"
msgid "Semi-custom"
msgstr "Semi-personnalisé"
msgid "Semi-custom prefix: (only if you want limit to a particular prefix)"
msgstr "Préfixe des liens semi-personnalisé : (Seulement si vous voulez limiter à un préfixe particulier)"
msgid "Sort by:"
msgstr "Trier par :"
msgid "Rank"
msgstr "Rang"
msgid "Limit:"
msgstr "Limite :"
msgid "Hide no followed links"
msgstr "Cacher les liens non suivis"
msgid "Long link:"
msgstr "Lien long :"
msgid "Rewrite \"%s\" in next field to show that you are not a robot:"
msgstr "Recopier \"%s\" dans le champs suivant pour montrer que vous n'êtes pas une machine :"
msgid "Shorten"
msgstr "Raccourir"
msgid "Plugin kUtRL"
msgstr "Extension kUtRL"
msgid "Short link creation"
msgstr "Création de lien court"
msgid "New short link of type \"%s\" and hash \"%s\" was created."
msgstr "Un nouveau lien court de type \"%s\" et de hash \"%s\" a été créé."
msgid "No short link matches the filter"
msgstr "Aucun lien correspondant au filtre"
@ -235,18 +202,51 @@ msgstr "Pas de lien court"
msgid "List of %s links matching the filter."
msgstr "Liste des %s liens correspondant au filtre."
msgid "List of links (%s)"
msgstr "Listes des liens (%s)"
msgid "List of links. (%s)"
msgstr "Liste des liens. (%s)"
msgid "There is nothing to configure for this service."
msgstr "Il n'y a rien à configurer pour ce service."
msgid "There is nothing to shorten."
msgstr "Il n'y a rien à réduire."
msgid "%s (Shorten with %s)"
msgstr "%s (réduit avec %s)"
msgid "This service does not allowed custom hash."
msgstr "Ce service n'accepte pas les liens court personnalisés."
msgid "This link is not a valid URL."
msgstr "Ce lien n'est pas valide."
msgid "This custom short url is already taken."
msgstr "Ce lien court personnalisé est déjà pris."
msgid "Failed to create short link. This could be caused by a service failure."
msgstr "Impossible de créé un lien court. Ceci peut être causé par un problème du service."
msgid "New short URL"
msgstr "Nouvelle URL courte"
msgid "New link"
msgstr "Nouveau lien"
msgid "You must set an admin service."
msgstr "Vous devez définir un service admin."
msgid "Only if you want a custom short link."
msgstr "Uniquement si vous souhaitez un lien court personnalisé."
msgid "You can use \"bob!!\" if you want a semi-custom link, it starts with \"bob\" and \"!!\" will be replaced by an increment value."
msgstr "Vous pouvez utiliser \"bob!!\" si vous souhaitez un lien semi-personnalisé, il commencera par \"bob\" et \"!!\" sera remplacé par une valeur incrémentale."
msgid "Shorten link using service \"%s\""
msgstr "Raccourcir un lien en utilisant le service \"%s\""
msgid "Service:"
msgstr "Service :"
msgid "Links successfully deleted"
msgstr "Liens supprimés avec succès"
msgid "Delete selected short links"
msgstr "Effacer les liens court sélectionnés"
msgid "Url of the service:"
msgstr "URL du service :"
@ -301,8 +301,8 @@ msgstr "Paramètre de la raquête. ex: \"longurl\""
msgid "Encode URL"
msgstr "Encoder l'URL à raccourcir"
msgid "This service is set to:"
msgstr "Ce service est règlé comme suit:"
msgid "There is nothing to configure for this service."
msgstr "Il n'y a rien à configurer pour ce service."
msgid "Full API URL:"
msgstr "URL complet vers l'API:"
@ -370,9 +370,75 @@ msgstr "Le lien court personnalisé n'est pas valide."
msgid "Failed to save link."
msgstr "Impossible d'enregistrer le lien."
msgid "This is the URL of the YOURLS service you want to use. Ex: \"http://www.smaller.org/api.php\"."
msgstr "Ceci est l'URL du service YOURLS que vous voulez utiliser. Ex: \"http://www.smaller.org/api.php\"."
msgid "Login:"
msgstr "Identifiant :"
msgid "This is your user name to sign up to this YOURLS service."
msgstr "Ceci est votre nom d'utilisateur pour vous connecter à ce service YOURLS."
msgid "This is your password to sign up to this YOURLS service."
msgstr "Ceci est votre mot de passe pour vous connecter à ce service YOURLS."
msgid "Authentication to service failed."
msgstr "Authentification au service échoué."
msgid "Unreadable service response."
msgstr "La réponse du service n'est pas lisible."
msgid "Shorten link"
msgstr "Réduire un lien"
msgid "Top of short links"
msgstr "Top des liens courts"
msgid "Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)"
msgstr "Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)"
msgid "URL length (if truncate)"
msgstr "Longueur de l'URL (si tronqué)"
msgid "All"
msgstr "Tous"
msgid "Mini URL"
msgstr "Mini URL"
msgid "Custom URL"
msgstr "URL personnalisé"
msgid "Semi-custom"
msgstr "Semi-personnalisé"
msgid "Semi-custom prefix: (only if you want limit to a particular prefix)"
msgstr "Préfixe des liens semi-personnalisé : (Seulement si vous voulez limiter à un préfixe particulier)"
msgid "Sort by:"
msgstr "Trier par :"
msgid "Rank"
msgstr "Rang"
msgid "Limit:"
msgstr "Limite :"
msgid "Hide no followed links"
msgstr "Cacher les liens non suivis"
msgid "Rewrite \"%s\" in next field to show that you are not a robot:"
msgstr "Recopier \"%s\" dans le champs suivant pour montrer que vous n'êtes pas une machine :"
msgid "%s (Shorten with %s)"
msgstr "%s (réduit avec %s)"
msgid "List of links (%s)"
msgstr "Listes des liens (%s)"
msgid "This service is set to:"
msgstr "Ce service est règlé comme suit:"
msgid "This is your login to sign up to %s"
msgstr "C'est votre identifiant pour vous connecter sur %s"
@ -388,75 +454,9 @@ msgstr "Ceci est votre mot de passe d'inscription sur tr.im."
msgid "Prevent service rate limit."
msgstr "Prévention de la limitation d'envoie du service."
msgid "Authentication to service failed."
msgstr "Authentification au service échoué."
msgid "Unreadable service response."
msgstr "La réponse du service n'est pas lisible."
msgid "This is the URL of the YOURLS service you want to use. Ex: \"http://www.smaller.org/api.php\"."
msgstr "Ceci est l'URL du service YOURLS que vous voulez utiliser. Ex: \"http://www.smaller.org/api.php\"."
msgid "This is your user name to sign up to this YOURLS service."
msgstr "Ceci est votre nom d'utilisateur pour vous connecter à ce service YOURLS."
msgid "This is your password to sign up to this YOURLS service."
msgstr "Ceci est votre mot de passe pour vous connecter à ce service YOURLS."
msgid "There is nothing to shorten."
msgstr "I n'y a rien à réduire."
msgid "This service does not allowed custom hash."
msgstr "Ce service n'accepte pas les liens court personnalisés."
msgid "This link is not a valid URL."
msgstr "Ce lien n'est pas valide."
msgid "This custom short url is already taken."
msgstr "Ce lien court personnalisé est déjà pris."
msgid "Failed to create short link. This could be caused by a service failure."
msgstr "Impossible de créé un lien court. Ceci peut être causé par un problème du service."
msgid "Service:"
msgstr "Service :"
msgid "Links successfully deleted"
msgstr "Liens supprimés avec succès"
msgid "New link"
msgstr "Nouveau lien"
msgid "You must set an admin service."
msgstr "Vous devez définir un service admin."
msgid "Shorten link using service \"%s\""
msgstr "Raccourcir un lien en utilisant le service \"%s\""
msgid "Only if you want a custom short link."
msgstr "Uniquement si vous souhaitez un lien court personnalisé."
msgid "You can use \"bob!!\" if you want a semi-custom link, it starts with \"bob\" and \"!!\" will be replaced by an increment value."
msgstr "Vous pouvez utiliser \"bob!!\" si vous souhaitez un lien semi-personnalisé, il commencera par \"bob\" et \"!!\" sera remplacé par une valeur incrémentale."
msgid "Delete selected short links"
msgstr "Effacer les liens court sélectionnés"
msgid "Configuration successfully saved"
msgstr "Configuration sauvegardée avec succès"
msgid "Plugin activation"
msgstr "Activation"
msgid "URL not found"
msgstr "Lien non trouvé"
msgid "The URL you are looking for does not exist."
msgstr "Le liens que vous recherchez n'existe pas."
msgid "Create your own short URL"
msgstr "Créer votre propre lien court"
msgid "Publish history"
msgstr "Publier l'historique"

View File

@ -10,371 +10,59 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return null;
}
declare(strict_types=1);
dcCore::app()->blog->settings->addNamespace(basename(__DIR__));
namespace Dotclear\Plugin\kUtRL;
require_once __DIR__ . '/_widgets.php';
use dcCore;
use Dotclear\Core\Process;
# Plugin menu
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
__('Links shortener'),
dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)),
urldecode(dcPage::getPF(basename(__DIR__) . '/icon.svg')),
preg_match('/' . preg_quote(dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__))) . '(&.*)?$/', $_SERVER['REQUEST_URI']),
dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)
);
# Admin behaviors
if (dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) {
dcCore::app()->addBehavior('adminDashboardFavoritesV2', ['adminKutrl', 'antispamDashboardFavoritesV2']);
dcCore::app()->addBehavior('adminColumnsListsV2', ['adminKutrl', 'adminColumnsListsV2']);
dcCore::app()->addBehavior('adminFiltersListsV2', ['adminKutrl', 'adminFiltersListsV2']);
dcCore::app()->addBehavior('adminPostHeaders', ['adminKutrl', 'adminPostHeaders']);
dcCore::app()->addBehavior('adminPostFormItems', ['adminKutrl', 'adminPostFormItems']);
dcCore::app()->addBehavior('adminAfterPostUpdate', ['adminKutrl', 'adminAfterPostUpdate']); // update existing short url
dcCore::app()->addBehavior('adminAfterPostUpdate', ['adminKutrl', 'adminAfterPostCreate']); // create new short url
dcCore::app()->addBehavior('adminAfterPostCreate', ['adminKutrl', 'adminAfterPostCreate']);
dcCore::app()->addBehavior('adminBeforePostDelete', ['adminKutrl', 'adminBeforePostDelete']);
dcCore::app()->addBehavior('adminPostsActions', ['adminKutrl', 'adminPostsActions']);
}
dcCore::app()->addBehavior('exportFullV2', ['backupKutrl', 'exportFullV2']);
dcCore::app()->addBehavior('exportSingleV2', ['backupKutrl', 'exportSingleV2']);
dcCore::app()->addBehavior('importInitV2', ['backupKutrl', 'importInitV2']);
dcCore::app()->addBehavior('importSingleV2', ['backupKutrl', 'importSingleV2']);
dcCore::app()->addBehavior('importFullV2', ['backupKutrl', 'importFullV2']);
# Admin behaviors class
class adminKutrl
/**
* Backend prepend.
*/
class Backend extends Process
{
public static function sortbyCombo()
public static function init(): bool
{
return [
__('Date') => 'kut_dt',
__('Short link') => 'kut_hash',
__('Long link') => 'kut_url',
__('Service') => 'kut_service',
];
return self::status(My::checkContext(My::BACKEND));
}
public static function antispamDashboardFavoritesV2(dcFavorites $favs)
public static function process(): bool
{
$favs->register(
'kUtRL',
[
'title' => __('Links shortener'),
'url' => dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)),
'small-icon' => dcPage::getPF(basename(__DIR__) . '/icon.png'),
'large-icon' => dcPage::getPF(basename(__DIR__) . '/icon-b.png'),
'permissions' => dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]),
]
);
}
public static function adminColumnsListsV2($cols)
{
$cols['kUtRL'] = [
__('Links shortener'),
[
'kut_hash' => [true, __('Hash')],
'kut_dt' => [true, __('Date')],
'kut_service' => [true, __('Service')],
],
];
}
public static function adminFiltersListsV2($sorts)
{
$sorts['kUtRL'] = [
__('Links shortener'),
self::sortbyCombo(),
'kut_dt',
'desc',
[__('links per page'), 30],
];
}
public static function adminPostHeaders()
{
return dcPage::jsModuleLoad(basename(__DIR__) . '/js/posts.js');
}
public static function adminPostFormItems($main_items, $sidebar_items, $post)
{
$s = dcCore::app()->blog->settings->get(basename(__DIR__));
if (!$s->get('active') || !$s->get('active')) {
return null;
}
if (null === ($kut = kUtRL::quickPlace('admin'))) {
return null;
if (!self::status()) {
return false;
}
if ($post) {
$post_url = $post->getURL();
$rs = $kut->isKnowUrl($post_url);
} else {
$post_url = '';
$rs = false;
// sidebar menu
My::addBackendMenuItem();
# Admin behaviors
if (My::settings()->get('active')) {
dcCore::app()->addBehaviors([
'adminDashboardFavoritesV2' => [BackendBehaviors::class, 'antispamDashboardFavoritesV2'],
'adminColumnsListsV2' => [BackendBehaviors::class, 'adminColumnsListsV2'],
'adminFiltersListsV2' => [BackendBehaviors::class, 'adminFiltersListsV2'],
'adminPostHeaders' => [BackendBehaviors::class, 'adminPostHeaders'],
'adminPostFormItems' => [BackendBehaviors::class, 'adminPostFormItems'],
'adminAfterPostUpdate' => [BackendBehaviors::class, 'adminAfterPostUpdate'], // update existing short url
'adminAfterPostUpdate' => [BackendBehaviors::class, 'adminAfterPostCreate'], // create new short url
'adminAfterPostCreate' => [BackendBehaviors::class, 'adminAfterPostCreate'],
'adminBeforePostDelete' => [BackendBehaviors::class, 'adminBeforePostDelete'],
'adminPostsActions' => [BackendBehaviors::class, 'adminPostsActions'],
]);
}
$ret = '<div id="kUtRL"><h5>' . __('Short link') . '</h5>' .
form::hidden(['kutrl_old_post_url'], $post_url);
dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initShorten']);
dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initRank']);
if (!$rs) {
if (empty($_POST['kutrl_old_post_url']) && $s->get('admin_entry_default')) {
$chk = true;
} else {
$chk = !empty($_POST['kutrl_create']);
}
$ret .= '<p><label class="classic">' .
form::checkbox('kutrl_create', 1, $chk, '', '3') . ' ' .
__('Create short link') . '</label></p>';
dcCore::app()->addBehaviors([
'exportFullV2' => [ImportExportBehaviors::class, 'exportFullV2'],
'exportSingleV2' => [ImportExportBehaviors::class, 'exportSingleV2'],
'importInitV2' => [ImportExportBehaviors::class, 'importInitV2'],
'importSingleV2' => [ImportExportBehaviors::class, 'importSingleV2'],
'importFullV2' => [ImportExportBehaviors::class, 'importFullV2'],
]);
if ($kut->allow_custom_hash) {
$ret .= '<p class="classic">' .
'<label for="custom">' . __('Custom short link:') . ' ' .
form::field('kutrl_create_custom', 32, 32, '', '3') .
'</label></p>';
}
} else {
$count = $rs->counter;
if ($count == 0) {
$title = __('never followed');
} elseif ($count == 1) {
$title = __('followed one time');
} else {
$title = sprintf(__('followed %s times'), $count);
}
$href = $kut->url_base . $rs->hash;
$ret .= '<p><label class="classic">' .
form::checkbox('kutrl_delete', 1, !empty($_POST['kutrl_delete']), '', '3') . ' ' .
__('Delete short link') . '</label></p>' .
'<p><a href="' . $href . '" ' . 'title="' . $title . '">' . $href . '</a></p>';
}
$ret .= '</div>';
$sidebar_items['options-box']['items']['kUtRL'] = $ret;
}
public static function adminAfterPostUpdate($cur, $post_id)
{
# Create: see adminAfterPostCreate
if (!empty($_POST['kutrl_create']) || !dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) {
return null;
}
if (null === ($kut = kUtRL::quickPlace('admin'))) {
return null;
}
if (empty($_POST['kutrl_old_post_url'])) {
return null;
}
$old_post_url = $_POST['kutrl_old_post_url'];
if (!($rs = $kut->isKnowUrl($old_post_url))) {
return null;
}
$rs = dcCore::app()->blog->getPosts(['post_id' => $post_id]);
if ($rs->isEmpty()) {
return null;
}
$title = html::escapeHTML($rs->post_title);
$new_post_url = $rs->getURL();
# Delete
if (!empty($_POST['kutrl_delete'])) {
$kut->remove($old_post_url);
# Update
} else {
if ($old_post_url == $new_post_url) {
return null;
}
$kut->remove($old_post_url);
$rs = $kut->hash($new_post_url, '');//$custom); // better to update (not yet implemented)
$url = $kut->url_base . $rs->hash;
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('adminAfterKutrlCreate', $rs, $title);
}
}
}
public static function adminAfterPostCreate($cur, $post_id)
{
if (empty($_POST['kutrl_create']) || !dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) {
return null;
}
if (null === ($kut = kUtRL::quickPlace('admin'))) {
return null;
}
$rs = dcCore::app()->blog->getPosts(['post_id' => $post_id]);
if ($rs->isEmpty()) {
return null;
}
$title = html::escapeHTML($rs->post_title);
$custom = !empty($_POST['kutrl_create_custom']) && $kut->allow_custom_hash ?
$_POST['kutrl_create_custom'] : null;
$rs = $kut->hash($rs->getURL(), $custom);
$url = $kut->url_base . $rs->hash;
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('adminAfterKutrlCreate', $rs, $title);
}
}
public static function adminBeforePostDelete($post_id)
{
if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) {
return null;
}
if (null === ($kut = kUtRL::quickPlace('admin'))) {
return null;
}
$rs = dcCore::app()->blog->getPosts(['post_id' => $post_id]);
if ($rs->isEmpty()) {
return null;
}
$kut->remove($rs->getURL());
}
public static function adminPostsActions(dcPostsActions $pa)
{
if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')
|| !dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) {
return null;
}
$pa->addAction(
[__('Links shortener') => [__('Create short link') => 'kutrl_create']],
['adminKutrl', 'callbackCreate']
);
$pa->addAction(
[__('Links shortener') => [__('Delete short link') => 'kutrl_delete']],
['adminKutrl', 'callbackDelete']
);
}
public static function callbackCreate(dcPostsActions $pa, ArrayObject $post)
{
# No entry
$posts_ids = $pa->getIDs();
if (empty($posts_ids)) {
throw new Exception(__('No entry selected'));
}
# No right
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) {
throw new Exception(__('No enough right'));
}
if (null === ($kut = kUtRL::quickPlace('admin'))) {
return null;
}
# retrieve posts info and create hash
$posts = dcCore::app()->blog->getPosts(['post_id' => $posts_ids]);
while ($posts->fetch()) {
$kut->hash($posts->getURL());
}
dcAdminNotices::addSuccessNotice(__('Posts short links have been created.'));
$pa->redirect(true);
}
public static function callbackDelete(dcPostsActions $pa, ArrayObject $post)
{
# No entry
$posts_ids = $pa->getIDs();
if (empty($posts_ids)) {
throw new Exception(__('No entry selected'));
}
# No right
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) {
throw new Exception(__('No enough right'));
}
if (null === ($kut = kUtRL::quickPlace('admin'))) {
return null;
}
# retrieve posts info and create hash
$posts = dcCore::app()->blog->getPosts(['post_id' => $posts_ids]);
while ($posts->fetch()) {
$kut->remove($posts->getURL());
}
dcAdminNotices::addSuccessNotice(__('Posts short links have been created.'));
$pa->redirect(true);
}
}
# Import/export behaviors for Import/export plugin
class backupKutrl
{
public static function exportSingleV2($exp, $blog_id)
{
$exp->export(
'kutrl',
'SELECT kut_id, blog_id, kut_service, kut_type, ' .
'kut_hash, kut_url, kut_dt, kut_password, kut_counter ' .
'FROM ' . dcCore::app()->prefix . initkUtRL::KURL_TABLE_NAME . ' ' .
"WHERE blog_id = '" . $blog_id . "' "
);
}
public static function exportFullV2($exp)
{
$exp->exportTable('kutrl');
}
public static function importInitV2($bk)
{
$bk->cur_kutrl = dcCore::app()->con->openCursor(dcCore::app()->prefix . initkUtRL::KURL_TABLE_NAME);
$bk->kutrl = new kutrlLog();
}
public static function importSingleV2($line, $bk)
{
if ($line->__name == 'kutrl') {
# Do nothing if str/type exists !
if (false === $bk->kutrl->select($line->kut_url, $line->kut_hash, $line->kut_type, $line->kut_service)) {
$bk->kutrl->insert($line->kut_url, $line->kut_hash, $line->kut_type, $line->kut_service);
}
}
}
public static function importFullV2($line, $bk)
{
if ($line->__name == 'kutrl') {
$bk->cur_kutrl->clean();
$bk->cur_kutrl->kut_id = (int) $line->kut_id;
$bk->cur_kutrl->blog_id = (string) $line->blog_id;
$bk->cur_kutrl->kut_service = (string) $line->kut_service;
$bk->cur_kutrl->kut_type = (string) $line->kut_type;
$bk->cur_kutrl->kut_hash = (string) $line->kut_hash;
$bk->cur_kutrl->kut_url = (string) $line->kut_url;
$bk->cur_kutrl->kut_dt = (string) $line->miniurl_dt;
$bk->cur_kutrl->kut_counter = (int) $line->kut_counter;
$bk->cur_kutrl->kut_password = (string) $line->kut_password;
$bk->cur_kutrl->insert();
}
return true;
}
}

View File

@ -0,0 +1,326 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use ArrayObject;
use dcCore;
use Dotclear\Core\Backend\{
Action\ActionsPosts,
Favorites,
Notices
};
use Dotclear\Database\MetaRecord;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
Hidden,
Input,
Label,
Link,
Para,
Text
};
use Dotclear\Helper\Html\Html;
use Exception;
# Admin behaviors class
class BackendBehaviors
{
public static function antispamDashboardFavoritesV2(Favorites $favs): void
{
$favs->register(
My::id(),
[
'title' => My::name(),
'url' => My::manageUrl(),
'small-icon' => My::icons(),
'large-icon' => My::icons(),
'permissions' => dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_ADMIN]),
]
);
}
public static function adminColumnsListsV2(ArrayObject $cols): void
{
$cols[My::id()] = [
My::name(),
[
'kut_hash' => [true, __('Hash')],
'kut_dt' => [true, __('Date')],
'kut_service' => [true, __('Service')],
],
];
}
public static function adminFiltersListsV2(ArrayObject $sorts): void
{
$sorts[My::id()] = [
My::name(),
Combo::sortbyCombo(),
'kut_dt',
'desc',
[__('links per page'), 30],
];
}
public static function adminPostHeaders(): string
{
return My::jsLoad('posts');
}
public static function adminPostFormItems(ArrayObject $main_items, ArrayObject $sidebar_items, ?MetaRecord $post): void
{
$s = My::settings();
if (!$s->get('active')
|| !$s->get('active')
|| null === ($kut = Utils::quickPlace('admin'))
) {
return;
}
$post_url = '';
$rs = false;
if ($post) {
$post_url = $post->getURL();
$rs = $kut->isKnowUrl($post_url);
}
$items = [];
if (!$rs) {
$chk = !empty($_POST['kutrl_create']);
if (empty($_POST['kutrl_old_post_url']) && $s->get('admin_entry_default')) {
$chk = true;
}
$items[] = (new Para())
->items([
(new Checkbox('kutrl_create', $chk))
->value(1),
(new Label(__('Create short link'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('kutrl_create'),
]);
if ($kut->allow_custom_hash) {
$items[] = (new Para())
->class('classic')
->items([
(new Label(__('Custom short link:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_create_custom'),
(new Input('kutrl_create_custom'))
->size(32)
->maxlenght(32)
->class('maximal')
->value(''),
]);
}
} else {
$count = $rs->counter;
if ($count == 0) {
$title = __('never followed');
} elseif ($count == 1) {
$title = __('followed one time');
} else {
$title = sprintf(__('followed %s times'), $count);
}
$href = $kut->url_base . $rs->hash;
$items[] = (new Para())
->items([
(new Checkbox('kutrl_delete', !empty($_POST['kutrl_delete'])))
->value(1),
(new Label(__('Delete short link'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('kutrl_delete'),
]);
$items[] = (new Para())
->items([
(new Link())
->href($href)
->title($title)
->text($href),
]);
}
$sidebar_items['options-box']['items'][My::id()] = (new Div(My::id()))
->items([
(new Text('h5', __('Short link'))),
(new Hidden('kutrl_old_post_url', $post_url)),
... $items,
])
->render();
}
public static function adminAfterPostUpdate(Cursor $cur, string|int $post_id): void
{
# Create: see adminAfterPostCreate
if (!empty($_POST['kutrl_create'])
|| !My::settings()->get('active')
|| null === ($kut = Utils::quickPlace('admin'))
|| empty($_POST['kutrl_old_post_url'])
) {
return;
}
$old_post_url = $_POST['kutrl_old_post_url'];
if (!($rs = $kut->isKnowUrl($old_post_url))) {
return;
}
$rs = dcCore::app()->blog->getPosts(['post_id' => $post_id]);
if ($rs->isEmpty()) {
return;
}
$title = Html::escapeHTML($rs->post_title);
$new_post_url = $rs->getURL();
# Delete
if (!empty($_POST['kutrl_delete'])) {
$kut->remove($old_post_url);
# Update
} else {
if ($old_post_url == $new_post_url) {
return;
}
$kut->remove($old_post_url);
$rs = $kut->hash($new_post_url, '');//$custom); // better to update (not yet implemented)
$url = $kut->url_base . $rs->hash;
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('adminAfterKutrlCreate', $rs, $title);
}
}
}
public static function adminAfterPostCreate(Cursor $cur, int $post_id): void
{
if (empty($_POST['kutrl_create'])
|| !My::settings()->get('active')
|| null === ($kut = Utils::quickPlace('admin'))
) {
return;
}
$rs = dcCore::app()->blog->getPosts(['post_id' => $post_id]);
if ($rs->isEmpty()) {
return;
}
$title = Html::escapeHTML($rs->post_title);
$custom = !empty($_POST['kutrl_create_custom']) && $kut->allow_custom_hash ?
$_POST['kutrl_create_custom'] : null;
$rs = $kut->hash($rs->getURL(), $custom);
$url = $kut->url_base . $rs->hash;
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('adminAfterKutrlCreate', $rs, $title);
}
}
public static function adminBeforePostDelete(string|int $post_id): void
{
if (!My::settings()->get('active')
|| null === ($kut = Utils::quickPlace('admin'))
) {
return;
}
$rs = dcCore::app()->blog->getPosts(['post_id' => $post_id]);
if ($rs->isEmpty()) {
return;
}
$kut->remove($rs->getURL());
}
public static function adminPostsActions(ActionsPosts $pa): void
{
if (!My::settings()->get('active')
|| !dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) {
return;
}
$pa->addAction(
[My::name() => [__('Create short link') => 'kutrl_create']],
[self::class, 'callbackCreate']
);
$pa->addAction(
[My::name() => [__('Delete short link') => 'kutrl_delete']],
[self::class, 'callbackDelete']
);
}
public static function callbackCreate(ActionsPosts $pa, ArrayObject $post): void
{
# No entry
$posts_ids = $pa->getIDs();
if (empty($posts_ids)) {
throw new Exception(__('No entry selected'));
}
# No right
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) {
throw new Exception(__('No enough right'));
}
if (null === ($kut = Utils::quickPlace('admin'))) {
return;
}
# retrieve posts info and create hash
$posts = dcCore::app()->blog->getPosts(['post_id' => $posts_ids]);
while ($posts->fetch()) {
$kut->hash($posts->getURL());
}
Notices::addSuccessNotice(__('Posts short links have been created.'));
$pa->redirect(true);
}
public static function callbackDelete(ActionsPosts $pa, ArrayObject $post): void
{
# No entry
$posts_ids = $pa->getIDs();
if (empty($posts_ids)) {
throw new Exception(__('No entry selected'));
}
# No right
if (!dcCore::app()->auth->check(dcCore::app()->auth->makePermissions([dcCore::app()->auth::PERMISSION_ADMIN]), dcCore::app()->blog->id)) {
throw new Exception(__('No enough right'));
}
if (null === ($kut = Utils::quickPlace('admin'))) {
return;
}
# retrieve posts info and create hash
$posts = dcCore::app()->blog->getPosts(['post_id' => $posts_ids]);
while ($posts->fetch()) {
$kut->remove($posts->getURL());
}
Notices::addSuccessNotice(__('Posts short links have been created.'));
$pa->redirect(true);
}
}

48
src/Combo.php 100644
View File

@ -0,0 +1,48 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
class Combo
{
/**
* @return array<string,string>
*/
public static function sortbyCombo(): array
{
return [
__('Date') => 'kut_dt',
__('Short link') => 'kut_hash',
__('Long link') => 'kut_url',
__('Service') => 'kut_service',
];
}
/**
* @return array<string,string>
*/
public static function ServicesCombo(bool $with_none = false): array
{
$services_combo = [];
foreach (Utils::getServices() as $service_id => $service) {
$o = new $service();
$services_combo[__($o->name)] = $o->id;
}
if ($with_none) {
$services_combo = array_merge([__('Disabled') => ''], $services_combo);
}
return $services_combo;
}
}

View File

@ -10,186 +10,320 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return;
}
declare(strict_types=1);
# Check user perms
dcPage::check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN]));
namespace Dotclear\Plugin\kUtRL;
# Settings
$s = dcCore::app()->blog->settings->get(basename(__DIR__));
use dcCore;
use Dotclear\Core\Backend\Notices;
use Dotclear\Core\Process;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
Label,
Link,
Note,
Para,
Select,
Text
};
use Exception;
# Default values
$img_green = '<img src="images/check-on.png" alt="ok" />';
$img_red = '<img src="images/check-off.png" alt="fail" />';
/**
* Backend module configuration.
*/
class Config extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::CONFIG));
}
$services_combo = [];
foreach (kUtRL::getServices() as $service_id => $service) {
$o = new $service();
$services_combo[__($o->name)] = $o->id;
}
$ext_services_combo = array_merge([__('Disabled') => ''], $services_combo);
$lst_services_combo = array_merge(['-' => ''], $services_combo);
$s_active = (bool) $s->get('active');
$s_plugin_service = (string) $s->get('plugin_service');
$s_admin_service = (string) $s->get('admin_service');
$s_tpl_service = (string) $s->get('tpl_service');
$s_wiki_service = (string) $s->get('wiki_service');
$s_allow_external_url = (bool) $s->get('allow_external_url');
$s_tpl_passive = (bool) $s->get('tpl_passive');
$s_tpl_active = (bool) $s->get('tpl_active');
$s_admin_entry_default = (string) $s->get('admin_entry_default');
if (!empty($_POST['save'])) {
try {
# settings
$s_active = !empty($_POST['s_active']);
$s_admin_service = (string) $_POST['s_admin_service'];
$s_plugin_service = (string) $_POST['s_plugin_service'];
$s_tpl_service = (string) $_POST['s_tpl_service'];
$s_wiki_service = (string) $_POST['s_wiki_service'];
$s_allow_external_url = !empty($_POST['s_allow_external_url']);
$s_tpl_passive = !empty($_POST['s_tpl_passive']);
$s_tpl_active = !empty($_POST['s_tpl_active']);
$s_admin_entry_default = !empty($_POST['s_admin_entry_default']);
$s->put('active', $s_active);
$s->put('plugin_service', $s_plugin_service);
$s->put('admin_service', $s_admin_service);
$s->put('tpl_service', $s_tpl_service);
$s->put('wiki_service', $s_wiki_service);
$s->put('allow_external_url', $s_allow_external_url);
$s->put('tpl_passive', $s_tpl_passive);
$s->put('tpl_active', $s_tpl_active);
$s->put('admin_entry_default', $s_admin_entry_default);
# services
foreach (kUtRL::getServices() as $service_id => $service) {
$o = new $service();
$o->saveSettings();
public static function process(): bool
{
if (!self::status()) {
return false;
}
dcCore::app()->blog->triggerBlog();
// no action
if (empty($_POST['save'])) {
return true;
}
dcAdminNotices::addSuccessNotice(
__('Configuration successfully updated.')
);
# Settings
$s = My::settings();
dcCore::app()->adminurl->redirect(
'admin.plugins',
['module' => basename(__DIR__), 'conf' => 1, 'chk' => 1, 'redir' => dcCore::app()->admin->list->getRedir()]
);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
}
$s_active = (bool) $s->get('active');
$s_plugin_service = (string) $s->get('plugin_service');
$s_admin_service = (string) $s->get('admin_service');
$s_tpl_service = (string) $s->get('tpl_service');
$s_wiki_service = (string) $s->get('wiki_service');
$s_allow_external_url = (bool) $s->get('allow_external_url');
$s_tpl_passive = (bool) $s->get('tpl_passive');
$s_tpl_active = (bool) $s->get('tpl_active');
$s_admin_entry_default = (string) $s->get('admin_entry_default');
echo '
<div class="fieldset"><h4>' . __('Settings') . '</h4>
<div id="setting-plugin">
<h5>' . __('Activation') . '</h5>
<p><label class="classic">' .
form::checkbox(['s_active'], '1', $s_active) .
__('Enable plugin') . '</label></p>
</div>
if (!empty($_POST['save'])) {
try {
# settings
$s_active = !empty($_POST['s_active']);
$s_admin_service = (string) $_POST['s_admin_service'];
$s_plugin_service = (string) $_POST['s_plugin_service'];
$s_tpl_service = (string) $_POST['s_tpl_service'];
$s_wiki_service = (string) $_POST['s_wiki_service'];
$s_allow_external_url = !empty($_POST['s_allow_external_url']);
$s_tpl_passive = !empty($_POST['s_tpl_passive']);
$s_tpl_active = !empty($_POST['s_tpl_active']);
$s_admin_entry_default = !empty($_POST['s_admin_entry_default']);
<hr/><div id="setting-option">
<h5>' . __('Behaviors') . '</h5>
<p><label class="classic">' .
form::checkbox(['s_allow_external_url'], '1', $s_allow_external_url) .
__('Allow short link for external URL') . '</label></p>
<p class="form-note">' . __('Not only link started with this blog URL could be shortened.') . '</p>
<p><label class="classic">' .
form::checkbox(['s_tpl_passive'], '1', $s_tpl_passive) .
__('Passive mode') . '</label></p>
<p class="form-note">' . __('If this extension is disabled and the passive mode is enabled, "kutrl" tags (like EntryKurl) will display long urls instead of nothing on templates.') . '</p>
<p><label class="classic">' .
form::checkbox(['s_tpl_active'], '1', $s_tpl_active) .
__('Active mode') . '</label></p>
<p class="form-note">' . __('If the active mode is enabled, all know default template tags (like EntryURL) will display short urls instead of long ones on templates.') . '<br />' .
__('You can disable URL shortening for a specific template tag by adding attribute disable_kutrl="1" to it . ') . '</p>
<p class="warning">' . __('We strongly discourage using active mode as it crashes public post form and complex url if theme is not customize for kUtRL.') . '</p>
<p><label class="classic">' .
form::checkbox(['s_admin_entry_default'], '1', $s_admin_entry_default) .
__('Create short link for new entries') . '</label></p>
<p class="form-note">' . __('This can be changed on page of creation/edition of an entry.') . '</p>
</div>
$s->put('active', $s_active);
$s->put('plugin_service', $s_plugin_service);
$s->put('admin_service', $s_admin_service);
$s->put('tpl_service', $s_tpl_service);
$s->put('wiki_service', $s_wiki_service);
$s->put('allow_external_url', $s_allow_external_url);
$s->put('tpl_passive', $s_tpl_passive);
$s->put('tpl_active', $s_tpl_active);
$s->put('admin_entry_default', $s_admin_entry_default);
<hr/><div id="setting-service">
<h5>' . __('Default services') . '</h5>
<p><label>';
if (!empty($_REQUEST['chk'])) {
if (null !== ($o = kUtRL::quickPlace($s_admin_service))) {
echo $o->testService() ? $img_green : $img_red;
}
}
echo '&nbsp;' . __('Administration:') . '<br />' .
form::combo(['s_admin_service'], $services_combo, $s_admin_service) . '
</label></p>
<p class="form-note">' . __('Service to use in this admin page and on edit page of an entry.') . '</p>
<p><label>';
if (!empty($_REQUEST['chk'])) {
if (null !== ($o = kUtRL::quickPlace($s_plugin_service))) {
echo $o->testService() ? $img_green : $img_red;
}
}
echo '&nbsp;' . __('Extensions:') . '<br />' .
form::combo(['s_plugin_service'], $services_combo, $s_plugin_service) . '
</label></p>
<p class="form-note">' . __('Service to use on third part plugins.') . '</p>
<p><label>';
if (!empty($_REQUEST['chk'])) {
if (null !== ($o = kUtRL::quickPlace($s_tpl_service))) {
echo $o->testService() ? $img_green : $img_red;
}
}
echo '&nbsp;' . __('Templates:') . '<br />' .
form::combo(['s_tpl_service'], $ext_services_combo, $s_tpl_service) . '
</label></p>
<p class="form-note">' . __('Shorten links automatically when using template value like "EntryKutrl".') . '</p>
<p><label>';
if (!empty($_REQUEST['chk'])) {
if (null !== ($o = kUtRL::quickPlace($s_wiki_service))) {
echo $o->testService() ? $img_green : $img_red;
}
}
echo '&nbsp;' . __('Contents:') . '<br />' .
form::combo(['s_wiki_service'], $ext_services_combo, $s_wiki_service) . '
</label></p>
<p class="form-note">' . __('Shorten links automatically found in contents using wiki synthax.') . '</p>
</div>
</div>
# services
foreach (Utils::getServices() as $service_id => $service) {
$o = new $service();
$o->saveSettings();
}
<div class="fieldset">
<h4>' . __('Services') . '</h4>
<p class="info">' . __('List of services you can use to shorten links with pkugin kUtRL.') . '</p>
';
dcCore::app()->blog->triggerBlog();
foreach (kUtRL::getServices() as $service_id => $service) {
$o = new $service();
Notices::addSuccessNotice(
__('Configuration successfully updated.')
);
echo '<hr/><div id="setting-' . $service_id . '"><h5>' . $o->name . '</h5>';
if (!empty($_REQUEST['chk'])) {
$img_chk = $img_red . ' ' . sprintf(__('Failed to test %s API.'), $o->name);
try {
if ($o->testService()) {
$img_chk = $img_green . ' ' . sprintf(__('%s API is well configured and runing.'), $o->name);
dcCore::app()->admin->url->redirect(
'admin.plugins',
['module' => My::id(), 'conf' => 1, 'chk' => 1, 'redir' => dcCore::app()->admin->list->getRedir()]
);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
} catch (Exception $e) {
dcCore::app()->error->add(sprintf(__('Failed to test service %s: %s'), $o->name, $e->getMessage()));
}
echo sprintf('<p><em>%s</em></p>', $img_chk) . $o->error->toHTML();
}
if ($o->home != '') {
echo '<p><a title="' . __('homepage') . '" href="' . $o->home . '">' . sprintf(__('Learn more about %s.'), $o->name) . '</a></p>';
}
$o->settingsForm();
echo '</div>';
return true;
}
public static function render(): void
{
if (!self::status()) {
return;
}
# Default values
$img_green = '<img src="images/check-on.png" alt="ok" />';
$img_red = '<img src="images/check-off.png" alt="fail" />';
# Settings
$s = My::settings();
$s_active = (bool) $s->get('active');
$s_plugin_service = (string) $s->get('plugin_service');
$s_admin_service = (string) $s->get('admin_service');
$s_tpl_service = (string) $s->get('tpl_service');
$s_wiki_service = (string) $s->get('wiki_service');
$s_allow_external_url = (bool) $s->get('allow_external_url');
$s_tpl_passive = (bool) $s->get('tpl_passive');
$s_tpl_active = (bool) $s->get('tpl_active');
$s_admin_entry_default = (bool) $s->get('admin_entry_default');
$chk_admin_service = '';
$chk_plugin_service = '';
$chk_tpl_service = '';
$chk_wiki_service = '';
if (!empty($_REQUEST['chk'])) {
if (null !== ($o = Utils::quickPlace($s_admin_service))) {
$chk_admin_service = ($o->testService() ? $img_green : $img_red) . '&nbsp;';
}
if (null !== ($o = Utils::quickPlace($s_plugin_service))) {
$chk_plugin_service = ($o->testService() ? $img_green : $img_red) . '&nbsp;';
}
if (null !== ($o = Utils::quickPlace($s_tpl_service))) {
$chk_tpl_service = ($o->testService() ? $img_green : $img_red) . '&nbsp;';
}
if (null !== ($o = Utils::quickPlace($s_wiki_service))) {
$chk_wiki_service = ($o->testService() ? $img_green : $img_red) . '&nbsp;';
}
}
$i_config = [];
foreach (Utils::getServices() as $service_id => $service) {
$o = new $service();
$s_items = [];
if (!empty($_REQUEST['chk'])) {
$img_chk = $img_red . ' ' . sprintf(__('Failed to test %s API.'), $o->name);
try {
if ($o->testService()) {
$img_chk = $img_green . ' ' . sprintf(__('%s API is well configured and runing.'), $o->name);
}
} catch (Exception $e) {
dcCore::app()->error->add(sprintf(__('Failed to test service %s: %s'), $o->name, $e->getMessage()));
}
$s_items[] = (new Text(null, sprintf('<p><em>%s</em></p>', $img_chk) . $o->error->toHTML()));
}
if ($o->home != '') {
$s_items[] = (new Para())
->items([
(new Link())
->href($o->home)
->title(__('homepage'))
->text(sprintf(__('Learn more about %s.'), $o->name)),
]);
}
$i_config[] = (new Text('hr'));
$i_config[] = (new Div('settings-' . $service_id))
->items([
(new Text('h5', $o->name)),
... $s_items,
$o->settingsForm(),
]);
}
echo (new Div())
->class('fieldset')
->items([
(new text('h4', __('Settings'))),
(new Div('setting-plugin'))
->items([
(new Text('h5', __('Activation'))),
(new Para())
->items([
(new Checkbox('s_active', $s_active))
->value(1),
(new Label(__('Enable plugin'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('s_active'),
]),
]),
(new Text('hr')),
(new Div('setting-option'))
->items([
(new Text('h5', __('Behaviors'))),
(new Para())
->items([
(new Checkbox('s_allow_external_url', $s_allow_external_url))
->value(1),
(new Label(__('Allow short link for external URL'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('s_allow_external_url'),
]),
(new Note())
->class('form-note')
->text(__('Not only link started with this blog URL could be shortened.')),
(new Para())
->items([
(new Checkbox('s_tpl_passive', $s_tpl_passive))
->value(1),
(new Label(__('Passive mode'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('s_tpl_passive'),
]),
(new Note())
->class('form-note')
->text(__('If this extension is disabled and the passive mode is enabled, "kutrl" tags (like EntryKurl) will display long urls instead of nothing on templates.')),
(new Para())
->items([
(new Checkbox('s_tpl_active', $s_tpl_active))
->value(1),
(new Label(__('Active mode'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('s_tpl_active'),
]),
(new Note())
->class('form-note')
->text(__('If the active mode is enabled, all know default template tags (like EntryURL) will display short urls instead of long ones on templates.')),
(new Note())
->class('form-note')
->text(__('You can disable URL shortening for a specific template tag by adding attribute disable_kutrl="1" to it . ')),
(new Note())
->class('warning')
->text(__('We strongly discourage using active mode as it crashes public post form and complex url if theme is not customize for kUtRL.')),
(new Para())
->items([
(new Checkbox('s_admin_entry_default', $s_admin_entry_default))
->value(1),
(new Label(__('Create short link for new entries'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('s_admin_entry_default'),
]),
(new Note())
->class('form-note')
->text(__('This can be changed on page of creation/edition of an entry.')),
]),
(new Text('hr')),
(new Div('setting-service'))
->items([
(new Text('h5', __('Default services'))),
(new Para())
->items([
(new Label($chk_admin_service . __('Administration:'), Label::OUTSIDE_LABEL_BEFORE))
->for('s_admin_service'),
(new Select('s_admin_service'))
->items(Combo::servicesCombo())
->default($s_admin_service),
]),
(new Note())
->class('form-note')
->text(__('Service to use in this admin page and on edit page of an entry.')),
(new Para())
->items([
(new Label($chk_plugin_service . __('Extensions:'), Label::OUTSIDE_LABEL_BEFORE))
->for('s_plugin_service'),
(new Select('s_plugin_service'))
->items(Combo::servicesCombo())
->default($s_plugin_service),
]),
(new Note())
->class('form-note')
->text(__('Service to use on third part plugins.')),
(new Para())
->items([
(new Label($chk_tpl_service . __('Templates:'), Label::OUTSIDE_LABEL_BEFORE))
->for('s_tpl_service'),
(new Select('s_tpl_service'))
->items(Combo::servicesCombo())
->default($s_tpl_service),
]),
(new Note())
->class('form-note')
->text(__('Shorten links automatically when using template value like "EntryKutrl".')),
(new Para())
->items([
(new Label($chk_wiki_service . __('Contents:'), Label::OUTSIDE_LABEL_BEFORE))
->for('s_wiki_service'),
(new Select('s_wiki_service'))
->items(Combo::servicesCombo())
->default($s_wiki_service),
]),
(new Note())
->class('form-note')
->text(__('Shorten links automatically found in contents using wiki synthax.')),
]),
])
->render() .
(new Div())
->class('fieldset')
->items([
(new text('h4', __('Settings'))),
(new Note())
->class('info')
->text(__('List of services you can use to shorten links with pkugin kUtRL.')),
... $i_config,
])
->render();
}
}
echo'</div>';

View File

@ -10,567 +10,66 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
require_once __DIR__ . '/_widgets.php';
namespace Dotclear\Plugin\kUtRL;
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/default-templates');
use dcCore;
dcCore::app()->addBehavior('publicBeforeDocumentV2', ['pubKutrl', 'publicBeforeDocumentV2']);
dcCore::app()->addBehavior('publicHeadContent', ['pubKutrl', 'publicHeadContent']);
dcCore::app()->addBehavior('publicBeforeContentFilterV2', ['pubKutrl', 'publicBeforeContentFilterV2']);
dcCore::app()->addBehavior('templateBeforeValueV2', ['pubKutrl', 'templateBeforeValueV2']);
dcCore::app()->addBehavior('templateAfterValueV2', ['pubKutrl', 'templateAfterValueV2']);
use Dotclear\Core\Process;
dcCore::app()->tpl->addBlock('kutrlPageIf', ['tplKutrl', 'pageIf']);
dcCore::app()->tpl->addBlock('kutrlMsgIf', ['tplKutrl', 'pageMsgIf']);
dcCore::app()->tpl->addValue('kutrlPageURL', ['tplKutrl', 'pageURL']);
dcCore::app()->tpl->addValue('kutrlMsg', ['tplKutrl', 'pageMsg']);
dcCore::app()->tpl->addValue('kutrlHumanField', ['tplKutrl', 'humanField']);
dcCore::app()->tpl->addValue('kutrlHumanFieldProtect', ['tplKutrl', 'humanFieldProtect']);
dcCore::app()->tpl->addBlock('AttachmentKutrlIf', ['tplKutrl', 'AttachmentKutrlIf']);
dcCore::app()->tpl->addValue('AttachmentKutrl', ['tplKutrl', 'AttachmentKutrl']);
dcCore::app()->tpl->addBlock('MediaKutrlIf', ['tplKutrl', 'MediaKutrlIf']);
dcCore::app()->tpl->addValue('MediaKutrl', ['tplKutrl', 'MediaKutrl']);
dcCore::app()->tpl->addBlock('EntryAuthorKutrlIf', ['tplKutrl', 'EntryAuthorKutrlIf']);
dcCore::app()->tpl->addValue('EntryAuthorKutrl', ['tplKutrl', 'EntryAuthorKutrl']);
dcCore::app()->tpl->addBlock('EntryKutrlIf', ['tplKutrl', 'EntryKutrlIf']);
dcCore::app()->tpl->addValue('EntryKutrl', ['tplKutrl', 'EntryKutrl']);
dcCore::app()->tpl->addBlock('CommentAuthorKutrlIf', ['tplKutrl', 'CommentAuthorKutrlIf']);
dcCore::app()->tpl->addValue('CommentAuthorKutrl', ['tplKutrl', 'CommentAuthorKutrl']);
dcCore::app()->tpl->addBlock('CommentPostKutrlIf', ['tplKutrl', 'CommentPostKutrlIf']);
dcCore::app()->tpl->addValue('CommentPostKutrl', ['tplKutrl', 'CommentPostKutrl']);
class urlKutrl extends dcUrlHandlers
/**
* Frontend prepend.
*/
class Frontend extends Process
{
# Redirect !!! local !!! service only
public static function redirectUrl($args)
public static function init(): bool
{
# Not active, go to default 404
if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) {
self::p404();
return null;
}
# Not a valid url, go to kutrl 404
if (!preg_match('#^(|(/(.*?)))$#', $args, $m)) {
self::kutrl404();
return null;
}
$args = $m[3] ?? '';
dcCore::app()->ctx->kutrl_msg = '';
dcCore::app()->ctx->kutrl_hmf = hmfKutrl::create();
dcCore::app()->ctx->kutrl_hmfp = hmfKutrl::protect(dcCore::app()->ctx->kutrl_hmf);
$kut = new localKutrlService();
# Nothing on url
if ($m[1] == '/') {
dcCore::app()->ctx->kutrl_msg = 'No link given.';
}
# find suffix on redirect url
$suffix = '';
if (preg_match('@^([^?/#]+)(.*?)$@', $args, $more)) {
$args = $more[1];
$suffix = $more[2];
}
# No arg, go to kurtl page
if ($args == '') {
self::pageKutrl($kut);
return null;
}
# Not find, go to kutrl 404
if (false === ($url = $kut->getUrl($args))) {
//dcCore::app()->ctx->kutrl_msg = 'Failed to find short link.';
//self::pageKutrl($kut);
self::kutrl404();
return null;
}
# Removed (empty url), go to kutrl 404
if (!$url) {
self::kutrl404();
return null;
}
dcCore::app()->blog->triggerBlog();
http::redirect($url . $suffix);
return null;
return self::status(My::checkContext(My::FRONTEND));
}
private static function pageKutrl($kut)
public static function process(): bool
{
$s = dcCore::app()->blog->settings->get(basename(__DIR__));
# Not active, go to default 404
if (!$s->get('active')) {
self::p404();
return null;
}
# Public page not active, go to kutrl 404
if (!$s->get('srv_local_public')) {
self::kutrl404();
return null;
}
# Validation form
$url = !empty($_POST['longurl']) ? trim(dcCore::app()->con->escape($_POST['longurl'])) : '';
if (!empty($url)) {
$hmf = !empty($_POST['hmf']) ? $_POST['hmf'] : '!';
$hmfu = !empty($_POST['hmfp']) ? hmfKutrl::unprotect($_POST['hmfp']) : '?';
$err = false;
if (!$err) {
if ($hmf != $hmfu) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Failed to verify protected field.');
}
}
if (!$err) {
if (!$kut->testService()) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Service is not well configured.');
}
}
if (!$err) {
if (!$kut->isValidUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This string is not a valid URL.');
}
}
if (!$err) {
if (!$kut->isLongerUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This link is too short.');
}
}
if (!$err) {
if (!$kut->isProtocolUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This type of link is not allowed.');
}
}
if (!$err) {
if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Short links are limited to this blog URL.');
}
}
if (!$err) {
if ($kut->isServiceUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This link is already a short link.');
}
}
if (!$err) {
if (false !== ($rs = $kut->isKnowUrl($url))) {
$err = true;
$url = $rs->url;
$new_url = $kut->url_base . $rs->hash;
dcCore::app()->ctx->kutrl_msg = sprintf(
__('Short link for %s is %s'),
html::escapeHTML($url),
'<a href="' . $new_url . '">' . $new_url . '</a>'
);
}
}
if (!$err) {
if (false === ($rs = $kut->hash($url))) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Failed to create short link.');
} else {
$url = $rs->url;
$new_url = $kut->url_base . $rs->hash;
dcCore::app()->ctx->kutrl_msg = sprintf(
__('Short link for %s is %s'),
html::escapeHTML($url),
'<a href="' . $new_url . '">' . $new_url . '</a>'
);
dcCore::app()->blog->triggerBlog();
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('publicAfterKutrlCreate', $rs, __('New public short URL'));
}
}
}
if (!self::status()) {
return false;
}
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/default-templates');
self::serveDocument('kutrl.html');
dcCore::app()->tpl->setPath(
dcCore::app()->tpl->getPath(),
My::path() . DIRECTORY_SEPARATOR . 'default-templates'
);
dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initShorten']);
dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initRank']);
return null;
}
dcCore::app()->addBehaviors([
'publicBeforeDocumentV2' => [FrontendBehaviors::class, 'publicBeforeDocumentV2'],
'publicHeadContent' => [FrontendBehaviors::class, 'publicHeadContent'],
'publicBeforeContentFilterV2' => [FrontendBehaviors::class, 'publicBeforeContentFilterV2'],
'templateBeforeValueV2' => [FrontendBehaviors::class, 'templateBeforeValueV2'],
'templateAfterValueV2' => [FrontendBehaviors::class, 'templateAfterValueV2'],
]);
protected static function kutrl404()
{
if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('srv_local_404_active')) {
self::p404();
dcCore::app()->tpl->addBlock('kutrlPageIf', [FrontendTemplate::class, 'pageIf']);
dcCore::app()->tpl->addBlock('kutrlMsgIf', [FrontendTemplate::class, 'pageMsgIf']);
return null;
}
dcCore::app()->tpl->addValue('kutrlPageURL', [FrontendTemplate::class, 'pageURL']);
dcCore::app()->tpl->addValue('kutrlMsg', [FrontendTemplate::class, 'pageMsg']);
dcCore::app()->tpl->addValue('kutrlHumanField', [FrontendTemplate::class, 'humanField']);
dcCore::app()->tpl->addValue('kutrlHumanFieldProtect', [FrontendTemplate::class, 'humanFieldProtect']);
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/default-templates');
dcCore::app()->tpl->addBlock('AttachmentKutrlIf', [FrontendTemplate::class, 'AttachmentKutrlIf']);
dcCore::app()->tpl->addValue('AttachmentKutrl', [FrontendTemplate::class, 'AttachmentKutrl']);
dcCore::app()->tpl->addBlock('MediaKutrlIf', [FrontendTemplate::class, 'MediaKutrlIf']);
dcCore::app()->tpl->addValue('MediaKutrl', [FrontendTemplate::class, 'MediaKutrl']);
dcCore::app()->tpl->addBlock('EntryAuthorKutrlIf', [FrontendTemplate::class, 'EntryAuthorKutrlIf']);
dcCore::app()->tpl->addValue('EntryAuthorKutrl', [FrontendTemplate::class, 'EntryAuthorKutrl']);
dcCore::app()->tpl->addBlock('EntryKutrlIf', [FrontendTemplate::class, 'EntryKutrlIf']);
dcCore::app()->tpl->addValue('EntryKutrl', [FrontendTemplate::class, 'EntryKutrl']);
dcCore::app()->tpl->addBlock('CommentAuthorKutrlIf', [FrontendTemplate::class, 'CommentAuthorKutrlIf']);
dcCore::app()->tpl->addValue('CommentAuthorKutrl', [FrontendTemplate::class, 'CommentAuthorKutrl']);
dcCore::app()->tpl->addBlock('CommentPostKutrlIf', [FrontendTemplate::class, 'CommentPostKutrlIf']);
dcCore::app()->tpl->addValue('CommentPostKutrl', [FrontendTemplate::class, 'CommentPostKutrl']);
header('Content-Type: text/html; charset=UTF-8');
http::head(404, 'Not Found');
dcCore::app()->url->type = '404';
dcCore::app()->ctx->current_tpl = 'kutrl404.html';
dcCore::app()->ctx->content_type = 'text/html';
echo dcCore::app()->tpl->getData(dcCore::app()->ctx->current_tpl);
# --BEHAVIOR-- publicAfterDocument
dcCore::app()->callBehavior('publicAfterDocumentV2');
exit;
}
}
class pubKutrl
{
# List of template tag which content URL that can be shortenn
public static $know_tags = [
'AttachmentURL',
'CategoryURL',
'MediaURL',
'EntryAuthorURL',
'EntryURL',
'EntryCategoryURL',
'CommentAuthorURL',
'CommentPostURL',
];
# Disable URL shoretning on filtered tag
public static function templateBeforeValueV2($tag, $attr)
{
if (!empty($attr['disable_kutrl']) && in_array($tag, pubKutrl::$know_tags)) {
return '<?php dcCore::app()->ctx->__set("disable_kutrl", true); ?>';
}
return null;
}
# Re unable it after tag
public static function templateAfterValueV2($tag, $attr)
{
if (!empty($attr['disable_kutrl']) && in_array($tag, pubKutrl::$know_tags)) {
return '<?php dcCore::app()->ctx->__set("disable_kutrl", false); ?>';
}
return null;
}
# Replace long urls on the fly (on filter) for default tags
public static function publicBeforeContentFilterV2($tag, $args)
{
# Unknow tag
if (!in_array($tag, pubKutrl::$know_tags)) {
return null;
}
# URL shortening is disabled by tag attribute
if (true !== dcCore::app()->ctx->__get('disable_kutrl')) {
# kUtRL is not activated
if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')
|| !dcCore::app()->blog->settings->get(basename(__DIR__))->get('tpl_active')
) {
return null;
}
# Oups
if (!dcCore::app()->ctx->exists('kutrl')) {
return null;
}
# Existing
if (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->isKnowUrl($args[0]))) {
$args[0] = dcCore::app()->ctx->kutrl->url_base . $kutrl_rs->hash;
# New
} elseif (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->hash($args[0]))) {
$args[0] = dcCore::app()->ctx->kutrl->url_base . $kutrl_rs->hash;
# ex: Send new url to messengers
if (!empty($kutrl_rs)) {
dcCore::app()->callBehavior('publicAfterKutrlCreate', $kutrl_rs, __('New public short URL'));
}
}
}
}
public static function publicBeforeDocumentV2()
{
$s = dcCore::app()->blog->settings->get(basename(__DIR__));
# Passive : all kutrl tag return long url
dcCore::app()->ctx->kutrl_passive = (bool) $s->get('tpl_passive');
if (!$s->get('active') || !$s->get('tpl_service')) {
return null;
}
if (null === ($kut = kUtRL::quickPlace('tpl'))) {
return null;
}
dcCore::app()->ctx->kutrl = $kut;
}
public static function publicHeadContent($_)
{
$css = dcCore::app()->blog->settings->get(basename(__DIR__))->get('srv_local_css');
if ($css) {
echo
"\n<!-- CSS for kUtRL --> \n" .
"<style type=\"text/css\"> \n" .
html::escapeHTML($css) . "\n" .
"</style>\n";
}
}
}
class tplKutrl
{
public static function pageURL($attr)
{
$f = dcCore::app()->tpl->getFilters($attr);
return '<?php echo ' . sprintf($f, 'dcCore::app()->blog->url.dcCore::app()->url->getBase("kutrl")') . '; ?>';
}
public static function pageIf($attr, $content)
{
$operator = isset($attr['operator']) ? self::getOperator($attr['operator']) : '&&';
if (isset($attr['is_active'])) {
$sign = (bool) $attr['is_active'] ? '' : '!';
$if[] = $sign . 'dcCore::app()->blog->settings->get("' . basename(__DIR__) . '")->get("srv_local_public")';
}
if (empty($if)) {
return $content;
}
return
'<?php if(' . implode(' ' . $operator . ' ', $if) . ") : ?>\n" .
$content .
"<?php endif; unset(\$s);?>\n";
}
public static function pageMsgIf($attr, $content)
{
$operator = isset($attr['operator']) ? self::getOperator($attr['operator']) : '&&';
if (isset($attr['has_message'])) {
$sign = (bool) $attr['has_message'] ? '!' : '=';
$if[] = '"" ' . $sign . '= dcCore::app()->ctx->kutrl_msg';
}
if (empty($if)) {
return $content;
}
return
'<?php if(' . implode(' ' . $operator . ' ', $if) . ") : ?>\n" .
$content .
"<?php endif; ?>\n";
}
public static function pageMsg($attr)
{
return '<?php echo dcCore::app()->ctx->kutrl_msg; ?>';
}
public static function humanField($attr)
{
return "<?php echo sprintf(__('Confirm by writing \"%s\" in next field:'),dcCore::app()->ctx->kutrl_hmf); ?>";
}
public static function humanFieldProtect($attr)
{
return
'<input type="hidden" name="hmfp" id="hmfp" value="<?php echo dcCore::app()->ctx->kutrl_hmfp; ?>" />' .
'<?php echo dcCore::app()->formNonce(); ?>';
}
public static function AttachmentKutrlIf($attr, $content)
{
return self::genericKutrlIf('$attach_f->file_url', $attr, $content);
}
public static function AttachmentKutrl($attr)
{
return self::genericKutrl('$attach_f->file_url', $attr);
}
public static function MediaKutrlIf($attr, $content)
{
return self::genericKutrlIf('dcCore::app()->ctx->file_url', $attr, $content);
}
public static function MediaKutrl($attr)
{
return self::genericKutrl('dcCore::app()->ctx->file_url', $attr);
}
public static function EntryAuthorKutrlIf($attr, $content)
{
return self::genericKutrlIf('dcCore::app()->ctx->posts->user_url', $attr, $content);
}
public static function EntryAuthorKutrl($attr)
{
return self::genericKutrl('dcCore::app()->ctx->posts->user_url', $attr);
}
public static function EntryKutrlIf($attr, $content)
{
return self::genericKutrlIf('dcCore::app()->ctx->posts->getURL()', $attr, $content);
}
public static function EntryKutrl($attr)
{
return self::genericKutrl('dcCore::app()->ctx->posts->getURL()', $attr);
}
public static function CommentAuthorKutrlIf($attr, $content)
{
return self::genericKutrlIf('dcCore::app()->ctx->comments->getAuthorURL()', $attr, $content);
}
public static function CommentAuthorKutrl($attr)
{
return self::genericKutrl('dcCore::app()->ctx->comments->getAuthorURL()', $attr);
}
public static function CommentPostKutrlIf($attr, $content)
{
return self::genericKutrlIf('dcCore::app()->ctx->comments->getPostURL()', $attr, $content);
}
public static function CommentPostKutrl($attr)
{
return self::genericKutrl('dcCore::app()->ctx->comments->getPostURL()', $attr);
}
protected static function genericKutrlIf($str, $attr, $content)
{
$operator = isset($attr['operator']) ? self::getOperator($attr['operator']) : '&&';
if (isset($attr['is_active'])) {
$sign = (bool) $attr['is_active'] ? '' : '!';
$if[] = $sign . 'dcCore::app()->ctx->exists("kutrl")';
}
if (isset($attr['passive_mode'])) {
$sign = (bool) $attr['passive_mode'] ? '' : '!';
$if[] = $sign . 'dcCore::app()->ctx->kutrl_passive';
}
if (isset($attr['has_kutrl'])) {
$sign = (bool) $attr['has_kutrl'] ? '!' : '=';
$if[] = '(dcCore::app()->ctx->exists("kutrl") && false ' . $sign . '== dcCore::app()->ctx->kutrl->select(' . $str . ',null,null,"kutrl"))';
}
if (empty($if)) {
return $content;
}
return
'<?php if(' . implode(' ' . $operator . ' ', $if) . ") : ?>\n" .
$content .
"<?php endif; ?>\n";
}
protected static function genericKutrl($str, $attr)
{
$f = dcCore::app()->tpl->getFilters($attr);
return
"<?php \n" .
# Preview
"if (dcCore::app()->ctx->preview) { \n" .
' echo ' . sprintf($f, $str) . '; ' .
"} else { \n" .
# Disable
"if (!dcCore::app()->ctx->exists('kutrl')) { \n" .
# Passive mode
' if (dcCore::app()->ctx->kutrl_passive) { ' .
' echo ' . sprintf($f, $str) . '; ' .
" } \n" .
"} else { \n" .
# Existing
' if (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->isKnowUrl(' . $str . '))) { ' .
' echo ' . sprintf($f, 'dcCore::app()->ctx->kutrl->url_base.$kutrl_rs->hash') . '; ' .
" } \n" .
# New
' elseif (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->hash(' . $str . '))) { ' .
' echo ' . sprintf($f, 'dcCore::app()->ctx->kutrl->url_base.$kutrl_rs->hash') . '; ' .
# ex: Send new url to messengers
' if (!empty($kutrl_rs)) { ' .
" dcCore::app()->callBehavior('publicAfterKutrlCreate',\$kutrl_rs,__('New public short URL')); " .
" } \n" .
" } \n" .
" unset(\$kutrl_rs); \n" .
"} \n" .
"} \n" .
"?>\n";
}
protected static function getOperator($op)
{
switch (strtolower($op)) {
case 'or':
case '||':
return '||';
case 'and':
case '&&':
default:
return '&&';
}
}
}
class hmfKutrl
{
public static $chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
public static function create($len = 6)
{
$res = '';
$chars = self::$chars;
for ($i = 0; $i < $len; $i++) {
$res .= $chars[rand(0, strlen($chars) - 1)];
}
return $res;
}
public static function protect($str)
{
$res = '';
$chars = self::$chars;
for ($i = 0; $i < strlen($str); $i++) {
$res .= $chars[rand(0, strlen($chars) - 1)] . $str[$i];
}
return $res;
}
public static function unprotect($str)
{
$res = '';
for ($i = 0; $i < strlen($str); $i++) {
$i++;
$res .= $str[$i];
}
return $res;
return true;
}
}

View File

@ -0,0 +1,102 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use ArrayObject;
use dcCore;
use Dotclear\Helper\Html\Html;
class FrontendBehaviors
{
# Disable URL shoretning on filtered tag
public static function templateBeforeValueV2(string $tag, ArrayObject $attr): ?string
{
if (!empty($attr['disable_kutrl']) && in_array($tag, My::USED_TAGS)) {
return '<?php dcCore::app()->ctx->__set("disable_kutrl", true); ?>';
}
return null;
}
# Re unable it after tag
public static function templateAfterValueV2(string $tag, ArrayObject $attr): ?string
{
if (!empty($attr['disable_kutrl']) && in_array($tag, My::USED_TAGS)) {
return '<?php dcCore::app()->ctx->__set("disable_kutrl", false); ?>';
}
return null;
}
# Replace long urls on the fly (on filter) for default tags
public static function publicBeforeContentFilterV2(string $tag, array $args): ?string
{
# Unknow tag
if (!in_array($tag, My::USED_TAGS)) {
return null;
}
# URL shortening is disabled by tag attribute
if (true !== dcCore::app()->ctx->__get('disable_kutrl')) {
# plugin is not activated
if (!My::settings()->get('active')
|| !My::settings()->get('tpl_active')
|| !dcCore::app()->ctx->exists('kutrl')
) {
return null;
}
# Existing
if (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->isKnowUrl($args[0]))) {
$args[0] = dcCore::app()->ctx->kutrl->url_base . $kutrl_rs->hash;
# New
} elseif (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->hash($args[0]))) {
$args[0] = dcCore::app()->ctx->kutrl->url_base . $kutrl_rs->hash;
# ex: Send new url to messengers
if (!empty($kutrl_rs)) {
dcCore::app()->callBehavior('publicAfterKutrlCreate', $kutrl_rs, __('New public short URL'));
}
}
}
}
public static function publicBeforeDocumentV2(): void
{
$s = My::settings();
# Passive : all kutrl tag return long url
dcCore::app()->ctx->kutrl_passive = (bool) $s->get('tpl_passive');
if (!$s->get('active')
|| !$s->get('tpl_service')
|| null === ($kut = Utils::quickPlace('tpl'))
) {
return;
}
dcCore::app()->ctx->kutrl = $kut;
}
public static function publicHeadContent($_): void
{
$css = My::settings()->get('srv_local_css');
if (!empty($css)) {
echo
"\n<!-- CSS for " . My::id() . " --> \n" .
"<style type=\"text/css\"> \n" .
Html::escapeHTML($css) . "\n" .
"</style>\n";
}
}
}

View File

@ -0,0 +1,205 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use ArrayObject;
use dcCore;
use dcTemplate;
class FrontendTemplate
{
public static function pageURL(ArrayObject$attr): string
{
$f = dcCore::app()->tpl->getFilters($attr);
return '<?php echo ' . sprintf($f, 'dcCore::app()->blog->url.dcCore::app()->url->getBase("kutrl")') . '; ?>';
}
public static function pageIf(ArrayObject $attr, string $content): string
{
$operator = isset($attr['operator']) ? dcTemplate::getOperator($attr['operator']) : '&&';
if (isset($attr['is_active'])) {
$sign = (bool) $attr['is_active'] ? '' : '!';
$if[] = $sign . 'dcCore::app()->blog->settings->get("' . My::id() . '")->get("srv_local_public")';
}
if (empty($if)) {
return $content;
}
return
'<?php if(' . implode(' ' . $operator . ' ', $if) . ") : ?>\n" .
$content .
"<?php endif; unset(\$s);?>\n";
}
public static function pageMsgIf(ArrayObject$attr, string $content): string
{
$operator = isset($attr['operator']) ? dcTemplate::getOperator($attr['operator']) : '&&';
if (isset($attr['has_message'])) {
$sign = (bool) $attr['has_message'] ? '!' : '=';
$if[] = '"" ' . $sign . '= dcCore::app()->ctx->kutrl_msg';
}
if (empty($if)) {
return $content;
}
return
'<?php if(' . implode(' ' . $operator . ' ', $if) . ") : ?>\n" .
$content .
"<?php endif; ?>\n";
}
public static function pageMsg(ArrayObject$attr): string
{
return '<?php echo dcCore::app()->ctx->kutrl_msg; ?>';
}
public static function humanField(ArrayObject $attr): string
{
return "<?php echo sprintf(__('Confirm by writing \"%s\" in next field:'),dcCore::app()->ctx->kutrl_hmf); ?>";
}
public static function humanFieldProtect(ArrayObject $attr): string
{
return
'<input type="hidden" name="hmfp" id="hmfp" value="<?php echo dcCore::app()->ctx->kutrl_hmfp; ?>" />' .
'<?php echo dcCore::app()->formNonce(); ?>';
}
public static function AttachmentKutrlIf(ArrayObject$attr, string $content): string
{
return self::genericKutrlIf('$attach_f->file_url', $attr, $content);
}
public static function AttachmentKutrl(ArrayObject $attr): string
{
return self::genericKutrl('$attach_f->file_url', $attr);
}
public static function MediaKutrlIf(ArrayObject$attr, string $content): string
{
return self::genericKutrlIf('dcCore::app()->ctx->file_url', $attr, $content);
}
public static function MediaKutrl(ArrayObject $attr): string
{
return self::genericKutrl('dcCore::app()->ctx->file_url', $attr);
}
public static function EntryAuthorKutrlIf(ArrayObject$attr, string $content): string
{
return self::genericKutrlIf('dcCore::app()->ctx->posts->user_url', $attr, $content);
}
public static function EntryAuthorKutrl(ArrayObject $attr): string
{
return self::genericKutrl('dcCore::app()->ctx->posts->user_url', $attr);
}
public static function EntryKutrlIf(ArrayObject $attr, string $content): string
{
return self::genericKutrlIf('dcCore::app()->ctx->posts->getURL()', $attr, $content);
}
public static function EntryKutrl(ArrayObject $attr): string
{
return self::genericKutrl('dcCore::app()->ctx->posts->getURL()', $attr);
}
public static function CommentAuthorKutrlIf(ArrayObject $attr, string $content): string
{
return self::genericKutrlIf('dcCore::app()->ctx->comments->getAuthorURL()', $attr, $content);
}
public static function CommentAuthorKutrl(ArrayObject $attr): string
{
return self::genericKutrl('dcCore::app()->ctx->comments->getAuthorURL()', $attr);
}
public static function CommentPostKutrlIf(ArrayObject $attr, string $content): string
{
return self::genericKutrlIf('dcCore::app()->ctx->comments->getPostURL()', $attr, $content);
}
public static function CommentPostKutrl(ArrayObject $attr): string
{
return self::genericKutrl('dcCore::app()->ctx->comments->getPostURL()', $attr);
}
protected static function genericKutrlIf(string $str, ArrayObject $attr, string $content): string
{
$operator = isset($attr['operator']) ? dcTemplate::getOperator($attr['operator']) : '&&';
if (isset($attr['is_active'])) {
$sign = (bool) $attr['is_active'] ? '' : '!';
$if[] = $sign . 'dcCore::app()->ctx->exists("kutrl")';
}
if (isset($attr['passive_mode'])) {
$sign = (bool) $attr['passive_mode'] ? '' : '!';
$if[] = $sign . 'dcCore::app()->ctx->kutrl_passive';
}
if (isset($attr['has_kutrl'])) {
$sign = (bool) $attr['has_kutrl'] ? '!' : '=';
$if[] = '(dcCore::app()->ctx->exists("kutrl") && false ' . $sign . '== dcCore::app()->ctx->kutrl->select(' . $str . ',null,null,"kutrl"))';
}
if (empty($if)) {
return $content;
}
return
'<?php if(' . implode(' ' . $operator . ' ', $if) . ") : ?>\n" .
$content .
"<?php endif; ?>\n";
}
protected static function genericKutrl(string $str, ArrayObject $attr): string
{
$f = dcCore::app()->tpl->getFilters($attr);
return
"<?php \n" .
# Preview
"if (dcCore::app()->ctx->preview) { \n" .
' echo ' . sprintf($f, $str) . '; ' .
"} else { \n" .
# Disable
"if (!dcCore::app()->ctx->exists('kutrl')) { \n" .
# Passive mode
' if (dcCore::app()->ctx->kutrl_passive) { ' .
' echo ' . sprintf($f, $str) . '; ' .
" } \n" .
"} else { \n" .
# Existing
' if (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->isKnowUrl(' . $str . '))) { ' .
' echo ' . sprintf($f, 'dcCore::app()->ctx->kutrl->url_base.$kutrl_rs->hash') . '; ' .
" } \n" .
# New
' elseif (false !== ($kutrl_rs = dcCore::app()->ctx->kutrl->hash(' . $str . '))) { ' .
' echo ' . sprintf($f, 'dcCore::app()->ctx->kutrl->url_base.$kutrl_rs->hash') . '; ' .
# ex: Send new url to messengers
' if (!empty($kutrl_rs)) { ' .
" dcCore::app()->callBehavior('publicAfterKutrlCreate',\$kutrl_rs,__('New public short URL')); " .
" } \n" .
" } \n" .
" unset(\$kutrl_rs); \n" .
"} \n" .
"} \n" .
"?>\n";
}
}

211
src/FrontendUrl.php 100644
View File

@ -0,0 +1,211 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use dcCore;
use dcUrlHandlers;
use Dotclear\Helper\Html\Html;
use Dotclear\Helper\Network\Http;
class FrontendUrl extends dcUrlHandlers
{
# Redirect !!! local !!! service only
public static function redirectUrl(?string $args): void
{
# Not active, go to default 404
if (!My::settings()->get('active')) {
self::p404();
return;
}
# Not a valid url, go to kutrl 404
if (!preg_match('#^(|(/(.*?)))$#', $args, $m)) {
self::kutrl404();
return;
}
$args = $m[3] ?? '';
dcCore::app()->ctx->kutrl_msg = '';
dcCore::app()->ctx->kutrl_hmf = FrontendUtils::create();
dcCore::app()->ctx->kutrl_hmfp = FrontendUtils::protect(dcCore::app()->ctx->kutrl_hmf);
$kut = new Service\ServiceLocal();
# Nothing on url
if ($m[1] == '/') {
dcCore::app()->ctx->kutrl_msg = 'No link given.';
}
# find suffix on redirect url
$suffix = '';
if (preg_match('@^([^?/#]+)(.*?)$@', $args, $more)) {
$args = $more[1];
$suffix = $more[2];
}
# No arg, go to kurtl page
if ($args == '') {
self::pageKutrl($kut);
return;
}
# Not find, go to kutrl 404
if (false === ($url = $kut->getUrl($args))) {
//dcCore::app()->ctx->kutrl_msg = 'Failed to find short link.';
//self::pageKutrl($kut);
self::kutrl404();
return;
}
# Removed (empty url), go to kutrl 404
if (!$url) {
self::kutrl404();
return;
}
dcCore::app()->blog->triggerBlog();
Http::redirect($url . $suffix);
}
private static function pageKutrl(Service $kut): void
{
$s = My::settings();
# Not active, go to default 404
if (!$s->get('active')) {
self::p404();
return;
}
# Public page not active, go to kutrl 404
if (!$s->get('srv_local_public')) {
self::kutrl404();
return;
}
# Validation form
$url = !empty($_POST['longurl']) ? trim(dcCore::app()->con->escapeStr((string) $_POST['longurl'])) : '';
if (!empty($url)) {
$hmf = !empty($_POST['hmf']) ? $_POST['hmf'] : '!';
$hmfu = !empty($_POST['hmfp']) ? FrontendUtils::unprotect($_POST['hmfp']) : '?';
$err = false;
if (!$err) {
if ($hmf != $hmfu) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Failed to verify protected field.');
}
}
if (!$err) {
if (!$kut->testService()) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Service is not well configured.');
}
}
if (!$err) {
if (!$kut->isValidUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This string is not a valid URL.');
}
}
if (!$err) {
if (!$kut->isLongerUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This link is too short.');
}
}
if (!$err) {
if (!$kut->isProtocolUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This type of link is not allowed.');
}
}
if (!$err) {
if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Short links are limited to this blog URL.');
}
}
if (!$err) {
if ($kut->isServiceUrl($url)) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('This link is already a short link.');
}
}
if (!$err) {
if (false !== ($rs = $kut->isKnowUrl($url))) {
$err = true;
$url = $rs->url;
$new_url = $kut->url_base . $rs->hash;
dcCore::app()->ctx->kutrl_msg = sprintf(
__('Short link for %s is %s'),
Html::escapeHTML($url),
'<a href="' . $new_url . '">' . $new_url . '</a>'
);
}
}
if (!$err) {
if (false === ($rs = $kut->hash($url))) {
$err = true;
dcCore::app()->ctx->kutrl_msg = __('Failed to create short link.');
} else {
$url = $rs->url;
$new_url = $kut->url_base . $rs->hash;
dcCore::app()->ctx->kutrl_msg = sprintf(
__('Short link for %s is %s'),
Html::escapeHTML($url),
'<a href="' . $new_url . '">' . $new_url . '</a>'
);
dcCore::app()->blog->triggerBlog();
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('publicAfterKutrlCreate', $rs, __('New public short URL'));
}
}
}
}
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), My::path() . '/default-templates');
self::serveDocument('kutrl.html');
}
protected static function kutrl404(): void
{
if (!My::settigns()->get('srv_local_404_active')) {
self::p404();
return;
}
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), My::path() . '/default-templates');
header('Content-Type: text/html; charset=UTF-8');
Http::head(404, 'Not Found');
dcCore::app()->url->type = '404';
dcCore::app()->ctx->current_tpl = 'kutrl404.html';
dcCore::app()->ctx->content_type = 'text/html';
echo dcCore::app()->tpl->getData(dcCore::app()->ctx->current_tpl);
# --BEHAVIOR-- publicAfterDocumentV2
dcCore::app()->callBehavior('publicAfterDocumentV2');
exit;
}
}

View File

@ -0,0 +1,53 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
class FrontendUtils
{
public static $chars = 'abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789';
public static function create($len = 6)
{
$res = '';
$chars = self::$chars;
for ($i = 0; $i < $len; $i++) {
$res .= $chars[rand(0, strlen($chars) - 1)];
}
return $res;
}
public static function protect($str)
{
$res = '';
$chars = self::$chars;
for ($i = 0; $i < strlen($str); $i++) {
$res .= $chars[rand(0, strlen($chars) - 1)] . $str[$i];
}
return $res;
}
public static function unprotect($str)
{
$res = '';
for ($i = 0; $i < strlen($str); $i++) {
$i++;
$res .= $str[$i];
}
return $res;
}
}

View File

@ -0,0 +1,70 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use dcCore;
# Import/export behaviors for Import/export plugin
class ImportExportBehaviors
{
public static function exportSingleV2($exp, $blog_id)
{
$exp->export(
My::TABLE_NAME,
'SELECT kut_id, blog_id, kut_service, kut_type, ' .
'kut_hash, kut_url, kut_dt, kut_password, kut_counter ' .
'FROM ' . dcCore::app()->prefix . My::TABLE_NAME . ' ' .
"WHERE blog_id = '" . $blog_id . "' "
);
}
public static function exportFullV2($exp)
{
$exp->exportTable(My::TABLE_NAME);
}
public static function importInitV2($bk)
{
$bk->cur_kutrl = dcCore::app()->con->openCursor(dcCore::app()->prefix . My::TABLE_NAME);
$bk->kutrl = new Logs();
}
public static function importSingleV2($line, $bk)
{
if ($line->__name == My::TABLE_NAME) {
# Do nothing if str/type exists !
if (false === $bk->kutrl->select($line->kut_url, $line->kut_hash, $line->kut_type, $line->kut_service)) {
$bk->kutrl->insert($line->kut_url, $line->kut_hash, $line->kut_type, $line->kut_service);
}
}
}
public static function importFullV2($line, $bk)
{
if ($line->__name == My::TABLE_NAME) {
$bk->cur_kutrl->clean();
$bk->cur_kutrl->kut_id = (int) $line->kut_id;
$bk->cur_kutrl->blog_id = (string) $line->blog_id;
$bk->cur_kutrl->kut_service = (string) $line->kut_service;
$bk->cur_kutrl->kut_type = (string) $line->kut_type;
$bk->cur_kutrl->kut_hash = (string) $line->kut_hash;
$bk->cur_kutrl->kut_url = (string) $line->kut_url;
$bk->cur_kutrl->kut_dt = (string) $line->miniurl_dt;
$bk->cur_kutrl->kut_counter = (int) $line->kut_counter;
$bk->cur_kutrl->kut_password = (string) $line->kut_password;
$bk->cur_kutrl->insert();
}
}
}

View File

@ -10,94 +10,109 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return;
}
declare(strict_types=1);
try {
// Compare versions
if (!dcCore::app()->newVersion(
basename(__DIR__),
dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version')
)) {
return null;
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use dcNamespace;
use Dotclear\Core\Process;
use Dotclear\Database\Structure;
use Exception;
/**
* Module installation.
*/
class Install extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::INSTALL));
}
// Table
$t = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
$t->{initkUtRL::KURL_TABLE_NAME}
->kut_id('bigint', 0, false)
->blog_id('varchar', 32, false)
->kut_service('varchar', 32, false, "'kUtRL'")
->kut_type('varchar', 32, false)
->kut_hash('varchar', 32, false)
->kut_url('text', 0, false)
->kut_dt('timestamp', 0, false, 'now()')
->kut_password('varchar', 32, true)
->kut_counter('bigint', 0, false, 0)
->primary('pk_kutrl', 'kut_id')
->index('idx_kut_blog_id', 'btree', 'blog_id')
->index('idx_kut_hash', 'btree', 'kut_hash')
->index('idx_kut_service', 'btree', 'kut_service')
->index('idx_kut_type', 'btree', 'kut_type');
$ti = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
$changes = $ti->synchronize($t);
// upgrade version < 2022.12.22 : upgrade settings id and ns and array
$current = dcCore::app()->getVersion(basename(__DIR__));
if ($current && version_compare($current, '2022.12.22', '<')) {
$record = dcCore::app()->con->select(
'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' .
"WHERE setting_ns = 'kUtRL' "
);
while ($record->fetch()) {
if (preg_match('/^kutrl_(.*?)$/', $record->setting_id, $match)) {
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME);
// avoid the use of serialize function
if (in_array($record->setting_id, ['kutrl_srv_custom'])) {
$cur->setting_value = json_encode(@unserialize(base64_decode((string) $record->setting_value)));
}
$cur->setting_id = $match[1];
$cur->setting_ns = basename(__DIR__);
$cur->update(
"WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'kUtRL' " .
'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escape($record->blog_id) . "' "))
);
}
public static function process(): bool
{
if (!self::status()) {
return false;
}
} else {
// Settings
$s = dcCore::app()->blog->settings->addNamespace(basename(__DIR__));
$s->put('active', false, 'boolean', 'Enabled kutrl plugin', false, true);
$s->put('plugin_service', 'default', 'string', 'Service to use to shorten links on third part plugins', false, true);
$s->put('admin_service', 'local', 'string', 'Service to use to shorten links on admin', false, true);
$s->put('tpl_service', 'local', 'string', 'Service to use to shorten links on template', false, true);
$s->put('wiki_service', 'local', 'string', 'Service to use to shorten links on contents', false, true);
$s->put('allow_external_url', true, 'boolean', 'Limited short url to current blog\'s url', false, true);
$s->put('tpl_passive', true, 'boolean', 'Return long url on kutrl tags if kutrl is unactivate', false, true);
$s->put('tpl_active', false, 'boolean', 'Return short url on dotclear tags if kutrl is active', false, true);
$s->put('admin_entry_default', true, 'boolean', 'Create short link on new entry by default', false, true);
# Settings for "local" service
$local_css = ".shortenkutrlwidget input { border: 1px solid #CCCCCC; }\n" .
'.dc-kutrl input { border: 1px solid #CCCCCC; margin: 10px; }';
$s->put('srv_local_protocols', 'http:,https:,ftp:,ftps:,irc:', 'string', 'Allowed kutrl local service protocols', false, true);
$s->put('srv_local_public', false, 'boolean', 'Enabled local service public page', false, true);
$s->put('srv_local_css', $local_css, 'string', 'Special CSS for kutrl local service', false, true);
$s->put('srv_local_404_active', false, 'boolean', 'Use special 404 page on unknow urls', false, true);
# Settings for "bilbolinks" service
$s->put('srv_bilbolinks_base', 'http://tux-pla.net/', 'string', 'URL of bilbolinks service', false, true);
# Settings for "YOURLS" service
$s->put('srv_yourls_base', '', 'string', 'URL of YOURLS service', false, true);
$s->put('srv_yourls_username', '', 'string', 'User name to YOURLS service', false, true);
$s->put('srv_yourls_password', '', 'string', 'User password to YOURLS service', false, true);
try {
// Table
$t = new Structure(dcCore::app()->con, dcCore::app()->prefix);
$t->{My::TABLE_NAME}
->kut_id('bigint', 0, false)
->blog_id('varchar', 32, false)
->kut_service('varchar', 32, false, "'kUtRL'")
->kut_type('varchar', 32, false)
->kut_hash('varchar', 32, false)
->kut_url('text', 0, false)
->kut_dt('timestamp', 0, false, 'now()')
->kut_password('varchar', 32, true)
->kut_counter('bigint', 0, false, 0)
->primary('pk_kutrl', 'kut_id')
->index('idx_kut_blog_id', 'btree', 'blog_id')
->index('idx_kut_hash', 'btree', 'kut_hash')
->index('idx_kut_service', 'btree', 'kut_service')
->index('idx_kut_type', 'btree', 'kut_type');
(new Structure(dcCore::app()->con, dcCore::app()->prefix))->synchronize($t);
// upgrade version < 2022.12.22 : upgrade settings id and ns and array
$current = dcCore::app()->getVersion(My::id());
if ($current && version_compare($current, '2022.12.22', '<')) {
$record = dcCore::app()->con->select(
'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' .
"WHERE setting_ns = 'kUtRL' "
);
while ($record->fetch()) {
if (preg_match('/^kutrl_(.*?)$/', $record->setting_id, $match)) {
$cur = dcCore::app()->con->openCursor(dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME);
// avoid the use of serialize function
if (in_array($record->setting_id, ['kutrl_srv_custom'])) {
$cur->setting_value = json_encode(@unserialize(base64_decode((string) $record->setting_value)));
}
$cur->setting_id = $match[1];
$cur->setting_ns = basename(__DIR__);
$cur->update(
"WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'kUtRL' " .
'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escapeStr((string) $record->blog_id) . "' "))
);
}
}
} else {
// Settings
$s = My::settings();
$s->put('active', false, 'boolean', 'Enabled kutrl plugin', false, true);
$s->put('plugin_service', 'default', 'string', 'Service to use to shorten links on third part plugins', false, true);
$s->put('admin_service', 'local', 'string', 'Service to use to shorten links on admin', false, true);
$s->put('tpl_service', 'local', 'string', 'Service to use to shorten links on template', false, true);
$s->put('wiki_service', 'local', 'string', 'Service to use to shorten links on contents', false, true);
$s->put('allow_external_url', true, 'boolean', 'Limited short url to current blog\'s url', false, true);
$s->put('tpl_passive', true, 'boolean', 'Return long url on kutrl tags if kutrl is unactivate', false, true);
$s->put('tpl_active', false, 'boolean', 'Return short url on dotclear tags if kutrl is active', false, true);
$s->put('admin_entry_default', true, 'boolean', 'Create short link on new entry by default', false, true);
# Settings for "local" service
$local_css = ".shortenkutrlwidget input { border: 1px solid #CCCCCC; }\n" .
'.dc-kutrl input { border: 1px solid #CCCCCC; margin: 10px; }';
$s->put('srv_local_protocols', 'http:,https:,ftp:,ftps:,irc:', 'string', 'Allowed kutrl local service protocols', false, true);
$s->put('srv_local_public', false, 'boolean', 'Enabled local service public page', false, true);
$s->put('srv_local_css', $local_css, 'string', 'Special CSS for kutrl local service', false, true);
$s->put('srv_local_404_active', false, 'boolean', 'Use special 404 page on unknow urls', false, true);
# Settings for "bilbolinks" service
$s->put('srv_bilbolinks_base', 'http://tux-pla.net/', 'string', 'URL of bilbolinks service', false, true);
# Settings for "YOURLS" service
$s->put('srv_yourls_base', '', 'string', 'URL of YOURLS service', false, true);
$s->put('srv_yourls_username', '', 'string', 'User name to YOURLS service', false, true);
$s->put('srv_yourls_password', '', 'string', 'User password to YOURLS service', false, true);
}
return true;
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
return false;
}
}
return true;
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
return false;

View File

@ -10,121 +10,141 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
class kutrlLinkslist
declare(strict_types=1);
namespace Dotclear\Plugin\kUtRL;
use ArrayObject;
use dcCore;
use Dotclear\Core\Backend\Filter\Filters;
use Dotclear\Core\Backend\Listing\{
Listing,
Pager
};
use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
Link,
Note,
Para,
Text,
};
use Dotclear\Helper\Html\Html;
class LinksListing extends Listing
{
protected $rs;
protected $rs_count;
protected $html_prev;
protected $html_next;
public function __construct($rs, $rs_count)
{
$this->rs = &$rs;
$this->rs_count = $rs_count;
$this->html_prev = __('&#171; prev.');
$this->html_next = __('next &#187;');
}
public function userColumns($type, $cols)
{
$cols_user = @dcCore::app()->auth->user_prefs->interface->cols;
if (is_array($cols_user) || $cols_user instanceof ArrayObject) {
if (isset($cols_user[$type])) {
foreach ($cols_user[$type] as $cn => $cd) {
if (!$cd && isset($cols[$cn])) {
unset($cols[$cn]);
}
}
}
}
}
public function display($page, $nb_per_page, $enclose_block, $filter = false)
public function display(Filters $filter, string $enclose_block): void
{
if ($this->rs->isEmpty()) {
if ($filter) {
echo '<p><strong>' . __('No short link matches the filter') . '</strong></p>';
} else {
echo '<p><strong>' . __('No short link') . '</strong></p>';
}
} else {
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$links = [];
if (isset($_REQUEST['entries'])) {
foreach ($_REQUEST['entries'] as $v) {
$links[(int) $v] = true;
}
}
echo (new Note())
->class('info')
->text($filter->show() ? __('No short link matches the filter') : __('No short link'))
->render();
$cols = [
'kut_url' => '<th colspan="2" class="first">' . __('Link') . '</th>',
'kut_hash' => '<th scope="col">' . __('Hash') . '</th>',
'kut_dt' => '<th scope="col">' . __('Date') . '</th>',
'kut_service' => '<th scope="col">' . __('Service') . '</th>',
];
$cols = new ArrayObject($cols);
$this->userColumns('kUtRL', $cols);
$html_block = '<div class="table-outer">' .
'<table>' .
'<caption>' . (
$filter ?
sprintf(__('List of %s links matching the filter.'), $this->rs_count) :
sprintf(__('List of links (%s)'), $this->rs_count)
) . '</caption>' .
'<thead>' .
'<tr>' . implode(iterator_to_array($cols)) . '</tr>' .
'</thead>' .
'<tbody>%s</tbody>' .
'</table>' .
'%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
$blocks = explode('%s', $html_block);
echo $pager->getLinks() . $blocks[0];
while ($this->rs->fetch()) {
echo $this->linkLine(isset($links[$this->rs->kut_id]));
}
echo $blocks[1] . $blocks[2] . $pager->getLinks();
return;
}
$links = [];
if (isset($_REQUEST['entries'])) {
foreach ($_REQUEST['entries'] as $v) {
$links[(int) $v] = true;
}
}
$pager = new Pager((int) $filter->value('page'), $this->rs_count, (int) $filter->nb, 10);
$cols = new ArrayObject([
'kut_url' => (new Text('th', __('Link')))
->class('first')
->extra('colspan="2"'),
'kut_hash' => (new Text('th', __('Hash')))
->extra('scope="col"'),
'kut_dt' => (new Text('th', __('Date')))
->extra('scope="col"'),
'kut_service' => (new Text('th', __('Service')))
->extra('scope="col"'),
]);
$this->userColumns(My::id(), $cols);
$lines = [];
while ($this->rs->fetch()) {
$lines[] = $this->linkLine(isset($links[$this->rs->kut_id]));
}
echo
$pager->getLinks() .
sprintf(
$enclose_block,
(new Div())
->class('table-outer')
->items([
(new Para(null, 'table'))
->items([
(new Text(
'caption',
$filter->show() ?
sprintf(__('List of %s links matching the filter.'), $this->rs_count) :
sprintf(__('List of links. (%s)'), $this->rs_count)
)),
(new Para(null, 'tr'))
->items(iterator_to_array($cols)),
(new Para(null, 'tbody'))
->items($lines),
]),
])
->render()
) .
$pager->getLinks();
}
private function linkLine($checked)
private function linkLine(bool $checked): Para
{
$type = $this->rs->kut_type;
$hash = $this->rs->kut_hash;
if (null !== ($o = kUtRL::quickService($type))) {
$type = '<a href="' . $o->home . '" title="' . $o->name . '">' . $o->name . '</a>';
$hash = '<a href="' . $o->url_base . $hash . '" title="' . $o->url_base . $hash . '">' . $hash . '</a>';
if (null !== ($o = Utils::quickService($type))) {
$type = (new Link())
->href($o->home)
->title($o->name)
->text($o->name)
->render();
$hash = (new Link())
->href($o->url_base . $hash)
->title($o->url_base . $hash)
->text($hash)
->render();
}
$cols = [
'check' => '<td class="nowrap">' .
form::checkbox(['entries[]'], $this->rs->kut_id, ['checked' => $checked]) .
'</td>',
'kut_url' => '<td class="maximal" scope="row">' .
'<a href="' . $this->rs->kut_url . '">' . $this->rs->kut_url . '</a>' .
'</td>',
'kut_hash' => '<td class="nowrap">' .
$hash .
'</td>',
'kut_dt' => '<td class="nowrap count">' .
dt::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->kut_dt, dcCore::app()->auth->getInfo('user_tz')) .
'</td>',
'kut_service' => '<td class="nowrap">' .
$type .
'</td>',
];
$cols = new ArrayObject([
'check' => (new Para(null, 'td'))
->class('nowrap minimal')
->items([
(new Checkbox(['entries[]'], $checked))
->value($this->rs->kut_id),
]),
'kut_url' => (new Para(null, 'td'))
->class('maximal')
->items([
(new Link())
->href($o->home)
->title($this->rs->kut_url)
->text($this->rs->kut_url),
]),
'kut_hash' => (new Text('td', $hash))
->class('nowrap'),
'kut_dt' => (new Text('td', Html::escapeHTML(Date::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->kut_dt, dcCore::app()->auth->getInfo('user_tz')))))
->class('nowrap'),
'kut_service' => (new Text('td', $type))
->class('nowrap'),
]);
$cols = new ArrayObject($cols);
$this->userColumns('kUtRL', $cols);
$this->userColumns(My::id(), $cols);
return '<tr class="line">' . implode(iterator_to_array($cols)) . '</tr>' . "\n";
return
(new Para('p' . $this->rs->kut_id, 'tr'))
->class('line')
->items(iterator_to_array($cols));
}
}

View File

@ -2,6 +2,8 @@
/**
* @brief kUtRL, a plugin for Dotclear 2
*
* This file contents class to acces local short links records
*
* @package Dotclear
* @subpackage Plugin
*
@ -10,36 +12,52 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
# This file contents class to acces local short links records
declare(strict_types=1);
class kutrlLog
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use Dotclear\Database\MetaRecord;
use Dotclear\Database\Statement\{
DeleteStatement,
JoinStatement,
SelectStatement,
UpdateStatement
};
class Logs
{
public $table;
public $blog;
public $con;
public function __construct()
{
$this->table = dcCore::app()->prefix . initkUtRL::KURL_TABLE_NAME;
$this->blog = dcCore::app()->con->escape(dcCore::app()->blog->id);
$this->table = dcCore::app()->prefix . My::TABLE_NAME;
$this->con = dcCore::app()->con;
}
public function nextId()
public function nextId(): int
{
return $this->con->select(
'SELECT MAX(kut_id) FROM ' . $this->table
)->f(0) + 1;
$sql = new SelectStatement();
return $sql
->column($sql->max('kut_id'))
->from($this->table)
->select()
->f(0) + 1;
}
public function insert($url, $hash, $type, $service = 'kutrl')
/**
* @return false|array<string,int|string>
*/
public function insert(string $url, string $hash, string $type, string $service = 'kutrl')
{
$cur = $this->con->openCursor($this->table);
$this->con->writeLock($this->table);
try {
$cur->kut_id = $this->nextId();
$cur->blog_id = $this->blog;
$cur->blog_id = dcCore::app()->blog->id;
$cur->kut_url = (string) $url;
$cur->kut_hash = (string) $hash;
$cur->kut_type = (string) $type;
@ -64,45 +82,50 @@ class kutrlLog
throw $e;
}
return false;
return [];
}
public function select($url = null, $hash = null, $type = null, $service = 'kutrl')
/**
* @return false|MetaRecord
*/
public function select(?string $url = null, ?string $hash = null, ?string $type = null, string $service = 'kutrl')
{
//$this->con->writeLock($this->table);
$req = 'SELECT kut_id as id, kut_hash as hash, kut_url as url, ' .
'kut_type as type, kut_service as service, kut_counter as counter ' .
'FROM ' . $this->table . ' ' .
"WHERE blog_id = '" . $this->blog . "' " .
"AND kut_service = '" . $this->con->escape($service) . "' ";
$sql = new SelectStatement();
$sql
->columns([
$sql->as('kut_id', 'id'),
$sql->as('kut_hash', 'hash'),
$sql->as('kut_url', 'url'),
$sql->as('kut_type', 'type'),
$sql->as('kut_service', 'service'),
$sql->as('kut_counter', 'counter'),
])
->from($this->table)
->where('blog_id = ' . $sql->quote(dcCore::app()->blog->id))
->and('kut_service = ' . $sql->quote($service))
;
if (null !== $url) {
$req .= "AND kut_url = '" . $this->con->escape($url) . "' ";
$sql->and('kut_url = ' . $sql->quote($url));
}
if (null !== $hash) {
$req .= "AND kut_hash = '" . $this->con->escape($hash) . "' ";
$sql->and('kut_hash = ' . $sql->quote($hash));
}
if (null !== $type) {
if (is_array($type)) {
$req .= "AND kut_type '" . $this->con->in($type) . "' ";
} else {
$req .= "AND kut_type = '" . $this->con->escape($type) . "' ";
}
$sql->and('kut_type = ' . $sql->quote($type));
}
$req .= 'ORDER BY kut_dt DESC ' . $this->con->limit(1);
$sql
->order('kut_dt DESC')
->limit(1);
$rs = $this->con->select($req);
//$this->con->unlock();
$rs = $sql->select();
return $rs->isEmpty() ? false : $rs;
}
public function clear($id)
public function clear(int $id): bool
{
$id = (int) $id;
$cur = $this->con->openCursor($this->table);
$this->con->writeLock($this->table);
@ -112,7 +135,7 @@ class kutrlLog
$cur->kut_counter = 0;
$cur->update(
"WHERE blog_id='" . $this->blog . "' " .
"WHERE blog_id='" . $this->con->escapeStr(dcCore::app()->blog->id) . "' " .
"AND kut_id='" . $id . "' "
);
$this->con->unlock();
@ -127,29 +150,29 @@ class kutrlLog
return false;
}
public function delete($id)
public function delete(int $id): bool
{
$id = (int) $id;
$sql = new DeleteStatement();
$sql
->from($this->table)
->where('blog_id = ' . $sql->quote(dcCore::app()->blog->id))
->and('kut_id = ' . $id)
->delete();
return $this->con->execute(
'DELETE FROM ' . $this->table . ' ' .
"WHERE blog_id='" . $this->blog . "' " .
"AND kut_id='" . $id . "' "
);
return true;
}
public function counter($id, $do = 'get')
public function counter(int $id, string $do = 'get'): int
{
$id = (int) $id;
$sql = new SelectStatement();
$rs = $sql
->column('kut_counter')
->from($this->table)
->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog?->id))
->and('kut_id = ' . $id)
->select();
$rs = $this->con->select(
'SELECT kut_counter ' .
'FROM ' . $this->table . ' ' .
"WHERE blog_id='" . $this->blog . "' " .
"AND kut_id='" . $id . "' "
);
$counter = $rs->isEmpty() ? 0 : $rs->kut_counter;
$counter = $rs->isEmpty() ? 0 : (int) $rs->kut_counter;
if ('get' == $do) {
return $counter;
@ -161,94 +184,86 @@ class kutrlLog
return 0;
}
$cur = $this->con->openCursor($this->table);
$this->con->writeLock($this->table);
$cur->kut_counter = (int) $counter;
$cur->update(
"WHERE blog_id='" . $this->blog . "' " .
"AND kut_id='" . $id . "'"
);
$this->con->unlock();
$sql = new UpdateStatement();
$ret = $sql->ref($this->table)
->column('kut_counter')
->value($counter)
->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog?->id))
->and('kut_id = ' . $id)
->update();
return $counter;
}
public function getLogs($p, $count_only = false)
public function getLogs(array $params, bool $count_only = false): MetaRecord
{
if ($count_only) {
$r = 'SELECT count(S.kut_id) ';
} else {
$content_req = '';
$sql = new SelectStatement();
if (!empty($p['columns']) && is_array($p['columns'])) {
$content_req .= implode(', ', $p['columns']) . ', ';
}
$r = 'SELECT S.kut_id, S.kut_type, S.kut_hash, S.kut_url, ' .
$content_req . 'S.kut_dt ';
}
$r .= 'FROM ' . $this->table . ' S ';
if (!empty($p['from'])) {
$r .= $p['from'] . ' ';
}
$r .= "WHERE S.blog_id = '" . $this->blog . "' ";
if (isset($p['kut_service'])) {
$r .= "AND kut_service='" . $this->con->escape($p['kut_service']) . "' ";
if ($count_only) {
$sql->column($sql->count($sql->unique('S.kut_id')));
} else {
$r .= "AND kut_service='kutrl' ";
}
if (isset($p['kut_type'])) {
if (is_array($p['kut_type']) && !empty($p['kut_type'])) {
$r .= 'AND kut_type ' . $this->con->in($p['kut_type']);
} elseif ($p['kut_type'] != '') {
$r .= "AND kut_type = '" . $this->con->escape($p['kut_type']) . "' ";
if (!empty($params['columns']) && is_array($params['columns'])) {
$sql->columns($params['columns']);
}
$sql->columns([
'S.kut_id',
'S.kut_type',
'S.kut_hash',
'S.kut_url',
'S.kut_dt',
'S.kut_counter',
]);
}
if (isset($p['kut_id'])) {
if (is_array($p['kut_id']) && !empty($p['kut_id'])) {
$r .= 'AND kut_id ' . $this->con->in($p['kut_id']);
} elseif ($p['kut_id'] != '') {
$r .= "AND kut_id = '" . $this->con->escape($p['kut_id']) . "' ";
}
$sql->from($sql->as($this->table, 'S'));
if (!empty($params['from'])) {
$sql->from($params['from']);
}
if (isset($p['kut_hash'])) {
if (is_array($p['kut_hash']) && !empty($p['kut_hash'])) {
$r .= 'AND kut_hash ' . $this->con->in($p['kut_hash']);
} elseif ($p['kut_hash'] != '') {
$r .= "AND kut_hash = '" . $this->con->escape($p['kut_hash']) . "' ";
}
$sql->where('S.blog_id = ' . $sql->quote(dcCore::app()->blog->id));
if (isset($params['kut_service'])) {
$sql->and('kut_service = ' . $sql->quote($params['kut_service']));
} else {
$sql->and("kut_service = 'kutrl' ");
}
if (isset($p['kut_url'])) {
if (is_array($p['kut_url']) && !empty($p['kut_url'])) {
$r .= 'AND kut_url ' . $this->con->in($p['kut_url']);
} elseif ($p['kut_url'] != '') {
$r .= "AND kut_url = '" . $this->con->escape($p['kut_url']) . "' ";
}
if (isset($params['kut_type'])) {
$sql->and('kut_type ' . $sql->in($params['kut_type']));
}
if (!empty($p['kut_year'])) {
$r .= 'AND ' . $this->con->dateFormat('kut_dt', '%Y') . ' = ' .
"'" . sprintf('%04d', $p['kut_year']) . "' ";
if (isset($params['kut_id'])) {
$sql->and('kut_id ' . $sql->in($params['kut_id']));
}
if (!empty($p['kut_month'])) {
$r .= 'AND ' . $this->con->dateFormat('kut_dt', '%m') . ' = ' .
"'" . sprintf('%02d', $p['kut_month']) . "' ";
if (isset($params['kut_hash'])) {
$sql->and('kut_hash ' . $sql->in($params['kut_hash']));
}
if (!empty($p['kut_day'])) {
$r .= 'AND ' . $this->con->dateFormat('kut_dt', '%d') . ' = ' .
"'" . sprintf('%02d', $p['kut_day']) . "' ";
if (isset($params['kut_url'])) {
$sql->and('kut_url ' . $sql->in($params['kut_url']));
}
if (!empty($p['sql'])) {
$r .= $p['sql'] . ' ';
if (!empty($params['kut_year'])) {
$sql->and($sql->dateFormat('kut_dt', '%Y') . ' = ' . $sql->quote(sprintf('%04d', $params['kut_year'])));
}
if (!empty($params['kut_month'])) {
$sql->and($sql->dateFormat('kut_dt', '%m') . ' = ' . $sql->quote(sprintf('%02d', $params['kut_month'])));
}
if (!empty($params['kut_day'])) {
$sql->and($sql->dateFormat('kut_dt', '%d') . ' = ' . $sql->quote(sprintf('%02d', $params['kut_day'])));
}
if (!empty($params['sql'])) {
$sql->sql($params['sql']);
}
if (!$count_only) {
$r .= empty($p['order']) ?
'ORDER BY kut_dt DESC ' :
'ORDER BY ' . $this->con->escape($p['order']) . ' ';
}
if (!$count_only && !empty($p['limit'])) {
$r .= $this->con->limit($p['limit']);
if (!empty($params['order'])) {
$sql->order($sql->escape($params['order']));
} else {
$sql->order('kut_dt DESC');
}
}
return $this->con->select($r);
if (!$count_only && !empty($params['limit'])) {
$sql->limit($params['limit']);
}
return $sql->select();
}
}

View File

@ -10,29 +10,56 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return;
}
declare(strict_types=1);
# Check user perms
dcPage::check(dcCore::app()->auth->makePermissions([
dcAuth::PERMISSION_ADMIN,
]));
namespace Dotclear\Plugin\kUtRL;
$header = '';
$part = $_REQUEST['part'] ?? 'links';
$action = $_POST['action'] ?? '';
use dcCore;
use Dotclear\Core\Backend\{
Notices,
Page
};
use Dotclear\Core\Process;
use Dotclear\Helper\Html\Form\{
Div,
Form,
Input,
Label,
Note,
Para,
Submit,
Text,
};
use Dotclear\Helper\Html\Html;
# link creation
if ($part == 'link') {
$kut = kUtRL::quickPlace('admin');
class Manage extends Process
{
public static function init(): bool
{
return self::status(($_REQUEST['part'] ?? 'links') === 'links' ? ManageLinks::init() : My::checkContext(My::MANAGE));
}
public static function process(): bool
{
if (!self::status()) {
return false;
}
if (($_REQUEST['part'] ?? 'links') === 'links') {
return ManageLinks::process();
}
$kut = Utils::quickPlace('admin');
if (empty($_POST['save'])) {
return true;
}
if (!empty($_POST['save'])) {
try {
if (null === $kut) {
throw new Exception('Unknow service');
}
$url = trim(dcCore::app()->con->escape($_POST['str']));
$url = trim(dcCore::app()->con->escapeStr((string) $_POST['str']));
$hash = empty($_POST['custom']) ? null : $_POST['custom'];
if (empty($url)) {
@ -66,9 +93,9 @@ if ($part == 'link') {
$url = $rs->url;
$new_url = $kut->url_base . $rs->hash;
dcAdminNotices::addSuccessNotice(sprintf(
Notices::addSuccessNotice(sprintf(
__('Short link for %s is %s'),
'<strong>' . html::escapeHTML($url) . '</strong>',
'<strong>' . Html::escapeHTML($url) . '</strong>',
'<a href="' . $new_url . '">' . $new_url . '</a>'
));
} else {
@ -82,9 +109,9 @@ if ($part == 'link') {
$url = $rs->url;
$new_url = $kut->url_base . $rs->hash;
dcAdminNotices::addSuccessNotice(sprintf(
Notices::addSuccessNotice(sprintf(
__('Short link for %s is %s'),
'<strong>' . html::escapeHTML($url) . '</strong>',
'<strong>' . Html::escapeHTML($url) . '</strong>',
'<a href="' . $new_url . '">' . $new_url . '</a>'
));
@ -97,152 +124,91 @@ if ($part == 'link') {
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
return true;
}
# links
} else {
$services_combo = [];
foreach (kUtRL::getServices() as $service_id => $service) {
$o = new $service();
$services_combo[__($o->name)] = $o->id;
}
$ext_services_combo = array_merge([__('Disabled') => ''], $services_combo);
$lst_services_combo = array_merge(['-' => ''], $services_combo);
$log = new kutrlLog();
$kUtRL_filter = new adminGenericFilterV2('kUtRL');
$kUtRL_filter->add('part', 'links');
$kUtRL_filter->add(dcAdminFilters::getPageFilter());
$kUtRL_filter->add(dcAdminFilters::getSelectFilter(
'urlsrv',
__('Service:'),
$lst_services_combo,
'kut_type'
));
$params = $kUtRL_filter->params();
try {
$list_all = $log->getLogs($params);
$list_counter = $log->getLogs($params, true)->f(0);
$list_current = new kutrlLinkslist($list_all, $list_counter);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
$header = $kUtRL_filter->js(dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['part' => 'links'])) .
dcPage::jsModuleLoad(basename(__DIR__) . '/js/admin.js');
if (!empty($_POST['deletelinks'])) {
try {
foreach ($_POST['entries'] as $id) {
$rs = $log->getLogs(['kut_id' => $id]);
if ($rs->isEmpty()) {
continue;
}
if (null === ($o = kUtRL::quickService($rs->kut_type))) {
continue;
}
$o->remove($rs->kut_url);
}
dcCore::app()->blog->triggerBlog();
dcAdminNotices::addSuccessNotice(
__('Links successfully deleted')
);
dcCore::app()->adminurl->redirect('admin.plugin.' . basename(__DIR__), $kUtRL_filter->values());
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
}
}
# display header
echo
'<html><head><title>kUtRL, ' . __('Links shortener') . '</title>' .
$header .
'</head><body>';
# display link creation
if ($part == 'link') {
echo
dcPage::breadcrumb([
__('Plugins') => '',
__('Links shortener') => dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)),
__('New link') => '',
]) .
dcPage::notices();
if (!isset($kut) || null === $kut) {
echo '<p>' . __('You must set an admin service.') . '</p>';
} else {
echo '
<div class="fieldset">
<h4>' . sprintf(__('Shorten link using service "%s"'), $kut->name) . '</h4>
<form id="create-link" method="post" action="' . dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)) . '">
<p><label for="str">' . __('Long link:') . '</label>' .
form::field('str', 100, 255, '') . '</p>';
if ($kut->allow_custom_hash) {
echo
'<p><label for="custom">' . __('Custom short link:') . '</label>' .
form::field('custom', 50, 32, '') . '</p>' .
'<p class="form-note">' . __('Only if you want a custom short link.') . '</p>';
if ($kut->admin_service == 'local') {
echo '<p class="form-note">' .
__('You can use "bob!!" if you want a semi-custom link, it starts with "bob" and "!!" will be replaced by an increment value.') .
'</p>';
}
public static function render(): void
{
if (!self::status()) {
return;
}
echo '
<p><input type="submit" name="save" value="' . __('Save') . '" />' .
dcCore::app()->formNonce() .
form::hidden(['part'], 'link') . '
</p></div>
</form>';
if (($_REQUEST['part'] ?? 'links') === 'links') {
ManageLinks::render();
return;
}
$kut = Utils::quickPlace('admin');
Page::openModule(My::id());
echo
Page::breadcrumb([
__('Plugins') => '',
My::name() => My::manageUrl(),
__('New link') => '',
]) .
Notices::getNotices();
if (!isset($kut) || null === $kut) {
echo (new Para())
->text(__('You must set an admin service.'))
->render();
} else {
$fields = [];
if ($kut->allow_custom_hash) {
$fields[] = (new Para())
->items([
(new Label(__('Custom short link:'), Label::OUTSIDE_LABEL_BEFORE))
->for('custom'),
(new Input('custom'))
->size(50)
->maxlenght(32)
->value(''),
]);
$fields[] = (new Note())
->class('form-note')
->text(__('Only if you want a custom short link.'));
if ($kut->admin_service == 'local') {
$fields[] = (new 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.'));
}
}
echo (new Div())
->items([
(new Text('h4', sprintf(__('Shorten link using service "%s"'), $kut->name))),
(new Form('create-link'))
->method('post')
->action(My::manageUrl())
->fields([
(new Para())
->items([
(new Label(__('Long link:'), Label::OUTSIDE_LABEL_BEFORE))
->for('str'),
(new Input('str'))
->size(100)
->maxlenght(255)
->value(''),
]),
... $fields,
(new Submit('save'))
->value(__('Save')),
... My::hiddenFields([
'part' => 'link',
]),
]),
])
->render();
}
Page::helpBlock(My::id());
Page::closeModule();
}
} else {
echo
dcPage::breadcrumb([
__('Plugins') => '',
__('Links shortener') => '',
]) .
dcPage::notices() .
'<p class="top-add"><a class="button add" href="' .
dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['part' => 'link']) .
'">' . __('New Link') . '</a></p>';
$kUtRL_filter->display('admin.plugin.' . basename(__DIR__), form::hidden('p', basename(__DIR__)) . form::hidden('part', 'links'));
$list_current->display(
$kUtRL_filter->value('page'),
$kUtRL_filter->nb,
'<form action="' . dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)) . '" method="post" id="form-entries">
%s
<div class="two-cols">
<div class="col left">
<p class="checkboxes-helpers"></p>
</div>
<p class="col right">
<input id="do-action" type="submit" value="' . __('Delete selected short links') . '" /></p>' .
dcCore::app()->adminurl->getHiddenFormFields('admin.plugin.' . basename(__DIR__), array_merge(['deletelinks' => 1], $kUtRL_filter->values(true))) .
dcCore::app()->formNonce() . '
</p>
</div>
</form>',
$kUtRL_filter->show()
);
}
# display footer
dcPage::helpBlock('kUtRL');
echo '</body></html>';

163
src/ManageLinks.php 100644
View File

@ -0,0 +1,163 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use dcCore;
use Dotclear\Core\Backend\Filter\{
Filters,
FiltersLibrary
};
use Dotclear\Core\Backend\{
Notices,
Page
};
use Dotclear\Core\Process;
use Dotclear\Helper\Html\Form\{
Div,
Form,
Hidden,
Link,
Para,
Submit,
Text
};
class ManageLinks extends Process
{
private static Filters $kutrl_filter;
private static Linkslisting $kutrl_listing;
public static function init(): bool
{
return self::status(My::checkContext(My::MANAGE) && ($_REQUEST['part'] ?? 'links') === 'links');
}
public static function process(): bool
{
if (!self::status()) {
return false;
}
$log = new Logs();
self::$kutrl_filter = new Filters(My::id());
self::$kutrl_filter->add('part', 'links');
self::$kutrl_filter->add(FiltersLibrary::getPageFilter());
self::$kutrl_filter->add(FiltersLibrary::getSelectFilter(
'urlsrv',
__('Service:'),
array_merge(['-' => ''], Combo::servicesCombo()),
'kut_type'
));
$params = self::$kutrl_filter->params();
try {
$list_all = $log->getLogs($params);
$list_counter = $log->getLogs($params, true)->f(0);
self::$kutrl_listing = new LinksListing($list_all, $list_counter);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
if (!empty($_POST['deletelinks'])) {
try {
foreach ($_POST['entries'] as $id) {
$rs = $log->getLogs(['kut_id' => $id]);
if ($rs->isEmpty()) {
continue;
}
if (null === ($o = Utils::quickService($rs->kut_type))) {
continue;
}
$o->remove($rs->kut_url);
}
dcCore::app()->blog->triggerBlog();
Notices::addSuccessNotice(__('Links successfully deleted'));
My::redirect(self::$kutrl_filter->values());
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
}
return true;
}
public static function render(): void
{
if (!self::status()) {
return;
}
Page::openModule(
My::id(),
self::$kutrl_filter->js(My::manageUrl(['part' => 'links'])) .
My::jsLoad('admin')
);
echo
Page::breadcrumb([
__('Plugins') => '',
My::name() => My::manageUrl(),
]) .
Notices::getNotices() .
(new Para())
->class('top-add')
->items([
(new Link())
->class('button add')
->href(My::manageUrl(['part' => 'link']))
->title(__('New Link'))
->text(__('New Link')),
])
->render();
self::$kutrl_filter->display(
'admin.plugin.' . My::id(),
(new Hidden('p', My::id()))->render() . (new Hidden('part', 'links'))->render()
);
self::$kutrl_listing->display(
self::$kutrl_filter,
(new Form('form-entries'))
->action(My::manageUrl())
->method('post')
->fields([
(new Text('', '%s')),
(new Div())
->class('two-cols')
->items([
(new Para())
->class('col checkboxes-helpers'),
(new Para())
->class('col right')
->separator('&nbsp;')
->items([
(new Submit('do-action'))
->class('delete')
->value(__('Delete selected short links')),
... My::hiddenFields(array_merge(['deletelinks' => 1], self::$kutrl_filter->values(true))),
]),
]),
])->render()
);
Page::helpBlock(My::id());
Page::closeModule();
}
}

38
src/My.php 100644
View File

@ -0,0 +1,38 @@
<?php
/**
* @brief kUtRL, 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\kUtRL;
use Dotclear\Module\MyPlugin;
/**
* This module definitions.
*/
class My extends MyPlugin
{
/** @var string This module database table name */
public const TABLE_NAME = \initkUtRL::KURL_TABLE_NAME;
/** @var array List of template tag which content URL that can be shorten */
public const USED_TAGS = [
'AttachmentURL',
'CategoryURL',
'MediaURL',
'EntryAuthorURL',
'EntryURL',
'EntryCategoryURL',
'CommentAuthorURL',
'CommentPostURL',
];
}

View File

@ -10,90 +10,87 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return;
}
declare(strict_types=1);
# Set a URL shortener for quick get request
if (!defined('SHORTEN_SERVICE_NAME')) {
define('SHORTEN_SERVICE_NAME', 'Is.gd');
}
if (!defined('SHORTEN_SERVICE_API')) {
define('SHORTEN_SERVICE_API', 'https://is.gd/api.php?');
}
if (!defined('SHORTEN_SERVICE_BASE')) {
define('SHORTEN_SERVICE_BASE', 'https://is.gd/');
}
if (!defined('SHORTEN_SERVICE_PARAM')) {
define('SHORTEN_SERVICE_PARAM', 'longurl');
}
if (!defined('SHORTEN_SERVICE_ENCODE')) {
define('SHORTEN_SERVICE_ENCODE', false);
}
namespace Dotclear\Plugin\kUtRL;
# Main class
$d = __DIR__ . '/inc/';
Clearbricks::lib()->autoload([
'kUtRL' => $d . 'class.kutrl.php',
'kutrlService' => $d . 'lib.kutrl.srv.php',
'kutrlLog' => $d . 'lib.kutrl.log.php',
'kutrlLinkslist' => $d . 'lib.kutrl.lst.php',
]);
use dcCore;
use Dotclear\Core\Process;
# Services
Clearbricks::lib()->autoload(['defaultKutrlService' => $d . 'services/class.default.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['default','defaultKutrlService']; });
if (!defined('SHORTEN_SERVICE_DISABLE_CUSTOM')) {
Clearbricks::lib()->autoload(['customKutrlService' => $d . 'services/class.custom.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['custom','customKutrlService']; });
}
if (!defined('SHORTEN_SERVICE_DISABLE_LOCAL')) {
Clearbricks::lib()->autoload(['localKutrlService' => $d . 'services/class.local.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['local','localKutrlService']; });
}
if (!defined('SHORTEN_SERVICE_DISABLE_BILBOLINKS')) {
Clearbricks::lib()->autoload(['bilbolinksKutrlService' => $d . 'services/class.bilbolinks.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['bilbolinks','bilbolinksKutrlService']; });
}
if (!defined('SHORTEN_SERVICE_DISABLE_BITLY')) {
Clearbricks::lib()->autoload(['bitlyKutrlService' => $d . 'services/class.bitly.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['bitly','bitlyKutrlService']; });
}
//if (!defined('SHORTEN_SERVICE_DISABLE_GOOGL')) {
// Clearbricks::lib()->autoload(['googlKutrlService' => $d . 'services/class.googl.service.php']);
// dcCore::app()->addBehavior('kutrlService', function() { return ["googl","googlKutrlService"]; } );
//}
if (!defined('SHORTEN_SERVICE_DISABLE_ISGD')) {
Clearbricks::lib()->autoload(['isgdKutrlService' => $d . 'services/class.isgd.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['isgd','isgdKutrlService']; });
}
//if (!defined('SHORTEN_SERVICE_DISABLE_SHORTTO')) {
// Clearbricks::lib()->autoload(['shorttoKutrlService' => $d . 'services/class.shortto.service.php']);
// dcCore::app()->addBehavior('kutrlService', function() { return ["shortto","shorttoKutrlService"]; } );
//}
//if (!defined('SHORTEN_SERVICE_DISABLE_TRIM')) {
// Clearbricks::lib()->autoload(['trimKutrlService' => $d . 'services/class.trim.service.php']);
// dcCore::app()->addBehavior('kutrlService', function() { return ["trim","trimKutrlService"]; } );
//}
if (!defined('SHORTEN_SERVICE_DISABLE_YOURLS')) {
Clearbricks::lib()->autoload(['yourlsKutrlService' => $d . 'services/class.yourls.service.php']);
dcCore::app()->addBehavior('kutrlService', function () { return ['yourls','yourlsKutrlService']; });
}
//if (!defined('SHORTEN_SERVICE_DISABLE_SUPR')) {
// Clearbricks::lib()->autoload(['suprKutrlService' => $d . 'services/class.supr.service.php']);
// dcCore::app()->addBehavior('kutrlService', function() { return ["supr","suprKutrlService"]; } );
//}
/**
* Module prepend.
*/
class Prepend extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::PREPEND));
}
# Shorten url passed through wiki functions
Clearbricks::lib()->autoload(['kutrlWiki' => $d . 'lib.wiki.kutrl.php']);
dcCore::app()->addBehavior('coreInitWikiPost', ['kutrlWiki','coreInitWiki']);
dcCore::app()->addBehavior('coreInitWikiComment', ['kutrlWiki','coreInitWiki']);
dcCore::app()->addBehavior('coreInitWikiSimpleComment', ['kutrlWiki','coreInitWiki']);
public static function process(): bool
{
if (!self::status()) {
return false;
}
# Public page
dcCore::app()->url->register('kutrl', 'go', '^go(/(.*?)|)$', ['urlKutrl', 'redirectUrl']);
# Set a URL shortener for quick get request
if (!defined('SHORTEN_SERVICE_NAME')) {
define('SHORTEN_SERVICE_NAME', 'Is.gd');
}
if (!defined('SHORTEN_SERVICE_API')) {
define('SHORTEN_SERVICE_API', 'https://is.gd/api.php?');
}
if (!defined('SHORTEN_SERVICE_BASE')) {
define('SHORTEN_SERVICE_BASE', 'https://is.gd/');
}
if (!defined('SHORTEN_SERVICE_PARAM')) {
define('SHORTEN_SERVICE_PARAM', 'longurl');
}
if (!defined('SHORTEN_SERVICE_ENCODE')) {
define('SHORTEN_SERVICE_ENCODE', false);
}
# Add kUtRL events on plugin activityReport
if (defined('ACTIVITY_REPORT_V2')) {
require_once $d . 'lib.kutrl.activityreport.php';
# Services
dcCore::app()->addBehavior('kutrlService', fn () => ['default', Service\ServiceDefault::class]);
if (!defined('SHORTEN_SERVICE_DISABLE_CUSTOM')) {
dcCore::app()->addBehavior('kutrlService', fn () => ['custom', Service\ServiceCustom::class]);
}
if (!defined('SHORTEN_SERVICE_DISABLE_LOCAL')) {
dcCore::app()->addBehavior('kutrlService', fn () => ['local', Service\ServiceLocal::class]);
}
if (!defined('SHORTEN_SERVICE_DISABLE_BILBOLINKS')) {
dcCore::app()->addBehavior('kutrlService', fn () => ['bilbolinks', Service\ServiceBilbolinks::class]);
}
if (!defined('SHORTEN_SERVICE_DISABLE_BITLY')) {
dcCore::app()->addBehavior('kutrlService', fn () => ['bitly', Service\ServiceBitly::class]);
}
if (!defined('SHORTEN_SERVICE_DISABLE_ISGD')) {
dcCore::app()->addBehavior('kutrlService', fn () => ['isgd', Service\ServiceIsgd::class]);
}
if (!defined('SHORTEN_SERVICE_DISABLE_YOURLS')) {
dcCore::app()->addBehavior('kutrlService', fn () => ['yourls', Service\ServiceYourls::class]);
}
# Shorten url passed through wiki functions
dcCore::app()->addBehaviors([
'coreInitWikiPost' => [Wiki::class, 'coreInitWiki'],
'coreInitWikiComment' => [Wiki::class, 'coreInitWiki'],
'coreInitWikiSimpleComment' => [Wiki::class,'coreInitWiki'],
]);
# Public page
dcCore::app()->url->register(
'kutrl',
'go',
'^go(/(.*?)|)$',
[FrontendUrl::class, 'redirectUrl']
);
# Add kUtRL events on plugin activityReport
if (defined('ACTIVITY_REPORT_V2')) {
require_once $d . 'lib.kutrl.activityreport.php';
}
return true;
}
}

View File

@ -2,6 +2,9 @@
/**
* @brief kUtRL, a plugin for Dotclear 2
*
* Generic class for shorten link service
* A service class must extends this one
*
* @package Dotclear
* @subpackage Plugin
*
@ -10,9 +13,20 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
# Generic class for shorten link service
# A service class must extends this one
class kutrlService
declare(strict_types=1);
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use dcError;
use Dotclear\Database\MetaRecord;
use Dotclear\Helper\Html\Form\{
Div,
Note
};
use Dotclear\Helper\Network\HttpClient;
class Service
{
public $error;
public $settings;
@ -22,32 +36,32 @@ class kutrlService
public function __construct()
{
$this->settings = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)));
$this->log = new kutrlLog();
$this->settings = My::settings();
$this->log = new Logs();
$this->error = new dcError();
//$this->error->setHTMLFormat('%s', "%s\n");
$this->init();
// Force setting
$allow_external_url = $this->settings->get('allow_external_url');
$this->config['$allow_external_url'] = null === $allow_external_url ?
$allow_external_url = $this->settings?->get('allow_external_url');
$this->config['allow_external_url'] = null === $allow_external_url ?
true : $allow_external_url;
$this->config = array_merge(
[
'id' => 'undefined',
'name' => 'undefined',
'home' => '',
'id' => 'undefined',
'name' => 'undefined',
'home' => '',
'allow_external_url' => true,
'allow_custom_hash' => false,
'allow_protocols' => ['http://'],
'url_test' => 'http://github.com/JcDenis/kUtRL/releases',
'url_api' => '',
'url_base' => '',
'url_min_len' => 0,
'url_test' => 'http://github.com/JcDenis/kUtRL/releases',
'url_api' => '',
'url_base' => '',
'url_min_len' => 0,
],
$this->config
);
@ -66,52 +80,54 @@ class kutrlService
}
# Additionnal actions on child start
protected function init()
protected function init(): void
{
//
}
# Save settings from admin page
public function saveSettings()
public function saveSettings(): void
{
return null;
//
}
# Settings form for admin page
public function settingsForm()
public function settingsForm(): Div
{
echo
'<p class="form-note">' .
__('There is nothing to configure for this service.') .
'</p>';
return (new Div())
->items([
(new Note())
->class('form-note')
->text(__('There is nothing to configure for this service.')),
]);
}
# Test if service is well configured
public function testService()
public function testService(): bool
{
return null;
return true;
}
# Test if an url is valid
public function isValidUrl($url)
public function isValidUrl(string $url): bool
{
return (bool) filter_var($url, FILTER_VALIDATE_URL);
}
# Test if an url contents know prefix
public function isServiceUrl($url)
public function isServiceUrl(string $url): bool
{
return strpos($url, $this->url_base) === 0;
}
# Test if an url is long enoutgh
public function isLongerUrl($url)
public function isLongerUrl(string $url): bool
{
return (strlen($url) >= (int) $this->url_min_len);
}
# Test if an url protocol (eg: http://) is allowed
public function isProtocolUrl($url)
public function isProtocolUrl(string $url): bool
{
foreach ($this->allow_protocols as $protocol) {
if (empty($protocol)) {
@ -126,7 +142,7 @@ class kutrlService
}
# Test if an url is from current blog
public function isBlogUrl($url)
public function isBlogUrl(string $url): bool
{
$base = dcCore::app()->blog->url;
$url = substr($url, 0, strlen($base));
@ -134,22 +150,34 @@ class kutrlService
return $url == $base;
}
# Test if an url is know
public function isKnowUrl($url)
/**
* Test if an url is know.
*
* @return false|MetaRecord
*/
public function isKnowUrl(string $url)
{
return $this->log->select($url, null, $this->id, 'kutrl');
}
# Test if an custom short url is know
public function isKnowHash($hash)
/**
* Test if an custom short url is know.
*
* @return false|MetaRecord
*/
public function isKnowHash(string $hash)
{
return $this->log->select(null, $hash, $this->id, 'kutrl');
}
# Create hash from url
public function hash($url, $hash = null)
/**
* Create hash from url.
*
* @return false|MetaRecord
*/
public function hash(string $url, ?string $hash = null)
{
$url = trim(dcCore::app()->con->escape($url));
$url = trim(dcCore::app()->con->escapeStr((string) $url));
if ('undefined' === $this->id) {
return false;
}
@ -183,41 +211,54 @@ class kutrlService
return $rs;
}
# Create a hash for a given url (and its custom hash)
public function createHash($url, $hash = null)
/**
* Create a hash for a given url (and its custom hash).
*
* @return false|ArrayObject
*/
public function createHash(string $url, ?string $hash = null)
{
return false;
}
# Remove an url from list of know urls
public function remove($url)
/**
* Remove an url from list of know urls.
*/
public function remove(string $url): bool
{
if (!($rs = $this->isKnowUrl($url))) {
return false;
}
$this->deleteUrl($url);
$this->log->delete($rs->id);
$this->log->delete((int) $rs->id);
return true;
}
# Delete url on service (second argument really delete urls)
public function deleteUrl($url, $delete = false)
{
return null;
}
# Retrieve long url from hash
public function getUrl($hash)
/**
* Delete url on service (second argument really delete urls).
*/
public function deleteUrl(string $url, bool $delete = false): bool
{
return false;
}
# Post request
public static function post($server, $data, $verbose = true, $get = false, $headers = [])
/**
* Retrieve long url from hash.
*
* @return false|string
*/
public function getUrl(string $hash)
{
$url = (string) $server;
$client = netHttp::initClient($url, $url);
return false;
}
/**
* Post request.
*/
public static function post(string $url, $data, bool $verbose = true, bool $get = false, $headers = [])
{
$client = HttpClient::initClient($url, $url);
$client->setUserAgent('kUtRL - https://github.com/JcDenis/kUtRL');
$client->setPersistReferers(false);

View File

@ -10,11 +10,21 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
class bilbolinksKutrlService extends kutrlService
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use Dotclear\Helper\Html\Form\{
Div,
Input,
label,
Note,
Para
};
use Dotclear\Plugin\kUtRL\Service;
class ServiceBilbolinks extends Service
{
protected $config = [
'id' => 'bilbolinks',
@ -22,7 +32,7 @@ class bilbolinksKutrlService extends kutrlService
'home' => 'http://www.tux-planet.fr/bilbobox/',
];
protected function init()
protected function init(): void
{
$base = (string) $this->settings->get('srv_bilbolinks_base');
if (!empty($base) && substr($base, -1, 1) != '/') {
@ -33,7 +43,7 @@ class bilbolinksKutrlService extends kutrlService
$this->config['url_min_len'] = 25;
}
public function saveSettings()
public function saveSettings(): void
{
$base = '';
if (!empty($_POST['kutrl_srv_bilbolinks_base'])) {
@ -45,19 +55,26 @@ class bilbolinksKutrlService extends kutrlService
$this->settings->put('srv_bilbolinks_base', $base);
}
public function settingsForm()
public function settingsForm(): Div
{
echo
'<p><label class="classic">' .
__('Url of the service:') . '<br />' .
form::field(['kutrl_srv_bilbolinks_base'], 50, 255, $this->settings->get('srv_bilbolinks_base')) .
'</label></p>' .
'<p class="form-note">' .
__('This is the root URL of the "bilbolinks" service you want to use. Ex: "http://tux-pla.net/".') .
'</p>';
return (new Div())
->items([
(new Para())
->items([
(new Label(__('Url of the service:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_bilbolinks_base'),
(new Input('kutrl_srv_bilbolinks_base'))
->size(50)
->maxlenght(255)
->value((string) $this->settings->get('srv_bilbolinks_base')),
]),
(new Note())
->class('form-note')
->text(__('This is the root URL of the "bilbolinks" service you want to use. Ex: "http://tux-pla.net/".')),
]);
}
public function testService()
public function testService(): bool
{
if (empty($this->url_base)) {
$this->error->add(__('Service is not well configured.'));
@ -75,7 +92,7 @@ class bilbolinksKutrlService extends kutrlService
return true;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
$arg = ['longurl' => $url];

View File

@ -10,20 +10,30 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
class bitlyKutrlService extends kutrlService
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use Dotclear\Helper\Html\Form\{
Div,
Input,
label,
Note,
Para
};
use Dotclear\Plugin\kUtRL\Service;
class ServiceBitly extends Service
{
protected $config = [
'id' => 'bitly',
'name' => 'bit.ly',
'home' => 'https://bit.ly',
'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,
'url_api' => 'https://api-ssl.bitly.com/v4/',
'url_base' => 'https://bit.ly/',
'url_min_len' => 25,
'allow_protocols' => ['http://', 'https://'],
];
@ -32,28 +42,36 @@ class bitlyKutrlService extends kutrlService
'apiKey' => '',
];
protected function init()
protected function init(): void
{
$this->args['apiKey'] = $this->settings->get('srv_bitly_apikey');
}
public function saveSettings()
public function saveSettings(): void
{
$this->settings->put('srv_bitly_apikey', $_POST['kutrl_srv_bitly_apikey']);
}
public function settingsForm()
public function settingsForm(): Div
{
echo
'<p><label class="classic">' . __('API Key:') . '<br />' .
form::field(['kutrl_srv_bitly_apikey'], 50, 255, $this->settings->get('srv_bitly_apikey')) .
'</label></p>' .
'<p class="form-note">' .
sprintf(__('This is your personnal %s API key. You can find it on your account page.'), $this->config['name']) .
'</p>';
return (new Div())
->items([
(new Para())
->items([
(new Label(__('API Key:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_bitly_apikey'),
(new Input('kutrl_srv_bitly_apikey'))
->size(50)
->maxlenght(255)
->value((string) $this->settings->get('srv_bitly_apikey')),
]),
(new Note())
->class('form-note')
->text(sprintf(__('This is your personnal %s API key. You can find it on your account page.'), $this->config['name'])),
]);
}
public function testService()
public function testService(): bool
{
if (empty($this->args['apiKey'])) {
$this->error->add(__('Service is not well configured.'));
@ -71,7 +89,7 @@ class bitlyKutrlService extends kutrlService
return true;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
$args = json_encode(['domain' => 'bit.ly', 'long_url' => $url]);

View File

@ -10,18 +10,29 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
class customKutrlService extends kutrlService
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
Input,
Label,
Note,
Para
};
use Dotclear\Plugin\kUtRL\Service;
class ServiceCustom extends Service
{
protected $config = [
'id' => 'custom',
'name' => 'Custom',
];
protected function init()
protected function init(): void
{
$config = json_decode((string) $this->settings->get('srv_custom'), true);
if (!is_array($config)) {
@ -36,7 +47,7 @@ class customKutrlService extends kutrlService
$this->config['url_min_length'] = strlen($this->url_base) + 2;
}
public function saveSettings()
public function saveSettings(): void
{
$config = [
'url_api' => $_POST['kutrl_srv_custom_url_api'],
@ -47,7 +58,7 @@ class customKutrlService extends kutrlService
$this->settings->put('srv_custom', json_encode($config));
}
public function settingsForm()
public function settingsForm(): Div
{
$default = [
'url_api' => '',
@ -61,30 +72,63 @@ class customKutrlService extends kutrlService
}
$config = array_merge($default, $config);
echo
'<p>' . __('You can set a configurable service.') . '<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 returned the short URL (or only hash) in clear text.') . '</p>' .
'<p><label class="classic">' . __('API URL:') . '<br />' .
form::field(['kutrl_srv_custom_url_api'], 50, 255, $config['url_api']) .
'</label></p>' .
'<p class="form-note">' . __('Full path to API of the URL shortener. ex: "http://is.gd/api.php"') . '</p>' .
'<p><label class="classic">' . __('Short URL domain:') . '<br />' .
form::field(['kutrl_srv_custom_url_base'], 50, 255, $config['url_base']) .
'</label></p>' .
'<p class="form-note">' . __('Common part of the short URL. ex: "http://is.gd/"') . '</p>' .
'<p><label class="classic">' . __('API URL param:') . '<br />' .
form::field(['kutrl_srv_custom_url_param'], 50, 255, $config['url_param']) .
'</label></p>' .
'<p class="form-note">' . __('Param of the query. ex: "longurl"') . '</p>' .
'<p><label class="classic">' .
form::checkbox(['kutrl_srv_custom_url_encode'], '1', $config['url_encode']) . ' ' .
__('Encode URL') .
'</label></p>';
return (new Div())
->items([
(new Para())
->text(
__('You can set a configurable service.') . '<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 returned the short URL (or only hash) in clear text.')
),
(new Para())
->items([
(new Label(__('API URL:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_custom_url_api'),
(new Input('kutrl_srv_custom_url_api'))
->size(50)
->maxlenght(255)
->value((string) $config['url_api']),
]),
(new Note())
->class('form-note')
->text(__('Full path to API of the URL shortener. ex: "http://is.gd/api.php"')),
(new Para())
->items([
(new Label(__('Short URL domain:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_custom_url_base'),
(new Input('kutrl_srv_custom_url_base'))
->size(50)
->maxlenght(255)
->value((string) $config['url_base']),
]),
(new Note())
->class('form-note')
->text(__('Common part of the short URL. ex: "http://is.gd/"')),
(new Para())
->items([
(new Label(__('API URL param:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_custom_url_param'),
(new Input('kutrl_srv_custom_url_param'))
->size(50)
->maxlenght(255)
->value((string) $config['url_param']),
]),
(new Note())
->class('form-note')
->text(__('Param of the query. ex: "longurl"')),
(new Para())
->items([
(new Checkbox('kutrl_srv_custom_url_encode', (bool) $config['url_encode']))
->value(1),
(new Label(__('Encode URL'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('kutrl_srv_custom_url_encode'),
]),
]);
}
public function testService()
public function testService(): bool
{
if (empty($this->url_api)) {
return false;
@ -100,7 +144,7 @@ class customKutrlService extends kutrlService
return true;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
$enc = $this->url_encode ? urlencode($url) : $url;
$arg = [$this->url_param => $enc];

View File

@ -10,55 +10,70 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use Dotclear\Helper\Html\Form\{
Div,
Note,
Para,
Text
};
use Dotclear\Plugin\kUtRL\Service;
# nb: "default" ne veut pas dire service par défaut
# mais service simple et rapide configuré par des constantes
# cela permet de configurer ces constantes dans le fichier
# config de Dotclear pour une plateforme complète.
class defaultKutrlService extends kutrlService
class ServiceDefault extends Service
{
protected function init()
protected function init(): void
{
$this->config = [
'id' => 'default',
'name' => 'Default',
'home' => '',
'id' => 'default',
'name' => 'Default',
'home' => '',
'url_api' => SHORTEN_SERVICE_API,
'url_base' => SHORTEN_SERVICE_BASE,
'url_min_len' => strlen(SHORTEN_SERVICE_BASE) + 2,
'url_param' => SHORTEN_SERVICE_PARAM,
'url_encode' => SHORTEN_SERVICE_ENCODE,
'url_param' => SHORTEN_SERVICE_PARAM,
'url_encode' => SHORTEN_SERVICE_ENCODE,
];
}
public function settingsForm()
public function settingsForm(): Div
{
echo
'<p class="form-note">' .
__('There is nothing to configure for this service.') .
'</p>' .
'<p>' . __('This service is set to:') . '</p>' .
'<dl>' .
'<dt>' . __('Service name:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_NAME . '</dd>' .
'<dt>' . __('Full API URL:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_API . '</dd>' .
'<dt>' . __('Query param:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_PARAM . '</dd>' .
'<dt>' . __('Short URL domain:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_BASE . '</dd>' .
'<dt>' . __('Encode URL:') . '</dt>' .
'<dd>' . (SHORTEN_SERVICE_ENCODE ? __('yes') : __('no')) . '</dd>' .
'</dl>';
return (new Div())
->items([
(new Note())
->class('form-note')
->text(__('There is nothing to configure for this service.')),
(new Para())
->text(__('There is nothing to configure for this service.')),
(new Text(
'',
'<dl>' .
'<dt>' . __('Service name:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_NAME . '</dd>' .
'<dt>' . __('Full API URL:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_API . '</dd>' .
'<dt>' . __('Query param:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_PARAM . '</dd>' .
'<dt>' . __('Short URL domain:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_BASE . '</dd>' .
'<dt>' . __('Encode URL:') . '</dt>' .
'<dd>' . (SHORTEN_SERVICE_ENCODE ? __('yes') : __('no')) . '</dd>' .
'</dl>'
)),
]);
}
public function testService()
public function testService(): bool
{
$url = $this->url_encode ? urlencode($this->url_test) : $this->url_test;
$arg = [$this->url_param => urlencode($this->url_test)];
@ -72,7 +87,7 @@ class defaultKutrlService extends kutrlService
return true;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
$enc = $this->url_encode ? urlencode($url) : $url;
$arg = [$this->url_param => $url];

View File

@ -10,23 +10,26 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return;
}
declare(strict_types=1);
class isgdKutrlService extends kutrlService
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use Dotclear\Plugin\kUtRL\Service;
class ServiceIsgd extends Service
{
protected $config = [
'id' => 'isgd',
'name' => 'is.gd',
'home' => 'http://is.gd/',
'id' => 'isgd',
'name' => 'is.gd',
'home' => 'http://is.gd/',
'url_api' => 'http://is.gd/api.php',
'url_base' => 'http://is.gd/',
'url_min_length' => 25,
];
public function testService()
public function testService(): bool
{
$arg = ['longurl' => urlencode($this->url_test)];
if (!self::post($this->url_api, $arg, true, true)) {
@ -38,7 +41,7 @@ class isgdKutrlService extends kutrlService
return true;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
$arg = ['longurl' => $url];

View File

@ -10,21 +10,36 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
class localKutrlService extends kutrlService
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use dcCore;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
Input,
Label,
Note,
Para,
Text,
Textarea
};
use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\kUtRL\Service;
class ServiceLocal extends Service
{
protected $config = [
'id' => 'local',
'name' => 'kUtRL',
'home' => 'https://github.com/JcDenis/kUtRL',
'id' => 'local',
'name' => 'kUtRL',
'home' => 'https://github.com/JcDenis/kUtRL',
'allow_custom_hash' => true,
];
protected function init()
protected function init(): void
{
$protocols = (string) $this->settings->get('srv_local_protocols');
$this->config['allow_protocols'] = empty($protocols) ? [] : explode(',', $protocols);
@ -33,7 +48,7 @@ class localKutrlService extends kutrlService
$this->config['url_min_len'] = strlen($this->url_base) + 2;
}
public function saveSettings()
public function saveSettings(): void
{
$this->settings->put('srv_local_protocols', $_POST['kutrl_srv_local_protocols'], 'string');
$this->settings->put('srv_local_public', isset($_POST['kutrl_srv_local_public']), 'boolean');
@ -41,64 +56,96 @@ class localKutrlService extends kutrlService
$this->settings->put('srv_local_404_active', isset($_POST['kutrl_srv_local_404_active']), 'boolean');
}
public function settingsForm()
public function settingsForm(): Div
{
echo
'<div class="two-cols"><div class="col">' .
return (new Div())
->items([
(new Div())
->class('two-cols')
->items([
(new Div())
->class('col')
->items([
(new Text('b', __('Settings:'))),
(new Para())
->items([
(new Label(__('Allowed protocols:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_local_protocols'),
(new Input('kutrl_srv_local_protocols'))
->size(50)
->maxlenght(255)
->value((string) $this->settings->get('srv_local_protocols')),
]),
(new Note())
->class('form-note')
->text(__('Use comma seperated list like: "http:,https:,ftp:"')),
(new Para())
->items([
(new Checkbox('kutrl_srv_local_public', (bool) $this->settings->get('srv_local_public')))
->value(1),
(new Label(__('Enable public page for visitors to shorten links'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('kutrl_srv_local_public'),
]),
(new Para('style-area'))
->class('area')
->items([
(new Label(__('CSS:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_local_css'),
(new Textarea('kutrl_srv_local_css', Html::escapeHTML($this->settings->get('srv_local_css'))))
->cols(50)
->rows(3),
]),
(new Note())
->class('form-note')
->text(__('You can add here special cascading style sheet. Body of page has class "dc-kutrl" and widgets have class "shortenkutrlwidget" and "rankkutrlwidget".')),
(new Para())
->items([
(new Checkbox('kutrl_srv_local_404_active', (bool) $this->settings->get('srv_local_404_active')))
->value(1),
(new Label(__('Enable special 404 error public page for unknow urls'), Label::OUTSIDE_LABEL_AFTER))
->class('classic')
->for('kutrl_srv_local_404_active'),
]),
(new Note())
->class('form-note')
->text(__('If this is not activated, the default 404 page of the theme will be display.')),
]),
'<p><strong>' . __('Settings:') . '</strong></p>' .
'<p><label class="classic">' .
__('Allowed protocols:') . '<br />' .
form::field(['kutrl_srv_local_protocols'], 50, 255, $this->settings->get('srv_local_protocols')) .
'</label></p>' .
'<p class="form-note">' .
__('Use comma seperated list like: "http:,https:,ftp:"') .
'</p>' .
'<p><label class="classic">' .
form::checkbox(['kutrl_srv_local_public'], '1', $this->settings->get('srv_local_public')) . ' ' .
__('Enable public page for visitors to shorten links') .
'</label></p>' .
'<p class="area" id="style-area"><label for="_style">' . __('CSS:') . '</label>' .
form::textarea('kutrl_srv_local_css', 50, 3, html::escapeHTML($this->settings->get('srv_local_css')), '', '2') .
'</p>' .
'<p class="form-note">' . __('You can add here special cascading style sheet. Body of page has class "dc-kutrl" and widgets have class "shortenkutrlwidget" and "rankkutrlwidget".') . '</p>' .
'<p><label class="classic">' .
form::checkbox(['kutrl_srv_local_404_active'], '1', $this->settings->get('srv_local_404_active')) . ' ' .
__('Enable special 404 error public page for unknow urls') .
'</label></p>' .
'<p class="form-note">' . __('If this is not activated, the default 404 page of the theme will be display.') . '</p>' .
'</div><div class="col">' .
'<p><strong>' . __('Note:') . '</strong></p>' .
'<p>' .
__('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) .
'</p>' .
'<p>' .
__("You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog.");
if (preg_match('/index\.php/', $this->url_base)) {
echo
'<p>' .
__("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">' .
__("You can find more about this on the Dotclear's documentation.") .
'</a></p>';
}
echo
'</p>' .
'<p>' . __('There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.') . '<br />' .
__('Files are in plugin directory /default-templates, just copy them into your theme and edit them.') . '</p>' .
'</div></div><br class="clear"/>';
(new Div())
->class('col')
->items([
(new Text('b', __('Note:'))),
(new Text(
'p',
__('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)
)),
(new Text(
'p',
__("You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog.") .
(
preg_match('/index\.php/', $this->url_base) ?
' ' .
__("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">' .
__("You can find more about this on the Dotclear's documentation.") .
'</a>'
: ''
)
)),
(new Text(
'p',
__('There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.') . '<br />' .
__('Files are in plugin directory /default-templates, just copy them into your theme and edit them.')
)),
]),
]),
(new Text('br', ''))->class('clear'),
]);
}
public function testService()
public function testService(): bool
{
$ap = $this->allow_protocols;
if (!empty($ap)) {
@ -109,7 +156,7 @@ class localKutrlService extends kutrlService
return false;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
# Create response object
$rs = new ArrayObject();
@ -121,12 +168,12 @@ class localKutrlService extends kutrlService
$type = 'localnormal';
$rs->hash = $this->next($this->last('localnormal'));
# Mixed custom link
# Mixed custom link
} elseif (preg_match('/^([A-Za-z0-9]{2,})\!\!$/', $hash, $m)) {
$type = 'localmix';
$rs->hash = $m[1] . $this->next(-1, $m[1]);
# Custom link
# Custom link
} elseif (preg_match('/^[A-Za-z0-9\.\-\_]{2,}$/', $hash)) {
if (false !== $this->log->select(null, $hash, null, 'local')) {
$this->error->add(__('Custom short link is already taken.'));
@ -136,7 +183,7 @@ class localKutrlService extends kutrlService
$type = 'localcustom';
$rs->hash = $hash;
# Wrong char in custom hash
# Wrong char in custom hash
} else {
$this->error->add(__('Custom short link is not valid.'));
@ -215,7 +262,7 @@ class localKutrlService extends kutrlService
return implode($id);
}
public function getUrl($hash)
public function getUrl(string $hash)
{
if (false === ($rs = $this->log->select(null, $hash, null, 'local'))) {
return false;
@ -223,20 +270,20 @@ class localKutrlService extends kutrlService
if (!$rs->url) { //previously removed url
return false;
}
$this->log->counter($rs->id, 'up');
$this->log->counter((int) $rs->id, 'up');
return $rs->url;
}
public function deleteUrl($url, $delete = false)
public function deleteUrl(string $url, bool $delete = false): bool
{
if (false === ($rs = $this->log->select($url, null, null, 'local'))) {
return false;
}
if ($delete) {
$this->log->delete($rs->id);
$this->log->delete((int) $rs->id);
} else {
$this->log->clear($rs->id, '');
$this->log->clear((int) $rs->id);
}
return true;

View File

@ -10,11 +10,21 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
class yourlsKutrlService extends kutrlService
namespace Dotclear\Plugin\kUtRL\Service;
use ArrayObject;
use Dotclear\Helper\Html\Form\{
Div,
Input,
Label,
Note,
Para
};
use Dotclear\Plugin\kUtRL\Service;
class ServiceYourls extends Service
{
protected $config = [
'id' => 'yourls',
@ -29,7 +39,7 @@ class yourlsKutrlService extends kutrlService
'action' => 'shorturl',
];
protected function init()
protected function init(): void
{
$this->args['username'] = $this->settings->get('srv_yourls_username');
$this->args['password'] = $this->settings->get('srv_yourls_password');
@ -42,38 +52,58 @@ class yourlsKutrlService extends kutrlService
$this->config['url_min_len'] = strlen($base) + 3;
}
public function saveSettings()
public function saveSettings(): void
{
$this->settings->put('srv_yourls_username', $_POST['kutrl_srv_yourls_username']);
$this->settings->put('srv_yourls_password', $_POST['kutrl_srv_yourls_password']);
$this->settings->put('srv_yourls_base', $_POST['kutrl_srv_yourls_base']);
}
public function settingsForm()
public function settingsForm(): Div
{
echo
'<p><label class="classic">' .
__('Url of the service:') . '<br />' .
form::field(['kutrl_srv_yourls_base'], 50, 255, $this->settings->get('srv_yourls_base')) .
'</label></p>' .
'<p class="form-note">' .
__('This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".') .
'</p>' .
'<p><label class="classic">' . __('Login:') . '<br />' .
form::field(['kutrl_srv_yourls_username'], 50, 255, $this->settings->get('srv_yourls_username')) .
'</label></p>' .
'<p class="form-note">' .
__('This is your user name to sign up to this YOURLS service.') .
'</p>' .
'<p><label class="classic">' . __('Password:') . '<br />' .
form::field(['kutrl_srv_yourls_password'], 50, 255, $this->settings->get('srv_yourls_password')) .
'</label></p>' .
'<p class="form-note">' .
__('This is your password to sign up to this YOURLS service.') .
'</p>';
return (new Div())
->items([
(new Para())
->items([
(new Label(__('Url of the service:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_yourls_base'),
(new Input('kutrl_srv_yourls_base'))
->size(50)
->maxlenght(255)
->value((string) $this->settings->get('srv_yourls_base')),
(new Note())
->class('form-note')
->text(__('This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".')),
]),
(new Para())
->items([
(new Label(__('Login:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_yourls_username'),
(new Input('kutrl_srv_yourls_username'))
->size(50)
->maxlenght(255)
->value((string) $this->settings->get('srv_yourls_username')),
(new Note())
->class('form-note')
->text(__('This is your user name to sign up to this YOURLS service.')),
]),
(new Para())
->items([
(new Label(__('Password:'), Label::OUTSIDE_LABEL_BEFORE))
->for('kutrl_srv_yourls_password'),
(new Input('kutrl_srv_yourls_password'))
->size(50)
->maxlenght(255)
->value((string) $this->settings->get('srv_yourls_password')),
(new Note())
->class('form-note')
->text(__('This is your password to sign up to this YOURLS service.')),
]),
]);
}
public function testService()
public function testService(): bool
{
if (empty($this->url_api)) {
$this->error->add(__('Service is not well configured.'));
@ -99,7 +129,7 @@ class yourlsKutrlService extends kutrlService
return false;
}
public function createHash($url, $hash = null)
public function createHash(string $url, ?string $hash = null)
{
$args = array_merge($this->args, ['url' => $url]);

View File

@ -1,84 +0,0 @@
<?php
/**
* @brief kUtRL, 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
*/
if (!defined('DC_RC_PATH')) {
return null;
}
class googlKutrlService extends kutrlService
{
public $id = 'googl';
public $name = 'goo.gl';
public $home = 'http://goo.gl';
private $url_api = 'https://www.googleapis.com/urlshortener/v1/url';
private $url_test = 'https://github.com/JcDenis/kUtRL/releases';
private $args = [
'key' => '',
];
private $headers = ['Content-Type: application/json'];
protected function init()
{
$this->url_base = 'http://goo.gl/';
$this->url_min_length = 20;
}
public function testService()
{
$args = $this->args;
$args['shortUrl'] = $this->url_base . 'PLovn';
if (!($response = self::post($this->url_api, $args, true, true, $this->headers))) {
$this->error->add(__('Failed to call service.'));
return false;
}
$rsp = json_decode($response);
if (empty($rsp->status)) {
$this->error->add(__('An error occured'));
return false;
}
return true;
}
public function createHash($url, $hash = null)
{
$args = $this->args;
$args['longUrl'] = $url;
$args = json_encode($args);
if (!($response = self::post($this->url_api, $args, true, false, $this->headers))) {
$this->error->add(__('Failed to call service.'));
return false;
}
$rsp = json_decode($response);
if (empty($rsp->id)) {
$this->error->add(__('An error occured'));
return false;
}
$rs = new ArrayObject();
$rs->hash = str_replace($this->url_base, '', $rsp->id);
$rs->url = $rsp->longUrl;
$rs->type = $this->id;
return $rs;
}
}

View File

@ -1,58 +0,0 @@
<?php
/**
* @brief kUtRL, 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
*/
if (!defined('DC_RC_PATH')) {
return null;
}
class shorttoKutrlService extends kutrlService
{
protected $config = [
'id' => 'shortto',
'name' => 'short.to',
'home' => 'http://short.to',
'url_api' => 'http://short.to/s.txt',
'url_base' => 'http://short.to/',
'url_min_len' => 25,
];
public function testService()
{
$arg = ['url' => urlencode($this->url_test)];
if (!self::post($this->url_api, $arg, true, true)) {
$this->error->add(__('Service is unavailable.'));
return false;
}
return true;
}
public function createHash($url, $hash = null)
{
$arg = ['url' => $url];
if (!($response = self::post($this->url_api, $arg, true, true))) {
$this->error->add(__('Service is unavailable.'));
return false;
}
$rs = new ArrayObject();
$rs->hash = str_replace($this->url_base, '', $response);
$rs->url = $url;
$rs->type = $this->id;
return $rs;
}
}

View File

@ -1,124 +0,0 @@
<?php
/**
* @brief kUtRL, 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
*/
if (!defined('DC_RC_PATH')) {
return;
}
class suprKutrlService extends kutrlService
{
protected $config = [
'id' => 'supr',
'name' => 'su.pr StumbleUpon',
'home' => 'http://su.pr',
'url_api' => 'http://su.pr/api/',
'url_base' => 'http://su.pr/',
'url_min_len' => 23,
];
private $args = [
'version' => '1.0',
'format' => 'xml',
'login' => '',
'apiKey' => '',
];
protected function init()
{
$this->args['login'] = $this->settings->get('srv_supr_login');
$this->args['apiKey'] = $this->settings->get('srv_supr_apikey');
}
public function saveSettings()
{
$this->settings->put('srv_supr_login', $_POST['kutrl_srv_supr_login']);
$this->settings->put('srv_supr_apikey', $_POST['kutrl_srv_supr_apikey']);
}
public function settingsForm()
{
echo
'<p><label class="classic">' . __('Login:') . '<br />' .
form::field(['kutrl_srv_supr_login'], 50, 255, $this->settings->get('srv_supr_login')) .
'</label></p>' .
'<p class="form-note">' .
sprintf(__('This is your login to sign up to %s'), $this->config['name']) .
'</p>' .
'<p><label class="classic">' . __('API Key:') . '<br />' .
form::field(['kutrl_srv_supr_apikey'], 50, 255, $this->settings->get('srv_supr_apikey')) .
'</label></p>' .
'<p class="form-note">' .
sprintf(__('This is your personnal %s API key. You can find it on your account page.'), $this->config['name']) .
'</p>';
}
public function testService()
{
if (empty($this->args['login']) || empty($this->args['apiKey'])) {
$this->error->add(__('Service is not well configured.'));
return false;
}
$args = $this->args;
$arg['longUrl'] = $this->url_test;
if (!($response = self::post($this->url_api . 'shorten', $args, true))) {
$this->error->add(__('Failed to call service.'));
return false;
}
$rsp = simplexml_load_string($response);
$status = (string) $rsp->statusCode;
if ($status != 'OK') {
$err_no = (int) $rsp->errorCode;
$err_msg = (int) $rsp->errorMessage;
$this->error->add(sprintf(__('An error occured with code %s and message "%s"'), $err_no, $err_msg));
return false;
}
return true;
}
public function createHash($url, $hash = null)
{
$args = $this->args;
$args['longUrl'] = $url;
if (!($response = self::post($this->url_api . 'shorten', $args, true))) {
$this->error->add(__('Failed to call service.'));
return false;
}
$rsp = simplexml_load_string($response);
$status = (string) $rsp->statusCode;
if ($status != 'OK') {
$err_no = (int) $rsp->errorCode;
$err_msg = (int) $rsp->errorMessage;
$this->error->add(sprintf(__('An error occured with code %s and message "%s"'), $err_no, $err_msg));
return false;
}
$rs = new ArrayObject();
$rs->hash = (string) $rsp->results[0]->nodeKeyVal->hash;
$rs->url = (string) $rsp->results[0]->nodeKeyVal->nodeKey;
$rs->type = $this->id;
return $rs;
}
}

View File

@ -1,127 +0,0 @@
<?php
/**
* @brief kUtRL, 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
*/
if (!defined('DC_RC_PATH')) {
return;
}
class trimKutrlService extends kutrlService
{
protected $config = [
'id' => 'trim',
'name' => 'tr.im',
'home' => 'http://tr.im',
'url_api' => 'http://api.tr.im/v1/',
'url_base' => 'http://tr.im/',
'url_min_len' => 25,
];
private $args = [
'username' => '',
'password' => '',
];
private $api_rate_time = 0;
protected function init()
{
$this->args['username'] = $this->settings->get('srv_trim_username');
$this->args['password'] = $this->settings->get('srv_trim_password');
$this->api_rate_time = (int) $this->settings->get('srv_trim_apiratetime');
}
public function saveSettings()
{
$this->settings->put('srv_trim_username', $_POST['kutrl_srv_trim_username']);
$this->settings->put('srv_trim_password', $_POST['kutrl_srv_trim_password']);
}
public function settingsForm()
{
echo
'<p><label class="classic">' . __('Login:') . '<br />' .
form::field(['kutrl_srv_trim_username'], 50, 255, $this->settings->get('srv_trim_username')) .
'</label></p>' .
'<p class="form-note">' .
__('This is your login to sign up to tr.im.') .
'</p>' .
'<p><label class="classic">' . __('Password:') . '<br />' .
form::field(['kutrl_srv_trim_password'], 50, 255, $this->settings->get('srv_trim_password')) .
'</label></p>' .
'<p class="form-note">' .
__('This is your password to sign up to tr.im.') .
'</p>';
}
public function testService()
{
if (empty($this->args['username']) || empty($this->args['password'])) {
$this->error->add(__('Service is not well configured.'));
return false;
}
if (time() < $this->api_rate_time + 300) { // bloc service within 5min on API rate limit
$this->error->add(__('Prevent service rate limit.'));
return false;
}
if (!($rsp = self::post($this->url_api . 'verify.xml', $this->args, true, true))) {
$this->error->add(__('Service is unavailable.'));
return false;
}
$r = simplexml_load_string($rsp);
if ($r['code'] == 200) {
return true;
}
$this->error->add(__('Authentication to service failed.'));
return false;
}
public function createHash($url, $hash = null)
{
$arg = $this->args;
$arg['url'] = $url;
if (!($rsp = self::post($this->url_api . 'trim_url.xml', $arg, true, true))) {
$this->error->add(__('Service is unavailable.'));
return false;
}
$r = simplexml_load_string($rsp);
# API rate limit
if ($r['code'] == 425) {
$this->settings->put('srv_trim_apiratetime', time());
$this->error->add(__('Service rate limit exceeded.'));
return false;
}
if (isset($r->trimpath)) {
$rs = new ArrayObject();
$rs->hash = $r->trimpath;
$rs->url = $url;
$rs->type = $this->id;
return $rs;
}
$this->error->add(__('Unreadable service response.'));
return false;
}
}

View File

@ -10,86 +10,73 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return;
declare(strict_types=1);
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use Dotclear\Core\Process;
use Dotclear\Plugin\Uninstaller\Uninstaller;
/**
* Plugin Uninstaller actions.
*/
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(
'tables',
'delete',
My::TABLE_NAME,
)
->addUserAction(
'plugins',
'delete',
My::id()
)
->addUserAction(
'versions',
'delete',
My::id()
)
->addDirectAction(
'settings',
'delete_all',
My::id()
)
->addDirectAction(
'tables',
'delete',
My::TABLE_NAME
)
->addDirectAction(
'plugins',
'delete',
My::id()
)
->addDirectAction(
'versions',
'delete',
My::id()
)
;
return false;
}
}
$this->addUserAction(
/* type */
'settings',
/* action */
'delete_all',
/* ns */
basename(__DIR__),
/* description */
__('delete all settings')
);
$this->addUserAction(
/* type */
'tables',
/* action */
'delete',
/* ns */
initkUtRL::KURL_TABLE_NAME,
/* description */
__('delete table')
);
$this->addUserAction(
/* type */
'plugins',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
__('delete plugin files')
);
$this->addUserAction(
/* type */
'versions',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
__('delete the version number')
);
# Delete only dc version and plugin files from pluginsBeforeDelete
# Keep table
$this->addDirectAction(
/* type */
'settings',
/* action */
'delete_all',
/* ns */
basename(__DIR__),
/* description */
sprintf(__('delete all %s settings'), basename(__DIR__))
);
$this->addDirectAction(
/* type */
'versions',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
sprintf(__('delete %s version number'), basename(__DIR__))
);
$this->addDirectAction(
/* type */
'plugins',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
sprintf(__('delete %s plugin files'), basename(__DIR__))
);

View File

@ -2,6 +2,8 @@
/**
* @brief kUtRL, a plugin for Dotclear 2
*
* Generic class to play easily with services
*
* @package Dotclear
* @subpackage Plugin
*
@ -10,15 +12,21 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
# Generic class to play easily with services
class kUtRL
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use Exception;
class Utils
{
# Load services list from behavior
public static function getServices()
/**
* Load services list from behavior.
*
* @return array<string,string> The services list
*/
public static function getServices(): ?array
{
$list = dcCore::app()->getBehaviors('kutrlService');
@ -37,9 +45,14 @@ class kUtRL
return $services;
}
# Silently try to load a service according to its id
# Return null on error else service on success
public static function quickService($id = '')
/**
* Silently try to load a service according to its id.
*
* @param string $id The service ID
*
* @return Service The service instance or null on error;
*/
public static function quickService(string $id = ''): ?Service
{
try {
if (empty($id)) {
@ -55,15 +68,20 @@ class kUtRL
return null;
}
# Silently try to load a service according to its place
# Return null on error else service on success
public static function quickPlace($place = 'plugin')
/**
* Silently try to load a service according to its place.
*
* @param string The execution context
*
* @return Service The service or null on error
*/
public static function quickPlace(string $place = 'plugin'): ?Service
{
try {
if (!in_array($place, ['tpl', 'wiki', 'admin', 'plugin'])) {
return null;
}
$id = dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get($place . '_service');
$id = My::settings()->get($place . '_service');
if (!empty($id)) {
return self::quickService($id);
}
@ -73,9 +91,16 @@ class kUtRL
return null;
}
# Silently try to reduce url (using 'plugin' place)
# return long url on error else short url on success
public static function quickReduce($url, $custom = null, $place = 'plugin')
/**
* Silently try to reduce url (using 'plugin' place).
*
* @param string $url The long URL
* @param string $cutom The custom short URI
* @param string $place The context
*
* @return string The short url on success else the long url
*/
public static function quickReduce(string $url, ?string $custom = null, string $place = 'plugin'): string
{
try {
$srv = self::quickPlace($place);

View File

@ -10,22 +10,32 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
dcCore::app()->addBehavior('initWidgets', ['widgetKutrl', 'adminShorten']);
dcCore::app()->addBehavior('initWidgets', ['widgetKutrl', 'adminRank']);
namespace Dotclear\Plugin\kUtRL;
class widgetKutrl
use dcCore;
use Dotclear\Helper\Html\Form\{
Form,
Hidden,
Input,
Label,
Para,
Submit
};
use Dotclear\Helper\Html\Html;
use Dotclear\Plugin\widgets\WidgetsStack;
use Dotclear\Plugin\widgets\WidgetsElement;
class Widgets
{
public static function adminShorten($w)
public static function initShorten(WidgetsStack $w): void
{
$w
->create(
'shortenkutrl',
__('Links shortener'),
['widgetKutrl', 'publicShorten']
My::name(),
[self::class, 'parseShorten']
)
->addTitle(__('Shorten link'))
->addHomeOnly()
@ -34,13 +44,13 @@ class widgetKutrl
->addOffline();
}
public static function adminRank($w)
public static function initRank(WidgetsStack $w): void
{
$w
->create(
'rankkutrl',
__('Top of short links'),
['widgetKutrl', 'publicRank']
[self::class, 'parseRank']
)
->addTitle(__('Top of short links'))
->setting(
@ -112,49 +122,65 @@ class widgetKutrl
->addOffline();
}
public static function publicShorten($w)
public static function parseShorten(WidgetsElement $w): string
{
$s = dcCore::app()->blog->settings->get(basename(__DIR__));
$s = My::settings();
if (!$s->get('active')
|| !$s->get('srv_local_public')
|| !$w->checkHomeOnly(dcCore::app()->url->type)
|| dcCore::app()->url->type == 'kutrl') {
return null;
return '';
}
$hmf = hmfKutrl::create();
$hmfp = hmfKutrl::protect($hmf);
$hmf = FrontendUtils::create();
$hmfp = FrontendUtils::protect($hmf);
return $w->renderDiv(
$w->content_only,
(bool) $w->content_only,
'shortenkutrlwidget ' . $w->class,
'',
($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') .
'<form name="shortenkutrlwidget" method="post" action="' .
dcCore::app()->blog->url . dcCore::app()->url->getBase('kutrl') . '">' .
'<p><label>' .
__('Long link:') . '<br />' .
form::field('longurl', 20, 255, '') .
'</label></p>' .
'<p><label>' .
sprintf(__('Rewrite "%s" in next field to show that you are not a robot:'), $hmf) . '<br />' .
form::field('hmf', 20, 255, '') .
'</label></p>' .
'<p><input class="submit" type="submit" name="submiturl" value="' . __('Shorten') . '" />' .
form::hidden('hmfp', $hmfp) .
dcCore::app()->formNonce() .
'</p>' .
'</form>'
($w->title ? $w->renderTitle(Html::escapeHTML($w->title)) : '') .
(new Form(['shortenkutrlwidget']))
->method('post')
->action(dcCore::app()->blog->url . dcCore::app()->url->getBase('kutrl'))
->fields([
(new Para())
->items([
(new Label(__('Long link:'), Label::OUTSIDE_LABEL_BEFORE))
->for('longurl'),
(new Input('longurl'))
->size(20)
->maxlenght(255)
->value(''),
]),
(new Para())
->items([
(new Label(sprintf(__('Rewrite "%s" in next field to show that you are not a robot:'), $hmf), Label::OUTSIDE_LABEL_BEFORE))
->for('hmf'),
(new Input('hmf'))
->size(20)
->maxlenght(255)
->value(''),
]),
(new Para())
->items([
(new Submit('submiturl'))
->value(__('Shorten')),
(new Hidden('hmfp', $hmfp)),
dcCore::app()->formNonce(false),
]),
])
->render()
);
}
public static function publicRank($w)
public static function parseRank(WidgetsElement $w): string
{
$s = dcCore::app()->blog->settings->get(basename(__DIR__));
$s = My::settings();
if (!$s->get('active') || !$w->checkHomeOnly(dcCore::app()->url->type)) {
return null;
return '';
}
$type = in_array($w->type, ['localnormal', 'localmix', 'localcustom']) ?
@ -165,7 +191,7 @@ class widgetKutrl
$more = '';
if ($w->type == 'localmix' && '' != $w->mixprefix) {
$more = "AND kut_hash LIKE '" . dcCore::app()->con->escape($w->mixprefix) . "%' ";
$more = "AND kut_hash LIKE '" . dcCore::app()->con->escapeStr((string) $w->mixprefix) . "%' ";
}
$order = ($w->sortby && in_array($w->sortby, ['kut_dt', 'kut_counter', 'kut_hash'])) ?
@ -177,14 +203,14 @@ class widgetKutrl
$rs = dcCore::app()->con->select(
'SELECT kut_counter, kut_hash ' .
'FROM ' . dcCore::app()->prefix . initkUtRL::KURL_TABLE_NAME . ' ' .
"WHERE blog_id='" . dcCore::app()->con->escape(dcCore::app()->blog->id) . "' " .
'FROM ' . dcCore::app()->prefix . My::TABLE_NAME . ' ' .
"WHERE blog_id='" . dcCore::app()->con->escapeStr((string) dcCore::app()->blog->id) . "' " .
"AND kut_service = 'local' " .
$type . $hide . $more . 'ORDER BY ' . $order . $limit
);
if ($rs->isEmpty()) {
return null;
return '';
}
$content = '';
@ -225,14 +251,14 @@ class widgetKutrl
}
if (empty($content)) {
return null;
return '';
}
return $w->renderDiv(
$w->content_only,
(bool) $w->content_only,
'lastblogupdate ' . $w->class,
'',
($w->title ? $w->renderTitle(html::escapeHTML($w->title)) : '') .
($w->title ? $w->renderTitle(Html::escapeHTML($w->title)) : '') .
sprintf('<ul>%s</ul>', $content)
);
}

View File

@ -2,6 +2,8 @@
/**
* @brief kUtRL, a plugin for Dotclear 2
*
* This file contents class to shorten url pass through wiki
*
* @package Dotclear
* @subpackage Plugin
*
@ -10,40 +12,44 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
# This file contents class to shorten url pass through wiki
declare(strict_types=1);
if (!defined('DC_RC_PATH')) {
return null;
}
namespace Dotclear\Plugin\kUtRL;
class kutrlWiki
use dcCore;
use Dotclear\Helper\Html\WikiToHtml;
class Wiki
{
public static function coreInitWiki($wiki2xhtml)
public static function coreInitWiki(WikiToHtml $wiki2xhtml): void
{
# Do nothing on comment preview and post preview
if (!empty($_POST['preview'])
|| isset(dcCore::app()->ctx) && dcCore::app()->ctx->preview
|| !dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('active')
|| !My::settings()?->get('active')
) {
return null;
return;
}
if (null === ($kut = kUtRL::quickPlace('wiki'))) {
return null;
if (null === ($kut = Utils::quickPlace('wiki'))) {
return;
}
foreach ($kut->allow_protocols as $protocol) {
$wiki2xhtml->registerFunction(
'url:' . $protocol,
['kutrlWiki', 'transform']
[self::class, 'transform']
);
}
}
public static function transform($url, $content)
/**
* @return array<string,string>
*/
public static function transform(string $url, string $content): ?array
{
if (!dcCore::app()->blog->settings->get(basename(dirname(__DIR__)))->get('active')) {
if (!My::settings()?->get('active')) {
return null;
}
if (null === ($kut = kUtRL::quickPlace('wiki'))) {
if (null === ($kut = Utils::quickPlace('wiki'))) {
return [];
}
# Test if long url exists
@ -64,10 +70,7 @@ class kutrlWiki
$res['content'] = $res['url'];
}
# ex: Send new url to messengers
if (!empty($rs)) {
dcCore::app()->callBehavior('wikiAfterKutrlCreate', $rs, __('New short URL'));
}
dcCore::app()->callBehavior('wikiAfterKutrlCreate', $rs, __('New short URL'));
return $res;
}