#642: Image in events
authorx2003bruneau <x2003bruneau@839d8a87-29fc-0310-9880-83ba4fa771e5>
Wed, 7 Mar 2007 09:40:22 +0000 (09:40 +0000)
committerx2003bruneau <x2003bruneau@839d8a87-29fc-0310-9880-83ba4fa771e5>
Wed, 7 Mar 2007 09:40:22 +0000 (09:40 +0000)
git-svn-id: svn+ssh://murphy/home/svn/platal/trunk@1555 839d8a87-29fc-0310-9880-83ba4fa771e5

14 files changed:
ChangeLog
classes/platal.php
classes/plupload.php
htdocs/css/default.css
htdocs/css/keynote.css
include/validations.inc.php
include/validations/evts.inc.php
modules/events.php
modules/xnetgrp.php
templates/events/form.tpl
templates/events/index.tpl
templates/include/form.valid.edit-evts.tpl
templates/include/form.valid.evts.tpl
upgrade/0.9.14/03_evenements.tpl [new file with mode: 0644]

index af87d45..5ca1597 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -9,6 +9,7 @@ New:
         - New Upload manager                                               -FRU
 
     * Events:
+        - #642: Can add an image                                           -FRU
         - #643: Sort menu                                                  -FRU
         - Can set events as important                                      -FRU
 
index cdfb3cb..686d83d 100644 (file)
@@ -125,7 +125,7 @@ class Platal
         return null;
     }
 
-    protected function near_hook()
+    public function near_hook()
     {
         $hooks = array();
         foreach ($this->__hooks as $hook=>$handler) {
index d5f428f..743a090 100644 (file)
@@ -89,6 +89,10 @@ class PlUpload
 
     public function download($url)
     {
+        if (!$url || @parse_url($url) === false) {
+            trigger_error('malformed URL given', E_USER_NOTICE);
+            return false;
+        }
         $data = file_get_contents($url);
         if (!$data) {
             return false;
@@ -158,9 +162,28 @@ class PlUpload
         return $this->type;
     }
 
+    public function isType($type, $subtype = null)
+    {
+        list($mytype, $mysubtype) = explode('/', $this->type);
+        if ($mytype != $type || ($subtype && $mysubtype != $subtype)) {
+            return false;
+        }
+        return true;
+    }
+
     public function imageInfo()
     {
-        return getimagesize($this->filename);
+        static $map;
+        if (!isset($map)) {
+            $map = array (1 => 'gif', 2 => 'jpeg', 3 => 'png');
+        }
+        $array = getimagesize($this->filename);
+        $array[2] = @$map[$array[2]];
+        if (!$array[2]) {
+            trigger_error('unknown image type', E_USER_NOTICE);
+            return null;
+        }
+        return $array;
     }
 
     public function resizeImage($max_x = -1, $max_y = -1, $min_x = 0, $min_y = 0, $maxsize = -1)
@@ -170,15 +193,11 @@ class PlUpload
             return false;
         }
         $image_infos = $this->imageInfo();
-        if (empty($image_infos)) {
+        if (!$image_infos) {
             trigger_error('invalid image', E_USER_NOTICE);
             return false;
         }
         list($this->x, $this->y, $mimetype) = $image_infos;
-        if ($mimetype < 1 || $mimetype > 3) { // 1 - gif, 2 - jpeg, 3 - png
-            trigger_error('unknown image type', E_USER_NOTICE);
-            return false;
-        }
         if ($max_x == -1) {
             $max_x = $this->x;
         }
index b948fab..178c0a0 100644 (file)
@@ -583,4 +583,8 @@ div#content {
     font-size: 95%;
 }
 
+#menu-evts {
+    font-size: 85%;
+}
+
 /* vim: set et ts=4 sts=4 sw=4: */
index 3b45110..3190db2 100644 (file)
@@ -605,4 +605,8 @@ div#content {
     font-size: 95%;
 }
 
+#menu-evts {
+    font-size: 85%;
+}
+
 /* vim: set et ts=4 sts=4 sw=4: */
index 4c35048..87d2a62 100644 (file)
@@ -285,6 +285,15 @@ abstract class Validate
     }
 
     // }}}
+    // {{{ function get_request_by_id()
+
+    static public function get_request_by_id($id)
+    {
+        list($uid, $type, $stamp) = explode('_', $id, 3);
+        return Validate::get_typed_request($uid, $type, $stamp);
+    }
+
+    // }}}
     // {{{ function get_typed_requests()
 
     /** same as get_typed_request() but return an array of objects
index 9cca8b5..1adf6db 100644 (file)
@@ -32,11 +32,16 @@ class EvtReq extends Validate
     public $pmax;
     public $peremption;    
     public $comment;
+
+    public $imgtype;
+    public $imgx;
+    public $imgy;
+    public $img;
     
     // }}}
     // {{{ constructor
 
-    public function __construct($_titre, $_texte, $_pmin, $_pmax, $_peremption, $_comment, $_uid)
+    public function __construct($_titre, $_texte, $_pmin, $_pmax, $_peremption, $_comment, $_uid, PlUpload &$upload = null)
     {
         parent::__construct($_uid, false, 'evts');
         $this->titre      = $_titre;
@@ -45,6 +50,21 @@ class EvtReq extends Validate
         $this->pmax       = $_pmax;
         $this->peremption = $_peremption;
         $this->comment    = $_comment;
+        if ($upload) {
+            $this->readImage($upload);
+        } 
+    }
+
+    // }}}
+    // {{{ function readImage()
+
+    private function readImage(PlUpload &$upload)
+    {
+        if ($upload->exists() && $upload->isType('image')) {
+            list($this->imgx, $this->imgy, $this->imgtype) = $upload->imageInfo();
+            $this->img = $upload->getContents();
+            $upload->rm();
+        }
     }
 
     // }}}
@@ -73,6 +93,19 @@ class EvtReq extends Validate
         $this->pmin       = Env::i('promo_min');
         $this->pmax       = Env::i('promo_max');
         $this->peremption = Env::v('peremption');
+        if (@$_FILES['image']['tmp_name']) {
+            $upload = PlUpload::get($_FILES['image'], S::v('forlife'), 'event');
+            if (!$upload) {
+                $this->trig("Impossible de télécharger le fichier");
+            } elseif (!$upload->isType('image')) {
+                $page->trig('Le fichier n\'est pas une image valide au format JPEG, GIF ou PNG');
+                $upload->rm();
+            } elseif (!$upload->resizeImage(200, 300, 100, 100, 32284)) {
+                $page->trig('Impossible de retraiter l\'image');
+            } else {
+                $this->readImage($upload);
+            }
+        }
         return true;
     }
 
@@ -101,12 +134,19 @@ class EvtReq extends Validate
 
     public function commit()
     {
-        return XDB::execute(
-                "INSERT INTO  evenements
+        if (XDB::execute("INSERT INTO  evenements
                          SET  user_id = {?}, creation_date=NOW(), titre={?}, texte={?},
                               peremption={?}, promo_min={?}, promo_max={?}, flags=CONCAT(flags,',valide')",
                 $this->uid, $this->titre, $this->texte,
-                $this->peremption, $this->pmin, $this->pmax);
+                $this->peremption, $this->pmin, $this->pmax)) {
+            if ($this->img) {
+                XDB::execute("INSERT INTO evenements_photo
+                                      SET eid = {?}, attachmime = {?}, x = {?}, y = {?}, attach = {?}",
+                             XDB::insertId(), $this->imgtype, $this->imgx, $this->imgy, $this->img);
+            }
+            return true;
+        }
+        return false;
     }
 
     // }}}
index 71eaaa2..2ac6457 100644 (file)
@@ -27,6 +27,7 @@ class EventsModule extends PLModule
             'events'         => $this->make_hook('ev',        AUTH_COOKIE),
             'rss'            => $this->make_hook('rss', AUTH_PUBLIC),
             'events/preview' => $this->make_hook('preview', AUTH_PUBLIC, 'user', NO_AUTH),
+            'events/photo'   => $this->make_hook('photo', AUTH_COOKIE),
             'events/submit'  => $this->make_hook('ev_submit', AUTH_MDP),
             'admin/events'   => $this->make_hook('admin_events',     AUTH_MDP, 'admin'),
 
@@ -35,7 +36,7 @@ class EventsModule extends PLModule
         );
     }
 
-    function get_tips($exclude = null)
+    private function get_tips($exclude = null)
     {
         global $globals;
         // Add a new special tip when changing plat/al version
@@ -79,7 +80,7 @@ class EventsModule extends PLModule
         return $res->fetchOneAssoc();
     }
 
-    function get_events($where, $order, array &$array, $name)
+    private function get_events($where, $order, array &$array, $name)
     {
         // affichage des evenements
         // annonces promos triées par présence d'une limite sur les promos
@@ -98,10 +99,12 @@ class EventsModule extends PLModule
         if (!$sum->total()) {
             return false;
         }
-        $sql = "SELECT  e.id,e.titre,e.texte,a.user_id,a.nom,a.prenom,a.promo,l.alias AS forlife
-                  FROM  evenements     AS e
-            INNER JOIN  auth_user_md5  AS a ON e.user_id=a.user_id
-            INNER JOIN  aliases        AS l ON ( a.user_id=l.id AND l.type='a_vie' )
+        $sql = "SELECT  e.id,e.titre,e.texte,a.user_id,a.nom,a.prenom,a.promo,l.alias AS forlife,
+                        p.x, p.y, p.attach IS NOT NULL AS img
+                  FROM  evenements       AS e
+             LEFT JOIN  evenements_photo AS p ON (e.id = p.eid)
+            INNER JOIN  auth_user_md5    AS a ON e.user_id=a.user_id
+            INNER JOIN  aliases          AS l ON ( a.user_id=l.id AND l.type='a_vie' )
              LEFT JOIN  evenements_vus AS ev ON (e.id = ev.evt_id AND ev.user_id = {?})
                  WHERE  FIND_IN_SET('valide', e.flags) AND peremption >= NOW()
                         AND (e.promo_min = 0 || e.promo_min <= {?})
@@ -114,6 +117,25 @@ class EventsModule extends PLModule
         return true;
     }
 
+    private function upload_image(PlatalPage &$page, PlUpload &$upload)
+    {
+        if (@!$_FILES['image']['tmp_name'] && !Env::v('image_url')) {
+            return true;
+        }
+        if (!$upload->upload($_FILES['image'])  && !$upload->download(Env::v('image_url'))) {
+            $page->trig('Impossible de télécharger l\'image');
+            return false;
+        } elseif (!$upload->isType('image')) {
+            $page->trig('Le fichier n\'est pas une image valide au format JPEG, GIF ou PNG');
+            $upload->rm();
+            return false;
+        } elseif (!$upload->resizeImage(200, 300, 100, 100, 32284)) {
+            $page->trig('Impossible de retraiter l\'image');
+            return false;
+        }
+        return true;
+    }
+
     function handler_ev(&$page, $action = 'list', $eid = null, $pound = null)
     {
         $page->changeTpl('events/index.tpl');
@@ -190,6 +212,38 @@ class EventsModule extends PLModule
         $page->assign_by_ref('events', $array);
     }
 
+    function handler_photo(&$page, $eid = null, $valid = null)
+    {
+        if ($eid && $eid != 'valid') {
+            $res = XDB::query("SELECT * FROM evenements_photo WHERE eid = {?}", $eid);
+            if ($res->numRows()) {
+                $photo = $res->fetchOneAssoc();
+                header('Content-Type: image/' . $photo['attachmime']);
+                echo $photo['attach'];
+                exit;
+            }
+        } elseif ($eid == 'valid') {
+            require_once 'validations.inc.php';
+            $valid = Validate::get_request_by_id($valid);
+            if ($valid && $valid->img) {
+                header('Content-Type: image/' . $valid->imgtype);
+                echo $valid->img;
+                exit;
+            }
+        } else {
+            $upload = new PlUpload(S::v('forlife'), 'event');
+            if ($upload->exists() && $upload->isType('image')) {
+                header('Content-Type: ' . $upload->contentType());
+                echo $upload->getContents();
+                exit;
+            }
+        }
+        global $globals;
+        header('Content-Type: image/png');
+        echo file_get_contents($globals->spoolroot . '/htdocs/images/logo.png');
+        exit;
+    }
+
     function handler_rss(&$page, $user = null, $hash = null)
     {       
         require_once 'rss.inc.php';
@@ -243,6 +297,8 @@ class EventsModule extends PLModule
         $peremption = Post::i('peremption');
         $valid_mesg = Post::v('valid_mesg');
         $action     = Post::v('action');
+        $upload     = new PlUpload(S::v('forlife'), 'event');
+        $this->upload_image($page, $upload);
 
         if (($promo_min > $promo_max && $promo_max != 0)||
             ($promo_min != 0 && ($promo_min <= 1900 || $promo_min >= 2020)) ||
@@ -263,16 +319,22 @@ class EventsModule extends PLModule
         $page->assign('peremption', $peremption);
         $page->assign('valid_mesg', $valid_mesg);
         $page->assign('action', strtolower($action));
+        $page->assign_by_ref('upload', $upload);
 
-        if ($action && (!trim($texte) || !trim($titre))) {
+        if ($action == 'Supprimer l\'image') {
+            $upload->rm();
+            $page->assign('action', false);
+        } elseif ($action && (!trim($texte) || !trim($titre))) {
             $page->trig("L'article doit avoir un titre et un contenu");
         } elseif ($action) {
                $texte = $texte_catch_url;
             require_once 'validations.inc.php';
             $evtreq = new EvtReq($titre, $texte, $promo_min, $promo_max,
-                                 $peremption, $valid_mesg, S::v('uid'));
+                                 $peremption, $valid_mesg, S::v('uid'), $upload);
             $evtreq->submit();
             $page->assign('ok', true);
+        } elseif (!Env::v('preview')) {
+            $upload->rm();
         }
 
         $select = '';
@@ -327,8 +389,21 @@ class EventsModule extends PLModule
 
         $arch = $action == 'archives';
         $page->assign('action', $action);
-        if (Post::v('action') == "Proposer" && $eid) {
+
+        $upload = new PlUpload(S::v('forlife'), 'event');
+        if ((Env::has('preview') || Post::v('action') == "Proposer") && $eid) {
+            $action = 'edit';
+            $this->upload_image($page, $upload);
+        }
+
+        if (Post::v('action') == 'Pas d\'image' && $eid) {
+            $upload->rm();
+            XDB::execute("DELETE FROM evenements_photo WHERE eid = {?}", $eid);
+            $action = 'edit';
+        } elseif (Post::v('action') == 'Supprimer l\'image' && $eid) {
+            $upload->rm();
+            $action = 'edit';
+        } elseif (Post::v('action') == "Proposer" && $eid) {
             $promo_min = Post::i('promo_min');
             $promo_max = Post::i('promo_max');
             if ($promo_min > $promo_max ||
@@ -353,14 +428,22 @@ class EventsModule extends PLModule
                               Post::v('titre'), Post::v('texte'), Post::v('peremption'),
                               Post::v('promo_min'), Post::v('promo_max'),
                               $flags->flags(), $eid);
+                if ($upload->exists() && list($x, $y, $type) = $upload->imageInfo()) {
+                    XDB::execute('REPLACE INTO  evenements_photo
+                                           SET  eid = {?}, attachmime = {?}, x = {?}, y = {?}, attach = {?}',
+                                 $eid, $type, $x, $y, $upload->getContents());
+                    $upload->rm();
+                }
             }    
         }
 
         if ($action == 'edit') {
-            $res = XDB::query('SELECT titre, texte, peremption, promo_min, promo_max, FIND_IN_SET(\'important\', flags)
-                                 FROM evenements
+            $res = XDB::query('SELECT titre, texte, peremption, promo_min, promo_max, FIND_IN_SET(\'important\', flags),
+                                      attach IS NOT NULL
+                                 FROM evenements       AS e
+                            LEFT JOIN evenements_photo AS p ON(e.id = p.eid)
                                 WHERE id={?}', $eid);
-            list($titre, $texte, $peremption, $promo_min, $promo_max, $important) = $res->fetchOneRow();
+            list($titre, $texte, $peremption, $promo_min, $promo_max, $important, $img) = $res->fetchOneRow();
             $page->assign('titre',$titre);
             $page->assign('texte',$texte);
             $page->assign('texte_html', pl_entity_decode($texte));
@@ -368,6 +451,9 @@ class EventsModule extends PLModule
             $page->assign('promo_max',$promo_max);
             $page->assign('peremption',$peremption);
             $page->assign('important', $important);
+            $page->assign('eid', $eid);
+            $page->assign('img', $img);
+            $page->assign_by_ref('upload', $upload);
 
             $select = "";
             for ($i = 1 ; $i < 30 ; $i++) {
index e0da41d..104a5f0 100644 (file)
@@ -214,7 +214,7 @@ class XnetGrpModule extends PLModule
             $page->trig('Le groupe n\'a pas de site web');
             return $this->handler_index($page);
         }
-        header("Location: $site");
+        http_redirect($site);
         exit;
     }
 
index 5a22651..418b1de 100644 (file)
@@ -24,6 +24,9 @@
   {literal}
   function updatePreview()
   {
+    if (document.getElementById('image').value != '' || document.getElementById('image_url').value != '') {
+      return true;
+    }
     var titre = document.getElementById('titre').value;
     var texte = document.getElementById('texte').value;
 
@@ -51,7 +54,7 @@
 </div>
 <br />
 
-<form action="{$platal->path}" method="post">
+<form action="{$platal->path}" method="post" enctype="multipart/form-data">
   <table class="bicol">
     <tr>
       <th colspan="2">Contenu de l'annonce</th>
         Essaie de faire un <strong>texte court</strong>, une annonce ne doit pas excéder 800 caractères soit une douzaine de ligne. Tu en es déjà à <input type='text' name='texte_count' size="4" /> caractères.
       </td>
     </tr>
+    <tr class="pair">
+      <td class="titre">Illustration</td>
+      <td>
+        {if $eid && $img}
+        <div style="float: left; text-align: center">
+          <em>Image actuelle</em><br />
+          <img src="events/photo/{$eid}" alt="Image actuelle" /><br />
+          <input type="submit" name="action" value="Pas d'image" />
+        </div>
+        {/if}
+        {if $upload && $upload->exists()}
+        <div style="float: right; text-align: center">
+          <em>Nouvelle image</em><br />
+          <img src="events/photo" alt="Nouvelle Image" /><br />
+          <input type="submit" name="action" value="Supprimer l'image" />
+        </div>
+        {/if}
+        <div style="clear: both">
+          Choisir un fichier : <input type="file" name="image" id="image" /><br />
+          Indiquer une adresse : <input type="text" name="image_url" id="image_url" value="" />
+        </div>
+      </td>
+    </tr>
   </table>
 
   <div class="center">
-    <input type="submit" name="preview" value="Aperçu" onclick="updatePreview(); return false;" />
+    <input type="submit" name="preview" value="Aperçu" onclick="return updatePreview();" />
   </div>
   <p id="info" {if trim($texte) && trim($titre)}style="display: none"{/if}>
     Le bouton de confirmation n'apparaît que si l'aperçu est concluant.
index c2d7e21..5284ea1 100644 (file)
@@ -89,9 +89,11 @@ Bienvenue {$smarty.session.prenom}
 
 {include file="include/tips.tpl" full=true}
   
-  <table class="bicol">
-    <tr>
-      <th>
+  <table class="tinybicol" id="menu-evts">
+    {foreach from=$events name=events key=category item=evenement}
+    <tr class="pair" style="height: 18px">
+      <td class="half titre" style="height: 18px; padding-top: 1px; padding-bottom: 1px;">
+        {if $smarty.foreach.events.first}
         {if $smarty.session.core_rss_hash}
         <a href='rss/{$smarty.session.forlife}/{$smarty.session.core_rss_hash}/rss.xml' style="display:block;float:right">
           {icon name=feed title='fil rss'}
@@ -100,14 +102,8 @@ Bienvenue {$smarty.session.prenom}
         <a href='prefs/rss?referer=events'  style="display:block;float:right">
           {icon name=feed_add title='Activer mon fil rss'}
         </a>
-       {/if}
-        Sommaire des informations événementielles
-      </th>
-    </tr>
-    {foreach from=$events name=events key=category item=evenement}
-    {if $smarty.foreach.events.total neq 1}
-    <tr class="pair" style="height: 18px">
-      <td class="half titre" style="height: 18px; padding-top: 1px; padding-bottom: 1px;">
+        {/if}
+        {/if}
         {if $category eq 'important'}
           {icon name=error} Informations prioritaires&nbsp;:
         {elseif $category eq 'news'}
@@ -119,7 +115,6 @@ Bienvenue {$smarty.session.prenom}
         {/if}
       </td>
     </tr>
-    {/if}
     {iterate item=ev from=$evenement.summary}
     <tr class="impair">
       <td class="half">
@@ -191,17 +186,34 @@ Bienvenue {$smarty.session.prenom}
         {/tidy}
       </th>
     </tr>
-    <tr class="{cycle values="impair,pair"}">
+    {cycle values="left,right" assign=position}
+    <tr class="impair">
+      <td class="half">
+        <div>
+          {* if $ev.img *}
+          <div style="float: {$position}; padding-{if $position eq right}left{else}right{/if}: 0.5em">
+            <img src="events/photo/{$ev.id}" alt="{$ev.title}" />
+          </div>
+          {* /if *}
+          <div style="text-align: justify">
+            {tidy}
+              {$ev.texte|smarty:nodefaults|nl2br}
+            {/tidy}
+          </div>
+        </div>
+      </td>
+    </tr>
+    <tr class="pair">
       <td class="half">
-        {tidy}
-          {$ev.texte|smarty:nodefaults|nl2br}
-        {/tidy}
-        <br />
-        <p class="smaller"><a href="events#pagetop" style="display:block;float:right"><img alt="Sommaire" title="Remonter tout en haut" src="images/up.png"/></a>Annonce proposée par
-        <a href="profile/{$ev.forlife}" class="popup2">
-          {$ev.prenom} {$ev.nom} X{$ev.promo}
+        <a href="events#pagetop" style="display:block; float: right; padding-left:1em">
+          <img alt="Sommaire" title="Remonter tout en haut" src="images/up.png"/>
         </a>
-        </p>
+        <span class="smaller">
+          Annonce proposée par
+          <a href="profile/{$ev.forlife}" class="popup2">
+            {$ev.prenom} {$ev.nom} X{$ev.promo}
+          </a>
+        </span>
       </td>
     </tr>
   </table>
index c97eec6..b696299 100644 (file)
@@ -27,6 +27,7 @@
 <strong>Péremption&nbsp;:</strong> <input type="text" name="peremption" size="10" value="{$valid->peremption}" />
 <strong>Promos&nbsp;:&nbsp;</strong>
 min <input type="text" name="promo_min" size="4" maxlength="4" value="{$valid->pmin}" />
-&nbsp;->&nbsp;max <input type="text" name="promo_max" size="4" maxlength="4" value="{$valid->pmax}" />
+&nbsp;->&nbsp;max <input type="text" name="promo_max" size="4" maxlength="4" value="{$valid->pmax}" /><br />
+<strong>Illustration&nbsp;:</strong> <input type="file" name="image" />
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
index 173bb08..d626a9a 100644 (file)
   <td>{$valid->pmin} - {$valid->pmax}</td>
 </tr>
 <tr class="pair">
-  <td class="titre">Commentaire</td>
-  <td>{$valid->comment}</td>
+  <td class="titre">Illustration</td>
+  <td>
+    {if $valid->imgtype}
+    <img src="events/photo/valid/{$valid->id()}" alt="Image" />
+    {else}
+    Pas d'image définie
+    {/if}
+  </td>
 </tr>
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/upgrade/0.9.14/03_evenements.tpl b/upgrade/0.9.14/03_evenements.tpl
new file mode 100644 (file)
index 0000000..40a959f
--- /dev/null
@@ -0,0 +1,11 @@
+alter table evenements change flags flags set('valide', 'archive', 'important') not null;
+create table evenements_photo (
+    eid smallint(4) unsigned not null,
+    attachmime enum('jpeg', 'png', 'gif') not null default 'jpeg',
+    attach blob not null,
+    x smallint(5) unsigned not null default 0,
+    y smallint(5) unsigned not null default 0,
+    primary key eid (eid)
+) charset=utf8;
+
+# vim:set syntax=mysql: