[Devel] Implémentation des tags

Thomas Petazzoni thomas.petazzoni at enix.org
Sam 13 Jan 18:11:25 CET 2007


Salut à tous,

Ci-dessous, vous trouverez un patch implémentant une gestion basique
des tags dans l'Agenda du Libre.

Au niveau du stockage, au lieu d'ajouter une table "tags" associant un
id d'évènement à un tag (ce qui aurait été le plus logique), j'ai
préféré faire plus simple pour cette première version: ajout d'un champ
"tags" dans la table "events". Ce champ "tags" contient la liste des
tags d'un évènement, séparés par des espaces.

Ce choix a été fait parce qu'au niveau de l'interface, c'est comme cela
que sont gérés les tags: une liste de mots séparés par des espaces.
Chaque mot ne peut contenir que des minuscules, chiffres ou tirets, et
chaque mot doit faire 4 caractères au minimum.

Le patch implémente:
 - ajout des tags à la soumission de l'évènement
 - édition des tags dans l'interface de modération
 - affichage des tags lorsque l'on affiche un évènement
 - une page listevents.php qui liste les évènements par tag
 - une page tags.php qui liste les tags

À faire:
 - flux RSS par tag
 - calendriers iCal par tag

Que pensez-vous de cette implémentation ? Que peut-on ajouter d'autre ?
Que peut-on améliorer ?

Merci de vos commentaires et bonne soirée,

Thomas

 funcs.inc.php  |   34 +++++++++++++++--
 listevents.php |  113 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 moderate.php   |   18 +++++----
 rss.php        |   18 ++++++++-
 showevent.php  |    3 +
 submit.php     |   41 ++++++++++++++++----
 tags.php       |   72 ++++++++++++++++++++++++++++++++++++
 7 files changed, 276 insertions(+), 23 deletions(-)

Index: tags.php
===================================================================
--- tags.php	(révision 0)
+++ tags.php	(révision 0)
@@ -0,0 +1,72 @@
+<?php
+
+/* Copyright 2005
+ * - Mélanie Bats <melanie POINT bats CHEZ utbm POINT fr>
+ * - Thomas Petazzoni <thomas POINT petazzoni CHEZ enix POINT org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+include("bd.inc.php");
+include("funcs.inc.php");
+
+put_header("Tags");
+
+echo "<h2>Tags</h2>";
+
+$db = new db();
+
+$sql = "select tags from events where tags != ''";
+$events = $db->query($sql);
+if (! $events)
+{
+  echo "<p>Erreur lors de la requête SQL.</p>";
+  put_footer();
+  exit;
+}
+
+$tags = array();
+while($event = mysql_fetch_object($events))
+{
+  foreach(split(" ", $event->tags) as $tag)
+    {
+      if (! isset($tags[$tag]))
+	$tags[$tag] = 1;
+      else
+	$tags[$tag]++;
+    }
+}
+
+echo "<p style=\"text-align: center; margin-top: 40px;\">";
+asort($tags);
+foreach($tags as $tag => $count)
+{
+  if ($count > 10)
+    echo "<font size=\"+3\">";
+  else if ($count > 2)
+    echo "<font size=\"+2\">";
+  else
+    echo "<font>";
+  echo "<a href=\"listevents.php?tag=" . $tag . "\">";
+  echo $tag;
+  echo "</a> ";
+  echo "</font>\n";
+}
+echo "</p>";
+
+put_footer();
+
+?>
\ Pas de fin de ligne à la fin du fichier
Index: submit.php
===================================================================
--- submit.php	(révision 196)
+++ submit.php	(copie de travail)
@@ -26,7 +26,7 @@
 $db = new db();
 
 function alert_moderators ($db, $id, $title, $start, $end, $description, $city,
-			   $region, $locality, $url, $contact, $submitter)
+			   $region, $locality, $url, $contact, $submitter, $tags)
 {
   global $moderatorlist;
 
@@ -35,7 +35,7 @@
   $mail_body = "Bonjour,\n\n" .
     "Un nouvel évènement est à modérer sur\n" . calendar_absolute_url("moderate.php#" . $id) . "\n\n".
     format_ascii_event ($db, $title, $start, $end, $description, $city, $region,
-			$locality, $url, $contact, $submitter) . "\n\n" .
+			$locality, $url, $contact, $submitter, $tags) . "\n\n" .
     "Merci !\n" .
     "-- Agenda du Libre";
 
@@ -44,7 +44,7 @@
   return 0;
 }
 
-function add_event ($db, $title, $start, $end, $description, $city, $region, $locality, $url, $contact, $submitter)
+function add_event ($db, $title, $start, $end, $description, $city, $region, $locality, $url, $contact, $submitter, $tags)
 {
   $error_cnt = 0;
 
@@ -54,6 +54,7 @@
   $url = stripslashes(strip_tags($url));
   $contact = stripslashes(strip_tags($contact));
   $submitter = stripslashes(strip_tags($submitter));
+  $tags_list = stripslashes(strip_tags($tags));
 
   if (! $description)
     {
@@ -103,6 +104,20 @@
       $error_cnt++;
     }
 
+  foreach(split(" ", $tags) as $tag)
+    {
+      if (! ereg("^[a-z0-9\-]*$", $tag))
+	{
+	  error("Tag '" . $tag . "' invalide. Les tags ne doivent contenir que des lettres minuscules, des chiffres ou des tirets.");
+	  $error_cnt++;
+	}
+      if (strlen($tag) < 4)
+	{
+	  error("Tag '" . $tag . "' trop court. Les tags doivent faire au moins 4 caractères de long.");
+	  $error_cnt++;
+	}
+    }
+
   if ($error_cnt != 0)
     {
       return -1;
@@ -112,7 +127,7 @@
     $submitter = $contact;
 
   /* Checks are done, add to database */
-  $sql = "INSERT INTO events (title,description,start_time,end_time,city,region,locality,url,contact,submitter,moderated) values (" .
+  $sql = "INSERT INTO events (title,description,start_time,end_time,city,region,locality,url,contact,submitter,tags,moderated) values (" .
     $db->quote_smart($title)                        . "," .
     $db->quote_smart($description)                  . "," .
     $db->quote_smart(date_timestamp2mysql ($start)) . "," .
@@ -123,6 +138,7 @@
     $db->quote_smart($url)                          . "," .
     $db->quote_smart($contact)                      . "," .
     $db->quote_smart($submitter)                    . "," .
+    $db->quote_smart($tags)                         . "," .
     "'0')";
 
   $ret = $db->query ($sql);
@@ -133,10 +149,13 @@
       return -1;
     }
 
+  $eventid = $db->insertid();
+
   alert_moderators ($db, $db->insertid(), $title, $start, $end, $description, $city,
-		    $region, $locality, $url, $contact, $submitter);
+		    $region, $locality, $url, $contact, $submitter, $tags);
 
-  echo "<p><b>Votre évènement a bien été ajouté à la liste des évènements en attente de modération. Il apparaîtra en ligne dès qu'un modérateur l'aura validé.</b></p>";
+  echo "<p><b>Votre évènement a bien été ajouté à la liste des évènements en attente de modération." .
+       "Il apparaîtra en ligne dès qu'un modérateur l'aura validé.</b></p>";
 
   echo "<p><a href=\"index.php\">Retour à l'Agenda</a></p>";
 
@@ -182,7 +201,8 @@
 		    $_POST['__event_locality'],
 		    $_POST['__event_url'],
 		    $_POST['__event_contact'],
-		    $_POST['__event_submitter']);
+		    $_POST['__event_submitter'],
+		    $_POST['__event_tags']);
 
   if ($ret == 0)
     {
@@ -207,7 +227,8 @@
 			 $_POST['__event_locality'],
 			 $_POST['__event_url'],
 			 $_POST['__event_contact'],
-			 $_POST['__event_submitter']);
+			 $_POST['__event_submitter'],
+			 $_POST['__event_tags']);
       echo "<hr/>";
     }
 }
@@ -224,7 +245,8 @@
 		     $_POST['__event_locality'],
 		     $_POST['__event_url'],
 		     $_POST['__event_contact'],
-		     $_POST['__event_submitter']);
+		     $_POST['__event_submitter'],
+		     $_POST['__event_tags']);
   echo "<hr/>";
 }
 
@@ -313,6 +335,7 @@
 	    $_POST['__event_url'],
 	    $_POST['__event_contact'],
 	    $_POST['__event_submitter'],
+	    $_POST['__event_tags'],
 	    TRUE);
 
 echo "</form>\n";
Index: listevents.php
===================================================================
--- listevents.php	(révision 0)
+++ listevents.php	(révision 0)
@@ -0,0 +1,113 @@
+<?php
+
+/* Copyright 2005
+ * - Mélanie Bats <melanie POINT bats CHEZ utbm POINT fr>
+ * - Thomas Petazzoni <thomas POINT petazzoni CHEZ enix POINT org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+include("bd.inc.php");
+include("funcs.inc.php");
+
+function list_events($events)
+{
+  echo " <ul>\n";
+  while($event = mysql_fetch_object($events))
+    {
+      echo "<li>";
+      echo "<a href=\"showevent.php?id=" . $event->id . "\">";
+      echo stripslashes($event->title);
+      echo "</a>";
+      $startday = onlyday_timestamp2humanreadable(date_mysql2timestamp($event->start_time));
+      $endday   = onlyday_timestamp2humanreadable(date_mysql2timestamp($event->end_time));
+      echo "<br/>";
+      if ($startday == $endday)
+	echo "le " . $startday . " ";
+      else
+	echo "du " . $startday . " au " . $endday . " ";
+      echo " à " . $event->city;
+      echo "</li>";
+    }
+  echo " </ul>\n";
+}
+
+put_header("Liste d'évènements");
+
+$db = new db();
+
+if (! $_GET['tag'] || !ereg("^[a-z0-9\-]*$", $_GET['tag']))
+{
+  echo "<p><b>Aucun tag sélectionné, ou tag invalide.</b></p>";
+  put_footer();
+  exit;
+}
+
+echo "<h2>Les évènements <i>" . $_GET['tag'] . "</i></h2>\n";
+$hasevent = FALSE;
+
+$sql = "select id, title, city, start_time, end_time from events " .
+       "where tags like '%" . $_GET['tag'] . "%' and start_time > NOW() order by start_time";
+$events = $db->query($sql);
+if (! $events)
+{
+  echo "<p><b>Erreur lors de la requête SQL.</b></p>";
+  put_footer();
+  exit;
+}
+
+if (mysql_num_rows($events))
+{
+  $hasevent = TRUE;
+  echo "<p>";
+  echo "<b>Prochainement</b>";
+  if (mysql_num_rows($events) == 1)
+    echo ", un évènement&nbsp;:";
+  else
+    echo ", " . mysql_num_rows($events) . " évènements&nbsp;:";
+  echo "</p>";
+  list_events($events);
+}
+
+$sql = "select id, title, city, start_time, end_time from events ".
+       "where tags like '%" . $_GET['tag'] . "%' and start_time < NOW() order by start_time desc";
+$events = $db->query($sql);
+if (! $events)
+{
+  echo "<p><b>Erreur lors de la requête SQL.</b>/p>";
+  put_footer();
+  exit;
+}
+
+if (mysql_num_rows($events))
+{
+  $hasevent = TRUE;
+  echo "<p>";
+  echo "<b>Dans le passé</b>";
+  if (mysql_num_rows($events) == 1)
+    echo ", un évènement&nbsp;:";
+  else
+    echo ", " . mysql_num_rows($events) . " évènements&nbsp;:";
+  echo "</p>";
+  list_events($events);
+}
+
+if (! $hasevent)
+  echo "<p>Aucun évènement avec ce tag.</p>";
+
+put_footer();
+?>
+
Index: moderate.php
===================================================================
--- moderate.php	(révision 196)
+++ moderate.php	(copie de travail)
@@ -43,7 +43,7 @@
 }
 
 function save_event ($db, $id, $title, $start, $end, $description, $city,
-		     $region, $locality, $url, $contact, $submitter, $userid)
+		     $region, $locality, $url, $contact, $submitter, $tags, $userid)
 {
   global $moderatorlist;
 
@@ -67,7 +67,8 @@
     "locality=" .    $db->quote_smart ($locality)                     . ", ".
     "url=" .         $db->quote_smart ($url)                          . ", ".
     "contact=" .     $db->quote_smart ($contact)                      . ", ".
-    "submitter=" .   $db->quote_smart ($submitter)                    . "  ".
+    "submitter=" .   $db->quote_smart ($submitter)                    . ", ".
+    "tags=" .        $db->quote_smart ($tags)                         . "  ".
     "where id=" .    $db->quote_smart ($id);
 
   $ret = $db->query ($sql);
@@ -82,11 +83,11 @@
     format_ascii_event ($db, $oldevent->title, date_mysql2timestamp($oldevent->start_time),
 			date_mysql2timestamp($oldevent->end_time),
 			$oldevent->description, $oldevent->city, $oldevent->region, $oldevent->locality,
-			$oldevent->url, $oldevent->contact, $oldevent->submitter);
+			$oldevent->url, $oldevent->contact, $oldevent->submitter, $oldevent->tags);
   $newevent_str =
     format_ascii_event ($db, $title, $start, $end,
 			$description, $city, $region, $locality,
-			$url, $contact, $submitter);
+			$url, $contact, $submitter, $tags);
 
   $diff = arr_diff (split ("\n", $oldevent_str), split ("\n", $newevent_str), 1);
 
@@ -142,7 +143,7 @@
 		 format_ascii_event ($db, $row->title, date_mysql2timestamp($row->start_time),
 				     date_mysql2timestamp($row->end_time),
 				     $row->description, $row->city, $row->region, $row->locality,
-				     $row->url, $row->contact, $row->submitter) . "\n" .
+				     $row->url, $row->contact, $row->submitter, $row->tags) . "\n" .
 		 "=====================================================\n\n" .
 		 "Merci de votre contribution à l'Agenda du Libre et à bientôt !\n\n".
 		 "-- \nL'équipe de modération");
@@ -185,7 +186,7 @@
 		 format_ascii_event ($db, $row->title, date_mysql2timestamp($row->start_time),
 				     date_mysql2timestamp($row->end_time),
 				     $row->description, $row->city, $row->region, $row->locality,
-				     $row->url, $row->contact, $row->submitter) . "\n" .
+				     $row->url, $row->contact, $row->submitter, $row->tags) . "\n" .
 		 "=====================================================\n\n" .
 		 "Merci de votre contribution !\n\n" .
 		 "-- \nL'équipe de modération");
@@ -285,7 +286,8 @@
 		  $event->locality,
 		  $event->url,
 		  $event->contact,
-		  $event->submitter);
+		  $event->submitter,
+		  $event->tags);
       echo "</form>\n";
     }
 
@@ -319,6 +321,7 @@
 		     $_POST['__event_url'],
 		     $_POST['__event_contact'],
 		     $_POST['__event_submitter'],
+		     $_POST['__event_tags'],
 		     $session->value ("agenda_libre_id"));
 
   if ($ret == 0)
@@ -395,6 +398,7 @@
 		     $row->url,
 		     $row->contact,
 		     $row->submitter,
+		     $row->tags,
 		     TRUE);
   echo "<input type=\"submit\" name=\"__event_edit\" value=\"Éditer\"/>";
   echo "<input type=\"submit\" name=\"__event_accept\" value=\"Accepter\"/>";
Index: rss.php
===================================================================
--- rss.php	(révision 196)
+++ rss.php	(copie de travail)
@@ -128,18 +128,32 @@
 
 while ($event = mysql_fetch_object($list))
 {
+  $tags = fetch_tags($db, $event->id);
+
   echo "  <item rdf:about=\"" . calendar_absolute_url("showevent.php?id=" . $event->id) . "\">\n";
   echo "   <title>" . xmlentities($event->city) . " : " . xmlentities($event->title) . "</title>\n";
   echo "   <link>" . calendar_absolute_url("showevent.php?id=" . $event->id) . "</link>\n";
   echo "   <guid>" . $event->id . "@agendadulibre.org</guid>";
   echo "   <description>\n";
 
-  echo xmlentities(strip_tags(format_event ($db, $event->title, date_mysql2timestamp($event->start_time), date_mysql2timestamp($event->end_time), $event->description, $event->city, $event->region, $event->locality, $event->url, $event->contact, $event->submitter)));
+  echo xmlentities(strip_tags(format_event ($db, $event->title,
+					    date_mysql2timestamp($event->start_time),
+					    date_mysql2timestamp($event->end_time),
+					    $event->description, $event->city,
+					    $event->region, $event->locality,
+					    $event->url, $event->contact,
+					    $event->submitter, $tags)));
 
   echo "   </description>\n";
   echo "   <content:encoded>\n";
 
-  echo xmlentities(format_event ($db, $event->title, date_mysql2timestamp($event->start_time), date_mysql2timestamp($event->end_time), $event->description, $event->city, $event->region, $event->locality, $event->url, $event->contact, $event->submitter));
+  echo xmlentities(format_event ($db, $event->title,
+				 date_mysql2timestamp($event->start_time),
+				 date_mysql2timestamp($event->end_time),
+				 $event->description, $event->city,
+				 $event->region, $event->locality,
+				 $event->url, $event->contact,
+				 $event->submitter, $tags));
 
   echo "   </content:encoded>\n";
   echo "  </item>\n\n";
Index: showevent.php
===================================================================
--- showevent.php	(révision 196)
+++ showevent.php	(copie de travail)
@@ -72,7 +72,8 @@
 		     $event->locality,
 		     $event->url,
 		     $event->contact,
-		     $event->submitter);
+		     $event->submitter,
+		     $event->tags);
 }
 
 put_footer();
Index: funcs.inc.php
===================================================================
--- funcs.inc.php	(révision 198)
+++ funcs.inc.php	(copie de travail)
@@ -99,7 +99,7 @@
 ?>
 </div>
 <div class="footer">
-<p><a href="submit.php">Proposer un évènement</a> - <a href="rsslist.php">Flux RSS</a> - <a href="icallist.php">Calendriers iCal</a> - <a href="map.php">Carte</a> - <a href="infos.php">Informations</a> - <a href="stats.php">Statistiques</a> - <a href="mailto:moderateurs CHEZ agendadulibre POINT org">Contact</a></p>
+<p><a href="submit.php">Proposer un évènement</a> - <a href="rsslist.php">Flux RSS</a> - <a href="icallist.php">Calendriers iCal</a> - <a href="map.php">Carte</a> - <a href="tags.php">Tags</a> - <a href="infos.php">Informations</a> - <a href="stats.php">Statistiques</a> - <a href="mailto:moderateurs CHEZ agendadulibre POINT org">Contact</a></p>
 </div>
 </body>
 </html>
@@ -546,7 +546,7 @@
  */
 function format_event ($db, $title, $start, $end, $description,
 		       $city, $region, $locality, $url, $contact,
-		       $submitter, $moderation = FALSE)
+		       $submitter, $tags, $moderation = FALSE)
 {
   $title       = stripslashes($title);
   $region      = stripslashes(region_find($db, $region));
@@ -578,6 +578,19 @@
   if ($moderation)
     $result .= "<p>Évènement à portée <b>" . ($locality == 1 ? "nationale" : "locale") . "</b></p>";
 
+  if ($tags != "")
+    {
+      $tags = split(" ", $tags);
+      $result .= "<p>Tags: ";
+      for ($i = 0; $i < count($tags); $i++)
+	{
+	  $result .= "<a href=\"listevents.php?tag=" . $tags[$i] . "\">" . $tags[$i] . "</a>";
+	  if ($i != count($tags) - 1)
+	    $result .= ", ";
+	}
+      $result .= "</p>";
+    }
+
   return $result;
 }
 
@@ -588,7 +601,7 @@
  */
 function format_ascii_event ($db, $title, $start, $end, $description,
 			     $city, $region, $locality, $url, $contact,
-			     $submitter)
+			     $submitter, $tags)
 {
   $title       = stripslashes($title);
   $start       = date_timestamp2humanreadable($start);
@@ -599,6 +612,7 @@
   $url         = stripslashes($url);
   $contact     = scramble_email(stripslashes($contact));
   $submitter   = scramble_email(stripslashes($submitter));
+  $tags        = stripslashes($tags);
 
   $str =
     "Titre       : " . $title . "\n" .
@@ -609,6 +623,7 @@
     "URL         : " . $url . "\n".
     "Contact     : " . $contact . "\n" .
     "Soumetteur  : " . $submitter . "\n" .
+    "Tags        : " . $tags . "\n" .
     "Description : \n " . preg_replace ("/\n/", "\n ", $description);
 
   return $str;
@@ -689,7 +704,7 @@
 
 function edit_event ($db, $title, $start, $end, $description,
 		     $city, $region, $locality, $url, $contact,
-		     $submitter, $wants_preview = FALSE)
+		     $submitter, $tags, $wants_preview = FALSE)
 {
   $title       = escape_form_string($title);
   $description = escape_form_string($description, "<p><b><i><br/><a><ul><li><ol>");
@@ -697,6 +712,7 @@
   $url         = escape_form_string($url);
   $contact     = escape_form_string($contact);
   $submitter   = escape_form_string($submitter);
+  $tags        = escape_form_string($tags);
 
 ?>
  <table>
@@ -811,6 +827,16 @@
    </td>
   </tr>
 
+  <tr>
+   <td>
+    Tags:
+   </td>
+   <td>
+    <i>Tags pour l'évènement. Les tags sont séparés par des espaces. Un tag ne peut contenir que des lettres minuscules, des chiffres et des tirets.</i><br/>
+    <input type="text" size="70" name="__event_tags" value="<?php echo $tags; ?>"/><br/>
+   </td>
+  </tr>
+
  <tr>
   <td>
   </td>


-- 
PETAZZONI Thomas - thomas.petazzoni at enix.org 
http://{thomas,sos,kos}.enix.org - Jabber: thomas.petazzoni at jabber.dk
http://{agenda,livret}dulibre.org - http://www.toulibre.org
Fingerprint : 0BE1 4CF3 CEA4 AC9D CC6E  1624 F653 CB30 98D3 F7A7


Plus d'informations sur la liste de diffusion Devel