diff --git a/TODO b/TODO index 8c22d70..5a32992 100755 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ * Don't cache the username -* JSON output +* JSON output => do the template inc/Invoices.class.php : ======================== @@ -9,6 +9,7 @@ inc/Invoices.class.php : Manage paybacks : ================= * TODO : Payback system (class should be ok) +* TODO : Global payback To test : ========= diff --git a/inc/Storage.class.php b/inc/Storage.class.php index adeb72d..e3c87f6 100644 --- a/inc/Storage.class.php +++ b/inc/Storage.class.php @@ -228,7 +228,7 @@ class Storage { foreach($this->fields as $field=>$type) { if(isset($this->$field)) { - if($fields[$field] == 'date') + if($type == 'date') $value = $value->format('Y-m-d H:i:s'); $query->bindParam(':'.$field, $this->$field); diff --git a/inc/User.class.php b/inc/User.class.php index 3a2f38d..ce1fb5c 100644 --- a/inc/User.class.php +++ b/inc/User.class.php @@ -3,14 +3,15 @@ require_once('data/config.php'); require_once('Storage.class.php'); class User extends Storage { - protected $id = 0, $login, $display_name, $password, $admin; + protected $id = 0, $login, $display_name, $password, $admin, $json_token; protected $TABLE_NAME = "Users"; protected $fields = array( 'id'=>'key', 'login'=>'string', 'display_name'=>'string', 'password'=>'password', - 'admin'=>'bool' + 'admin'=>'bool', + 'json_token'=>'string', ); public function __construct() { @@ -35,6 +36,10 @@ class User extends Storage { return $this->admin; } + public function getJsonToken() { + return $this->json_token; + } + // Setters // ======= public function setId($id) { @@ -57,6 +62,10 @@ class User extends Storage { $this->admin = (bool) $admin; } + public function setJsonToken($token) { + $this->json_token = $token; + } + // Password functions // ================== public function encrypt($text) { @@ -67,6 +76,12 @@ class User extends Storage { return User::encrypt($password) == $this->password; } + // JSON token functions + // ==================== + public function newJsonToken() { + $this->json_token = md5(uniqid(mt_rand(), true)); + } + // Check if a user exists by login and load it // =========================================== public function exists() { @@ -83,7 +98,7 @@ class User extends Storage { // Session storage // =============== public function sessionStore() { - return serialize(array('id'=>$this->id, 'login'=>$this->login, 'display_name'=>$this->display_name, 'password'=>$this->password, 'admin'=>$this->admin)); + return serialize(array('id'=>$this->id, 'login'=>$this->login, 'display_name'=>$this->display_name, 'password'=>$this->password, 'admin'=>$this->admin, 'json_token'=>$this->json_token)); } public function sessionRestore($data, $serialized = false) { @@ -97,6 +112,7 @@ class User extends Storage { $this->setDisplayName($user_data['display_name']); $this->setPassword($user_data['password']); $this->setAdmin($user_data['admin']); + $this->setJsonToken($user_data['json_token']); } // Check wether a user already exists or not @@ -118,6 +134,7 @@ class User extends Storage { $this->login = htmlspecialchars($this->login); $this->display_name = htmlspecialchars($this->display_name); $this->admin = (int) $this->admin; + $this->json_token = htmlspecialchars($this->json_token); return $this; } diff --git a/inc/functions.php b/inc/functions.php index 582b97e..2103edf 100644 --- a/inc/functions.php +++ b/inc/functions.php @@ -61,7 +61,7 @@ if ($handle = opendir($dir)) { while (false !== ($entry = readdir($handle))) { - if ($entry != "." && $entry != ".." && is_dir($dir.$entry)) { + if ($entry != "." && $entry != ".." && $entry != 'json' && is_dir($dir.$entry)) { $return[] = array('value'=>$entry, 'option'=>str_replace(array('_en', '_fr'), array(' (English)', ' (French)'), $entry)); } } diff --git a/index.php b/index.php index 1a05375..0fa4aa7 100644 --- a/index.php +++ b/index.php @@ -20,7 +20,14 @@ require_once('inc/functions.php'); require_once('inc/Ban.inc.php'); require_once('inc/CSRF.inc.php'); - raintpl::$tpl_dir = TEMPLATE_DIR; + if(!empty($_GET['json'])) { + raintpl::$tpl_dir = 'tpl/json/'; + $get_redir = 'json=1'; + } + else { + raintpl::$tpl_dir = TEMPLATE_DIR; + $get_redir = ''; + } raintpl::$cache_dir = 'tmp/'; // Define raintpl instance @@ -57,17 +64,35 @@ } $tpl->assign('current_user', secureDisplay($current_user)); - // If not connected, redirect to connection page - if($current_user === false && (empty($_GET['do']) OR $_GET['do'] != 'connect')) { - header('location: index.php?do=connect'); - exit(); + if(!empty($_GET['json_token'])) { + $current_user = new User(); + + if($current_user->load(array('json_token'=>$_GET['json_token'], true)) === false) { + header('location: index.php?do=connect'.$get_redir); + exit(); + } + else { + if(!empty($get_redir)) + $get_redir .= '&'; + + $get_redir .= 'json_token='.$_GET['json_token']; + } } - - // If IP has changed, logout - if($current_user !== false && user_ip() != $_SESSION['ip']) { - session_destroy(); - header('location: index.php?do=connect'); - exit(); + else { + //If json token not available + + // If not connected, redirect to connection page + if($current_user === false && (empty($_GET['do']) OR $_GET['do'] != 'connect')) { + header('location: index.php?do=connect&'.$get_redir); + exit(); + } + + // If IP has changed, logout + if($current_user !== false && user_ip() != $_SESSION['ip']) { + session_destroy(); + header('location: index.php?do=connect&'.$get_redir); + exit(); + } } // Initialize empty $_GET['do'] if required to avoid error @@ -79,7 +104,7 @@ switch($_GET['do']) { case 'connect': if($current_user !== false) { - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } if(!empty($_POST['login']) && !empty($_POST['password']) && check_token(600, 'connection')) { @@ -106,7 +131,7 @@ session_set_cookie_params($_SESSION['remember_me'], $cookie_dir, $_SERVER['HTTP_HOST']); session_regenerate_id(true); - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } else { @@ -124,7 +149,7 @@ case 'disconnect': $current_user = false; session_destroy(); - header('location: index.php?do=connect'); + header('location: index.php?do=connect&'.$get_redir); exit(); break; @@ -135,7 +160,7 @@ $current_user->setPassword($current_user->encrypt($_POST['password'])); $current_user->save(); - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } else { @@ -147,6 +172,7 @@ } } $tpl->assign('view', 'password'); + $tpl->assign('json_token', htmlspecialchars($current_user->getJsonToken())); $tpl->assign('token', generate_token('password')); $tpl->draw('edit_users'); break; @@ -154,7 +180,7 @@ case 'edit_users': case 'add_user': if(!$current_user->getAdmin()) { - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } @@ -164,6 +190,9 @@ if(!empty($_POST['user_id'])) { $user->setId($_POST['user_id']); } + else { + $user->newJsonToken(); + } $user->setLogin($_POST['login']); $user->setDisplayName($_POST['display_name']); if(!empty($_POST['password'])) { @@ -177,7 +206,7 @@ // Clear the cache array_map("unlink", glob(raintpl::$cache_dir."*.rtpl.php")); - header('location: index.php?do=edit_users'); + header('location: index.php?do=edit_users&'.$get_redir); exit(); } else { @@ -213,6 +242,24 @@ $tpl->draw('edit_users'); break; + case 'new_token': + if(!empty($_GET['user_id']) && $current_user->getAdmin()) { + $user_id = (int) $_GET['user_id']; + } + else { + $user_id = $current_user->getId(); + } + + $user = new User(); + $user = $user->load(array('id'=>$user_id), true); + $user->newJsonToken(); + $user->save(); + $_SESSION['current_user'] = $user->sessionStore(); + + header('location: index.php'.$get_redir); + exit(); + break; + case 'delete_user': if($_GET['user_id'] != $current_user->getId()) { $user = new User(); @@ -222,7 +269,7 @@ // Clear the cache array_map("unlink", glob(raintpl::$cache_dir."*.rtpl.php")); - header('location: index.php?do=edit_users'); + header('location: index.php?do=edit_users&'.$get_redir); exit(); } break; @@ -234,7 +281,7 @@ // Clear the cache array_map("unlink", glob(raintpl::$cache_dir."*.rtpl.php")); - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } @@ -286,7 +333,7 @@ // Clear the cache array_map("unlink", glob(raintpl::$cache_dir."*.rtpl.php")); - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } else { @@ -366,7 +413,7 @@ // Clear the cache array_map("unlink", glob(raintpl::$cache_dir."*.rtpl.php")); - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } } @@ -405,7 +452,7 @@ // Clear the cache array_map("unlink", glob(raintpl::$cache_dir."*.rtpl.php")); - header('location: index.php'); + header('location: index.php?'.$get_redir); exit(); } break; diff --git a/tpl/default_en/edit_users.html b/tpl/default_en/edit_users.html index 1e85862..3f6aae5 100644 --- a/tpl/default_en/edit_users.html +++ b/tpl/default_en/edit_users.html @@ -54,6 +54,11 @@

+{if condition="$user_id != -1"} +

Personal token for this user

+

The personal token for this user to be used with the API is : {$user_data->getJsonToken()}.
If you think it might be compromised, you can generate a new one.

+{/if} + {elseif condition="$view == 'password'"}

Edit your password

@@ -61,4 +66,8 @@

Toggle visible

+ +

Your personal token to use the API

+

Your personal token to use the API is : {$json_token}.
If you think it might be compromised, you can generate a new one.

{/if} +{include="footer"} diff --git a/tpl/json/connection.html b/tpl/json/connection.html new file mode 100644 index 0000000..e1ee7d6 --- /dev/null +++ b/tpl/json/connection.html @@ -0,0 +1,5 @@ +{if condition="LANG=='fr'"} + Vous devez utiliser votre token unique d'identification pour l'utilisation de l'API JSON. Vous pouvez le trouver dans le menu "Modifier votre mot de passe". +{else} + You must use your unique id token to use JSON API. You can find it under the "Edit password" menu. +{/if} diff --git a/tpl/json/edit_users.html b/tpl/json/edit_users.html new file mode 100644 index 0000000..cb9669c --- /dev/null +++ b/tpl/json/edit_users.html @@ -0,0 +1,62 @@ +{if condition="$error != ''"} +

{$error}

+{/if} + +{if condition="$view == 'list_users'"} +

List of users

+

You can also add a user.

+ + + + + + + + + + {loop="users"} + + + + + + + + + {/loop} +
IdLoginDisplay NameIs admin ?EditDelete
{$value->getId()}{$value->getLogin()}{$value->getDisplayName()}{$value->getAdmin() ? "Yes" : "No"}Edit{if condition="$value->getId() != $current_user->getId()"}Delete{/if}
+{elseif condition="$view == 'edit_user'"} +

{$user_id != -1 ? 'Edit' : 'Add'} a user

+
+

+ +

+

+ +

+

+ Toggle visible + {if condition="$user_id != -1"} +
Note : Leave blank this field if you don't want to edit password. + {/if} +

+

+ Give admin rights to this user ?
+
+ +

+

+ + {if condition="$user_id != -1"}{/if} + +

+
+ +{elseif condition="$view == 'password'"} +

Edit your password

+
+

+

Toggle visible

+

+

+{/if} diff --git a/tpl/json/index.html b/tpl/json/index.html new file mode 100755 index 0000000..cca8039 --- /dev/null +++ b/tpl/json/index.html @@ -0,0 +1,54 @@ +{if condition="$notice != ''"} +

{$notice}

+{/if} + +
+

Balance

+

Read line owes case {$currency} to column. You can click on links to confirm the payback. + + + + {loop="users"} + + {/loop} + + {loop="users"} + + + {loop="users"} + + {/loop} + + {/loop} +
Owes\To{$value->getDisplayName()}
{$value->getDisplayName()}{$value->getDisplayName()}
+

+
+

Detailed list of bills for last month

+ + {if condition="count($invoices)>1"} + + + + + + + + + + + {loop="invoices"} + + + + + + + + + + {/loop} +
DatePaid byUsers inAmountWhat ?EditDelete
{$value->getDate()}{$value->getBuyer()->getDisplayName()}{$value->getUsersIn()}{$value->getAmount()}{$value->getWhat()}EditDelete
+ {else} +

No bills added.

+ {/if} +
diff --git a/tpl/json/new_invoice.html b/tpl/json/new_invoice.html new file mode 100755 index 0000000..febe8f0 --- /dev/null +++ b/tpl/json/new_invoice.html @@ -0,0 +1,52 @@ +{if condition="$error != ''"} +

{$error}

+{/if} + +

Add a bill

+ +
+
+ Expense +

+ +

+ +

+ + {$currency} +

+

+ + / + / + + +

+
+
+ Users in ? + {loop="users"} +
and . + {/loop} +
+

+ + {if condition="$id != 0"}{/if} + +

+
diff --git a/tpl/json/settings.html b/tpl/json/settings.html new file mode 100644 index 0000000..66af828 --- /dev/null +++ b/tpl/json/settings.html @@ -0,0 +1,63 @@ +{if condition="!$show_settings"} +

Edit homepage notice

+{if condition="$error"}

{$error}

{/if} +
+

+
+ +

+

Note : You can use HTML formatting in this form.

+

+ + +

+
+ +{else} +

Change settings of your Bouffe@Ulm installation

+{if condition="$error"}

{$error}

{/if} +
+
+ Database +

Note : Use these settings carefully. Your database won't be updated by the script as it was during install and you'll have to manually update it.

+

+ +

+

+ Toggle visible
+ Note : Leave the above field blank if you don't want to change your password. +

+

+
+ Note : You must create this database first. +

+

+
+ Note : Leave the field blank to not use any.

+
+
+ General options +

+

+
+ Note : This is the base URL from which you access this page. You must keep the trailing "/" in the above address. +

+

+

+
+ For example : Europe/Paris. See the doc for more info. +

+

+ + +

+
+

+
+ +{/if}