Adds an admin interface for Google Apps accounts.
authorVincent Zanotti <vincent.zanotti@polytechnique.org>
Fri, 21 Mar 2008 16:17:42 +0000 (17:17 +0100)
committerVincent Zanotti <vincent.zanotti@polytechnique.org>
Fri, 21 Mar 2008 16:18:00 +0000 (17:18 +0100)
Signed-off-by: Vincent Zanotti <vincent.zanotti@polytechnique.org>
include/googleapps.inc.php
modules/googleapps.php
templates/googleapps/admin.job.tpl [new file with mode: 0644]
templates/googleapps/admin.tpl [new file with mode: 0644]
templates/googleapps/admin.user.tpl [new file with mode: 0644]

index e6d6943..908083b 100644 (file)
@@ -116,6 +116,7 @@ class GoogleAppsAccount
     public $activate_mail_redirection;
 
     // Account status, obtained from Google Apps provisioning & reporting APIs.
+    public $g_account_id;
     public $g_status;
     public $g_suspension;
     public $r_disk_usage;
@@ -151,7 +152,7 @@ class GoogleAppsAccount
 
         $res = XDB::query(
             "SELECT  l_sync_password, l_activate_mail_redirection,
-                     g_account_name, g_status, g_suspension, r_disk_usage,
+                     g_account_name, g_account_id, g_status, g_suspension, r_disk_usage,
                      UNIX_TIMESTAMP(r_creation) as r_creation,
                      UNIX_TIMESTAMP(r_last_login) as r_last_login,
                      UNIX_TIMESTAMP(r_last_webmail) as r_last_webmail
@@ -161,6 +162,7 @@ class GoogleAppsAccount
         if ($account = $res->fetchOneAssoc()) {
             $this->sync_password = $account['l_sync_password'];
             $this->activate_mail_redirection = $account['l_activate_mail_redirection'];
+            $this->g_account_id = $account['g_account_id'];
             $this->g_status = $account['g_status'];
             $this->g_suspension = $account['g_suspension'];
             $this->r_disk_usage = $account['r_disk_usage'];
index 9dc333b..6eb41ba 100644 (file)
@@ -29,7 +29,10 @@ class GoogleAppsModule extends PLModule
         }
 
         return array(
-            'googleapps' => $this->make_hook('index', AUTH_MDP),
+            'googleapps'            => $this->make_hook('index', AUTH_MDP),
+            'admin/googleapps'      => $this->make_hook('admin', AUTH_MDP. 'admin'),
+            'admin/googleapps/job'  => $this->make_hook('admin_job', AUTH_MDP, 'admin'),
+            'admin/googleapps/user' => $this->make_hook('admin_user', AUTH_MDP, 'admin'),
         );
     }
 
@@ -106,6 +109,110 @@ class GoogleAppsModule extends PLModule
 
         $page->assign('account', $account);
     }
+
+    function handler_admin(&$page, $action = null) {
+        require_once("googleapps.inc.php");
+        $page->changeTpl('googleapps/admin.tpl');
+        $page->assign('xorg_title', 'Polytechnique.org - Administration Google Apps');
+        $page->assign('googleapps_admin', GoogleAppsAccount::is_administrator(S::v('uid')));
+
+        if ($action == 'ack') {
+            $qid = @func_get_arg(2);
+            if ($qid) {
+                XDB::execute(
+                    "DELETE FROM  gapps_queue
+                           WHERE  q_id = {?} AND p_status = 'hardfail'", $qid);
+                $page->trig("La requête échouée a bien été retirée.");
+            }
+        }
+
+        // Retrieves latest pending administrative requests from the gappsd queue.
+        $res = XDB::iterator(
+            "SELECT  q_id, q_recipient_id, a.alias, j_type, j_parameters,
+                     UNIX_TIMESTAMP(q.p_entry_date) AS p_entry_date
+               FROM  gapps_queue AS q
+          LEFT JOIN  aliases AS a ON (a.id = q_recipient_id AND a.type = 'a_vie')
+              WHERE  p_status IN ('idle', 'active', 'softfail') AND
+                     p_admin_request IS TRUE
+           ORDER BY  p_entry_date");
+        while ($request = $res->next()) {
+            $j_parameters = json_decode($request['j_parameters'], true);
+            unset($j_parameters['username']);
+            $parameters = array_keys($j_parameters);
+            $request['parameters'] = implode(', ', $parameters);
+
+            $page->append('admin_requests', $request);
+        }
+
+        // Retrieves latest failed requests from the gappsd queue.
+        $res = XDB::iterator(
+            "SELECT  q.q_id, q.q_recipient_id, a.alias, q.j_type, q.r_result,
+                     UNIX_TIMESTAMP(q.p_entry_date) AS p_entry_date
+               FROM  gapps_queue AS q
+          LEFT JOIN  aliases AS a ON (a.id = q.q_recipient_id AND a.type = 'a_vie')
+              WHERE  q.p_status = 'hardfail'
+           ORDER BY  p_entry_date DESC
+              LIMIT  20");
+        $page->assign('failed_requests', $res);
+    }
+
+    function handler_admin_job(&$page, $job = null) {
+        require_once("googleapps.inc.php");
+        $page->changeTpl('googleapps/admin.job.tpl');
+        $page->assign('xorg_title', 'Polytechnique.org - Administration Google Apps');
+        $page->assign('googleapps_admin', GoogleAppsAccount::is_administrator(S::v('uid')));
+
+        if ($job) {
+            $res = XDB::query(
+                "SELECT  q.*, ao.alias AS q_owner, ar.alias AS q_recipient
+                   FROM  gapps_queue AS q
+              LEFT JOIN  aliases AS ao ON (ao.id = q.q_owner_id AND ao.type = 'a_vie')
+              LEFT JOIN  aliases AS ar ON (ar.id = q.q_recipient_id AND ar.type = 'a_vie')
+                  WHERE  q_id = {?}", $job);
+            $sql_job = $res->fetchOneAssoc();
+            $sql_job['decoded_parameters'] = var_export(json_decode($sql_job['j_parameters'], true), true);
+            $page->assign('job', $sql_job);
+        }
+    }
+
+    function handler_admin_user(&$page, $user = null, $action = null) {
+        require_once("emails.inc.php");
+        require_once("googleapps.inc.php");
+        $page->changeTpl('googleapps/admin.user.tpl');
+        $page->assign('xorg_title', 'Polytechnique.org - Administration Google Apps');
+        $page->assign('googleapps_admin', GoogleAppsAccount::is_administrator(S::v('uid')));
+        
+        if ($user && !is_numeric($user)) {
+            $res = XDB::query("SELECT id FROM aliases WHERE alias = {?} AND type != 'homonyme'", $user);
+            $user = $res->fetchOneCell();
+        }
+
+        if ($user) {
+            $account = new GoogleAppsAccount($user);
+            $storage = new MailStorageGoogleApps($user);
+
+            // Force synchronization of plat/al and Google Apps passwords.
+            if ($action == 'forcesync' && $account->sync_password) {
+                $res = XDB::query("SELECT password FROM auth_user_md5 WHERE user_id = {?}", $user);
+                $account->set_password($res->fetchOneCell());
+                $page->trig('Le mot de passe a été synchronisé.');
+            }
+
+            // Displays basic account information.
+            $page->assign('account', $account);
+            $page->assign('admin_account', GoogleAppsAccount::is_administrator($user));
+            $page->assign('googleapps_storage', $storage->active());
+            $page->assign('user', $user);
+
+            // Retrieves user's pending requests.
+            $res = XDB::iterator(
+                "SELECT  q_id, q_recipient_id, p_status, j_type, UNIX_TIMESTAMP(p_entry_date) AS p_entry_date
+                   FROM  gapps_queue
+                  WHERE  q_recipient_id = {?}
+               ORDER BY  p_entry_date DESC", $user);
+            $page->assign('requests', $res);
+        }
+    }
 }
 
 // vim:set et sw=4 sts=4 sws=4 foldmethod=marker enc=utf-8:
diff --git a/templates/googleapps/admin.job.tpl b/templates/googleapps/admin.job.tpl
new file mode 100644 (file)
index 0000000..56638c9
--- /dev/null
@@ -0,0 +1,86 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Requête de la queue Google Apps</h1>
+
+{if $job}
+<table class="bicol">
+  <col width="50%" />
+  <col width="50%" />
+  <tr>
+    <th style="text-align: left" colspan="2">Queue id: {$job.q_id}</th>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Propriétaire</td><td>{if $job.q_owner}{$job.q_owner}{else}<em>none</em>{/if}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Destinataire</td><td>{if $job.q_recipient}{$job.q_recipient}{else}<em>none</em>{/if}</td>
+  </tr>
+
+  <tr class="pair">
+    <td class="titre">Statut</td><td><code>{$job.p_status}</code></td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Priorité</td><td><code>{$job.p_priority}</code></td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Requête administrateur ?</td><td>{if $job.p_admin_request}oui{else}non{/if}</td>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Entrée dans la queue</td><td>{$job.p_entry_date}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Date d'activation</td><td>{$job.p_notbefore_date}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Début de traitement</td><td>{if $job.p_start_date}{$job.p_start_date}{else}<em>none</em>{/if}</td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Fin de traitement</td><td>{if $job.p_end_date}{$job.p_end_date}{else}<em>none</em>{/if}</td>
+  </tr>
+
+  <tr class="pair">
+    <td class="titre">Erreurs récupérables</td><td>{$job.r_softfail_count}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Dernière erreur récupérable</td><td><code>{if $job.r_softfail_date}{$job.r_softfail_date}{else}<em>none</em>{/if}</code></td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Résultat du traitement</td><td><code>{if $job.r_result}{$job.r_result}{else}<em>none</em>{/if}</code></td>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Type de requête</td><td><code>{$job.j_type}</code></td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Paramètres</td><td><pre>{$job.decoded_parameters}</pre></td>
+  </tr>
+</table>
+{else}
+<p><strong>Aucune requête n'a été trouvée.</strong></p>
+{/if}
+
+<p>Retourner à la <a href="admin/googleapps">page d'administration de Google Apps</a>.</p>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/googleapps/admin.tpl b/templates/googleapps/admin.tpl
new file mode 100644 (file)
index 0000000..67e9ccb
--- /dev/null
@@ -0,0 +1,100 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Gestion des utilisateurs</h1>
+
+<form method="post" action="admin/googleapps/user">
+<table class="tinybicol" cellspacing="0" cellpadding="2">
+  <tr>
+    <th>Administrer un utilisateur (Google Apps)</th>
+  </tr>
+  <tr>
+    <td class="center"><input type="text" name="login" size="40" maxlength="255" value="" /></td>
+  </tr>
+  <tr>
+    <td class="center"><input type="submit" value="Valider" /></td>
+  </tr>
+</table>
+</form>
+
+<h1>Queue de requêtes vers Google Apps</h1>
+
+<p>
+  Requête nécessitant <a href="Equipe/Infra-GoogleApps#admin-cli">l'intervention manuelle</a>
+  d'un administrateur Google Apps {if $googleapps_admin}(tu en es un){/if}&nbsp;:
+</p>
+<table class="bicol" style="text-align: center">
+  <tr>
+    <th>qid</th>
+    <th>date</th>
+    <th>recipient</th>
+    <th>type</th>
+    <th>parameters</th>
+  </tr>
+  {foreach from=$admin_requests item=r}
+  <tr class="{cycle values="impair,pair"}">
+    <td><a href="admin/googleapps/job/{$r.q_id}">{$r.q_id}</a></td>
+    <td>{$r.p_entry_date|date_format:"%Y-%m-%d %H:%M"}</td>
+    <td>{if $r.alias}<a href="admin/googleapps/user/{$r.alias}">{$r.alias}</a>{else}-{/if}</td>
+    <td>{$r.j_type}</td>
+    <td>{$r.parameters}</td>
+  </tr>
+  {/foreach}
+</table>
+
+<p>
+  Requêtes ayant échoué récemment (plus d'information dans la <a href="Equipe/Infra-GoogleApps">documentation</a>) :
+</p>
+<table class="bicol" style="text-align: center">
+  <tr>
+    <th>qid</th>
+    <th>date</th>
+    <th>recipient</th>
+    <th>type</th>
+    <th>reason</th>
+    <th></th>
+  </tr>
+  {iterate from=$failed_requests item=r}
+  <tr class="{cycle values="impair,pair"}">
+    <td><a href="admin/googleapps/job/{$r.q_id}">{$r.q_id}</a></td>
+    <td>{$r.p_entry_date|date_format:"%Y-%m-%d %H:%M"}</td>
+    <td>{if $r.alias}<a href="admin/googleapps/user/{$r.alias}">{$r.alias}</a>{else}-{/if}</td>
+    <td>{$r.j_type}</td>
+    <td><code>{$r.r_result}</code></td>
+    <td><a href="admin/googleapps/ack/{$r.q_id}">{icon name=cross title="Retirer cet échec"}</a></td>
+  </tr>
+  {/iterate}
+</table>
+
+<h1>Statistiques d'utilisation de Google Apps</h1>
+
+<div style="text-align: center">
+  <img src="images/googleapps/activity-monthly.png" alt="Activité Google Apps - 1 mois" width="500 height="250" />
+  <br /><em>Utilisation des comptes Google Apps sur les 31 derniers jours</em>.
+</div>
+
+<div style="text-align: center">
+  <img src="images/googleapps/activity-yearly.png" alt="Activité Google Apps - 1 an" width="500 height="250" />
+  <br /><em>Utilisation des comptes Google Apps sur les 12 derniers mois</em>.
+</div>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}
diff --git a/templates/googleapps/admin.user.tpl b/templates/googleapps/admin.user.tpl
new file mode 100644 (file)
index 0000000..cb2af6f
--- /dev/null
@@ -0,0 +1,105 @@
+{**************************************************************************}
+{*                                                                        *}
+{*  Copyright (C) 2003-2008 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               *}
+{*                                                                        *}
+{**************************************************************************}
+
+<h1>Compte Google Apps</h1>
+
+{if $account}
+{assign var=a value=$account}
+<table class="bicol">
+  <col width="50%" />
+  <col width="50%" />
+  <tr>
+    <th colspan="2" style="text-align: left">
+      <div style="float: left; text-align: left">
+        Compte = {$a->g_account_name}
+      </div>
+      <div style="float: right; text-align: right">
+        Google id = {$a->g_account_id}<br />
+        Plat/al id = {$user}
+      </div>
+    </th>
+  </tr>
+
+  <tr class="impair">
+    <td class="titre">Statut du compte</td>
+    <td>
+      <strong>{$a->g_status}</strong>
+      {if $admin_account}<br /><strong>Compte administrateur de Google Apps</strong>{/if}
+    </td>
+  </tr>
+  {if $a->suspended()}
+  <tr class="impair">
+    <td class="titre">Raison de suspension</td><td>{$a->g_suspension}</td>
+  </tr>
+  {/if}
+  <tr class="impair">
+    <td class="titre">Mots de passes synchronisés</td>
+    <td>
+      {if $a->sync_password}
+        oui (<a href="admin/googleapps/user/{$a->g_account_name}/forcesync">lancer une synchronisation</a>)
+      {else}non{/if}
+    </td>
+  </tr>
+  <tr class="impair">
+    <td class="titre">Redirection des mails</td><td>{if $googleapps_storage}activée{else}désactivee{/if}</td>
+  </tr>
+
+  <tr class="pair">
+    <td class="titre">Date de création</td><td>{$a->r_creation|date_format:"%Y-%m-%d"}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Dernière connexion</td><td>{$a->r_last_login|date_format:"%Y-%m-%d"}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Dernière utilisation du webmail</td><td>{$a->r_last_webmail|date_format:"%Y-%m-%d"}</td>
+  </tr>
+  <tr class="pair">
+    <td class="titre">Utilisation du quota mail</td><td>{$a->r_disk_usage/1024/1024|string_format:"%.2f"}MB</td>
+  </tr>
+</table><br />
+
+<table class="bicol" style="text-align: center">
+  <tr>
+    <th colspan="4" style="text-align: left">Requêtes en attente</th>
+  </tr>
+  <tr>
+    <th>qid</th>
+    <th>date</th>
+    <th>statut</th>
+    <th>type</th>
+  </tr>
+  {iterate from=$requests item=r}
+  <tr class="{cycle values="impair,pair"}">
+    <td><a href="admin/googleapps/job/{$r.q_id}">{$r.q_id}</a></td>
+    <td>{$r.p_entry_date|date_format:"%Y-%m-%d %H:%M"}</td>
+    <td>{$r.p_status}</td>
+    <td>{$r.j_type}</td>
+  </tr>
+  {/iterate}
+</table>
+{else}
+<p><strong>Aucun utilisateur n'a été trouvé.</strong></p>
+{/if}
+
+<p>Retourner à la <a href="admin/googleapps">page d'administration de Google Apps</a>.</p>
+
+{* vim:set et sw=2 sts=2 sws=2 enc=utf-8: *}