Moved post content and thumbnail retrieval to API

This commit is contained in:
Marcin Kurczewski 2014-05-03 22:14:00 +02:00
parent 9f4d97aa23
commit 758f5bd134
13 changed files with 209 additions and 120 deletions

View file

@ -89,6 +89,8 @@ $postValidation =
\Chibi\Router::register(['PostController', 'upvotedView'], 'GET', '/upvoted/{page}', $postValidation);
\Chibi\Router::register(['PostController', 'genericView'], 'GET', '/post/{id}', $postValidation);
\Chibi\Router::register(['PostController', 'fileView'], 'GET', '/post/{name}/retrieve', $postValidation);
\Chibi\Router::register(['PostController', 'thumbView'], 'GET', '/post/{name}/thumb', $postValidation);
\Chibi\Router::register(['PostController', 'toggleTagAction'], 'POST', '/post/{id}/toggle-tag/{tag}/{enable}', $postValidation);
\Chibi\Router::register(['PostController', 'flagAction'], 'POST', '/post/{id}/flag', $postValidation);
@ -114,9 +116,6 @@ $commentValidation =
foreach (['GET', 'POST'] as $method)
{
\Chibi\Router::register(['PostController', 'retrieveAction'], $method, '/post/{name}/retrieve', $postValidation);
\Chibi\Router::register(['PostController', 'thumbAction'], $method, '/post/{name}/thumb', $postValidation);
$tagValidation =
[
'page' => '\d*',

View file

@ -40,12 +40,4 @@ class Api
});
return $statuses;
}
public static function serializeFile($filePath, $fileName)
{
$x = new StdClass;
$x->filePath = $filePath;
$x->fileName = $fileName;
return $x;
}
}

17
src/ApiFileInput.php Normal file
View file

@ -0,0 +1,17 @@
<?php
/**
* Used for serializing files passed in POST requests to job arguments
*/
class ApiFileInput
{
public $filePath;
public $fileName;
public function __construct($filePath, $fileName)
{
//todo: move_uploaded_file here
//concerns post thumbs and post content
$this->filePath = $filePath;
$this->fileName = $fileName;
}
}

17
src/ApiFileOutput.php Normal file
View file

@ -0,0 +1,17 @@
<?php
/**
* Used for serializing files output from jobs
*/
class ApiFileOutput
{
public $fileContent;
public $fileName;
public function __construct($filePath, $fileName)
{
$this->fileContent = file_get_contents($filePath);
$this->fileName = $fileName;
$this->lastModified = filemtime($filePath);
$this->mimeType = mime_content_type($filePath);
}
}

View file

@ -107,7 +107,7 @@ class PostController
$file = $_FILES['file'];
TransferHelper::handleUploadErrors($file);
$jobArgs[EditPostContentJob::POST_CONTENT] = Api::serializeFile(
$jobArgs[EditPostContentJob::POST_CONTENT] = new ApiFileInput(
$file['tmp_name'],
$file['name']);
}
@ -147,7 +147,7 @@ class PostController
$file = $_FILES['file'];
TransferHelper::handleUploadErrors($file);
$jobArgs[EditPostContentJob::POST_CONTENT] = Api::serializeFile(
$jobArgs[EditPostContentJob::POST_CONTENT] = new ApiFileInput(
$file['tmp_name'],
$file['name']);
}
@ -157,7 +157,7 @@ class PostController
$file = $_FILES['thumb'];
TransferHelper::handleUploadErrors($file);
$jobArgs[EditPostThumbJob::THUMB_CONTENT] = Api::serializeFile(
$jobArgs[EditPostThumbJob::THUMB_CONTENT] = new ApiFileInput(
$file['tmp_name'],
$file['name']);
}
@ -256,67 +256,34 @@ class PostController
$context->transport->nextPostId = $nextPostId ? $nextPostId : null;
}
public function thumbAction($name, $width = null, $height = null)
public function fileView($name)
{
$ret = Api::run(new GetPostContentJob(), [GetPostContentJob::POST_NAME => $name]);
$context = getContext();
$path = PostModel::getThumbCustomPath($name, $width, $height);
if (!file_exists($path))
{
$path = PostModel::getThumbDefaultPath($name, $width, $height);
if (!file_exists($path))
{
$post = PostModel::findByIdOrName($name);
Access::assert(Privilege::ListPosts);
Access::assert(Privilege::ListPosts, PostSafety::toString($post->safety));
$post->generateThumb($width, $height);
if (!file_exists($path))
{
$path = getConfig()->main->mediaPath . DS . 'img' . DS . 'thumb.jpg';
$path = TextHelper::absolutePath($path);
}
}
}
if (!is_readable($path))
throw new SimpleException('Thumbnail file is not readable');
$context->layoutName = 'layout-file';
$context->transport->cacheDaysToLive = 365;
$context->transport->mimeType = 'image/jpeg';
$context->transport->fileHash = 'thumb' . md5($name . filemtime($path));
$context->transport->filePath = $path;
}
public function retrieveAction($name)
{
$post = PostModel::findByName($name, true);
$config = getConfig();
$context = getContext();
Access::assert(Privilege::RetrievePost);
Access::assert(Privilege::RetrievePost, PostSafety::toString($post->safety));
$path = $config->main->filesPath . DS . $post->name;
$path = TextHelper::absolutePath($path);
if (!file_exists($path))
throw new SimpleNotFoundException('Post file does not exist');
if (!is_readable($path))
throw new SimpleException('Post file is not readable');
$fn = sprintf('%s_%s_%s.%s',
$config->main->title,
$post->id,
join(',', array_map(function($tag) { return $tag->name; }, $post->getTags())),
TextHelper::resolveMimeType($post->mimeType) ?: 'dat');
$fn = preg_replace('/[[:^print:]]/', '', $fn);
$ttl = 60 * 60 * 24 * 14;
$context->layoutName = 'layout-file';
$context->transport->cacheDaysToLive = 14;
$context->transport->customFileName = $fn;
$context->transport->mimeType = $post->mimeType;
$context->transport->fileHash = 'post' . $post->fileHash;
$context->transport->filePath = $path;
$context->transport->customFileName = $ret->fileName;
$context->transport->mimeType = $ret->mimeType;
$context->transport->fileHash = 'post' . md5(substr($ret->fileContent, 0, 4096));
$context->transport->fileContent = $ret->fileContent;
$context->transport->lastModified = $ret->lastModified;
$context->layoutName = 'layout-file';
}
public function thumbView($name, $width = null, $height = null)
{
$ret = Api::run(new GetPostThumbJob(), [
GetPostThumbJob::POST_NAME => $name,
GetPostThumbJob::WIDTH => $width,
GetPostThumbJob::HEIGHT => $height]);
$context = getContext();
$context->transport->cacheDaysToLive = 365;
$context->transport->customFileName = $ret->fileName;
$context->transport->mimeType = 'image/jpeg';
$context->transport->fileHash = 'thumb' . md5(substr($ret->fileContent, 0, 4096));
$context->transport->fileContent = $ret->fileContent;
$context->transport->lastModified = $ret->lastModified;
$context->layoutName = 'layout-file';
}
}

View file

@ -3,6 +3,7 @@ abstract class AbstractJob
{
const COMMENT_ID = 'comment-id';
const POST_ID = 'post-id';
const POST_NAME = 'post-name';
const TAG_NAME = 'tag-name';
const TAG_NAMES = 'tags';
const TEXT = 'text';

View file

@ -0,0 +1,48 @@
<?php
class GetPostContentJob extends AbstractJob
{
public function execute()
{
$post = PostModel::findByName($this->getArgument(self::POST_NAME));
//todo: refactor this so that requiresPrivilege can accept multiple privileges
if ($post->hidden)
Access::assert(Privilege::RetrievePost, 'hidden');
Access::assert(Privilege::RetrievePost);
Access::assert(Privilege::RetrievePost, PostSafety::toString($post->safety));
$config = getConfig();
$path = $config->main->filesPath . DS . $post->name;
$path = TextHelper::absolutePath($path);
if (!file_exists($path))
throw new SimpleNotFoundException('Post file does not exist');
if (!is_readable($path))
throw new SimpleException('Post file is not readable');
$fileName = sprintf('%s_%s_%s.%s',
$config->main->title,
$post->id,
join(',', array_map(function($tag) { return $tag->name; }, $post->getTags())),
TextHelper::resolveMimeType($post->mimeType) ?: 'dat');
$fileName = preg_replace('/[[:^print:]]/', '', $fileName);
return new ApiFileOutput($path, $fileName);
}
public function requiresPrivilege()
{
//temporarily enforced in execute
return false;
}
public function requiresAuthentication()
{
return false;
}
public function requiresConfirmedEmail()
{
return false;
}
}

View file

@ -6,10 +6,10 @@ class GetPostJob extends AbstractPostEditJob
$post = $this->post;
//todo: refactor this so that requiresPrivilege can accept multiple privileges
if ($this->post->hidden)
if ($post->hidden)
Access::assert(Privilege::ViewPost, 'hidden');
Access::assert(Privilege::ViewPost);
Access::assert(Privilege::ViewPost, PostSafety::toString($this->post->safety));
Access::assert(Privilege::ViewPost, PostSafety::toString($post->safety));
CommentModel::preloadCommenters($post->getComments());

View file

@ -0,0 +1,57 @@
<?php
class GetPostThumbJob extends AbstractJob
{
const WIDTH = 'width';
const HEIGHT = 'height';
public function execute()
{
$name = $this->getArgument(self::POST_NAME);
$width = $this->hasArgument(self::WIDTH) ? $this->getArgument(self::WIDTH) : null;
$height = $this->hasArgument(self::HEIGHT) ? $this->getArgument(self::HEIGHT) : null;
$path = PostModel::getThumbCustomPath($name, $width, $height);
if (!file_exists($path))
{
$path = PostModel::getThumbDefaultPath($name, $width, $height);
if (!file_exists($path))
{
$post = PostModel::findByIdOrName($name);
if ($post->hidden)
Access::assert(Privilege::ListPosts, 'hidden');
Access::assert(Privilege::ListPosts);
Access::assert(Privilege::ListPosts, PostSafety::toString($post->safety));
$post->generateThumb($width, $height);
if (!file_exists($path))
{
$path = getConfig()->main->mediaPath . DS . 'img' . DS . 'thumb.jpg';
$path = TextHelper::absolutePath($path);
}
}
}
if (!is_readable($path))
throw new SimpleException('Thumbnail file is not readable');
return new ApiFileOutput($path, 'thumbnail.jpg');
}
public function requiresPrivilege()
{
//manually enforced in execute when post is retrieved
return false;
}
public function requiresAuthentication()
{
return false;
}
public function requiresConfirmedEmail()
{
return false;
}
}

View file

@ -1,12 +1,5 @@
<?php
if (!empty($this->context->transport->errorMessage))
{
\Chibi\Util\Headers::set('Content-Type', 'text/plain; charset=utf-8');
echo $this->context->transport->errorMessage;
}
else
{
$lastModified = filemtime($this->context->transport->filePath);
$lastModified = $this->context->transport->lastModified;
$eTag = $this->context->transport->fileHash;
$ttl = $this->context->transport->cacheDaysToLive * 24 * 3600;
@ -35,13 +28,11 @@ else
'Content-Type',
$this->context->transport->mimeType);
if (strtotime($ifModifiedSince) == $lastModified or $eTagHeader == $eTag)
{
header('HTTP/1.1 304 Not Modified');
\Chibi\Util\Headers::setCode('304');
exit;
}
readfile($this->context->transport->filePath);
echo $this->context->transport->fileContent;
flush();
}

View file

@ -1,6 +1,6 @@
<?php
Assets::setPageThumb(\Chibi\Router::linkTo(
['PostController', 'thumbAction'],
['PostController', 'thumbView'],
['name' => $this->context->transport->post->name]));
$post = $this->context->transport->post;
?>
@ -13,7 +13,7 @@ $post = $this->context->transport->post;
<img alt="<?= $post->name ?>"
src="<?= \Chibi\Router::linkTo(
['PostController', 'retrieveAction'],
['PostController', 'fileView'],
['name' => $post->name]) ?>"/>
<?php if (!empty($this->context->imageLink)): ?>
@ -27,12 +27,12 @@ $post = $this->context->transport->post;
width="<?= $post->imageWidth ?>"
height="<?= $post->imageHeight ?>"
data="<?= \Chibi\Router::linkTo(
['PostController', 'retrieveAction'],
['PostController', 'fileView'],
['name' => $post->name]) ?>">
<param name="wmode" value="opaque"/>
<param name="movie" value="<?= \Chibi\Router::linkTo(
['PostController', 'retrieveAction'],
['PostController', 'fileView'],
['name' => $post->name]) ?>"/>
</object>
@ -52,7 +52,7 @@ $post = $this->context->transport->post;
<source
type="<?= $post->mimeType ?>"
src="<?= \Chibi\Router::linkTo(
['PostController', 'retrieveAction'],
['PostController', 'fileView'],
['name' => $post->name]) ?>">
Your browser doesn't support HTML5 &lt;video&gt; tag.

View file

@ -48,7 +48,7 @@ if ($masstag)
<img
class="thumb"
src="<?= \Chibi\Router::linkTo(['PostController', 'thumbAction'], ['name' => $this->context->post->name]) ?>"
src="<?= \Chibi\Router::linkTo(['PostController', 'thumbView'], ['name' => $this->context->post->name]) ?>"
alt="@<?= $this->context->post->id ?>"/>
<?php

View file

@ -187,7 +187,7 @@ $canEditAnything = count(array_filter($editPostPrivileges)) > 0;
<?php if ($this->context->transport->post->type != PostType::Youtube): ?>
<div class="hl-option">
<a title="Download" href="<?= \Chibi\Router::linkTo(
['PostController', 'retrieveAction'],
['PostController', 'fileView'],
['name' => $this->context->transport->post->name]) ?>">
<i class="icon-dl"></i>
<span>