Do not check anymore data folder permissions

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.
This commit is contained in:
Frederic Guillot
2015-09-23 20:59:21 -04:00
parent 2af45250c4
commit 25b9e90ef3
8 changed files with 74 additions and 50 deletions

View File

@@ -29,6 +29,11 @@ Improvements:
* Add abstract storage layer * Add abstract storage layer
* Add abstract cache 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: Bug fixes:
* Fix typo in template that prevent the Gitlab OAuth link to be displayed * Fix typo in template that prevent the Gitlab OAuth link to be displayed

View File

@@ -54,6 +54,8 @@ abstract class Base extends \Core\Base
else if (! $is_user && ! $is_both_procedure && $is_user_procedure) { else if (! $is_user && ! $is_both_procedure && $is_user_procedure) {
throw new AccessDeniedException('Permission denied'); throw new AccessDeniedException('Permission denied');
} }
$this->logger->debug('API call: '.$procedure);
} }
public function checkProjectPermission($project_id) 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)) { if (! empty($task)) {
$task['url'] = $this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']), '', true); $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; return $task;
} }
protected function formatTasks(array $tasks) protected function formatTasks($tasks)
{ {
if (! empty($tasks)) { if (! empty($tasks)) {
foreach ($tasks as &$task) { foreach ($tasks as &$task) {
@@ -91,7 +93,7 @@ abstract class Base extends \Core\Base
return $tasks; return $tasks;
} }
protected function formatProject(array $project) protected function formatProject($project)
{ {
if (! empty($project)) { if (! empty($project)) {
$project['url'] = array( $project['url'] = array(
@@ -104,7 +106,7 @@ abstract class Base extends \Core\Base
return $project; return $project;
} }
protected function formatProjects(array $projects) protected function formatProjects($projects)
{ {
if (! empty($projects)) { if (! empty($projects)) {
foreach ($projects as &$project) { foreach ($projects as &$project) {

View File

@@ -2,6 +2,8 @@
namespace Api; namespace Api;
use Core\ObjectStorage\ObjectStorageException;
/** /**
* File API controller * File API controller
* *
@@ -22,16 +24,17 @@ class File extends \Core\Base
public function downloadFile($file_id) public function downloadFile($file_id)
{ {
$file = $this->file->getById($file_id); try {
if (! empty($file)) { $file = $this->file->getById($file_id);
$filename = FILES_DIR.$file['path']; if (! empty($file)) {
return base64_encode($this->objectStorage->get($file['path']));
if (file_exists($filename)) {
return base64_encode(file_get_contents($filename));
} }
} }
catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
}
return ''; return '';
} }

View File

@@ -2,6 +2,8 @@
namespace Controller; namespace Controller;
use Core\ObjectStorage\ObjectStorageException;
/** /**
* File controller * File controller
* *
@@ -74,15 +76,21 @@ class File extends Base
*/ */
public function download() public function download()
{ {
$task = $this->getTask(); try {
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
if ($file['task_id'] != $task['id']) { $task = $this->getTask();
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); $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']);
}
catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
} }
$this->response->forceDownload($file['name']);
$this->objectStorage->passthru($file['path']);
} }
/** /**
@@ -110,15 +118,21 @@ class File extends Base
*/ */
public function image() public function image()
{ {
$task = $this->getTask(); try {
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
if ($file['task_id'] != $task['id']) { $task = $this->getTask();
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); $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($this->file->getImageMimeType($file['name']));
$this->objectStorage->passthru($file['path']);
}
catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
} }
$this->response->contentType($this->file->getImageMimeType($file['name']));
$this->objectStorage->passthru($file['path']);
} }
/** /**
@@ -128,15 +142,21 @@ class File extends Base
*/ */
public function thumbnail() public function thumbnail()
{ {
$task = $this->getTask(); try {
$file = $this->file->getById($this->request->getIntegerParam('file_id'));
if ($file['task_id'] != $task['id']) { $task = $this->getTask();
$this->response->redirect($this->helper->url->to('task', 'show', array('task_id' => $task['id'], 'project_id' => $task['project_id']))); $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']));
}
catch (ObjectStorageException $e) {
$this->logger->error($e->getMessage());
} }
$this->response->contentType('image/jpeg');
$this->objectStorage->passthru($this->file->getThumbnailPath($file['path']));
} }
/** /**

View File

@@ -54,6 +54,10 @@ class File extends Base
$file = $this->getbyId($file_id); $file = $this->getbyId($file_id);
$this->objectStorage->remove($file['path']); $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(); return $this->db->table(self::TABLE)->eq('id', $file['id'])->remove();
} }
catch (ObjectStorageException $e) { catch (ObjectStorageException $e) {

View File

@@ -47,7 +47,7 @@
<?= $this->render('header', array( <?= $this->render('header', array(
'title' => $title, 'title' => $title,
'description' => isset($description) ? $description : '', 'description' => isset($description) ? $description : '',
'board_selector' => $board_selector, 'board_selector' => isset($board_selector) ? $board_selector : array(),
)) ?> )) ?>
<section class="page"> <section class="page">
<?= $this->app->flashMessage() ?> <?= $this->app->flashMessage() ?>

View File

@@ -29,24 +29,7 @@ if (! extension_loaded('mbstring')) {
die('PHP extension required: 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() // Fix wrong value for arg_separator.output, used by the function http_build_query()
if (ini_get('arg_separator.output') === '&amp;') { if (ini_get('arg_separator.output') === '&amp;') {
ini_set('arg_separator.output', '&'); 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');
}

View File

@@ -20,7 +20,14 @@ From the archive (stable version)
6. Start to use the software 6. Start to use the software
7. Don't forget to change your password! 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) From the repository (development version)
----------------------------------------- -----------------------------------------