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:
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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 '';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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']));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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() ?>
|
||||||
|
|||||||
@@ -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') === '&') {
|
if (ini_get('arg_separator.output') === '&') {
|
||||||
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');
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -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)
|
||||||
-----------------------------------------
|
-----------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user