upgrade to dotclear 2.27

This commit is contained in:
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 */ /* toogle admin form sidebar */
$('#kUtRL h5').toggleWithLegend( $('#kUtRL h5').toggleWithLegend(
$('#kUtRL').children().not('h5'), $('#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 ! # DOT NOT MODIFY THIS FILE !
# #
l10n::$locales['Links shortener'] = 'Réducteur de liens'; use Dotclear\Helper\L10n;
l10n::$locales['Short link'] = 'Lien court';
l10n::$locales['Long link'] = 'Lien long'; L10n::$locales['Links shortener'] = 'Réducteur de liens';
l10n::$locales['Service'] = 'Service'; L10n::$locales['Long link:'] = 'Lien long :';
l10n::$locales['Hash'] = 'Hash'; L10n::$locales['Shorten'] = 'Raccourir';
l10n::$locales['links per page'] = 'liens par page'; L10n::$locales['URL not found'] = 'Lien non trouvé';
l10n::$locales['Create short link'] = 'Créer un lien court'; L10n::$locales['The URL you are looking for does not exist.'] = 'Le liens que vous recherchez n\'existe pas.';
l10n::$locales['Custom short link:'] = 'Lien court personnalisé :'; L10n::$locales['Create your own short URL'] = 'Créer votre propre lien court';
l10n::$locales['never followed'] = 'jamais suivi'; L10n::$locales['Plugin kUtRL'] = 'Extension kUtRL';
l10n::$locales['followed one time'] = 'suivi une fois'; L10n::$locales['Short link creation'] = 'Création de lien court';
l10n::$locales['followed %s times'] = 'suivi %s fois'; 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['Delete short link'] = 'Effacer un lien court'; L10n::$locales['Hash'] = 'Hash';
l10n::$locales['No enough right'] = 'Privilèges insuffisants'; L10n::$locales['Service'] = 'Service';
l10n::$locales['Posts short links have been created.'] = 'Les liens courts des billets ont été créé.'; L10n::$locales['links per page'] = 'liens par page';
l10n::$locales['Disabled'] = 'Désactiver'; L10n::$locales['Create short link'] = 'Créer un lien court';
l10n::$locales['Enable plugin'] = 'Activer le plugin'; L10n::$locales['Custom short link:'] = 'Lien court personnalisé :';
l10n::$locales['Behaviors'] = 'Comportements'; L10n::$locales['never followed'] = 'jamais suivi';
l10n::$locales['Allow short link for external URL'] = 'Autoriser les liens court sur des URLs externes'; L10n::$locales['followed one time'] = 'suivi une fois';
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['followed %s times'] = 'suivi %s fois';
l10n::$locales['Passive mode'] = 'Mode passif'; L10n::$locales['Delete short link'] = 'Effacer un lien court';
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['Short link'] = 'Lien court';
l10n::$locales['Active mode'] = 'Mode actif'; L10n::$locales['No enough right'] = 'Privilèges insuffisants';
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['Posts short links have been created.'] = 'Les liens courts des billets ont été créé.';
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['Long link'] = 'Lien long';
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['Disabled'] = 'Désactiver';
l10n::$locales['Create short link for new entries'] = 'Créer un lien court pour les nouveaux billets'; L10n::$locales['Failed to test %s API.'] = 'Impossible de tester l\'API %s.';
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['%s API is well configured and runing.'] = 'L\'API %s est correctement configurée et est fonctionnelle.';
l10n::$locales['Default services'] = 'Services par défaut'; L10n::$locales['Failed to test service %s: %s'] = 'Impossible de tester le service %s : %s';
l10n::$locales['Administration:'] = 'Administration :'; L10n::$locales['homepage'] = 'page d\'accueil';
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['Learn more about %s.'] = 'En savoir plus à propos de %s.';
l10n::$locales['Extensions:'] = 'Extensions :'; L10n::$locales['Enable plugin'] = 'Activer le plugin';
l10n::$locales['Service to use on third part plugins.'] = 'Service à utiliser par les plugins tiers'; L10n::$locales['Behaviors'] = 'Comportements';
l10n::$locales['Templates:'] = 'Templates :'; L10n::$locales['Allow short link for external URL'] = 'Autoriser les liens court sur des URLs externes';
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['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['Contents:'] = 'Contenus :'; L10n::$locales['Passive mode'] = 'Mode passif';
l10n::$locales['Shorten links automatically found in contents using wiki synthax.'] = 'Réduit automatiquement les liens des contenus utilisant la syntax wiki.'; 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['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['Active mode'] = 'Mode actif';
l10n::$locales['Failed to test %s API.'] = 'Impossible de tester l\'API %s.'; 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['%s API is well configured and runing.'] = 'L\'API %s est correctement configurée et est fonctionnelle.'; 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['Failed to test service %s: %s'] = 'Impossible de tester le service %s : %s'; 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['homepage'] = 'page d\'accueil'; L10n::$locales['Create short link for new entries'] = 'Créer un lien court pour les nouveaux billets';
l10n::$locales['Learn more about %s.'] = 'En savoir plus à propos de %s.'; 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['Failed to verify protected field.'] = 'Impossible de vérifier le champs de protection.'; L10n::$locales['Default services'] = 'Services par défaut';
l10n::$locales['Service is not well configured.'] = 'Le service n\'est pas correctement configuré.'; L10n::$locales['Administration:'] = 'Administration :';
l10n::$locales['This string is not a valid URL.'] = 'Cette chaine n\'est pas un lien valide.'; 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['This link is too short.'] = 'Ce lien est trop court.'; L10n::$locales['Extensions:'] = 'Extensions :';
l10n::$locales['This type of link is not allowed.'] = 'Ce type de lien n\'est pas autorisé.'; L10n::$locales['Service to use on third part plugins.'] = 'Service à utiliser par les plugins tiers';
l10n::$locales['Short links are limited to this blog URL.'] = 'Les liens courts sont limités à l\'URL de ce blog.'; L10n::$locales['Templates:'] = 'Templates :';
l10n::$locales['This link is already a short link.'] = 'Ce lien est dèjà un lien court.'; 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['Short link for %s is %s'] = 'Le lien court pour %s est %s'; L10n::$locales['Contents:'] = 'Contenus :';
l10n::$locales['Failed to create short link.'] = 'Impossible de créer le lien court.'; L10n::$locales['Shorten links automatically found in contents using wiki synthax.'] = 'Réduit automatiquement les liens des contenus utilisant la syntax wiki.';
l10n::$locales['New public short URL'] = 'Nouvelle URL courte'; 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['Confirm by writing "%s" in next field:'] = 'Confirmez en écrivant "%s" dans le champs suivant :'; L10n::$locales['New public short URL'] = 'Nouvelle URL courte';
l10n::$locales['Shorten link'] = 'Réduire un lien'; L10n::$locales['Confirm by writing "%s" in next field:'] = 'Confirmez en écrivant "%s" dans le champs suivant :';
l10n::$locales['Top of short links'] = 'Top des liens courts'; L10n::$locales['Failed to verify protected field.'] = 'Impossible de vérifier le champs de protection.';
l10n::$locales['Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)'] = 'Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)'; L10n::$locales['Service is not well configured.'] = 'Le service n\'est pas correctement configuré.';
l10n::$locales['URL length (if truncate)'] = 'Longueur de l\'URL (si tronqué)'; L10n::$locales['This string is not a valid URL.'] = 'Cette chaine n\'est pas un lien valide.';
l10n::$locales['All'] = 'Tous'; L10n::$locales['This link is too short.'] = 'Ce lien est trop court.';
l10n::$locales['Mini URL'] = 'Mini URL'; L10n::$locales['This type of link is not allowed.'] = 'Ce type de lien n\'est pas autorisé.';
l10n::$locales['Custom URL'] = 'URL personnalisé'; L10n::$locales['Short links are limited to this blog URL.'] = 'Les liens courts sont limités à l\'URL de ce blog.';
l10n::$locales['Semi-custom'] = 'Semi-personnalisé'; L10n::$locales['This link is already a short link.'] = 'Ce lien est dèjà un lien court.';
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['Short link for %s is %s'] = 'Le lien court pour %s est %s';
l10n::$locales['Sort by:'] = 'Trier par :'; L10n::$locales['Failed to create short link.'] = 'Impossible de créer le lien court.';
l10n::$locales['Rank'] = 'Rang'; L10n::$locales['No short link matches the filter'] = 'Aucun lien correspondant au filtre';
l10n::$locales['Limit:'] = 'Limite :'; L10n::$locales['No short link'] = 'Pas de lien court';
l10n::$locales['Hide no followed links'] = 'Cacher les liens non suivis'; L10n::$locales['List of %s links matching the filter.'] = 'Liste des %s liens correspondant au filtre.';
l10n::$locales['Long link:'] = 'Lien long :'; L10n::$locales['List of links. (%s)'] = 'Liste des liens. (%s)';
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['There is nothing to shorten.'] = 'Il n\'y a rien à réduire.';
l10n::$locales['Shorten'] = 'Raccourir'; L10n::$locales['This service does not allowed custom hash.'] = 'Ce service n\'accepte pas les liens court personnalisés.';
l10n::$locales['Plugin kUtRL'] = 'Extension kUtRL'; L10n::$locales['This link is not a valid URL.'] = 'Ce lien n\'est pas valide.';
l10n::$locales['Short link creation'] = 'Création de lien court'; L10n::$locales['This custom short url is already taken.'] = 'Ce lien court personnalisé est déjà pris.';
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['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['No short link matches the filter'] = 'Aucun lien correspondant au filtre'; L10n::$locales['New short URL'] = 'Nouvelle URL courte';
l10n::$locales['No short link'] = 'Pas de lien court'; L10n::$locales['New link'] = 'Nouveau lien';
l10n::$locales['List of %s links matching the filter.'] = 'Liste des %s liens correspondant au filtre.'; L10n::$locales['You must set an admin service.'] = 'Vous devez définir un service admin.';
l10n::$locales['List of links (%s)'] = 'Listes des liens (%s)'; L10n::$locales['Only if you want a custom short link.'] = 'Uniquement si vous souhaitez un lien court personnalisé.';
l10n::$locales['There is nothing to configure for this service.'] = 'Il n\'y a rien à configurer pour ce service.'; 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['%s (Shorten with %s)'] = '%s (réduit avec %s)'; L10n::$locales['Shorten link using service "%s"'] = 'Raccourcir un lien en utilisant le service "%s"';
l10n::$locales['New short URL'] = 'Nouvelle URL courte'; L10n::$locales['Service:'] = 'Service :';
l10n::$locales['Url of the service:'] = 'URL du service :'; L10n::$locales['Links successfully deleted'] = 'Liens supprimés avec succès';
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['Delete selected short links'] = 'Effacer les liens court sélectionnés';
l10n::$locales['Service is unavailable.'] = 'Le service n\'est pas disponible.'; L10n::$locales['Url of the service:'] = 'URL du service :';
l10n::$locales['Service rate limit exceeded.'] = 'La limitation d\'envoie au service est atteinte.'; 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['API Key:'] = 'Clé API :'; L10n::$locales['Service is unavailable.'] = 'Le service n\'est pas disponible.';
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['Service rate limit exceeded.'] = 'La limitation d\'envoie au service est atteinte.';
l10n::$locales['Failed to call service.'] = 'Impossible d\'appeler le service.'; L10n::$locales['API Key:'] = 'Clé API :';
l10n::$locales['You can set a configurable service.'] = 'Vous pouvez configurer un service particulier.'; 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['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['Failed to call service.'] = 'Impossible d\'appeler le service.';
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['You can set a configurable service.'] = 'Vous pouvez configurer un service particulier.';
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['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['API URL:'] = 'URL de l\'API:'; 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['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['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['Short URL domain:'] = 'Domaine des URLs courtes:'; L10n::$locales['API URL:'] = 'URL de l\'API:';
l10n::$locales['Common part of the short URL. ex: "http://is.gd/"'] = 'Partie commune aux URLs courtes. ex: "http://is.gd/"'; 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['API URL param:'] = 'Paramètre de l\'URL'; L10n::$locales['Short URL domain:'] = 'Domaine des URLs courtes:';
l10n::$locales['Param of the query. ex: "longurl"'] = 'Paramètre de la raquête. ex: "longurl"'; L10n::$locales['Common part of the short URL. ex: "http://is.gd/"'] = 'Partie commune aux URLs courtes. ex: "http://is.gd/"';
l10n::$locales['Encode URL'] = 'Encoder l\'URL à raccourcir'; L10n::$locales['API URL param:'] = 'Paramètre de l\'URL';
l10n::$locales['This service is set to:'] = 'Ce service est règlé comme suit:'; L10n::$locales['Param of the query. ex: "longurl"'] = 'Paramètre de la raquête. ex: "longurl"';
l10n::$locales['Full API URL:'] = 'URL complet vers l\'API:'; L10n::$locales['Encode URL'] = 'Encoder l\'URL à raccourcir';
l10n::$locales['Query param:'] = 'Paramètre de la requête:'; L10n::$locales['There is nothing to configure for this service.'] = 'Il n\'y a rien à configurer pour ce service.';
l10n::$locales['Encode URL:'] = 'Encodage des URLs à raccourcir:'; L10n::$locales['Full API URL:'] = 'URL complet vers l\'API:';
l10n::$locales['Settings:'] = 'Paramètres :'; L10n::$locales['Query param:'] = 'Paramètre de la requête:';
l10n::$locales['Allowed protocols:'] = 'Protocoles autorisés :'; L10n::$locales['Encode URL:'] = 'Encodage des URLs à raccourcir:';
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['Settings:'] = 'Paramètres :';
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['Allowed protocols:'] = 'Protocoles autorisés :';
l10n::$locales['CSS:'] = 'CSS :'; 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['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 public page for visitors to shorten links'] = 'Activer la page publique pour que les visiteurs puissent réduire des liens';
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['CSS:'] = 'CSS :';
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['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['Note:'] = 'Note :'; 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['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['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['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['Note:'] = 'Note :';
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['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['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['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 find more about this on the Dotclear\'s documentation.'] = 'Vous trouverez plus d\'information à ce sujet dans la documentation Dotclear.'; 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['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['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['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['You can find more about this on the Dotclear\'s documentation.'] = 'Vous trouverez plus d\'information à ce sujet dans la documentation Dotclear.';
l10n::$locales['Custom short link is already taken.'] = 'Le lien court personnalisé est déjà pris.'; 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['Custom short link is not valid.'] = 'Le lien court personnalisé n\'est pas valide.'; 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['Failed to save link.'] = 'Impossible d\'enregistrer le lien.'; L10n::$locales['Custom short link is already taken.'] = 'Le lien court personnalisé est déjà pris.';
l10n::$locales['Login:'] = 'Identifiant :'; L10n::$locales['Custom short link is not valid.'] = 'Le lien court personnalisé n\'est pas valide.';
l10n::$locales['This is your login to sign up to %s'] = 'C\'est votre identifiant pour vous connecter sur %s'; L10n::$locales['Failed to save link.'] = 'Impossible d\'enregistrer le lien.';
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 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 login to sign up to tr.im.'] = 'Ceci est votre login d\'inscription sur tr.im.'; L10n::$locales['Login:'] = 'Identifiant :';
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['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['Prevent service rate limit.'] = 'Prévention de la limitation d\'envoie du service.'; 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['Authentication to service failed.'] = 'Authentification au service échoué.';
l10n::$locales['Unreadable service response.'] = 'La réponse du service n\'est pas lisible.'; 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['Shorten link'] = 'Réduire un lien';
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['Top of short links'] = 'Top des liens courts';
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['Text: (Use wildcard %rank%, %hash%, %url%, %count%, %counttext%)'] = 'Texte : (Ustiliser les jokers %rank%, %hash%, %url%, %count%, %counttext%)';
l10n::$locales['There is nothing to shorten.'] = 'I n\'y a rien à réduire.'; L10n::$locales['URL length (if truncate)'] = 'Longueur de l\'URL (si tronqué)';
l10n::$locales['This service does not allowed custom hash.'] = 'Ce service n\'accepte pas les liens court personnalisés.'; L10n::$locales['All'] = 'Tous';
l10n::$locales['This link is not a valid URL.'] = 'Ce lien n\'est pas valide.'; L10n::$locales['Mini URL'] = 'Mini URL';
l10n::$locales['This custom short url is already taken.'] = 'Ce lien court personnalisé est déjà pris.'; L10n::$locales['Custom URL'] = 'URL personnalisé';
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['Semi-custom'] = 'Semi-personnalisé';
l10n::$locales['Service:'] = 'Service :'; 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['Links successfully deleted'] = 'Liens supprimés avec succès'; L10n::$locales['Sort by:'] = 'Trier par :';
l10n::$locales['New link'] = 'Nouveau lien'; L10n::$locales['Rank'] = 'Rang';
l10n::$locales['You must set an admin service.'] = 'Vous devez définir un service admin.'; L10n::$locales['Limit:'] = 'Limite :';
l10n::$locales['Shorten link using service "%s"'] = 'Raccourcir un lien en utilisant le service "%s"'; L10n::$locales['Hide no followed links'] = 'Cacher les liens non suivis';
l10n::$locales['Only if you want a custom short link.'] = 'Uniquement si vous souhaitez un lien court personnalisé.'; 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['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['%s (Shorten with %s)'] = '%s (réduit avec %s)';
l10n::$locales['Delete selected short links'] = 'Effacer les liens court sélectionnés'; L10n::$locales['List of links (%s)'] = 'Listes des liens (%s)';
l10n::$locales['Configuration successfully saved'] = 'Configuration sauvegardée avec succès'; L10n::$locales['This service is set to:'] = 'Ce service est règlé comme suit:';
l10n::$locales['Plugin activation'] = 'Activation'; L10n::$locales['This is your login to sign up to %s'] = 'C\'est votre identifiant pour vous connecter sur %s';
l10n::$locales['URL not found'] = 'Lien non trouvé'; 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['The URL you are looking for does not exist.'] = 'Le liens que vous recherchez n\'existe pas.'; L10n::$locales['This is your login to sign up to tr.im.'] = 'Ceci est votre login d\'inscription sur tr.im.';
l10n::$locales['Create your own short URL'] = 'Créer votre propre lien court'; 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['Publish history'] = 'Publier l\'historique'; L10n::$locales['Prevent service rate limit.'] = 'Prévention de la limitation d\'envoie du service.';
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['Configuration successfully saved'] = 'Configuration sauvegardée avec succès';
l10n::$locales['Use, create and serve short url on your blog'] = 'Utiliser, créer et servir des liens court sur votre blog'; 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 "" msgid ""
msgstr "" msgstr ""
"Content-Type: text/plain; charset=UTF-8\n" "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" "POT-Creation-Date: \n"
"PO-Revision-Date: 2022-11-20T16:20:38+00:00\n" "PO-Revision-Date: 2023-08-21T14:43:14+00:00\n"
"Last-Translator: Jean-Crhistian Denis\n" "Last-Translator: Jean-Christain Denis\n"
"Language-Team: \n" "Language-Team: \n"
"MIME-Version: 1.0\n" "MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
@ -13,18 +13,36 @@ msgstr ""
msgid "Links shortener" msgid "Links shortener"
msgstr "Réducteur de liens" msgstr "Réducteur de liens"
msgid "Short link" msgid "Long link:"
msgstr "Lien court" msgstr "Lien long :"
msgid "Long link" msgid "Shorten"
msgstr "Lien long" msgstr "Raccourir"
msgid "Service" msgid "URL not found"
msgstr "Service" 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" msgid "Hash"
msgstr "Hash" msgstr "Hash"
msgid "Service"
msgstr "Service"
msgid "links per page" msgid "links per page"
msgstr "liens par page" msgstr "liens par page"
@ -46,15 +64,36 @@ msgstr "suivi %s fois"
msgid "Delete short link" msgid "Delete short link"
msgstr "Effacer un lien court" msgstr "Effacer un lien court"
msgid "Short link"
msgstr "Lien court"
msgid "No enough right" msgid "No enough right"
msgstr "Privilèges insuffisants" msgstr "Privilèges insuffisants"
msgid "Posts short links have been created." msgid "Posts short links have been created."
msgstr "Les liens courts des billets ont été créé." msgstr "Les liens courts des billets ont été créé."
msgid "Long link"
msgstr "Lien long"
msgid "Disabled" msgid "Disabled"
msgstr "Désactiver" 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" msgid "Enable plugin"
msgstr "Activer le 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." 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." msgstr "Liste des services que vous pouvez utiliser pour réduire des liens à l'aide du plugin kUtRL."
msgid "Failed to test %s API." msgid "New public short URL"
msgstr "Impossible de tester l'API %s." msgstr "Nouvelle URL courte"
msgid "%s API is well configured and runing." msgid "Confirm by writing \"%s\" in next field:"
msgstr "L'API %s est correctement configurée et est fonctionnelle." msgstr "Confirmez en écrivant \"%s\" dans le champs suivant :"
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 "Failed to verify protected field." msgid "Failed to verify protected field."
msgstr "Impossible de vérifier le champs de protection." 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." msgid "Failed to create short link."
msgstr "Impossible de créer le lien court." 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" msgid "No short link matches the filter"
msgstr "Aucun lien correspondant au filtre" msgstr "Aucun lien correspondant au filtre"
@ -235,18 +202,51 @@ msgstr "Pas de lien court"
msgid "List of %s links matching the filter." msgid "List of %s links matching the filter."
msgstr "Liste des %s liens correspondant au filtre." msgstr "Liste des %s liens correspondant au filtre."
msgid "List of links (%s)" msgid "List of links. (%s)"
msgstr "Listes des liens (%s)" msgstr "Liste des liens. (%s)"
msgid "There is nothing to configure for this service." msgid "There is nothing to shorten."
msgstr "Il n'y a rien à configurer pour ce service." msgstr "Il n'y a rien à réduire."
msgid "%s (Shorten with %s)" msgid "This service does not allowed custom hash."
msgstr "%s (réduit avec %s)" 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" msgid "New short URL"
msgstr "Nouvelle URL courte" 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:" msgid "Url of the service:"
msgstr "URL du service :" msgstr "URL du service :"
@ -301,8 +301,8 @@ msgstr "Paramètre de la raquête. ex: \"longurl\""
msgid "Encode URL" msgid "Encode URL"
msgstr "Encoder l'URL à raccourcir" msgstr "Encoder l'URL à raccourcir"
msgid "This service is set to:" msgid "There is nothing to configure for this service."
msgstr "Ce service est règlé comme suit:" msgstr "Il n'y a rien à configurer pour ce service."
msgid "Full API URL:" msgid "Full API URL:"
msgstr "URL complet vers l'API:" msgstr "URL complet vers l'API:"
@ -370,9 +370,75 @@ msgstr "Le lien court personnalisé n'est pas valide."
msgid "Failed to save link." msgid "Failed to save link."
msgstr "Impossible d'enregistrer le lien." 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:" msgid "Login:"
msgstr "Identifiant :" 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" msgid "This is your login to sign up to %s"
msgstr "C'est votre identifiant pour vous connecter sur %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." msgid "Prevent service rate limit."
msgstr "Prévention de la limitation d'envoie du service." 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" msgid "Configuration successfully saved"
msgstr "Configuration sauvegardée avec succès" 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" msgid "Publish history"
msgstr "Publier l'historique" msgstr "Publier l'historique"

View File

@ -10,371 +10,59 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return null;
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use Dotclear\Core\Process;
/**
* Backend prepend.
*/
class Backend extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::BACKEND));
} }
dcCore::app()->blog->settings->addNamespace(basename(__DIR__)); public static function process(): bool
{
if (!self::status()) {
return false;
}
require_once __DIR__ . '/_widgets.php'; // sidebar menu
My::addBackendMenuItem();
# 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 # Admin behaviors
if (dcCore::app()->blog->settings->get(basename(__DIR__))->get('active')) { if (My::settings()->get('active')) {
dcCore::app()->addBehavior('adminDashboardFavoritesV2', ['adminKutrl', 'antispamDashboardFavoritesV2']); dcCore::app()->addBehaviors([
dcCore::app()->addBehavior('adminColumnsListsV2', ['adminKutrl', 'adminColumnsListsV2']); 'adminDashboardFavoritesV2' => [BackendBehaviors::class, 'antispamDashboardFavoritesV2'],
dcCore::app()->addBehavior('adminFiltersListsV2', ['adminKutrl', 'adminFiltersListsV2']); 'adminColumnsListsV2' => [BackendBehaviors::class, 'adminColumnsListsV2'],
dcCore::app()->addBehavior('adminPostHeaders', ['adminKutrl', 'adminPostHeaders']); 'adminFiltersListsV2' => [BackendBehaviors::class, 'adminFiltersListsV2'],
dcCore::app()->addBehavior('adminPostFormItems', ['adminKutrl', 'adminPostFormItems']); 'adminPostHeaders' => [BackendBehaviors::class, 'adminPostHeaders'],
dcCore::app()->addBehavior('adminAfterPostUpdate', ['adminKutrl', 'adminAfterPostUpdate']); // update existing short url 'adminPostFormItems' => [BackendBehaviors::class, 'adminPostFormItems'],
dcCore::app()->addBehavior('adminAfterPostUpdate', ['adminKutrl', 'adminAfterPostCreate']); // create new short url 'adminAfterPostUpdate' => [BackendBehaviors::class, 'adminAfterPostUpdate'], // update existing short url
dcCore::app()->addBehavior('adminAfterPostCreate', ['adminKutrl', 'adminAfterPostCreate']); 'adminAfterPostUpdate' => [BackendBehaviors::class, 'adminAfterPostCreate'], // create new short url
dcCore::app()->addBehavior('adminBeforePostDelete', ['adminKutrl', 'adminBeforePostDelete']); 'adminAfterPostCreate' => [BackendBehaviors::class, 'adminAfterPostCreate'],
dcCore::app()->addBehavior('adminPostsActions', ['adminKutrl', 'adminPostsActions']); 'adminBeforePostDelete' => [BackendBehaviors::class, 'adminBeforePostDelete'],
'adminPostsActions' => [BackendBehaviors::class, 'adminPostsActions'],
]);
} }
dcCore::app()->addBehavior('exportFullV2', ['backupKutrl', 'exportFullV2']); dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initShorten']);
dcCore::app()->addBehavior('exportSingleV2', ['backupKutrl', 'exportSingleV2']); dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initRank']);
dcCore::app()->addBehavior('importInitV2', ['backupKutrl', 'importInitV2']);
dcCore::app()->addBehavior('importSingleV2', ['backupKutrl', 'importSingleV2']);
dcCore::app()->addBehavior('importFullV2', ['backupKutrl', 'importFullV2']);
# Admin behaviors class dcCore::app()->addBehaviors([
class adminKutrl 'exportFullV2' => [ImportExportBehaviors::class, 'exportFullV2'],
{ 'exportSingleV2' => [ImportExportBehaviors::class, 'exportSingleV2'],
public static function sortbyCombo() 'importInitV2' => [ImportExportBehaviors::class, 'importInitV2'],
{ 'importSingleV2' => [ImportExportBehaviors::class, 'importSingleV2'],
return [ 'importFullV2' => [ImportExportBehaviors::class, 'importFullV2'],
__('Date') => 'kut_dt', ]);
__('Short link') => 'kut_hash',
__('Long link') => 'kut_url',
__('Service') => 'kut_service',
];
}
public static function antispamDashboardFavoritesV2(dcFavorites $favs) return true;
{
$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 ($post) {
$post_url = $post->getURL();
$rs = $kut->isKnowUrl($post_url);
} else {
$post_url = '';
$rs = false;
}
$ret = '<div id="kUtRL"><h5>' . __('Short link') . '</h5>' .
form::hidden(['kutrl_old_post_url'], $post_url);
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>';
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();
}
} }
} }

326
src/BackendBehaviors.php Normal file
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 Normal file
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,27 +10,48 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
namespace Dotclear\Plugin\kUtRL;
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;
/**
* Backend module configuration.
*/
class Config extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::CONFIG));
} }
# Check user perms public static function process(): bool
dcPage::check(dcCore::app()->auth->makePermissions([dcAuth::PERMISSION_ADMIN])); {
if (!self::status()) {
return false;
}
// no action
if (empty($_POST['save'])) {
return true;
}
# Settings # Settings
$s = dcCore::app()->blog->settings->get(basename(__DIR__)); $s = My::settings();
# Default values
$img_green = '<img src="images/check-on.png" alt="ok" />';
$img_red = '<img src="images/check-off.png" alt="fail" />';
$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_active = (bool) $s->get('active');
$s_plugin_service = (string) $s->get('plugin_service'); $s_plugin_service = (string) $s->get('plugin_service');
@ -66,111 +87,76 @@ if (!empty($_POST['save'])) {
$s->put('admin_entry_default', $s_admin_entry_default); $s->put('admin_entry_default', $s_admin_entry_default);
# services # services
foreach (kUtRL::getServices() as $service_id => $service) { foreach (Utils::getServices() as $service_id => $service) {
$o = new $service(); $o = new $service();
$o->saveSettings(); $o->saveSettings();
} }
dcCore::app()->blog->triggerBlog(); dcCore::app()->blog->triggerBlog();
dcAdminNotices::addSuccessNotice( Notices::addSuccessNotice(
__('Configuration successfully updated.') __('Configuration successfully updated.')
); );
dcCore::app()->adminurl->redirect( dcCore::app()->admin->url->redirect(
'admin.plugins', 'admin.plugins',
['module' => basename(__DIR__), 'conf' => 1, 'chk' => 1, 'redir' => dcCore::app()->admin->list->getRedir()] ['module' => My::id(), 'conf' => 1, 'chk' => 1, 'redir' => dcCore::app()->admin->list->getRedir()]
); );
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
} }
} }
echo ' return true;
<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>
<hr/><div id="setting-option"> public static function render(): void
<h5>' . __('Behaviors') . '</h5> {
<p><label class="classic">' . if (!self::status()) {
form::checkbox(['s_allow_external_url'], '1', $s_allow_external_url) . return;
__('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>
<hr/><div id="setting-service"> # Default values
<h5>' . __('Default services') . '</h5> $img_green = '<img src="images/check-on.png" alt="ok" />';
<p><label>'; $img_red = '<img src="images/check-off.png" alt="fail" />';
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>
<div class="fieldset"> # Settings
<h4>' . __('Services') . '</h4> $s = My::settings();
<p class="info">' . __('List of services you can use to shorten links with pkugin kUtRL.') . '</p>
';
foreach (kUtRL::getServices() as $service_id => $service) { $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(); $o = new $service();
echo '<hr/><div id="setting-' . $service_id . '"><h5>' . $o->name . '</h5>'; $s_items = [];
if (!empty($_REQUEST['chk'])) { if (!empty($_REQUEST['chk'])) {
$img_chk = $img_red . ' ' . sprintf(__('Failed to test %s API.'), $o->name); $img_chk = $img_red . ' ' . sprintf(__('Failed to test %s API.'), $o->name);
@ -182,14 +168,162 @@ foreach (kUtRL::getServices() as $service_id => $service) {
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add(sprintf(__('Failed to test service %s: %s'), $o->name, $e->getMessage())); 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(); $s_items[] = (new Text(null, sprintf('<p><em>%s</em></p>', $img_chk) . $o->error->toHTML()));
} }
if ($o->home != '') { if ($o->home != '') {
echo '<p><a title="' . __('homepage') . '" href="' . $o->home . '">' . sprintf(__('Learn more about %s.'), $o->name) . '</a></p>'; $s_items[] = (new Para())
} ->items([
$o->settingsForm(); (new Link())
->href($o->home)
echo '</div>'; ->title(__('homepage'))
->text(sprintf(__('Learn more about %s.'), $o->name)),
]);
} }
echo'</div>'; $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();
}
}

View File

@ -10,567 +10,66 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return null;
}
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']); use Dotclear\Core\Process;
dcCore::app()->addBehavior('publicHeadContent', ['pubKutrl', 'publicHeadContent']);
dcCore::app()->addBehavior('publicBeforeContentFilterV2', ['pubKutrl', 'publicBeforeContentFilterV2']);
dcCore::app()->addBehavior('templateBeforeValueV2', ['pubKutrl', 'templateBeforeValueV2']);
dcCore::app()->addBehavior('templateAfterValueV2', ['pubKutrl', 'templateAfterValueV2']);
dcCore::app()->tpl->addBlock('kutrlPageIf', ['tplKutrl', 'pageIf']); /**
dcCore::app()->tpl->addBlock('kutrlMsgIf', ['tplKutrl', 'pageMsgIf']); * Frontend prepend.
*/
dcCore::app()->tpl->addValue('kutrlPageURL', ['tplKutrl', 'pageURL']); class Frontend extends Process
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
{ {
# Redirect !!! local !!! service only public static function init(): bool
public static function redirectUrl($args)
{ {
# Not active, go to default 404 return self::status(My::checkContext(My::FRONTEND));
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] ?? ''; public static function process(): bool
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;
}
private static function pageKutrl($kut)
{ {
$s = dcCore::app()->blog->settings->get(basename(__DIR__)); if (!self::status()) {
return false;
# 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) { dcCore::app()->tpl->setPath(
if (!$kut->allow_external_url && !$kut->isBlogUrl($url)) { dcCore::app()->tpl->getPath(),
$err = true; My::path() . DIRECTORY_SEPARATOR . 'default-templates'
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>'
); );
} dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initShorten']);
} dcCore::app()->addBehavior('initWidgets', [Widgets::class, 'initRank']);
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( dcCore::app()->addBehaviors([
__('Short link for %s is %s'), 'publicBeforeDocumentV2' => [FrontendBehaviors::class, 'publicBeforeDocumentV2'],
html::escapeHTML($url), 'publicHeadContent' => [FrontendBehaviors::class, 'publicHeadContent'],
'<a href="' . $new_url . '">' . $new_url . '</a>' 'publicBeforeContentFilterV2' => [FrontendBehaviors::class, 'publicBeforeContentFilterV2'],
); 'templateBeforeValueV2' => [FrontendBehaviors::class, 'templateBeforeValueV2'],
dcCore::app()->blog->triggerBlog(); 'templateAfterValueV2' => [FrontendBehaviors::class, 'templateAfterValueV2'],
]);
# ex: Send new url to messengers dcCore::app()->tpl->addBlock('kutrlPageIf', [FrontendTemplate::class, 'pageIf']);
if (!empty($rs)) { dcCore::app()->tpl->addBlock('kutrlMsgIf', [FrontendTemplate::class, 'pageMsgIf']);
dcCore::app()->callBehavior('publicAfterKutrlCreate', $rs, __('New public short URL'));
}
}
}
}
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/default-templates'); dcCore::app()->tpl->addValue('kutrlPageURL', [FrontendTemplate::class, 'pageURL']);
self::serveDocument('kutrl.html'); dcCore::app()->tpl->addValue('kutrlMsg', [FrontendTemplate::class, 'pageMsg']);
dcCore::app()->tpl->addValue('kutrlHumanField', [FrontendTemplate::class, 'humanField']);
dcCore::app()->tpl->addValue('kutrlHumanFieldProtect', [FrontendTemplate::class, 'humanFieldProtect']);
return null; 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']);
protected static function kutrl404() return true;
{
if (!dcCore::app()->blog->settings->get(basename(__DIR__))->get('srv_local_404_active')) {
self::p404();
return null;
}
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/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-- 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;
} }
} }

102
src/FrontendBehaviors.php Normal file
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";
}
}
}

205
src/FrontendTemplate.php Normal file
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 Normal file
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;
}
}

53
src/FrontendUtils.php Normal file
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,22 +10,36 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
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));
}
public static function process(): bool
{
if (!self::status()) {
return false;
} }
try { try {
// Compare versions
if (!dcCore::app()->newVersion(
basename(__DIR__),
dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version')
)) {
return null;
}
// Table // Table
$t = new dbStruct(dcCore::app()->con, dcCore::app()->prefix); $t = new Structure(dcCore::app()->con, dcCore::app()->prefix);
$t->{initkUtRL::KURL_TABLE_NAME} $t->{My::TABLE_NAME}
->kut_id('bigint', 0, false) ->kut_id('bigint', 0, false)
->blog_id('varchar', 32, false) ->blog_id('varchar', 32, false)
->kut_service('varchar', 32, false, "'kUtRL'") ->kut_service('varchar', 32, false, "'kUtRL'")
@ -42,11 +56,10 @@ try {
->index('idx_kut_service', 'btree', 'kut_service') ->index('idx_kut_service', 'btree', 'kut_service')
->index('idx_kut_type', 'btree', 'kut_type'); ->index('idx_kut_type', 'btree', 'kut_type');
$ti = new dbStruct(dcCore::app()->con, dcCore::app()->prefix); (new Structure(dcCore::app()->con, dcCore::app()->prefix))->synchronize($t);
$changes = $ti->synchronize($t);
// upgrade version < 2022.12.22 : upgrade settings id and ns and array // upgrade version < 2022.12.22 : upgrade settings id and ns and array
$current = dcCore::app()->getVersion(basename(__DIR__)); $current = dcCore::app()->getVersion(My::id());
if ($current && version_compare($current, '2022.12.22', '<')) { if ($current && version_compare($current, '2022.12.22', '<')) {
$record = dcCore::app()->con->select( $record = dcCore::app()->con->select(
'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' . 'SELECT * FROM ' . dcCore::app()->prefix . dcNamespace::NS_TABLE_NAME . ' ' .
@ -63,13 +76,13 @@ try {
$cur->setting_ns = basename(__DIR__); $cur->setting_ns = basename(__DIR__);
$cur->update( $cur->update(
"WHERE setting_id = '" . $record->setting_id . "' and setting_ns = 'kUtRL' " . "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) . "' ")) 'AND blog_id ' . (null === $record->blog_id ? 'IS NULL ' : ("= '" . dcCore::app()->con->escapeStr((string) $record->blog_id) . "' "))
); );
} }
} }
} else { } else {
// Settings // Settings
$s = dcCore::app()->blog->settings->addNamespace(basename(__DIR__)); $s = My::settings();
$s->put('active', false, 'boolean', 'Enabled kutrl plugin', false, true); $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('plugin_service', 'default', 'string', 'Service to use to shorten links on third part plugins', false, true);
@ -98,6 +111,8 @@ try {
return true; return true;
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
}
return false; return false;
}
}
}

View File

@ -10,45 +10,41 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
class kutrlLinkslist declare(strict_types=1);
{
protected $rs;
protected $rs_count;
protected $html_prev;
protected $html_next;
public function __construct($rs, $rs_count) namespace Dotclear\Plugin\kUtRL;
{
$this->rs = &$rs;
$this->rs_count = $rs_count;
$this->html_prev = __('&#171; prev.');
$this->html_next = __('next &#187;');
}
public function userColumns($type, $cols) use ArrayObject;
{ use dcCore;
$cols_user = @dcCore::app()->auth->user_prefs->interface->cols; use Dotclear\Core\Backend\Filter\Filters;
if (is_array($cols_user) || $cols_user instanceof ArrayObject) { use Dotclear\Core\Backend\Listing\{
if (isset($cols_user[$type])) { Listing,
foreach ($cols_user[$type] as $cn => $cd) { Pager
if (!$cd && isset($cols[$cn])) { };
unset($cols[$cn]); use Dotclear\Helper\Date;
} use Dotclear\Helper\Html\Form\{
} Checkbox,
} Div,
} Link,
} Note,
Para,
Text,
};
use Dotclear\Helper\Html\Html;
public function display($page, $nb_per_page, $enclose_block, $filter = false) class LinksListing extends Listing
{
public function display(Filters $filter, string $enclose_block): void
{ {
if ($this->rs->isEmpty()) { if ($this->rs->isEmpty()) {
if ($filter) { echo (new Note())
echo '<p><strong>' . __('No short link matches the filter') . '</strong></p>'; ->class('info')
} else { ->text($filter->show() ? __('No short link matches the filter') : __('No short link'))
echo '<p><strong>' . __('No short link') . '</strong></p>'; ->render();
return;
} }
} else {
$pager = new dcPager($page, $this->rs_count, $nb_per_page, 10);
$links = []; $links = [];
if (isset($_REQUEST['entries'])) { if (isset($_REQUEST['entries'])) {
foreach ($_REQUEST['entries'] as $v) { foreach ($_REQUEST['entries'] as $v) {
@ -56,75 +52,99 @@ class kutrlLinkslist
} }
} }
$cols = [ $pager = new Pager((int) $filter->value('page'), $this->rs_count, (int) $filter->nb, 10);
'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">' . $cols = new ArrayObject([
'<table>' . 'kut_url' => (new Text('th', __('Link')))
'<caption>' . ( ->class('first')
$filter ? ->extra('colspan="2"'),
sprintf(__('List of %s links matching the filter.'), $this->rs_count) : 'kut_hash' => (new Text('th', __('Hash')))
sprintf(__('List of links (%s)'), $this->rs_count) ->extra('scope="col"'),
) . '</caption>' . 'kut_dt' => (new Text('th', __('Date')))
'<thead>' . ->extra('scope="col"'),
'<tr>' . implode(iterator_to_array($cols)) . '</tr>' . 'kut_service' => (new Text('th', __('Service')))
'</thead>' . ->extra('scope="col"'),
'<tbody>%s</tbody>' . ]);
'</table>' .
'%s</div>';
if ($enclose_block) { $this->userColumns(My::id(), $cols);
$html_block = sprintf($enclose_block, $html_block);
}
$blocks = explode('%s', $html_block);
echo $pager->getLinks() . $blocks[0];
$lines = [];
while ($this->rs->fetch()) { while ($this->rs->fetch()) {
echo $this->linkLine(isset($links[$this->rs->kut_id])); $lines[] = $this->linkLine(isset($links[$this->rs->kut_id]));
} }
echo $blocks[1] . $blocks[2] . $pager->getLinks(); 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; $type = $this->rs->kut_type;
$hash = $this->rs->kut_hash; $hash = $this->rs->kut_hash;
if (null !== ($o = kUtRL::quickService($type))) { if (null !== ($o = Utils::quickService($type))) {
$type = '<a href="' . $o->home . '" title="' . $o->name . '">' . $o->name . '</a>'; $type = (new Link())
$hash = '<a href="' . $o->url_base . $hash . '" title="' . $o->url_base . $hash . '">' . $hash . '</a>'; ->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 = [ $cols = new ArrayObject([
'check' => '<td class="nowrap">' . 'check' => (new Para(null, 'td'))
form::checkbox(['entries[]'], $this->rs->kut_id, ['checked' => $checked]) . ->class('nowrap minimal')
'</td>', ->items([
'kut_url' => '<td class="maximal" scope="row">' . (new Checkbox(['entries[]'], $checked))
'<a href="' . $this->rs->kut_url . '">' . $this->rs->kut_url . '</a>' . ->value($this->rs->kut_id),
'</td>', ]),
'kut_hash' => '<td class="nowrap">' . 'kut_url' => (new Para(null, 'td'))
$hash . ->class('maximal')
'</td>', ->items([
'kut_dt' => '<td class="nowrap count">' . (new Link())
dt::dt2str(__('%Y-%m-%d %H:%M'), $this->rs->kut_dt, dcCore::app()->auth->getInfo('user_tz')) . ->href($o->home)
'</td>', ->title($this->rs->kut_url)
'kut_service' => '<td class="nowrap">' . ->text($this->rs->kut_url),
$type . ]),
'</td>', '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(My::id(), $cols);
$this->userColumns('kUtRL', $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 * @brief kUtRL, a plugin for Dotclear 2
* *
* This file contents class to acces local short links records
*
* @package Dotclear * @package Dotclear
* @subpackage Plugin * @subpackage Plugin
* *
@ -10,36 +12,52 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
# 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 $table;
public $blog;
public $con; public $con;
public function __construct() public function __construct()
{ {
$this->table = dcCore::app()->prefix . initkUtRL::KURL_TABLE_NAME; $this->table = dcCore::app()->prefix . My::TABLE_NAME;
$this->blog = dcCore::app()->con->escape(dcCore::app()->blog->id);
$this->con = dcCore::app()->con; $this->con = dcCore::app()->con;
} }
public function nextId() public function nextId(): int
{ {
return $this->con->select( $sql = new SelectStatement();
'SELECT MAX(kut_id) FROM ' . $this->table
)->f(0) + 1; 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); $cur = $this->con->openCursor($this->table);
$this->con->writeLock($this->table); $this->con->writeLock($this->table);
try { try {
$cur->kut_id = $this->nextId(); $cur->kut_id = $this->nextId();
$cur->blog_id = $this->blog; $cur->blog_id = dcCore::app()->blog->id;
$cur->kut_url = (string) $url; $cur->kut_url = (string) $url;
$cur->kut_hash = (string) $hash; $cur->kut_hash = (string) $hash;
$cur->kut_type = (string) $type; $cur->kut_type = (string) $type;
@ -64,45 +82,50 @@ class kutrlLog
throw $e; 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); $sql = new SelectStatement();
$sql
$req = 'SELECT kut_id as id, kut_hash as hash, kut_url as url, ' . ->columns([
'kut_type as type, kut_service as service, kut_counter as counter ' . $sql->as('kut_id', 'id'),
'FROM ' . $this->table . ' ' . $sql->as('kut_hash', 'hash'),
"WHERE blog_id = '" . $this->blog . "' " . $sql->as('kut_url', 'url'),
"AND kut_service = '" . $this->con->escape($service) . "' "; $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) { if (null !== $url) {
$req .= "AND kut_url = '" . $this->con->escape($url) . "' "; $sql->and('kut_url = ' . $sql->quote($url));
} }
if (null !== $hash) { if (null !== $hash) {
$req .= "AND kut_hash = '" . $this->con->escape($hash) . "' "; $sql->and('kut_hash = ' . $sql->quote($hash));
} }
if (null !== $type) { if (null !== $type) {
if (is_array($type)) { $sql->and('kut_type = ' . $sql->quote($type));
$req .= "AND kut_type '" . $this->con->in($type) . "' ";
} else {
$req .= "AND kut_type = '" . $this->con->escape($type) . "' ";
}
} }
$req .= 'ORDER BY kut_dt DESC ' . $this->con->limit(1); $sql
->order('kut_dt DESC')
->limit(1);
$rs = $this->con->select($req); $rs = $sql->select();
//$this->con->unlock();
return $rs->isEmpty() ? false : $rs; return $rs->isEmpty() ? false : $rs;
} }
public function clear($id) public function clear(int $id): bool
{ {
$id = (int) $id;
$cur = $this->con->openCursor($this->table); $cur = $this->con->openCursor($this->table);
$this->con->writeLock($this->table); $this->con->writeLock($this->table);
@ -112,7 +135,7 @@ class kutrlLog
$cur->kut_counter = 0; $cur->kut_counter = 0;
$cur->update( $cur->update(
"WHERE blog_id='" . $this->blog . "' " . "WHERE blog_id='" . $this->con->escapeStr(dcCore::app()->blog->id) . "' " .
"AND kut_id='" . $id . "' " "AND kut_id='" . $id . "' "
); );
$this->con->unlock(); $this->con->unlock();
@ -127,29 +150,29 @@ class kutrlLog
return false; 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( return true;
'DELETE FROM ' . $this->table . ' ' .
"WHERE blog_id='" . $this->blog . "' " .
"AND kut_id='" . $id . "' "
);
} }
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( $counter = $rs->isEmpty() ? 0 : (int) $rs->kut_counter;
'SELECT kut_counter ' .
'FROM ' . $this->table . ' ' .
"WHERE blog_id='" . $this->blog . "' " .
"AND kut_id='" . $id . "' "
);
$counter = $rs->isEmpty() ? 0 : $rs->kut_counter;
if ('get' == $do) { if ('get' == $do) {
return $counter; return $counter;
@ -161,94 +184,86 @@ class kutrlLog
return 0; return 0;
} }
$cur = $this->con->openCursor($this->table); $sql = new UpdateStatement();
$this->con->writeLock($this->table); $ret = $sql->ref($this->table)
->column('kut_counter')
$cur->kut_counter = (int) $counter; ->value($counter)
$cur->update( ->where('blog_id = ' . $sql->quote((string) dcCore::app()->blog?->id))
"WHERE blog_id='" . $this->blog . "' " . ->and('kut_id = ' . $id)
"AND kut_id='" . $id . "'" ->update();
);
$this->con->unlock();
return $counter; return $counter;
} }
public function getLogs($p, $count_only = false) public function getLogs(array $params, bool $count_only = false): MetaRecord
{ {
if ($count_only) { $sql = new SelectStatement();
$r = 'SELECT count(S.kut_id) ';
} else {
$content_req = '';
if (!empty($p['columns']) && is_array($p['columns'])) { if ($count_only) {
$content_req .= implode(', ', $p['columns']) . ', '; $sql->column($sql->count($sql->unique('S.kut_id')));
}
$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']) . "' ";
} else { } else {
$r .= "AND kut_service='kutrl' "; if (!empty($params['columns']) && is_array($params['columns'])) {
$sql->columns($params['columns']);
} }
if (isset($p['kut_type'])) { $sql->columns([
if (is_array($p['kut_type']) && !empty($p['kut_type'])) { 'S.kut_id',
$r .= 'AND kut_type ' . $this->con->in($p['kut_type']); 'S.kut_type',
} elseif ($p['kut_type'] != '') { 'S.kut_hash',
$r .= "AND kut_type = '" . $this->con->escape($p['kut_type']) . "' "; 'S.kut_url',
'S.kut_dt',
'S.kut_counter',
]);
} }
$sql->from($sql->as($this->table, 'S'));
if (!empty($params['from'])) {
$sql->from($params['from']);
} }
if (isset($p['kut_id'])) {
if (is_array($p['kut_id']) && !empty($p['kut_id'])) { $sql->where('S.blog_id = ' . $sql->quote(dcCore::app()->blog->id));
$r .= 'AND kut_id ' . $this->con->in($p['kut_id']);
} elseif ($p['kut_id'] != '') { if (isset($params['kut_service'])) {
$r .= "AND kut_id = '" . $this->con->escape($p['kut_id']) . "' "; $sql->and('kut_service = ' . $sql->quote($params['kut_service']));
} else {
$sql->and("kut_service = 'kutrl' ");
} }
if (isset($params['kut_type'])) {
$sql->and('kut_type ' . $sql->in($params['kut_type']));
} }
if (isset($p['kut_hash'])) { if (isset($params['kut_id'])) {
if (is_array($p['kut_hash']) && !empty($p['kut_hash'])) { $sql->and('kut_id ' . $sql->in($params['kut_id']));
$r .= 'AND kut_hash ' . $this->con->in($p['kut_hash']);
} elseif ($p['kut_hash'] != '') {
$r .= "AND kut_hash = '" . $this->con->escape($p['kut_hash']) . "' ";
} }
if (isset($params['kut_hash'])) {
$sql->and('kut_hash ' . $sql->in($params['kut_hash']));
} }
if (isset($p['kut_url'])) { if (isset($params['kut_url'])) {
if (is_array($p['kut_url']) && !empty($p['kut_url'])) { $sql->and('kut_url ' . $sql->in($params['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 (!empty($params['kut_year'])) {
$sql->and($sql->dateFormat('kut_dt', '%Y') . ' = ' . $sql->quote(sprintf('%04d', $params['kut_year'])));
} }
if (!empty($p['kut_year'])) { if (!empty($params['kut_month'])) {
$r .= 'AND ' . $this->con->dateFormat('kut_dt', '%Y') . ' = ' . $sql->and($sql->dateFormat('kut_dt', '%m') . ' = ' . $sql->quote(sprintf('%02d', $params['kut_month'])));
"'" . sprintf('%04d', $p['kut_year']) . "' ";
} }
if (!empty($p['kut_month'])) { if (!empty($params['kut_day'])) {
$r .= 'AND ' . $this->con->dateFormat('kut_dt', '%m') . ' = ' . $sql->and($sql->dateFormat('kut_dt', '%d') . ' = ' . $sql->quote(sprintf('%02d', $params['kut_day'])));
"'" . sprintf('%02d', $p['kut_month']) . "' ";
} }
if (!empty($p['kut_day'])) { if (!empty($params['sql'])) {
$r .= 'AND ' . $this->con->dateFormat('kut_dt', '%d') . ' = ' . $sql->sql($params['sql']);
"'" . sprintf('%02d', $p['kut_day']) . "' ";
}
if (!empty($p['sql'])) {
$r .= $p['sql'] . ' ';
} }
if (!$count_only) { if (!$count_only) {
$r .= empty($p['order']) ? if (!empty($params['order'])) {
'ORDER BY kut_dt DESC ' : $sql->order($sql->escape($params['order']));
'ORDER BY ' . $this->con->escape($p['order']) . ' '; } else {
$sql->order('kut_dt DESC');
} }
if (!$count_only && !empty($p['limit'])) {
$r .= $this->con->limit($p['limit']);
} }
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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
namespace Dotclear\Plugin\kUtRL;
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;
class Manage extends Process
{
public static function init(): bool
{
return self::status(($_REQUEST['part'] ?? 'links') === 'links' ? ManageLinks::init() : My::checkContext(My::MANAGE));
} }
# Check user perms public static function process(): bool
dcPage::check(dcCore::app()->auth->makePermissions([ {
dcAuth::PERMISSION_ADMIN, if (!self::status()) {
])); return false;
}
$header = ''; if (($_REQUEST['part'] ?? 'links') === 'links') {
$part = $_REQUEST['part'] ?? 'links'; return ManageLinks::process();
$action = $_POST['action'] ?? ''; }
# link creation $kut = Utils::quickPlace('admin');
if ($part == 'link') {
$kut = kUtRL::quickPlace('admin'); if (empty($_POST['save'])) {
return true;
}
if (!empty($_POST['save'])) {
try { try {
if (null === $kut) { if (null === $kut) {
throw new Exception('Unknow service'); 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']; $hash = empty($_POST['custom']) ? null : $_POST['custom'];
if (empty($url)) { if (empty($url)) {
@ -66,9 +93,9 @@ if ($part == 'link') {
$url = $rs->url; $url = $rs->url;
$new_url = $kut->url_base . $rs->hash; $new_url = $kut->url_base . $rs->hash;
dcAdminNotices::addSuccessNotice(sprintf( Notices::addSuccessNotice(sprintf(
__('Short link for %s is %s'), __('Short link for %s is %s'),
'<strong>' . html::escapeHTML($url) . '</strong>', '<strong>' . Html::escapeHTML($url) . '</strong>',
'<a href="' . $new_url . '">' . $new_url . '</a>' '<a href="' . $new_url . '">' . $new_url . '</a>'
)); ));
} else { } else {
@ -82,9 +109,9 @@ if ($part == 'link') {
$url = $rs->url; $url = $rs->url;
$new_url = $kut->url_base . $rs->hash; $new_url = $kut->url_base . $rs->hash;
dcAdminNotices::addSuccessNotice(sprintf( Notices::addSuccessNotice(sprintf(
__('Short link for %s is %s'), __('Short link for %s is %s'),
'<strong>' . html::escapeHTML($url) . '</strong>', '<strong>' . Html::escapeHTML($url) . '</strong>',
'<a href="' . $new_url . '">' . $new_url . '</a>' '<a href="' . $new_url . '">' . $new_url . '</a>'
)); ));
@ -97,152 +124,91 @@ if ($part == 'link') {
} catch (Exception $e) { } catch (Exception $e) {
dcCore::app()->error->add($e->getMessage()); dcCore::app()->error->add($e->getMessage());
} }
return true;
} }
# links public static function render(): void
} else { {
$services_combo = []; if (!self::status()) {
foreach (kUtRL::getServices() as $service_id => $service) { return;
$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'])) . if (($_REQUEST['part'] ?? 'links') === 'links') {
dcPage::jsModuleLoad(basename(__DIR__) . '/js/admin.js'); ManageLinks::render();
if (!empty($_POST['deletelinks'])) { return;
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(); $kut = Utils::quickPlace('admin');
dcAdminNotices::addSuccessNotice( Page::openModule(My::id());
__('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 echo
'<html><head><title>kUtRL, ' . __('Links shortener') . '</title>' . Page::breadcrumb([
$header .
'</head><body>';
# display link creation
if ($part == 'link') {
echo
dcPage::breadcrumb([
__('Plugins') => '', __('Plugins') => '',
__('Links shortener') => dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)), My::name() => My::manageUrl(),
__('New link') => '', __('New link') => '',
]) . ]) .
dcPage::notices(); Notices::getNotices();
if (!isset($kut) || null === $kut) { if (!isset($kut) || null === $kut) {
echo '<p>' . __('You must set an admin service.') . '</p>'; echo (new Para())
->text(__('You must set an admin service.'))
->render();
} else { } else {
echo ' $fields = [];
<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) { if ($kut->allow_custom_hash) {
echo $fields[] = (new Para())
'<p><label for="custom">' . __('Custom short link:') . '</label>' . ->items([
form::field('custom', 50, 32, '') . '</p>' . (new Label(__('Custom short link:'), Label::OUTSIDE_LABEL_BEFORE))
'<p class="form-note">' . __('Only if you want a custom short link.') . '</p>'; ->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') { if ($kut->admin_service == 'local') {
echo '<p class="form-note">' . $fields[] = (new Note())
__('You can use "bob!!" if you want a semi-custom link, it starts with "bob" and "!!" will be replaced by an increment value.') . ->class('form-note')
'</p>'; ->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 ' echo (new Div())
<p><input type="submit" name="save" value="' . __('Save') . '" />' . ->items([
dcCore::app()->formNonce() . (new Text('h4', sprintf(__('Shorten link using service "%s"'), $kut->name))),
form::hidden(['part'], 'link') . ' (new Form('create-link'))
</p></div> ->method('post')
</form>'; ->action(My::manageUrl())
} ->fields([
} else { (new Para())
echo ->items([
dcPage::breadcrumb([ (new Label(__('Long link:'), Label::OUTSIDE_LABEL_BEFORE))
__('Plugins') => '', ->for('str'),
__('Links shortener') => '', (new Input('str'))
]) . ->size(100)
dcPage::notices() . ->maxlenght(255)
->value(''),
'<p class="top-add"><a class="button add" href="' . ]),
dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['part' => 'link']) . ... $fields,
'">' . __('New Link') . '</a></p>'; (new Submit('save'))
->value(__('Save')),
$kUtRL_filter->display('admin.plugin.' . basename(__DIR__), form::hidden('p', basename(__DIR__)) . form::hidden('part', 'links')); ... My::hiddenFields([
'part' => 'link',
$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"> ->render();
%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 Page::helpBlock(My::id());
dcPage::helpBlock('kUtRL');
echo '</body></html>'; Page::closeModule();
}
}

163
src/ManageLinks.php Normal file
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 Normal file
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,8 +10,27 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return;
namespace Dotclear\Plugin\kUtRL;
use dcCore;
use Dotclear\Core\Process;
/**
* Module prepend.
*/
class Prepend extends Process
{
public static function init(): bool
{
return self::status(My::checkContext(My::PREPEND));
}
public static function process(): bool
{
if (!self::status()) {
return false;
} }
# Set a URL shortener for quick get request # Set a URL shortener for quick get request
@ -31,69 +50,47 @@ if (!defined('SHORTEN_SERVICE_ENCODE')) {
define('SHORTEN_SERVICE_ENCODE', false); define('SHORTEN_SERVICE_ENCODE', false);
} }
# 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',
]);
# Services # Services
Clearbricks::lib()->autoload(['defaultKutrlService' => $d . 'services/class.default.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['default', Service\ServiceDefault::class]);
dcCore::app()->addBehavior('kutrlService', function () { return ['default','defaultKutrlService']; });
if (!defined('SHORTEN_SERVICE_DISABLE_CUSTOM')) { if (!defined('SHORTEN_SERVICE_DISABLE_CUSTOM')) {
Clearbricks::lib()->autoload(['customKutrlService' => $d . 'services/class.custom.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['custom', Service\ServiceCustom::class]);
dcCore::app()->addBehavior('kutrlService', function () { return ['custom','customKutrlService']; });
} }
if (!defined('SHORTEN_SERVICE_DISABLE_LOCAL')) { if (!defined('SHORTEN_SERVICE_DISABLE_LOCAL')) {
Clearbricks::lib()->autoload(['localKutrlService' => $d . 'services/class.local.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['local', Service\ServiceLocal::class]);
dcCore::app()->addBehavior('kutrlService', function () { return ['local','localKutrlService']; });
} }
if (!defined('SHORTEN_SERVICE_DISABLE_BILBOLINKS')) { if (!defined('SHORTEN_SERVICE_DISABLE_BILBOLINKS')) {
Clearbricks::lib()->autoload(['bilbolinksKutrlService' => $d . 'services/class.bilbolinks.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['bilbolinks', Service\ServiceBilbolinks::class]);
dcCore::app()->addBehavior('kutrlService', function () { return ['bilbolinks','bilbolinksKutrlService']; });
} }
if (!defined('SHORTEN_SERVICE_DISABLE_BITLY')) { if (!defined('SHORTEN_SERVICE_DISABLE_BITLY')) {
Clearbricks::lib()->autoload(['bitlyKutrlService' => $d . 'services/class.bitly.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['bitly', Service\ServiceBitly::class]);
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')) { if (!defined('SHORTEN_SERVICE_DISABLE_ISGD')) {
Clearbricks::lib()->autoload(['isgdKutrlService' => $d . 'services/class.isgd.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['isgd', Service\ServiceIsgd::class]);
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')) { if (!defined('SHORTEN_SERVICE_DISABLE_YOURLS')) {
Clearbricks::lib()->autoload(['yourlsKutrlService' => $d . 'services/class.yourls.service.php']); dcCore::app()->addBehavior('kutrlService', fn () => ['yourls', Service\ServiceYourls::class]);
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"]; } );
//}
# Shorten url passed through wiki functions # Shorten url passed through wiki functions
Clearbricks::lib()->autoload(['kutrlWiki' => $d . 'lib.wiki.kutrl.php']); dcCore::app()->addBehaviors([
dcCore::app()->addBehavior('coreInitWikiPost', ['kutrlWiki','coreInitWiki']); 'coreInitWikiPost' => [Wiki::class, 'coreInitWiki'],
dcCore::app()->addBehavior('coreInitWikiComment', ['kutrlWiki','coreInitWiki']); 'coreInitWikiComment' => [Wiki::class, 'coreInitWiki'],
dcCore::app()->addBehavior('coreInitWikiSimpleComment', ['kutrlWiki','coreInitWiki']); 'coreInitWikiSimpleComment' => [Wiki::class,'coreInitWiki'],
]);
# Public page # Public page
dcCore::app()->url->register('kutrl', 'go', '^go(/(.*?)|)$', ['urlKutrl', 'redirectUrl']); dcCore::app()->url->register(
'kutrl',
'go',
'^go(/(.*?)|)$',
[FrontendUrl::class, 'redirectUrl']
);
# Add kUtRL events on plugin activityReport # Add kUtRL events on plugin activityReport
if (defined('ACTIVITY_REPORT_V2')) { if (defined('ACTIVITY_REPORT_V2')) {
require_once $d . 'lib.kutrl.activityreport.php'; require_once $d . 'lib.kutrl.activityreport.php';
} }
return true;
}
}

View File

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

View File

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

View File

@ -10,11 +10,21 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return null;
}
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 = [ protected $config = [
'id' => 'bitly', 'id' => 'bitly',
@ -32,28 +42,36 @@ class bitlyKutrlService extends kutrlService
'apiKey' => '', 'apiKey' => '',
]; ];
protected function init() protected function init(): void
{ {
$this->args['apiKey'] = $this->settings->get('srv_bitly_apikey'); $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']); $this->settings->put('srv_bitly_apikey', $_POST['kutrl_srv_bitly_apikey']);
} }
public function settingsForm() public function settingsForm(): Div
{ {
echo return (new Div())
'<p><label class="classic">' . __('API Key:') . '<br />' . ->items([
form::field(['kutrl_srv_bitly_apikey'], 50, 255, $this->settings->get('srv_bitly_apikey')) . (new Para())
'</label></p>' . ->items([
'<p class="form-note">' . (new Label(__('API Key:'), Label::OUTSIDE_LABEL_BEFORE))
sprintf(__('This is your personnal %s API key. You can find it on your account page.'), $this->config['name']) . ->for('kutrl_srv_bitly_apikey'),
'</p>'; (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'])) { if (empty($this->args['apiKey'])) {
$this->error->add(__('Service is not well configured.')); $this->error->add(__('Service is not well configured.'));
@ -71,7 +89,7 @@ class bitlyKutrlService extends kutrlService
return true; 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]); $args = json_encode(['domain' => 'bit.ly', 'long_url' => $url]);

View File

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

View File

@ -10,18 +10,27 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return null;
} 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 # nb: "default" ne veut pas dire service par défaut
# mais service simple et rapide configuré par des constantes # mais service simple et rapide configuré par des constantes
# cela permet de configurer ces constantes dans le fichier # cela permet de configurer ces constantes dans le fichier
# config de Dotclear pour une plateforme complète. # 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 = [ $this->config = [
'id' => 'default', 'id' => 'default',
@ -37,13 +46,17 @@ class defaultKutrlService extends kutrlService
]; ];
} }
public function settingsForm() public function settingsForm(): Div
{ {
echo return (new Div())
'<p class="form-note">' . ->items([
__('There is nothing to configure for this service.') . (new Note())
'</p>' . ->class('form-note')
'<p>' . __('This service is set to:') . '</p>' . ->text(__('There is nothing to configure for this service.')),
(new Para())
->text(__('There is nothing to configure for this service.')),
(new Text(
'',
'<dl>' . '<dl>' .
'<dt>' . __('Service name:') . '</dt>' . '<dt>' . __('Service name:') . '</dt>' .
'<dd>' . SHORTEN_SERVICE_NAME . '</dd>' . '<dd>' . SHORTEN_SERVICE_NAME . '</dd>' .
@ -55,10 +68,12 @@ class defaultKutrlService extends kutrlService
'<dd>' . SHORTEN_SERVICE_BASE . '</dd>' . '<dd>' . SHORTEN_SERVICE_BASE . '</dd>' .
'<dt>' . __('Encode URL:') . '</dt>' . '<dt>' . __('Encode URL:') . '</dt>' .
'<dd>' . (SHORTEN_SERVICE_ENCODE ? __('yes') : __('no')) . '</dd>' . '<dd>' . (SHORTEN_SERVICE_ENCODE ? __('yes') : __('no')) . '</dd>' .
'</dl>'; '</dl>'
)),
]);
} }
public function testService() public function testService(): bool
{ {
$url = $this->url_encode ? urlencode($this->url_test) : $this->url_test; $url = $this->url_encode ? urlencode($this->url_test) : $this->url_test;
$arg = [$this->url_param => urlencode($this->url_test)]; $arg = [$this->url_param => urlencode($this->url_test)];
@ -72,7 +87,7 @@ class defaultKutrlService extends kutrlService
return true; return true;
} }
public function createHash($url, $hash = null) public function createHash(string $url, ?string $hash = null)
{ {
$enc = $this->url_encode ? urlencode($url) : $url; $enc = $this->url_encode ? urlencode($url) : $url;
$arg = [$this->url_param => $url]; $arg = [$this->url_param => $url];

View File

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

View File

@ -10,11 +10,26 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return null;
}
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 = [ protected $config = [
'id' => 'local', 'id' => 'local',
@ -24,7 +39,7 @@ class localKutrlService extends kutrlService
'allow_custom_hash' => true, 'allow_custom_hash' => true,
]; ];
protected function init() protected function init(): void
{ {
$protocols = (string) $this->settings->get('srv_local_protocols'); $protocols = (string) $this->settings->get('srv_local_protocols');
$this->config['allow_protocols'] = empty($protocols) ? [] : explode(',', $protocols); $this->config['allow_protocols'] = empty($protocols) ? [] : explode(',', $protocols);
@ -33,7 +48,7 @@ class localKutrlService extends kutrlService
$this->config['url_min_len'] = strlen($this->url_base) + 2; $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_protocols', $_POST['kutrl_srv_local_protocols'], 'string');
$this->settings->put('srv_local_public', isset($_POST['kutrl_srv_local_public']), 'boolean'); $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'); $this->settings->put('srv_local_404_active', isset($_POST['kutrl_srv_local_404_active']), 'boolean');
} }
public function settingsForm() public function settingsForm(): Div
{ {
echo return (new Div())
'<div class="two-cols"><div class="col">' . ->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>' . (new Div())
'<p><label class="classic">' . ->class('col')
__('Allowed protocols:') . '<br />' . ->items([
form::field(['kutrl_srv_local_protocols'], 50, 255, $this->settings->get('srv_local_protocols')) . (new Text('b', __('Note:'))),
'</label></p>' . (new Text(
'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 />' . __('This service use your own Blog to shorten and serve URL.') . '<br />' .
sprintf(__('This means that with this service short links start with "%s".'), $this->url_base) . sprintf(__('This means that with this service short links start with "%s".'), $this->url_base)
'</p>' . )),
'<p>' . (new Text(
__("You can use Dotclear's plugin called myUrlHandlers to change short links prefix on your blog."); '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 preg_match('/index\.php/', $this->url_base) ?
'<p>' . ' ' .
__("We recommand that you use a rewrite engine in order to remove 'index.php' from your blog's URL.") . __("We recommand that you use a rewrite engine in order to remove 'index.php' from your blog's URL.") .
'<br /><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters">' . '<br /><a href="http://fr.dotclear.org/documentation/2.0/usage/blog-parameters">' .
__("You can find more about this on the Dotclear's documentation.") . __("You can find more about this on the Dotclear's documentation.") .
'</a></p>'; '</a>'
} : ''
echo )
'</p>' . )),
'<p>' . __('There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.') . '<br />' . (new Text(
__('Files are in plugin directory /default-templates, just copy them into your theme and edit them.') . '</p>' . 'p',
__('There are two templates delivered with kUtRL, if you do not use default theme, you may adapt them to yours.') . '<br />' .
'</div></div><br class="clear"/>'; __('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; $ap = $this->allow_protocols;
if (!empty($ap)) { if (!empty($ap)) {
@ -109,7 +156,7 @@ class localKutrlService extends kutrlService
return false; return false;
} }
public function createHash($url, $hash = null) public function createHash(string $url, ?string $hash = null)
{ {
# Create response object # Create response object
$rs = new ArrayObject(); $rs = new ArrayObject();
@ -215,7 +262,7 @@ class localKutrlService extends kutrlService
return implode($id); return implode($id);
} }
public function getUrl($hash) public function getUrl(string $hash)
{ {
if (false === ($rs = $this->log->select(null, $hash, null, 'local'))) { if (false === ($rs = $this->log->select(null, $hash, null, 'local'))) {
return false; return false;
@ -223,20 +270,20 @@ class localKutrlService extends kutrlService
if (!$rs->url) { //previously removed url if (!$rs->url) { //previously removed url
return false; return false;
} }
$this->log->counter($rs->id, 'up'); $this->log->counter((int) $rs->id, 'up');
return $rs->url; 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'))) { if (false === ($rs = $this->log->select($url, null, null, 'local'))) {
return false; return false;
} }
if ($delete) { if ($delete) {
$this->log->delete($rs->id); $this->log->delete((int) $rs->id);
} else { } else {
$this->log->clear($rs->id, ''); $this->log->clear((int) $rs->id);
} }
return true; return true;

View File

@ -10,11 +10,21 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_RC_PATH')) { declare(strict_types=1);
return null;
}
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 = [ protected $config = [
'id' => 'yourls', 'id' => 'yourls',
@ -29,7 +39,7 @@ class yourlsKutrlService extends kutrlService
'action' => 'shorturl', 'action' => 'shorturl',
]; ];
protected function init() protected function init(): void
{ {
$this->args['username'] = $this->settings->get('srv_yourls_username'); $this->args['username'] = $this->settings->get('srv_yourls_username');
$this->args['password'] = $this->settings->get('srv_yourls_password'); $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; $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_username', $_POST['kutrl_srv_yourls_username']);
$this->settings->put('srv_yourls_password', $_POST['kutrl_srv_yourls_password']); $this->settings->put('srv_yourls_password', $_POST['kutrl_srv_yourls_password']);
$this->settings->put('srv_yourls_base', $_POST['kutrl_srv_yourls_base']); $this->settings->put('srv_yourls_base', $_POST['kutrl_srv_yourls_base']);
} }
public function settingsForm() public function settingsForm(): Div
{ {
echo return (new Div())
'<p><label class="classic">' . ->items([
__('Url of the service:') . '<br />' . (new Para())
form::field(['kutrl_srv_yourls_base'], 50, 255, $this->settings->get('srv_yourls_base')) . ->items([
'</label></p>' . (new Label(__('Url of the service:'), Label::OUTSIDE_LABEL_BEFORE))
'<p class="form-note">' . ->for('kutrl_srv_yourls_base'),
__('This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".') . (new Input('kutrl_srv_yourls_base'))
'</p>' . ->size(50)
'<p><label class="classic">' . __('Login:') . '<br />' . ->maxlenght(255)
form::field(['kutrl_srv_yourls_username'], 50, 255, $this->settings->get('srv_yourls_username')) . ->value((string) $this->settings->get('srv_yourls_base')),
'</label></p>' . (new Note())
'<p class="form-note">' . ->class('form-note')
__('This is your user name to sign up to this YOURLS service.') . ->text(__('This is the URL of the YOURLS service you want to use. Ex: "http://www.smaller.org/api.php".')),
'</p>' . ]),
'<p><label class="classic">' . __('Password:') . '<br />' . (new Para())
form::field(['kutrl_srv_yourls_password'], 50, 255, $this->settings->get('srv_yourls_password')) . ->items([
'</label></p>' . (new Label(__('Login:'), Label::OUTSIDE_LABEL_BEFORE))
'<p class="form-note">' . ->for('kutrl_srv_yourls_username'),
__('This is your password to sign up to this YOURLS service.') . (new Input('kutrl_srv_yourls_username'))
'</p>'; ->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)) { if (empty($this->url_api)) {
$this->error->add(__('Service is not well configured.')); $this->error->add(__('Service is not well configured.'));
@ -99,7 +129,7 @@ class yourlsKutrlService extends kutrlService
return false; return false;
} }
public function createHash($url, $hash = null) public function createHash(string $url, ?string $hash = null)
{ {
$args = array_merge($this->args, ['url' => $url]); $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 Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
if (!defined('DC_CONTEXT_ADMIN')) { declare(strict_types=1);
return;
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));
} }
$this->addUserAction( public static function process(): bool
/* type */ {
'settings', if (!self::status() || !dcCore::app()->plugins->moduleExists('Uninstaller')) {
/* action */ return false;
'delete_all', }
/* ns */
basename(__DIR__),
/* description */
__('delete all settings')
);
$this->addUserAction( Uninstaller::instance()
/* type */ ->addUserAction(
'settings',
'delete_all',
My::id()
)
->addUserAction(
'tables', 'tables',
/* action */
'delete', 'delete',
/* ns */ My::TABLE_NAME,
initkUtRL::KURL_TABLE_NAME, )
/* description */ ->addUserAction(
__('delete table')
);
$this->addUserAction(
/* type */
'plugins', 'plugins',
/* action */
'delete', 'delete',
/* ns */ My::id()
basename(__DIR__), )
/* description */ ->addUserAction(
__('delete plugin files')
);
$this->addUserAction(
/* type */
'versions', 'versions',
/* action */
'delete', 'delete',
/* ns */ My::id()
basename(__DIR__), )
/* description */ ->addDirectAction(
__('delete the version number')
);
# Delete only dc version and plugin files from pluginsBeforeDelete
# Keep table
$this->addDirectAction(
/* type */
'settings', 'settings',
/* action */
'delete_all', 'delete_all',
/* ns */ My::id()
basename(__DIR__), )
/* description */ ->addDirectAction(
sprintf(__('delete all %s settings'), basename(__DIR__)) 'tables',
);
$this->addDirectAction(
/* type */
'versions',
/* action */
'delete', 'delete',
/* ns */ My::TABLE_NAME
basename(__DIR__), )
/* description */ ->addDirectAction(
sprintf(__('delete %s version number'), basename(__DIR__))
);
$this->addDirectAction(
/* type */
'plugins', 'plugins',
/* action */
'delete', 'delete',
/* ns */ My::id()
basename(__DIR__), )
/* description */ ->addDirectAction(
sprintf(__('delete %s plugin files'), basename(__DIR__)) 'versions',
); 'delete',
My::id()
)
;
return false;
}
}

View File

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

View File

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

View File

@ -2,6 +2,8 @@
/** /**
* @brief kUtRL, a plugin for Dotclear 2 * @brief kUtRL, a plugin for Dotclear 2
* *
* This file contents class to shorten url pass through wiki
*
* @package Dotclear * @package Dotclear
* @subpackage Plugin * @subpackage Plugin
* *
@ -10,40 +12,44 @@
* @copyright Jean-Christian Denis * @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html * @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/ */
# This file contents class to shorten url pass through wiki declare(strict_types=1);
if (!defined('DC_RC_PATH')) { namespace Dotclear\Plugin\kUtRL;
return null;
}
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 # Do nothing on comment preview and post preview
if (!empty($_POST['preview']) if (!empty($_POST['preview'])
|| isset(dcCore::app()->ctx) && dcCore::app()->ctx->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'))) { if (null === ($kut = Utils::quickPlace('wiki'))) {
return null; return;
} }
foreach ($kut->allow_protocols as $protocol) { foreach ($kut->allow_protocols as $protocol) {
$wiki2xhtml->registerFunction( $wiki2xhtml->registerFunction(
'url:' . $protocol, '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; return null;
} }
if (null === ($kut = kUtRL::quickPlace('wiki'))) { if (null === ($kut = Utils::quickPlace('wiki'))) {
return []; return [];
} }
# Test if long url exists # Test if long url exists
@ -64,10 +70,7 @@ class kutrlWiki
$res['content'] = $res['url']; $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; return $res;
} }