Allows users to notify erroneous geocoding.
authorStéphane Jacob <sj@m4x.org>
Tue, 10 May 2011 14:38:54 +0000 (16:38 +0200)
committerStéphane Jacob <sj@m4x.org>
Tue, 10 May 2011 15:44:41 +0000 (17:44 +0200)
Signed-off-by: Stéphane Jacob <sj@m4x.org>
classes/address.php
htdocs/javascript/profile.js
include/validations.inc.php
include/validations/address.inc.php [new file with mode: 0644]
modules/profile.php
modules/profile/addresses.inc.php
templates/geoloc/form.address.tpl
templates/include/form.valid.address.tpl [new file with mode: 0644]
templates/include/form.valid.edit-address.tpl [new file with mode: 0644]

index 1b15158..0fab4ed 100644 (file)
@@ -310,6 +310,7 @@ class Address
     public $location_type = '';
     public $partial_match = false;
     public $componentsIds = '';
+    public $request = false;
 
     // Database's field required for both 'home' and 'job' addresses.
     public $pub = 'ax';
@@ -352,6 +353,7 @@ class Address
                                                                                array('', "\n"), $this->text)), 'CEDEX')) !== false);
             }
         }
+        $this->request = !is_null(AddressReq::get_request($this->pid, $this->jobid, $this->groupid, $this->type, $this->text));
     }
 
     public function setId($id)
@@ -611,7 +613,8 @@ class Address
             'northeast_longitude' => $this->northeast_longitude,
             'location_type'       => $this->location_type,
             'partial_match'       => $this->partial_match,
-            'componentsIds'       => $this->componentsIds
+            'componentsIds'       => $this->componentsIds,
+            'request'             => $this->request
         );
 
         if ($this->type == self::LINK_PROFILE || $this->type == self::LINK_JOB) {
@@ -700,6 +703,44 @@ class Address
         }
     }
 
+    public function updateGeocoding($text)
+    {
+        $id = null;
+        $texts = XDB::fetchAllAssoc('id', 'SELECT  id, text
+                                   FROM  profile_addresses
+                                  WHERE  pid = {?} AND jobid = {?} AND groupid = {?} AND type = {?}',
+                                $this->pid, $this->jobid, $this->groupid, $this->type);
+        $text = preg_replace('/\s+/', ' ', $text);
+        foreach ($texts as $key => $value) {
+            if (strcmp($text, preg_replace('/\s+/', ' ', $value)) == 0) {
+                $id = $key;
+                break;
+            }
+        }
+        if (!is_null($id)) {
+            XDB::execute('UPDATE  profile_addresses
+                             SET  text = {?}, postalText = {?}, types = {?}, formatted_address = {?},
+                                  location_type = {?}, partial_match = {?}, latitude = {?}, longitude = {?},
+                                  southwest_latitude = {?}, southwest_longitude = {?}, northeast_latitude = {?}, northeast_longitude = {?}
+                           WHERE  pid = {?} AND jobid = {?} AND groupid = {?} AND type = {?} AND id = {?}',
+                         $this->text, $this->postalText, $this->types, $this->formatted_address,
+                         $this->location_type, $this->partial_match, $this->latitude, $this->longitude,
+                         $this->southwest_latitude, $this->southwest_longitude, $this->northeast_latitude, $this->northeast_longitude,
+                         $this->pid, $this->jobid, $this->groupid, $this->type, $id);
+
+            XDB::execute('DELETE FROM  profile_addresses_components
+                                WHERE  pid = {?} AND jobid = {?} AND groupid = {?} AND type = {?} AND id = {?}',
+                         $this->pid, $this->jobid, $this->groupid, $this->type, $id);
+            if ($this->componentsIds) {
+                foreach (explode(',', $this->componentsIds) as $component_id) {
+                    XDB::execute('INSERT IGNORE INTO  profile_addresses_components (pid, jobid, groupid, type, id, component_id)
+                                              VALUES  ({?}, {?}, {?}, {?}, {?}, {?})',
+                                 $this->pid, $this->jobid, $this->groupid, $this->type, $id, $component_id);
+                }
+            }
+        }
+    }
+
     public function delete()
     {
         XDB::execute('DELETE FROM  profile_addresses
index b95aa03..3a10c17 100644 (file)
@@ -333,18 +333,21 @@ function addressChanged(prefid)
     $('#' + prefid + '_cont').find('[name*=changed]').val("1");
 }
 
-function deleteGeocoding()
+function deleteGeocoding(prefid, hrpid)
 {
     var confirmation = confirm(
         "La localisation de l'adresse sert à deux choses : te placer dans "
         + "le planisphère et te faire apparaître dans la recherche avancée par "
-        + "pays, région, département, ville. La supprimer t'en fera disparaître. "
+        + "pays, région, département, ville... La supprimer t'en fera disparaître. "
         + "\nIl ne faut le faire que si cette localisation "
         + "est réellement erronée. Avant de supprimer cette localisation, l'équipe de "
         + "Polytechnique.org tentera de la réparer.\n\nConfirmes-tu ta "
         + "demande de suppression de cette localisation ?");
+
     if (confirmation) {
-        alert('Warning: not implemented yet.');
+        var address = $('#' + prefid).find("[name*='[text]']").val();
+        $.xpost('profile/ajax/address/del/' + hrpid, { address:address });
+        $('#' + prefid + '_geocoding_removal').html('Localisation en attente de validation.');
     }
 }
 
index eb2cd4c..35746bd 100644 (file)
@@ -624,6 +624,25 @@ abstract class ProfileValidate extends Validate
     }
 
     // }}}
+    // {{{ function get_all_typed_requests()
+
+    /** Same as get_typed_request() but return an array of objects.
+     */
+    static public function get_all_typed_requests($type)
+    {
+        $res = XDB::iterRow('SELECT  data
+                               FROM  requests
+                              WHERE  type = {?}
+                           ORDER BY  stamp',
+                            $type);
+        $array = array();
+        while (list($data) = $res->next()) {
+            $array[] = Validate::unserialize($data);
+        }
+        return $array;
+    }
+
+    // }}}
     // {{{ function get_typed_requests_count()
 
     /** Same as get_typed_requests() but returns the count of available requests.
diff --git a/include/validations/address.inc.php b/include/validations/address.inc.php
new file mode 100644 (file)
index 0000000..349674a
--- /dev/null
@@ -0,0 +1,174 @@
+<?php
+/***************************************************************************
+ *  Copyright (C) 2003-2011 Polytechnique.org                              *
+ *  http://opensource.polytechnique.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                *
+ ***************************************************************************/
+
+// {{{ class AddressReq
+
+class AddressReq extends ProfileValidate
+{
+    // {{{ properties
+
+    // Address primary field that are not in its formatted array.
+    public $pid;
+    public $jobid;
+    public $groupid;
+    public $type;
+
+    // We need the text given by the user, and the toy version to try to improve
+    // the geocoding.
+    public $address;
+    public $given_text;
+    public $toy_text = '';
+    public $modified = false;
+
+    public $rules = 'Si la localisation est bonne, refuser. Sinon, si le texte est faux, le corriger. Si la géolocaliastion ne marche toujours pas, utiliser la version jouet qui ne sera pas stockée, mais dont les données de localisation le seront.';
+
+    // }}}
+    // {{{ constructor
+
+    public function __construct(User $_user, Profile $_profile, $_text, $_pid, $_jobid, $_groupid, $_type, $_stamp = 0)
+    {
+        parent::__construct($_user, $_profile, false, 'address', $_stamp);
+        $this->key_pid = $_pid;
+        $this->key_jobid = $_jobid;
+        $this->key_groupid = $_groupid;
+        $this->key_type = $_type;
+        $this->given_text = $_text;
+        $address = new Address(array('changed' => 1, 'text' => $_text));
+        $address->format();
+        $this->address = $address->toFormArray();
+    }
+
+    // }}}
+    // {{{ function formu()
+
+    public function formu()
+    {
+        return 'include/form.valid.address.tpl';
+    }
+
+    // }}}
+    // {{{ function editor()
+
+    public function editor()
+    {
+        return 'include/form.valid.edit-address.tpl';
+    }
+
+    // }}}
+    // {{{ function handle_editor()
+
+    protected function handle_editor()
+    {
+        $data = Post::v('valid');
+        if (isset($data['text']) && $data['text'] != $this->toy_text && $data['text'] != $this->given_text) {
+            $this->toy_text = $data['text'];
+            $address = new Address(array('changed' => 1, 'text' => $this->toy_text));
+            $address->format();
+            $this->address = $address->toFormArray();
+        }
+        $this->modified = isset($data['modified']);
+
+        return true;
+    }
+
+    // }}}
+    // {{{ function _mail_subj
+
+    protected function _mail_subj()
+    {
+        return '[Polytechnique.org/Adresse] Demande d\'amélioration de la localisation d\'une adresse';
+    }
+
+    // }}}
+    // {{{ function _mail_body
+
+    protected function _mail_body($isok)
+    {
+        if ($isok) {
+            return "  Nous avons réussit à mieux localiser l'adresse.";
+        } else {
+            return "  L'adresse est suffisemment bien localisée pour les besoins du site (recherche avancée, planisphère), nous avons donc choisi de ne pas la modifier.";
+        }
+    }
+
+    // }}}
+    // {{{ function commit()
+
+    public function commit()
+    {
+        $this->address = array_merge($this->address, array(
+            'pid' => $this->key_pid,
+            'jobid' => $this->key_jobid,
+            'groupid' => $this->key_groupid,
+            'type' => $this->key_type
+        ));
+        $this->address['text'] = ($this->modified ? $this->toy_text : $this->given_text);;
+        $this->address['changed'] = 0;
+        $address = new Address($this->address);
+        $address->format();
+        $address->updateGeocoding($this->given_text);
+
+        return true;
+    }
+
+    // }}}
+    // {{{ function get_request()
+
+    static public function get_request($pid, $jobid, $groupid, $type, $address)
+    {
+        $reqs = parent::get_typed_requests($pid, 'address');
+        foreach ($reqs as &$req) {
+            if ($req->key_pid == $pid && $req->key_jobid == $jobid && $req->key_groupid == $groupid
+                && $req->key_type == $type && $req->address['text'] == $address) {
+                return $req;
+            }
+        }
+        return null;
+    }
+
+    // }}}
+    // {{{ function purge_requests()
+
+    // Purges address localization requests based on deleted addresses.
+    static public function purge_requests($pid, $jobid, $groupid, $type)
+    {
+        $requests = parent::get_all_typed_requests('address');
+        foreach ($requests as &$req) {
+            if ($req->key_pid == $pid && $req->key_jobid == $jobid && $req->key_groupid == $groupid && $req->key_type == $type) {
+                $count = XDB::fetchOneCell('SELECT  COUNT(*)
+                                              FROM  profile_addresses
+                                             WHERE  pid = {?} AND jobid = {?} AND groupid = {?}
+                                                    AND type = {?} AND text = {?}',
+                                           $pid, $jobid, $groupid, $type, $req->address['text']);
+                if ($count == 0) {
+                    $req->clean();
+                }
+            }
+        }
+    }
+
+    // }}}
+}
+
+// }}}
+
+// vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
+?>
index 9416557..bbdd8ea 100644 (file)
@@ -33,6 +33,7 @@ class ProfileModule extends PLModule
             'profile/ax'                 => $this->make_hook('ax',                         AUTH_COOKIE, 'admin,edit_directory'),
             'profile/edit'               => $this->make_hook('p_edit',                     AUTH_MDP),
             'profile/ajax/address'       => $this->make_hook('ajax_address',               AUTH_COOKIE, 'user', NO_AUTH),
+            'profile/ajax/address/del'   => $this->make_hook('ajax_address_del',           AUTH_MDP),
             'profile/ajax/tel'           => $this->make_hook('ajax_tel',                   AUTH_COOKIE, 'user', NO_AUTH),
             'profile/ajax/edu'           => $this->make_hook('ajax_edu',                   AUTH_COOKIE, 'user', NO_AUTH),
             'profile/ajax/medal'         => $this->make_hook('ajax_medal',                 AUTH_COOKIE, 'user', NO_AUTH),
@@ -355,6 +356,7 @@ class ProfileModule extends PLModule
         }
 
        $page->setTitle('Mon Profil');
+       $page->assign('hrpid', $profile->hrid());
        if (isset($success) && $success) {
            $page->trigSuccess('Ton profil a bien été mis à jour.');
        }
@@ -398,6 +400,20 @@ class ProfileModule extends PLModule
         $page->assign('address', array());
     }
 
+    function handler_ajax_address_del($page, $hrpid)
+    {
+        if ($profile = Profile::get($hrpid)) {
+            if (S::user()->canEdit($profile)) {
+                $address = Post::t('address');
+                if (is_null(AddressReq::get_request($profile->id(), 0, 0, Address::LINK_PROFILE, $address))) {
+                    $req = new AddressReq(S::user(), $profile, $address, $profile->id(), 0, 0, Address::LINK_PROFILE);
+                    $req->submit();
+                }
+            }
+        }
+        exit();
+    }
+
     function handler_ajax_tel($page, $prefid, $prefname, $telid, $subField, $mainField, $mainId)
     {
         pl_content_headers("text/html");
index 2961f1e..62d21ea 100644 (file)
@@ -48,6 +48,7 @@ class ProfileSettingAddresses implements ProfileSetting
         Phone::deletePhones($page->pid(), Phone::LINK_ADDRESS, null, $deletePrivate);
         Address::deleteAddresses($page->pid(), Address::LINK_PROFILE, null, null, $deletePrivate);
         Address::saveFromArray($value, $page->pid(), Address::LINK_PROFILE, null, $deletePrivate);
+        AddressReq::purge_requests($page->pid(), 0, 0, Address::LINK_PROFILE);
         if (S::user()->isMe($page->owner) && count($value) > 1) {
             Platal::page()->trigWarning('Attention, tu as plusieurs adresses sur ton profil. Pense à supprimer celles qui sont obsolètes.');
         }
@@ -68,6 +69,7 @@ class ProfilePageAddresses extends ProfilePage
         parent::__construct($wiz);
         $this->settings['addresses'] = new ProfileSettingAddresses();
         $this->watched['addresses']  = true;
+        Platal::page()->assign('geocoding_removal', true);
     }
 }
 
index 033c3c0..e419512 100644 (file)
 {*                                                                        *}
 {**************************************************************************}
 
+{if t($validation)}
+<div style="float: left">
+{else}
 <tr{if t($class)} class="{$class}"{/if}>
   <td>
+{/if}
     <textarea name="{$prefname}[text]" cols="30" rows="4" onkeyup="addressChanged('{$prefid}')">{$address.text}</textarea>
     <input type="hidden" name="{$prefname}[postalText]" value="{$address.postalText}" />
     <input type="hidden" name="{$prefname}[types]" value="{$address.types}" />
     <input type="hidden" name="{$prefname}[componentsIds]" value="{$address.componentsIds}" />
     <input type="hidden" name="{$prefname}[changed]" value="0" />
     <input type="hidden" name="{$prefname}[removed]" value="0" />
+{if t($validation)}
+    <br />
+    <label><input type="checkbox" name="{$prefname}[modified]"{if $valid->modified} checked="checked"{/if} />Utiliser la version modifiée</label>
+</div>
+<div style="float: right">
+{else}
   </td>
   <td>
+{/if}
   {if t($address.latitude)}
     <img src="https://maps.googleapis.com/maps/api/staticmap?size=300x100&amp;markers=color:{$profile->promoColor()}%7C{$address.latitude},{$address.longitude}&amp;zoom=12&amp;sensor=false"
          alt="Position de l'adresse" />
+    {if t($geocoding_removal)}
     <br />
-    <small><a href="javascript:deleteGeocoding()">{icon name=cross title="Adresse mal localisée"} Signaler que le repère est mal placé</a></small>
+    <small id="{$prefid}_geocoding_removal">
+    {if !t($address.request)}
+      <a href="javascript:deleteGeocoding('{$prefid}', '{$hrpid}')">{icon name=cross title="Adresse mal localisée"} Signaler que le repère est mal placé</a>
+    {else}
+    Localisation en attente de validation.
+    {/if}
+    </small>
+    {/if}
   {/if}
+{if t($validation)}
+</div>
+<div style="clear: both"></div>
+{else}
   </td>
 </tr>
+{/if}
 
 {* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/include/form.valid.address.tpl b/templates/include/form.valid.address.tpl
new file mode 100644 (file)
index 0000000..9b6a696
--- /dev/null
@@ -0,0 +1,28 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2011 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<tr class="pair">
+  <td class="titre">Adresse fournie</td>
+  <td>{$valid->given_text}</td>
+</tr>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/include/form.valid.edit-address.tpl b/templates/include/form.valid.edit-address.tpl
new file mode 100644 (file)
index 0000000..0e6abcc
--- /dev/null
@@ -0,0 +1,25 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2011 Polytechnique.org                             *}
+{*  http://opensource.polytechnique.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 file="geoloc/form.address.tpl" prefname="valid" prefid=0 address=$valid->address validation=1}
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}