summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--app/Api/Base.php10
-rw-r--r--app/Api/File.php15
-rw-r--r--app/Controller/File.php62
-rw-r--r--app/Core/ObjectStorage/FileStorage.php2
-rw-r--r--app/Core/ObjectStorage/ObjectStorageInterface.php2
-rw-r--r--app/Model/File.php4
-rw-r--r--app/Template/layout.php2
-rw-r--r--app/check_setup.php17
-rw-r--r--doc/installation.markdown9
-rw-r--r--tests/units/Model/FileTest.php10
11 files changed, 85 insertions, 53 deletions
diff --git a/ChangeLog b/ChangeLog
index 566f501a..3302fae9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -29,6 +29,11 @@ Improvements:
* Add abstract storage layer
* Add abstract cache layer
+Others:
+
+* Data directory permissions are not checked anymore
+* Data directory is not mandatory anymore for people that use a remote database and remote object storage
+
Bug fixes:
* Fix typo in template that prevent the Gitlab OAuth link to be displayed
diff --git a/app/Api/Base.php b/app/Api/Base.php
index fef36e0c..0287e0ec 100644
--- a/app/Api/Base.php
+++ b/app/Api/Base.php
@@ -54,6 +54,8 @@ abstract class Base extends \Core\Base
else if (! $is_user && ! $is_both_procedure && $is_user_procedure) {
throw new AccessDeniedException('Permission denied');
}
+
+ $this->logger->debug('API call: '.$procedure);
}
public function checkProjectPermission($project_id)
@@ -70,7 +72,7 @@ abstract class Base extends \Core\Base
}
}
- protected function formatTask(array $task)
+ protected function formatTask($task)
{
if (! empty($task)) {
$task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true);
@@ -80,7 +82,7 @@ abstract class Base extends \Core\Base
return $task;
}
- protected function formatTasks(array $tasks)
+ protected function formatTasks($tasks)
{
if (! empty($tasks)) {
foreach ($tasks as &$task) {
@@ -91,7 +93,7 @@ abstract class Base extends \Core\Base
return $tasks;
}
- protected function formatProject(array $project)
+ protected function formatProject($project)
{
if (! empty($project)) {
$project['url'] = array(
@@ -104,7 +106,7 @@ abstract class Base extends \Core\Base
return $project;
}
- protected function formatProjects(array $projects)
+ protected function formatProjects($projects)
{
if (! empty($projects)) {
foreach ($projects as &$project) {
diff --git a/app/Api/File.php b/app/Api/File.php
index 97aa9d82..ad736ad4 100644
--- a/app/Api/File.php
+++ b/app/Api/File.php
@@ -2,6 +2,8 @@
namespace Api;
+use Core\ObjectStorage\ObjectStorageException;
+
/**
* File API controller
*
@@ -22,16 +24,17 @@ class File extends \Core\Base
public function downloadFile($file_id)
{
- $file = $this->file->getById($file_id);
-
- if (! empty($file)) {
+ try {
- $filename = FILES_DIR.$file['path'];
+ $file = $this->file->getById($file_id);
- if (file_exists($filename)) {
- return base64_encode(file_get_contents($filename));
+ if (! empty($file)) {
+ return base64_encode($this->objectStorage->get($file['path']));
}
}
+ catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
return '';
}
diff --git a/app/Controller/File.php b/app/Controller/File.php
index 7b7c75ee..ef90c55a 100644
--- a/app/Controller/File.php
+++ b/app/Controller/File.php
@@ -2,6 +2,8 @@
namespace Controller;
+use Core\ObjectStorage\ObjectStorageException;
+
/**
* File controller
*
@@ -74,15 +76,21 @@ class File extends Base
*/
public function download()
{
- $task = $this->getTask();
- $file = $this->file->getById($this->request->getIntegerParam('file_id'));
+ try {
- if ($file['task_id'] != $task['id']) {
- $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
- }
+ $task = $this->getTask();
+ $file = $this->file->getById($this->request->getIntegerParam('file_id'));
+
+ if ($file['task_id'] != $task['id']) {
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
+ }
- $this->response->forceDownload($file['name']);
- $this->objectStorage->passthru($file['path']);
+ $this->response->forceDownload($file['name']);
+ $this->objectStorage->output($file['path']);
+ }
+ catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
}
/**
@@ -110,15 +118,21 @@ class File extends Base
*/
public function image()
{
- $task = $this->getTask();
- $file = $this->file->getById($this->request->getIntegerParam('file_id'));
+ try {
- if ($file['task_id'] != $task['id']) {
- $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
- }
+ $task = $this->getTask();
+ $file = $this->file->getById($this->request->getIntegerParam('file_id'));
- $this->response->contentType($this->file->getImageMimeType($file['name']));
- $this->objectStorage->passthru($file['path']);
+ if ($file['task_id'] != $task['id']) {
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
+ }
+
+ $this->response->contentType($this->file->getImageMimeType($file['name']));
+ $this->objectStorage->output($file['path']);
+ }
+ catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
}
/**
@@ -128,15 +142,21 @@ class File extends Base
*/
public function thumbnail()
{
- $task = $this->getTask();
- $file = $this->file->getById($this->request->getIntegerParam('file_id'));
+ try {
- if ($file['task_id'] != $task['id']) {
- $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
- }
+ $task = $this->getTask();
+ $file = $this->file->getById($this->request->getIntegerParam('file_id'));
+
+ if ($file['task_id'] != $task['id']) {
+ $this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id'])));
+ }
- $this->response->contentType('image/jpeg');
- $this->objectStorage->passthru($this->file->getThumbnailPath($file['path']));
+ $this->response->contentType('image/jpeg');
+ $this->objectStorage->output($this->file->getThumbnailPath($file['path']));
+ }
+ catch (ObjectStorageException $e) {
+ $this->logger->error($e->getMessage());
+ }
}
/**
diff --git a/app/Core/ObjectStorage/FileStorage.php b/app/Core/ObjectStorage/FileStorage.php
index 96478c3a..fa1efe21 100644
--- a/app/Core/ObjectStorage/FileStorage.php
+++ b/app/Core/ObjectStorage/FileStorage.php
@@ -70,7 +70,7 @@ class FileStorage implements ObjectStorageInterface
* @access public
* @param string $key
*/
- public function passthru($key)
+ public function output($key)
{
$filename = $this->path.DIRECTORY_SEPARATOR.$key;
diff --git a/app/Core/ObjectStorage/ObjectStorageInterface.php b/app/Core/ObjectStorage/ObjectStorageInterface.php
index 5440cf2b..180bdf86 100644
--- a/app/Core/ObjectStorage/ObjectStorageInterface.php
+++ b/app/Core/ObjectStorage/ObjectStorageInterface.php
@@ -35,7 +35,7 @@ interface ObjectStorageInterface
* @access public
* @param string $key
*/
- public function passthru($key);
+ public function output($key);
/**
* Move local file to object storage
diff --git a/app/Model/File.php b/app/Model/File.php
index 7adab42b..1d44a415 100644
--- a/app/Model/File.php
+++ b/app/Model/File.php
@@ -54,6 +54,10 @@ class File extends Base
$file = $this->getbyId($file_id);
$this->objectStorage->remove($file['path']);
+ if ($file['is_image'] == 1) {
+ $this->objectStorage->remove($this->getThumbnailPath($file['path']));
+ }
+
return $this->db->table(self::TABLE)->eq('id', $file['id'])->remove();
}
catch (ObjectStorageException $e) {
diff --git a/app/Template/layout.php b/app/Template/layout.php
index cba8d2a3..20582952 100644
--- a/app/Template/layout.php
+++ b/app/Template/layout.php
@@ -47,7 +47,7 @@
<?= $this->render('header', array(
'title' => $title,
'description' => isset($description) ? $description : '',
- 'board_selector' => $board_selector,
+ 'board_selector' => isset($board_selector) ? $board_selector : array(),
)) ?>
<section class="page">
<?= $this->app->flashMessage() ?>
diff --git a/app/check_setup.php b/app/check_setup.php
index 624b6b34..65f291e5 100644
--- a/app/check_setup.php
+++ b/app/check_setup.php
@@ -29,24 +29,7 @@ if (! extension_loaded('mbstring')) {
die('PHP extension required: mbstring');
}
-// Check if /data is writeable
-if (! is_writable('data')) {
- die('The directory "data" must be writeable by your web server user');
-}
-
// Fix wrong value for arg_separator.output, used by the function http_build_query()
if (ini_get('arg_separator.output') === '&amp;') {
ini_set('arg_separator.output', '&');
}
-
-// Prepare folder for uploaded files
-if (! is_dir(FILES_DIR)) {
- if (! mkdir(FILES_DIR, 0755, true)) {
- die('Unable to create the upload directory: "'.FILES_DIR.'"');
- }
-}
-
-// Check permissions for files folder
-if (! is_writable(FILES_DIR)) {
- die('The directory "'.FILES_DIR.'" must be writeable by your webserver user');
-}
diff --git a/doc/installation.markdown b/doc/installation.markdown
index 53e7095b..30a2916c 100644
--- a/doc/installation.markdown
+++ b/doc/installation.markdown
@@ -20,7 +20,14 @@ From the archive (stable version)
6. Start to use the software
7. Don't forget to change your password!
-Note: The folder data is the location where Kanboard stores uploaded files as well as the Sqlite database.
+The data folder is used to store:
+
+- Sqlite database: `db.sqlite`
+- Debug file: `debug.log` (if debug mode enabled)
+- Uploaded files: `files/*`
+- Image thumbnails: `files/thumbnails/*`
+
+People who are using a remote database (Mysql/Postgresql) and a remote file storage (Aws S3 or similar) don't necessary needs to have a persistent local data folder or to change the permissions.
From the repository (development version)
-----------------------------------------
diff --git a/tests/units/Model/FileTest.php b/tests/units/Model/FileTest.php
index e7520c89..d1ad7248 100644
--- a/tests/units/Model/FileTest.php
+++ b/tests/units/Model/FileTest.php
@@ -227,7 +227,7 @@ class FileTest extends Base
->expects($this->at(1))
->method('remove')
->with(
- $this->equalTo('/tmp/foo1')
+ $this->equalTo('thumbnails//tmp/foo2')
)
->will($this->returnValue(true));
@@ -235,6 +235,14 @@ class FileTest extends Base
->expects($this->at(2))
->method('remove')
->with(
+ $this->equalTo('/tmp/foo1')
+ )
+ ->will($this->returnValue(true));
+
+ $this->container['objectStorage']
+ ->expects($this->at(3))
+ ->method('remove')
+ ->with(
$this->equalTo('/tmp/foo3')
)
->will($this->returnValue(true));