Added post history
This commit is contained in:
parent
df939e0343
commit
9edc74f9a5
29 changed files with 995 additions and 27 deletions
2
TODO
2
TODO
|
@ -7,8 +7,6 @@ everything related to posts:
|
||||||
- score
|
- score
|
||||||
- editing
|
- editing
|
||||||
- ability to loop video posts
|
- ability to loop video posts
|
||||||
- post edit history (think
|
|
||||||
http://konachan.com/history?search=post%3A188614)
|
|
||||||
- previous and next post (difficult)
|
- previous and next post (difficult)
|
||||||
- extract Pager from PagedCollectionPresenter
|
- extract Pager from PagedCollectionPresenter
|
||||||
- rename PagedCollectionPresenter to PagerPresenter
|
- rename PagedCollectionPresenter to PagerPresenter
|
||||||
|
|
|
@ -53,6 +53,8 @@ changePostRelations = regularUser, powerUser, moderator, administrator
|
||||||
|
|
||||||
listTags = anonymous, regularUser, powerUser, moderator, administrator
|
listTags = anonymous, regularUser, powerUser, moderator, administrator
|
||||||
|
|
||||||
|
viewHistory = anonymous, regularUser, powerUser, moderator, administrator
|
||||||
|
|
||||||
[users]
|
[users]
|
||||||
minUserNameLength = 1
|
minUserNameLength = 1
|
||||||
maxUserNameLength = 32
|
maxUserNameLength = 32
|
||||||
|
|
50
public_html/css/history.css
Normal file
50
public_html/css/history.css
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
table.history {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
table.history .addition {
|
||||||
|
color: forestgreen;
|
||||||
|
}
|
||||||
|
table.history .addition:before {
|
||||||
|
content: '+';
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history .removal {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
table.history .removal:before {
|
||||||
|
content: '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history .time,
|
||||||
|
table.history .user,
|
||||||
|
table.history .subject {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history .user img {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history td {
|
||||||
|
padding: 0.1em 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history ul {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
table.history ul:before {
|
||||||
|
content: ' (';
|
||||||
|
}
|
||||||
|
table.history ul:after {
|
||||||
|
content: ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
table.history li {
|
||||||
|
display: inline;
|
||||||
|
}
|
||||||
|
table.history li:not(:last-of-type):after {
|
||||||
|
content: ', ';
|
||||||
|
}
|
|
@ -124,3 +124,8 @@
|
||||||
#post-view-wrapper .post-edit-wrapper .file-handler {
|
#post-view-wrapper .post-edit-wrapper .file-handler {
|
||||||
margin: 0.5em 0;
|
margin: 0.5em 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#post-view-wrapper .post-history-wrapper {
|
||||||
|
padding: 1em;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="/css/post-list.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/post-list.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/post.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/post.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="/css/home.css"/>
|
<link rel="stylesheet" type="text/css" href="/css/home.css"/>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/css/history.css"/>
|
||||||
<!-- /build -->
|
<!-- /build -->
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,8 @@ App.Auth = function(_, jQuery, util, api, appState, promise) {
|
||||||
changePostRelations: 'changePostRelations',
|
changePostRelations: 'changePostRelations',
|
||||||
|
|
||||||
listTags: 'listTags',
|
listTags: 'listTags',
|
||||||
|
|
||||||
|
viewHistory: 'viewHistory',
|
||||||
};
|
};
|
||||||
|
|
||||||
function loginFromCredentials(userNameOrEmail, password, remember) {
|
function loginFromCredentials(userNameOrEmail, password, remember) {
|
||||||
|
|
|
@ -15,13 +15,19 @@ App.Presenters.PostPresenter = function(
|
||||||
|
|
||||||
var $el = jQuery('#content');
|
var $el = jQuery('#content');
|
||||||
var $messages = $el;
|
var $messages = $el;
|
||||||
|
|
||||||
var postTemplate;
|
var postTemplate;
|
||||||
var postEditTemplate;
|
var postEditTemplate;
|
||||||
var postContentTemplate;
|
var postContentTemplate;
|
||||||
|
var historyTemplate;
|
||||||
|
|
||||||
var post;
|
var post;
|
||||||
|
var postHistory;
|
||||||
var postNameOrId;
|
var postNameOrId;
|
||||||
|
|
||||||
var privileges = {};
|
var privileges = {};
|
||||||
var editPrivileges = {};
|
var editPrivileges = {};
|
||||||
|
|
||||||
var tagInput;
|
var tagInput;
|
||||||
var postContentFileDropper;
|
var postContentFileDropper;
|
||||||
var postThumbnailFileDropper;
|
var postThumbnailFileDropper;
|
||||||
|
@ -33,6 +39,7 @@ App.Presenters.PostPresenter = function(
|
||||||
|
|
||||||
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
|
privileges.canDeletePosts = auth.hasPrivilege(auth.privileges.deletePosts);
|
||||||
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
|
privileges.canFeaturePosts = auth.hasPrivilege(auth.privileges.featurePosts);
|
||||||
|
privileges.canViewHistory = auth.hasPrivilege(auth.privileges.viewHistory);
|
||||||
editPrivileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
|
editPrivileges.canChangeSafety = auth.hasPrivilege(auth.privileges.changePostSafety);
|
||||||
editPrivileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
|
editPrivileges.canChangeSource = auth.hasPrivilege(auth.privileges.changePostSource);
|
||||||
editPrivileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
|
editPrivileges.canChangeTags = auth.hasPrivilege(auth.privileges.changePostTags);
|
||||||
|
@ -43,15 +50,17 @@ App.Presenters.PostPresenter = function(
|
||||||
promise.waitAll(
|
promise.waitAll(
|
||||||
util.promiseTemplate('post'),
|
util.promiseTemplate('post'),
|
||||||
util.promiseTemplate('post-edit'),
|
util.promiseTemplate('post-edit'),
|
||||||
util.promiseTemplate('post-content'))
|
util.promiseTemplate('post-content'),
|
||||||
|
util.promiseTemplate('history'))
|
||||||
.then(function(
|
.then(function(
|
||||||
postTemplateHtml,
|
postTemplateHtml,
|
||||||
postEditTemplateHtml,
|
postEditTemplateHtml,
|
||||||
postContentTemplateHtml,
|
postContentTemplateHtml,
|
||||||
response) {
|
historyTemplateHtml) {
|
||||||
postTemplate = _.template(postTemplateHtml);
|
postTemplate = _.template(postTemplateHtml);
|
||||||
postEditTemplate = _.template(postEditTemplateHtml);
|
postEditTemplate = _.template(postEditTemplateHtml);
|
||||||
postContentTemplate = _.template(postContentTemplateHtml);
|
postContentTemplate = _.template(postContentTemplateHtml);
|
||||||
|
historyTemplate = _.template(historyTemplateHtml);
|
||||||
|
|
||||||
reinit(args, loaded);
|
reinit(args, loaded);
|
||||||
}).fail(showGenericError);
|
}).fail(showGenericError);
|
||||||
|
@ -60,9 +69,14 @@ App.Presenters.PostPresenter = function(
|
||||||
function reinit(args, loaded) {
|
function reinit(args, loaded) {
|
||||||
postNameOrId = args.postNameOrId;
|
postNameOrId = args.postNameOrId;
|
||||||
|
|
||||||
promise.wait(api.get('/posts/' + postNameOrId))
|
promise.waitAll(
|
||||||
.then(function(response) {
|
api.get('/posts/' + postNameOrId),
|
||||||
post = response.json;
|
privileges.canViewHistory ?
|
||||||
|
api.get('/posts/' + postNameOrId + '/history') :
|
||||||
|
null)
|
||||||
|
.then(function(postResponse, postHistoryResponse) {
|
||||||
|
post = postResponse.json;
|
||||||
|
postHistory = postHistoryResponse && postHistoryResponse.json && postHistoryResponse.json.data;
|
||||||
topNavigationPresenter.changeTitle('@' + post.id);
|
topNavigationPresenter.changeTitle('@' + post.id);
|
||||||
render();
|
render();
|
||||||
loaded();
|
loaded();
|
||||||
|
@ -92,9 +106,10 @@ App.Presenters.PostPresenter = function(
|
||||||
}
|
}
|
||||||
|
|
||||||
$el.find('.post-edit-wrapper form').submit(editFormSubmitted);
|
$el.find('.post-edit-wrapper form').submit(editFormSubmitted);
|
||||||
$el.find('.delete').click(deleteButtonClicked);
|
$el.find('#sidebar .delete').click(deleteButtonClicked);
|
||||||
$el.find('.feature').click(featureButtonClicked);
|
$el.find('#sidebar .feature').click(featureButtonClicked);
|
||||||
$el.find('.edit').click(editButtonClicked);
|
$el.find('#sidebar .edit').click(editButtonClicked);
|
||||||
|
$el.find('#sidebar .history').click(historyButtonClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderSidebar() {
|
function renderSidebar() {
|
||||||
|
@ -104,10 +119,12 @@ App.Presenters.PostPresenter = function(
|
||||||
function renderPostTemplate() {
|
function renderPostTemplate() {
|
||||||
return postTemplate({
|
return postTemplate({
|
||||||
post: post,
|
post: post,
|
||||||
|
postHistory: postHistory,
|
||||||
formatRelativeTime: util.formatRelativeTime,
|
formatRelativeTime: util.formatRelativeTime,
|
||||||
formatFileSize: util.formatFileSize,
|
formatFileSize: util.formatFileSize,
|
||||||
postContentTemplate: postContentTemplate,
|
postContentTemplate: postContentTemplate,
|
||||||
postEditTemplate: postEditTemplate,
|
postEditTemplate: postEditTemplate,
|
||||||
|
historyTemplate: historyTemplate,
|
||||||
privileges: privileges,
|
privileges: privileges,
|
||||||
editPrivileges: editPrivileges,
|
editPrivileges: editPrivileges,
|
||||||
});
|
});
|
||||||
|
@ -228,6 +245,23 @@ App.Presenters.PostPresenter = function(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function historyButtonClicked(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
if ($el.find('.post-history-wrapper').is(':visible')) {
|
||||||
|
hideHistory();
|
||||||
|
} else {
|
||||||
|
showHistory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideHistory() {
|
||||||
|
$el.find('.post-history-wrapper').slideUp('slow');
|
||||||
|
}
|
||||||
|
|
||||||
|
function showHistory() {
|
||||||
|
$el.find('.post-history-wrapper').slideDown('slow');
|
||||||
|
}
|
||||||
|
|
||||||
function showEditError(response) {
|
function showEditError(response) {
|
||||||
window.alert(response.json && response.json.error || response);
|
window.alert(response.json && response.json.error || response);
|
||||||
}
|
}
|
||||||
|
|
63
public_html/templates/history.tpl
Normal file
63
public_html/templates/history.tpl
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
<table class="history">
|
||||||
|
<tbody>
|
||||||
|
<% _.each(history, function( historyEntry) { %>
|
||||||
|
<tr>
|
||||||
|
<td class="time">
|
||||||
|
<%= formatRelativeTime(historyEntry.time) %>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="user">
|
||||||
|
<% var userName = historyEntry.user && historyEntry.user.name || '' %>
|
||||||
|
|
||||||
|
<% if (userName) { %>
|
||||||
|
<a href="#/user/<%= userName %>">
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<img class="author-avatar"
|
||||||
|
src="/data/thumbnails/20x20/avatars/<%= userName || '!' %>"
|
||||||
|
alt="<%= userName || 'Anonymous user' %>"/>
|
||||||
|
|
||||||
|
<%= userName || 'Anonymous user' %>
|
||||||
|
|
||||||
|
<% if (userName) { %>
|
||||||
|
</a>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="subject">
|
||||||
|
<% if (historyEntry.type == 0) { %>
|
||||||
|
<a href="#/post/<%= historyEntry.primaryKey %>">
|
||||||
|
@<%= historyEntry.primaryKey %>
|
||||||
|
</a>
|
||||||
|
<% } else { %>
|
||||||
|
?
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<td class="difference">
|
||||||
|
<% if (historyEntry.operation == 1) { %>
|
||||||
|
deleted
|
||||||
|
<% } else { %>
|
||||||
|
changed
|
||||||
|
|
||||||
|
<% if (historyEntry.dataDifference) { %>
|
||||||
|
<ul><!--
|
||||||
|
--><% _.each(historyEntry.dataDifference['+'], function (difference) { %><!--
|
||||||
|
--><li class="addition difference-<%= difference[0] %>"><!--
|
||||||
|
--><%= difference[0] + ':' + difference[1] %><!--
|
||||||
|
--></li><!--
|
||||||
|
--><% }) %><!--
|
||||||
|
|
||||||
|
--><% _.each(historyEntry.dataDifference['-'], function (difference) { %><!--
|
||||||
|
--><li class="removal difference-<%= difference[0] %>"><!--
|
||||||
|
--><%= difference[0] + ':' + difference[1] %><!--
|
||||||
|
--></li><!--
|
||||||
|
--><% }) %><!--
|
||||||
|
--></ul>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<% }) %>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
|
@ -20,11 +20,20 @@
|
||||||
|
|
||||||
<span class="right">
|
<span class="right">
|
||||||
featured by
|
featured by
|
||||||
|
|
||||||
|
<% if (post.user.name) { %>
|
||||||
|
<a href="#/user/<%= post.user.name %>">
|
||||||
|
<% } %>
|
||||||
|
|
||||||
<img class="author-avatar"
|
<img class="author-avatar"
|
||||||
src="/data/thumbnails/25x25/avatars/<%= post.user.name || '!' %>"
|
src="/data/thumbnails/25x25/avatars/<%= post.user.name || '!' %>"
|
||||||
alt="<%= post.user.name || 'Anonymous user' %>"/>
|
alt="<%= post.user.name || 'Anonymous user' %>"/>
|
||||||
|
|
||||||
<%= post.user.name || 'Anonymous user' %>
|
<%= post.user.name || 'Anonymous user' %>
|
||||||
|
|
||||||
|
<% if (post.user.name) { %>
|
||||||
|
</a>
|
||||||
|
<% } %>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -134,6 +134,14 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<% if (privileges.canViewHistory) { %>
|
||||||
|
<li>
|
||||||
|
<a href="#" class="history">
|
||||||
|
History
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<% } %>
|
||||||
</ul>
|
</ul>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
@ -147,5 +155,14 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<%= postContentTemplate({post: post}) %>
|
<%= postContentTemplate({post: post}) %>
|
||||||
|
|
||||||
|
<% if (privileges.canViewHistory) { %>
|
||||||
|
<div class="post-history-wrapper">
|
||||||
|
<%= historyTemplate({
|
||||||
|
history: postHistory,
|
||||||
|
formatRelativeTime: formatRelativeTime
|
||||||
|
}) %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
44
src/Controllers/HistoryController.php
Normal file
44
src/Controllers/HistoryController.php
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Controllers;
|
||||||
|
|
||||||
|
final class HistoryController extends AbstractController
|
||||||
|
{
|
||||||
|
private $historyService;
|
||||||
|
private $privilegeService;
|
||||||
|
private $snapshotSearchParser;
|
||||||
|
private $inputReader;
|
||||||
|
private $snapshotViewProxy;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
\Szurubooru\Services\HistoryService $historyService,
|
||||||
|
\Szurubooru\Services\PrivilegeService $privilegeService,
|
||||||
|
\Szurubooru\SearchServices\Parsers\SnapshotSearchParser $snapshotSearchParser,
|
||||||
|
\Szurubooru\Helpers\InputReader $inputReader,
|
||||||
|
\Szurubooru\Controllers\ViewProxies\SnapshotViewProxy $snapshotViewProxy)
|
||||||
|
{
|
||||||
|
$this->historyService = $historyService;
|
||||||
|
$this->privilegeService = $privilegeService;
|
||||||
|
$this->snapshotSearchParser = $snapshotSearchParser;
|
||||||
|
$this->inputReader = $inputReader;
|
||||||
|
$this->snapshotViewProxy = $snapshotViewProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function registerRoutes(\Szurubooru\Router $router)
|
||||||
|
{
|
||||||
|
$router->get('/api/history', [$this, 'getFiltered']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFiltered()
|
||||||
|
{
|
||||||
|
$this->privilegeService->assertPrivilege(\Szurubooru\Privilege::VIEW_HISTORY);
|
||||||
|
|
||||||
|
$filter = $this->snapshotSearchParser->createFilterFromInputReader($this->inputReader);
|
||||||
|
$filter->setPageSize(50);
|
||||||
|
$result = $this->historyService->getFiltered($filter);
|
||||||
|
$entities = $this->snapshotViewProxy->fromArray($result->getEntities());
|
||||||
|
return [
|
||||||
|
'data' => $entities,
|
||||||
|
'pageSize' => $result->getPageSize(),
|
||||||
|
'totalRecords' => $result->getTotalRecords()];
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,7 @@ final class PostController extends AbstractController
|
||||||
private $postSearchParser;
|
private $postSearchParser;
|
||||||
private $inputReader;
|
private $inputReader;
|
||||||
private $postViewProxy;
|
private $postViewProxy;
|
||||||
|
private $snapshotViewProxy;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
\Szurubooru\Config $config,
|
\Szurubooru\Config $config,
|
||||||
|
@ -16,7 +17,8 @@ final class PostController extends AbstractController
|
||||||
\Szurubooru\Services\PostService $postService,
|
\Szurubooru\Services\PostService $postService,
|
||||||
\Szurubooru\SearchServices\Parsers\PostSearchParser $postSearchParser,
|
\Szurubooru\SearchServices\Parsers\PostSearchParser $postSearchParser,
|
||||||
\Szurubooru\Helpers\InputReader $inputReader,
|
\Szurubooru\Helpers\InputReader $inputReader,
|
||||||
\Szurubooru\Controllers\ViewProxies\PostViewProxy $postViewProxy)
|
\Szurubooru\Controllers\ViewProxies\PostViewProxy $postViewProxy,
|
||||||
|
\Szurubooru\Controllers\ViewProxies\SnapshotViewProxy $snapshotViewProxy)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
$this->privilegeService = $privilegeService;
|
$this->privilegeService = $privilegeService;
|
||||||
|
@ -24,30 +26,31 @@ final class PostController extends AbstractController
|
||||||
$this->postSearchParser = $postSearchParser;
|
$this->postSearchParser = $postSearchParser;
|
||||||
$this->inputReader = $inputReader;
|
$this->inputReader = $inputReader;
|
||||||
$this->postViewProxy = $postViewProxy;
|
$this->postViewProxy = $postViewProxy;
|
||||||
|
$this->snapshotViewProxy = $snapshotViewProxy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function registerRoutes(\Szurubooru\Router $router)
|
public function registerRoutes(\Szurubooru\Router $router)
|
||||||
{
|
{
|
||||||
$router->post('/api/posts', [$this, 'createPost']);
|
$router->post('/api/posts', [$this, 'createPost']);
|
||||||
$router->get('/api/posts', [$this, 'getFiltered']);
|
$router->get('/api/posts', [$this, 'getFiltered']);
|
||||||
$router->get('/api/posts/featured', [$this, 'getFeatured']);
|
|
||||||
$router->get('/api/posts/:postNameOrId', [$this, 'getByNameOrId']);
|
$router->get('/api/posts/:postNameOrId', [$this, 'getByNameOrId']);
|
||||||
|
$router->get('/api/posts/:postNameOrId/history', [$this, 'getHistory']);
|
||||||
$router->put('/api/posts/:postNameOrId', [$this, 'updatePost']);
|
$router->put('/api/posts/:postNameOrId', [$this, 'updatePost']);
|
||||||
$router->delete('/api/posts/:postNameOrId', [$this, 'deletePost']);
|
$router->delete('/api/posts/:postNameOrId', [$this, 'deletePost']);
|
||||||
$router->post('/api/posts/:postNameOrId/feature', [$this, 'featurePost']);
|
$router->post('/api/posts/:postNameOrId/feature', [$this, 'featurePost']);
|
||||||
$router->put('/api/posts/:postNameOrId/feature', [$this, 'featurePost']);
|
$router->put('/api/posts/:postNameOrId/feature', [$this, 'featurePost']);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFeatured()
|
public function getByNameOrId($postNameOrId)
|
||||||
{
|
{
|
||||||
$post = $this->postService->getFeatured();
|
$post = $this->getByNameOrIdWithoutProxy($postNameOrId);
|
||||||
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getByNameOrId($postNameOrId)
|
public function getHistory($postNameOrId)
|
||||||
{
|
{
|
||||||
$post = $this->postService->getByNameOrId($postNameOrId);
|
$post = $this->getByNameOrIdWithoutProxy($postNameOrId);
|
||||||
return $this->postViewProxy->fromEntity($post, $this->getFullFetchConfig());
|
return ['data' => $this->snapshotViewProxy->fromArray($this->postService->getHistory($post))];
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFiltered()
|
public function getFiltered()
|
||||||
|
@ -113,6 +116,14 @@ final class PostController extends AbstractController
|
||||||
$this->postService->featurePost($post);
|
$this->postService->featurePost($post);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function getByNameOrIdWithoutProxy($postNameOrId)
|
||||||
|
{
|
||||||
|
if ($postNameOrId === 'featured')
|
||||||
|
return $this->postService->getFeatured();
|
||||||
|
else
|
||||||
|
return $this->postService->getByNameOrId($postNameOrId);
|
||||||
|
}
|
||||||
|
|
||||||
private function getFullFetchConfig()
|
private function getFullFetchConfig()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
29
src/Controllers/ViewProxies/SnapshotViewProxy.php
Normal file
29
src/Controllers/ViewProxies/SnapshotViewProxy.php
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Controllers\ViewProxies;
|
||||||
|
|
||||||
|
class SnapshotViewProxy extends AbstractViewProxy
|
||||||
|
{
|
||||||
|
private $userViewProxy;
|
||||||
|
|
||||||
|
public function __construct(UserViewProxy $userViewProxy)
|
||||||
|
{
|
||||||
|
$this->userViewProxy = $userViewProxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function fromEntity($snapshot, $config = [])
|
||||||
|
{
|
||||||
|
$result = new \StdClass;
|
||||||
|
if ($snapshot)
|
||||||
|
{
|
||||||
|
$result->time = $snapshot->getTime();
|
||||||
|
$result->type = $snapshot->getType();
|
||||||
|
$result->primaryKey = $snapshot->getPrimaryKey();
|
||||||
|
$result->operation = $snapshot->getOperation();
|
||||||
|
$result->user = $this->userViewProxy->fromEntity($snapshot->getUser());
|
||||||
|
$result->data = $snapshot->getData();
|
||||||
|
$result->dataDifference = $snapshot->getDataDifference();
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
34
src/Dao/EntityConverters/SnapshotEntityConverter.php
Normal file
34
src/Dao/EntityConverters/SnapshotEntityConverter.php
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Dao\EntityConverters;
|
||||||
|
|
||||||
|
class SnapshotEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||||
|
{
|
||||||
|
public function toArray(\Szurubooru\Entities\Entity $entity)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
[
|
||||||
|
'id' => $entity->getId(),
|
||||||
|
'time' => $entity->getTime(),
|
||||||
|
'type' => $entity->getType(),
|
||||||
|
'primaryKey' => $entity->getPrimaryKey(),
|
||||||
|
'userId' => $entity->getUserId(),
|
||||||
|
'operation' => $entity->getOperation(),
|
||||||
|
'data' => json_encode($entity->getData()),
|
||||||
|
'dataDifference' => json_encode($entity->getDataDifference()),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function toBasicEntity(array $array)
|
||||||
|
{
|
||||||
|
$entity = new \Szurubooru\Entities\Snapshot(intval($array['id']));
|
||||||
|
$entity->setTime($array['time']);
|
||||||
|
$entity->setType(intval($array['type']));
|
||||||
|
$entity->setPrimaryKey($array['primaryKey']);
|
||||||
|
$entity->setUserId($array['userId']);
|
||||||
|
$entity->setOperation($array['operation']);
|
||||||
|
$entity->setData(json_decode($array['data'], true));
|
||||||
|
$entity->setDataDifference(json_decode($array['dataDifference'], true));
|
||||||
|
return $entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
45
src/Dao/SnapshotDao.php
Normal file
45
src/Dao/SnapshotDao.php
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Dao;
|
||||||
|
|
||||||
|
class SnapshotDao extends AbstractDao
|
||||||
|
{
|
||||||
|
private $userDao;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
\Szurubooru\DatabaseConnection $databaseConnection,
|
||||||
|
\Szurubooru\Dao\UserDao $userDao)
|
||||||
|
{
|
||||||
|
parent::__construct(
|
||||||
|
$databaseConnection,
|
||||||
|
'snapshots',
|
||||||
|
new \Szurubooru\Dao\EntityConverters\SnapshotEntityConverter());
|
||||||
|
|
||||||
|
$this->userDao = $userDao;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function findByTypeAndKey($type, $primaryKey)
|
||||||
|
{
|
||||||
|
$query = $this->fpdo
|
||||||
|
->from($this->tableName)
|
||||||
|
->where('type', $type)
|
||||||
|
->where('primaryKey', $primaryKey)
|
||||||
|
->orderBy('time DESC');
|
||||||
|
return $this->arrayToEntities(iterator_to_array($query));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function afterLoad(\Szurubooru\Entities\Entity $snapshot)
|
||||||
|
{
|
||||||
|
$snapshot->setLazyLoader(
|
||||||
|
\Szurubooru\Entities\Snapshot::LAZY_LOADER_USER,
|
||||||
|
function (\Szurubooru\Entities\Snapshot $snapshot)
|
||||||
|
{
|
||||||
|
return $this->getUser($snapshot);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getUser(\Szurubooru\Entities\Snapshot $snapshot)
|
||||||
|
{
|
||||||
|
$userId = $snapshot->getUserId();
|
||||||
|
return $this->userDao->findById($userId);
|
||||||
|
}
|
||||||
|
}
|
|
@ -220,14 +220,7 @@ final class Post extends Entity
|
||||||
public function setUser(\Szurubooru\Entities\User $user = null)
|
public function setUser(\Szurubooru\Entities\User $user = null)
|
||||||
{
|
{
|
||||||
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||||
if ($user)
|
$this->userId = $user ? $user->getId() : null;
|
||||||
{
|
|
||||||
$this->userId = $user->getId();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
$this->userId = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getContent()
|
public function getContent()
|
||||||
|
|
101
src/Entities/Snapshot.php
Normal file
101
src/Entities/Snapshot.php
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Entities;
|
||||||
|
|
||||||
|
final class Snapshot extends Entity
|
||||||
|
{
|
||||||
|
const TYPE_POST = 0;
|
||||||
|
|
||||||
|
const OPERATION_CHANGE = 0;
|
||||||
|
const OPERATION_DELETE = 1;
|
||||||
|
|
||||||
|
const LAZY_LOADER_USER = 'user';
|
||||||
|
|
||||||
|
private $time;
|
||||||
|
private $type;
|
||||||
|
private $primaryKey;
|
||||||
|
private $operation;
|
||||||
|
private $userId;
|
||||||
|
private $data;
|
||||||
|
private $dataDifference;
|
||||||
|
|
||||||
|
public function getTime()
|
||||||
|
{
|
||||||
|
return $this->time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setTime($time)
|
||||||
|
{
|
||||||
|
$this->time = $time;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getType()
|
||||||
|
{
|
||||||
|
return $this->type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setType($type)
|
||||||
|
{
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPrimaryKey()
|
||||||
|
{
|
||||||
|
return $this->primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setPrimaryKey($primaryKey)
|
||||||
|
{
|
||||||
|
$this->primaryKey = $primaryKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getOperation()
|
||||||
|
{
|
||||||
|
return $this->operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setOperation($operation)
|
||||||
|
{
|
||||||
|
$this->operation = $operation;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUserId()
|
||||||
|
{
|
||||||
|
return $this->userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUserId($userId)
|
||||||
|
{
|
||||||
|
$this->userId = $userId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getData()
|
||||||
|
{
|
||||||
|
return $this->data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setData($data)
|
||||||
|
{
|
||||||
|
$this->data = $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDataDifference()
|
||||||
|
{
|
||||||
|
return $this->dataDifference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setDataDifference($dataDifference)
|
||||||
|
{
|
||||||
|
$this->dataDifference = $dataDifference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUser()
|
||||||
|
{
|
||||||
|
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUser(\Szurubooru\Entities\User $user = null)
|
||||||
|
{
|
||||||
|
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||||
|
$this->userId = $user ? $user->getId() : null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,6 +35,11 @@ class EnumHelper
|
||||||
'youtube' => \Szurubooru\Entities\Post::POST_TYPE_YOUTUBE,
|
'youtube' => \Szurubooru\Entities\Post::POST_TYPE_YOUTUBE,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
private static $snapshotTypeMap =
|
||||||
|
[
|
||||||
|
'post' => \Szurubooru\Entities\Snapshot::TYPE_POST,
|
||||||
|
];
|
||||||
|
|
||||||
public static function accessRankToString($accessRank)
|
public static function accessRankToString($accessRank)
|
||||||
{
|
{
|
||||||
return self::enumToString(self::$accessRankMap, $accessRank);
|
return self::enumToString(self::$accessRankMap, $accessRank);
|
||||||
|
@ -70,6 +75,11 @@ class EnumHelper
|
||||||
return self::enumToString(self::$postTypeMap, $postType);
|
return self::enumToString(self::$postTypeMap, $postType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function snapshotTypeFromString($snapshotTypeString)
|
||||||
|
{
|
||||||
|
return self::stringToEnum(self::$snapshotTypeMap, $snapshotTypeString);
|
||||||
|
}
|
||||||
|
|
||||||
private static function enumToString($enumMap, $enumValue)
|
private static function enumToString($enumMap, $enumValue)
|
||||||
{
|
{
|
||||||
$reverseMap = array_flip($enumMap);
|
$reverseMap = array_flip($enumMap);
|
||||||
|
|
|
@ -33,4 +33,6 @@ class Privilege
|
||||||
const CHANGE_POST_RELATIONS = 'changePostRelations';
|
const CHANGE_POST_RELATIONS = 'changePostRelations';
|
||||||
|
|
||||||
const LIST_TAGS = 'listTags';
|
const LIST_TAGS = 'listTags';
|
||||||
|
|
||||||
|
const VIEW_HISTORY = 'viewHistory';
|
||||||
}
|
}
|
||||||
|
|
8
src/SearchServices/Filters/SnapshotFilter.php
Normal file
8
src/SearchServices/Filters/SnapshotFilter.php
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices\Filters;
|
||||||
|
|
||||||
|
class SnapshotFilter extends BasicFilter implements IFilter
|
||||||
|
{
|
||||||
|
const REQUIREMENT_PRIMARY_KEY = 'primaryKey';
|
||||||
|
const REQUIREMENT_TYPE = 'type';
|
||||||
|
}
|
41
src/SearchServices/Parsers/SnapshotSearchParser.php
Normal file
41
src/SearchServices/Parsers/SnapshotSearchParser.php
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\SearchServices\Parsers;
|
||||||
|
|
||||||
|
class SnapshotSearchParser extends AbstractSearchParser
|
||||||
|
{
|
||||||
|
protected function createFilter()
|
||||||
|
{
|
||||||
|
return new \Szurubooru\SearchServices\Filters\SnapshotFilter;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decorateFilterFromToken($filter, $token)
|
||||||
|
{
|
||||||
|
if (substr_count($token->getValue(), ',') !== 1)
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
|
||||||
|
if ($token->isNegated())
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
|
||||||
|
list ($type, $primaryKey) = explode(',', $token->getValue());
|
||||||
|
|
||||||
|
$requirement = new \Szurubooru\SearchServices\Requirements\Requirement();
|
||||||
|
$requirement->setType(\Szurubooru\SearchServices\Filters\SnapshotFilter::REQUIREMENT_PRIMARY_KEY);
|
||||||
|
$requirement->setValue($primaryKey);
|
||||||
|
$filter->addRequirement($requirement);
|
||||||
|
|
||||||
|
$requirement = new \Szurubooru\SearchServices\Requirements\Requirement();
|
||||||
|
$requirement->setType(\Szurubooru\SearchServices\Filters\SnapshotFilter::REQUIREMENT_TYPE);
|
||||||
|
$requirement->setValue(\Szurubooru\Helpers\EnumHelper::snapshotTypeFromString($type));
|
||||||
|
$filter->addRequirement($requirement);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function decorateFilterFromNamedToken($filter, $namedToken)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getOrderColumn($token)
|
||||||
|
{
|
||||||
|
throw new \BadMethodCallException('Not supported');
|
||||||
|
}
|
||||||
|
}
|
145
src/Services/HistoryService.php
Normal file
145
src/Services/HistoryService.php
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Services;
|
||||||
|
|
||||||
|
class HistoryService
|
||||||
|
{
|
||||||
|
private $validator;
|
||||||
|
private $snapshotDao;
|
||||||
|
private $globalParamDao;
|
||||||
|
private $timeService;
|
||||||
|
private $authService;
|
||||||
|
private $transactionManager;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
\Szurubooru\Validator $validator,
|
||||||
|
\Szurubooru\Dao\SnapshotDao $snapshotDao,
|
||||||
|
\Szurubooru\Dao\GlobalParamDao $globalParamDao,
|
||||||
|
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||||
|
\Szurubooru\Services\TimeService $timeService,
|
||||||
|
\Szurubooru\Services\AuthService $authService)
|
||||||
|
{
|
||||||
|
$this->validator = $validator;
|
||||||
|
$this->snapshotDao = $snapshotDao;
|
||||||
|
$this->globalParamDao = $globalParamDao;
|
||||||
|
$this->timeService = $timeService;
|
||||||
|
$this->authService = $authService;
|
||||||
|
$this->transactionManager = $transactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFiltered(\Szurubooru\SearchServices\Filters\SnapshotFilter $filter)
|
||||||
|
{
|
||||||
|
$transactionFunc = function() use ($filter)
|
||||||
|
{
|
||||||
|
return $this->snapshotDao->findFiltered($filter);
|
||||||
|
};
|
||||||
|
return $this->transactionManager->rollback($transactionFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function saveSnapshot(\Szurubooru\Entities\Snapshot $snapshot)
|
||||||
|
{
|
||||||
|
$transactionFunc = function() use ($snapshot)
|
||||||
|
{
|
||||||
|
$otherSnapshots = $this->snapshotDao->findByTypeAndKey($snapshot->getType(), $snapshot->getPrimaryKey());
|
||||||
|
if ($otherSnapshots)
|
||||||
|
{
|
||||||
|
$lastSnapshot = array_shift($otherSnapshots);
|
||||||
|
if ($lastSnapshot->getData() === $snapshot->getData())
|
||||||
|
return $lastSnapshot;
|
||||||
|
|
||||||
|
$dataDifference = $this->getSnapshotDataDifference($snapshot->getData(), $lastSnapshot->getData());
|
||||||
|
$snapshot->setDataDifference($dataDifference);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$dataDifference = $this->getSnapshotDataDifference($snapshot->getData(), []);
|
||||||
|
$snapshot->setDataDifference($dataDifference);
|
||||||
|
}
|
||||||
|
|
||||||
|
$snapshot->setTime($this->timeService->getCurrentTime());
|
||||||
|
$snapshot->setUser($this->authService->getLoggedInUser());
|
||||||
|
return $this->snapshotDao->save($snapshot);
|
||||||
|
};
|
||||||
|
return $this->transactionManager->commit($transactionFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPostDeleteSnapshot(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
$snapshot = $this->getPostSnapshot($post);
|
||||||
|
$snapshot->setOperation(\Szurubooru\Entities\Snapshot::OPERATION_DELETE);
|
||||||
|
return $snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPostChangeSnapshot(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
$featuredPostParam = $this->globalParamDao->findByKey(\Szurubooru\Entities\GlobalParam::KEY_FEATURED_POST);
|
||||||
|
$isFeatured = ($featuredPostParam and intval($featuredPostParam->getValue()) === $post->getId());
|
||||||
|
|
||||||
|
$data =
|
||||||
|
[
|
||||||
|
'source' => $post->getSource(),
|
||||||
|
'safety' => \Szurubooru\Helpers\EnumHelper::postSafetyToString($post->getSafety()),
|
||||||
|
'contentChecksum' => $post->getContentChecksum(),
|
||||||
|
'featured' => $isFeatured,
|
||||||
|
|
||||||
|
'tags' =>
|
||||||
|
array_map(
|
||||||
|
function ($tag)
|
||||||
|
{
|
||||||
|
return $tag->getName();
|
||||||
|
},
|
||||||
|
$post->getTags()),
|
||||||
|
|
||||||
|
'relations' =>
|
||||||
|
array_map(
|
||||||
|
function ($post)
|
||||||
|
{
|
||||||
|
return $post->getId();
|
||||||
|
},
|
||||||
|
$post->getRelatedPosts()),
|
||||||
|
|
||||||
|
];
|
||||||
|
|
||||||
|
$snapshot = $this->getPostSnapshot($post);
|
||||||
|
$snapshot->setOperation(\Szurubooru\Entities\Snapshot::OPERATION_CHANGE);
|
||||||
|
$snapshot->setData($data);
|
||||||
|
return $snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSnapshotDataDifference($newData, $oldData)
|
||||||
|
{
|
||||||
|
$diffFunction = function($base, $other)
|
||||||
|
{
|
||||||
|
$result = [];
|
||||||
|
foreach ($base as $key => $value)
|
||||||
|
{
|
||||||
|
if (is_array($base[$key]))
|
||||||
|
{
|
||||||
|
foreach ($base[$key] as $subValue)
|
||||||
|
{
|
||||||
|
if (!isset($other[$key]) or !in_array($subValue, $other[$key]))
|
||||||
|
$result[] = [$key, $subValue];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
elseif (!isset($other[$key]) or $base[$key] !== $other[$key])
|
||||||
|
{
|
||||||
|
$result[] = [$key, $value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
return [
|
||||||
|
'+' => $diffFunction($newData, $oldData),
|
||||||
|
'-' => $diffFunction($oldData, $newData),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getPostSnapshot(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
$snapshot = new \Szurubooru\Entities\Snapshot();
|
||||||
|
$snapshot->setType(\Szurubooru\Entities\Snapshot::TYPE_POST);
|
||||||
|
$snapshot->setPrimaryKey($post->getId());
|
||||||
|
return $snapshot;
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ class PostService
|
||||||
private $timeService;
|
private $timeService;
|
||||||
private $authService;
|
private $authService;
|
||||||
private $fileService;
|
private $fileService;
|
||||||
|
private $historyService;
|
||||||
private $imageManipulator;
|
private $imageManipulator;
|
||||||
|
|
||||||
public function __construct(
|
public function __construct(
|
||||||
|
@ -22,6 +23,7 @@ class PostService
|
||||||
\Szurubooru\Services\AuthService $authService,
|
\Szurubooru\Services\AuthService $authService,
|
||||||
\Szurubooru\Services\TimeService $timeService,
|
\Szurubooru\Services\TimeService $timeService,
|
||||||
\Szurubooru\Services\FileService $fileService,
|
\Szurubooru\Services\FileService $fileService,
|
||||||
|
\Szurubooru\Services\HistoryService $historyService,
|
||||||
\Szurubooru\Services\ImageManipulation\ImageManipulator $imageManipulator)
|
\Szurubooru\Services\ImageManipulation\ImageManipulator $imageManipulator)
|
||||||
{
|
{
|
||||||
$this->config = $config;
|
$this->config = $config;
|
||||||
|
@ -32,6 +34,7 @@ class PostService
|
||||||
$this->timeService = $timeService;
|
$this->timeService = $timeService;
|
||||||
$this->authService = $authService;
|
$this->authService = $authService;
|
||||||
$this->fileService = $fileService;
|
$this->fileService = $fileService;
|
||||||
|
$this->historyService = $historyService;
|
||||||
$this->imageManipulator = $imageManipulator;
|
$this->imageManipulator = $imageManipulator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +85,27 @@ class PostService
|
||||||
return $this->transactionManager->rollback($transactionFunc);
|
return $this->transactionManager->rollback($transactionFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getHistory(\Szurubooru\Entities\Post $post)
|
||||||
|
{
|
||||||
|
$transactionFunc = function() use ($post)
|
||||||
|
{
|
||||||
|
$filter = new \Szurubooru\SearchServices\Filters\SnapshotFilter();
|
||||||
|
|
||||||
|
$requirement = new \Szurubooru\SearchServices\Requirement();
|
||||||
|
$requirement->setType(\Szurubooru\SearchServices\Filters\SnapshotFilter::REQUIREMENT_PRIMARY_KEY);
|
||||||
|
$requirement->setValue($post->getId());
|
||||||
|
$filter->addRequirement($requirement);
|
||||||
|
|
||||||
|
$requirement = new \Szurubooru\SearchServices\Requirement();
|
||||||
|
$requirement->setType(\Szurubooru\SearchServices\Filters\SnapshotFilter::REQUIREMENT_TYPE);
|
||||||
|
$requirement->setValue(\Szurubooru\Entities\Snapshot::TYPE_POST);
|
||||||
|
$filter->addRequirement($requirement);
|
||||||
|
|
||||||
|
return $this->historyService->getFiltered($filter)->getEntities();
|
||||||
|
};
|
||||||
|
return $this->transactionManager->rollback($transactionFunc);
|
||||||
|
}
|
||||||
|
|
||||||
public function createPost(\Szurubooru\FormData\UploadFormData $formData)
|
public function createPost(\Szurubooru\FormData\UploadFormData $formData)
|
||||||
{
|
{
|
||||||
$transactionFunc = function() use ($formData)
|
$transactionFunc = function() use ($formData)
|
||||||
|
@ -100,7 +124,10 @@ class PostService
|
||||||
$this->updatePostTags($post, $formData->tags);
|
$this->updatePostTags($post, $formData->tags);
|
||||||
$this->updatePostContentFromStringOrUrl($post, $formData->content, $formData->url);
|
$this->updatePostContentFromStringOrUrl($post, $formData->content, $formData->url);
|
||||||
|
|
||||||
return $this->postDao->save($post);
|
$savedPost = $this->postDao->save($post);
|
||||||
|
|
||||||
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($savedPost));
|
||||||
|
return $savedPost;
|
||||||
};
|
};
|
||||||
return $this->transactionManager->commit($transactionFunc);
|
return $this->transactionManager->commit($transactionFunc);
|
||||||
}
|
}
|
||||||
|
@ -134,6 +161,7 @@ class PostService
|
||||||
if ($formData->relations !== null)
|
if ($formData->relations !== null)
|
||||||
$this->updatePostRelations($post, $formData->relations);
|
$this->updatePostRelations($post, $formData->relations);
|
||||||
|
|
||||||
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
|
||||||
return $this->postDao->save($post);
|
return $this->postDao->save($post);
|
||||||
};
|
};
|
||||||
return $this->transactionManager->commit($transactionFunc);
|
return $this->transactionManager->commit($transactionFunc);
|
||||||
|
@ -246,8 +274,10 @@ class PostService
|
||||||
{
|
{
|
||||||
$relatedPosts = $this->postDao->findByIds($newRelatedPostIds);
|
$relatedPosts = $this->postDao->findByIds($newRelatedPostIds);
|
||||||
foreach ($newRelatedPostIds as $postId)
|
foreach ($newRelatedPostIds as $postId)
|
||||||
|
{
|
||||||
if (!isset($relatedPosts[$postId]))
|
if (!isset($relatedPosts[$postId]))
|
||||||
throw new \DomainException('Post with id "' . $postId . '" was not found.');
|
throw new \DomainException('Post with id "' . $postId . '" was not found.');
|
||||||
|
}
|
||||||
|
|
||||||
$post->setRelatedPosts($relatedPosts);
|
$post->setRelatedPosts($relatedPosts);
|
||||||
}
|
}
|
||||||
|
@ -256,6 +286,7 @@ class PostService
|
||||||
{
|
{
|
||||||
$transactionFunc = function() use ($post)
|
$transactionFunc = function() use ($post)
|
||||||
{
|
{
|
||||||
|
$this->historyService->saveSnapshot($this->historyService->getPostDeleteSnapshot($post));
|
||||||
$this->postDao->deleteById($post->getId());
|
$this->postDao->deleteById($post->getId());
|
||||||
};
|
};
|
||||||
$this->transactionManager->commit($transactionFunc);
|
$this->transactionManager->commit($transactionFunc);
|
||||||
|
@ -265,6 +296,8 @@ class PostService
|
||||||
{
|
{
|
||||||
$transactionFunc = function() use ($post)
|
$transactionFunc = function() use ($post)
|
||||||
{
|
{
|
||||||
|
$previousFeaturedPost = $this->getFeatured();
|
||||||
|
|
||||||
$post->setLastFeatureTime($this->timeService->getCurrentTime());
|
$post->setLastFeatureTime($this->timeService->getCurrentTime());
|
||||||
$post->setFeatureCount($post->getFeatureCount() + 1);
|
$post->setFeatureCount($post->getFeatureCount() + 1);
|
||||||
$this->postDao->save($post);
|
$this->postDao->save($post);
|
||||||
|
@ -272,6 +305,10 @@ class PostService
|
||||||
$globalParam->setKey(\Szurubooru\Entities\GlobalParam::KEY_FEATURED_POST);
|
$globalParam->setKey(\Szurubooru\Entities\GlobalParam::KEY_FEATURED_POST);
|
||||||
$globalParam->setValue($post->getId());
|
$globalParam->setValue($post->getId());
|
||||||
$this->globalParamDao->save($globalParam);
|
$this->globalParamDao->save($globalParam);
|
||||||
|
|
||||||
|
if ($previousFeaturedPost)
|
||||||
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($previousFeaturedPost));
|
||||||
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
|
||||||
};
|
};
|
||||||
$this->transactionManager->commit($transactionFunc);
|
$this->transactionManager->commit($transactionFunc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,4 +16,3 @@ class Upgrade08 implements IUpgrade
|
||||||
)');
|
)');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
40
src/Upgrades/Upgrade09.php
Normal file
40
src/Upgrades/Upgrade09.php
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Upgrades;
|
||||||
|
|
||||||
|
class Upgrade09 implements IUpgrade
|
||||||
|
{
|
||||||
|
private $postDao;
|
||||||
|
private $historyService;
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
\Szurubooru\Dao\PostDao $postDao,
|
||||||
|
\Szurubooru\Services\HistoryService $historyService)
|
||||||
|
{
|
||||||
|
$this->postDao = $postDao;
|
||||||
|
$this->historyService = $historyService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function run(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||||
|
{
|
||||||
|
$pdo = $databaseConnection->getPDO();
|
||||||
|
|
||||||
|
$pdo->exec('DROP TABLE IF EXISTS snapshots');
|
||||||
|
|
||||||
|
$pdo->exec('CREATE TABLE snapshots
|
||||||
|
(
|
||||||
|
id INTEGER PRIMARY KEY NOT NULL,
|
||||||
|
time TIMESTAMP NOT NULL,
|
||||||
|
type INTEGER NOT NULL,
|
||||||
|
primaryKey TEXT NOT NULL,
|
||||||
|
operation INTEGER NOT NULL,
|
||||||
|
userId INTEGER,
|
||||||
|
data BLOB,
|
||||||
|
dataDifference BLOB
|
||||||
|
)');
|
||||||
|
|
||||||
|
foreach ($this->postDao->findAll() as $post)
|
||||||
|
{
|
||||||
|
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ return [
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade06::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade06::class),
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade07::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade07::class),
|
||||||
$container->get(\Szurubooru\Upgrades\Upgrade08::class),
|
$container->get(\Szurubooru\Upgrades\Upgrade08::class),
|
||||||
|
$container->get(\Szurubooru\Upgrades\Upgrade09::class),
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ return [
|
||||||
$container->get(\Szurubooru\Controllers\PostController::class),
|
$container->get(\Szurubooru\Controllers\PostController::class),
|
||||||
$container->get(\Szurubooru\Controllers\PostContentController::class),
|
$container->get(\Szurubooru\Controllers\PostContentController::class),
|
||||||
$container->get(\Szurubooru\Controllers\GlobalParamController::class),
|
$container->get(\Szurubooru\Controllers\GlobalParamController::class),
|
||||||
|
$container->get(\Szurubooru\Controllers\HistoryController::class),
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
|
|
55
tests/Dao/SnapshotDaoTest.php
Normal file
55
tests/Dao/SnapshotDaoTest.php
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Tests\Dao;
|
||||||
|
|
||||||
|
class SnapshotDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
||||||
|
{
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSaving()
|
||||||
|
{
|
||||||
|
$snapshot = $this->getTestSnapshot();
|
||||||
|
$snapshotDao = $this->getSnapshotDao();
|
||||||
|
$snapshotDao->save($snapshot);
|
||||||
|
$this->assertNotNull($snapshot->getId());
|
||||||
|
$this->assertEntitiesEqual($snapshot, $snapshotDao->findById($snapshot->getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUserLazyLoader()
|
||||||
|
{
|
||||||
|
$snapshot = $this->getTestSnapshot();
|
||||||
|
$snapshot->setUser(new \Szurubooru\Entities\User(5));
|
||||||
|
$this->assertEquals(5, $snapshot->getUserId());
|
||||||
|
$snapshotDao = $this->getSnapshotDao();
|
||||||
|
$snapshotDao->save($snapshot);
|
||||||
|
$savedSnapshot = $snapshotDao->findById($snapshot->getId());
|
||||||
|
$this->assertEquals(5, $savedSnapshot->getUserId());
|
||||||
|
|
||||||
|
$this->userDaoMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('findById');
|
||||||
|
$savedSnapshot->getUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getTestSnapshot()
|
||||||
|
{
|
||||||
|
$snapshot = new \Szurubooru\Entities\Snapshot();
|
||||||
|
$snapshot->setType(\Szurubooru\Entities\Snapshot::TYPE_POST);
|
||||||
|
$snapshot->setData(['wake up', 'neo', ['follow' => 'white rabbit']]);
|
||||||
|
$snapshot->setPrimaryKey(1);
|
||||||
|
$snapshot->setTime('whateveer');
|
||||||
|
$snapshot->setUserId(null);
|
||||||
|
$snapshot->setOperation(\Szurubooru\Entities\Snapshot::OPERATION_CHANGE);
|
||||||
|
return $snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getSnapshotDao()
|
||||||
|
{
|
||||||
|
return new \Szurubooru\Dao\SnapshotDao(
|
||||||
|
$this->databaseConnection,
|
||||||
|
$this->userDaoMock);
|
||||||
|
}
|
||||||
|
}
|
183
tests/Services/HistoryServiceTest.php
Normal file
183
tests/Services/HistoryServiceTest.php
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
<?php
|
||||||
|
namespace Szurubooru\Tests\Services;
|
||||||
|
|
||||||
|
class HistoryServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
|
{
|
||||||
|
private $validatorMock;
|
||||||
|
private $snapshotDaoMock;
|
||||||
|
private $globalParamDaoMock;
|
||||||
|
private $timeServiceMock;
|
||||||
|
private $authServiceMock;
|
||||||
|
private $transactionManagerMock;
|
||||||
|
|
||||||
|
public static function snapshotDataDifferenceProvider()
|
||||||
|
{
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
[],
|
||||||
|
[],
|
||||||
|
['+' => [], '-' => []]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => 'unchangedValue'],
|
||||||
|
['key' => 'unchangedValue'],
|
||||||
|
['+' => [], '-' => []]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => 'newValue'],
|
||||||
|
[],
|
||||||
|
[
|
||||||
|
'+' => [['key', 'newValue']],
|
||||||
|
'-' => []
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
[],
|
||||||
|
['key' => 'deletedValue'],
|
||||||
|
[
|
||||||
|
'+' => [],
|
||||||
|
'-' => [['key', 'deletedValue']]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => 'changedValue'],
|
||||||
|
['key' => 'oldValue'],
|
||||||
|
[
|
||||||
|
'+' => [['key', 'changedValue']],
|
||||||
|
'-' => [['key', 'oldValue']]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => []],
|
||||||
|
['key' => []],
|
||||||
|
[
|
||||||
|
'+' => [],
|
||||||
|
'-' => []
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => ['newArrayElement']],
|
||||||
|
['key' => []],
|
||||||
|
[
|
||||||
|
'+' => [['key', 'newArrayElement']],
|
||||||
|
'-' => []
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => []],
|
||||||
|
['key' => ['removedArrayElement']],
|
||||||
|
[
|
||||||
|
'+' => [],
|
||||||
|
'-' => [['key', 'removedArrayElement']]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
yield
|
||||||
|
[
|
||||||
|
['key' => ['unchangedValue', 'newValue']],
|
||||||
|
['key' => ['unchangedValue', 'oldValue']],
|
||||||
|
[
|
||||||
|
'+' => [['key', 'newValue']],
|
||||||
|
'-' => [['key', 'oldValue']]
|
||||||
|
]
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp()
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
||||||
|
$this->snapshotDaoMock = $this->mock(\Szurubooru\Dao\SnapshotDao::class);
|
||||||
|
$this->globalParamDaoMock = $this->mock(\Szurubooru\Dao\GlobalParamDao::class);
|
||||||
|
$this->transactionManagerMock = $this->mock(\Szurubooru\Dao\TransactionManager::class);
|
||||||
|
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||||
|
$this->authServiceMock = $this->mock(\Szurubooru\Services\AuthService::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testPostChangeSnapshot()
|
||||||
|
{
|
||||||
|
$tag1 = new \Szurubooru\Entities\Tag();
|
||||||
|
$tag2 = new \Szurubooru\Entities\Tag();
|
||||||
|
$tag1->setName('tag1');
|
||||||
|
$tag2->setName('tag2');
|
||||||
|
$post1 = new \Szurubooru\Entities\Post(1);
|
||||||
|
$post2 = new \Szurubooru\Entities\Post(2);
|
||||||
|
|
||||||
|
$post = new \Szurubooru\Entities\Post(5);
|
||||||
|
$post->setTags([$tag1, $tag2]);
|
||||||
|
$post->setRelatedPosts([$post1, $post2]);
|
||||||
|
$post->setContentChecksum('checksum');
|
||||||
|
$post->setSafety(\Szurubooru\Entities\Post::POST_SAFETY_SKETCHY);
|
||||||
|
$post->setSource('amazing source');
|
||||||
|
|
||||||
|
$historyService = $this->getHistoryService();
|
||||||
|
$snapshot = $historyService->getPostChangeSnapshot($post);
|
||||||
|
|
||||||
|
$this->assertEquals([
|
||||||
|
'source' => 'amazing source',
|
||||||
|
'safety' => 'sketchy',
|
||||||
|
'contentChecksum' => 'checksum',
|
||||||
|
'featured' => false,
|
||||||
|
'tags' => ['tag1', 'tag2'],
|
||||||
|
'relations' => [1, 2]
|
||||||
|
], $snapshot->getData());
|
||||||
|
|
||||||
|
$this->assertEquals(\Szurubooru\Entities\Snapshot::TYPE_POST, $snapshot->getType());
|
||||||
|
$this->assertEquals(5, $snapshot->getPrimaryKey());
|
||||||
|
|
||||||
|
return $post;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testPostChangeSnapshot
|
||||||
|
*/
|
||||||
|
public function testPostChangeSnapshotFeature($post)
|
||||||
|
{
|
||||||
|
$param = new \Szurubooru\Entities\GlobalParam;
|
||||||
|
$param->setValue($post->getId());
|
||||||
|
$this->globalParamDaoMock
|
||||||
|
->expects($this->once())
|
||||||
|
->method('findByKey')
|
||||||
|
->with(\Szurubooru\Entities\GlobalParam::KEY_FEATURED_POST)
|
||||||
|
->willReturn($param);
|
||||||
|
|
||||||
|
$historyService = $this->getHistoryService();
|
||||||
|
$snapshot = $historyService->getPostChangeSnapshot($post);
|
||||||
|
|
||||||
|
$this->assertTrue($snapshot->getData()['featured']);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @dataProvider snapshotDataDifferenceProvider
|
||||||
|
*/
|
||||||
|
public function testSnapshotDataDifference($newData, $oldData, $expectedResult)
|
||||||
|
{
|
||||||
|
$historyService = $this->getHistoryService();
|
||||||
|
$this->assertEquals($expectedResult, $historyService->getSnapshotDataDifference($newData, $oldData));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function getHistoryService()
|
||||||
|
{
|
||||||
|
return new \Szurubooru\Services\HistoryService(
|
||||||
|
$this->validatorMock,
|
||||||
|
$this->snapshotDaoMock,
|
||||||
|
$this->globalParamDaoMock,
|
||||||
|
$this->transactionManagerMock,
|
||||||
|
$this->timeServiceMock,
|
||||||
|
$this->authServiceMock);
|
||||||
|
}
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
private $authServiceMock;
|
private $authServiceMock;
|
||||||
private $timeServiceMock;
|
private $timeServiceMock;
|
||||||
private $fileServiceMock;
|
private $fileServiceMock;
|
||||||
|
private $historyServiceMock;
|
||||||
private $imageManipulatorMock;
|
private $imageManipulatorMock;
|
||||||
|
|
||||||
public function setUp()
|
public function setUp()
|
||||||
|
@ -23,6 +24,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->authServiceMock = $this->mock(\Szurubooru\Services\AuthService::class);
|
$this->authServiceMock = $this->mock(\Szurubooru\Services\AuthService::class);
|
||||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||||
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||||
|
$this->historyServiceMock = $this->mock(\Szurubooru\Services\HistoryService::class);
|
||||||
$this->configMock->set('database/maxPostSize', 1000000);
|
$this->configMock->set('database/maxPostSize', 1000000);
|
||||||
$this->imageManipulatorMock = $this->mock(\Szurubooru\Services\ImageManipulation\ImageManipulator::class);
|
$this->imageManipulatorMock = $this->mock(\Szurubooru\Services\ImageManipulation\ImageManipulator::class);
|
||||||
}
|
}
|
||||||
|
@ -37,6 +39,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
|
|
||||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||||
$this->authServiceMock->expects($this->once())->method('getLoggedInUser')->willReturn(new \Szurubooru\Entities\User(5));
|
$this->authServiceMock->expects($this->once())->method('getLoggedInUser')->willReturn(new \Szurubooru\Entities\User(5));
|
||||||
|
$this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new \Szurubooru\Entities\Snapshot());
|
||||||
|
|
||||||
$this->postService = $this->getPostService();
|
$this->postService = $this->getPostService();
|
||||||
$savedPost = $this->postService->createPost($formData);
|
$savedPost = $this->postService->createPost($formData);
|
||||||
|
@ -65,6 +68,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||||
$this->imageManipulatorMock->expects($this->once())->method('getImageWidth')->willReturn(640);
|
$this->imageManipulatorMock->expects($this->once())->method('getImageWidth')->willReturn(640);
|
||||||
$this->imageManipulatorMock->expects($this->once())->method('getImageHeight')->willReturn(480);
|
$this->imageManipulatorMock->expects($this->once())->method('getImageHeight')->willReturn(480);
|
||||||
|
$this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new \Szurubooru\Entities\Snapshot());
|
||||||
|
|
||||||
$this->postService = $this->getPostService();
|
$this->postService = $this->getPostService();
|
||||||
$savedPost = $this->postService->createPost($formData);
|
$savedPost = $this->postService->createPost($formData);
|
||||||
|
@ -85,6 +89,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$formData->contentFileName = 'blah';
|
$formData->contentFileName = 'blah';
|
||||||
|
|
||||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||||
|
$this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new \Szurubooru\Entities\Snapshot());
|
||||||
|
|
||||||
$this->postService = $this->getPostService();
|
$this->postService = $this->getPostService();
|
||||||
$savedPost = $this->postService->createPost($formData);
|
$savedPost = $this->postService->createPost($formData);
|
||||||
|
@ -103,6 +108,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$formData->contentFileName = 'blah';
|
$formData->contentFileName = 'blah';
|
||||||
|
|
||||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||||
|
$this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new \Szurubooru\Entities\Snapshot());
|
||||||
|
|
||||||
$this->postService = $this->getPostService();
|
$this->postService = $this->getPostService();
|
||||||
$savedPost = $this->postService->createPost($formData);
|
$savedPost = $this->postService->createPost($formData);
|
||||||
|
@ -165,6 +171,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
|
|
||||||
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
$this->postDaoMock->expects($this->once())->method('save')->will($this->returnArgument(0));
|
||||||
$this->authServiceMock->expects($this->never())->method('getLoggedInUser');
|
$this->authServiceMock->expects($this->never())->method('getLoggedInUser');
|
||||||
|
$this->historyServiceMock->expects($this->once())->method('getPostChangeSnapshot')->willReturn(new \Szurubooru\Entities\Snapshot());
|
||||||
|
|
||||||
$this->postService = $this->getPostService();
|
$this->postService = $this->getPostService();
|
||||||
$savedPost = $this->postService->createPost($formData);
|
$savedPost = $this->postService->createPost($formData);
|
||||||
|
@ -182,6 +189,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||||
$this->authServiceMock,
|
$this->authServiceMock,
|
||||||
$this->timeServiceMock,
|
$this->timeServiceMock,
|
||||||
$this->fileServiceMock,
|
$this->fileServiceMock,
|
||||||
|
$this->historyServiceMock,
|
||||||
$this->imageManipulatorMock);
|
$this->imageManipulatorMock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue