Browse Source

Base du plugin Pushsubscribers permettant de gérer des inscriptions et envois à des pushs. Les tables nécessaires aux inscriptions et envois en masse. Une surcharge (temporaire espérons) du plugin Offline ajoutant des pipelines permettant de complérer les JS d'installation et de service worker. Arrive ensuite la gestion des listes/contextes et des envois.

pull/1/head
RastaPopoulos 6 months ago
commit
a9b70ab488
  1. 150
      action/api_offline.php
  2. 66
      action/api_pushsubscription.php
  3. 91
      action/supprimer_pushlist.php
  4. 91
      action/supprimer_pushsubscriber.php
  5. 51
      action/tester_pushsubscriber.php
  6. 189
      base/pushsubscribers.php
  7. 5
      composer.json
  8. 1030
      composer.lock
  9. 1
      formulaires/configurer_pushsubscribers.html
  10. 132
      formulaires/configurer_pushsubscribers.php
  11. 29
      formulaires/editer_push.html
  12. 124
      formulaires/editer_push.php
  13. 23
      formulaires/editer_pushlist.html
  14. 124
      formulaires/editer_pushlist.php
  15. 29
      formulaires/editer_pushsubscriber.html
  16. 124
      formulaires/editer_pushsubscriber.php
  17. 91
      inc/pushsubscribers.php
  18. 70
      javascript/pushsubscribers.install.js
  19. 84
      javascript/pushsubscribers.sw.js
  20. 14
      lang/paquet-pushsubscribers_fr.php
  21. 49
      lang/push_fr.php
  22. 47
      lang/pushlist_fr.php
  23. 49
      lang/pushsubscriber_fr.php
  24. 20
      lang/pushsubscribers_fr.php
  25. 35
      paquet.xml
  26. 27
      prive/objets/contenu/push.html
  27. 17
      prive/objets/contenu/pushlist.html
  28. 27
      prive/objets/contenu/pushsubscriber.html
  29. 34
      prive/objets/liste/pushlists.html
  30. 39
      prive/objets/liste/pushs.html
  31. 36
      prive/objets/liste/pushsubscribers.html
  32. 7
      prive/squelettes/contenu/configurer_pushsubscribers.html
  33. 60
      prive/squelettes/contenu/pushsubscriber.html
  34. 11
      prive/squelettes/contenu/pushsubscribers.html
  35. BIN
      prive/themes/spip/images/push-12.png
  36. BIN
      prive/themes/spip/images/push-16.png
  37. BIN
      prive/themes/spip/images/push-24.png
  38. BIN
      prive/themes/spip/images/push-32.png
  39. BIN
      prive/themes/spip/images/push-new-16.png
  40. BIN
      prive/themes/spip/images/pushlist-12.png
  41. BIN
      prive/themes/spip/images/pushlist-16.png
  42. BIN
      prive/themes/spip/images/pushlist-24.png
  43. BIN
      prive/themes/spip/images/pushlist-32.png
  44. BIN
      prive/themes/spip/images/pushlist-new-16.png
  45. BIN
      prive/themes/spip/images/pushsubscriber-12.png
  46. BIN
      prive/themes/spip/images/pushsubscriber-16.png
  47. BIN
      prive/themes/spip/images/pushsubscriber-24.png
  48. BIN
      prive/themes/spip/images/pushsubscriber-32.png
  49. BIN
      prive/themes/spip/images/pushsubscriber-new-16.png
  50. 1
      prive/themes/spip/images/pushsubscribers-xx.svg
  51. 65
      pushsubscribers_administrations.php
  52. 111
      pushsubscribers_autorisations.php
  53. 54
      pushsubscribers_pipelines.php
  54. 7
      vendor/autoload.php
  55. 20
      vendor/brick/math/LICENSE
  56. 16
      vendor/brick/math/SECURITY.md
  57. 35
      vendor/brick/math/composer.json
  58. 40
      vendor/brick/math/psalm-baseline.xml
  59. 56
      vendor/brick/math/psalm.xml
  60. 184
      vendor/brick/math/random-tests.php
  61. 855
      vendor/brick/math/src/BigDecimal.php
  62. 1134
      vendor/brick/math/src/BigInteger.php
  63. 566
      vendor/brick/math/src/BigNumber.php
  64. 479
      vendor/brick/math/src/BigRational.php
  65. 41
      vendor/brick/math/src/Exception/DivisionByZeroException.php
  66. 27
      vendor/brick/math/src/Exception/IntegerOverflowException.php
  67. 14
      vendor/brick/math/src/Exception/MathException.php
  68. 12
      vendor/brick/math/src/Exception/NegativeNumberException.php
  69. 35
      vendor/brick/math/src/Exception/NumberFormatException.php
  70. 21
      vendor/brick/math/src/Exception/RoundingNecessaryException.php
  71. 756
      vendor/brick/math/src/Internal/Calculator.php
  72. 92
      vendor/brick/math/src/Internal/Calculator/BcMathCalculator.php
  73. 156
      vendor/brick/math/src/Internal/Calculator/GmpCalculator.php
  74. 616
      vendor/brick/math/src/Internal/Calculator/NativeCalculator.php
  75. 107
      vendor/brick/math/src/RoundingMode.php
  76. 445
      vendor/composer/ClassLoader.php
  77. 21
      vendor/composer/LICENSE
  78. 9
      vendor/composer/autoload_classmap.php
  79. 13
      vendor/composer/autoload_files.php
  80. 9
      vendor/composer/autoload_namespaces.php
  81. 23
      vendor/composer/autoload_psr4.php
  82. 70
      vendor/composer/autoload_real.php
  83. 119
      vendor/composer/autoload_static.php
  84. 1046
      vendor/composer/installed.json
  85. 38
      vendor/fgrosse/phpasn1/CHANGELOG.md
  86. 19
      vendor/fgrosse/phpasn1/LICENSE
  87. 167
      vendor/fgrosse/phpasn1/README.md
  88. 47
      vendor/fgrosse/phpasn1/composer.json
  89. 355
      vendor/fgrosse/phpasn1/lib/ASN1/ASNObject.php
  90. 136
      vendor/fgrosse/phpasn1/lib/ASN1/AbstractString.php
  91. 78
      vendor/fgrosse/phpasn1/lib/ASN1/AbstractTime.php
  92. 63
      vendor/fgrosse/phpasn1/lib/ASN1/Base128.php
  93. 35
      vendor/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php
  94. 37
      vendor/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php
  95. 50
      vendor/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php
  96. 191
      vendor/fgrosse/phpasn1/lib/ASN1/Construct.php
  97. 15
      vendor/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php
  98. 29
      vendor/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php
  99. 131
      vendor/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php
  100. 339
      vendor/fgrosse/phpasn1/lib/ASN1/Identifier.php

150
action/api_offline.php

@ -0,0 +1,150 @@
<?php
/**
* Produire les JS de gestion du offline
*
* @plugin Offline
* @copyright 2018
* @author Cedric
* @licence GNU/GPL
* @package SPIP\Offline\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* @param null $arg
* @param bool $return
* @param null $cached_or_refresh
* par defaut null car si un fichier existe il sera pris par le .htaccess et donc on arrive la que par appel explicite
* @return string
*/
function action_api_offline_dist($arg = null, $return = false, $cached_or_refresh = null) {
if (is_null($arg)) {
$arg = _request('arg');
}
if ($cached_or_refresh === 'cache'
and file_exists($f = _DIR_VAR . 'offline/' . $arg)) {
lire_fichier($f, $t);
}
else {
include_spip('inc/offline');
$quoi = preg_replace(',\W+,', '_', $arg);
$api_offline_quoi = charger_fonction('api_offline_' . $quoi, 'action');
$t = $api_offline_quoi($cached_or_refresh === 'refresh');
// si on est pas en mode debug on cache le fichier qui sera servi ensuite directement par apache
// via regexp
if (!defined('_OFFLINE_DEBUG') or !_OFFLINE_DEBUG) {
// secu : on n'ecrit que des fichiers de la forme xxxxx.yyy
if (preg_match(",^\w+\.(\w+)$,", $arg, $m)) {
if (!function_exists('minifier')) {
include_spip('compresseur_fonctions');
}
$t = minifier($t, $m[1]);
$t = str_replace("\n}","}", $t);
$t = str_replace("\n.",".", $t);
$t = str_replace("\n;",";", $t);
$t = str_replace(",\n",",", $t);
$t = str_replace(";\n",";", $t);
$t = str_replace("{\n","{", $t);
$t = str_replace("(\n","(", $t);
$t = str_replace("[\n","[", $t);
$cache_file = sous_repertoire(_DIR_VAR, 'offline') . $arg;
offline_ecrire_fichier_statique_versionne($cache_file, $t);
}
}
}
if ($return) {
return $t;
}
$c = $GLOBALS['meta']['charset'];
$content_type = 'text/plain';
if (substr($arg,-3) === '.js') {
$content_type = 'application/javascript';
}
elseif (substr($arg,-5) === '.json') {
$content_type = 'application/json';
}
header('Content-Type: ' . $content_type . '; charset=' . $c);
echo $t;
}
function action_api_offline_install_js_dist($force_refresh = false) {
$config = offline_config_js($force_refresh);
$debug = false;
if (isset($config['debug']) && $config['debug']) {
$debug = true;
$c = $config;
}
else {
// le offlineConfig du corps de page n'est pas partage avec celui du service worker
// donc hors debug on y envoie que ce qui est utilise par l'installation
$c = array(
"swUrl" => $config["swUrl"],
"swOptions" => $config["swOptions"],
"cacheName" => $config["cacheName"],
);
}
$serviceworker_install_js = pipeline(
'serviceworker_install_js',
array(
'javascript/offline.install.utils.js',
$debug ? 'javascript/offline.install.debug.js' : '',
'javascript/offline.install.js',
)
);
return offline_build_jslist($c, $serviceworker_install_js);
}
function action_api_offline_sw_js_dist($force_refresh = false) {
$config = offline_config_js($force_refresh);
$serviceworker_sw_js = pipeline(
'serviceworker_sw_js',
array(
'javascript/offline.sw.utils.js',
'javascript/offline.sw.caching.js',
'javascript/offline.sw.manager.js',
'javascript/offline.sw.js',
)
);
return offline_build_jslist($config, $serviceworker_sw_js);
}
function action_api_offline_uninstall_js_dist($force_refresh = false) {
$config = array();
$serviceworker_uninstall_js = pipeline(
'serviceworker_uninstall_js',
array(
'javascript/offline.uninstall.js',
)
);
return offline_build_jslist($config, $serviceworker_uninstall_js);
}
function action_api_offline_urlsdownload_json_dist() {
$objet = _request('objet');
$id_objet = _request('id_objet');
$file_urls_load = offline_filename_urls_to_load_objet($objet, $id_objet);
if (!file_exists($file_urls_load) or !$urls = file_get_contents($file_urls_load)) {
return '[]';
}
$urls = explode("\n", $urls);
return json_encode($urls);
}

66
action/api_pushsubscription.php

@ -0,0 +1,66 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('base/abstract_sql');
include_spip('action/editer_objet');
include_spip('inc/autoriser');
include_spip('inc/config');
include_spip('inc/session');
function action_api_pushsubscription_dist() {
// On récupère les infos
$action = _request('arg');
$endpoint = _request('endpoint');
$keys = _request('keys');
$auth = $keys['auth'];
$p256dh = $keys['p256dh'];
$vapid_public = lire_config('pushsubscribers/vapid_public');
if (
in_array($action, array('create', 'update', 'delete'))
and $endpoint and $auth and $p256dh
) {
// On cherche si le endpoint existe déjà
$id_pushsubscriber = intval(sql_getfetsel('id_pushsubscriber', 'spip_pushsubscribers', 'endpoint = '.sql_quote($endpoint)));
// Si c'est une demande de création ou update, c'est un peu pareil
if ($action != 'delete') {
// S'il n'existait pas déjà, on le crée
if (!$id_pushsubscriber) {
$id_pushsubscriber = objet_inserer('pushsubscriber', 0, array('date_creation'=>date('Y-m-d H:i:s')));
}
// On met à jour
autoriser_exception('instituer', 'pushsubscriber', $id_pushsubscriber, true);
$reponse = objet_modifier(
'pushsubscriber', $id_pushsubscriber,
array(
'endpoint' => $endpoint,
'id_auteur' => intval(session_get('id_auteur')),
'auth' => $auth,
'p256dh' => $p256dh,
'vapid_public' => $vapid_public,
'statut' => 'valide',
)
);
autoriser_exception('instituer', 'pushsubscriber', $id_pushsubscriber, false);
}
// Si c'est pour supprimer
elseif ($id_pushsubscriber) {
autoriser_exception('instituer', 'pushsubscriber', $id_pushsubscriber, true);
$reponse = objet_modifier(
'pushsubscriber', $id_pushsubscriber,
array(
'statut' => 'poubelle',
)
);
autoriser_exception('instituer', 'pushsubscriber', $id_pushsubscriber, false);
}
return array($id_pushsubscriber, $reponse);
}
}

91
action/supprimer_pushlist.php

@ -0,0 +1,91 @@
<?php
/**
* Utilisation de l'action supprimer pour l'objet pushlist
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Action pour supprimer un·e pushlist
*
* Vérifier l'autorisation avant d'appeler l'action.
*
* @param null|int $arg
* Identifiant à supprimer.
* En absence de id utilise l'argument de l'action sécurisée.
**/
function action_supprimer_pushlist_dist($arg=null) {
$need_confirm = false;
if (is_null($arg)){
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
$need_confirm = true;
}
$arg = intval($arg);
if ($need_confirm){
$ok = confirmer_supprimer_pushlist_avant_action(_T('pushlist:confirmer_supprimer_pushlist'), _T('item_oui') . '! ' . _T('pushlist:supprimer_pushlist'));
}
// cas suppression
if (autoriser('supprimer', 'pushlist', $arg)) {
if ($arg) {
$objet = sql_fetsel('*', 'spip_pushlists', 'id_pushlist=' . sql_quote($arg));
$qui = (!empty($GLOBALS['visiteur_session']['id_auteur']) ? 'auteur #' . $GLOBALS['visiteur_session']['id_auteur'] : 'IP ' . $GLOBALS['ip']);
spip_log("SUPPRESSION pushlist#$arg par $qui : " . json_encode($objet), "suppressions" . _LOG_INFO_IMPORTANTE);
sql_delete('spip_pushlists', 'id_pushlist=' . sql_quote($arg));
// invalider le cache
include_spip('inc/invalideur');
suivre_invalideur("id='pushlist/$arg'");
}
else {
spip_log("action_supprimer_pushlist_dist $arg pas compris");
}
}
}
/**
* Confirmer avant suppression si on arrive par un bouton action
* @param string $titre
* @param string $titre_bouton
* @param string|null $url_action
* @return bool
*/
function confirmer_supprimer_pushlist_avant_action($titre, $titre_bouton, $url_action=null) {
if (!$url_action) {
$url_action = self();
$action = _request('action');
$url_action = parametre_url($url_action, 'action', $action, '&');
}
else {
$action = parametre_url($url_action, 'action');
}
$arg = parametre_url($url_action, 'arg');
$confirm = md5("$action:$arg:".realpath(__FILE__));
if (_request('confirm_action') === $confirm) {
return true;
}
$url_confirm = parametre_url($url_action, "confirm_action", $confirm, '&');
include_spip("inc/filtres");
$bouton_action = bouton_action($titre_bouton, $url_confirm);
$corps = "<div style='text-align:center;'>$bouton_action</div>";
include_spip("inc/minipres");
echo minipres($titre,$corps);
exit;
}

91
action/supprimer_pushsubscriber.php

@ -0,0 +1,91 @@
<?php
/**
* Utilisation de l'action supprimer pour l'objet pushsubscriber
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Action pour supprimer un·e pushsubscriber
*
* Vérifier l'autorisation avant d'appeler l'action.
*
* @param null|int $arg
* Identifiant à supprimer.
* En absence de id utilise l'argument de l'action sécurisée.
**/
function action_supprimer_pushsubscriber_dist($arg=null) {
$need_confirm = false;
if (is_null($arg)){
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
$need_confirm = true;
}
$arg = intval($arg);
if ($need_confirm){
$ok = confirmer_supprimer_pushsubscriber_avant_action(_T('pushsubscriber:confirmer_supprimer_pushsubscriber'), _T('item_oui') . '! ' . _T('pushsubscriber:supprimer_pushsubscriber'));
}
// cas suppression
if (autoriser('supprimer', 'pushsubscriber', $arg)) {
if ($arg) {
$objet = sql_fetsel('*', 'spip_pushsubscribers', 'id_pushsubscriber=' . sql_quote($arg));
$qui = (!empty($GLOBALS['visiteur_session']['id_auteur']) ? 'auteur #' . $GLOBALS['visiteur_session']['id_auteur'] : 'IP ' . $GLOBALS['ip']);
spip_log("SUPPRESSION pushsubscriber#$arg par $qui : " . json_encode($objet), "suppressions" . _LOG_INFO_IMPORTANTE);
sql_delete('spip_pushsubscribers', 'id_pushsubscriber=' . sql_quote($arg));
// invalider le cache
include_spip('inc/invalideur');
suivre_invalideur("id='pushsubscriber/$arg'");
}
else {
spip_log("action_supprimer_pushsubscriber_dist $arg pas compris");
}
}
}
/**
* Confirmer avant suppression si on arrive par un bouton action
* @param string $titre
* @param string $titre_bouton
* @param string|null $url_action
* @return bool
*/
function confirmer_supprimer_pushsubscriber_avant_action($titre, $titre_bouton, $url_action=null) {
if (!$url_action) {
$url_action = self();
$action = _request('action');
$url_action = parametre_url($url_action, 'action', $action, '&');
}
else {
$action = parametre_url($url_action, 'action');
}
$arg = parametre_url($url_action, 'arg');
$confirm = md5("$action:$arg:".realpath(__FILE__));
if (_request('confirm_action') === $confirm) {
return true;
}
$url_confirm = parametre_url($url_action, "confirm_action", $confirm, '&');
include_spip("inc/filtres");
$bouton_action = bouton_action($titre_bouton, $url_confirm);
$corps = "<div style='text-align:center;'>$bouton_action</div>";
include_spip("inc/minipres");
echo minipres($titre,$corps);
exit;
}

51
action/tester_pushsubscriber.php

@ -0,0 +1,51 @@
<?php
/**
* Utilisation de l'action supprimer pour l'objet pushsubscriber
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Action
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Action pour supprimer un·e pushsubscriber
*
* Vérifier l'autorisation avant d'appeler l'action.
*
* @param null|int $arg
* Identifiant à supprimer.
* En absence de id utilise l'argument de l'action sécurisée.
**/
function action_tester_pushsubscriber_dist($arg=null) {
$need_confirm = false;
if (is_null($arg)){
$securiser_action = charger_fonction('securiser_action', 'inc');
$arg = $securiser_action();
}
$id_pushsubscriber = intval($arg);
// Si on peut tester l'envoi d'un push
if ($id_pushsubscriber and autoriser('tester', 'pushsubscriber', $id_pushsubscriber)) {
include_spip('inc/pushsubscribers');
pushsubscribers_envoyer_notification(
$id_pushsubscriber,
array(
'title' => 'Notification de test du site '.$GLOBALS['meta']['nom_site'],
'body' => 'Ceci est juste une notification de test',
'actions' => array(
array('action' => 'close', 'title' => 'Fermer'),
),
'data' => array(
'url' => $GLOBALS['meta']['adresse_site'],
),
)
);
}
}

189
base/pushsubscribers.php

@ -0,0 +1,189 @@
<?php
/**
* Déclarations relatives à la base de données
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Pipelines
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Déclaration des alias de tables et filtres automatiques de champs
*
* @pipeline declarer_tables_interfaces
* @param array $interfaces
* Déclarations d'interface pour le compilateur
* @return array
* Déclarations d'interface pour le compilateur
*/
function pushsubscribers_declarer_tables_interfaces($interfaces) {
$interfaces['table_des_tables']['pushsubscribers'] = 'pushsubscribers';
$interfaces['table_des_tables']['pushlists'] = 'pushlists';
$interfaces['table_des_tables']['pushs'] = 'pushs';
return $interfaces;
}
/**
* Déclaration des objets éditoriaux
*
* @pipeline declarer_tables_objets_sql
* @param array $tables
* Description des tables
* @return array
* Description complétée des tables
*/
function pushsubscribers_declarer_tables_objets_sql($tables) {
$tables['spip_pushsubscribers'] = array(
'type' => 'pushsubscriber',
'principale' => 'oui',
'field'=> array(
'id_pushsubscriber' => 'bigint(21) NOT NULL',
'id_auteur' => 'bigint(21) NOT NULL',
'endpoint' => 'varchar(512) NOT NULL DEFAULT ""',
'p256dh' => 'varchar(512) NOT NULL DEFAULT ""',
'auth' => 'varchar(512) NOT NULL DEFAULT ""',
'vapid_public' => 'varchar(512) NOT NULL DEFAULT ""',
'date_creation' => 'datetime NOT NULL DEFAULT "0000-00-00 00:00:00"',
'statut' => 'varchar(20) DEFAULT "0" NOT NULL',
'maj' => 'TIMESTAMP NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'
),
'key' => array(
'PRIMARY KEY' => 'id_pushsubscriber',
'KEY statut' => 'statut',
'KEY id_auteur' => 'id_auteur',
),
'titre' => 'endpoint AS titre, "" AS lang',
#'date' => '',
'champs_editables' => array('endpoint', 'p256dh', 'auth', 'vapid_public'),
'champs_versionnes' => array('endpoint', 'p256dh', 'auth', 'vapid_public', 'date_creation'),
'rechercher_champs' => array("endpoint" => 5, "p256dh" => 5, "auth" => 5, "vapid_public" => 5),
'tables_jointures' => array(),
'statut_textes_instituer' => array(
'valide' => 'texte_statut_publie',
'refuse' => 'texte_statut_refuse',
'poubelle' => 'texte_statut_poubelle',
),
'statut'=> array(
array(
'champ' => 'statut',
'publie' => 'valide',
'previsu' => 'valide',
'post_date' => 'date',
'exception' => array('statut','tout')
)
),
'texte_changer_statut' => 'pushsubscriber:texte_changer_statut_pushsubscriber',
);
$tables['spip_pushlists'] = array(
'type' => 'pushlist',
'principale' => 'oui',
'field'=> array(
'id_pushlist' => 'bigint(21) NOT NULL',
'titre' => 'text NOT NULL DEFAULT ""',
'type' => 'varchar(25) NOT NULL DEFAULT ""',
'contexte' => 'varchar(255) NOT NULL DEFAULT ""',
'maj' => 'TIMESTAMP NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'
),
'key' => array(
'PRIMARY KEY' => 'id_pushlist',
),
'titre' => 'titre AS titre, "" AS lang',
#'date' => '',
'champs_editables' => array('titre', 'contexte'),
'champs_versionnes' => array('titre', 'type', 'contexte'),
'rechercher_champs' => array("titre" => 10),
'tables_jointures' => array(),
);
$tables['spip_pushs'] = array(
'type' => 'push',
'principale' => 'oui',
'field'=> array(
'id_push' => 'bigint(21) NOT NULL',
'titre' => 'text NOT NULL DEFAULT ""',
'texte' => 'text NOT NULL DEFAULT ""',
'url' => 'varchar(255) NOT NULL DEFAULT ""',
'tag' => 'varchar(255) NOT NULL DEFAULT ""',
'date_debut' => 'datetime NOT NULL DEFAULT "0000-00-00 00:00:00"',
'date' => 'datetime NOT NULL DEFAULT "0000-00-00 00:00:00"',
'statut' => 'varchar(20) DEFAULT "0" NOT NULL',
'maj' => 'TIMESTAMP NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'
),
'key' => array(
'PRIMARY KEY' => 'id_push',
'KEY statut' => 'statut',
),
'titre' => 'titre AS titre, "" AS lang',
'date' => 'date',
'champs_editables' => array('titre', 'texte', 'url', 'tag'),
'champs_versionnes' => array('titre', 'texte', 'url', 'tag'),
'rechercher_champs' => array("titre" => 10, "texte" => 5, "tag" => 10),
'tables_jointures' => array(),
'statut_textes_instituer' => array(
'prepa' => 'texte_statut_en_cours_redaction',
'prop' => 'texte_statut_propose_evaluation',
'publie' => 'texte_statut_publie',
'refuse' => 'texte_statut_refuse',
'poubelle' => 'texte_statut_poubelle',
),
'statut'=> array(
array(
'champ' => 'statut',
'publie' => 'publie',
'previsu' => 'publie,prop,prepa',
'post_date' => 'date',
'exception' => array('statut','tout')
)
),
'texte_changer_statut' => 'push:texte_changer_statut_push',
);
return $tables;
}
/**
* Déclaration des tables secondaires (liaisons)
* @param array $tables
* @return array
*/
function pushsubscribers_declarer_tables_auxiliaires($tables) {
$tables['spip_pushsubscriptions'] = array(
'field' => array(
'id_pushsubscription' => 'bigint(21) default"0" NOT NULL',
'id_pushsubscriber' => 'bigint(21) default "0" NOT NULL',
'id_pushlist' => 'bigint(21) default "0" NOT NULL',
),
'key' => array(
"PRIMARY KEY" => "id_pushsubscription",
"KEY id_pushsubscriber" => "id_pushsubscriber",
"KEY id_pushlist" => "id_pushlist",
)
);
$tables['spip_pushs_destinataires'] = array(
'field' => array(
"id_push" => "bigint(21) DEFAULT '0' NOT NULL",
"id_pushsubscriber" => "bigint(21) DEFAULT '0' NOT NULL",
// recopier ici tous les champs permettant d'envoyer sans refaire une requête sur spip_pushsubscribers ?
"date" => "datetime NOT NULL DEFAULT '0000-00-00 00:00:00'",
"statut" => "char(4) DEFAULT 'todo' NOT NULL", // todo, sent, fail
"try" => "tinyint NOT NULL DEFAULT 0", // nombre d'essais
),
'key' => array(
"PRIMARY KEY" => "id_push,id_pushsubscriber",
"KEY statut" => "statut"
)
);
return $tables;
}

5
composer.json

@ -0,0 +1,5 @@
{
"require": {
"minishlink/web-push": "^6.0"
}
}

1030
composer.lock
File diff suppressed because it is too large
View File

1
formulaires/configurer_pushsubscribers.html

@ -0,0 +1 @@

132
formulaires/configurer_pushsubscribers.php

@ -0,0 +1,132 @@
<?php
/**
* Gestion du formulaire de de configuration de PushSubscribers
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Formulaires
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
*
* @param int|string $id_pushsubscriber
* Identifiant du pushsubscriber. 'new' pour un nouveau pushsubscriber.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushsubscriber source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushsubscriber, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return string
* Hash du formulaire
*/
function formulaires_configurer_pushsubscribers_saisies_dist() {
$saisies = array(
array(
'saisie' => 'fieldset',
'options' => array(
'nom' => 'vapid',
'label' => 'Clés d’identification du site',
'attention' => 'Attention, tout changement de ces paramètres invalideront l’ensemble de vos inscriptions !',
),
'saisies' => array(
array(
'saisie' => 'input',
'options' => array(
'nom' => 'vapid_subject',
'label' => 'Sujet VAPID',
'defaut' => $GLOBALS['meta']['adresse_site'],
),
),
array(
'saisie' => 'input',
'options' => array(
'nom' => 'vapid_public',
'label' => 'Clé VAPID publique',
),
),
array(
'saisie' => 'input',
'options' => array(
'nom' => 'vapid_private',
'label' => 'Clé VAPID privée',
'inserer_fin' => '<input style="display:none;" class="submit" type="submit" value="Go" /><input class="link" name="vapid_generer" type="submit" value="Générer des clés VAPID" />'
),
),
),
),
array(
'saisie' => 'fieldset',
'options' => array(
'nom' => 'envois',
'label' => 'Configuration des envois',
),
'saisies' => array(
array(
'saisie' => 'input',
'options' => array(
'nom' => 'heure_matin',
'label' => 'Heure du matin',
),
'verifier' => array(
'type' => 'entier',
'options' => array(
'min' => 0,
'max' => 24,
),
),
),
array(
'saisie' => 'input',
'options' => array(
'nom' => 'heure_soir',
'label' => 'Heure du soir',
),
'verifier' => array(
'type' => 'entier',
'options' => array(
'min' => 0,
'max' => 24,
),
),
),
),
),
);
return $saisies;
}
function formulaires_configurer_pushsubscribers_verifier_dist() {
$erreurs = array();
if (_request('vapid_generer')) {
include_spip('inc/pushsubscribers');
pushsubscribers_loader();
$cles = Minishlink\WebPush\VAPID::createVapidKeys();
if (isset($cles['publicKey']) and isset($cles['privateKey'])) {
set_request('vapid_public', $cles['publicKey']);
$erreurs['vapid_public'] = 'Cette clé vient d’être re-générée !';
set_request('vapid_private', $cles['privateKey']);
$erreurs['vapid_private'] = 'Cette clé vient d’être re-générée !';
$erreurs['message_erreur'] = '';
}
}
return $erreurs;
}

29
formulaires/editer_push.html

@ -0,0 +1,29 @@
<div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_push,nouveau}'>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#ENV{editable})
<form method="post" action="#ENV{action}"><div>
#ACTION_FORMULAIRE
<input type="hidden" name="id_push" value="#ENV{id_push}" />
<div class="editer-groupe">
[(#SAISIE{input, titre, obligatoire=oui,
label=<:push:champ_titre_label:/>})]
[(#SAISIE{textarea, texte,
label=<:push:champ_texte_label:/>})]
[(#SAISIE{input, url,
label=<:push:champ_url_label:/>})]
[(#SAISIE{input, tag, obligatoire=oui,
label=<:push:champ_tag_label:/>})]
</div>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer|attribut_html:/>" /></p>
</div></form>
]
</div>

124
formulaires/editer_push.php

@ -0,0 +1,124 @@
<?php
/**
* Gestion du formulaire de d'édition de push
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Formulaires
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/actions');
include_spip('inc/editer');
/**
* Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
*
* @param int|string $id_push
* Identifiant du push. 'new' pour un nouveau push.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un push source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du push, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return string
* Hash du formulaire
*/
function formulaires_editer_push_identifier_dist($id_push = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
return serialize(array(intval($id_push)));
}
/**
* Chargement du formulaire d'édition de push
*
* Déclarer les champs postés et y intégrer les valeurs par défaut
*
* @uses formulaires_editer_objet_charger()
*
* @param int|string $id_push
* Identifiant du push. 'new' pour un nouveau push.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un push source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du push, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Environnement du formulaire
*/
function formulaires_editer_push_charger_dist($id_push = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$valeurs = formulaires_editer_objet_charger('push', $id_push, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $valeurs;
}
/**
* Vérifications du formulaire d'édition de push
*
* Vérifier les champs postés et signaler d'éventuelles erreurs
*
* @uses formulaires_editer_objet_verifier()
*
* @param int|string $id_push
* Identifiant du push. 'new' pour un nouveau push.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un push source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du push, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Tableau des erreurs
*/
function formulaires_editer_push_verifier_dist($id_push = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$erreurs = array();
$erreurs = formulaires_editer_objet_verifier('push', $id_push, array('titre', 'tag'));
return $erreurs;
}
/**
* Traitement du formulaire d'édition de push
*
* Traiter les champs postés
*
* @uses formulaires_editer_objet_traiter()
*
* @param int|string $id_push
* Identifiant du push. 'new' pour un nouveau push.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un push source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du push, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Retours des traitements
*/
function formulaires_editer_push_traiter_dist($id_push = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$retours = formulaires_editer_objet_traiter('push', $id_push, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $retours;
}

23
formulaires/editer_pushlist.html

@ -0,0 +1,23 @@
<div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_pushlist,nouveau}'>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#ENV{editable})
<form method="post" action="#ENV{action}"><div>
#ACTION_FORMULAIRE
<input type="hidden" name="id_pushlist" value="#ENV{id_pushlist}" />
<div class="editer-groupe">
[(#SAISIE{input, titre, obligatoire=oui,
label=<:pushlist:champ_titre_label:/>})]
[(#SAISIE{input, contexte, obligatoire=oui,
label=<:pushlist:champ_contexte_label:/>})]
</div>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer|attribut_html:/>" /></p>
</div></form>
]
</div>

124
formulaires/editer_pushlist.php

@ -0,0 +1,124 @@
<?php
/**
* Gestion du formulaire de d'édition de pushlist
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Formulaires
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/actions');
include_spip('inc/editer');
/**
* Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
*
* @param int|string $id_pushlist
* Identifiant du pushlist. 'new' pour un nouveau pushlist.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushlist source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushlist, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return string
* Hash du formulaire
*/
function formulaires_editer_pushlist_identifier_dist($id_pushlist = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
return serialize(array(intval($id_pushlist)));
}
/**
* Chargement du formulaire d'édition de pushlist
*
* Déclarer les champs postés et y intégrer les valeurs par défaut
*
* @uses formulaires_editer_objet_charger()
*
* @param int|string $id_pushlist
* Identifiant du pushlist. 'new' pour un nouveau pushlist.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushlist source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushlist, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Environnement du formulaire
*/
function formulaires_editer_pushlist_charger_dist($id_pushlist = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$valeurs = formulaires_editer_objet_charger('pushlist', $id_pushlist, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $valeurs;
}
/**
* Vérifications du formulaire d'édition de pushlist
*
* Vérifier les champs postés et signaler d'éventuelles erreurs
*
* @uses formulaires_editer_objet_verifier()
*
* @param int|string $id_pushlist
* Identifiant du pushlist. 'new' pour un nouveau pushlist.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushlist source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushlist, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Tableau des erreurs
*/
function formulaires_editer_pushlist_verifier_dist($id_pushlist = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$erreurs = array();
$erreurs = formulaires_editer_objet_verifier('pushlist', $id_pushlist, array('titre', 'contexte'));
return $erreurs;
}
/**
* Traitement du formulaire d'édition de pushlist
*
* Traiter les champs postés
*
* @uses formulaires_editer_objet_traiter()
*
* @param int|string $id_pushlist
* Identifiant du pushlist. 'new' pour un nouveau pushlist.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushlist source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushlist, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Retours des traitements
*/
function formulaires_editer_pushlist_traiter_dist($id_pushlist = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$retours = formulaires_editer_objet_traiter('pushlist', $id_pushlist, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $retours;
}

29
formulaires/editer_pushsubscriber.html

@ -0,0 +1,29 @@
<div class='formulaire_spip formulaire_editer formulaire_#FORM formulaire_#FORM-#ENV{id_pushsubscriber,nouveau}'>
[<p class="reponse_formulaire reponse_formulaire_ok">(#ENV**{message_ok})</p>]
[<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>]
[(#ENV{editable})
<form method="post" action="#ENV{action}"><div>
#ACTION_FORMULAIRE
<input type="hidden" name="id_pushsubscriber" value="#ENV{id_pushsubscriber}" />
<div class="editer-groupe">
[(#SAISIE{input, endpoint, obligatoire=oui,
label=<:pushsubscriber:champ_endpoint_label:/>})]
[(#SAISIE{input, p256dh, obligatoire=oui,
label=<:pushsubscriber:champ_p256dh_label:/>})]
[(#SAISIE{input, auth, obligatoire=oui,
label=<:pushsubscriber:champ_auth_label:/>})]
[(#SAISIE{input, vapid_public, obligatoire=oui,
label=<:pushsubscriber:champ_vapid_public_label:/>})]
</div>
[(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ]
<!--extra-->
<p class="boutons"><input type="submit" class="submit" value="<:bouton_enregistrer|attribut_html:/>" /></p>
</div></form>
]
</div>

124
formulaires/editer_pushsubscriber.php

@ -0,0 +1,124 @@
<?php
/**
* Gestion du formulaire de d'édition de pushsubscriber
*
* @plugin PushSubscribers
* @copyright 2020
* @author Mukt
* @licence GNU/GPL
* @package SPIP\Pushsubscribers\Formulaires
*/
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
include_spip('inc/actions');
include_spip('inc/editer');
/**
* Identifier le formulaire en faisant abstraction des paramètres qui ne représentent pas l'objet edité
*
* @param int|string $id_pushsubscriber
* Identifiant du pushsubscriber. 'new' pour un nouveau pushsubscriber.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushsubscriber source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushsubscriber, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return string
* Hash du formulaire
*/
function formulaires_editer_pushsubscriber_identifier_dist($id_pushsubscriber = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
return serialize(array(intval($id_pushsubscriber)));
}
/**
* Chargement du formulaire d'édition de pushsubscriber
*
* Déclarer les champs postés et y intégrer les valeurs par défaut
*
* @uses formulaires_editer_objet_charger()
*
* @param int|string $id_pushsubscriber
* Identifiant du pushsubscriber. 'new' pour un nouveau pushsubscriber.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushsubscriber source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushsubscriber, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Environnement du formulaire
*/
function formulaires_editer_pushsubscriber_charger_dist($id_pushsubscriber = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$valeurs = formulaires_editer_objet_charger('pushsubscriber', $id_pushsubscriber, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $valeurs;
}
/**
* Vérifications du formulaire d'édition de pushsubscriber
*
* Vérifier les champs postés et signaler d'éventuelles erreurs
*
* @uses formulaires_editer_objet_verifier()
*
* @param int|string $id_pushsubscriber
* Identifiant du pushsubscriber. 'new' pour un nouveau pushsubscriber.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushsubscriber source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushsubscriber, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Tableau des erreurs
*/
function formulaires_editer_pushsubscriber_verifier_dist($id_pushsubscriber = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$erreurs = array();
$erreurs = formulaires_editer_objet_verifier('pushsubscriber', $id_pushsubscriber, array('endpoint', 'p256dh', 'auth', 'vapid_public'));
return $erreurs;
}
/**
* Traitement du formulaire d'édition de pushsubscriber
*
* Traiter les champs postés
*
* @uses formulaires_editer_objet_traiter()
*
* @param int|string $id_pushsubscriber
* Identifiant du pushsubscriber. 'new' pour un nouveau pushsubscriber.
* @param string $retour
* URL de redirection après le traitement
* @param int $lier_trad
* Identifiant éventuel d'un pushsubscriber source d'une traduction
* @param string $config_fonc
* Nom de la fonction ajoutant des configurations particulières au formulaire
* @param array $row
* Valeurs de la ligne SQL du pushsubscriber, si connu
* @param string $hidden
* Contenu HTML ajouté en même temps que les champs cachés du formulaire.
* @return array
* Retours des traitements
*/
function formulaires_editer_pushsubscriber_traiter_dist($id_pushsubscriber = 'new', $retour = '', $lier_trad = 0, $config_fonc = '', $row = array(), $hidden = '') {
$retours = formulaires_editer_objet_traiter('pushsubscriber', $id_pushsubscriber, '', $lier_trad, $retour, $config_fonc, $row, $hidden);
return $retours;
}

91
inc/pushsubscribers.php

@ -0,0 +1,91 @@
<?php
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
/**
* Lance le chargeur PSR pour les libs embarquées
**/
function pushsubscribers_loader() {
static $done = false;
if (!$done) {
$done = true;
require_once __DIR__ . '/../vendor/autoload.php';
}
}
/**
* Envoyer UNE notification, en ayant toutes les infos nécessaires
*
* Doit plutôt être employée pour envoyer des notifs transactionnelles (suivi, admin), pas pour de l'information en masse
*
* @param array $subscriber
* Tableau contenant les infos d'un inscrit :
* array(
* 'endpoint' =>
* 'keys' => array(
* 'auth' =>
* 'p256dh' =>
* )
* )
* @param string $payload
* Chaine représentant un objet JSON ou tableau PHP, avec le contenu attendu par le service-worker :
* array(
* 'title' => 'Titre de la notif',
* 'message' => 'Contenu texte de la notif',
* 'icon' => 'URL image',
* 'data' => array('url' => 'URL de lien quand on clique',),
* 'actions' => array(
* array('action' => 'close', 'title' => 'Fermer'),
* )
* )
*/
function pushsubscribers_envoyer_notification($pushsubscriber, $payload) {
include_spip('base/abstract_sql');
// Si on a bien des infos d'inscription
if (
(is_int($pushsubscriber) and $pushsubscriber = sql_fetsel('*', 'spip_pushsubscribers', 'id_pushsubscriber = '.$pushsubscriber))
or
(is_array($pushsubscriber) and isset($pushsubscriber['endpoint']) and isset($pushsubscriber['auth']) and isset($pushsubscriber['p256dh']))
) {
// On charge pour les classes
pushsubscribers_loader();
// On crée le controleur
$webpush = new Minishlink\WebPush\WebPush(array(
'VAPID' => array(
'subject' => lire_config('pushsubscribers/vapid_subject'),
'publicKey' => lire_config('pushsubscribers/vapid_public'),
'privateKey' => lire_config('pushsubscribers/vapid_private'),
)
));
// On crée vraiment l'inscription en objet
$subscription = Minishlink\WebPush\Subscription::create(array(
'endpoint' => $pushsubscriber['endpoint'],
'keys' => array(
'auth' => $pushsubscriber['auth'],
'p256dh' => $pushsubscriber['p256dh'],
),
));
if (is_array($payload)) {
$payload = json_encode($payload);
}
// On envoie la notif
$report = $webpush->sendOneNotification($subscription, $payload);
// On teste si ça a marché
if ($report->isSuccess()) {
}
else {
}
}
}

70
javascript/pushsubscribers.install.js

@ -0,0 +1,70 @@
var offlineConfig;
// Public base64 to Uint
function urlBase64ToUint8Array(base64String) {
var padding = '='.repeat((4 - base64String.length % 4) % 4);
var base64 = (base64String + padding)
.replace(/\-/g, '+')
.replace(/_/g, '/');
var rawData = window.atob(base64);
var outputArray = new Uint8Array(rawData.length);
for (var i = 0; i < rawData.length; ++i) {
outputArray[i] = rawData.charCodeAt(i);
}
return outputArray;
}
if (typeof offlineConfig == "undefined"){
console.error("Erreur offline.install.js appele sans configuration");
}
else {
// On appelle jQuery
(function ($) {
// On cherche les boutons d'inscription aux pushs
function pushsubscribers_boutons() {
// S'il ça gère les serviceworkers et qu'on trouve la clé publique
if ('serviceWorker' in navigator && jQuery.spip.pushsubscribers.vapid_public) {
// On recherche l'enregistrement du SW
// navigator.serviceWorker.ready.then(function (registration) {
// navigator.serviceWorker.getRegistration().then(function (registration) {
navigator.serviceWorker.register(offlineConfig.swUrl, offlineConfig.swOptions).then(function (registration) {
var applicationServerKey = urlBase64ToUint8Array(jQuery.spip.pushsubscribers.vapid_public);
return registration.pushManager.getSubscription()
.then(subscription => {
if (subscription) {
return subscription;
}
return registration.pushManager.subscribe({
userVisibleOnly: true,
applicationServerKey: applicationServerKey
});
})
.then(subscription => {
// On a maintenant une inscription, on l'envoie au serveur pour la garder en mémoire
subscription_json = subscription.toJSON();
console.debug("subscription_json", subscription_json);
// On envoie les infos à SPIP
$.post(
'pushsubscription.api/create',
subscription_json
);
})
.catch(err => console.error('Impossible de souscrire aux notifications : ', err));
}, function (err){
// registration failed :(
console.log('Impossible de trouver l’enregistrement du Service Worker : ', err);
});
}
}
// Quand le DOM est prêt
$(function() {
pushsubscribers_boutons();
});
}(jQuery));
}

84
javascript/pushsubscribers.sw.js

@ -0,0 +1,84 @@
var offlineConfig;
/**
* Gestion d'une réception de push
*/
self.addEventListener('push', function (event) {
console.log('Hey mon ami⋅e, tu reçois un push !', event);
// On récupère le contenu du payload du push : une chaine json
var params;
if (event.data) {
params = event.data.text();
params = JSON.parse(params);
}
// On rajoute la date d'arrivée
params.data.date_reception = Date.now();
//~ var options = {
//~ body: params['message'] ||'',
//~ icon: params['icon'] || '',
//~ // vibrate: params['vibrate'],
//~ data: {
//~ dateOfArrival: Date.now(),
//~ url: params['url'] || '',
//~ },
//~ actions: [
//~ {action: 'close', title: 'Fermer'}
//~ ]
//~ };
// Keep the service worker alive until the notification is created
event.waitUntil(
self.registration.showNotification(params['title'], params)
);
});
/**
* Gestion des clics dans les notifications
*/
self.addEventListener('notificationclick', function (event) {
var notification = event.notification;
var action = event.action;
var url;
if (notification.data.url) {
url = notification.data.url;
}
else {
url = '/';
}
if (action === 'close') {
notification.close();
}
else {
event.waitUntil(
clients.openWindow(url)
);
}
});
/**
* Gestion de l'expiration de l'inscription
*/
//~ self.addEventListener('pushsubscriptionchange', function(event) {
//~ console.log('Inscription aux notifications expirée !');
//~ event.waitUntil(
//~ self.registration.pushManager.subscribe({ userVisibleOnly: true })
//~ .then(function(subscription) {
//~ console.log('Subscribed after expiration', subscription.endpoint);
//~ return fetch('register', {
//~ method: 'post',
//~ headers: {
//~ 'Content-type': 'application/json'
//~ },
//~ body: JSON.stringify({
//~ endpoint: subscription.endpoint
//~ })
//~ });
//~ })
//~ );
//~ });

14
lang/paquet-pushsubscribers_fr.php

@ -0,0 +1,14 @@
<?php
// This is a SPIP language file -- Ceci est un fichier langue de SPIP
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
$GLOBALS[$GLOBALS['idx_lang']] = array(
// P
'pushsubscribers_description' => 'Ce plugin fournit les outils permettant d\'inscrire un navigateur a un ou plusieurs flux de notifications pushs, et les fonctions d\'envoi vers les inscrits.',
'pushsubscribers_nom' => 'PushSubscribers',
'pushsubscribers_slogan' => 'Gère les inscriptions à des notifications push',
);

49
lang/push_fr.php

@ -0,0 +1,49 @@
<?php
// This is a SPIP language file -- Ceci est un fichier langue de SPIP
if (!defined('_ECRIRE_INC_VERSION')) {
return;
}
$GLOBALS[$GLOBALS['idx_lang']] = array(
// A
'ajouter_lien_push' => 'Ajouter cette notification push',
// C
'champ_date_debut_label' => 'Date d\'envoi',
'champ_tag_label' => 'Étiquette identifiant',