2014-09-15 11:38:24 +02:00
|
|
|
<?php
|
|
|
|
namespace Szurubooru\Services;
|
|
|
|
|
|
|
|
class PostService
|
|
|
|
{
|
|
|
|
private $config;
|
|
|
|
private $validator;
|
|
|
|
private $transactionManager;
|
|
|
|
private $postDao;
|
2014-09-24 23:24:51 +02:00
|
|
|
private $globalParamDao;
|
2014-09-15 11:38:24 +02:00
|
|
|
private $timeService;
|
|
|
|
private $authService;
|
2014-09-20 12:45:56 +02:00
|
|
|
private $fileService;
|
2014-09-26 20:41:28 +02:00
|
|
|
private $historyService;
|
2014-09-20 18:30:48 +02:00
|
|
|
private $imageManipulator;
|
2014-09-15 11:38:24 +02:00
|
|
|
|
|
|
|
public function __construct(
|
|
|
|
\Szurubooru\Config $config,
|
|
|
|
\Szurubooru\Validator $validator,
|
|
|
|
\Szurubooru\Dao\TransactionManager $transactionManager,
|
|
|
|
\Szurubooru\Dao\PostDao $postDao,
|
2014-09-24 23:24:51 +02:00
|
|
|
\Szurubooru\Dao\GlobalParamDao $globalParamDao,
|
2014-09-15 11:38:24 +02:00
|
|
|
\Szurubooru\Services\AuthService $authService,
|
|
|
|
\Szurubooru\Services\TimeService $timeService,
|
2014-09-20 18:30:48 +02:00
|
|
|
\Szurubooru\Services\FileService $fileService,
|
2014-09-26 20:41:28 +02:00
|
|
|
\Szurubooru\Services\HistoryService $historyService,
|
2014-09-20 18:30:48 +02:00
|
|
|
\Szurubooru\Services\ImageManipulation\ImageManipulator $imageManipulator)
|
2014-09-15 11:38:24 +02:00
|
|
|
{
|
|
|
|
$this->config = $config;
|
|
|
|
$this->validator = $validator;
|
|
|
|
$this->transactionManager = $transactionManager;
|
|
|
|
$this->postDao = $postDao;
|
2014-09-24 23:24:51 +02:00
|
|
|
$this->globalParamDao = $globalParamDao;
|
2014-09-15 11:38:24 +02:00
|
|
|
$this->timeService = $timeService;
|
|
|
|
$this->authService = $authService;
|
2014-09-20 12:45:56 +02:00
|
|
|
$this->fileService = $fileService;
|
2014-09-26 20:41:28 +02:00
|
|
|
$this->historyService = $historyService;
|
2014-09-20 18:30:48 +02:00
|
|
|
$this->imageManipulator = $imageManipulator;
|
2014-09-15 11:38:24 +02:00
|
|
|
}
|
|
|
|
|
2014-09-18 17:39:51 +02:00
|
|
|
public function getByNameOrId($postNameOrId)
|
|
|
|
{
|
|
|
|
$transactionFunc = function() use ($postNameOrId)
|
|
|
|
{
|
|
|
|
$post = $this->postDao->findByName($postNameOrId);
|
|
|
|
if (!$post)
|
|
|
|
$post = $this->postDao->findById($postNameOrId);
|
|
|
|
if (!$post)
|
2014-09-21 18:30:29 +02:00
|
|
|
throw new \InvalidArgumentException('Post with name "' . $postNameOrId . '" was not found.');
|
2014-09-18 17:39:51 +02:00
|
|
|
return $post;
|
|
|
|
};
|
|
|
|
return $this->transactionManager->rollback($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-17 12:59:33 +02:00
|
|
|
public function getByName($postName)
|
|
|
|
{
|
|
|
|
$transactionFunc = function() use ($postName)
|
|
|
|
{
|
|
|
|
$post = $this->postDao->findByName($postName);
|
|
|
|
if (!$post)
|
|
|
|
throw new \InvalidArgumentException('Post with name "' . $postName . '" was not found.');
|
|
|
|
return $post;
|
|
|
|
};
|
|
|
|
return $this->transactionManager->rollback($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-26 19:14:34 +02:00
|
|
|
public function getFiltered(\Szurubooru\SearchServices\Filters\PostFilter $filter)
|
2014-09-17 18:34:57 +02:00
|
|
|
{
|
2014-09-26 19:14:34 +02:00
|
|
|
$transactionFunc = function() use ($filter)
|
2014-09-17 18:34:57 +02:00
|
|
|
{
|
2014-09-26 19:14:34 +02:00
|
|
|
return $this->postDao->findFiltered($filter);
|
2014-09-17 18:34:57 +02:00
|
|
|
};
|
|
|
|
return $this->transactionManager->rollback($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-24 23:24:51 +02:00
|
|
|
public function getFeatured()
|
|
|
|
{
|
|
|
|
$transactionFunc = function()
|
|
|
|
{
|
|
|
|
$globalParam = $this->globalParamDao->findByKey(\Szurubooru\Entities\GlobalParam::KEY_FEATURED_POST);
|
|
|
|
if (!$globalParam)
|
|
|
|
return null;
|
|
|
|
return $this->getByNameOrId($globalParam->getValue());
|
|
|
|
};
|
|
|
|
return $this->transactionManager->rollback($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-26 20:41:28 +02:00
|
|
|
public function getHistory(\Szurubooru\Entities\Post $post)
|
|
|
|
{
|
|
|
|
$transactionFunc = function() use ($post)
|
|
|
|
{
|
|
|
|
$filter = new \Szurubooru\SearchServices\Filters\SnapshotFilter();
|
|
|
|
|
2014-09-27 10:59:37 +02:00
|
|
|
$requirement = new \Szurubooru\SearchServices\Requirements\Requirement();
|
2014-09-26 20:41:28 +02:00
|
|
|
$requirement->setType(\Szurubooru\SearchServices\Filters\SnapshotFilter::REQUIREMENT_PRIMARY_KEY);
|
2014-09-27 10:59:37 +02:00
|
|
|
$requirement->setValue(new \Szurubooru\SearchServices\Requirements\RequirementSingleValue($post->getId()));
|
2014-09-26 20:41:28 +02:00
|
|
|
$filter->addRequirement($requirement);
|
|
|
|
|
2014-09-27 10:59:37 +02:00
|
|
|
$requirement = new \Szurubooru\SearchServices\Requirements\Requirement();
|
2014-09-26 20:41:28 +02:00
|
|
|
$requirement->setType(\Szurubooru\SearchServices\Filters\SnapshotFilter::REQUIREMENT_TYPE);
|
2014-09-27 10:59:37 +02:00
|
|
|
$requirement->setValue(new \Szurubooru\SearchServices\Requirements\RequirementSingleValue(\Szurubooru\Entities\Snapshot::TYPE_POST));
|
2014-09-26 20:41:28 +02:00
|
|
|
$filter->addRequirement($requirement);
|
|
|
|
|
|
|
|
return $this->historyService->getFiltered($filter)->getEntities();
|
|
|
|
};
|
|
|
|
return $this->transactionManager->rollback($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-15 11:38:24 +02:00
|
|
|
public function createPost(\Szurubooru\FormData\UploadFormData $formData)
|
|
|
|
{
|
2014-09-16 14:04:53 +02:00
|
|
|
$transactionFunc = function() use ($formData)
|
2014-09-15 11:38:24 +02:00
|
|
|
{
|
|
|
|
$formData->validate($this->validator);
|
|
|
|
|
|
|
|
$post = new \Szurubooru\Entities\Post();
|
|
|
|
$post->setUploadTime($this->timeService->getCurrentTime());
|
|
|
|
$post->setLastEditTime($this->timeService->getCurrentTime());
|
|
|
|
$post->setUser($formData->anonymous ? null : $this->authService->getLoggedInUser());
|
|
|
|
$post->setOriginalFileName($formData->contentFileName);
|
|
|
|
$post->setName($this->getUniqueRandomPostName());
|
|
|
|
|
|
|
|
$this->updatePostSafety($post, $formData->safety);
|
|
|
|
$this->updatePostSource($post, $formData->source);
|
|
|
|
$this->updatePostTags($post, $formData->tags);
|
|
|
|
$this->updatePostContentFromStringOrUrl($post, $formData->content, $formData->url);
|
|
|
|
|
2014-09-26 20:41:28 +02:00
|
|
|
$savedPost = $this->postDao->save($post);
|
|
|
|
|
|
|
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($savedPost));
|
|
|
|
return $savedPost;
|
2014-09-16 14:04:53 +02:00
|
|
|
};
|
|
|
|
return $this->transactionManager->commit($transactionFunc);
|
2014-09-15 11:38:24 +02:00
|
|
|
}
|
|
|
|
|
2014-09-25 19:11:41 +02:00
|
|
|
public function updatePost(\Szurubooru\Entities\Post $post, \Szurubooru\FormData\PostEditFormData $formData)
|
|
|
|
{
|
|
|
|
$transactionFunc = function() use ($post, $formData)
|
|
|
|
{
|
|
|
|
$this->validator->validate($formData);
|
2014-09-25 22:19:15 +02:00
|
|
|
|
|
|
|
if ($post->getLastEditTime() !== $formData->seenEditTime)
|
|
|
|
throw new \DomainException('Someone has already edited this post in the meantime.');
|
|
|
|
|
2014-09-25 22:10:28 +02:00
|
|
|
$post->setLastEditTime($this->timeService->getCurrentTime());
|
2014-09-25 19:11:41 +02:00
|
|
|
|
|
|
|
if ($formData->content !== null)
|
|
|
|
$this->updatePostContentFromString($post, $formData->content);
|
|
|
|
|
|
|
|
if ($formData->thumbnail !== null)
|
|
|
|
$this->updatePostThumbnailFromString($post, $formData->thumbnail);
|
|
|
|
|
|
|
|
if ($formData->safety !== null)
|
|
|
|
$this->updatePostSafety($post, $formData->safety);
|
|
|
|
|
|
|
|
if ($formData->source !== null)
|
|
|
|
$this->updatePostSource($post, $formData->source);
|
|
|
|
|
|
|
|
if ($formData->tags !== null)
|
|
|
|
$this->updatePostTags($post, $formData->tags);
|
|
|
|
|
2014-09-25 23:53:47 +02:00
|
|
|
if ($formData->relations !== null)
|
|
|
|
$this->updatePostRelations($post, $formData->relations);
|
|
|
|
|
2014-09-26 20:41:28 +02:00
|
|
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
|
2014-09-25 19:11:41 +02:00
|
|
|
return $this->postDao->save($post);
|
|
|
|
};
|
|
|
|
return $this->transactionManager->commit($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-15 11:38:24 +02:00
|
|
|
private function updatePostSafety(\Szurubooru\Entities\Post $post, $newSafety)
|
|
|
|
{
|
|
|
|
$post->setSafety($newSafety);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function updatePostSource(\Szurubooru\Entities\Post $post, $newSource)
|
|
|
|
{
|
|
|
|
$post->setSource($newSource);
|
|
|
|
}
|
|
|
|
|
|
|
|
private function updatePostContentFromStringOrUrl(\Szurubooru\Entities\Post $post, $content, $url)
|
|
|
|
{
|
|
|
|
if ($url)
|
|
|
|
$this->updatePostContentFromUrl($post, $url);
|
|
|
|
else if ($content)
|
|
|
|
$this->updatePostContentFromString($post, $content);
|
|
|
|
else
|
|
|
|
throw new \DomainException('No content specified');
|
|
|
|
}
|
|
|
|
|
|
|
|
private function updatePostContentFromString(\Szurubooru\Entities\Post $post, $content)
|
|
|
|
{
|
|
|
|
if (!$content)
|
|
|
|
throw new \DomainException('File cannot be empty.');
|
|
|
|
|
2014-09-16 18:10:01 +02:00
|
|
|
if (strlen($content) > $this->config->database->maxPostSize)
|
|
|
|
throw new \DomainException('Upload is too big.');
|
|
|
|
|
2014-09-15 11:38:24 +02:00
|
|
|
$mime = \Szurubooru\Helpers\MimeHelper::getMimeTypeFromBuffer($content);
|
2014-09-18 19:30:12 +02:00
|
|
|
$post->setContentMimeType($mime);
|
2014-09-15 11:38:24 +02:00
|
|
|
|
|
|
|
if (\Szurubooru\Helpers\MimeHelper::isFlash($mime))
|
|
|
|
$post->setContentType(\Szurubooru\Entities\Post::POST_TYPE_FLASH);
|
|
|
|
elseif (\Szurubooru\Helpers\MimeHelper::isImage($mime))
|
|
|
|
$post->setContentType(\Szurubooru\Entities\Post::POST_TYPE_IMAGE);
|
|
|
|
elseif (\Szurubooru\Helpers\MimeHelper::isVideo($mime))
|
|
|
|
$post->setContentType(\Szurubooru\Entities\Post::POST_TYPE_VIDEO);
|
|
|
|
else
|
|
|
|
throw new \DomainException('Unhandled file type: "' . $mime . '"');
|
|
|
|
|
|
|
|
$post->setContentChecksum(sha1($content));
|
|
|
|
$this->assertNoPostWithThisContentChecksum($post);
|
|
|
|
|
2014-09-20 12:45:56 +02:00
|
|
|
$post->setContent($content);
|
2014-09-15 11:38:24 +02:00
|
|
|
|
2014-09-20 18:30:48 +02:00
|
|
|
$image = $this->imageManipulator->loadFromBuffer($content);
|
|
|
|
$post->setImageWidth($this->imageManipulator->getImageWidth($image));
|
|
|
|
$post->setImageHeight($this->imageManipulator->getImageHeight($image));
|
2014-09-15 11:38:24 +02:00
|
|
|
|
2014-09-20 12:45:56 +02:00
|
|
|
$post->setOriginalFileSize(strlen($content));
|
2014-09-15 11:38:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private function updatePostContentFromUrl(\Szurubooru\Entities\Post $post, $url)
|
|
|
|
{
|
|
|
|
if (!preg_match('/^https?:\/\//', $url))
|
|
|
|
throw new \InvalidArgumentException('Invalid URL "' . $url . '"');
|
|
|
|
|
|
|
|
$youtubeId = null;
|
|
|
|
if (preg_match('/youtube.com\/watch.*?=([a-zA-Z0-9_-]+)/', $url, $matches))
|
|
|
|
$youtubeId = $matches[1];
|
|
|
|
|
|
|
|
if ($youtubeId)
|
|
|
|
{
|
|
|
|
$post->setContentType(\Szurubooru\Entities\Post::POST_TYPE_YOUTUBE);
|
|
|
|
$post->setImageWidth(null);
|
|
|
|
$post->setImageHeight(null);
|
|
|
|
$post->setContentChecksum($url);
|
|
|
|
$post->setOriginalFileName($url);
|
|
|
|
$post->setOriginalFileSize(null);
|
|
|
|
$post->setContentChecksum($youtubeId);
|
|
|
|
|
|
|
|
$this->assertNoPostWithThisContentChecksum($post);
|
2014-09-18 17:44:00 +02:00
|
|
|
$youtubeThumbnailUrl = 'http://img.youtube.com/vi/' . $youtubeId . '/mqdefault.jpg';
|
|
|
|
$youtubeThumbnail = $this->fileService->download($youtubeThumbnailUrl);
|
2014-09-20 12:45:56 +02:00
|
|
|
$post->setThumbnailSourceContent($youtubeThumbnail);
|
2014-09-15 11:38:24 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
$contents = $this->fileService->download($url);
|
|
|
|
$this->updatePostContentFromString($post, $contents);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-25 19:11:41 +02:00
|
|
|
private function updatePostThumbnailFromString(\Szurubooru\Entities\Post $post, $newThumbnail)
|
|
|
|
{
|
|
|
|
if (strlen($newThumbnail) > $this->config->database->maxCustomThumbnailSize)
|
|
|
|
throw new \DomainException('Thumbnail is too big.');
|
|
|
|
|
|
|
|
$post->setThumbnailSourceContent($newThumbnail);
|
|
|
|
}
|
|
|
|
|
2014-09-21 09:35:43 +02:00
|
|
|
private function updatePostTags(\Szurubooru\Entities\Post $post, array $newTagNames)
|
2014-09-15 11:38:24 +02:00
|
|
|
{
|
2014-09-21 09:35:43 +02:00
|
|
|
$tags = [];
|
|
|
|
foreach ($newTagNames as $tagName)
|
|
|
|
{
|
|
|
|
$tag = new \Szurubooru\Entities\Tag();
|
|
|
|
$tag->setName($tagName);
|
|
|
|
$tags[] = $tag;
|
|
|
|
}
|
|
|
|
$post->setTags($tags);
|
2014-09-15 11:38:24 +02:00
|
|
|
}
|
|
|
|
|
2014-09-25 23:53:47 +02:00
|
|
|
private function updatePostRelations(\Szurubooru\Entities\Post $post, array $newRelatedPostIds)
|
|
|
|
{
|
|
|
|
$relatedPosts = $this->postDao->findByIds($newRelatedPostIds);
|
|
|
|
foreach ($newRelatedPostIds as $postId)
|
2014-09-26 20:41:28 +02:00
|
|
|
{
|
2014-09-25 23:53:47 +02:00
|
|
|
if (!isset($relatedPosts[$postId]))
|
|
|
|
throw new \DomainException('Post with id "' . $postId . '" was not found.');
|
2014-09-26 20:41:28 +02:00
|
|
|
}
|
2014-09-25 23:53:47 +02:00
|
|
|
|
|
|
|
$post->setRelatedPosts($relatedPosts);
|
|
|
|
}
|
|
|
|
|
2014-09-23 20:18:12 +02:00
|
|
|
public function deletePost(\Szurubooru\Entities\Post $post)
|
|
|
|
{
|
|
|
|
$transactionFunc = function() use ($post)
|
|
|
|
{
|
2014-09-26 20:41:28 +02:00
|
|
|
$this->historyService->saveSnapshot($this->historyService->getPostDeleteSnapshot($post));
|
2014-09-23 20:18:12 +02:00
|
|
|
$this->postDao->deleteById($post->getId());
|
|
|
|
};
|
|
|
|
$this->transactionManager->commit($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-24 23:24:51 +02:00
|
|
|
public function featurePost(\Szurubooru\Entities\Post $post)
|
|
|
|
{
|
|
|
|
$transactionFunc = function() use ($post)
|
|
|
|
{
|
2014-09-26 20:41:28 +02:00
|
|
|
$previousFeaturedPost = $this->getFeatured();
|
|
|
|
|
2014-09-24 23:24:51 +02:00
|
|
|
$post->setLastFeatureTime($this->timeService->getCurrentTime());
|
|
|
|
$post->setFeatureCount($post->getFeatureCount() + 1);
|
|
|
|
$this->postDao->save($post);
|
|
|
|
$globalParam = new \Szurubooru\Entities\GlobalParam();
|
|
|
|
$globalParam->setKey(\Szurubooru\Entities\GlobalParam::KEY_FEATURED_POST);
|
|
|
|
$globalParam->setValue($post->getId());
|
|
|
|
$this->globalParamDao->save($globalParam);
|
2014-09-26 20:41:28 +02:00
|
|
|
|
|
|
|
if ($previousFeaturedPost)
|
|
|
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($previousFeaturedPost));
|
|
|
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
|
2014-09-24 23:24:51 +02:00
|
|
|
};
|
|
|
|
$this->transactionManager->commit($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-25 11:45:46 +02:00
|
|
|
public function updatePostGlobals()
|
|
|
|
{
|
|
|
|
$transactionFunc = function()
|
|
|
|
{
|
|
|
|
$countParam = new \Szurubooru\Entities\GlobalParam();
|
|
|
|
$countParam->setKey(\Szurubooru\Entities\GlobalParam::KEY_POST_COUNT);
|
|
|
|
$countParam->setValue($this->postDao->getCount());
|
|
|
|
$this->globalParamDao->save($countParam);
|
|
|
|
|
|
|
|
$fileSizeParam = new \Szurubooru\Entities\GlobalParam();
|
|
|
|
$fileSizeParam->setKey(\Szurubooru\Entities\GlobalParam::KEY_POST_SIZE);
|
|
|
|
$fileSizeParam->setValue($this->postDao->getTotalFileSize());
|
|
|
|
$this->globalParamDao->save($fileSizeParam);
|
|
|
|
};
|
|
|
|
$this->transactionManager->commit($transactionFunc);
|
|
|
|
}
|
|
|
|
|
2014-09-15 11:38:24 +02:00
|
|
|
private function assertNoPostWithThisContentChecksum(\Szurubooru\Entities\Post $parent)
|
|
|
|
{
|
|
|
|
$checksumToCheck = $parent->getContentChecksum();
|
|
|
|
$postWithThisChecksum = $this->postDao->findByContentChecksum($checksumToCheck);
|
|
|
|
if ($postWithThisChecksum and $postWithThisChecksum->getId() !== $parent->getId())
|
|
|
|
throw new \DomainException('Duplicate post: ' . $postWithThisChecksum->getIdMarkdown());
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getRandomPostName()
|
|
|
|
{
|
|
|
|
return sha1(microtime(true) . mt_rand() . uniqid());
|
|
|
|
}
|
|
|
|
|
|
|
|
private function getUniqueRandomPostName()
|
|
|
|
{
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
$name = $this->getRandomPostName();
|
|
|
|
if (!$this->postDao->findByName($name))
|
|
|
|
return $name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|