Moved post upload to API
This commit is contained in:
parent
f383a5ed21
commit
6ae4cea8bb
17 changed files with 433 additions and 47 deletions
|
@ -70,6 +70,9 @@ $postValidation =
|
|||
'score' => '-1|0|1',
|
||||
];
|
||||
|
||||
\Chibi\Router::register(['PostController', 'uploadView'], 'GET', '/posts/upload', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'uploadAction'], 'POST', '/posts/upload', $postValidation);
|
||||
|
||||
\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{query}', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'listView'], 'GET', '/{source}/{query}/{page}', $postValidation);
|
||||
|
@ -92,7 +95,6 @@ $postValidation =
|
|||
|
||||
foreach (['GET', 'POST'] as $method)
|
||||
{
|
||||
\Chibi\Router::register(['PostController', 'uploadAction'], $method, '/posts/upload', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'viewAction'], $method, '/post/{id}', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'retrieveAction'], $method, '/post/{name}/retrieve', $postValidation);
|
||||
\Chibi\Router::register(['PostController', 'thumbAction'], $method, '/post/{name}/thumb', $postValidation);
|
||||
|
|
|
@ -166,6 +166,7 @@ $(function()
|
|||
{
|
||||
handleInputs(files, function(postDom, file)
|
||||
{
|
||||
postDom.data('url', '');
|
||||
postDom.data('file', file);
|
||||
$('.file-name strong', postDom).text(file.name);
|
||||
|
||||
|
@ -198,6 +199,7 @@ $(function()
|
|||
handleInputs(urls, function(postDom, url)
|
||||
{
|
||||
postDom.data('url', url);
|
||||
postDom.data('file', '');
|
||||
postDom.find('[name=source]').val(url);
|
||||
if (matches = url.match(/watch.*?=([a-zA-Z0-9_-]+)/))
|
||||
{
|
||||
|
|
|
@ -40,4 +40,12 @@ class Api
|
|||
});
|
||||
return $statuses;
|
||||
}
|
||||
|
||||
public static function serializeFile($filePath, $fileName)
|
||||
{
|
||||
$x = new StdClass;
|
||||
$x->filePath = $filePath;
|
||||
$x->fileName = $fileName;
|
||||
return $x;
|
||||
}
|
||||
}
|
||||
|
|
8
src/ApiMissingArgumentException.php
Normal file
8
src/ApiMissingArgumentException.php
Normal file
|
@ -0,0 +1,8 @@
|
|||
<?php
|
||||
class ApiMissingArgumentException extends SimpleException
|
||||
{
|
||||
public function __construct($argumentName)
|
||||
{
|
||||
parent::__construct('Expected argument "' . $argumentName . '" was not specified');
|
||||
}
|
||||
}
|
|
@ -84,54 +84,35 @@ class PostController
|
|||
]);
|
||||
}
|
||||
|
||||
public function uploadView()
|
||||
{
|
||||
}
|
||||
|
||||
public function uploadAction()
|
||||
{
|
||||
$context = getContext();
|
||||
Access::assert(Privilege::UploadPost);
|
||||
if (getConfig()->registration->needEmailForUploading)
|
||||
Access::assertEmailConfirmation();
|
||||
$jobArgs =
|
||||
[
|
||||
AddPostJob::ANONYMOUS => InputHelper::get('anonymous'),
|
||||
EditPostSafetyJob::SAFETY => InputHelper::get('safety'),
|
||||
EditPostTagsJob::TAG_NAMES => InputHelper::get('tags'),
|
||||
EditPostSourceJob::SOURCE => InputHelper::get('source'),
|
||||
];
|
||||
|
||||
if (!InputHelper::get('submit'))
|
||||
return;
|
||||
|
||||
\Chibi\Database::transaction(function() use ($context)
|
||||
if (!empty(InputHelper::get('url')))
|
||||
{
|
||||
$post = PostModel::spawn();
|
||||
LogHelper::bufferChanges();
|
||||
$jobArgs[EditPostUrlJob::CONTENT_URL] = InputHelper::get('url');
|
||||
}
|
||||
elseif (!empty($_FILES['file']['name']))
|
||||
{
|
||||
$file = $_FILES['file'];
|
||||
TransferHelper::handleUploadErrors($file);
|
||||
|
||||
//basic stuff
|
||||
$anonymous = InputHelper::get('anonymous');
|
||||
if (Auth::isLoggedIn() and !$anonymous)
|
||||
$post->setUploader(Auth::getCurrentUser());
|
||||
$jobArgs[EditPostContentJob::POST_CONTENT] = Api::serializeFile(
|
||||
$file['tmp_name'],
|
||||
$file['name']);
|
||||
}
|
||||
|
||||
//store the post to get the ID in the logs
|
||||
PostModel::forgeId($post);
|
||||
|
||||
//do the edits
|
||||
$this->doEdit($post, true);
|
||||
|
||||
//this basically means that user didn't specify file nor url
|
||||
if (empty($post->type))
|
||||
throw new SimpleException('No post type detected; upload faled');
|
||||
|
||||
//clean edit log
|
||||
LogHelper::setBuffer([]);
|
||||
|
||||
//log
|
||||
$fmt = ($anonymous and !getConfig()->misc->logAnonymousUploads)
|
||||
? '{anon}'
|
||||
: '{user}';
|
||||
$fmt .= ' added {post} (tags: {tags}, safety: {safety}, source: {source})';
|
||||
LogHelper::log($fmt, [
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'tags' => TextHelper::reprTags($post->getTags()),
|
||||
'safety' => PostSafety::toString($post->safety),
|
||||
'source' => $post->source]);
|
||||
|
||||
//finish
|
||||
LogHelper::flush();
|
||||
PostModel::save($post);
|
||||
});
|
||||
Api::run(new AddPostJob(), $jobArgs);
|
||||
}
|
||||
|
||||
public function editAction($id)
|
||||
|
|
|
@ -4,6 +4,7 @@ abstract class AbstractJob
|
|||
const COMMENT_ID = 'comment-id';
|
||||
const POST_ID = 'post-id';
|
||||
const TAG_NAME = 'tag-name';
|
||||
const TAG_NAMES = 'tags';
|
||||
const TEXT = 'text';
|
||||
const PAGE_NUMBER = 'page-number';
|
||||
const QUERY = 'query';
|
||||
|
@ -24,12 +25,22 @@ abstract class AbstractJob
|
|||
|
||||
public function getArgument($key)
|
||||
{
|
||||
if (!isset($this->arguments[$key]))
|
||||
throw new SimpleException('Expected argument "' . $key . '" was not specified');
|
||||
if (!$this->hasArgument($key))
|
||||
throw new ApiMissingArgumentException($key);
|
||||
|
||||
return $this->arguments[$key];
|
||||
}
|
||||
|
||||
public function getArguments()
|
||||
{
|
||||
return $this->arguments;
|
||||
}
|
||||
|
||||
public function hasArgument($key)
|
||||
{
|
||||
return isset($this->arguments[$key]);
|
||||
}
|
||||
|
||||
public function setArguments($arguments)
|
||||
{
|
||||
$this->arguments = $arguments;
|
||||
|
|
89
src/Jobs/AddPostJob.php
Normal file
89
src/Jobs/AddPostJob.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
class AddPostJob extends AbstractJob
|
||||
{
|
||||
const ANONYMOUS = 'anonymous';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$post = PostModel::spawn();
|
||||
LogHelper::bufferChanges();
|
||||
|
||||
//basic stuff
|
||||
$anonymous = $this->getArgument(self::ANONYMOUS);
|
||||
if (Auth::isLoggedIn() and !$anonymous)
|
||||
$post->setUploader(Auth::getCurrentUser());
|
||||
|
||||
//store the post to get the ID in the logs
|
||||
PostModel::forgeId($post);
|
||||
|
||||
//do the edits
|
||||
//warning: each handler runs uses the same privileges as post editing
|
||||
$subJobs =
|
||||
[
|
||||
new EditPostSafetyJob(),
|
||||
new EditPostTagsJob(),
|
||||
new EditPostSourceJob(),
|
||||
new EditPostRelationsJob(),
|
||||
new EditPostContentJob(),
|
||||
new EditPostUrlJob(),
|
||||
];
|
||||
|
||||
foreach ($subJobs as $subJob)
|
||||
{
|
||||
$args = $this->getArguments();
|
||||
$args[self::POST_ID] = $post->id;
|
||||
try
|
||||
{
|
||||
Api::run($subJob, $args);
|
||||
}
|
||||
catch (ApiMissingArgumentException $e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//load the post after edits
|
||||
$post = PostModel::findById($post->id);
|
||||
|
||||
// basically means that user didn't specify file nor url
|
||||
//todo:
|
||||
//- move this to PostEntity::isValid()
|
||||
//- create IValidatable interface
|
||||
//- enforce entity validity upon calling save() in models
|
||||
if (empty($post->type))
|
||||
throw new SimpleException('No post type detected; upload faled');
|
||||
|
||||
//clean edit log
|
||||
LogHelper::setBuffer([]);
|
||||
|
||||
//log
|
||||
LogHelper::log('{user} added {post} (tags: {tags}, safety: {safety}, source: {source})', [
|
||||
'user' => ($anonymous and !getConfig()->misc->logAnonymousUploads)
|
||||
? TextHelper::reprUser(UserModel::getAnonymousName())
|
||||
: TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'tags' => TextHelper::reprTags($post->getTags()),
|
||||
'safety' => PostSafety::toString($post->safety),
|
||||
'source' => $post->source]);
|
||||
|
||||
//finish
|
||||
LogHelper::flush();
|
||||
PostModel::save($post);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return Privilege::UploadPost;
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return getConfig()->registration->needEmailForUploading;
|
||||
}
|
||||
}
|
38
src/Jobs/EditPostContentJob.php
Normal file
38
src/Jobs/EditPostContentJob.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
class EditPostContentJob extends AbstractPostEditJob
|
||||
{
|
||||
const CONTENT = 'content';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$file = $this->getArgument(self::CONTENT);
|
||||
|
||||
$this->post->setContentFromPath($file->filePath, $file->fileName);
|
||||
|
||||
PostModel::save($this->post);
|
||||
LogHelper::log('{user} changed contents of {post}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($this->post)]);
|
||||
|
||||
return $this->post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::EditPostFile,
|
||||
Access::getIdentity($this->post->getUploader())
|
||||
];
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
54
src/Jobs/EditPostRelationsJob.php
Normal file
54
src/Jobs/EditPostRelationsJob.php
Normal file
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
class EditPostRelationsJob extends AbstractPostEditJob
|
||||
{
|
||||
const RELATED_POST_IDS = 'related-post-ids';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$post = $this->post;
|
||||
$relations = $this->getArgument(self::RELATED_POST_IDS);
|
||||
|
||||
$oldRelatedIds = array_map(function($post) { return $post->id; }, $post->getRelations());
|
||||
$post->setRelationsFromText($relations);
|
||||
$newRelatedIds = array_map(function($post) { return $post->id; }, $post->getRelations());
|
||||
|
||||
PostModel::save($post);
|
||||
|
||||
foreach (array_diff($oldRelatedIds, $newRelatedIds) as $post2id)
|
||||
{
|
||||
LogHelper::log('{user} removed relation between {post} and {post2}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'post2' => TextHelper::reprPost($post2id)]);
|
||||
}
|
||||
|
||||
foreach (array_diff($newRelatedIds, $oldRelatedIds) as $post2id)
|
||||
{
|
||||
LogHelper::log('{user} added relation between {post} and {post2}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'post2' => TextHelper::reprPost($post2id)]);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::EditPostRelations,
|
||||
Access::getIdentity($this->post->getUploader())
|
||||
];
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
45
src/Jobs/EditPostSafetyJob.php
Normal file
45
src/Jobs/EditPostSafetyJob.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
class EditPostSafetyJob extends AbstractPostEditJob
|
||||
{
|
||||
const SAFETY = 'safety';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$post = $this->post;
|
||||
$newSafety = $this->getArgument(self::SAFETY);
|
||||
|
||||
$oldSafety = $post->safety;
|
||||
$post->setSafety($newSafety);
|
||||
|
||||
PostModel::save($post);
|
||||
|
||||
if ($oldSafety != $newSafety)
|
||||
{
|
||||
LogHelper::log('{user} changed safety of {post} to {safety}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'safety' => PostSafety::toString($post->safety)]);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::EditPostSafety,
|
||||
Access::getIdentity($this->post->getUploader())
|
||||
];
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
45
src/Jobs/EditPostSourceJob.php
Normal file
45
src/Jobs/EditPostSourceJob.php
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
class EditPostSourceJob extends AbstractPostEditJob
|
||||
{
|
||||
const SOURCE = 'source';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$post = $this->post;
|
||||
$newSource = $this->getArgument(self::SOURCE);
|
||||
|
||||
$oldSource = $post->source;
|
||||
$post->setSource($newSource);
|
||||
|
||||
PostModel::save($post);
|
||||
|
||||
if ($oldSource != $newSource)
|
||||
{
|
||||
LogHelper::log('{user} changed source of {post} to {source}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'source' => $post->source]);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::EditPostSource,
|
||||
Access::getIdentity($this->post->getUploader())
|
||||
];
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
52
src/Jobs/EditPostTagsJob.php
Normal file
52
src/Jobs/EditPostTagsJob.php
Normal file
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
class EditPostTagsJob extends AbstractPostEditJob
|
||||
{
|
||||
public function execute()
|
||||
{
|
||||
$post = $this->post;
|
||||
$tags = $this->getArgument(self::TAG_NAMES);
|
||||
|
||||
$oldTags = array_map(function($tag) { return $tag->name; }, $post->getTags());
|
||||
$post->setTagsFromText($tags);
|
||||
$newTags = array_map(function($tag) { return $tag->name; }, $post->getTags());
|
||||
|
||||
PostModel::save($post);
|
||||
|
||||
foreach (array_diff($oldTags, $newTags) as $tag)
|
||||
{
|
||||
LogHelper::log('{user} untagged {post} with {tag}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'tag' => TextHelper::reprTag($tag)]);
|
||||
}
|
||||
|
||||
foreach (array_diff($newTags, $oldTags) as $tag)
|
||||
{
|
||||
LogHelper::log('{user} tagged {post} with {tag}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post),
|
||||
'tag' => TextHelper::reprTag($tag)]);
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::EditPostTags,
|
||||
Access::getIdentity($this->post->getUploader())
|
||||
];
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
40
src/Jobs/EditPostUrlJob.php
Normal file
40
src/Jobs/EditPostUrlJob.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
class EditPostUrlJob extends AbstractPostEditJob
|
||||
{
|
||||
const CONTENT_URL = 'url';
|
||||
|
||||
public function execute()
|
||||
{
|
||||
$post = $this->post;
|
||||
$url = $this->getArgument(self::CONTENT_URL);
|
||||
|
||||
$post->setContentFromUrl($url);
|
||||
|
||||
PostModel::save($post);
|
||||
|
||||
LogHelper::log('{user} changed contents of {post}', [
|
||||
'user' => TextHelper::reprUser(Auth::getCurrentUser()),
|
||||
'post' => TextHelper::reprPost($post)]);
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
public function requiresPrivilege()
|
||||
{
|
||||
return
|
||||
[
|
||||
Privilege::EditPostFile,
|
||||
Access::getIdentity($this->post->getUploader())
|
||||
];
|
||||
}
|
||||
|
||||
public function requiresAuthentication()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function requiresConfirmedEmail()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -120,6 +120,14 @@ abstract class AbstractCrudModel implements IModel
|
|||
{
|
||||
$stmt = new Sql\InsertStatement();
|
||||
$stmt->setTable($table);
|
||||
foreach ($entity as $key => $val)
|
||||
{
|
||||
$key = TextCaseConverter::convert($key,
|
||||
TextCaseConverter::LOWER_CAMEL_CASE,
|
||||
TextCaseConverter::SNAKE_CASE);
|
||||
|
||||
$stmt->setColumn($key, new Sql\Binding($val));
|
||||
}
|
||||
Database::exec($stmt);
|
||||
$entity->id = Database::lastInsertId();
|
||||
}
|
||||
|
|
|
@ -19,6 +19,10 @@ class PostModel extends AbstractCrudModel
|
|||
public static function spawn()
|
||||
{
|
||||
$post = new PostEntity;
|
||||
$post->score = 0;
|
||||
$post->favCount = 0;
|
||||
$post->commentCount = 0;
|
||||
$post->safety = PostSafety::Safe;
|
||||
$post->hidden = false;
|
||||
$post->uploadDate = time();
|
||||
do
|
||||
|
|
|
@ -30,7 +30,6 @@ class TokenModel extends AbstractCrudModel
|
|||
$stmt->setColumn($key, new Sql\Binding($val));
|
||||
|
||||
Database::exec($stmt);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
{
|
||||
$registerNavItem(
|
||||
'Upload',
|
||||
\Chibi\Router::linkTo(['PostController', 'uploadAction']),
|
||||
\Chibi\Router::linkTo(['PostController', 'uploadView']),
|
||||
$activeController == 'post' and $activeAction == 'upload');
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue