use namespace (and nearly full rewrite)

This commit is contained in:
Jean-Christian Denis 2023-04-20 14:22:43 +02:00
parent 81d9f1e944
commit 02edbcb877
Signed by: JcDenis
GPG key ID: 1B5B8C5B90B6C951
28 changed files with 2833 additions and 1683 deletions

View file

@ -17,6 +17,5 @@ if (!defined('DC_RC_PATH')) {
class initActivityReport
{
public const ACTIVITY_TABLE_NAME = 'activity';
public const SETTING_TABLE_NAME = 'activity_setting';
public const CACHE_DIR_NAME = 'activityreport';
}

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 792 B

2
icon.svg Normal file
View file

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<svg fill="#B2B2B2" width="64px" height="64px" viewBox="0 0 24 24" id="frequency" data-name="Flat Color" xmlns="http://www.w3.org/2000/svg" class="icon flat-color"><path id="primary" d="M9,17a1,1,0,0,1-.89-.55L6.38,13H3a1,1,0,0,1,0-2H7a1,1,0,0,1,.89.55L9,13.76l3.11-6.21A1.05,1.05,0,0,1,13,7a1,1,0,0,1,.89.61l2.27,5.3,1-1.46A1,1,0,0,1,18,11h3a1,1,0,0,1,0,2H18.54l-1.71,2.55a1,1,0,0,1-.92.45,1,1,0,0,1-.83-.61l-2.15-5-3,6.07A1,1,0,0,1,9,17Z"></path></svg>

After

Width:  |  Height:  |  Size: 493 B

10
js/backend.js Normal file
View file

@ -0,0 +1,10 @@
/*global $, dotclear */
'use strict';
Object.assign(dotclear.msg, dotclear.getData('activityReport'));
$(() => {
$('#form-logs').on('submit', function () {
return window.confirm(dotclear.msg.confirm_delete);
});
});

View file

@ -1,91 +0,0 @@
/* -- BEGIN LICENSE BLOCK ----------------------------------
* This file is part of activityReport, a plugin for Dotclear 2.
*
* Copyright (c) 2009-2010 JC Denis and contributors
* jcdenis@gdwd.com
*
* Licensed under the GPL version 2.0 license.
* A copy of this license is available in LICENSE file or at
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* -- END LICENSE BLOCK ------------------------------------*/
$(function(){
/* tools */
dotclear.jcTools = new jcToolsBox();
/* setting blog */
var bForm=$('#setting-blog-form');
if ($(bForm).attr('id')!=undefined){
dotclear.jcTools.formFieldsetToMenu(bForm);
$(bForm).submit(function(){dotclear.jcTools.waitMessage();return true;});
}
/* setting global */
var gForm=$('#setting-super-form');
if ($(gForm).attr('id')!=undefined){
dotclear.jcTools.formFieldsetToMenu(gForm);
$(gForm).submit(function(){dotclear.jcTools.waitMessage();return true;});
}
});
function jcToolsBox(){}
jcToolsBox.prototype={
text_wait:'Please wait',
section:'',
formFieldsetToMenu:function(form){
var This=this;
var section=$(form).children('fieldset[id='+This.section+']').attr('id');
var hidden_section=$(form).children('input[name=section]').attr('value');
var formMenu=$(form).children('p.formMenu').get(0);
if (formMenu==undefined) {
$(form).prepend($('<p></p>').addClass('formMenu'));
}
$(form).children('fieldset').each(function(){
var Fieldset=this;
$(Fieldset).hide();
var title=$(Fieldset).children('legend').text();
var menu=$('<a></a>').text(title).addClass('button').attr('tabindex','2').click(
function(){
var fieldset_visible=$(form).children('fieldset:visible');
if (fieldset_visible==undefined){
$(Fieldset).slideDown('slow');$(form).children('input[type=submit]').show();
}else{
$(fieldset_visible).fadeOut('fast',function(){$(Fieldset).fadeIn('fast');$(form).children('input[type=submit]').show();})
}
if (hidden_section==undefined){
$(form).children('input[name=section]').remove();
$(form).append($('<input type="hidden" />').attr('name','section').attr('value',$(Fieldset).attr('id')));
}
$('.message').fadeOut('slow',function(){$(this).slideUp('slow',function(){$(this).remove();})});
}
);
$(form).children('.formMenu').append(menu).append(' ');
});
if (section!=undefined){
$(form).children('fieldset[id='+section+']').show();
}else{
$(form).children('fieldset:first').show();
}
},
waitMessage:function(){
var This=this;
var content=$('div[id=content]');
if (content!=undefined){
$(content).hide();
}else{
$('input').hide();$('select').hide();
content=$('body');
}
var text=$('<p></p>').addClass('message').text(This.text_wait);
This.blinkItem(text);
var box=$('<div></div>').attr('style','margin: 60px auto auto;width:200px;').append(text);
$(content).before($(box));
},
blinkItem:function(item){
var This=this;
$(item).fadeOut('slow',function(){$(this).fadeIn('slow',function(){This.blinkItem(this);})});
}
}

108
locales/fr/main.lang.php Normal file
View file

@ -0,0 +1,108 @@
<?php
/**
* @package Dotclear
*
* @copyright Olivier Meunier & Association Dotclear
* @copyright GPL-2.0-only
*/
#
# DOT NOT MODIFY THIS FILE !
#
use Dotclear\Helper\L10n;
L10n::$locales['ActivityReport messages'] = 'Messages de l\'extension';
L10n::$locales['Actions on blog'] = 'Actions sur le blog';
L10n::$locales['Actions on posts'] = 'Actions sur les billets';
L10n::$locales['Actions on comments'] = 'Actions sur les commentaires';
L10n::$locales['Actions on categories'] = 'Actions sur les catégories';
L10n::$locales['Actions on users'] = 'Actions sur les utilisateurs';
L10n::$locales['Special messages'] = 'Messages spéciaux';
L10n::$locales['%s'] = '%s';
L10n::$locales['updating blog'] = 'Mise à jour du blog';
L10n::$locales['Blog was updated by "%s"'] = 'Blog mis à jour par "%s"';
L10n::$locales['404 error'] = 'Erreur 404';
L10n::$locales['New 404 error page at "%s"'] = 'Nouvelle erreur 404 à l\'adresse "%s"';
L10n::$locales['post creation'] = 'Création de billet';
L10n::$locales['A new post called "%s" was created by "%s" at %s'] = 'Un nouveau billet nommé "%s" a été créé par "%s" à l\'adresse "%s"';
L10n::$locales['updating post'] = 'Mise à jour de billet';
L10n::$locales['Post called "%s" has been updated by "%s" at %s'] = 'Le billet nommé "%s" a été mis à jour par "%s" à l\'adresse "%s"';
L10n::$locales['post deletion'] = 'Suppression de billet';
L10n::$locales['Post called "%s" has been deleted by "%s"'] = 'Le billet nommé "%s" a été supprimé par "%s"';
L10n::$locales['Post protection'] = 'Protection des billets';
L10n::$locales['An attempt failed on a passworded post with password "%s" at "%s"'] = 'Une tentative a échoué sur un billet protégé par mot de passe avec l\'essai "%s" à l\'adresse "%s"';
L10n::$locales['comment creation'] = 'Création de commentaire';
L10n::$locales['A new comment was created by "%s" on post "%s" at %s'] = 'Un nouveau commentaire a été créé par "%s" sur le billet "%s"';
L10n::$locales['updating comment'] = 'Mise à jour de commentaire';
L10n::$locales['Comment has been updated by "%s" at %s'] = 'Un commentaire a été mise à jour par "%s" à l\'adresse "%s"';
L10n::$locales['trackback creation'] = 'Création de trackback';
L10n::$locales['A new trackback to "%" at "%s" was created on post "%s" at %s'] = 'Un nouveau rétrolien vers "%s" a été créé sur le billet "%s" à l\'adresse "%s"';
L10n::$locales['category creation'] = 'Création de catégorie';
L10n::$locales['A new category called "%s" was created by "%s" at %s'] = 'Un nouvelle catégorie nommée "%s" a été créé par "%s" à l\'adresse "%s"';
L10n::$locales['updating category'] = 'Mise à jour de catégorie';
L10n::$locales['Category called "%s" has been updated by "%s" at %s'] = 'La catégorie nommée "%s" a été mise à jour par "%s" à l\'adresse "%s"';
L10n::$locales['user creation'] = 'Création d\'utilisateur';
L10n::$locales['A new user named "%s" was created by "%s"'] = 'Un nouvel utilisateur a été ajouté par "%s"';
L10n::$locales['updating user'] = 'Mise à jour d\'utilisateur';
L10n::$locales['User named "%s" has been updated by "%s"'] = 'L\'utilisateur "%s" a été mis à jour par "%s"';
L10n::$locales['user deletion'] = 'Suppression d\'utilisateur';
L10n::$locales['User named "%s" has been deleted by "%"'] = 'L\'utilisateur nommé "%s" a été supprimé par "%s"';
L10n::$locales['HTML'] = 'HTML';
L10n::$locales['Activity report'] = 'Rapport d\'activité';
L10n::$locales['An error occured when parsing report.'] = 'Une erreur est survenue lors de la compilation du rapport.';
L10n::$locales['You received a message from your blog\'s activity report module.'] = 'Vous recevez un message du module de rapport d\'activité de votre blog.';
L10n::$locales['Period from %s to %s'] = 'Période du %s au %s';
L10n::$locales['Activity report deletes some old logs.'] = 'L\'extension a automatiquement effacé des anciennes activités.';
L10n::$locales['Blog "%s" activity report'] = 'Rapport d\'activité du blog "%s"';
L10n::$locales['View all logs'] = 'Voir tous les logs';
L10n::$locales['Number of activities to show on dashboard:'] = 'Nombre d\'activités à afficher sur le tableau de bord :';
L10n::$locales['Do not show activity report'] = 'Ne pas afficher le rapport d\'activité';
L10n::$locales['Group'] = 'Groupe';
L10n::$locales['logs per page'] = 'enregistrements par page';
L10n::$locales['every hour'] = 'toutes les heures';
L10n::$locales['every 2 hours'] = 'toutes les 2 heures';
L10n::$locales['2 times by day'] = '2 fois par jour';
L10n::$locales['every day'] = 'tous les jours';
L10n::$locales['every 2 days'] = 'tous les 2 jours';
L10n::$locales['every week'] = 'toutes les semaines';
L10n::$locales['every 2 weeks'] = 'toutes les 2 semaines';
L10n::$locales['every 4 weeks'] = 'toutes les 4 semaines';
L10n::$locales['Report successfully sent.'] = 'Rapport envoyé avec succès.';
L10n::$locales['Logs successfully deleted.'] = 'Logs effacés avec succès.';
L10n::$locales['never'] = 'jamais';
L10n::$locales['on new activity'] = 'lors d\'une nouvelle activité';
L10n::$locales['This server has no mail function, activityReport does not send email report.'] = 'Ce server n\'a pas de fonction d\'envoie de mail, le rapport ne sera pas envoyer.';
L10n::$locales['Mail report'] = 'Rapport par email';
L10n::$locales['Send report:'] = 'Rapport envoyé :';
L10n::$locales['Recipients:'] = 'Destinataires :';
L10n::$locales['Separate multiple email addresses with a semicolon ";"'] = 'Séparer les adresses email par un point-virgule ";"';
L10n::$locales['Leave it empty to disable mail report.'] = 'Laisser vide pour désactiver le rapport par email.';
L10n::$locales['Use Dotclear date formaters. ex: %B %d at %H:%M'] = 'Utiliser le formatage des dates de Dotclear. ex: %d %B à %H:%M';
L10n::$locales['Report format:'] = 'Format du rapport :';
L10n::$locales['Last report by email:'] = 'Dernier rapport par email :';
L10n::$locales['Next report by email:'] = 'Prochain rapport par email :';
L10n::$locales['Feeds'] = 'Flux';
L10n::$locales['Enable activity feed'] = 'Activer le flux d\'activités';
L10n::$locales['RSS feed'] = 'Flux RSS';
L10n::$locales['Rss2 activities feed'] = 'Flux RSS2 d\'activités';
L10n::$locales['Atom feed'] = 'Flux Atom';
L10n::$locales['Atom activities feed'] = 'Flux Atom d\'activités';
L10n::$locales['Activities'] = 'Activités';
L10n::$locales['Select actions by activity type to add to report'] = 'Sélectionner les actions par type d\'activité à ajouter au rapport';
L10n::$locales['Automatic cleaning of old logs:'] = 'Nettoyage automatique des anciennes activités:';
L10n::$locales['Send report now'] = 'Envoyer un rapport maintenant';
L10n::$locales['Delete all logs now'] = 'Effacer tous les logs maintenant';
L10n::$locales['Plain text'] = 'Texte brut';
L10n::$locales['Logs successfully deleted'] = 'Enregistrements effacés avec succès';
L10n::$locales['Are you sure you want to delete logs?'] = 'Êtes-vous sure de vouloir effacer les enregistrements ?';
L10n::$locales['Delete all aticivity logs'] = 'Effacer tous les enregistrements d\'activités';
L10n::$locales['Delete all allready reported logs'] = 'Effacer les enregistrements d\'activités déjà envoyé par email';
L10n::$locales['No log matches the filter'] = 'Aucun enregistrement ne correspond au filtre';
L10n::$locales['No log'] = 'Pas d\'enregistrement';
L10n::$locales['List of %s logs matching the filter.'] = 'Liste des %s logs correspondants au filtre.';
L10n::$locales['List of %s logs.'] = 'Listes des %s enregistrements';
L10n::$locales['Message'] = 'Message';
L10n::$locales['undefined'] = 'inconnu';
L10n::$locales['reported'] = 'envoyé';
L10n::$locales['Activity log'] = 'Journal d\'activité';
L10n::$locales['Log and receive your blog activity by email, feed, or on dashboard'] = 'Enregistrer et recevoir l\'activité de votre blog par mail, flux ou sur le tableau de bord';

View file

@ -1,270 +1,398 @@
# Language: Français
# Module: activityReport - 3.0
# Date: 2023-04-20 12:20:14
# Author: , contact@jcdenis.fr
# Translated with translater 2023.03.19
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Project-Id-Version: activityReport 2.0\n"
"Project-Id-Version: activityReport 3.0\n"
"POT-Creation-Date: \n"
"PO-Revision-Date: 2022-11-27T21:29:52+00:00\n"
"Last-Translator: Jean-Crhistian Denis\n"
"PO-Revision-Date: 2023-04-20T12:20:14+00:00\n"
"Last-Translator: Jean-Christian Denis\n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
msgid "Activity report"
msgstr "Rapport d'activité"
msgid "View all logs"
msgstr "Voir tous les logs"
msgid "Number of activities to show on dashboard:"
msgstr "Nombre d'activités à afficher sur le tableau de bord :"
msgid "Do not show activity report"
msgstr "Ne pas afficher le rapport d'activité"
msgid "every hour"
msgstr "toutes les heures"
msgid "every 2 hours"
msgstr "toutes les 2 heures"
msgid "2 times by day"
msgstr "2 fois par jour"
msgid "every day"
msgstr "tous les jours"
msgid "every 2 days"
msgstr "tous les 2 jours"
msgid "every week"
msgstr "toutes les semaines"
msgid "every 2 weeks"
msgstr "toutes les 2 semaines"
msgid "every 4 weeks"
msgstr "toutes les 4 semaines"
msgid "Plain text"
msgstr "Texte brut"
msgid "HTML"
msgstr "HTML"
msgid "Report successfully sent."
msgstr "Rapport envoyé avec succès."
msgid "Logs successfully deleted."
msgstr "Logs effacés avec succès."
msgid "never"
msgstr "jamais"
msgid "on new activity"
msgstr "lors d'une nouvelle activité"
msgid "Configure activity report for %s"
msgstr "Configurer le rapport d'activité pour %s"
msgid "current blog"
msgstr "le blog courant"
msgid "all blogs"
msgstr "tous les blogs"
msgid "This server has no mail function, activityReport does not send email report."
msgstr "Ce server n'a pas de fonction d'envoie de mail, le rapport ne sera pas envoyer."
msgid "Enable super administrator report"
msgstr "Autoriser le rapport de super administrateur"
msgid "Enable report on this blog"
msgstr "Autoriser le rapport sur ce blog"
msgid "Automatic cleaning of old logs:"
msgstr "Nettoyage automatique des anciennes activités:"
msgid "Use Dotclear date formaters. ex: %B %d at %H:%M"
msgstr "Utiliser le formatage des dates de Dotclear. ex: %d %B à %H:%M"
msgid "RSS feed"
msgstr "Flux RSS"
msgid "Rss2 feed for activity on this blog"
msgstr "Flux Rss2 pour l'activité de ce blog"
msgid "Atom feed"
msgstr "Flux Atom"
msgid "Atom feed for activity on this blog"
msgstr "Flux Atom pour l'activité de ce blog"
msgid "Send report:"
msgstr "Rapport envoyé :"
msgid "Recipients:"
msgstr "Destinataires :"
msgid "Separate multiple email addresses with a semicolon \";\""
msgstr "Séparer les adresses email par un point-virgule \";\""
msgid "Report format:"
msgstr "Format du rapport :"
msgid "Last report by email:"
msgstr "Dernier rapport par email :"
msgid "Next report by email:"
msgstr "Prochain rapport par email :"
msgid "Select blogs to add to report"
msgstr "Sélectionner les blogs à ajouter au rapport"
msgid "Report"
msgstr "Rapport"
msgid "Select actions by activity type to add to report"
msgstr "Sélectionner les actions par type d'activité à ajouter au rapport"
msgid "Send report now"
msgstr "Envoyer un rapport maintenant"
msgid "Delete all logs now"
msgstr "Effacer tous les logs maintenant"
#: src/ActivityBehaviors.php:32
msgid "ActivityReport messages"
msgstr "Messages de l'extension"
msgid "Special messages"
msgstr "Messages spéciaux"
msgid "%s"
msgstr "%s"
#: src/ActivityBehaviors.php:33
msgid "Actions on blog"
msgstr "Actions sur le blog"
msgid "updating blog"
msgstr "Mise à jour du blog"
msgid "Blog was updated by \"%s\""
msgstr "Blog mis à jour par \"%s\""
msgid "404 error"
msgstr "Erreur 404"
msgid "New 404 error page at \"%s\""
msgstr "Nouvelle erreur 404 à l'adresse \"%s\""
#: src/ActivityBehaviors.php:34
msgid "Actions on posts"
msgstr "Actions sur les billets"
msgid "post creation"
msgstr "Création de billet"
msgid "A new post called \"%s\" was created by \"%s\" at %s"
msgstr "Un nouveau billet nommé \"%s\" a été créé par \"%s\" à l'adresse \"%s\""
msgid "updating post"
msgstr "Mise à jour de billet"
msgid "Post called \"%s\" has been updated by \"%s\" at %s"
msgstr "Le billet nommé \"%s\" a été mis à jour par \"%s\" à l'adresse \"%s\""
msgid "post deletion"
msgstr "Suppression de billet"
msgid "Post called \"%s\" has been deleted by \"%s\""
msgstr "Le billet nommé \"%s\" a été supprimé par \"%s\""
msgid "Post protection"
msgstr "Protection des billets"
msgid "An attempt failed on a passworded post with password \"%s\" at \"%s\""
msgstr "Une tentative a échoué sur un billet protégé par mot de passe avec l'essai \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:35
msgid "Actions on comments"
msgstr "Actions sur les commentaires"
msgid "comment creation"
msgstr "Création de commentaire"
msgid "A new comment was created by \"%s\" on post \"%s\" at %s"
msgstr "Un nouveau commentaire a été créé par \"%s\" sur le billet \"%s\""
msgid "updating comment"
msgstr "Mise à jour de commentaire"
msgid "Comment has been updated by \"%s\" at %s"
msgstr "Un commentaire a été mise à jour par \"%s\" à l'adresse \"%s\""
msgid "trackback creation"
msgstr "Création de trackback"
msgid "A new trackback to \"%\" at \"%s\" was created on post \"%s\" at %s"
msgstr "Un nouveau rétrolien vers \"%s\" a été créé sur le billet \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:36
msgid "Actions on categories"
msgstr "Actions sur les catégories"
msgid "category creation"
msgstr "Création de catégorie"
msgid "A new category called \"%s\" was created by \"%s\" at %s"
msgstr "Un nouvelle catégorie nommée \"%s\" a été créé par \"%s\" à l'adresse \"%s\""
msgid "updating category"
msgstr "Mise à jour de catégorie"
msgid "Category called \"%s\" has been updated by \"%s\" at %s"
msgstr "La catégorie nommée \"%s\" a été mise à jour par \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:37
msgid "Actions on users"
msgstr "Actions sur les utilisateurs"
#: src/ActivityBehaviors.php:43
msgid "Special messages"
msgstr "Messages spéciaux"
#: src/ActivityBehaviors.php:44
msgid "%s"
msgstr "%s"
#: src/ActivityBehaviors.php:54
msgid "updating blog"
msgstr "Mise à jour du blog"
#: src/ActivityBehaviors.php:55
msgid "Blog was updated by \"%s\""
msgstr "Blog mis à jour par \"%s\""
#: src/ActivityBehaviors.php:63
msgid "404 error"
msgstr "Erreur 404"
#: src/ActivityBehaviors.php:64
msgid "New 404 error page at \"%s\""
msgstr "Nouvelle erreur 404 à l'adresse \"%s\""
#: src/ActivityBehaviors.php:74
msgid "post creation"
msgstr "Création de billet"
#: src/ActivityBehaviors.php:75
msgid "A new post called \"%s\" was created by \"%s\" at %s"
msgstr "Un nouveau billet nommé \"%s\" a été créé par \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:94
msgid "updating post"
msgstr "Mise à jour de billet"
#: src/ActivityBehaviors.php:95
msgid "Post called \"%s\" has been updated by \"%s\" at %s"
msgstr "Le billet nommé \"%s\" a été mis à jour par \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:103
msgid "post deletion"
msgstr "Suppression de billet"
#: src/ActivityBehaviors.php:104
msgid "Post called \"%s\" has been deleted by \"%s\""
msgstr "Le billet nommé \"%s\" a été supprimé par \"%s\""
#: src/ActivityBehaviors.php:113
msgid "Post protection"
msgstr "Protection des billets"
#: src/ActivityBehaviors.php:114
msgid "An attempt failed on a passworded post with password \"%s\" at \"%s\""
msgstr "Une tentative a échoué sur un billet protégé par mot de passe avec l'essai \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:124
msgid "comment creation"
msgstr "Création de commentaire"
#: src/ActivityBehaviors.php:125
msgid "A new comment was created by \"%s\" on post \"%s\" at %s"
msgstr "Un nouveau commentaire a été créé par \"%s\" sur le billet \"%s\""
#: src/ActivityBehaviors.php:134
msgid "updating comment"
msgstr "Mise à jour de commentaire"
#: src/ActivityBehaviors.php:135
msgid "Comment has been updated by \"%s\" at %s"
msgstr "Un commentaire a été mise à jour par \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:147
msgid "trackback creation"
msgstr "Création de trackback"
#: src/ActivityBehaviors.php:148
msgid "A new trackback to \"%\" at \"%s\" was created on post \"%s\" at %s"
msgstr "Un nouveau rétrolien vers \"%s\" a été créé sur le billet \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:156
msgid "category creation"
msgstr "Création de catégorie"
#: src/ActivityBehaviors.php:157
msgid "A new category called \"%s\" was created by \"%s\" at %s"
msgstr "Un nouvelle catégorie nommée \"%s\" a été créé par \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:165
msgid "updating category"
msgstr "Mise à jour de catégorie"
#: src/ActivityBehaviors.php:166
msgid "Category called \"%s\" has been updated by \"%s\" at %s"
msgstr "La catégorie nommée \"%s\" a été mise à jour par \"%s\" à l'adresse \"%s\""
#: src/ActivityBehaviors.php:176
msgid "user creation"
msgstr "Création d'utilisateur"
#: src/ActivityBehaviors.php:177
msgid "A new user named \"%s\" was created by \"%s\""
msgstr "Un nouvel utilisateur a été ajouté par \"%s\""
#: src/ActivityBehaviors.php:185
msgid "updating user"
msgstr "Mise à jour d'utilisateur"
#: src/ActivityBehaviors.php:186
msgid "User named \"%s\" has been updated by \"%s\""
msgstr "L'utilisateur \"%s\" a été mis à jour par \"%s\""
#: src/ActivityBehaviors.php:217
msgid "user deletion"
msgstr "Suppression d'utilisateur"
#: src/ActivityBehaviors.php:218
msgid "User named \"%s\" has been deleted by \"%\""
msgstr "L'utilisateur nommé \"%s\" a été supprimé par \"%s\""
#: src/ActivityBehaviors.php:235
msgid "HTML"
msgstr "HTML"
#: src/ActivityBehaviors.php:248
#: src/ActivityReport.php:341
msgid "Activity report"
msgstr "Rapport d'activité"
#: src/ActivityReport.php:331
msgid "An error occured when parsing report."
msgstr "Une erreur est survenue lors de la compilation du rapport."
#: src/ActivityReport.php:347
msgid "You received a message from your blog's activity report module."
msgstr "Vous recevez un message du module de rapport d'activité de votre blog."
#: src/ActivityReport.php:356
msgid "Period from %s to %s"
msgstr "Période du %s au %s"
#: src/ActivityReport.php:404
msgid "Activity report deletes some old logs."
msgstr "L'extension a automatiquement effacé des anciennes activités."
msgid "Blog activity report"
msgstr "Rapport d'activité du blog"
#: src/ActivityReport.php:661
msgid "Blog \"%s\" activity report"
msgstr "Rapport d'activité du blog \"%s\""
msgid "Logs"
msgstr "Enregistrements"
#: src/Backend.php:126
msgid "View all logs"
msgstr "Voir tous les logs"
#: src/Backend.php:142
msgid "Number of activities to show on dashboard:"
msgstr "Nombre d'activités à afficher sur le tableau de bord :"
#: src/Backend.php:144
msgid "Do not show activity report"
msgstr "Ne pas afficher le rapport d'activité"
#: src/Backend.php:170
#: src/ManageList.php:48
msgid "Group"
msgstr "Groupe"
#: src/Backend.php:177
msgid "logs per page"
msgstr "enregistrements par page"
#: src/Combo.php:45
msgid "every hour"
msgstr "toutes les heures"
#: src/Combo.php:46
msgid "every 2 hours"
msgstr "toutes les 2 heures"
#: src/Combo.php:47
msgid "2 times by day"
msgstr "2 fois par jour"
#: src/Combo.php:48
msgid "every day"
msgstr "tous les jours"
#: src/Combo.php:49
msgid "every 2 days"
msgstr "tous les 2 jours"
#: src/Combo.php:50
msgid "every week"
msgstr "toutes les semaines"
#: src/Combo.php:68
msgid "every 2 weeks"
msgstr "toutes les 2 semaines"
#: src/Combo.php:69
msgid "every 4 weeks"
msgstr "toutes les 4 semaines"
#: src/Config.php:85
msgid "Report successfully sent."
msgstr "Rapport envoyé avec succès."
#: src/Config.php:92
msgid "Logs successfully deleted."
msgstr "Logs effacés avec succès."
#: src/Config.php:116
msgid "never"
msgstr "jamais"
#: src/Config.php:117
msgid "on new activity"
msgstr "lors d'une nouvelle activité"
#: src/Config.php:133
msgid "This server has no mail function, activityReport does not send email report."
msgstr "Ce server n'a pas de fonction d'envoie de mail, le rapport ne sera pas envoyer."
#: src/Config.php:140
msgid "Mail report"
msgstr "Rapport par email"
#: src/Config.php:142
msgid "Send report:"
msgstr "Rapport envoyé :"
#: src/Config.php:146
msgid "Recipients:"
msgstr "Destinataires :"
#: src/Config.php:149
msgid "Separate multiple email addresses with a semicolon \";\""
msgstr "Séparer les adresses email par un point-virgule \";\""
#: src/Config.php:150
msgid "Leave it empty to disable mail report."
msgstr "Laisser vide pour désactiver le rapport par email."
#: src/Config.php:155
msgid "Use Dotclear date formaters. ex: %B %d at %H:%M"
msgstr "Utiliser le formatage des dates de Dotclear. ex: %d %B à %H:%M"
#: src/Config.php:157
msgid "Report format:"
msgstr "Format du rapport :"
#: src/Config.php:162
msgid "Last report by email:"
msgstr "Dernier rapport par email :"
#: src/Config.php:163
msgid "Next report by email:"
msgstr "Prochain rapport par email :"
#: src/Config.php:167
msgid "Feeds"
msgstr "Flux"
#: src/Config.php:170
msgid "Enable activity feed"
msgstr "Activer le flux d'activités"
#: src/Config.php:174
msgid "RSS feed"
msgstr "Flux RSS"
#: src/Config.php:177
msgid "Rss2 activities feed"
msgstr "Flux RSS2 d'activités"
#: src/Config.php:178
msgid "Atom feed"
msgstr "Flux Atom"
#: src/Config.php:181
msgid "Atom activities feed"
msgstr "Flux Atom d'activités"
#: src/Config.php:188
msgid "Activities"
msgstr "Activités"
#: src/Config.php:189
msgid "Select actions by activity type to add to report"
msgstr "Sélectionner les actions par type d'activité à ajouter au rapport"
#: src/Config.php:214
msgid "Automatic cleaning of old logs:"
msgstr "Nettoyage automatique des anciennes activités:"
#: src/Config.php:219
msgid "Send report now"
msgstr "Envoyer un rapport maintenant"
#: src/Config.php:223
msgid "Delete all logs now"
msgstr "Effacer tous les logs maintenant"
#: src/Format.php:68
msgid "Plain text"
msgstr "Texte brut"
#: src/Manage.php:58
msgid "Logs successfully deleted"
msgstr "Enregistrements effacés avec succès"
#: src/Manage.php:91
msgid "Are you sure you want to delete logs?"
msgstr "Êtes-vous sure de vouloir effacer les enregistrements ?"
#: src/Manage.php:114
msgid "Delete all aticivity logs"
msgstr "Effacer tous les enregistrements d'activités"
#: src/Manage.php:115
msgid "Delete all allready reported logs"
msgstr "Effacer les enregistrements d'activités déjà envoyé par email"
#: src/ManageList.php:33
msgid "No log matches the filter"
msgstr "Aucun enregistrement ne correspond au filtre"
#: src/ManageList.php:35
msgid "No log"
msgstr "Pas d'enregistrement"
#: src/ManageList.php:43
msgid "List of %s logs matching the filter."
msgstr "Liste des %s logs correspondants au filtre."
#: src/ManageList.php:44
msgid "List of %s logs."
msgstr "Listes des %s enregistrements"
#: src/ManageList.php:50
msgid "Message"
msgstr "Message"
msgid "Activity report module"
msgstr "Module de rapport d'activité"
#: src/ManageList.php:79
msgid "undefined"
msgstr "inconnu"
#: src/ManageList.php:85
msgid "reported"
msgstr "envoyé"
msgid "Activity log"
msgstr "Journal d'activité"
msgid "Log and receive your blog activity by email, feed, or on dashboard"
msgstr "Enregistrer et recevoir l'activité de votre blog par mail, flux ou sur le tableau de bord"

45
src/Action.php Normal file
View file

@ -0,0 +1,45 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use dcCore;
/**
* Action descriptor.
*/
class Action
{
/**
* Constructor sets action description.
*
* @param string $id The action ID
* @param string $title The action title
* @param string $message The action message
* @param string $behavior The behavior name
* @param null|callable $function The callback function
*/
public function __construct(
public readonly string $id,
public readonly string $title,
public readonly string $message,
string $behavior,
?callable $function
) {
// fake action has no behavior
if (null !== $function) {
dcCore::app()->addBehavior($behavior, $function);
}
}
}

View file

@ -10,393 +10,470 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
if (!defined('ACTIVITY_REPORT_V2')) {
return null;
}
namespace Dotclear\Plugin\activityReport;
class activityReportBehaviors
use ArrayObject;
use cursor;
use dcBlog;
use dcCore;
use dcRecord;
use dcUtils;
use Dotclear\Helper\Network\Http;
/**
* Register default activities and export mail formats.
*/
class ActivityBehaviors
{
public static function registerBehaviors()
public static function register(): void
{
// ActivityReport plugin
dcCore::app()->activityReport->addGroup(basename(dirname(__DIR__)), __('ActivityReport messages'));
$my = new Group(My::id(), __('ActivityReport messages'));
$blog = new Group('blog', __('Actions on blog'));
$post = new Group('post', __('Actions on posts'));
$comment = new Group('comment', __('Actions on comments'));
$category = new Group('category', __('Actions on categories'));
$user = new Group('user', __('Actions on users'));
dcCore::app()->activityReport->addAction(
basename(dirname(__DIR__)),
// ActivityReport plugin
$my->add(new Action(
'message',
__('Special messages'),
__('%s'),
'messageActivityReport',
['activityReportBehaviors', 'messageActivityReport']
);
// Blog
dcCore::app()->activityReport->addGroup('blog', __('Actions on blog'));
[self::class, 'messageActivityReport']
));
// Not use as it is global : BEHAVIOR adminAfterBlogCreate in admin/blog.php
// from BEHAVIOR adminAfterBlogUpdate in admin/blog_pref.php
dcCore::app()->activityReport->addAction(
'blog',
$blog->add(new Action(
'update',
__('updating blog'),
__('Blog was updated by "%s"'),
'adminAfterBlogUpdate',
['activityReportBehaviors', 'blogUpdate']
);
[self::class, 'blogUpdate']
));
// from BEHAVIOR publicHeadContent in template
dcCore::app()->activityReport->addAction(
'blog',
$blog->add(new Action(
'p404',
__('404 error'),
__('New 404 error page at "%s"'),
'publicHeadContent',
['activityReportBehaviors', 'blogP404']
);
// Post
dcCore::app()->activityReport->addGroup('post', __('Actions on posts'));
[self::class, 'blogP404']
));
// from BEHAVIOR coreAfterPostCreate in inc/core/class.dc.blog.php (DC 2.2)
// duplicate adminAfterPostCreate in admin/post.php
// duplicate adminAfterPostCreate in admin/services.php
dcCore::app()->activityReport->addAction(
'post',
$post->add(new Action(
'create',
__('post creation'),
__('A new post called "%s" was created by "%s" at %s'),
'adminAfterPostCreate',
['activityReportBehaviors', 'postCreate']
);
[self::class, 'postCreate']
));
// Plugin contribute
// from BEHAVIOR publicAfterPostCreate in plugins/contribute/_public.php
dcCore::app()->activityReport->addAction(
'post',
$post->add(new Action(
'create',
__('post creation'),
__('A new post called "%s" was created by "%s" at %s'),
'publicAfterPostCreate',
['activityReportBehaviors', 'postCreate']
);
[self::class, 'postCreate']
));
// from BEHAVIOR coreAfterPostUpdate in inc/core/class.dc.blog.php (DC2.2)
// duplicate adminAfterPostUpdate in admin/post.php
dcCore::app()->activityReport->addAction(
'post',
$post->add(new Action(
'update',
__('updating post'),
__('Post called "%s" has been updated by "%s" at %s'),
'adminAfterPostUpdate',
['activityReportBehaviors', 'postUpdate']
);
[self::class, 'postUpdate']
));
// from BEHAVIOR adminBeforePostDelete in admin/post.php
dcCore::app()->activityReport->addAction(
'post',
$post->add(new Action(
'delete',
__('post deletion'),
__('Post called "%s" has been deleted by "%s"'),
'adminBeforePostDelete',
['activityReportBehaviors', 'postDelete']
);
[self::class, 'postDelete']
));
// Wrong attempt on passworded enrty
// from BEHAVIOR urlHandlerServeDocument in inc/public/lib.urlhandlers.php
dcCore::app()->activityReport->addAction(
'post',
$post->add(new Action(
'protection',
__('Post protection'),
__('An attempt failed on a passworded post with password "%s" at "%s"'),
'urlHandlerServeDocument',
['activityReportBehaviors', 'postPasswordAttempt']
);
// Comment
dcCore::app()->activityReport->addGroup('comment', __('Actions on comments'));
[self::class, 'postPasswordAttempt']
));
// from BEHAVIOR coreAfterCommentCreate in inc/core/class.dc.blog.php
// duplicate adminAfterCommentCreate in admin/comment.php
// duplicate publicAfterCommentCreate in inc/public/lib.urlhandlers.php
dcCore::app()->activityReport->addAction(
'comment',
$comment->add(new Action(
'create',
__('comment creation'),
__('A new comment was created by "%s" on post "%s" at %s'),
'coreAfterCommentCreate',
['activityReportBehaviors', 'commentCreate']
);
[self::class, 'commentCreate']
));
// from BEHAVIOR coreAfterCommentUpdate in inc/core/class.dc.blog.php
// duplicate adminAfterCommentUpdate in admin/comment.php
dcCore::app()->activityReport->addAction(
'comment',
$comment->add(new Action(
'update',
__('updating comment'),
__('Comment has been updated by "%s" at %s'),
'coreAfterCommentUpdate',
['activityReportBehaviors', 'commentUpdate']
);
[self::class, 'commentUpdate']
));
// Missing coreBeforeCommentDelete in inc/core/class.dc.blog.php
// Missing adminBeforeCommentDelete in admin/comment.php
// from BEHAVIOR coreAfterCommentCreate in inc/core/class.dc.blog.php
// duplicate publicAfterTrackbackCreate in inc/core/class.dc.trackback.php
dcCore::app()->activityReport->addAction(
'comment',
$comment->add(new Action(
'trackback',
__('trackback creation'),
__('A new trackback to "%" at "%s" was created on post "%s" at %s'),
'coreAfterCommentCreate',
['activityReportBehaviors', 'trackbackCreate']
);
// Category
dcCore::app()->activityReport->addGroup('category', __('Actions on categories'));
[self::class, 'trackbackCreate']
));
// from BEHAVIOR adminAfterCategoryCreate in admin/category.php
dcCore::app()->activityReport->addAction(
'category',
$category->add(new Action(
'create',
__('category creation'),
__('A new category called "%s" was created by "%s" at %s'),
'adminAfterCategoryCreate',
['activityReportBehaviors', 'categoryCreate']
);
[self::class, 'categoryCreate']
));
// from BEHAVIOR adminAfterCategoryUpdate in admin/category.php
dcCore::app()->activityReport->addAction(
'category',
$category->add(new Action(
'update',
__('updating category'),
__('Category called "%s" has been updated by "%s" at %s'),
'adminAfterCategoryUpdate',
['activityReportBehaviors', 'categoryUpdate']
);
[self::class, 'categoryUpdate']
));
// Missing adminBeforeCategoryDelete in admin/category.php
// User
dcCore::app()->activityReport->addGroup('user', __('Actions on users'));
// from BEHAVIOR adminAfterUserCreate in admin/user.php
dcCore::app()->activityReport->addAction(
'user',
$user->add(new Action(
'create',
__('user creation'),
__('A new user named "%s" was created by "%s"'),
'adminAfterUserCreate',
['activityReportBehaviors', 'userCreate']
);
[self::class, 'userCreate']
));
// from BEHAVIOR adminAfterUserUpdated in admin/user.php
dcCore::app()->activityReport->addAction(
'user',
$user->add(new Action(
'update',
__('updating user'),
__('User named "%s" has been updated by "%s"'),
'adminAfterUserUpdate',
['activityReportBehaviors', 'userUpdate']
);
[self::class, 'userUpdate']
));
// from BEHAVIOR adminAfterUserProfileUpdate in admin/preferences.php
$user->add(new Action(
'preference',
__('updating user preference'),
__('User named "%s" preference has been updated by "%s"'),
'adminAfterUserProfileUpdate',
[self::class, 'userPreference']
));
$user->add(new Action(
'preference',
__('updating user preference'),
__('User named "%s" preference has been updated by "%s"'),
'adminAfterUserOptionsUpdate',
[self::class, 'userPreference']
));
$user->add(new Action(
'preference',
__('updating user preference'),
__('User named "%s" preference has been updated by "%s"'),
'adminAfterDashboardOptionsUpdate',
[self::class, 'userPreference']
));
// from BEHAVIOR adminBeforeUserDelete in admin/users.php
dcCore::app()->activityReport->addAction(
'user',
$user->add(new Action(
'delete',
__('user deletion'),
__('User named "%s" has been deleted by "%"'),
'adminBeforeUserDelete',
['activityReportBehaviors', 'userDelete']
);
[self::class, 'userDelete']
));
ActivityReport::instance()->groups
->add($my)
->add($blog)
->add($post)
->add($comment)
->add($category)
->add($user);
// Add default email report formats
ActivityReport::instance()->formats
->add(new Format('plain', [])) // plain text format is build with default values
->add(new Format('html', [
'name' => __('HTML'),
'blog_title' => '<h2><a href="%URL%">%TEXT%</a></h2>',
'group_title' => '<h3>%TEXT%</h3>',
'group_open' => '<ul>',
'group_close' => '</ul>',
'action' => '<li><em>%TIME%</em><br />%TEXT%</li>',
'error' => '<p>%TEXT%</p>',
'period_title' => '<h1>%TEXT%</h1>',
'period_open' => '<ul>',
'period_close' => '</ul>',
'info' => '<li>%TEXT%</li>',
'page' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n" .
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">' . "\n" .
'<head><title>' . __('Activity report') . '</title>' .
'<style type="text/css">' .
' body { color: #303030; background: #FCFCFC; font-size: 0.7em;font-family: Georgia, Tahoma, Arial, Helvetica, sans-serif; }' .
' a { color: #303030; text-decoration: none; }' .
' h1 { text-align: center; font-size: 2em; }' .
' h2 { color: #303030; text-align:center; }' .
' h3 { color: #7F3F3F; }' .
' li em { color: #303030; }' .
' div.info { color: #3F497F; background-color: #F8F8EB; border: 1px solid #888888; margin: 4px; padding: 4px; }' .
' div.content { color: #3F7F47; background-color: #F8F8EB; border: 1px solid #888888; margin: 4px; padding: 4px; }' .
' div.foot { text-align:center; font-size: 0.9em; }' .
'</style>' .
'</head><body>' .
'<div class="info">%PERIOD%</div><div class="content">%TEXT%</div>' .
'<div class="foot"><p>Powered by <a href="https://github.com/JcDenis/activityReport">activityReport</a></p></div>' .
'</body></html>',
]));
}
public static function messageActivityReport($message)
public static function messageActivityReport(string $message): void
{
$logs = [$message];
dcCore::app()->activityReport->addLog(basename(dirname(__DIR__)), 'message', $logs);
ActivityReport::instance()->addLog(My::id(), 'message', $logs);
}
public static function blogUpdate($cur, $blog_id)
public static function blogUpdate(cursor $cur, string $blog_id): void
{
$logs = [dcCore::app()->auth->getInfo('user_cn')];
dcCore::app()->activityReport->addLog('blog', 'update', $logs);
$logs = [(string) dcCore::app()->auth?->getInfo('user_cn')];
ActivityReport::instance()->addLog('blog', 'update', $logs);
}
public static function blogP404()
public static function blogP404(): void
{
if (dcCore::app()->url->type != '404') {
return null;
return;
}
$logs = [dcCore::app()->blog->url . $_SERVER['QUERY_STRING']];
dcCore::app()->activityReport->addLog('blog', 'p404', $logs);
$logs = [(string) dcCore::app()->blog?->url . $_SERVER['QUERY_STRING']];
ActivityReport::instance()->addLog('blog', 'p404', $logs);
}
public static function postCreate($cur, $post_id)
public static function postCreate(cursor $cur, int $post_id): void
{
$type = $cur->post_type ? $cur->post_type : 'post';
$post_url = dcCore::app()->blog->getPostURL('', $cur->post_dt, $cur->post_title, $post_id);
$type = $cur->getField('post_type') ?? 'post';
$post_url = dcCore::app()->blog?->getPostURL('', $cur->getField('post_dt'), $cur->getField('post_title'), $post_id);
$logs = [
$cur->post_title,
dcCore::app()->auth->getInfo('user_cn'),
dcCore::app()->blog->url . dcCore::app()->url->getBase($type) . '/' . $post_url,
(string) $cur->getField('post_title'),
(string) dcCore::app()->auth?->getInfo('user_cn'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase($type) . '/' . $post_url,
];
dcCore::app()->activityReport->addLog('post', 'create', $logs);
ActivityReport::instance()->addLog('post', 'create', $logs);
}
public static function postUpdate($cur, $post_id)
public static function postUpdate(cursor $cur, int $post_id): void
{
$type = $cur->post_type ? $cur->post_type : 'post';
$post_url = dcCore::app()->blog->getPostURL('', $cur->post_dt, $cur->post_title, $post_id);
$type = $cur->getField('post_type') ?? 'post';
$post_url = dcCore::app()->blog?->getPostURL('', $cur->getField('post_dt'), $cur->getField('post_title'), $post_id);
$logs = [
$cur->post_title,
dcCore::app()->auth->getInfo('user_cn'),
dcCore::app()->blog->url . dcCore::app()->url->getBase($type) . '/' . $post_url,
(string) $cur->getField('post_title'),
(string) dcCore::app()->auth?->getInfo('user_cn'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase($type) . '/' . $post_url,
];
dcCore::app()->activityReport->addLog('post', 'update', $logs);
ActivityReport::instance()->addLog('post', 'update', $logs);
}
public static function postDelete($post_id)
public static function postDelete(int $post_id): void
{
$posts = dcCore::app()->blog->getPosts(['post_id' => $post_id, 'limit' => 1]);
$logs = [
$posts->post_title,
dcCore::app()->auth->getInfo('user_cn'),
$posts = dcCore::app()->blog?->getPosts(['post_id' => $post_id, 'limit' => 1]);
if (!$posts || $posts->isEmpty()) {
return;
}
$logs = [
(string) $posts->f('post_title'),
(string) dcCore::app()->auth?->getInfo('user_cn'),
];
dcCore::app()->activityReport->addLog('post', 'delete', $logs);
ActivityReport::instance()->addLog('post', 'delete', $logs);
}
public static function postPasswordAttempt($result)
public static function postPasswordAttempt(ArrayObject $result): void
{
if ($result['tpl'] != 'password-form.html' || empty($_POST['password'])) {
return null;
return;
}
$logs = [
$_POST['password'],
http::getSelfURI(),
Http::getSelfURI(),
];
dcCore::app()->activityReport->addLog('post', 'protection', $logs);
ActivityReport::instance()->addLog('post', 'protection', $logs);
}
public static function commentCreate($blog, $cur)
public static function commentCreate(dcBlog $blog, cursor $cur): void
{
if ($cur->comment_trackback) {
return null;
if ($cur->getField('comment_trackback')) {
return;
}
$posts = dcCore::app()->blog->getPosts(['post_id' => $cur->post_id, 'limit' => 1]);
$logs = [
$cur->comment_author,
$posts->post_title,
dcCore::app()->blog->url . dcCore::app()->url->getBase($posts->post_type) .
'/' . $posts->post_url . '#c' . $cur->comment_id,
];
dcCore::app()->activityReport->addLog('comment', 'create', $logs);
}
public static function commentUpdate($blog, $cur, $old)
{
$posts = dcCore::app()->blog->getPosts(['post_id' => $old->post_id, 'limit' => 1]);
$logs = [
dcCore::app()->auth->getInfo('user_cn'),
$posts->post_title,
dcCore::app()->blog->url . dcCore::app()->url->getBase($posts->post_type) .
'/' . $posts->post_url . '#c' . $old->comment_id,
];
dcCore::app()->activityReport->addLog('comment', 'update', $logs);
}
public static function trackbackCreate($cur, $comment_id)
{
// From blog args are $blog, $cur #thks to bruno
$c = $cur instanceof dcBlog ? $comment_id : $cur;
if (!$c->comment_trackback || !$c->comment_site) {
return null;
}
$posts = dcCore::app()->blog->getPosts(
['post_id' => $c->post_id, 'no_content' => true, 'limit' => 1]
$posts = dcCore::app()->blog?->getPosts(
['post_id' => $cur->getField('post_id'), 'limit' => 1, 'post_type' => '']
);
if ($posts->isEmpty()) {
return null;
if (!$posts || $posts->isEmpty()) {
return;
}
$logs = [
$c->comment_author,
$c->comment_site,
$posts->post_title,
dcCore::app()->blog->url . dcCore::app()->url->getBase($posts->post_type) .
'/' . $posts->post_url,
(string) $cur->getField('comment_author'),
(string) $posts->f('post_title'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase((string) $posts->f('post_type')) .
'/' . $posts->f('post_url') . '#c' . $cur->getField('comment_id'),
];
dcCore::app()->activityReport->addLog('comment', 'trackback', $logs);
ActivityReport::instance()->addLog('comment', 'create', $logs);
}
public static function categoryCreate($cur, $cat_id)
public static function commentUpdate(dcBlog $blog, cursor $cur, dcRecord $old): void
{
$posts = dcCore::app()->blog?->getPosts(
['post_id' => $old->f('post_id'), 'limit' => 1]
);
if (!$posts || $posts->isEmpty()) {
return;
}
$logs = [
(string) dcCore::app()->auth?->getInfo('user_cn'),
(string) $posts->f('post_title'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase((string) $posts->f('post_type')) .
'/' . $posts->f('post_url') . '#c' . $old->f('comment_id'),
];
ActivityReport::instance()->addLog('comment', 'update', $logs);
}
public static function trackbackCreate(dcBlog $blog, cursor $cur): void
{
if (!$cur->getField('comment_trackback')) {
return;
}
$posts = dcCore::app()->blog?->getPosts(
['post_id' => $cur->getField('post_id'), 'no_content' => true, 'limit' => 1]
);
if (!$posts || $posts->isEmpty()) {
return;
}
$logs = [
(string) $cur->getField('comment_author'),
(string) $cur->getField('comment_site'),
(string) $posts->f('post_title'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase($posts->f('post_type')) .
'/' . $posts->f('post_url'),
];
ActivityReport::instance()->addLog('comment', 'trackback', $logs);
}
public static function categoryCreate(cursor $cur, int $cat_id): void
{
$logs = [
$cur->cat_title,
dcCore::app()->auth->getInfo('user_cn'),
dcCore::app()->blog->url . dcCore::app()->url->getBase('category') . '/' . $cur->cat_url,
(string) $cur->getField('cat_title'),
(string) dcCore::app()->auth?->getInfo('user_cn'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase('category') . '/' . $cur->getField('cat_url'),
];
dcCore::app()->activityReport->addLog('category', 'create', $logs);
ActivityReport::instance()->addLog('category', 'create', $logs);
}
public static function categoryUpdate($cur, $cat_id)
public static function categoryUpdate(cursor $cur, int $cat_id): void
{
$logs = [
$cur->cat_title,
dcCore::app()->auth->getInfo('user_cn'),
dcCore::app()->blog->url . dcCore::app()->url->getBase('category') . '/' . $cur->cat_url,
(string) $cur->getField('cat_title'),
(string) dcCore::app()->auth?->getInfo('user_cn'),
(string) dcCore::app()->blog?->url . dcCore::app()->url->getBase('category') . '/' . $cur->getField('cat_url'),
];
dcCore::app()->activityReport->addLog('category', 'update', $logs);
ActivityReport::instance()->addLog('category', 'update', $logs);
}
public static function userCreate($cur, $user_id)
public static function userCreate(cursor $cur, string $user_id): void
{
$user_cn = dcUtils::getUserCN(
$cur->user_id,
$cur->user_name,
$cur->user_firstname,
$cur->user_displayname
$cur->getField('user_id'),
$cur->getField('user_name'),
$cur->getField('user_firstname'),
$cur->getField('user_displayname')
);
$logs = [
$user_cn,
dcCore::app()->auth->getInfo('user_cn'),
(string) $user_cn,
(string) dcCore::app()->auth?->getInfo('user_cn'),
];
dcCore::app()->activityReport->addLog('user', 'create', $logs);
ActivityReport::instance()->addLog('user', 'create', $logs);
}
public static function usertUpdate($cur, $user_id)
public static function userUpdate(cursor $cur, string $user_id): void
{
$user_cn = dcUtils::getUserCN(
$cur->user_id,
$cur->user_name,
$cur->user_firstname,
$cur->user_displayname
$cur->getField('user_id'),
$cur->getField('user_name'),
$cur->getField('user_firstname'),
$cur->getField('user_displayname')
);
$logs = [
$user_cn,
dcCore::app()->auth->getInfo('user_cn'),
(string) $user_cn,
(string) dcCore::app()->auth?->getInfo('user_cn'),
];
dcCore::app()->activityReport->addLog('user', 'update', $logs);
ActivityReport::instance()->addLog('user', 'update', $logs);
}
public static function userDelete($user_id)
public static function userPreference(cursor $cur, string $user_id): void
{
$user_cn = dcUtils::getUserCN(
$cur->getField('user_id'),
$cur->getField('user_name'),
$cur->getField('user_firstname'),
$cur->getField('user_displayname')
);
$logs = [
(string) $user_cn,
(string) dcCore::app()->auth?->getInfo('user_cn'),
];
ActivityReport::instance()->addLog('user', 'preference', $logs);
}
public static function userDelete(string $user_id): void
{
$users = dcCore::app()->getUser($user_id);
$user_cn = dcUtils::getUserCN(
$users->user_id,
$users->user_name,
$users->user_firstname,
$users->user_displayname
$users->f('user_id'),
$users->f('user_name'),
$users->f('user_firstname'),
$users->f('user_displayname')
);
$logs = [
$user_cn,
dcCore::app()->auth->getInfo('user_cn'),
(string) $user_cn,
(string) dcCore::app()->auth?->getInfo('user_cn'),
];
dcCore::app()->activityReport->addLog('user', 'delete', $logs);
ActivityReport::instance()->addLog('user', 'delete', $logs);
}
}

File diff suppressed because it is too large Load diff

View file

@ -10,140 +10,187 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return null;
}
if (!defined('ACTIVITY_REPORT_V2')) {
return null;
}
declare(strict_types=1);
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
__('Activity report'),
dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)),
dcPage::getPF(basename(__DIR__) . '/icon.png'),
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)
);
namespace Dotclear\Plugin\activityReport;
if (dcCore::app()->activityReport->getSetting('active')) {
dcCore::app()->addBehavior('adminDashboardContentsV2', ['activityReportAdmin', 'adminDashboardContentsV2']);
dcCore::app()->addBehavior('adminDashboardOptionsFormV2', ['activityReportAdmin', 'adminDashboardOptionsFormV2']);
dcCore::app()->addBehavior('adminAfterDashboardOptionsUpdate', ['activityReportAdmin', 'adminAfterDashboardOptionsUpdate']);
}
use ArrayObject;
use dcAdmin;
use dcAuth;
use dcCore;
use dcFavorites;
use dcNsProcess;
use dcPage;
use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Form\{
Div,
Label,
Para,
Select,
Text
};
class activityReportAdmin
/**
* Backend process
*/
class Backend extends dcNsProcess
{
public static function adminDashboardContentsV2($items)
public static function init(): bool
{
dcCore::app()->auth->user_prefs->addWorkspace(basename(__DIR__));
$limit = abs((int) dcCore::app()->auth->user_prefs->__get(basename(__DIR__))->dashboard_item);
if (!$limit) {
return null;
}
$p = [
'limit' => $limit,
'order' => 'activity_dt DESC',
'sql' => dcCore::app()->activityReport->requests2params(dcCore::app()->activityReport->getSetting('requests')),
];
$lines = [];
$rs = dcCore::app()->activityReport->getLogs($p);
if ($rs->isEmpty()) {
return null;
}
$groups = dcCore::app()->activityReport->getGroups();
while ($rs->fetch()) {
$group = $rs->activity_group;
static::$init = defined('DC_CONTEXT_ADMIN')
&& defined('ACTIVITY_REPORT')
&& My::phpCompliant()
&& My::isInstalled();
if (!isset($groups[$group])) {
continue;
}
$lines[] = '<dt title="' . __($groups[$group]['title']) . '">' .
'<strong>' . __($groups[$group]['actions'][$rs->activity_action]['title']) . '</strong>' .
'<br />' . dt::str(
dcCore::app()->blog->settings->system->date_format . ', ' . dcCore::app()->blog->settings->system->time_format,
strtotime($rs->activity_dt),
dcCore::app()->auth->getInfo('user_tz')
) . '<dt>' .
'<dd><p>' .
'<em>' . vsprintf(
__($groups[$group]['actions'][$rs->activity_action]['msg']),
dcCore::app()->activityReport->decode($rs->activity_logs)
) . '</em></p></dd>';
}
if (empty($lines)) {
return null;
}
$items[] = new ArrayObject([
'<div id="activity-report-logs" class="box medium">' .
'<h3>' . __('Activity report') . '</h3>' .
'<dl id="reports">' . implode('', $lines) . '</dl>' .
'<p class="modules"><a class="module-details" href="' .
dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__)) . '">' .
__('View all logs') . '</a> - <a class="module-config" href="' .
dcCore::app()->adminurl->get('admin.plugins', [
'module' => basename(__DIR__),
'conf' => 1,
'redir' => dcCore::app()->adminurl->get('admin.home') . '#activity-report-logs',
]) . '">' .
__('Configure plugin') . '</a></p>' .
'</div>',
]);
return static::$init;
}
public static function adminDashboardOptionsFormV2()
public static function process(): bool
{
dcCore::app()->auth->user_prefs->addWorkspace(basename(__DIR__));
echo
'<div class="fieldset">' .
'<h4>' . __('Activity report') . '</h4>' .
'<p><label for="activityReport_dashboard_item">' .
__('Number of activities to show on dashboard:') . '</label>' .
form::combo(
'activityReport_dashboard_item',
self::comboList(),
self::comboList(dcCore::app()->auth->user_prefs->__get(basename(__DIR__))->dashboard_item)
) . '</p>' .
'</div>';
}
public static function adminAfterDashboardOptionsUpdate($user_id = null)
{
if (is_null($user_id)) {
return;
if (!static::$init) {
return false;
}
dcCore::app()->auth->user_prefs->addWorkspace(basename(__DIR__));
dcCore::app()->auth->user_prefs->__get(basename(__DIR__))->put(
'dashboard_item',
self::comboList(@$_POST['activityReport_dashboard_item']),
'integer'
dcCore::app()->menu[dcAdmin::MENU_PLUGINS]->addItem(
My::name(),
dcCore::app()->adminurl?->get('admin.plugin.' . My::id()),
dcPage::getPF(My::id() . '/icon.svg'),
preg_match(
'/' . preg_quote((string) dcCore::app()->adminurl?->get('admin.plugin.' . My::id())) . '(&.*)?$/',
$_SERVER['REQUEST_URI']
),
dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([
dcAuth::PERMISSION_ADMIN,
]), dcCore::app()->blog?->id)
);
}
private static function comboList($q = true)
{
$l = [
__('Do not show activity report') => 0,
5 => 5,
10 => 10,
15 => 15,
20 => 20,
50 => 50,
100 => 100,
];
if (true === $q) {
return $l;
}
if (!$q) {
$q = -1;
}
dcCore::app()->addBehaviors([
// dashboard favorites icon
'adminDashboardFavoritesV2' => function (dcFavorites $favs): void {
$favs->register(My::id(), [
'title' => My::name(),
'url' => dcCore::app()->adminurl?->get('admin.plugin.' . My::id()),
'small-icon' => dcPage::getPF(My::id() . '/icon.svg'),
'large-icon' => dcPage::getPF(My::id() . '/icon.svg'),
'permissions' => dcCore::app()->auth?->makePermissions([
dcAuth::PERMISSION_ADMIN,
]),
]);
},
// dashboard content display
'adminDashboardContentsV2' => function (ArrayObject $items): void {
$limit = abs((int) dcCore::app()->auth?->user_prefs?->get(My::id())->get('dashboard_item'));
if (!$limit) {
return ;
}
return in_array($q, $l) ? $l[$q] : 0;
$params = new ArrayObject([
'limit' => $limit,
'requests' => true,
]);
$rs = ActivityReport::instance()->getLogs($params);
if (!$rs || $rs->isEmpty()) {
return;
}
$lines = [];
$groups = ActivityReport::instance()->groups;
while ($rs->fetch()) {
if (!$groups->has($rs->f('activity_group'))) {
continue;
}
$group = $groups->get($rs->f('activity_group'));
$lines[] = '<dt title="' . __($group->title) . '">' .
'<strong>' . __($group->get($rs->f('activity_action'))->title) . '</strong>' .
'<br />' . Date::str(
dcCore::app()->blog?->settings->get('system')->get('date_format') . ', ' . dcCore::app()->blog?->settings->get('system')->get('time_format'),
(int) strtotime($rs->f('activity_dt')),
dcCore::app()->auth?->getInfo('user_tz')
) . '<dt>' .
'<dd><p>' .
'<em>' . vsprintf(
__($group->get($rs->f('activity_action'))->message),
json_decode($rs->f('activity_logs'), true)
) . '</em></p></dd>';
}
if (empty($lines)) {
return ;
}
$items[] = new ArrayObject([
'<div id="activity-report-logs" class="box medium">' .
'<h3>' . My::name() . '</h3>' .
'<dl id="reports">' . implode('', $lines) . '</dl>' .
'<p class="modules"><a class="module-details" href="' .
dcCore::app()->adminurl?->get('admin.plugin.' . My::id()) . '">' .
__('View all logs') . '</a> - <a class="module-config" href="' .
dcCore::app()->adminurl?->get('admin.plugins', [
'module' => My::id(),
'conf' => 1,
'redir' => dcCore::app()->adminurl->get('admin.home'),
]) . '">' .
__('Configure plugin') . '</a></p>' .
'</div>',
]);
},
// dashboard content user preference form
'adminDashboardOptionsFormV2' => function (): void {
echo
(new Div())->class('fieldset')->items([
(new Text('h4', My::name())),
(new Para())->items([
(new Label(__('Number of activities to show on dashboard:'), Label::OUTSIDE_LABEL_BEFORE))->for(My::id() . '_dashboard_item'),
(new Select(My::id() . '_dashboard_item'))->default((string) dcCore::app()->auth?->user_prefs?->get(My::id())->get('dashboard_item'))->items([
__('Do not show activity report') => 0,
5 => 5,
10 => 10,
15 => 15,
20 => 20,
50 => 50,
100 => 100,
]),
]),
])->render();
},
// save dashboard content user preference
'adminAfterDashboardOptionsUpdate' => function (?string $user_id = null): void {
if (!is_null($user_id)) {
dcCore::app()->auth?->user_prefs?->get(My::id())->put(
'dashboard_item',
(int) $_POST[My::id() . '_dashboard_item'],
'integer'
);
}
},
// list filters
'adminFiltersListsV2' => function (ArrayObject $sorts): void {
$sorts[My::id()] = [
My::name(),
[
__('Group') => 'activity_group',
__('Action') => 'activity_action',
__('Date') => 'activity_dt',
__('Status') => 'activity_status',
],
'activity_dt',
'desc',
[__('logs per page'), 30],
];
},
// list columns user preference
'adminColumnsListsV2' => function (ArrayObject $cols): void {
$cols[My::id()] = [
My::name(),
[
'activity_group' => [true, __('Group')],
'activity_action' => [true, __('Action')],
'activity_dt' => [true, __('Date')],
'activity_status' => [false, __('Status')],
],
];
},
]);
return true;
}
}

72
src/Combo.php Normal file
View file

@ -0,0 +1,72 @@
<?php
/**
* @brief activityReport, 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\activityReport;
/**
* Combo helper.
*/
class Combo
{
/**
* Mail content formats.
*
* @return array The formats combo
*/
public static function mailformat(): array
{
$combo = [];
foreach (ActivityReport::instance()->formats->dump() as $format) {
$combo[$format->name] = $format->id;
}
return $combo;
}
/**
* Get report intervals.
*
* @return array The intervals combo
*/
public static function interval(): array
{
return [
__('every hour') => 3600,
__('every 2 hours') => 7200,
__('2 times by day') => 43200,
__('every day') => 86400,
__('every 2 days') => 172800,
__('every week') => 604800,
];
}
/**
* Get obsolete period.
*
* @return array The obsolete period combo
*/
public static function obselete(): array
{
return [
__('every hour') => 3600,
__('every 2 hours') => 7200,
__('2 times by day') => 43200,
__('every day') => 86400,
__('every 2 days') => 172800,
__('every week') => 604800,
__('every 2 weeks') => 1209600,
__('every 4 weeks') => 2419200,
];
}
}

View file

@ -10,232 +10,218 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_MODULE')) {
return null;
}
declare(strict_types=1);
$super = dcCore::app()->auth->isSuperAdmin() && !empty($_REQUEST['super']);
$redir = empty($_REQUEST['redir']) ? dcCore::app()->admin->list->getURL() . '#plugins' : $_REQUEST['redir'];
namespace Dotclear\Plugin\activityReport;
if ($super) {
dcCore::app()->activityReport->setGlobal();
}
use dcAuth;
use dcCore;
use dcPage;
use dcNsProcess;
use Dotclear\Helper\Date;
use Dotclear\Helper\Html\Form\{
Checkbox,
Div,
Hidden,
Input,
Label,
Note,
Para,
Select,
Text
};
use Exception;
$combo_interval = [
__('every hour') => 3600,
__('every 2 hours') => 7200,
__('2 times by day') => 43200,
__('every day') => 86400,
__('every 2 days') => 172800,
__('every week') => 604800,
];
/**
* Config process.
*/
class Config extends dcNsProcess
{
public static function init(): bool
{
static::$init == defined('DC_CONTEXT_ADMIN')
&& defined('ACTIVITY_REPORT')
&& My::phpCompliant()
&& dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([
dcAuth::PERMISSION_ADMIN,
]), dcCore::app()->blog?->id);
$combo_obselete = [
__('every hour') => 3600,
__('every 2 hours') => 7200,
__('2 times by day') => 43200,
__('every day') => 86400,
__('every 2 days') => 172800,
__('every week') => 604800,
__('every 2 weeks') => 1209600,
__('every 4 weeks') => 2419200,
];
return static::$init;
}
$combo_format = [
__('Plain text') => 'plain',
__('HTML') => 'html',
];
if (!empty($_POST['save'])) {
try {
dcCore::app()->activityReport->setSetting('active', !empty($_POST['active']));
if (in_array($_POST['interval'], $combo_interval)) {
dcCore::app()->activityReport->setSetting('interval', (int) $_POST['interval']);
public static function process(): bool
{
if (!static::$init) {
return false;
}
if (in_array($_POST['obsolete'], $combo_obselete)) {
dcCore::app()->activityReport->setSetting('obsolete', (int) $_POST['obsolete']);
if (empty($_POST['save'])) {
return true;
}
dcCore::app()->activityReport->setSetting('mailinglist', explode(';', $_POST['mailinglist']));
dcCore::app()->activityReport->setSetting('mailformat', isset($_POST['mailformat']) && $_POST['mailformat'] == 'html' ? 'html' : 'plain');
dcCore::app()->activityReport->setSetting('dateformat', html::escapeHTML($_POST['dateformat']));
dcCore::app()->activityReport->setSetting('requests', $_POST['requests'] ?? []);
dcCore::app()->activityReport->setSetting('blogs', $_POST['blogs'] ?? []);
if (!empty($_POST['send_report_now'])) {
dcCore::app()->activityReport->needReport(true);
try {
$s = ActivityReport::instance()->settings;
dcAdminNotices::addSuccessNotice(
__('Report successfully sent.')
$s->set('feed_active', !empty($_POST['feed_active']));
if (in_array($_POST['interval'], Combo::interval())) {
$s->set('interval', (int) $_POST['interval']);
}
if (in_array($_POST['obsolete'], Combo::obselete())) {
$s->set('obsolete', (int) $_POST['obsolete']);
}
$s->set('mailinglist', explode(';', $_POST['mailinglist']));
$s->set('mailformat', isset($_POST['mailformat']) && $_POST['mailformat'] == 'html' ? 'html' : 'plain');
$s->set('dateformat', $_POST['dateformat']);
$s->set('requests', $_POST['requests'] ?? []);
dcPage::addSuccessNotice(
__('Configuration successfully updated.')
);
}
if (!empty($_POST['delete_report_now'])) {
dcCore::app()->activityReport->deleteLogs();
dcAdminNotices::addSuccessNotice(
__('Logs successfully deleted.')
if (!empty($_POST['send_report_now'])) {
ActivityReport::instance()->needReport(true);
dcPage::addSuccessNotice(
__('Report successfully sent.')
);
}
if (!empty($_POST['delete_report_now'])) {
ActivityReport::instance()->deleteLogs();
dcPage::addSuccessNotice(
__('Logs successfully deleted.')
);
}
dcCore::app()->adminurl?->redirect('admin.plugins', [
'module' => My::id(),
'conf' => 1,
]);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
return true;
}
public static function render(): void
{
if (!static::$init) {
return;
}
$s = ActivityReport::instance()->settings;
if (!$s->lastreport) {
$last_report = __('never');
$next_report = __('on new activity');
} else {
$last_report = Date::str(
dcCore::app()->blog?->settings->get('system')->get('date_format') . ', ' . dcCore::app()->blog?->settings->get('system')->get('time_format'),
$s->lastreport,
dcCore::app()->auth?->getInfo('user_tz')
);
$next_report = Date::str(
dcCore::app()->blog?->settings->get('system')->get('date_format') . ', ' . dcCore::app()->blog?->settings->get('system')->get('time_format'),
$s->interval + $s->lastreport,
dcCore::app()->auth?->getInfo('user_tz')
);
}
dcAdminNotices::addSuccessNotice(
__('Configuration successfully updated.')
);
dcCore::app()->adminurl->redirect('admin.plugins', ['module' => basename(__DIR__), 'conf' => 1, 'super' => $super]);
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
if (!ActivityReport::hasMailer()) {
echo '<p class="message">' .
__('This server has no mail function, activityReport does not send email report.') .
'</p>';
}
echo
(new Div())->class('two-boxes')->separator('')->items([
(new Div())->class('fieldset box odd')->items([
(new Text('h4', __('Mail report'))),
(new Para())->items([
(new Label(__('Send report:'), Label::OUTSIDE_LABEL_BEFORE))->for('interval'),
(new Select('interval'))->default((string) $s->interval)->items(Combo::interval()),
]),
(new Para())->items([
(new Label(__('Recipients:'), Label::OUTSIDE_LABEL_BEFORE))->for('mailinglist'),
(new Input('mailinglist'))->size(60)->maxlenght(255)->value(implode(';', $s->mailinglist)),
]),
(new Note())->class('form-note')->text(__('Separate multiple email addresses with a semicolon ";"')),
(new Note())->class('form-note')->text(__('Leave it empty to disable mail report.')),
(new Para())->items([
(new Label(__('Date format:'), Label::OUTSIDE_LABEL_BEFORE))->for('dateformat'),
(new Input('dateformat'))->size(60)->maxlenght(255)->value($s->dateformat),
]),
(new Note())->class('form-note')->text(__('Use Dotclear date formaters. ex: %B %d at %H:%M')),
(new Para())->items([
(new Label(__('Report format:'), Label::OUTSIDE_LABEL_BEFORE))->for('mailformat'),
(new Select('mailformat'))->default($s->mailformat)->items(Combo::mailformat()),
]),
(new Text(
'ul',
'<li>' . __('Last report by email:') . ' ' . $last_report . '</li>' .
'<li>' . __('Next report by email:') . ' ' . $next_report . '</li>'
)),
]),
(new Div())->class('fieldset box even')->items([
(new Text('h4', __('Feeds'))),
(new Para())->items([
(new Checkbox('feed_active', $s->feed_active))->value(1),
(new Label(__('Enable activity feed'), Label::OUTSIDE_LABEL_AFTER))->for('feed_active')->class('classic'),
]),
(new Text(
'ul',
'<li><img alt="' . __('RSS feed') . '" src="' . dcPage::getPF(My::id() . '/img/feed.png') . '" /> ' .
'<a title="' . __('RSS feed') . '" href="' .
dcCore::app()->blog?->url . dcCore::app()->url->getBase(My::id()) . '/rss2/' . ActivityReport::instance()->getUserCode() . '">' .
__('Rss2 activities feed') . '</a></li>' .
'<li><img alt="' . __('Atom feed') . '" src="' . dcPage::getPF(My::id() . '/img/feed.png') . '" /> ' .
'<a title="' . __('Atom feed') . '" href="' .
dcCore::app()->blog?->url . dcCore::app()->url->getBase(My::id()) . '/atom/' . ActivityReport::instance()->getUserCode() . '">' .
__('Atom activities feed') . '</a></li>'
)),
]),
])->render();
$i = 0;
$g = [
(new Text('h4', __('Activities'))),
(new Text('p', __('Select actions by activity type to add to report'))),
];
foreach (ActivityReport::instance()->groups->dump() as $group_id => $group) {
$a = [];
$a[] = (new Text('h5', __($group->title)));
foreach ($group->dump() as $action_id => $action) {
$a[] = (new Para())->items([
(new Checkbox(
['requests[' . $group_id . '][' . $action_id . ']', 'requests_' . $group_id . '_' . $action_id . '_'],
isset($s->requests[$group_id][$action_id])
))->value(1),
(new Label(__($action->title), Label::OUTSIDE_LABEL_AFTER))->for(
'requests_' . $group_id . '_' . $action_id . '_'
)->class('classic'),
]);
}
$g[] = (new Div())->class('fieldset box')->items($a);
}
echo
(new Div('setting_report'))->class('fieldset one-box')->items($g)->render();
echo
(new Div('settings'))->class('fieldset')->items([
(new Text('h4', __('Maintenance'))),
(new Para())->items([
(new Label(__('Automatic cleaning of old logs:'), Label::OUTSIDE_LABEL_BEFORE))->for('obselete'),
(new Select('obselete'))->default((string) $s->obsolete)->items(Combo::obselete()),
]),
(new Para())->items([
(new Checkbox('send_report_now'))->value(1),
(new Label(__('Send report now'), Label::OUTSIDE_LABEL_AFTER))->for('send_report_now')->class('classic'),
]),
(new Para())->items([
(new Checkbox('delete_report_now'))->value(1),
(new Label(__('Delete all logs now'), Label::OUTSIDE_LABEL_AFTER))->for('delete_report_now')->class('classic'),
]),
])->render();
}
}
$last_report_ts = dcCore::app()->activityReport->getSetting('lastreport');
if (!$last_report_ts) {
$last_report = __('never');
$next_report = __('on new activity');
} else {
$last_report = dt::str(
dcCore::app()->blog->settings->system->date_format . ', ' . dcCore::app()->blog->settings->system->time_format,
$last_report_ts,
dcCore::app()->auth->getInfo('user_tz')
);
$next_report = dt::str(
dcCore::app()->blog->settings->system->date_format . ', ' . dcCore::app()->blog->settings->system->time_format,
(int) dcCore::app()->activityReport->getSetting('interval') + $last_report_ts,
dcCore::app()->auth->getInfo('user_tz')
);
}
$emails = implode(';', dcCore::app()->activityReport->getSetting('mailinglist'));
echo '<p class="warn">' . ($super ? __('All blogs') : __('Current blog')) . '</p>';
if (dcCore::app()->auth->isSuperAdmin()) {
echo sprintf(
'<p class="modules right"><a class="module-config" href="%s">%s</a><br class="clear"/></p>',
dcCore::app()->adminurl->get('admin.plugins', ['module' => basename(__DIR__), 'conf' => 1, 'super' => !$super]),
sprintf(__('Configure activity report for %s'), $super ? __('current blog') : __('all blogs'))
);
}
if (!activityReport::hasMailer()) {
echo '<p class="message">' .
__('This server has no mail function, activityReport does not send email report.') .
'</p>';
}
echo '
<div class="fieldset two-cols" id="settings"><h4>' . __('Settings') . '</h4>
<div class="col">
<p><label class="classic" for="active">' .
form::checkbox('active', '1', dcCore::app()->activityReport->getSetting('active')) . ' ' .
(
$super ?
__('Enable super administrator report') :
__('Enable report on this blog')
) . '</label></p>
<p><label for="obselete">' . __('Automatic cleaning of old logs:') . '</label>' .
form::combo('obsolete', $combo_obselete, dcCore::app()->activityReport->getSetting('obsolete')) . '</p>
<p><label for="dateformat">' . __('Date format:') . '<br />' .
form::field('dateformat', 60, 255, dcCore::app()->activityReport->getSetting('dateformat')) . '</label></p>
<p class="form-note">' . __('Use Dotclear date formaters. ex: %B %d at %H:%M') . '</p>' .
form::hidden(['super'], $super);
if (!$super) {
echo
'<p><img alt="' . __('RSS feed') . '" src="' . dcPage::getPF(basename(__DIR__) . '/inc/img/feed.png') . '" />' .
'<a title="' . __('RSS feed') . '" href="' .
dcCore::app()->blog->url . dcCore::app()->url->getBase(basename(__DIR__)) . '/rss2/' . dcCore::app()->activityReport->getUserCode() . '">' .
__('Rss2 feed for activity on this blog') . '</a><br />' .
'<img alt="' . __('Atom feed') . '" src="' . dcPage::getPF(basename(__DIR__) . '/inc/img/feed.png') . '" />' .
'<a title="' . __('Atom feed') . '" href="' .
dcCore::app()->blog->url . dcCore::app()->url->getBase(basename(__DIR__)) . '/atom/' . dcCore::app()->activityReport->getUserCode() . '">' .
__('Atom feed for activity on this blog') . '</a></p>';
}
echo '
</div><div class="col">
<p><label for="interval">' . __('Send report:') . '</label>' .
form::combo('interval', $combo_interval, dcCore::app()->activityReport->getSetting('interval')) . '</p>
<p><label for="mailinglist">' . __('Recipients:') . '<br />' .
form::field('mailinglist', 60, 255, $emails) . '</label></p>
<p class="form-note">' . __('Separate multiple email addresses with a semicolon ";"') . '</p>
<p><label for="mailformat">' . __('Report format:') . '</label>' .
form::combo('mailformat', $combo_format, dcCore::app()->activityReport->getSetting('mailformat')) . '</p>
<ul>
<li>' . __('Last report by email:') . ' ' . $last_report . '</li>
<li>' . __('Next report by email:') . ' ' . $next_report . '</li>
</ul>
</div><br class="clear"/>
</div><br class="clear"/>';
if ($super) {
echo '
<div class="fieldset one-box" id="setting_blog"><h4>' . __('Blogs') . '</h4>
<p>' . __('Select blogs to add to report') . '</p>';
$i = $j = 0;
$selected_blogs = dcCore::app()->activityReport->getSetting('blogs');
$blogs = dcCore::app()->getBlogs();
$num_blogs = $blogs->count();
while ($blogs->fetch()) {
$blog_id = dcCore::app()->con->escape($blogs->blog_id);
echo '
<div class="fieldset box">
<p><label class="classic" for="blogs_' . $i . '_">' .
form::checkbox(
['blogs[' . $i . ']', 'blogs_' . $i . '_'],
$blog_id,
in_array($blog_id, $selected_blogs)
) . ' ' .
$blogs->blog_name . ' (' . $blog_id . ')</label></p>
</div>';
$i++;
}
echo '</div>';
} else {
echo form::hidden('blogs[0]', dcCore::app()->blog->id);
}
echo '
<div class="fieldset one-box" id="setting_report"><h4>' . __('Report') . '</h4>
<p>' . __('Select actions by activity type to add to report') . '</p>';
$groups = dcCore::app()->activityReport->getGroups();
$blog_request = dcCore::app()->activityReport->getSetting('requests');
$i = 0;
foreach ($groups as $group_id => $group) {
echo '<div class="fieldset box"><h5>' . __($group['title']) . '</h5>';
foreach ($group['actions'] as $action_id => $action) {
echo '
<p><label class="classic" for="requests_' . $group_id . '_' . $action_id . '_">' .
form::checkbox(
['requests[' . $group_id . '][' . $action_id . ']', 'requests_' . $group_id . '_' . $action_id . '_'],
1,
isset($blog_request[$group_id][$action_id])
) . ' ' . __($action['title']) . '</label></p>';
}
echo '</div>';
}
echo '</div>';
if (1) {
echo '
<div class="fieldset" id="settings"><h4>' . __('Special') . '</h4>
<p><label class="classic" for="send_report_now">' .
form::checkbox('send_report_now', '1', false) . ' ' .
__('Send report now') . '</label></p>
<p><label class="classic" for="delete_report_now">' .
form::checkbox('delete_report_now', '1', false) . ' ' .
__('Delete all logs now') . '</label></p>
</div>';
}
dcCore::app()->activityReport->unsetGlobal();

71
src/Context.php Normal file
View file

@ -0,0 +1,71 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use dcCore;
/**
* Template helper.
*/
class Context
{
/**
* Parse title.
*
* @return string The parsed title
*/
public static function parseTitle(): string
{
if (!dcCore::app()->ctx || !dcCore::app()->ctx->exists('activityreports')) {
return '';
}
$group = dcCore::app()->ctx->__get('activityreports')->activity_group;
$action = dcCore::app()->ctx->__get('activityreports')->activity_action;
if (!ActivityReport::instance()->groups->get($group)->has($action)) {
return '';
}
return __(ActivityReport::instance()->groups->get($group)->get($action)->title);
}
/**
* Parse content.
*
* @return string The parsed content
*/
public static function parseContent(): string
{
if (!dcCore::app()->ctx || !dcCore::app()->ctx->exists('activityreports')) {
return '';
}
$group = dcCore::app()->ctx->__get('activityreports')->activity_group;
$action = dcCore::app()->ctx->__get('activityreports')->activity_action;
$logs = json_decode((string) dcCore::app()->ctx->__get('activityreports')->activity_logs, true);
if (!is_array($logs) || !ActivityReport::instance()->groups->get($group)->has($action)) {
return '';
}
dcCore::app()->initWikiComment();
return dcCore::app()->wikiTransform(vsprintf(
__(ActivityReport::instance()->groups->get($group)->get($action)->message),
$logs
));
}
}

81
src/Format.php Normal file
View file

@ -0,0 +1,81 @@
<?php
/**
* @brief activityReport, 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\activityReport;
/**
* Report format descriptor.
*/
class Format
{
/** @var string $name The name format */
public readonly string $name;
/** @var string $blog_title The blog title format */
public readonly string $blog_title;
/** @var string $group_title The group title format */
public readonly string $group_title;
/** @var string $group_open The group opening format */
public readonly string $group_open;
/** @var string $group_close The group closing format */
public readonly string $group_close;
/** @var string $action The action format */
public readonly string $action;
/** @var string $error The error format */
public readonly string $error;
/** @var string $period_title The period title format */
public readonly string $period_title;
/** @var string $period_open The period opening format */
public readonly string $period_open;
/** @var string $period_close The period closing format */
public readonly string $period_close;
/** @var string $info The info format */
public readonly string $info;
/** @var string $page The page format */
public readonly string $page;
/**
* Constructor sets format id.
*
* @param string $id The format ID
* @param array $format The format values
*/
public function __construct(
public readonly string $id,
array $format
) {
$this->name = $format['name'] ?? __('Plain text');
$this->blog_title = $format['blog_title'] ?? "\n--- %TEXT% ---\n";
$this->group_title = $format['group_title'] ?? "\n-- %TEXT% --\n\n";
$this->group_open = $format['group_open'] ?? '';
$this->group_close = $format['group_close'] ?? '';
$this->action = $format['action'] ?? "- %TIME% : %TEXT%\n";
$this->error = $format['error'] ?? '%TEXT%';
$this->period_title = $format['period_title'] ?? "%TEXT%\n";
$this->period_open = $format['period_open'] ?? '';
$this->period_close = $format['period_close'] ?? '';
$this->info = $format['info'] ?? "%TEXT%\n";
$this->page = $format['page'] ?? "%PERIOD%\n-----------------------------------------------------------\n%TEXT%";
}
}

View file

@ -10,52 +10,63 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
$format = [
'html' => [
'blog_title' => '<h2><a href="%URL%">%TEXT%</a></h2>',
'blog_open' => '',
'blog_close' => '',
'group_title' => '<h3>%TEXT%</h3>',
'group_open' => '<ul>',
'group_close' => '</ul>',
'action' => '<li><em>%TIME%</em><br />%TEXT%</li>',
'error' => '<p>%TEXT%</p>',
'period_title' => '<h1>%TEXT%</h1>',
'period_open' => '<ul>',
'period_close' => '</ul>',
'info' => '<li>%TEXT%</li>',
'page' => '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">' . "\n" .
'<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">' . "\n" .
'<head><title>' . __('Activity report') . '</title>' .
'<style type="text/css">' .
' body { color: #303030; background: #FCFCFC; font-size: 0.7em;font-family: Georgia, Tahoma, Arial, Helvetica, sans-serif; }' .
' a { color: #303030; text-decoration: none; }' .
' h1 { text-align: center; font-size: 2em; }' .
' h2 { color: #303030; text-align:center; }' .
' h3 { color: #7F3F3F; }' .
' li em { color: #303030; }' .
' div.info { color: #3F497F; background-color: #F8F8EB; border: 1px solid #888888; margin: 4px; padding: 4px; }' .
' div.content { color: #3F7F47; background-color: #F8F8EB; border: 1px solid #888888; margin: 4px; padding: 4px; }' .
' div.foot { text-align:center; font-size: 0.9em; }' .
'</style>' .
'</head><body>' .
'<div class="info">%PERIOD%</div><div class="content">%TEXT%</div>' .
'<div class="foot"><p>Powered by <a href="https://github.com/JcDenis/activityReport">activityReport</a></p></div>' .
'</body></html>',
],
'plain' => [
'blog_title' => "\n--- %TEXT% ---\n",
'blog_open' => '',
'blog_close' => '',
'group_title' => "\n-- %TEXT% --\n\n",
'group_open' => '',
'group_close' => '',
'action' => "- %TIME% : %TEXT%\n",
'error' => '%TEXT%',
'period_title' => "%TEXT%\n",
'period_open' => '',
'period_close' => '',
'info' => "%TEXT%\n",
'page' => "%PERIOD%\n-----------------------------------------------------------\n%TEXT%",
],
];
declare(strict_types=1);
namespace Dotclear\Plugin\activityReport;
/**
* Email report formats stack.
*/
class Formats
{
/** @var array<string, Format> $stack The formats stack */
private array $stack = [];
/**
* Chek if a format exists.
*
* @param string $id The format ID
*
* @return bool True if it exists
*/
public function has(string $id): bool
{
return isset($this->stack[$id]);
}
/**
* Add a format.
*
* @param Format $format The format object
*
* @return Formats The formats instance
*/
public function add(Format $format): Formats
{
$this->stack[$format->id] = $format;
return $this;
}
/**
* Get a format.
*
* @param string $id The format ID
*
* @return Format The format descriptor
*/
public function get(string $id): Format
{
return $this->stack[$id] ?? new Format('plain', []);
}
/**
* Get all formats.
*
* @return array<string, Format> The formats stack
*/
public function dump(): array
{
return $this->stack;
}
}

View file

@ -10,165 +10,41 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
if (!defined('ACTIVITY_REPORT_V2')) {
return null;
}
declare(strict_types=1);
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), __DIR__ . '/default-templates/tpl');
dcCore::app()->tpl->addBlock('activityReports', ['activityReportPublicTpl','activityReports']);
dcCore::app()->tpl->addValue('activityReportFeedID', ['activityReportPublicTpl','activityReportFeedID']);
dcCore::app()->tpl->addValue('activityReportTitle', ['activityReportPublicTpl','activityReportTitle']);
dcCore::app()->tpl->addValue('activityReportDate', ['activityReportPublicTpl','activityReportDate']);
dcCore::app()->tpl->addValue('activityReportContent', ['activityReportPublicTpl','activityReportContent']);
namespace Dotclear\Plugin\activityReport;
class activityReportPublicUrl extends dcUrlHandlers
use dcCore;
use dcNsProcess;
/**
* Front end process.
*/
class Frontend extends dcNsProcess
{
public static function feed(?string $args): void
public static function init(): bool
{
if (!preg_match('/^(atom|rss2)\/(.+)$/', $args, $m)) {
self::p404();
static::$init = defined('ACTIVITY_REPORT')
&& My::phpCompliant()
&& My::isInstalled();
return;
}
if (!defined('ACTIVITY_REPORT_V2')) {
self::p404();
return static::$init;
}
return;
}
if (!dcCore::app()->activityReport->getSetting('active')) {
self::p404();
return;
}
$mime = $m[1] == 'atom' ? 'application/atom+xml' : 'application/xml';
if (false === dcCore::app()->activityReport->checkUserCode($m[2])) {
self::p404();
return;
public static function process(): bool
{
if (!static::$init) {
return false;
}
dcCore::app()->ctx->nb_entry_per_page = (int) dcCore::app()->blog->settings->system->nb_post_per_feed;
dcCore::app()->ctx->short_feed_items = (int) dcCore::app()->blog->settings->system->short_feed_items;
dcCore::app()->tpl->setPath(dcCore::app()->tpl->getPath(), implode(DIRECTORY_SEPARATOR, [My::root(), 'default-templates', 'tpl']));
header('X-Robots-Tag: ' . context::robotsPolicy(dcCore::app()->blog->settings->system->robots_policy, ''));
self::serveDocument('activityreport-' . $m[1] . '.xml', $mime);
}
}
class activityReportPublicTpl
{
public static function activityReports($attr, $content)
{
$lastn = 0;
if (isset($attr['lastn'])) {
$lastn = abs((int) $attr['lastn']) + 0;
}
$p = '$_page_number = dcCore::app()->public->getPageNumber(); if ($_page_number < 1) { $_page_number = 1; }' . "\n\$params = array();\n";
if ($lastn > 0) {
$p .= "\$params['limit'] = " . $lastn . ";\n";
} else {
$p .= "\$params['limit'] = dcCore::app()->ctx->nb_entry_per_page;\n";
}
if (!isset($attr['ignore_pagination']) || $attr['ignore_pagination'] == '0') {
$p .= "\$params['limit'] = array(((\$_page_number-1)*\$params['limit']),\$params['limit']);\n";
} else {
$p .= "\$params['limit'] = array(0, \$params['limit']);\n";
}
return
"<?php \n" .
$p .
'dcCore::app()->ctx->activityreport_params = $params; ' . "\n" .
'dcCore::app()->ctx->activityreports = dcCore::app()->activityReport->getLogs($params); unset($params); ' . "\n" .
'while (dcCore::app()->ctx->activityreports->fetch()) : ?>' . $content . '<?php endwhile; ' .
'dcCore::app()->ctx->pop("activityreports"); dcCore::app()->ctx->pop("activityreport_params"); ' . "\n" .
'?>';
}
public static function activityReportFeedID($attr)
{
return
'urn:md5:<?php echo md5(dcCore::app()->ctx->activityreports->blog_id.' .
'dcCore::app()->ctx->activityreports->activity_id.dcCore::app()->ctx->activityreports->activity_dt); ' .
'?>';
}
public static function activityReportTitle($attr)
{
$f = dcCore::app()->tpl->getFilters($attr);
return '<?php echo ' . sprintf($f, 'activityReportContext::parseTitle()') . '; ?>';
}
public static function activityReportContent($attr)
{
$f = dcCore::app()->tpl->getFilters($attr);
return '<?php echo ' . sprintf($f, 'activityReportContext::parseContent()') . '; ?>';
}
public static function activityReportDate($attr)
{
$format = '';
if (!empty($attr['format'])) {
$format = addslashes($attr['format']);
}
$iso8601 = !empty($attr['iso8601']);
$rfc822 = !empty($attr['rfc822']);
$f = dcCore::app()->tpl->getFilters($attr);
if ($rfc822) {
return '<?php echo ' . sprintf($f, 'dt::rfc822(strtotime(dcCore::app()->ctx->activityreports->activity_dt),dcCore::app()->blog->settings->system->blog_timezone)') . '; ?>';
} elseif ($iso8601) {
return '<?php echo ' . sprintf($f, 'dt::iso8601(strtotime(dcCore::app()->ctx->activityreports->activity_dt),dcCore::app()->blog->settings->system->blog_timezone)') . '; ?>';
} elseif (!empty($format)) {
return '<?php echo ' . sprintf($f, "dt::dt2str('" . $format . "',dcCore::app()->ctx->activityreports->activity_dt)") . '; ?>';
}
return '<?php echo ' . sprintf($f, 'dt::dt2str(dcCore::app()->blog->settings->system->date_format,dcCore::app()->ctx->activityreports->activity_dt)') . '; ?>';
}
}
class activityReportContext
{
public static function parseTitle()
{
$groups = dcCore::app()->activityReport->getGroups();
$group = dcCore::app()->ctx->activityreports->activity_group;
$action = dcCore::app()->ctx->activityreports->activity_action;
if (!empty($groups[$group]['actions'][$action]['title'])) {
return __($groups[$group]['actions'][$action]['title']);
}
return '';
}
public static function parseContent()
{
$groups = dcCore::app()->activityReport->getGroups();
$group = dcCore::app()->ctx->activityreports->activity_group;
$action = dcCore::app()->ctx->activityreports->activity_action;
$logs = dcCore::app()->ctx->activityreports->activity_logs;
$logs = dcCore::app()->activityReport->decode($logs);
if (!empty($groups[$group]['actions'][$action]['msg'])) {
dcCore::app()->initWikiComment();
return dcCore::app()->wikiTransform(vsprintf(__($groups[$group]['actions'][$action]['msg']), $logs));
}
return '';
dcCore::app()->tpl->addBlock('activityReports', [Template::class, 'activityReports']);
dcCore::app()->tpl->addValue('activityReportFeedID', [Template::class, 'activityReportFeedID']);
dcCore::app()->tpl->addValue('activityReportTitle', [Template::class, 'activityReportTitle']);
dcCore::app()->tpl->addValue('activityReportDate', [Template::class, 'activityReportDate']);
dcCore::app()->tpl->addValue('activityReportContent', [Template::class, 'activityReportContent']);
return true;
}
}

82
src/Group.php Normal file
View file

@ -0,0 +1,82 @@
<?php
/**
* @brief activityReport, 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\activityReport;
/**
* Actions stack.
*/
class Group
{
/** @var array<string, Action> $stack The actions stack */
private array $stack = [];
/**
* Constructor sets group description.
*
* @param string $id The group ID
* @param string $title The group title
*/
public function __construct(public readonly string $id, public readonly string $title)
{
}
/**
* Chek if a action exists.
*
* @param string $id The action ID
*
* @return bool True if it exists
*/
public function has(string $id): bool
{
return isset($this->stack[$id]);
}
/**
* Add an action.
*
* @param Action $action The action object
*
* @return Group The group instance
*/
public function add(Action $action): Group
{
$this->stack[$action->id] = $action;
return $this;
}
/**
* Get an action.
*
* @param string $id The action ID
*
* @return Action The action descriptor
*/
public function get(string $id): Action
{
return $this->stack[$id] ?? new Action($id, 'undefined', 'undefined', 'undefined', null);
}
/**
* Get all actions.
*
* @return array<string, Action> The actions stack
*/
public function dump(): array
{
return $this->stack;
}
}

72
src/Groups.php Normal file
View file

@ -0,0 +1,72 @@
<?php
/**
* @brief activityReport, 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\activityReport;
/**
* Actions groups stack.
*/
class Groups
{
/** @var array<string, Group> $stack The actions groups stack */
private array $stack = [];
/**
* Chek if a group exists.
*
* @param string $id The group ID
*
* @return bool True if it exists
*/
public function has(string $id): bool
{
return isset($this->stack[$id]);
}
/**
* Add a group.
*
* @param Group $group The group object
*
* @return Groups The groups instance
*/
public function add(Group $group): Groups
{
$this->stack[$group->id] = $group;
return $this;
}
/**
* Get a group.
*
* @param string $id The group ID
*
* @return Group The group descriptor
*/
public function get(string $id): Group
{
return $this->stack[$id] ?? new Group($id, 'undefined');
}
/**
* Get all groups.
*
* @return array<string, Group> The groups stack
*/
public function dump(): array
{
return $this->stack;
}
}

View file

@ -10,53 +10,87 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return null;
declare(strict_types=1);
namespace Dotclear\Plugin\activityReport;
use dbStruct;
use dcCore;
use dcNsProcess;
use Dotclear\Database\Statement\{
DropStatement,
TruncateStatement
};
use Exception;
/**
* Install process.
*/
class Install extends dcNsProcess
{
public static function init(): bool
{
static::$init = defined('DC_CONTEXT_ADMIN')
&& My::phpCompliant()
&& dcCore::app()->newVersion(My::id(), dcCore::app()->plugins->moduleInfo(My::id(), 'version'));
return static::$init;
}
public static function process(): bool
{
if (!static::$init) {
return false;
}
try {
self::beforeGrowUp();
$s = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
$s->{My::ACTIVITY_TABLE_NAME}
->activity_id('bigint', 0, false)
->activity_type('varchar', 32, false, "'" . My::id() . "'")
->blog_id('varchar', 32, true)
->activity_group('varchar', 32, false)
->activity_action('varchar', 32, false)
->activity_logs('text', 0, false)
->activity_dt('timestamp', 0, false, 'now()')
->activity_status('smallint', 0, false, 0)
->primary('pk_activity', 'activity_id')
->index('idx_activity_type', 'btree', 'activity_type')
->index('idx_activity_blog_id', 'btree', 'blog_id')
->index('idx_activity_action', 'btree', 'activity_group', 'activity_action')
->index('idx_activity_status', 'btree', 'activity_status');
(new dbStruct(dcCore::app()->con, dcCore::app()->prefix))->synchronize($s);
return true;
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
return false;
}
}
/**
* Do some action on previous version before install.
*/
private static function beforeGrowUp(): void
{
$current = dcCore::app()->getVersion('activityReport');
// sorry not sorry we restart from scratch
if ($current && version_compare($current, '3.0', '<')) {
$struct = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
if ($struct->tableExists('activity')) {
(new TruncateStatement())->from(dcCore::app()->prefix . 'activity')->truncate();
}
if ($struct->tableExists('activity_settings')) {
(new TruncateStatement())->from(dcCore::app()->prefix . 'activity_settings')->truncate();
(new DropStatement())->from(dcCore::app()->prefix . 'activity_settings')->drop();
}
}
}
}
if (!dcCore::app()->newVersion(
basename(__DIR__),
dcCore::app()->plugins->moduleInfo(basename(__DIR__), 'version')
)) {
return null;
}
try {
$s = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
$s->{initActivityReport::ACTIVITY_TABLE_NAME}
->activity_id('bigint', 0, false)
->activity_type('varchar', 32, false, "'" . basename(__DIR__) . "'")
->blog_id('varchar', 32, true)
->activity_group('varchar', 32, false)
->activity_action('varchar', 32, false)
->activity_logs('text', 0, false)
->activity_dt('timestamp', 0, false, 'now()')
->activity_blog_status('smallint', 0, false, 0)
->activity_super_status('smallint', 0, false, 0)
->primary('pk_activity', 'activity_id')
->index('idx_activity_type', 'btree', 'activity_type')
->index('idx_activity_blog_id', 'btree', 'blog_id')
->index('idx_activity_action', 'btree', 'activity_group', 'activity_action')
->index('idx_activity_blog_status', 'btree', 'activity_blog_status')
->index('idx_activity_super_status', 'btree', 'activity_super_status');
$s->{initActivityReport::SETTING_TABLE_NAME}
->setting_id('varchar', 64, false)
->blog_id('varchar', 32, true)
->setting_type('varchar', 32, false)
->setting_value('text', 0, false)
->unique('uk_activity_setting', 'setting_id', 'blog_id', 'setting_type')
->index('idx_activity_setting_blog_id', 'btree', 'blog_id')
->index('idx_activity_setting_type', 'btree', 'setting_type');
$si = new dbStruct(dcCore::app()->con, dcCore::app()->prefix);
$changes = $si->synchronize($s);
return true;
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
return false;

View file

@ -10,83 +10,114 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return null;
}
declare(strict_types=1);
if (!defined('ACTIVITY_REPORT_V2')) {
return null;
}
namespace Dotclear\Plugin\activityReport;
dcPage::check(dcCore::app()->auth->makePermissions([
dcAuth::PERMISSION_ADMIN,
]));
use ArrayObject;
use adminGenericFilter;
use dcAuth;
use dcCore;
use dcNsProcess;
use dcPage;
use Dotclear\Helper\Html\Form\{
Form,
Hidden,
Para,
Submit,
Text
};
use Exception;
$super = dcCore::app()->auth->isSuperAdmin() && !empty($_REQUEST['super']);
/**
* Manage process (admin logs list).
*/
class Manage extends dcNsProcess
{
public static function init(): bool
{
static::$init = defined('DC_CONTEXT_ADMIN')
&& defined('ACTIVITY_REPORT')
&& My::phpCompliant()
&& dcCore::app()->auth?->check(dcCore::app()->auth->makePermissions([
dcAuth::PERMISSION_ADMIN,
]), dcCore::app()->blog?->id);
if ($super) {
dcCore::app()->activityReport->setGlobal();
}
$logs = dcCore::app()->activityReport->getLogs([]);
if ($super) {
$breadcrumb = [
__('Current blog') => dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['super' => 0]),
'<span class="page-title">' . __('All blogs') . '</span>' => '',
];
} else {
$breadcrumb = ['<span class="page-title">' . __('Current blog') . '</span>' => ''];
if (dcCore::app()->auth->isSuperAdmin()) {
$breadcrumb[__('All blogs')] = dcCore::app()->adminurl->get('admin.plugin.' . basename(__DIR__), ['super' => 1]);
return static::$init;
}
}
echo '<html><head><title>' . __('Activity report') . '</title></head><body>' .
dcPage::breadcrumb(array_merge([__('Activity report') => '', __('Logs') => ''], $breadcrumb), ['hl' => false]) .
dcPage::notices();
if ($logs->isEmpty()) {
echo '<p>' . __('No log') . '</p>';
} else {
echo '
<div class="table-outer"><table><thead>
<tr>
<th>' . __('Action') . '</th>
<th>' . __('Message') . '</th>
<th>' . __('Date') . '</th>';
if ($super) {
echo '<th>' . __('Blog') . '</th>';
}
echo '</tr></thead><tbody>';
while ($logs->fetch()) {
$action = dcCore::app()->activityReport->getGroups($logs->activity_group, $logs->activity_action);
if (empty($action)) {
continue;
public static function process(): bool
{
if (!static::$init) {
return false;
}
$off = $super && $logs->activity_blog_status == 1 ? ' offline' : '';
$date = dt::str(
dcCore::app()->blog->settings->system->date_format . ', ' . dcCore::app()->blog->settings->system->time_format,
strtotime($logs->activity_dt),
dcCore::app()->auth->getInfo('user_tz')
if (!empty($_POST['delete_all_logs']) || !empty($_POST['delete_reported_logs'])) {
try {
ActivityReport::instance()->deleteLogs(!empty($_POST['delete_reported_logs']));
dcPage::addSuccessNotice(__('Logs successfully deleted'));
dcCore::app()->adminurl?->redirect('admin.plugin.' . My::id());
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
}
return true;
}
public static function render(): void
{
if (!static::$init) {
return;
}
$logs = $counter = $list = null;
$filter = new adminGenericFilter(dcCore::app(), My::id());
$params = new ArrayObject($filter->params());
try {
$logs = ActivityReport::instance()->getLogs($params);
$counter = ActivityReport::instance()->getLogs($params, true);
if (!is_null($logs) && !is_null($counter)) {
$list = new ManageList(dcCore::app(), $logs, $counter->f(0));
}
} catch (Exception $e) {
dcCore::app()->error->add($e->getMessage());
}
dcPage::openModule(
My::name(),
$filter->js((string) dcCore::app()->adminurl?->get('admin.plugin.' . My::id())) .
dcPage::jsJson(My::id(), ['confirm_delete' => __('Are you sure you want to delete logs?')]) .
dcPage::jsModuleLoad(My::id() . '/js/backend.js') .
# --BEHAVIOR-- activityReportListHeader --
dcCore::app()->callBehavior('activityReportListHeader')
);
$msg = vsprintf(__($action['msg']), dcCore::app()->activityReport->decode($logs->activity_logs));
echo '
<tr class="line' . $off . '">
<td class="nowrap">' . __($action['title']) . '</td>
<td class="maximal">' . $msg . '</td>
<td class="nowrap">' . $date . '</td>';
if ($super) {
echo '<td class="nowrap">' . $logs->blog_id . '</td>';
echo
dcPage::breadcrumb([
__('Plugins') => '',
My::name() => '',
]) .
dcPage::notices();
if (!is_null($list)) {
$filter->display('admin.plugin.' . My::id(), (new Hidden('p', My::id()))->render());
$list->logsDisplay($filter, '%s');
}
echo '</tr>';
}
echo '</tbody></table></div>';
}
dcCore::app()->activityReport->unsetGlobal();
echo '</body></html>';
if (!is_null($logs) && !$logs->isEmpty()) {
echo
(new Form('form-logs'))->method('post')->action(dcCore::app()->admin->getPageURL())->fields([
(new Para())->class('right')->separator(' ')->items([
(new Submit('delete_all_logs'))->class('delete')->value(__('Delete all aticivity logs')),
(new Submit('delete_reported_logs'))->class('delete')->value(__('Delete all allready reported logs')),
dcCore::app()->formNonce(false),
]),
])->render();
}
dcPage::closeModule();
}
}

102
src/ManageList.php Normal file
View file

@ -0,0 +1,102 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use ArrayObject;
use adminGenericFilter;
use adminGenericList;
use dcCore;
use dcPager;
use Dotclear\Helper\Date;
/**
* Logs admin list helper.
*/
class ManageList extends adminGenericList
{
public function logsDisplay(adminGenericFilter $filter, string $enclose_block = ''): void
{
if (!$this->rs || $this->rs->isEmpty()) {
if ($filter->show()) {
echo '<p><strong>' . __('No log matches the filter') . '</strong></p>';
} else {
echo '<p><strong>' . __('No log') . '</strong></p>';
}
} else {
$pager = new dcPager((int) $filter->value('page'), (int) $this->rs_count, (int) $filter->value('nb'), 10);
$pager->var_page = 'page';
$html_block = '<div class="table-outer"><table><caption>' . (
$filter->show() ?
sprintf(__('List of %s logs matching the filter.'), $this->rs_count) :
sprintf(__('List of %s logs.'), $this->rs_count)
) . '</caption>';
$cols = new ArrayObject([
'activity_group' => '<th scope="col" class="nowrap">' . __('Group') . '</th>',
'activity_action' => '<th scope="col" class="nowrap">' . __('Action') . '</th>',
'activity_logs' => '<th scope="col" class="nowrap">' . __('Message') . '</th>',
'activity_date' => '<th scope="col" class="nowrap">' . __('Date') . '</th>',
'activity_status' => '<th scope="col" class="nowrap">' . __('Status') . '</th>',
]);
$this->userColumns(My::id(), $cols);
$html_block .= '<tr>' . implode(iterator_to_array($cols)) . '</tr>%s</table>%s</div>';
if ($enclose_block) {
$html_block = sprintf($enclose_block, $html_block);
}
$blocks = explode('%s', $html_block);
echo $pager->getLinks() . $blocks[0];
while ($this->rs->fetch()) {
echo $this->logsLine();
}
echo $blocks[1] . $blocks[2] . $pager->getLinks();
}
}
private function logsLine(): string
{
$offline = (int) $this->rs->f('activity_status') == ActivityReport::STATUS_REPORTED ? ' offline' : '';
$group = ActivityReport::instance()->groups->get($this->rs->f('activity_group'));
$action = $group->get($this->rs->f('activity_action'));
$message = json_decode((string) $this->rs->f('activity_logs'), true);
$message = $message[0] == 'undefined' ? __('undefined') : vsprintf(__($action->message), $message);
$date = Date::str(
dcCore::app()->blog?->settings->get('system')->get('date_format') . ', ' . dcCore::app()->blog?->settings->get('system')->get('time_format'),
(int) strtotime((string) $this->rs->f('activity_dt')),
dcCore::app()->auth?->getInfo('user_tz')
);
$status = (int) $this->rs->f('activity_status') == ActivityReport::STATUS_PENDING ? __('pending') : __('reported');
$cols = new ArrayObject([
'activity_group' => '<td class="nowrap">' . __($group->title) . '</td>',
'activity_action' => '<td class="nowrap">' . __($action->title) . '</td>',
'activity_logs' => '<td class="maximal">' . $message . '</td>',
'activity_date' => '<td class="nowrap">' . $date . '</td>',
'activity_status' => '<td class="nowrap">' . $status . '</td>',
]);
$this->userColumns(My::id(), $cols);
return
'<tr class="line ' . $offline . '" id="l' . $this->rs->f('activity_id') . '">' .
implode(iterator_to_array($cols)) .
'</tr>';
}
}

77
src/My.php Normal file
View file

@ -0,0 +1,77 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use dcCore;
/**
* Module definitions
*/
class My
{
/** @var string Required php version */
public const PHP_MIN = '8.1';
/** @var string Activity database table name */
public const ACTIVITY_TABLE_NAME = 'activity';
/** @var string Cache sub directory name */
public const CACHE_DIR_NAME = 'activityreport';
/** @var int Incremental version by breaking changes */
public const COMPATIBILITY_VERSION = 3;
/**
* This module id.
*/
public static function id(): string
{
return basename(dirname(__DIR__));
}
/**
* This module name.
*/
public static function name(): string
{
return __((string) dcCore::app()->plugins->moduleInfo(self::id(), 'name'));
}
/**
* This module root.
*/
public static function root(): string
{
return dirname(__DIR__);
}
/**
* Check is module is trully installed.
*
* Required as table structrue has changed
*/
public static function isInstalled(): bool
{
return dcCore::app()->getVersion(self::id()) == dcCore::app()->plugins->moduleInfo(self::id(), 'version');
}
/**
* Check php version.
*/
public static function phpCompliant(): bool
{
return version_compare(phpversion(), self::PHP_MIN, '>=');
}
}

View file

@ -10,30 +10,58 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_RC_PATH')) {
return null;
}
declare(strict_types=1);
Clearbricks::lib()->autoload([
'activityReport' => __DIR__ . '/inc/class.activity.report.php',
'activityReportBehaviors' => __DIR__ . '/inc/class.activity.report.behaviors.php',
]);
namespace Dotclear\Plugin\activityReport;
try {
if (!defined('ACTIVITY_REPORT_V2')) {
dcCore::app()->__set('activityReport', new activityReport());
use dcCore;
use dcNsProcess;
use Exception;
dcCore::app()->url->register(
basename(__DIR__),
'reports',
'^reports/((atom|rss2)/(.+))$',
['activityReportPublicUrl', 'feed']
);
/**
* Prepend process.
*/
class Prepend extends dcNsProcess
{
public static function init(): bool
{
static::$init = defined('DC_RC_PATH')
&& My::phpCompliant()
&& My::isInstalled();
define('ACTIVITY_REPORT_V2', true);
activityReportBehaviors::registerBehaviors();
return static::$init;
}
public static function process(): bool
{
if (!static::$init) {
return false;
}
if (defined('ACTIVITY_REPORT')) {
return true;
}
try {
// launch once activity report stuff
ActivityReport::instance();
// regirster activity feed URL
dcCore::app()->url->register(
My::id(),
'reports',
'^reports/((atom|rss2)/(.+))$',
[UrlHandler::class, 'feed']
);
// declare report open
define('ACTIVITY_REPORT', My::COMPATIBILITY_VERSION);
// register predefined activities scan
ActivityBehaviors::register();
} catch (Exception $e) {
}
return true;
}
} catch (Exception $e) {
//throw new Exception('Failed to launch activityReport');
}

113
src/Settings.php Normal file
View file

@ -0,0 +1,113 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use dcCore;
use Exception;
/**
* Module settings helper.
*/
class Settings
{
/** @var bool $feed_active The activity feed activation */
public readonly bool $feed_active;
/** @var int $obsolete The logs obsolete time */
public readonly int $obsolete;
/** @var int $interval The report interval time */
public readonly int $interval;
/** @var int $lastreport The last report time */
public readonly int $lastreport;
/** @var array $mailinglist The mailing list */
public readonly array $mailinglist;
/** @var string $mailformat The mail content format */
public readonly string $mailformat;
/** @var string $date format The date format */
public readonly string $dateformat;
/** @var array $requests The selected actions list to report */
public readonly array $requests;
/**
* Constructor sets settings properties.
*/
public function __construct()
{
if (dcCore::app()->blog === null) {
throw new Exception('Blog is not set');
}
$this->feed_active = (bool) ($this->get('feed_active') ?? false);
$this->obsolete = (int) ($this->get('obsolete') ?? 2419200);
$this->interval = (int) ($this->get('interval') ?? 86400);
$this->lastreport = (int) ($this->get('lastreport') ?? 0);
$this->mailinglist = (array) ($this->get('mailinglist') ?? []);
$this->mailformat = (string) ($this->get('mailformat') ?? 'plain');
$this->dateformat = (string) ($this->get('dateformat') ?? '%Y-%m-%d %H:%M:%S');
$this->requests = (array) ($this->get('requests') ?? []);
}
/**
* Dump properties.
*
* @return array<string, mixed> The settings properties
*/
public function dump(): array
{
$vars = get_class_vars(__CLASS__);
return $vars ? $vars : [];
}
/**
* Set a setting in database.
*
* Setting is modified in database but not in script !
*
* @param string $key The setting key
* @param mixed $value The setting value
*/
public function set(string $key, mixed $value): void
{
if (property_exists($this, $key) && gettype($value) == gettype($this->{$key})) {
dcCore::app()->blog?->settings->get(My::id())->put(
$key,
$value,
gettype($value),
null,
true,
false
);
}
}
/**
* Get a setting from database.
*
* @param string $key The setting key
*
* @return mixed The setting value
*/
private function get(string $key): mixed
{
return dcCore::app()->blog?->settings->get(My::id())->get($key);
}
}

161
src/Template.php Normal file
View file

@ -0,0 +1,161 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use ArrayObject;
use dcCore;
use Dotclear\Helper\Date;
/**
* Template blocs and values.
*/
class Template
{
/**
* tpl:activityReports [attributes] : Activity report logs (tpl block)
*
* attributes:
*
* - lastn integer Limit to last n logs
* - ingnore_pagination 1|0 Ignore pagination paramaters
*
* @param ArrayObject $attr The attributes
* @param string $content The content
*
* @return string The code
*/
public static function activityReports(ArrayObject $attr, string $content): string
{
$lastn = 0;
if (isset($attr['lastn'])) {
$lastn = abs((int) $attr['lastn']) + 0;
}
$p = '$_page_number = dcCore::app()->public->getPageNumber(); if ($_page_number < 1) { $_page_number = 1; }' . "\n\$params = new ArrayObject();\n";
if ($lastn > 0) {
$p .= "\$params['limit'] = " . $lastn . ";\n";
} else {
$p .= "\$params['limit'] = dcCore::app()->ctx->nb_entry_per_page;\n";
}
if (!isset($attr['ignore_pagination']) || $attr['ignore_pagination'] == '0') {
$p .= "\$params['limit'] = array(((\$_page_number-1)*\$params['limit']),\$params['limit']);\n";
} else {
$p .= "\$params['limit'] = array(0, \$params['limit']);\n";
}
return
"<?php \n" .
$p .
'dcCore::app()->ctx->activityreport_params = $params; ' . "\n" .
'dcCore::app()->ctx->activityreports = ' . ActivityReport::class . '::instance()->getLogs($params); unset($params); ' . "\n" .
'while (dcCore::app()->ctx->activityreports->fetch()) : ?>' . $content . '<?php endwhile; ' .
'dcCore::app()->ctx->pop("activityreports"); dcCore::app()->ctx->pop("activityreport_params"); ' . "\n" .
'?>';
}
/**
* tpl:activityReportFeedID [attributes] : Activity report feed ID (tpl value)
*
* attributes:
*
* - any filters See self::getFilters()
*
* @param ArrayObject $attr The attributes
*
* @return string The code
*/
public static function activityReportFeedID(ArrayObject $attr): string
{
return
'urn:md5:<?php echo md5(dcCore::app()->ctx->activityreports->blog_id.' .
'dcCore::app()->ctx->activityreports->activity_id.dcCore::app()->ctx->activityreports->activity_dt); ' .
'?>';
}
/**
* tpl:activityReportTitle [attributes] : Activity report log title (tpl value)
*
* attributes:
*
* - any filters See self::getFilters()
*
* @param ArrayObject $attr The attributes
*
* @return string The code
*/
public static function activityReportTitle(ArrayObject $attr): string
{
$f = dcCore::app()->tpl->getFilters($attr);
return '<?php echo ' . sprintf($f, Context::class . '::parseTitle()') . '; ?>';
}
/**
* tpl:activityReportContent [attributes] : Activity report log message (tpl value)
*
* attributes:
*
* - any filters See self::getFilters()
*
* @param ArrayObject $attr The attributes
*
* @return string The code
*/
public static function activityReportContent(ArrayObject $attr): string
{
$f = dcCore::app()->tpl->getFilters($attr);
return '<?php echo ' . sprintf($f, Context::class . '::parseContent()') . '; ?>';
}
/**
* tpl:activityReportDate [attributes] : Activity report log date (tpl value)
*
* attributes:
*
* - format Use Date::str() (if iso8601 nor rfc822 were specified default to %Y-%m-%d %H:%M:%S)
* - iso8601 (1|0) Use Date::iso8601()
* - rfc822 (1|0) Use Date::rfc822()
* - any filters See self::getFilters()
*
* @param ArrayObject $attr The attributes
*
* @return string The code
*/
public static function activityReportDate(ArrayObject $attr): string
{
$format = '';
if (!empty($attr['format'])) {
$format = addslashes($attr['format']);
}
$iso8601 = !empty($attr['iso8601']);
$rfc822 = !empty($attr['rfc822']);
$f = dcCore::app()->tpl->getFilters($attr);
if ($rfc822) {
return '<?php echo ' . sprintf($f, Date::class . '::rfc822(strtotime(dcCore::app()->ctx->activityreports->activity_dt),dcCore::app()->blog->settings->system->blog_timezone)') . '; ?>';
} elseif ($iso8601) {
return '<?php echo ' . sprintf($f, Date::class . '::iso8601(strtotime(dcCore::app()->ctx->activityreports->activity_dt),dcCore::app()->blog->settings->system->blog_timezone)') . '; ?>';
} elseif (!empty($format)) {
return '<?php echo ' . sprintf($f, Date::class . "::dt2str('" . $format . "',dcCore::app()->ctx->activityreports->activity_dt)") . '; ?>';
}
return '<?php echo ' . sprintf($f, Date::class . '::dt2str(dcCore::app()->blog->settings->system->date_format,dcCore::app()->ctx->activityreports->activity_dt)') . '; ?>';
}
}

View file

@ -10,72 +10,78 @@
* @copyright Jean-Christian Denis
* @copyright GPL-2.0 https://www.gnu.org/licenses/gpl-2.0.html
*/
if (!defined('DC_CONTEXT_ADMIN')) {
return null;
declare(strict_types=1);
namespace Dotclear\Plugin\activityReport;
use dcCore;
use dcNsProcess;
use Dotclear\Plugin\Uninstaller\Uninstaller;
/**
* Uninstall process.
*
* Using plugin Uninstaller
*/
class Uninstall extends dcNsProcess
{
public static function init(): bool
{
static::$init = defined('DC_CONTEXT_ADMIN');
return static::$init;
}
public static function process(): bool
{
if (!static::$init || !dcCore::app()->plugins->moduleExists('Uninstaller')) {
return false;
}
Uninstaller::instance()
->addUserAction(
'tables',
'delete',
My::ACTIVITY_TABLE_NAME
)
->addUserAction(
'settings',
'delete_all',
My::id()
)
->addUserAction(
'versions',
'delete',
My::id()
)
->addUserAction(
'plugins',
'delete',
My::id()
)
->addDirectAction(
'tables',
'delete',
My::ACTIVITY_TABLE_NAME
)
->addDirectAction(
'settings',
'delete_all',
My::id()
)
->addDirectAction(
'versions',
'delete',
My::id()
)
->addDirectAction(
'plugins',
'delete',
My::id()
)
;
// no custom action
return false;
}
}
$this->addUserAction(
/* type */
'tables',
/* action */
'delete',
/* ns */
initActivityReport::ACTIVITY_TABLE_NAME,
/* description */
sprintf(__('delete %s table'), '"activity"')
);
$this->addUserAction(
/* type */
'tables',
/* action */
'delete',
/* ns */
initActivityReport::SETTING_TABLE_NAME,
/* description */
sprintf(__('delete %s table'), '"activity_setting"')
);
$this->addUserAction(
/* type */
'plugins',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
__('delete plugin files')
);
$this->addUserAction(
/* type */
'versions',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
__('delete the version number')
);
$this->addDirectAction(
/* type */
'versions',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
sprintf(__('delete %s version number'), basename(__DIR__))
);
$this->addDirectAction(
/* type */
'plugins',
/* action */
'delete',
/* ns */
basename(__DIR__),
/* description */
sprintf(__('delete %s plugin files'), basename(__DIR__))
);

56
src/UrlHandler.php Normal file
View file

@ -0,0 +1,56 @@
<?php
/**
* @brief activityReport, 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\activityReport;
use context;
use dcCore;
use dcUrlHandlers;
/**
* Frontend URL handler.
*/
class UrlHandler extends dcUrlHandlers
{
/**
* Get activity logs feed.
*
* @param null|string $args The URL arguments
*/
public static function feed(?string $args): void
{
// no context or wrong URL args or module no loaded or report unactive
if (!dcCore::app()->ctx
|| !preg_match('/^(atom|rss2)\/(.+)$/', (string) $args, $m)
|| !defined('ACTIVITY_REPORT')
|| !ActivityReport::instance()->settings->feed_active
) {
self::p404();
}
// get type of feed
$mime = $m[1] == 'atom' ? 'application/atom+xml' : 'application/xml';
if (false === ActivityReport::instance()->checkUserCode($m[2])) {
self::p404();
}
// feed limits
dcCore::app()->ctx->__set('nb_entry_per_page', (int) dcCore::app()->blog?->settings->get('system')->get('nb_post_per_feed'));
dcCore::app()->ctx->__set('short_feed_items', (int) dcCore::app()->blog?->settings->get('system')->get('short_feed_items'));
// serve activity feed template
header('X-Robots-Tag: ' . context::robotsPolicy(dcCore::app()->blog?->settings->get('system')->get('robots_policy'), ''));
self::serveDocument('activityreport-' . $m[1] . '.xml', $mime);
}
}