[SPIP] v3.2.1-->v3.2.2
[lhc/web/www.git] / www / ecrire / inc / filtres_ecrire.php
1 <?php
2
3 /***************************************************************************\
4 * SPIP, Systeme de publication pour l'internet *
5 * *
6 * Copyright (c) 2001-2019 *
7 * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James *
8 * *
9 * Ce programme est un logiciel libre distribue sous licence GNU/GPL. *
10 * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. *
11 \***************************************************************************/
12
13 /**
14 * Fonctions utilisées au calcul des squelette du privé.
15 *
16 * @package SPIP\Core\Filtres
17 */
18 if (!defined('_ECRIRE_INC_VERSION')) {
19 return;
20 }
21
22 include_spip('inc/filtres_boites');
23 include_spip('inc/boutons');
24 include_spip('inc/pipelines_ecrire');
25
26
27 /**
28 * Retourne les paramètres de personnalisation css de l'espace privé
29 *
30 * Ces paramètres sont (ltr et couleurs) ce qui permet une écriture comme :
31 * generer_url_public('style_prive', parametres_css_prive())
32 * qu'il est alors possible de récuperer dans le squelette style_prive.html avec
33 *
34 * #SET{claire,##ENV{couleur_claire,edf3fe}}
35 * #SET{foncee,##ENV{couleur_foncee,3874b0}}
36 * #SET{left,#ENV{ltr}|choixsiegal{left,left,right}}
37 * #SET{right,#ENV{ltr}|choixsiegal{left,right,left}}
38 *
39 * @return string
40 */
41 function parametres_css_prive() {
42
43 $args = array();
44 $args['v'] = $GLOBALS['spip_version_code'];
45 $args['p'] = substr(md5($GLOBALS['meta']['plugin']), 0, 4);
46 $args['themes'] = implode(',', lister_themes_prives());
47 $args['ltr'] = $GLOBALS['spip_lang_left'];
48 // un md5 des menus : si un menu change il faut maj la css
49 $args['md5b'] = (function_exists('md5_boutons_plugins') ? md5_boutons_plugins() : '');
50
51 $c = (is_array($GLOBALS['visiteur_session'])
52 and is_array($GLOBALS['visiteur_session']['prefs']))
53 ? $GLOBALS['visiteur_session']['prefs']['couleur']
54 : 9;
55
56 $couleurs = charger_fonction('couleurs', 'inc');
57 parse_str($couleurs($c), $c);
58 $args = array_merge($args, $c);
59
60 if (_request('var_mode') == 'recalcul' or (defined('_VAR_MODE') and _VAR_MODE == 'recalcul')) {
61 $args['var_mode'] = 'recalcul';
62 }
63
64 return http_build_query($args);
65 }
66
67
68 /**
69 * Afficher le sélecteur de rubrique
70 *
71 * Il permet de placer un objet dans la hiérarchie des rubriques de SPIP
72 *
73 * @uses inc_chercher_rubrique_dist()
74 *
75 * @param string $titre
76 * @param int $id_objet
77 * @param int $id_parent
78 * @param string $objet
79 * @param int $id_secteur
80 * @param bool $restreint
81 * @param bool $actionable
82 * true : fournit le selecteur dans un form directement postable
83 * @param bool $retour_sans_cadre
84 * @return string
85 */
86 function chercher_rubrique(
87 $titre,
88 $id_objet,
89 $id_parent,
90 $objet,
91 $id_secteur,
92 $restreint,
93 $actionable = false,
94 $retour_sans_cadre = false
95 ) {
96
97 include_spip('inc/autoriser');
98 if (intval($id_objet) && !autoriser('modifier', $objet, $id_objet)) {
99 return "";
100 }
101 if (!sql_countsel('spip_rubriques')) {
102 return "";
103 }
104 $chercher_rubrique = charger_fonction('chercher_rubrique', 'inc');
105 $form = $chercher_rubrique($id_parent, $objet, $restreint, ($objet == 'rubrique') ? $id_objet : 0);
106
107 if ($id_parent == 0) {
108 $logo = "racine-24.png";
109 } elseif ($id_secteur == $id_parent) {
110 $logo = "secteur-24.png";
111 } else {
112 $logo = "rubrique-24.png";
113 }
114
115 $confirm = "";
116 if ($objet == 'rubrique') {
117 // si c'est une rubrique-secteur contenant des breves, demander la
118 // confirmation du deplacement
119 $contient_breves = sql_countsel('spip_breves', "id_rubrique=" . intval($id_objet));
120
121 if ($contient_breves > 0) {
122 $scb = ($contient_breves > 1 ? 's' : '');
123 $scb = _T('avis_deplacement_rubrique',
124 array(
125 'contient_breves' => $contient_breves,
126 'scb' => $scb
127 ));
128 $confirm .= "\n<div class='confirmer_deplacement verdana2'>"
129 . "<div class='choix'><input type='checkbox' name='confirme_deplace' value='oui' id='confirme-deplace' /><label for='confirme-deplace'>"
130 . $scb .
131 "</label></div></div>\n";
132 } else {
133 $confirm .= "<input type='hidden' name='confirme_deplace' value='oui' />\n";
134 }
135 }
136 $form .= $confirm;
137 if ($actionable) {
138 if (strpos($form, '<select') !== false) {
139 $form .= "<div style='text-align: " . $GLOBALS['spip_lang_right'] . ";'>"
140 . '<input class="fondo" type="submit" value="' . _T('bouton_choisir') . '"/>'
141 . "</div>";
142 }
143 $form = "<input type='hidden' name='editer_$objet' value='oui' />\n" . $form;
144 if ($action = charger_fonction("editer_$objet", "action", true)) {
145 $form = generer_action_auteur("editer_$objet", $id_objet, self(), $form,
146 " method='post' class='submit_plongeur'");
147 } else {
148 $form = generer_action_auteur("editer_objet", "$objet/$id_objet", self(), $form,
149 " method='post' class='submit_plongeur'");
150 }
151 }
152
153 if ($retour_sans_cadre) {
154 return $form;
155 }
156
157 include_spip('inc/presentation');
158
159 return debut_cadre_couleur($logo, true, "", $titre) . $form . fin_cadre_couleur(true);
160
161 }
162
163
164 /**
165 * Tester si le site peut avoir des visiteurs
166 *
167 * @param bool $past
168 * si true, prendre en compte le fait que le site a *deja* des visiteurs
169 * comme le droit d'en avoir de nouveaux
170 * @param bool $accepter
171 * @return bool
172 */
173 function avoir_visiteurs($past = false, $accepter = true) {
174 if ($GLOBALS['meta']["forums_publics"] == 'abo') {
175 return true;
176 }
177 if ($accepter and $GLOBALS['meta']["accepter_visiteurs"] <> 'non') {
178 return true;
179 }
180 if (sql_countsel('spip_articles', "accepter_forum='abo'")) {
181 return true;
182 }
183 if (!$past) {
184 return false;
185 }
186
187 return sql_countsel('spip_auteurs',
188 "statut NOT IN ('0minirezo','1comite', '5poubelle')
189 AND (statut<>'nouveau' OR prefs NOT IN ('0minirezo','1comite', '5poubelle'))");
190 }
191
192 /**
193 * Lister les status d'article visibles dans l'espace prive
194 * en fonction du statut de l'auteur
195 *
196 * Pour l'extensibilie de SPIP, on se repose sur autoriser('voir','article')
197 * en testant un à un les status présents en base
198 *
199 * On mémorise en static pour éviter de refaire plusieurs fois.
200 *
201 * @param string $statut_auteur
202 * @return array
203 */
204 function statuts_articles_visibles($statut_auteur) {
205 static $auth = array();
206 if (!isset($auth[$statut_auteur])) {
207 $auth[$statut_auteur] = array();
208 $statuts = array_map('reset', sql_allfetsel('distinct statut', 'spip_articles'));
209 foreach ($statuts as $s) {
210 if (autoriser('voir', 'article', 0, array('statut' => $statut_auteur), array('statut' => $s))) {
211 $auth[$statut_auteur][] = $s;
212 }
213 }
214 }
215
216 return $auth[$statut_auteur];
217 }
218
219 /**
220 * Traduire le statut technique de l'auteur en langage compréhensible
221 *
222 * Si $statut=='nouveau' et que le statut en attente est fourni,
223 * le prendre en compte en affichant que l'auteur est en attente
224 *
225 * @param string $statut
226 * @param string $attente
227 * @return string
228 */
229 function traduire_statut_auteur($statut, $attente = "") {
230 $plus = "";
231 if ($statut == 'nouveau') {
232 if ($attente) {
233 $statut = $attente;
234 $plus = " (" . _T('info_statut_auteur_a_confirmer') . ")";
235 } else {
236 return _T('info_statut_auteur_a_confirmer');
237 }
238 }
239
240 $recom = array(
241 "info_administrateurs" => _T('item_administrateur_2'),
242 "info_redacteurs" => _T('intem_redacteur'),
243 "info_visiteurs" => _T('item_visiteur'),
244 '5poubelle' => _T('texte_statut_poubelle'), // bouh
245 );
246 if (isset($recom[$statut])) {
247 return $recom[$statut] . $plus;
248 }
249
250 // retrouver directement par le statut sinon
251 if ($t = array_search($statut, $GLOBALS['liste_des_statuts'])) {
252 if (isset($recom[$t])) {
253 return $recom[$t] . $plus;
254 }
255
256 return _T($t) . $plus;
257 }
258
259 // si on a pas reussi a le traduire, retournons la chaine telle quelle
260 // c'est toujours plus informatif que rien du tout
261 return $statut;
262 }
263
264 /**
265 * Afficher la mention des autres auteurs ayant modifié un objet
266 *
267 * @param int $id_objet
268 * @param string $objet
269 * @return string
270 */
271 function afficher_qui_edite($id_objet, $objet) {
272 static $qui = array();
273 if (isset($qui[$objet][$id_objet])) {
274 return $qui[$objet][$id_objet];
275 }
276
277 if ($GLOBALS['meta']['articles_modif'] == 'non') {
278 return $qui[$objet][$id_objet] = '';
279 }
280
281 include_spip('inc/drapeau_edition');
282 $modif = mention_qui_edite($id_objet, $objet);
283 if (!$modif) {
284 return $qui[$objet][$id_objet] = '';
285 }
286
287 include_spip('base/objets');
288 $infos = lister_tables_objets_sql(table_objet_sql($objet));
289 if (isset($infos['texte_signale_edition'])) {
290 return $qui[$objet][$id_objet] = _T($infos['texte_signale_edition'], $modif);
291 }
292
293 return $qui[$objet][$id_objet] = _T('info_qui_edite', $modif);
294 }
295
296 /**
297 * Lister les statuts des auteurs
298 *
299 * @param string $quoi
300 * - redacteurs : retourne les statuts des auteurs au moins redacteur,
301 * tels que defini par AUTEURS_MIN_REDAC
302 * - visiteurs : retourne les statuts des autres auteurs, cad les visiteurs
303 * et autres statuts perso
304 * - tous : retourne tous les statuts connus
305 * @param bool $en_base
306 * si true, ne retourne strictement que les status existants en base
307 * dans tous les cas, les statuts existants en base sont inclus
308 * @return array
309 */
310 function auteurs_lister_statuts($quoi = 'tous', $en_base = true) {
311 if (!defined('AUTEURS_MIN_REDAC')) {
312 define('AUTEURS_MIN_REDAC', "0minirezo,1comite,5poubelle");
313 }
314
315 switch ($quoi) {
316 case "redacteurs":
317 $statut = AUTEURS_MIN_REDAC;
318 $statut = explode(',', $statut);
319 if ($en_base) {
320 $check = array_map('reset', sql_allfetsel('DISTINCT statut', 'spip_auteurs', sql_in('statut', $statut)));
321 $retire = array_diff($statut, $check);
322 $statut = array_diff($statut, $retire);
323 }
324
325 return array_unique($statut);
326 break;
327 case "visiteurs":
328 $statut = array();
329 $exclus = AUTEURS_MIN_REDAC;
330 $exclus = explode(',', $exclus);
331 if (!$en_base) {
332 // prendre aussi les statuts de la table des status qui ne sont pas dans le define
333 $statut = array_diff(array_values($GLOBALS['liste_des_statuts']), $exclus);
334 }
335 $s_complement = array_map('reset',
336 sql_allfetsel('DISTINCT statut', 'spip_auteurs', sql_in('statut', $exclus, 'NOT')));
337
338 return array_unique(array_merge($statut, $s_complement));
339 break;
340 default:
341 case "tous":
342 $statut = array_values($GLOBALS['liste_des_statuts']);
343 $s_complement = array_map('reset',
344 sql_allfetsel('DISTINCT statut', 'spip_auteurs', sql_in('statut', $statut, 'NOT')));
345 $statut = array_merge($statut, $s_complement);
346 if ($en_base) {
347 $check = array_map('reset', sql_allfetsel('DISTINCT statut', 'spip_auteurs', sql_in('statut', $statut)));
348 $retire = array_diff($statut, $check);
349 $statut = array_diff($statut, $retire);
350 }
351
352 return array_unique($statut);
353 break;
354 }
355
356 // on arrive jamais ici
357 return array_values($GLOBALS['liste_des_statuts']);
358 }
359
360 /**
361 * Déterminer la rubrique pour la création d'un objet heuristique
362 *
363 * Rubrique courante si possible,
364 * - sinon rubrique administrée pour les admin restreint
365 * - sinon première rubrique de premier niveau autorisée que l'on trouve
366 *
367 * @param int $id_rubrique Identifiant de rubrique (si connu)
368 * @param string $objet Objet en cours de création
369 * @return int Identifiant de la rubrique dans laquelle créer l'objet
370 */
371 function trouver_rubrique_creer_objet($id_rubrique, $objet) {
372
373 if (!$id_rubrique and defined('_CHOIX_RUBRIQUE_PAR_DEFAUT') and _CHOIX_RUBRIQUE_PAR_DEFAUT) {
374 $in = !count($GLOBALS['connect_id_rubrique'])
375 ? ''
376 : (" AND " . sql_in('id_rubrique', $GLOBALS['connect_id_rubrique']));
377
378 // on tente d'abord l'ecriture a la racine dans le cas des rubriques uniquement
379 if ($objet == 'rubrique') {
380 $id_rubrique = 0;
381 } else {
382 $id_rubrique = sql_getfetsel('id_rubrique', 'spip_rubriques', "id_parent=0$in", '', "id_rubrique DESC", 1);
383 }
384
385 if (!autoriser("creer{$objet}dans", 'rubrique', $id_rubrique)) {
386 // manque de chance, la rubrique n'est pas autorisee, on cherche un des secteurs autorises
387 $res = sql_select("id_rubrique", "spip_rubriques", "id_parent=0");
388 while (!autoriser("creer{$objet}dans", 'rubrique', $id_rubrique) && $row_rub = sql_fetch($res)) {
389 $id_rubrique = $row_rub['id_rubrique'];
390 }
391 }
392 }
393
394 return $id_rubrique;
395 }
396
397 /**
398 * Afficher le lien de redirection d'un article virtuel si il y a lieu
399 * (rien si l'article n'est pas redirige)
400 *
401 * @param string $virtuel
402 * @return string
403 */
404 function lien_article_virtuel($virtuel) {
405 include_spip('inc/lien');
406 if (!$virtuel = virtuel_redirige($virtuel)) {
407 return '';
408 }
409
410 return propre("[->" . $virtuel . "]");
411 }
412
413
414 /**
415 * Filtre pour générer un lien vers un flux RSS privé
416 *
417 * Le RSS est protegé par un hash de faible sécurité
418 *
419 * @example
420 * - `[(#VAL{a_suivre}|bouton_spip_rss)]`
421 * - `[(#VAL{signatures}|bouton_spip_rss{#ARRAY{id_article,#ID_ARTICLE}})]`
422 *
423 * @filtre
424 * @uses param_low_sec()
425 * @param string $op
426 * @param array $args
427 * @param string $lang
428 * @param string $title
429 * @return string
430 * Code HTML du lien
431 */
432 function bouton_spip_rss($op, $args = array(), $lang = '', $title = 'RSS') {
433 include_spip('inc/acces');
434 $clic = http_img_pack('feed.png', 'RSS', '', $title);
435 $args = param_low_sec($op, $args, $lang, 'rss');
436 $url = generer_url_public('rss', $args);
437
438 return "<a style='float: " . $GLOBALS['spip_lang_right'] . ";' href='$url'>$clic</a>";
439 }
440
441
442 /**
443 * Vérifier la présence d'alertes pour les auteur
444 *
445 * @param int $id_auteur
446 * @return string
447 */
448 function alertes_auteur($id_auteur) {
449
450 $alertes = array();
451
452 if (isset($GLOBALS['meta']['message_crash_tables'])
453 and autoriser('detruire', null, null, $id_auteur)
454 ) {
455 include_spip('genie/maintenance');
456 if ($msg = message_crash_tables()) {
457 $alertes[] = $msg;
458 }
459 }
460
461 if (isset($GLOBALS['meta']['message_crash_plugins'])
462 and $GLOBALS['meta']['message_crash_plugins']
463 and autoriser('configurer', '_plugins', null, $id_auteur)
464 and is_array($msg = unserialize($GLOBALS['meta']['message_crash_plugins']))
465 ) {
466 $msg = implode(', ', array_map('joli_repertoire', array_keys($msg)));
467 $alertes[] = _T('plugins_erreur', array('plugins' => $msg));
468 }
469
470 $a = isset($GLOBALS['meta']['message_alertes_auteurs']) ? $GLOBALS['meta']['message_alertes_auteurs'] : '';
471 if ($a
472 and is_array($a = unserialize($a))
473 and count($a)
474 ) {
475 $update = false;
476 if (isset($a[$GLOBALS['visiteur_session']['statut']])) {
477 $alertes = array_merge($alertes, $a[$GLOBALS['visiteur_session']['statut']]);
478 unset($a[$GLOBALS['visiteur_session']['statut']]);
479 $update = true;
480 }
481 if (isset($a[''])) {
482 $alertes = array_merge($alertes, $a['']);
483 unset($a['']);
484 $update = true;
485 }
486 if ($update) {
487 ecrire_meta("message_alertes_auteurs", serialize($a));
488 }
489 }
490
491 if (isset($GLOBALS['meta']['plugin_erreur_activation'])
492 and autoriser('configurer', '_plugins', null, $id_auteur)
493 ) {
494 include_spip('inc/plugin');
495 $alertes[] = plugin_donne_erreurs();
496 }
497
498 $alertes = pipeline(
499 'alertes_auteur',
500 array(
501 'args' => array(
502 'id_auteur' => $id_auteur,
503 'exec' => _request('exec'),
504 ),
505 'data' => $alertes
506 )
507 );
508
509 if ($alertes = array_filter($alertes)) {
510 return "<div class='wrap-messages-alertes'><div class='messages-alertes'>" .
511 join(' | ', $alertes)
512 . "</div></div>";
513 }
514 }
515
516 /**
517 * Filtre pour afficher les rubriques enfants d'une rubrique
518 *
519 * @param int $id_rubrique
520 * @return string
521 */
522 function filtre_afficher_enfant_rub_dist($id_rubrique) {
523 include_spip('inc/presenter_enfants');
524
525 return afficher_enfant_rub(intval($id_rubrique));
526 }
527
528 /**
529 * Afficher un petit "i" pour lien vers autre page
530 *
531 * @param string $lien
532 * URL du lien desire
533 * @param string $titre
534 * Titre au survol de l'icone pointant le lien
535 * @param string $titre_lien
536 * Si present, ajoutera en plus apres l'icone
537 * un lien simple, vers la meme URL,
538 * avec le titre indique
539 *
540 * @return string
541 */
542 function afficher_plus_info($lien, $titre = "+", $titre_lien = "") {
543 $titre = attribut_html($titre);
544 $icone = "\n<a href='$lien' title='$titre' class='plus_info'>" .
545 http_img_pack("information-16.png", $titre) . "</a>";
546
547 if (!$titre_lien) {
548 return $icone;
549 } else {
550 return $icone . "\n<a href='$lien'>$titre_lien</a>";
551 }
552 }
553
554 /**
555 * Lister les id objet_source associés à l'objet id_objet
556 * via la table de lien objet_lien
557 *
558 * Utilisé pour les listes de #FORMULAIRE_EDITER_LIENS
559 *
560 * @param string $objet_source
561 * @param string $objet
562 * @param int $id_objet
563 * @param string $objet_lien
564 * @return array
565 */
566 function lister_objets_lies($objet_source, $objet, $id_objet, $objet_lien) {
567 include_spip('action/editer_liens');
568 $l = array();
569 // quand $objet == $objet_lien == $objet_source on reste sur le cas par defaut de $objet_lien == $objet_source
570 if ($objet_lien == $objet and $objet_lien !== $objet_source) {
571 $res = objet_trouver_liens(array($objet => $id_objet), array($objet_source => '*'));
572 } else {
573 $res = objet_trouver_liens(array($objet_source => '*'), array($objet => $id_objet));
574 }
575 while ($row = array_shift($res)) {
576 $l[] = $row[$objet_source];
577 }
578
579 return $l;
580 }