Added posts listing (closed #7)
This commit is contained in:
parent
15eb2342b9
commit
a16a2d3235
10 changed files with 156 additions and 4 deletions
|
@ -49,5 +49,8 @@ minUserNameLength = 1
|
|||
maxUserNameLength = 32
|
||||
usersPerPage = 20
|
||||
|
||||
[posts]
|
||||
postsPerPage = 40
|
||||
|
||||
[misc]
|
||||
thumbnailCropStyle = outside
|
||||
|
|
26
public_html/css/post-list.css
Normal file
26
public_html/css/post-list.css
Normal file
|
@ -0,0 +1,26 @@
|
|||
#post-list {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#post-list .wrapper {
|
||||
display: inline-block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
#post-list ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#post-list li a {
|
||||
display: block;
|
||||
margin: 0.4em;
|
||||
}
|
||||
#post-list li img {
|
||||
display: block;
|
||||
box-shadow: 0 0 0 1px #999;
|
||||
}
|
|
@ -29,6 +29,7 @@
|
|||
<link rel="stylesheet" type="text/css" href="/css/post-upload.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/user-list.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/user.css"/>
|
||||
<link rel="stylesheet" type="text/css" href="/css/post-list.css"/>
|
||||
<!-- /build -->
|
||||
</head>
|
||||
|
||||
|
|
|
@ -2,26 +2,91 @@ var App = App || {};
|
|||
App.Presenters = App.Presenters || {};
|
||||
|
||||
App.Presenters.PostListPresenter = function(
|
||||
_,
|
||||
jQuery,
|
||||
topNavigationPresenter) {
|
||||
util,
|
||||
promise,
|
||||
auth,
|
||||
router,
|
||||
pagedCollectionPresenter,
|
||||
topNavigationPresenter,
|
||||
messagePresenter) {
|
||||
|
||||
var $el = jQuery('#content');
|
||||
var listTemplate;
|
||||
var itemTemplate;
|
||||
|
||||
function init(args) {
|
||||
topNavigationPresenter.select('posts');
|
||||
topNavigationPresenter.changeTitle('Posts');
|
||||
|
||||
promise.waitAll(
|
||||
util.promiseTemplate('post-list'),
|
||||
util.promiseTemplate('post-list-item')).then(function(listHtml, itemHtml) {
|
||||
listTemplate = _.template(listHtml);
|
||||
itemTemplate = _.template(itemHtml);
|
||||
|
||||
render();
|
||||
reinit(args);
|
||||
});
|
||||
}
|
||||
|
||||
function reinit(args) {
|
||||
var searchArgs = util.parseComplexRouteArgs(args.searchArgs);
|
||||
searchArgs.order = searchArgs.order;
|
||||
|
||||
updateActiveOrder(searchArgs.order);
|
||||
initPaginator(searchArgs);
|
||||
}
|
||||
|
||||
function initPaginator(searchArgs) {
|
||||
pagedCollectionPresenter.init({
|
||||
page: searchArgs.page,
|
||||
searchParams: {order: searchArgs.order},
|
||||
baseUri: '#/posts',
|
||||
backendUri: '/posts',
|
||||
updateCallback: function(data, clear) {
|
||||
renderPosts(data.entities, clear);
|
||||
return $el.find('.pagination-content');
|
||||
},
|
||||
failCallback: function(response) {
|
||||
$el.empty();
|
||||
messagePresenter.showError($el, response.json && response.json.error || response);
|
||||
}});
|
||||
}
|
||||
|
||||
function render() {
|
||||
$el.html('Post list placeholder');
|
||||
$el.html(listTemplate());
|
||||
}
|
||||
|
||||
function updateActiveOrder(activeOrder) {
|
||||
$el.find('.order li a').removeClass('active');
|
||||
$el.find('.order [data-order="' + activeOrder + '"]').addClass('active');
|
||||
}
|
||||
|
||||
function renderPosts(posts, clear) {
|
||||
var $target = $el.find('.posts');
|
||||
|
||||
var all = '';
|
||||
_.each(posts, function(post) {
|
||||
all += itemTemplate({
|
||||
post: post,
|
||||
});
|
||||
});
|
||||
|
||||
if (clear) {
|
||||
$target.html(all);
|
||||
} else {
|
||||
$target.append(all);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
init: init,
|
||||
reinit: reinit,
|
||||
render: render,
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
App.DI.register('postListPresenter', ['jQuery', 'topNavigationPresenter'], App.Presenters.PostListPresenter);
|
||||
App.DI.register('postListPresenter', ['_', 'jQuery', 'util', 'promise', 'auth', 'router', 'pagedCollectionPresenter', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.PostListPresenter);
|
||||
|
|
8
public_html/templates/post-list-item.tpl
Normal file
8
public_html/templates/post-list-item.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
<li class="post post-type-<%= post.contentType %> ">
|
||||
<a class="link"
|
||||
title="<%= _.map(post.tags, function(tag) { return '#' + tag; }).join(', ') %>"
|
||||
href="#/post/<%= post.id %>">
|
||||
|
||||
<img class="thumb" src="/data/thumbnails/160x160/posts/<%= post.name %>" alt="@<%= post.id %>"/>
|
||||
</a>
|
||||
</li>
|
8
public_html/templates/post-list.tpl
Normal file
8
public_html/templates/post-list.tpl
Normal file
|
@ -0,0 +1,8 @@
|
|||
<div id="post-list">
|
||||
<div class="pagination-content">
|
||||
<div class="wrapper">
|
||||
<ul class="posts">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -22,9 +22,21 @@ final class PostController extends AbstractController
|
|||
|
||||
public function registerRoutes(\Szurubooru\Router $router)
|
||||
{
|
||||
$router->get('/api/posts', [$this, 'getFiltered']);
|
||||
$router->post('/api/posts', [$this, 'createPost']);
|
||||
}
|
||||
|
||||
public function getFiltered()
|
||||
{
|
||||
$formData = new \Szurubooru\FormData\SearchFormData($this->inputReader);
|
||||
$searchResult = $this->postService->getFiltered($formData);
|
||||
$entities = $this->postViewProxy->fromArray($searchResult->entities);
|
||||
return [
|
||||
'data' => $entities,
|
||||
'pageSize' => $searchResult->filter->pageSize,
|
||||
'totalRecords' => $searchResult->totalRecords];
|
||||
}
|
||||
|
||||
public function createPost()
|
||||
{
|
||||
$this->privilegeService->assertPrivilege(\Szurubooru\Privilege::UPLOAD_POSTS);
|
||||
|
|
12
src/Dao/Services/PostSearchService.php
Normal file
12
src/Dao/Services/PostSearchService.php
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace Szurubooru\Dao\Services;
|
||||
|
||||
class PostSearchService extends AbstractSearchService
|
||||
{
|
||||
public function __construct(
|
||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
||||
\Szurubooru\Dao\PostDao $postDao)
|
||||
{
|
||||
parent::__construct($databaseConnection, $postDao);
|
||||
}
|
||||
}
|
|
@ -7,6 +7,7 @@ class PostService
|
|||
private $validator;
|
||||
private $transactionManager;
|
||||
private $postDao;
|
||||
private $postSearchService;
|
||||
private $fileService;
|
||||
private $timeService;
|
||||
private $authService;
|
||||
|
@ -16,6 +17,7 @@ class PostService
|
|||
\Szurubooru\Validator $validator,
|
||||
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||
\Szurubooru\Dao\PostDao $postDao,
|
||||
\Szurubooru\Dao\Services\PostSearchService $postSearchService,
|
||||
\Szurubooru\Services\AuthService $authService,
|
||||
\Szurubooru\Services\TimeService $timeService,
|
||||
\Szurubooru\Services\FileService $fileService)
|
||||
|
@ -24,6 +26,7 @@ class PostService
|
|||
$this->validator = $validator;
|
||||
$this->transactionManager = $transactionManager;
|
||||
$this->postDao = $postDao;
|
||||
$this->postSearchService = $postSearchService;
|
||||
$this->fileService = $fileService;
|
||||
$this->timeService = $timeService;
|
||||
$this->authService = $authService;
|
||||
|
@ -41,6 +44,17 @@ class PostService
|
|||
return $this->transactionManager->rollback($transactionFunc);
|
||||
}
|
||||
|
||||
public function getFiltered(\Szurubooru\FormData\SearchFormData $formData)
|
||||
{
|
||||
$transactionFunc = function() use ($formData)
|
||||
{
|
||||
$this->validator->validate($formData);
|
||||
$searchFilter = new \Szurubooru\Dao\SearchFilter($this->config->posts->postsPerPage, $formData);
|
||||
return $this->postSearchService->getFiltered($searchFilter);
|
||||
};
|
||||
return $this->transactionManager->rollback($transactionFunc);
|
||||
}
|
||||
|
||||
public function createPost(\Szurubooru\FormData\UploadFormData $formData)
|
||||
{
|
||||
$transactionFunc = function() use ($formData)
|
||||
|
|
|
@ -7,6 +7,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
private $validatorMock;
|
||||
private $transactionManagerMock;
|
||||
private $postDaoMock;
|
||||
private $postSearchServiceMock;
|
||||
private $authServiceMock;
|
||||
private $timeServiceMock;
|
||||
private $fileServiceMock;
|
||||
|
@ -17,6 +18,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$this->validatorMock = $this->mock(\Szurubooru\Validator::class);
|
||||
$this->transactionManagerMock = $this->mockTransactionManager();
|
||||
$this->postDaoMock = $this->mock(\Szurubooru\Dao\PostDao::class);
|
||||
$this->postSearchServiceMock = $this->mock(\Szurubooru\Dao\Services\PostSearchService::class);
|
||||
$this->authServiceMock = $this->mock(\Szurubooru\Services\AuthService::class);
|
||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||
$this->fileServiceMock = $this->mock(\Szurubooru\Services\FileService::class);
|
||||
|
@ -181,6 +183,7 @@ class PostServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$this->validatorMock,
|
||||
$this->transactionManagerMock,
|
||||
$this->postDaoMock,
|
||||
$this->postSearchServiceMock,
|
||||
$this->authServiceMock,
|
||||
$this->timeServiceMock,
|
||||
$this->fileServiceMock);
|
||||
|
|
Loading…
Reference in a new issue