summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrédéric Guillot <contact@fredericguillot.com>2014-02-22 16:30:03 -0500
committerFrédéric Guillot <contact@fredericguillot.com>2014-02-22 16:30:03 -0500
commit2f4651411b1827e1e5859ba6053052b508f455e0 (patch)
treeea07631e7a5e5850367f873c7a9c1a0e07e10638
parenta1923d3d7f9276e859d6fd6bee339f0ea00f6544 (diff)
Add kiosk mode, public board access with read-only and auto-refresh
-rw-r--r--controllers/base.php1
-rw-r--r--controllers/board.php28
-rw-r--r--index.php5
-rw-r--r--locales/fr_FR/translations.php1
-rw-r--r--locales/pl_PL/translations.php4
-rw-r--r--models/base.php15
-rw-r--r--models/config.php10
-rw-r--r--models/project.php7
-rw-r--r--models/schema.php22
-rw-r--r--templates/board_public.php41
-rw-r--r--templates/layout.php3
-rw-r--r--templates/project_index.php3
12 files changed, 121 insertions, 19 deletions
diff --git a/controllers/base.php b/controllers/base.php
index 5c48d927..c248ede1 100644
--- a/controllers/base.php
+++ b/controllers/base.php
@@ -45,6 +45,7 @@ abstract class Base
$public = array(
'user' => array('login', 'check'),
'task' => array('add'),
+ 'board' => array('readonly'),
);
if (isset($public[$controller])) {
diff --git a/controllers/board.php b/controllers/board.php
index ec32e8a0..e8b161e7 100644
--- a/controllers/board.php
+++ b/controllers/board.php
@@ -4,7 +4,29 @@ namespace Controller;
class Board extends Base
{
- // Display current board
+ // Display the public version of a board
+ // Access checked by a simple token, no user login, read only, auto-refresh
+ public function readonly()
+ {
+ $token = $this->request->getStringParam('token');
+ $project = $this->project->getByToken($token);
+
+ // Token verification
+ if (! $project) {
+ $this->response->text('Not Authorized', 401);
+ }
+
+ // Display the board with a specific layout
+ $this->response->html($this->template->layout('board_public', array(
+ 'project' => $project,
+ 'columns' => $this->board->get($project['id']),
+ 'title' => $project['name'],
+ 'no_layout' => true,
+ 'auto_refresh' => true,
+ )));
+ }
+
+ // Display the default user project or the first project
public function index()
{
$projects = $this->project->getListByStatus(\Model\Project::ACTIVE);
@@ -30,7 +52,7 @@ class Board extends Base
)));
}
- // Show a board
+ // Show a board for a given project
public function show()
{
$projects = $this->project->getListByStatus(\Model\Project::ACTIVE);
@@ -175,7 +197,7 @@ class Board extends Base
$this->response->redirect('?controller=board&action=edit&project_id='.$column['project_id']);
}
- // Save the board (Ajax request made by drag and drop)
+ // Save the board (Ajax request made by the drag and drop)
public function save()
{
$this->response->json(array(
diff --git a/index.php b/index.php
index 7d4b70cf..6925570e 100644
--- a/index.php
+++ b/index.php
@@ -4,5 +4,10 @@ require __DIR__.'/check_setup.php';
require __DIR__.'/controllers/base.php';
require __DIR__.'/lib/router.php';
+if (file_exists('config.php')) require 'config.php';
+
+// Auto-refresh frequency in seconds for the public board view
+defined('AUTO_REFRESH_DURATION') or define('AUTO_REFRESH_DURATION', 60);
+
$router = new Router;
$router->execute();
diff --git a/locales/fr_FR/translations.php b/locales/fr_FR/translations.php
index 245825ad..7d021fcc 100644
--- a/locales/fr_FR/translations.php
+++ b/locales/fr_FR/translations.php
@@ -179,4 +179,5 @@ return array(
'Completed tasks for "%s"' => 'Tâches terminées pour "%s"',
'%d closed tasks' => '%d tâches terminées',
'no task for this project' => 'aucune tâche pour ce projet',
+ 'Public link' => 'Accès public',
);
diff --git a/locales/pl_PL/translations.php b/locales/pl_PL/translations.php
index 32e9e3c8..c5e993f5 100644
--- a/locales/pl_PL/translations.php
+++ b/locales/pl_PL/translations.php
@@ -181,5 +181,7 @@ return array(
'List of projects' => '',
'Completed tasks for "%s"' => '',
'%d closed tasks' => '',
- 'no task for this project' => '',*/
+ 'no task for this project' => '',
+ 'Public link' => '',
+ */
);
diff --git a/models/base.php b/models/base.php
index 981c7839..3c071623 100644
--- a/models/base.php
+++ b/models/base.php
@@ -17,7 +17,7 @@ require __DIR__.'/schema.php';
abstract class Base
{
const APP_VERSION = 'master';
- const DB_VERSION = 2;
+ const DB_VERSION = 3;
const DB_FILENAME = 'data/db.sqlite';
private static $dbInstance = null;
@@ -46,4 +46,17 @@ abstract class Base
die('Unable to migrate database schema!');
}
}
+
+ // Generate a random token from /dev/urandom or with uniqid()
+ public static function generateToken()
+ {
+ if (ini_get('open_basedir') === '') {
+ $token = file_get_contents('/dev/urandom', false, null, 0, 30);
+ }
+ else {
+ $token = uniqid(mt_rand(), true);
+ }
+
+ return hash('crc32b', $token);
+ }
}
diff --git a/models/config.php b/models/config.php
index fe4f6c99..f4d34986 100644
--- a/models/config.php
+++ b/models/config.php
@@ -66,16 +66,6 @@ class Config extends Base
);
}
- public static function generateToken()
- {
- if (ini_get('open_basedir') === '') {
- return substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15);
- }
- else {
- return substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
- }
- }
-
public function optimizeDatabase()
{
$this->db->getconnection()->exec("VACUUM");
diff --git a/models/project.php b/models/project.php
index 10d7c572..cb96dccd 100644
--- a/models/project.php
+++ b/models/project.php
@@ -16,6 +16,11 @@ class Project extends Base
return $this->db->table(self::TABLE)->eq('id', $project_id)->findOne();
}
+ public function getByToken($token)
+ {
+ return $this->db->table(self::TABLE)->eq('token', $token)->findOne();
+ }
+
public function getFirst()
{
return $this->db->table(self::TABLE)->findOne();
@@ -92,12 +97,12 @@ class Project extends Base
{
$this->db->startTransaction();
+ $values['token'] = self::generateToken();
$this->db->table(self::TABLE)->save($values);
$project_id = $this->db->getConnection()->getLastId();
$boardModel = new \Model\Board;
-
$boardModel->create($project_id, array(
t('Backlog'),
t('Ready'),
diff --git a/models/schema.php b/models/schema.php
index 9ccb500f..84926d73 100644
--- a/models/schema.php
+++ b/models/schema.php
@@ -2,11 +2,27 @@
namespace Schema;
+function version_3($pdo)
+{
+ $pdo->exec('ALTER TABLE projects ADD column token TEXT');
+
+ // For each existing project, assign a different token
+ $rq = $pdo->prepare("SELECT id FROM projects WHERE token IS NULL");
+ $rq->execute();
+ $results = $rq->fetchAll(\PDO::FETCH_ASSOC);
+
+ if ($results !== false) {
+
+ foreach ($results as &$result) {
+ $rq = $pdo->prepare('UPDATE projects SET token=? WHERE id=?');
+ $rq->execute(array(\Model\Base::generateToken(), $result['id']));
+ }
+ }
+}
+
function version_2($pdo)
{
$pdo->exec('ALTER TABLE tasks ADD column date_completed INTEGER');
-
- // For all existing completed tasks, set the date of creation as a date of completion
$pdo->exec('UPDATE tasks SET date_completed=date_creation WHERE is_active=0');
}
@@ -74,6 +90,6 @@ function version_1($pdo)
$pdo->exec("
INSERT INTO config
(language, webhooks_token)
- VALUES ('en_US', '".\Model\Config::generateToken()."')
+ VALUES ('en_US', '".\Model\Base::generateToken()."')
");
}
diff --git a/templates/board_public.php b/templates/board_public.php
new file mode 100644
index 00000000..d01bae0f
--- /dev/null
+++ b/templates/board_public.php
@@ -0,0 +1,41 @@
+<section id="main">
+
+ <table id="board">
+ <tr>
+ <?php $column_with = round(100 / count($columns), 2); ?>
+ <?php foreach ($columns as $column): ?>
+ <th width="<?= $column_with ?>%">
+ <?= Helper\escape($column['title']) ?>
+ </th>
+ <?php endforeach ?>
+ </tr>
+ <tr>
+ <?php foreach ($columns as $column): ?>
+ <td class="column">
+ <?php foreach ($column['tasks'] as $task): ?>
+ <div class="draggable-item">
+ <div class="task task-<?= $task['color_id'] ?>">
+
+ #<?= $task['id'] ?> -
+
+ <span class="task-user">
+ <?php if (! empty($task['owner_id'])): ?>
+ <?= t('Assigned to %s', $task['username']) ?>
+ <?php else: ?>
+ <span class="task-nobody"><?= t('No body assigned') ?></span>
+ <?php endif ?>
+ </span>
+
+ <div class="task-title">
+ <?= Helper\escape($task['title']) ?>
+ </div>
+
+ </div>
+ </div>
+ <?php endforeach ?>
+ </td>
+ <?php endforeach ?>
+ </tr>
+ </table>
+
+</section> \ No newline at end of file
diff --git a/templates/layout.php b/templates/layout.php
index 1c89f2ab..0791b910 100644
--- a/templates/layout.php
+++ b/templates/layout.php
@@ -10,6 +10,9 @@
<link rel="apple-touch-icon" sizes="114x114" href="assets/img/touch-icon-iphone-retina.png">
<link rel="apple-touch-icon" sizes="144x144" href="assets/img/touch-icon-ipad-retina.png">
<title><?= isset($title) ? Helper\escape($title) : 'Kanboard' ?></title>
+ <?php if (isset($auto_refresh)): ?>
+ <meta http-equiv="refresh" content="<?= AUTO_REFRESH_DURATION ?>" >
+ <?php endif ?>
</head>
<body>
<?php if (isset($no_layout)): ?>
diff --git a/templates/project_index.php b/templates/project_index.php
index d144e41f..8c75ef0b 100644
--- a/templates/project_index.php
+++ b/templates/project_index.php
@@ -75,6 +75,9 @@
<li>
<a href="?controller=project&amp;action=confirm&amp;project_id=<?= $project['id'] ?>"><?= t('Remove') ?></a>
</li>
+ <li>
+ <a href="?controller=board&amp;action=readonly&amp;token=<?= $project['token'] ?>" target="_blank"><?= t('Public link') ?></a>
+ </li>
</ul>
</td>
<?php endif ?>