Closed #10
This commit is contained in:
parent
be4a2615dd
commit
6c4affe454
10 changed files with 534 additions and 137 deletions
22
config.ini
22
config.ini
|
@ -37,14 +37,26 @@ Kind regards,
|
||||||
|
|
||||||
[privileges]
|
[privileges]
|
||||||
uploadPost=registered
|
uploadPost=registered
|
||||||
viewPost=anonymous
|
|
||||||
viewPost.sketchy=registered
|
|
||||||
viewPost.unsafe=registered
|
|
||||||
listPosts=anonymous
|
listPosts=anonymous
|
||||||
listPosts.sketchy=registered
|
listPosts.sketchy=registered
|
||||||
listPosts.unsafe=registered
|
listPosts.unsafe=registered
|
||||||
|
listPosts.hidden=nobody
|
||||||
listUsers=registered
|
listUsers=registered
|
||||||
favoritePost=registered
|
viewPost=anonymous
|
||||||
listComments=anonymous
|
viewPost.sketchy=registered
|
||||||
|
viewPost.unsafe=registered
|
||||||
|
viewPost.hidden=admin
|
||||||
retrievePost=anonymous
|
retrievePost=anonymous
|
||||||
|
favoritePost=registered
|
||||||
|
editPostSafety.own=registered
|
||||||
|
editPostSafety.all=moderator
|
||||||
|
editPostTags.own=registered
|
||||||
|
editPostTags.all=registered
|
||||||
|
editPostThumb.own=moderator
|
||||||
|
editPostThumb.all=moderator
|
||||||
|
hidePost.own=moderator
|
||||||
|
hidePost.all=moderator
|
||||||
|
deletePost.own=moderator
|
||||||
|
deletePost.all=moderator
|
||||||
|
listComments=anonymous
|
||||||
listTags=anonymous
|
listTags=anonymous
|
||||||
|
|
|
@ -96,6 +96,9 @@ body {
|
||||||
|
|
||||||
#sidebar h1 {
|
#sidebar h1 {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, h2, h3 {
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,12 +73,15 @@ i.icon-dl {
|
||||||
margin-right: 0.5em;
|
margin-right: 0.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.options nav ul {
|
.options ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.favorites p {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.favorites ul {
|
.favorites ul {
|
||||||
list-style-type: none;
|
list-style-type: none;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
@ -90,3 +93,42 @@ i.icon-dl {
|
||||||
.favorites a {
|
.favorites a {
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inactive {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.edit {
|
||||||
|
display: none;
|
||||||
|
padding: 0.5em 1em;
|
||||||
|
border: 1px solid #eee;
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
margin: 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.edit>div {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
form.edit input[type=checkbox],
|
||||||
|
form.edit label {
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 33px;
|
||||||
|
}
|
||||||
|
form.edit label.left {
|
||||||
|
display: inline-block;
|
||||||
|
width: 5em;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
form.edit .safety label:not(.left) {
|
||||||
|
margin-right: 0.75em;
|
||||||
|
}
|
||||||
|
form.edit>div {
|
||||||
|
clear: left;
|
||||||
|
}
|
||||||
|
ul.tagit {
|
||||||
|
display: block;
|
||||||
|
vertical-align: middle;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1em;
|
||||||
|
}
|
||||||
|
|
|
@ -1,20 +1,122 @@
|
||||||
$(function()
|
$(function()
|
||||||
{
|
{
|
||||||
$('.add-fav a, .rem-fav a').click(function(e)
|
$('.add-fav a, .rem-fav a, .hide a, .unhide a').click(function(e)
|
||||||
{
|
{
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var url = $(this).attr('href');
|
|
||||||
url += '?json';
|
var aDom = $(this);
|
||||||
|
if (aDom.hasClass('inactive'))
|
||||||
|
return;
|
||||||
|
aDom.addClass('inactive');
|
||||||
|
|
||||||
|
var url = $(this).attr('href') + '?json';
|
||||||
$.get(url, function(data)
|
$.get(url, function(data)
|
||||||
{
|
{
|
||||||
if (data['errorMessage'])
|
if (data['success'])
|
||||||
{
|
|
||||||
alert(data['errorMessage']);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alert(data['errorMessage']);
|
||||||
|
aDom.removeClass('inactive');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('.delete a').click(function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var aDom = $(this);
|
||||||
|
if (aDom.hasClass('inactive'))
|
||||||
|
return;
|
||||||
|
aDom.addClass('inactive');
|
||||||
|
|
||||||
|
//todo: move this string literal to html
|
||||||
|
if (confirm(aDom.attr('data-confirm-text')))
|
||||||
|
{
|
||||||
|
var url = $(this).attr('href') + '?json';
|
||||||
|
$.get(url, function(data)
|
||||||
|
{
|
||||||
|
if (data['success'])
|
||||||
|
{
|
||||||
|
window.location.href = aDom.attr('data-redirect-url');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alert(data['errorMessage']);
|
||||||
|
aDom.removeClass('inactive');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aDom.removeClass('inactive');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('li.edit a').click(function(e)
|
||||||
|
{
|
||||||
|
var aDom = $(this);
|
||||||
|
if (aDom.hasClass('inactive'))
|
||||||
|
return;
|
||||||
|
aDom.addClass('inactive');
|
||||||
|
|
||||||
|
var tags = [];
|
||||||
|
$.getJSON('/tags?json', function(data)
|
||||||
|
{
|
||||||
|
tags = data['tags'];
|
||||||
|
|
||||||
|
var tagItOptions =
|
||||||
|
{
|
||||||
|
caseSensitive: true,
|
||||||
|
availableTags: tags,
|
||||||
|
placeholderText: $('.tags input').attr('placeholder')
|
||||||
|
};
|
||||||
|
$('.tags input').tagit(tagItOptions);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
$('form.edit').slideDown();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
$('form.edit').submit(function(e)
|
||||||
|
{
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
var formDom = $(this);
|
||||||
|
if (formDom.hasClass('inactive'))
|
||||||
|
return;
|
||||||
|
formDom.addClass('inactive');
|
||||||
|
formDom.find(':input').attr('readonly', true);
|
||||||
|
|
||||||
|
var url = formDom.attr('action') + '?json';
|
||||||
|
var fd = new FormData(formDom[0]);
|
||||||
|
|
||||||
|
var ajaxData =
|
||||||
|
{
|
||||||
|
url: url,
|
||||||
|
data: fd,
|
||||||
|
processData: false,
|
||||||
|
contentType: false,
|
||||||
|
type: 'POST',
|
||||||
|
|
||||||
|
success: function(data)
|
||||||
|
{
|
||||||
|
if (data['success'])
|
||||||
|
{
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
alert(data['errorMessage']);
|
||||||
|
formDom.find(':input').attr('readonly', false);
|
||||||
|
formDom.removeClass('inactive');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$.ajax(ajaxData);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -154,7 +154,8 @@ $(function()
|
||||||
|
|
||||||
postDom.show();
|
postDom.show();
|
||||||
var tagItOptions =
|
var tagItOptions =
|
||||||
{ caseSensitive: true,
|
{
|
||||||
|
caseSensitive: true,
|
||||||
availableTags: tags,
|
availableTags: tags,
|
||||||
placeholderText: $('.tags input').attr('placeholder')
|
placeholderText: $('.tags input').attr('placeholder')
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,6 +8,60 @@ class PostController
|
||||||
$callback();
|
$callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static function locatePost($key)
|
||||||
|
{
|
||||||
|
if (is_numeric($key))
|
||||||
|
{
|
||||||
|
$post = R::findOne('post', 'id = ?', [$key]);
|
||||||
|
if (!$post)
|
||||||
|
throw new SimpleException('Invalid post ID "' . $key . '"');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$post = R::findOne('post', 'name = ?', [$key]);
|
||||||
|
if (!$post)
|
||||||
|
throw new SimpleException('Invalid post name "' . $key . '"');
|
||||||
|
}
|
||||||
|
return $post;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function serializeTags($post)
|
||||||
|
{
|
||||||
|
$x = [];
|
||||||
|
foreach ($post->sharedTag as $tag)
|
||||||
|
$x []= $tag->name;
|
||||||
|
natcasesort($x);
|
||||||
|
$x = join('', $x);
|
||||||
|
return md5($x);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function handleUploadErrors($file)
|
||||||
|
{
|
||||||
|
switch ($file['error'])
|
||||||
|
{
|
||||||
|
case UPLOAD_ERR_OK:
|
||||||
|
break;
|
||||||
|
case UPLOAD_ERR_INI_SIZE:
|
||||||
|
throw new SimpleException('File is too big (maximum size allowed: ' . ini_get('upload_max_filesize') . ')');
|
||||||
|
case UPLOAD_ERR_FORM_SIZE:
|
||||||
|
throw new SimpleException('File is too big than it was allowed in HTML form');
|
||||||
|
case UPLOAD_ERR_PARTIAL:
|
||||||
|
throw new SimpleException('File transfer was interrupted');
|
||||||
|
case UPLOAD_ERR_NO_FILE:
|
||||||
|
throw new SimpleException('No file was uploaded');
|
||||||
|
case UPLOAD_ERR_NO_TMP_DIR:
|
||||||
|
throw new SimpleException('Server misconfiguration error: missing temporary folder');
|
||||||
|
case UPLOAD_ERR_CANT_WRITE:
|
||||||
|
throw new SimpleException('Server misconfiguration error: cannot write to disk');
|
||||||
|
case UPLOAD_ERR_EXTENSION:
|
||||||
|
throw new SimpleException('Server misconfiguration error: upload was canceled by an extension');
|
||||||
|
default:
|
||||||
|
throw new SimpleException('Generic file upload error (id: ' . $file['error'] . ')');
|
||||||
|
}
|
||||||
|
if (!is_uploaded_file($file['tmp_name']))
|
||||||
|
throw new SimpleException('Generic file upload error');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -37,7 +91,6 @@ class PostController
|
||||||
$this->context->subTitle = 'browsing posts';
|
$this->context->subTitle = 'browsing posts';
|
||||||
$page = intval($page);
|
$page = intval($page);
|
||||||
$postsPerPage = intval($this->config->browsing->postsPerPage);
|
$postsPerPage = intval($this->config->browsing->postsPerPage);
|
||||||
|
|
||||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ListPosts);
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ListPosts);
|
||||||
|
|
||||||
$buildDbQuery = function($dbQuery)
|
$buildDbQuery = function($dbQuery)
|
||||||
|
@ -54,6 +107,9 @@ class PostController
|
||||||
foreach ($allowedSafety as $s)
|
foreach ($allowedSafety as $s)
|
||||||
$dbQuery->put($s);
|
$dbQuery->put($s);
|
||||||
|
|
||||||
|
if (!PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts, 'hidden'))
|
||||||
|
$dbQuery->andNot('hidden');
|
||||||
|
|
||||||
//todo construct WHERE based on filters
|
//todo construct WHERE based on filters
|
||||||
|
|
||||||
//todo construct ORDER based on filers
|
//todo construct ORDER based on filers
|
||||||
|
@ -82,6 +138,19 @@ class PostController
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route /favorites
|
||||||
|
* @route /favorites/{page}
|
||||||
|
* @validate page \d*
|
||||||
|
*/
|
||||||
|
public function favoritesAction($page = 1)
|
||||||
|
{
|
||||||
|
$this->listAction('favmin:1', $page);
|
||||||
|
$this->context->viewName = 'post-list';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @route /post/upload
|
* @route /post/upload
|
||||||
*/
|
*/
|
||||||
|
@ -90,15 +159,17 @@ class PostController
|
||||||
$this->context->stylesheets []= 'upload.css';
|
$this->context->stylesheets []= 'upload.css';
|
||||||
$this->context->scripts []= 'upload.js';
|
$this->context->scripts []= 'upload.js';
|
||||||
$this->context->subTitle = 'upload';
|
$this->context->subTitle = 'upload';
|
||||||
|
|
||||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::UploadPost);
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::UploadPost);
|
||||||
|
|
||||||
if (isset($_FILES['file']))
|
if (isset($_FILES['file']))
|
||||||
{
|
{
|
||||||
|
/* safety */
|
||||||
$suppliedSafety = intval(InputHelper::get('safety'));
|
$suppliedSafety = intval(InputHelper::get('safety'));
|
||||||
if (!in_array($suppliedSafety, PostSafety::getAll()))
|
if (!in_array($suppliedSafety, PostSafety::getAll()))
|
||||||
throw new SimpleException('Invalid safety type "' . $suppliedSafety . '"');
|
throw new SimpleException('Invalid safety type "' . $suppliedSafety . '"');
|
||||||
|
|
||||||
|
|
||||||
|
/* tags */
|
||||||
$suppliedTags = InputHelper::get('tags');
|
$suppliedTags = InputHelper::get('tags');
|
||||||
$suppliedTags = preg_split('/[,;\s+]/', $suppliedTags);
|
$suppliedTags = preg_split('/[,;\s+]/', $suppliedTags);
|
||||||
$suppliedTags = array_filter($suppliedTags);
|
$suppliedTags = array_filter($suppliedTags);
|
||||||
|
@ -109,32 +180,26 @@ class PostController
|
||||||
if (empty($suppliedTags))
|
if (empty($suppliedTags))
|
||||||
throw new SimpleException('No tags set');
|
throw new SimpleException('No tags set');
|
||||||
|
|
||||||
$suppliedFile = $_FILES['file'];
|
$dbTags = [];
|
||||||
switch ($suppliedFile['error'])
|
foreach ($suppliedTags as $tag)
|
||||||
{
|
{
|
||||||
case UPLOAD_ERR_OK:
|
$dbTag = R::findOne('tag', 'name = ?', [$tag]);
|
||||||
break;
|
if (!$dbTag)
|
||||||
case UPLOAD_ERR_INI_SIZE:
|
{
|
||||||
throw new SimpleException('File is too big (maximum size allowed: ' . ini_get('upload_max_filesize') . ')');
|
$dbTag = R::dispense('tag');
|
||||||
case UPLOAD_ERR_FORM_SIZE:
|
$dbTag->name = $tag;
|
||||||
throw new SimpleException('File is too big than it was allowed in HTML form');
|
R::store($dbTag);
|
||||||
case UPLOAD_ERR_PARTIAL:
|
}
|
||||||
throw new SimpleException('File transfer was interrupted');
|
$dbTags []= $dbTag;
|
||||||
case UPLOAD_ERR_NO_FILE:
|
|
||||||
throw new SimpleException('No file was uploaded');
|
|
||||||
case UPLOAD_ERR_NO_TMP_DIR:
|
|
||||||
throw new SimpleException('Server misconfiguration error: missing temporary folder');
|
|
||||||
case UPLOAD_ERR_CANT_WRITE:
|
|
||||||
throw new SimpleException('Server misconfiguration error: cannot write to disk');
|
|
||||||
case UPLOAD_ERR_EXTENSION:
|
|
||||||
throw new SimpleException('Server misconfiguration error: upload was canceled by an extension');
|
|
||||||
default:
|
|
||||||
throw new SimpleException('Generic file upload error (id: ' . $suppliedFile['error'] . ')');
|
|
||||||
}
|
}
|
||||||
if (!is_uploaded_file($suppliedFile['tmp_name']))
|
|
||||||
throw new SimpleException('Generic file upload error');
|
|
||||||
|
|
||||||
#$mimeType = $suppliedFile['type'];
|
|
||||||
|
/* file contents */
|
||||||
|
$suppliedFile = $_FILES['file'];
|
||||||
|
self::handleUploadErrors($suppliedFile);
|
||||||
|
|
||||||
|
|
||||||
|
/* file details */
|
||||||
$mimeType = mime_content_type($suppliedFile['tmp_name']);
|
$mimeType = mime_content_type($suppliedFile['tmp_name']);
|
||||||
$imageWidth = null;
|
$imageWidth = null;
|
||||||
$imageHeight = null;
|
$imageHeight = null;
|
||||||
|
@ -166,19 +231,8 @@ class PostController
|
||||||
}
|
}
|
||||||
while (file_exists($path));
|
while (file_exists($path));
|
||||||
|
|
||||||
$dbTags = [];
|
|
||||||
foreach ($suppliedTags as $tag)
|
|
||||||
{
|
|
||||||
$dbTag = R::findOne('tag', 'name = ?', [$tag]);
|
|
||||||
if (!$dbTag)
|
|
||||||
{
|
|
||||||
$dbTag = R::dispense('tag');
|
|
||||||
$dbTag->name = $tag;
|
|
||||||
R::store($dbTag);
|
|
||||||
}
|
|
||||||
$dbTags []= $dbTag;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* db storage */
|
||||||
$dbPost = R::dispense('post');
|
$dbPost = R::dispense('post');
|
||||||
$dbPost->type = $postType;
|
$dbPost->type = $postType;
|
||||||
$dbPost->name = $name;
|
$dbPost->name = $name;
|
||||||
|
@ -187,6 +241,7 @@ class PostController
|
||||||
$dbPost->file_size = filesize($suppliedFile['tmp_name']);
|
$dbPost->file_size = filesize($suppliedFile['tmp_name']);
|
||||||
$dbPost->mime_type = $mimeType;
|
$dbPost->mime_type = $mimeType;
|
||||||
$dbPost->safety = $suppliedSafety;
|
$dbPost->safety = $suppliedSafety;
|
||||||
|
$dbPost->hidden = false;
|
||||||
$dbPost->upload_date = time();
|
$dbPost->upload_date = time();
|
||||||
$dbPost->image_width = $imageWidth;
|
$dbPost->image_width = $imageWidth;
|
||||||
$dbPost->image_height = $imageHeight;
|
$dbPost->image_height = $imageHeight;
|
||||||
|
@ -201,6 +256,141 @@ class PostController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route /post/edit/{id}
|
||||||
|
*/
|
||||||
|
public function editAction($id)
|
||||||
|
{
|
||||||
|
$post = self::locatePost($id);
|
||||||
|
R::preload($post, ['uploader' => 'user']);
|
||||||
|
$edited = false;
|
||||||
|
$secondary = $post->uploader->id == $this->context->user->id ? 'own' : 'all';
|
||||||
|
|
||||||
|
|
||||||
|
/* safety */
|
||||||
|
$suppliedSafety = InputHelper::get('safety');
|
||||||
|
if ($suppliedSafety !== null)
|
||||||
|
{
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::EditPostSafety, $secondary);
|
||||||
|
$suppliedSafety = intval($suppliedSafety);
|
||||||
|
if (!in_array($suppliedSafety, PostSafety::getAll()))
|
||||||
|
throw new SimpleException('Invalid safety type "' . $suppliedSafety . '"');
|
||||||
|
$post->safety = $suppliedSafety;
|
||||||
|
$edited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* tags */
|
||||||
|
$suppliedTags = InputHelper::get('tags');
|
||||||
|
if ($suppliedTags !== null)
|
||||||
|
{
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::EditPostTags, $secondary);
|
||||||
|
$currentToken = self::serializeTags($post);
|
||||||
|
if (InputHelper::get('tags-token') != $currentToken)
|
||||||
|
throw new SimpleException('Someone else has changed the tags in the meantime');
|
||||||
|
|
||||||
|
$suppliedTags = preg_split('/[,;\s+]/', $suppliedTags);
|
||||||
|
$suppliedTags = array_filter($suppliedTags);
|
||||||
|
$suppliedTags = array_unique($suppliedTags);
|
||||||
|
foreach ($suppliedTags as $tag)
|
||||||
|
if (!preg_match('/^[a-zA-Z0-9_-]+$/i', $tag))
|
||||||
|
throw new SimpleException('Invalid tag "' . $tag . '"');
|
||||||
|
if (empty($suppliedTags))
|
||||||
|
throw new SimpleException('No tags set');
|
||||||
|
|
||||||
|
$dbTags = [];
|
||||||
|
foreach ($suppliedTags as $tag)
|
||||||
|
{
|
||||||
|
$dbTag = R::findOne('tag', 'name = ?', [$tag]);
|
||||||
|
if (!$dbTag)
|
||||||
|
{
|
||||||
|
$dbTag = R::dispense('tag');
|
||||||
|
$dbTag->name = $tag;
|
||||||
|
R::store($dbTag);
|
||||||
|
}
|
||||||
|
$dbTags []= $dbTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
$post->sharedTag = $dbTags;
|
||||||
|
$edited = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* thumbnail */
|
||||||
|
if (isset($_FILES['thumb']))
|
||||||
|
{
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::EditPostThumb, $secondary);
|
||||||
|
$suppliedFile = $_FILES['thumb'];
|
||||||
|
self::handleUploadErrors($suppliedFile);
|
||||||
|
|
||||||
|
$mimeType = mime_content_type($suppliedFile['tmp_name']);
|
||||||
|
if (!in_array($mimeType, ['image/gif', 'image/png', 'image/jpeg']))
|
||||||
|
throw new SimpleException('Invalid thumbnail type "' . $mimeType . '"');
|
||||||
|
list ($imageWidth, $imageHeight) = getimagesize($suppliedFile['tmp_name']);
|
||||||
|
if ($imageWidth != $this->config->browsing->thumbWidth)
|
||||||
|
throw new SimpleException('Invalid thumbnail width (should be ' . $this->config->browsing->thumbWidth . ')');
|
||||||
|
if ($imageWidth != $this->config->browsing->thumbHeight)
|
||||||
|
throw new SimpleException('Invalid thumbnail width (should be ' . $this->config->browsing->thumbHeight . ')');
|
||||||
|
|
||||||
|
$path = $this->config->main->thumbsPath . DS . $post->name;
|
||||||
|
move_uploaded_file($suppliedFile['tmp_name'], $path);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* db storage */
|
||||||
|
if ($edited)
|
||||||
|
R::store($post);
|
||||||
|
$this->context->transport->success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route /post/hide/{id}
|
||||||
|
*/
|
||||||
|
public function hideAction($id)
|
||||||
|
{
|
||||||
|
$post = self::locatePost($id);
|
||||||
|
$secondary = $post->uploader->id == $this->context->user->id ? 'own' : 'all';
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::HidePost, $secondary);
|
||||||
|
$post->hidden = true;
|
||||||
|
R::store($post);
|
||||||
|
$this->context->transport->success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route /post/unhide/{id}
|
||||||
|
*/
|
||||||
|
public function unhideAction($id)
|
||||||
|
{
|
||||||
|
$post = self::locatePost($id);
|
||||||
|
$secondary = $post->uploader->id == $this->context->user->id ? 'own' : 'all';
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::HidePost, $secondary);
|
||||||
|
$post->hidden = false;
|
||||||
|
R::store($post);
|
||||||
|
$this->context->transport->success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @route /post/delete/{id}
|
||||||
|
*/
|
||||||
|
public function deleteAction($id)
|
||||||
|
{
|
||||||
|
$post = self::locatePost($id);
|
||||||
|
$secondary = $post->uploader->id == $this->context->user->id ? 'own' : 'all';
|
||||||
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::DeletePost, $secondary);
|
||||||
|
//remove stuff from auxiliary tables
|
||||||
|
$post->ownFavoritee = [];
|
||||||
|
$post->sharedTag = [];
|
||||||
|
R::store($post);
|
||||||
|
R::trash($post);
|
||||||
|
$this->context->transport->success = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @route /post/add-fav/{id}
|
* @route /post/add-fav/{id}
|
||||||
* @route /post/fav-add/{id}
|
* @route /post/fav-add/{id}
|
||||||
|
@ -260,12 +450,31 @@ class PostController
|
||||||
$post = self::locatePost($id);
|
$post = self::locatePost($id);
|
||||||
R::preload($post, ['favoritee' => 'user', 'uploader' => 'user', 'tag']);
|
R::preload($post, ['favoritee' => 'user', 'uploader' => 'user', 'tag']);
|
||||||
|
|
||||||
$prevPost = R::findOne('post', 'id < ? ORDER BY id DESC LIMIT 1', [$id]);
|
if ($post->hidden)
|
||||||
$nextPost = R::findOne('post', 'id > ? ORDER BY id ASC LIMIT 1', [$id]);
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, 'hidden');
|
||||||
|
|
||||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost);
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost);
|
||||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, PostSafety::toString($post->safety));
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, PostSafety::toString($post->safety));
|
||||||
|
|
||||||
|
$buildNextPostQuery = function($dbQuery, $id, $next)
|
||||||
|
{
|
||||||
|
$dbQuery->select('id')
|
||||||
|
->from('post')
|
||||||
|
->where($next ? 'id > ?' : 'id < ?')
|
||||||
|
->put($id);
|
||||||
|
if (!PrivilegesHelper::confirm($this->context->user, Privilege::ListPosts, 'hidden'))
|
||||||
|
$dbQuery->andNot('hidden');
|
||||||
|
$dbQuery->orderBy($next ? 'id asc' : 'id desc')
|
||||||
|
->limit(1);
|
||||||
|
};
|
||||||
|
|
||||||
|
$prevPostQuery = R::$f->begin();
|
||||||
|
$buildNextPostQuery($prevPostQuery, $id, false);
|
||||||
|
$prevPost = $prevPostQuery->get('row');
|
||||||
|
|
||||||
|
$nextPostQuery = R::$f->begin();
|
||||||
|
$buildNextPostQuery($nextPostQuery, $id, true);
|
||||||
|
$nextPost = $nextPostQuery->get('row');
|
||||||
|
|
||||||
$favorite = false;
|
$favorite = false;
|
||||||
if ($this->context->loggedIn)
|
if ($this->context->loggedIn)
|
||||||
foreach ($post->ownFavoritee as $fav)
|
foreach ($post->ownFavoritee as $fav)
|
||||||
|
@ -291,8 +500,9 @@ class PostController
|
||||||
$this->context->subTitle = 'showing @' . $post->id;
|
$this->context->subTitle = 'showing @' . $post->id;
|
||||||
$this->context->favorite = $favorite;
|
$this->context->favorite = $favorite;
|
||||||
$this->context->transport->post = $post;
|
$this->context->transport->post = $post;
|
||||||
$this->context->transport->prevPostId = $prevPost ? $prevPost->id : null;
|
$this->context->transport->prevPostId = $prevPost ? $prevPost['id'] : null;
|
||||||
$this->context->transport->nextPostId = $nextPost ? $nextPost->id : null;
|
$this->context->transport->nextPostId = $nextPost ? $nextPost['id'] : null;
|
||||||
|
$this->context->transport->tagsToken = self::serializeTags($post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -309,7 +519,7 @@ class PostController
|
||||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost);
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost);
|
||||||
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, PostSafety::toString($post->safety));
|
PrivilegesHelper::confirmWithException($this->context->user, Privilege::ViewPost, PostSafety::toString($post->safety));
|
||||||
|
|
||||||
$path = $this->config->main->thumbsPath . DS . $post->name . '.png';
|
$path = $this->config->main->thumbsPath . DS . $post->name;
|
||||||
if (!file_exists($path))
|
if (!file_exists($path))
|
||||||
{
|
{
|
||||||
$srcPath = $this->config->main->filesPath . DS . $post->name;
|
$srcPath = $this->config->main->filesPath . DS . $post->name;
|
||||||
|
@ -317,7 +527,7 @@ class PostController
|
||||||
$dstWidth = $this->config->browsing->thumbWidth;
|
$dstWidth = $this->config->browsing->thumbWidth;
|
||||||
$dstHeight = $this->config->browsing->thumbHeight;
|
$dstHeight = $this->config->browsing->thumbHeight;
|
||||||
|
|
||||||
switch($post->mime_type)
|
switch ($post->mime_type)
|
||||||
{
|
{
|
||||||
case 'image/jpeg':
|
case 'image/jpeg':
|
||||||
$srcImage = imagecreatefromjpeg($srcPath);
|
$srcImage = imagecreatefromjpeg($srcPath);
|
||||||
|
@ -389,34 +599,4 @@ class PostController
|
||||||
$this->context->transport->mimeType = $post->mimeType;
|
$this->context->transport->mimeType = $post->mimeType;
|
||||||
$this->context->transport->filePath = $path;
|
$this->context->transport->filePath = $path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @route /favorites
|
|
||||||
* @route /favorites/{page}
|
|
||||||
* @validate page \d*
|
|
||||||
*/
|
|
||||||
public function favoritesAction($page = 1)
|
|
||||||
{
|
|
||||||
$this->listAction('favmin:1', $page);
|
|
||||||
$this->context->viewName = 'post-list';
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function locatePost($key)
|
|
||||||
{
|
|
||||||
if (is_numeric($key))
|
|
||||||
{
|
|
||||||
$post = R::findOne('post', 'id = ?', [$key]);
|
|
||||||
if (!$post)
|
|
||||||
throw new SimpleException('Invalid post ID "' . $key . '"');
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$post = R::findOne('post', 'name = ?', [$key]);
|
|
||||||
if (!$post)
|
|
||||||
throw new SimpleException('Invalid post name "' . $key . '"');
|
|
||||||
}
|
|
||||||
return $post;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,13 @@ class Privilege extends Enum
|
||||||
const ViewPost = 3;
|
const ViewPost = 3;
|
||||||
const RetrievePost = 4;
|
const RetrievePost = 4;
|
||||||
const FavoritePost = 5;
|
const FavoritePost = 5;
|
||||||
const ListUsers = 6;
|
const EditPostSafety = 6;
|
||||||
const ListComments = 7;
|
const EditPostTags = 7;
|
||||||
const ListTags = 8;
|
const EditPostThumb = 8;
|
||||||
|
const HidePost = 9;
|
||||||
|
const DeletePost = 10;
|
||||||
|
|
||||||
|
const ListUsers = 11;
|
||||||
|
const ListComments = 12;
|
||||||
|
const ListTags = 13;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,7 +66,7 @@
|
||||||
<form name="search" action="<?php echo \Chibi\UrlHelper::route('post', 'list') ?>" method="get">
|
<form name="search" action="<?php echo \Chibi\UrlHelper::route('post', 'list') ?>" method="get">
|
||||||
<input type="search" name="query" placeholder="Search…" value="<?php echo isset($this->context->transport->searchQuery) ? $this->context->transport->searchQuery : '' ?>">
|
<input type="search" name="query" placeholder="Search…" value="<?php echo isset($this->context->transport->searchQuery) ? $this->context->transport->searchQuery : '' ?>">
|
||||||
</form>
|
</form>
|
||||||
</i>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="clear"></div>
|
<div class="clear"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -27,7 +27,6 @@
|
||||||
|
|
||||||
<div class="sidebar-unit tags">
|
<div class="sidebar-unit tags">
|
||||||
<h1>tags (<?php echo count($this->context->transport->post->sharedTag) ?>)</h1>
|
<h1>tags (<?php echo count($this->context->transport->post->sharedTag) ?>)</h1>
|
||||||
<!-- todo: edit tags -->
|
|
||||||
<ul>
|
<ul>
|
||||||
<?php foreach ($this->context->transport->post->sharedTag as $tag): ?>
|
<?php foreach ($this->context->transport->post->sharedTag as $tag): ?>
|
||||||
<li>
|
<li>
|
||||||
|
@ -107,7 +106,6 @@
|
||||||
<div class="sidebar-unit options">
|
<div class="sidebar-unit options">
|
||||||
<h1>options</h1>
|
<h1>options</h1>
|
||||||
|
|
||||||
<nav>
|
|
||||||
<ul>
|
<ul>
|
||||||
<?php if (PrivilegesHelper::confirm($this->context->user, Privilege::FavoritePost)): ?>
|
<?php if (PrivilegesHelper::confirm($this->context->user, Privilege::FavoritePost)): ?>
|
||||||
<?php if (!$this->context->favorite): ?>
|
<?php if (!$this->context->favorite): ?>
|
||||||
|
@ -125,39 +123,54 @@
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
|
|
||||||
<!--
|
<?php
|
||||||
<li>
|
$secondary = $this->context->transport->post->uploader->id == $this->context->user->id ? 'own' : 'all';
|
||||||
<a href="#">
|
$editPostPrivileges = [
|
||||||
Edit tags
|
Privilege::EditPostSafety,
|
||||||
</a>
|
Privilege::EditPostTags,
|
||||||
</li>
|
Privilege::EditPostThumb,
|
||||||
|
];
|
||||||
|
$editPostPrivileges = array_fill_keys($editPostPrivileges, false);
|
||||||
|
foreach (array_keys($editPostPrivileges) as $privilege)
|
||||||
|
{
|
||||||
|
if (PrivilegesHelper::confirm($this->context->user, $privilege, $secondary))
|
||||||
|
$editPostPrivileges[$privilege] = true;
|
||||||
|
}
|
||||||
|
$canEditAnything = count(array_filter($editPostPrivileges)) > 0;
|
||||||
|
?>
|
||||||
|
|
||||||
<li>
|
<?php if ($canEditAnything): ?>
|
||||||
|
<li class="edit">
|
||||||
<a href="#">
|
<a href="#">
|
||||||
Change safety
|
Edit
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<li>
|
<?php if (PrivilegesHelper::confirm($this->context->user, Privilege::HidePost, $secondary)): ?>
|
||||||
<a href="#">
|
<?php if ($this->context->transport->post->hidden): ?>
|
||||||
Show on main page
|
<li class="unhide">
|
||||||
|
<a href="<?php echo \Chibi\UrlHelper::route('post', 'unhide', ['id' => $this->context->transport->post->id]) ?>">
|
||||||
|
Unhide
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<?php else: ?>
|
||||||
|
<li class="hide">
|
||||||
|
<a href="<?php echo \Chibi\UrlHelper::route('post', 'hide', ['id' => $this->context->transport->post->id]) ?>">
|
||||||
|
Hide
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php endif ?>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
<li>
|
<?php if (PrivilegesHelper::confirm($this->context->user, Privilege::DeletePost, $secondary)): ?>
|
||||||
<a href="#">
|
<li class="delete">
|
||||||
Hide from main page
|
<a href="<?php echo \Chibi\UrlHelper::route('post', 'delete', ['id' => $this->context->transport->post->id]) ?>" data-confirm-text="Are you sure?" data-redirect-url="<?php echo \Chibi\UrlHelper::route('post', 'list') ?>">
|
||||||
|
Delete
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
<?php endif ?>
|
||||||
<li>
|
|
||||||
<a href="#">
|
|
||||||
Remove
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
-->
|
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
if (!$('.options ul li').length)
|
if (!$('.options ul li').length)
|
||||||
|
@ -174,4 +187,41 @@
|
||||||
<embed width="<?php echo $this->context->transport->post->image_width ?>" height="<?php echo $this->context->transport->post->image_height ?>" type="application/x-shockwave-flash" src="<?php echo \Chibi\UrlHelper::route('post', 'retrieve', ['name' => $this->context->transport->post->name]) ?>"/>
|
<embed width="<?php echo $this->context->transport->post->image_width ?>" height="<?php echo $this->context->transport->post->image_height ?>" type="application/x-shockwave-flash" src="<?php echo \Chibi\UrlHelper::route('post', 'retrieve', ['name' => $this->context->transport->post->name]) ?>"/>
|
||||||
<?php endif ?>
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if ($canEditAnything): ?>
|
||||||
|
<form action="<?php echo \Chibi\UrlHelper::route('post', 'edit', ['id' => $this->context->transport->post->id]) ?>" method="post" enctype="multiplart/form-data" class="edit">
|
||||||
|
<h1>edit post</h1>
|
||||||
|
<?php if ($editPostPrivileges[Privilege::EditPostSafety]): ?>
|
||||||
|
<div class="safety">
|
||||||
|
<label class="left">Safety:</label>
|
||||||
|
<?php foreach (PostSafety::getAll() as $safety): ?>
|
||||||
|
<label>
|
||||||
|
<input type="radio" name="safety" value="<?php echo $safety ?>" <?php if ($this->context->transport->post->safety == $safety) echo 'checked="checked"' ?>/>
|
||||||
|
<?php echo PostSafety::toString($safety) ?>
|
||||||
|
</label>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php if ($editPostPrivileges[Privilege::EditPostTags]): ?>
|
||||||
|
<div class="tags">
|
||||||
|
<label class="left" for="tags">Tags:</label>
|
||||||
|
<input type="text" name="tags" id="tags" placeholder="enter some tags…" value="<?php echo join(',', array_map(function($tag) { return $tag->name; }, $this->context->transport->post->sharedTag)) ?>"/>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" name="tags-token" id="tags-token" value="<?php echo $this->context->transport->tagsToken ?>"/>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<?php if ($editPostPrivileges[Privilege::EditPostThumb]): ?>
|
||||||
|
<div class="thumb">
|
||||||
|
<label class="left" for="thumb">Thumb:</label>
|
||||||
|
<input type="file" name="thumb" id="thumb"/>
|
||||||
|
</div>
|
||||||
|
<?php endif ?>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label class="left"> </label>
|
||||||
|
<button type="submit">Submit</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
<?php endif ?>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -40,6 +40,7 @@ function configFactory()
|
||||||
|
|
||||||
$config = configFactory();
|
$config = configFactory();
|
||||||
R::setup('sqlite:' . $config->main->dbPath);
|
R::setup('sqlite:' . $config->main->dbPath);
|
||||||
|
#R::dependencies(['tag' => ['post'], 'post' => ['user']]);
|
||||||
|
|
||||||
//wire models
|
//wire models
|
||||||
\Chibi\AutoLoader::init([$config->chibi->userCodeDir, __DIR__]);
|
\Chibi\AutoLoader::init([$config->chibi->userCodeDir, __DIR__]);
|
||||||
|
|
Loading…
Reference in a new issue