Added post scoring
This commit is contained in:
parent
23a5a8afeb
commit
6d7566ee2f
20 changed files with 638 additions and 102 deletions
3
TODO
3
TODO
|
@ -3,7 +3,7 @@ first major release.
|
|||
|
||||
everything related to posts:
|
||||
- single post view
|
||||
- score
|
||||
- reduce requests to server
|
||||
- editing
|
||||
- ability to loop video posts
|
||||
- previous and next post (difficult)
|
||||
|
@ -21,7 +21,6 @@ everything related to posts:
|
|||
|
||||
- post listing
|
||||
- better thumbnail loading
|
||||
- score
|
||||
- comment count
|
||||
- regard safety settings
|
||||
- regard disliked settings
|
||||
|
|
|
@ -22,6 +22,7 @@ App.Presenters.PostPresenter = function(
|
|||
var historyTemplate;
|
||||
|
||||
var post;
|
||||
var postScore;
|
||||
var postFavorites;
|
||||
var postHistory;
|
||||
var postNameOrId;
|
||||
|
@ -73,25 +74,39 @@ App.Presenters.PostPresenter = function(
|
|||
function reinit(args, loaded) {
|
||||
postNameOrId = args.postNameOrId;
|
||||
|
||||
refreshPost()
|
||||
.then(function() {
|
||||
topNavigationPresenter.changeTitle('@' + post.id);
|
||||
render();
|
||||
loaded();
|
||||
});
|
||||
}
|
||||
|
||||
function refreshPost() {
|
||||
return promise.make(function(resolve, reject) {
|
||||
promise.waitAll(
|
||||
api.get('/posts/' + postNameOrId),
|
||||
api.get('/posts/' + postNameOrId + '/favorites'),
|
||||
auth.isLoggedIn() ?
|
||||
api.get('/posts/' + postNameOrId + '/score') :
|
||||
null,
|
||||
privileges.canViewHistory ?
|
||||
api.get('/posts/' + postNameOrId + '/history') :
|
||||
null)
|
||||
.then(function(
|
||||
postResponse,
|
||||
postFavoritesResponse,
|
||||
postScoreResponse,
|
||||
postHistoryResponse) {
|
||||
post = postResponse.json;
|
||||
postScore = postScoreResponse && postScoreResponse.json && postScoreResponse.json.score;
|
||||
postFavorites = postFavoritesResponse && postFavoritesResponse.json && postFavoritesResponse.json.data;
|
||||
postHistory = postHistoryResponse && postHistoryResponse.json && postHistoryResponse.json.data;
|
||||
topNavigationPresenter.changeTitle('@' + post.id);
|
||||
render();
|
||||
loaded();
|
||||
resolve();
|
||||
}).fail(function(response) {
|
||||
showGenericError(response);
|
||||
loaded();
|
||||
reject();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -129,6 +144,7 @@ App.Presenters.PostPresenter = function(
|
|||
function renderPostTemplate() {
|
||||
return postTemplate({
|
||||
post: post,
|
||||
ownScore: postScore,
|
||||
postFavorites: postFavorites,
|
||||
postHistory: postHistory,
|
||||
|
||||
|
@ -153,6 +169,8 @@ App.Presenters.PostPresenter = function(
|
|||
$el.find('#sidebar .history').click(historyButtonClicked);
|
||||
$el.find('#sidebar .add-favorite').click(addFavoriteButtonClicked);
|
||||
$el.find('#sidebar .delete-favorite').click(deleteFavoriteButtonClicked);
|
||||
$el.find('#sidebar .score-up').click(scoreUpButtonClicked);
|
||||
$el.find('#sidebar .score-down').click(scoreDownButtonClicked);
|
||||
}
|
||||
|
||||
function deleteButtonClicked(e) {
|
||||
|
@ -300,8 +318,7 @@ App.Presenters.PostPresenter = function(
|
|||
function addFavorite() {
|
||||
api.post('/posts/' + post.id + '/favorites')
|
||||
.then(function(response) {
|
||||
postFavorites = response.json.data;
|
||||
renderSidebar();
|
||||
refreshPost().then(renderSidebar);
|
||||
})
|
||||
.fail(showGenericError);
|
||||
}
|
||||
|
@ -309,8 +326,27 @@ App.Presenters.PostPresenter = function(
|
|||
function deleteFavorite() {
|
||||
api.delete('/posts/' + post.id + '/favorites')
|
||||
.then(function(response) {
|
||||
postFavorites = response.json.data;
|
||||
renderSidebar();
|
||||
refreshPost().then(renderSidebar);
|
||||
})
|
||||
.fail(showGenericError);
|
||||
}
|
||||
|
||||
function scoreUpButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
var $target = jQuery(this);
|
||||
score($target.hasClass('active') ? 0 : 1);
|
||||
}
|
||||
|
||||
function scoreDownButtonClicked(e) {
|
||||
e.preventDefault();
|
||||
var $target = jQuery(this);
|
||||
score($target.hasClass('active') ? 0 : -1);
|
||||
}
|
||||
|
||||
function score(scoreValue) {
|
||||
api.post('/posts/' + post.id + '/score', {score: scoreValue})
|
||||
.then(function() {
|
||||
refreshPost().then(renderSidebar);
|
||||
})
|
||||
.fail(showGenericError);
|
||||
}
|
||||
|
|
|
@ -5,15 +5,22 @@
|
|||
|
||||
<img class="thumb" src="/data/thumbnails/160x160/posts/<%= post.name %>" alt="<%= post.idMarkdown %>"/>
|
||||
|
||||
<% if (post.favoriteCount) { %>
|
||||
<% if (post.favoriteCount || post.score) { %>
|
||||
<div class="info">
|
||||
<ul>
|
||||
<% if (post.favoriteCount) { %>
|
||||
<li>
|
||||
<i class="fa fa-heart"></i>
|
||||
<i class="fa fa-heart-o"></i>
|
||||
<%= post.favoriteCount %>
|
||||
</li>
|
||||
<% } %>
|
||||
|
||||
<% if (post.score) { %>
|
||||
<li>
|
||||
<i class="fa fa-thumbs-o-up"></i>
|
||||
<%= post.score %>
|
||||
</li>
|
||||
<% } %>
|
||||
</ul>
|
||||
</div>
|
||||
<% } %>
|
||||
|
|
|
@ -23,6 +23,26 @@
|
|||
</a>
|
||||
<% } %>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#" class="score-up <% print(ownScore === 1 ? 'active' : '') %>">
|
||||
<% if (ownScore === 1) { %>
|
||||
<i class="fa fa-thumbs-up"></i>
|
||||
<% } else { %>
|
||||
<i class="fa fa-thumbs-o-up"></i>
|
||||
<% } %>
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li>
|
||||
<a href="#" class="score-down <% print(ownScore === -1 ? 'active' : '') %>">
|
||||
<% if (ownScore === -1) { %>
|
||||
<i class="fa fa-thumbs-down"></i>
|
||||
<% } else { %>
|
||||
<i class="fa fa-thumbs-o-down"></i>
|
||||
<% } %>
|
||||
</a>
|
||||
</li>
|
||||
<% } %>
|
||||
</ul>
|
||||
|
||||
|
@ -112,6 +132,10 @@
|
|||
--><% } %><!--
|
||||
--></li>
|
||||
<% } %>
|
||||
|
||||
<li>
|
||||
Score: <%= post.score %>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<% if (_.any(postFavorites)) { %>
|
||||
|
|
50
src/Controllers/PostScoreController.php
Normal file
50
src/Controllers/PostScoreController.php
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
namespace Szurubooru\Controllers;
|
||||
|
||||
class PostScoreController extends AbstractController
|
||||
{
|
||||
private $privilegeService;
|
||||
private $authService;
|
||||
private $postService;
|
||||
private $postScoreService;
|
||||
private $inputReader;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\Services\PrivilegeService $privilegeService,
|
||||
\Szurubooru\Services\AuthService $authService,
|
||||
\Szurubooru\Services\PostService $postService,
|
||||
\Szurubooru\Services\PostScoreService $postScoreService,
|
||||
\Szurubooru\Helpers\InputReader $inputReader)
|
||||
{
|
||||
$this->privilegeService = $privilegeService;
|
||||
$this->authService = $authService;
|
||||
$this->postService = $postService;
|
||||
$this->postScoreService = $postScoreService;
|
||||
$this->inputReader = $inputReader;
|
||||
}
|
||||
|
||||
public function registerRoutes(\Szurubooru\Router $router)
|
||||
{
|
||||
$router->get('/api/posts/:postNameOrId/score', [$this, 'getScore']);
|
||||
$router->post('/api/posts/:postNameOrId/score', [$this, 'setScore']);
|
||||
}
|
||||
|
||||
public function getScore($postNameOrId)
|
||||
{
|
||||
$this->privilegeService->assertLoggedIn();
|
||||
$user = $this->authService->getLoggedInUser();
|
||||
$post = $this->postService->getByNameOrId($postNameOrId);
|
||||
$result = $this->postScoreService->getScore($user, $post);
|
||||
return ['score' => $result ? $result->getScore() : 0];
|
||||
}
|
||||
|
||||
public function setScore($postNameOrId)
|
||||
{
|
||||
$this->privilegeService->assertLoggedIn();
|
||||
$score = intval($this->inputReader->score);
|
||||
$user = $this->authService->getLoggedInUser();
|
||||
$post = $this->postService->getByNameOrId($postNameOrId);
|
||||
$result = $this->postScoreService->setScore($user, $post, $score);
|
||||
return ['score' => $result->getScore()];
|
||||
}
|
||||
}
|
|
@ -40,6 +40,7 @@ class PostViewProxy extends AbstractViewProxy
|
|||
$result->lastFeatureTime = $post->getLastFeatureTime();
|
||||
$result->originalFileSize = $post->getOriginalFileSize();
|
||||
$result->favoriteCount = $post->getFavoriteCount();
|
||||
$result->score = $post->getScore();
|
||||
|
||||
if (!empty($config[self::FETCH_TAGS]))
|
||||
$result->tags = $this->tagViewProxy->fromArray($post->getTags());
|
||||
|
|
|
@ -46,6 +46,7 @@ class PostEntityConverter extends AbstractEntityConverter implements IEntityConv
|
|||
$entity->setLastFeatureTime($array['lastFeatureTime']);
|
||||
$entity->setMeta(\Szurubooru\Entities\Post::META_TAG_COUNT, intval($array['tagCount']));
|
||||
$entity->setMeta(\Szurubooru\Entities\Post::META_FAV_COUNT, intval($array['favCount']));
|
||||
$entity->setMeta(\Szurubooru\Entities\Post::META_SCORE, intval($array['score']));
|
||||
return $entity;
|
||||
}
|
||||
}
|
||||
|
|
27
src/Dao/EntityConverters/PostScoreEntityConverter.php
Normal file
27
src/Dao/EntityConverters/PostScoreEntityConverter.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Szurubooru\Dao\EntityConverters;
|
||||
|
||||
class PostScoreEntityConverter extends AbstractEntityConverter implements IEntityConverter
|
||||
{
|
||||
public function toArray(\Szurubooru\Entities\Entity $entity)
|
||||
{
|
||||
return
|
||||
[
|
||||
'id' => $entity->getId(),
|
||||
'userId' => $entity->getUserId(),
|
||||
'postId' => $entity->getPostId(),
|
||||
'time' => $entity->getTime(),
|
||||
'score' => $entity->getScore(),
|
||||
];
|
||||
}
|
||||
|
||||
public function toBasicEntity(array $array)
|
||||
{
|
||||
$entity = new \Szurubooru\Entities\PostScore($array['id']);
|
||||
$entity->setUserId($array['userId']);
|
||||
$entity->setPostId($array['postId']);
|
||||
$entity->setTime($array['time']);
|
||||
$entity->setScore(intval($array['score']));
|
||||
return $entity;
|
||||
}
|
||||
}
|
|
@ -5,11 +5,13 @@ class FavoritesDao extends AbstractDao implements ICrudDao
|
|||
{
|
||||
private $userDao;
|
||||
private $postDao;
|
||||
private $timeService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
||||
\Szurubooru\Dao\UserDao $userDao,
|
||||
\Szurubooru\Dao\PostDao $postDao)
|
||||
\Szurubooru\Dao\PostDao $postDao,
|
||||
\Szurubooru\Services\TimeService $timeService)
|
||||
{
|
||||
parent::__construct(
|
||||
$databaseConnection,
|
||||
|
@ -18,16 +20,7 @@ class FavoritesDao extends AbstractDao implements ICrudDao
|
|||
|
||||
$this->userDao = $userDao;
|
||||
$this->postDao = $postDao;
|
||||
}
|
||||
|
||||
public function findByUserAndPost(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$query = $this->fpdo->from($this->tableName)
|
||||
->where('userId', $user->getId())
|
||||
->where('postId', $post->getId());
|
||||
$arrayEntities = iterator_to_array($query);
|
||||
$entities = $this->arrayToEntities($arrayEntities);
|
||||
return array_shift($entities);
|
||||
$this->timeService = $timeService;
|
||||
}
|
||||
|
||||
public function findByPost(\Szurubooru\Entities\Post $post)
|
||||
|
@ -35,6 +28,27 @@ class FavoritesDao extends AbstractDao implements ICrudDao
|
|||
return $this->findBy('postId', $post->getId());
|
||||
}
|
||||
|
||||
public function set(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$favorite = $this->get($user, $post);
|
||||
if (!$favorite)
|
||||
{
|
||||
$favorite = new \Szurubooru\Entities\Favorite();
|
||||
$favorite->setUser($user);
|
||||
$favorite->setPost($post);
|
||||
$favorite->setTime($this->timeService->getCurrentTime());
|
||||
$this->save($favorite);
|
||||
}
|
||||
return $favorite;
|
||||
}
|
||||
|
||||
public function delete(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$favorite = $this->get($user, $post);
|
||||
if ($favorite)
|
||||
$this->deleteById($favorite->getId());
|
||||
}
|
||||
|
||||
protected function afterLoad(\Szurubooru\Entities\Entity $favorite)
|
||||
{
|
||||
$favorite->setLazyLoader(
|
||||
|
@ -51,4 +65,14 @@ class FavoritesDao extends AbstractDao implements ICrudDao
|
|||
return $this->postDao->findById($favorite->getPostId());
|
||||
});
|
||||
}
|
||||
|
||||
private function get(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$query = $this->fpdo->from($this->tableName)
|
||||
->where('userId', $user->getId())
|
||||
->where('postId', $post->getId());
|
||||
$arrayEntities = iterator_to_array($query);
|
||||
$entities = $this->arrayToEntities($arrayEntities);
|
||||
return array_shift($entities);
|
||||
}
|
||||
}
|
||||
|
|
67
src/Dao/PostScoreDao.php
Normal file
67
src/Dao/PostScoreDao.php
Normal file
|
@ -0,0 +1,67 @@
|
|||
<?php
|
||||
namespace Szurubooru\Dao;
|
||||
|
||||
class PostScoreDao extends AbstractDao implements ICrudDao
|
||||
{
|
||||
private $userDao;
|
||||
private $postDao;
|
||||
private $timeService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\DatabaseConnection $databaseConnection,
|
||||
\Szurubooru\Dao\UserDao $userDao,
|
||||
\Szurubooru\Dao\PostDao $postDao,
|
||||
\Szurubooru\Services\TimeService $timeService)
|
||||
{
|
||||
parent::__construct(
|
||||
$databaseConnection,
|
||||
'postScores',
|
||||
new \Szurubooru\Dao\EntityConverters\PostScoreEntityConverter());
|
||||
|
||||
$this->userDao = $userDao;
|
||||
$this->postDao = $postDao;
|
||||
$this->timeService = $timeService;
|
||||
}
|
||||
|
||||
public function getScore(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$query = $this->fpdo->from($this->tableName)
|
||||
->where('userId', $user->getId())
|
||||
->where('postId', $post->getId());
|
||||
$arrayEntities = iterator_to_array($query);
|
||||
$entities = $this->arrayToEntities($arrayEntities);
|
||||
return array_shift($entities);
|
||||
}
|
||||
|
||||
public function setScore(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post, $scoreValue)
|
||||
{
|
||||
$postScore = $this->getScore($user, $post);
|
||||
if (!$postScore)
|
||||
{
|
||||
$postScore = new \Szurubooru\Entities\PostScore();
|
||||
$postScore->setUser($user);
|
||||
$postScore->setPost($post);
|
||||
$postScore->setTime($this->timeService->getCurrentTime());
|
||||
}
|
||||
$postScore->setScore($scoreValue);
|
||||
$this->save($postScore);
|
||||
return $postScore;
|
||||
}
|
||||
|
||||
protected function afterLoad(\Szurubooru\Entities\Entity $postScore)
|
||||
{
|
||||
$postScore->setLazyLoader(
|
||||
\Szurubooru\Entities\PostScore::LAZY_LOADER_USER,
|
||||
function (\Szurubooru\Entities\PostScore $postScore)
|
||||
{
|
||||
return $this->userDao->findById($postScore->getUserId());
|
||||
});
|
||||
|
||||
$postScore->setLazyLoader(
|
||||
\Szurubooru\Entities\PostScore::LAZY_LOADER_POST,
|
||||
function (\Szurubooru\Entities\PostScore $postScore)
|
||||
{
|
||||
return $this->postDao->findById($postScore->getPostId());
|
||||
});
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@ final class Post extends Entity
|
|||
|
||||
const META_TAG_COUNT = 'tagCount';
|
||||
const META_FAV_COUNT = 'favCount';
|
||||
const META_SCORE = 'score';
|
||||
|
||||
protected $name;
|
||||
protected $userId;
|
||||
|
@ -263,4 +264,9 @@ final class Post extends Entity
|
|||
{
|
||||
return $this->getMeta(self::META_FAV_COUNT, 0);
|
||||
}
|
||||
|
||||
public function getScore()
|
||||
{
|
||||
return $this->getMeta(self::META_SCORE, 0);
|
||||
}
|
||||
}
|
||||
|
|
75
src/Entities/PostScore.php
Normal file
75
src/Entities/PostScore.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
namespace Szurubooru\Entities;
|
||||
|
||||
class PostScore extends Entity
|
||||
{
|
||||
private $postId;
|
||||
private $userId;
|
||||
private $time;
|
||||
private $score;
|
||||
|
||||
const LAZY_LOADER_USER = 'user';
|
||||
const LAZY_LOADER_POST = 'post';
|
||||
|
||||
public function getUserId()
|
||||
{
|
||||
return $this->userId;
|
||||
}
|
||||
|
||||
public function setUserId($userId)
|
||||
{
|
||||
$this->userId = $userId;
|
||||
}
|
||||
|
||||
public function getPostId()
|
||||
{
|
||||
return $this->postId;
|
||||
}
|
||||
|
||||
public function setPostId($postId)
|
||||
{
|
||||
$this->postId = $postId;
|
||||
}
|
||||
|
||||
public function getTime()
|
||||
{
|
||||
return $this->time;
|
||||
}
|
||||
|
||||
public function setTime($time)
|
||||
{
|
||||
$this->time = $time;
|
||||
}
|
||||
|
||||
public function getScore()
|
||||
{
|
||||
return $this->score;
|
||||
}
|
||||
|
||||
public function setScore($score)
|
||||
{
|
||||
$this->score = $score;
|
||||
}
|
||||
|
||||
public function getUser()
|
||||
{
|
||||
return $this->lazyLoad(self::LAZY_LOADER_USER, null);
|
||||
}
|
||||
|
||||
public function setUser(\Szurubooru\Entities\User $user)
|
||||
{
|
||||
$this->lazySave(self::LAZY_LOADER_USER, $user);
|
||||
$this->userId = $user->getId();
|
||||
}
|
||||
|
||||
public function getPost()
|
||||
{
|
||||
return $this->lazyLoad(self::LAZY_LOADER_POST, null);
|
||||
}
|
||||
|
||||
public function setPost(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$this->lazySave(self::LAZY_LOADER_POST, $post);
|
||||
$this->postId = $post->getId();
|
||||
}
|
||||
}
|
|
@ -4,17 +4,20 @@ namespace Szurubooru\Services;
|
|||
class FavoritesService
|
||||
{
|
||||
private $favoritesDao;
|
||||
private $postScoreDao;
|
||||
private $userDao;
|
||||
private $transactionManager;
|
||||
private $timeService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\Dao\FavoritesDao $favoritesDao,
|
||||
\Szurubooru\Dao\PostScoreDao $postScoreDao,
|
||||
\Szurubooru\Dao\UserDao $userDao,
|
||||
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||
\Szurubooru\Services\TimeService $timeService)
|
||||
{
|
||||
$this->favoritesDao = $favoritesDao;
|
||||
$this->postScoreDao = $postScoreDao;
|
||||
$this->userDao = $userDao;
|
||||
$this->transactionManager = $transactionManager;
|
||||
$this->timeService = $timeService;
|
||||
|
@ -39,15 +42,9 @@ class FavoritesService
|
|||
{
|
||||
$transactionFunc = function() use ($user, $post)
|
||||
{
|
||||
$favorite = $this->favoritesDao->findByUserAndPost($user, $post);
|
||||
if (!$favorite)
|
||||
{
|
||||
$favorite = new \Szurubooru\Entities\Favorite();
|
||||
$favorite->setUser($user);
|
||||
$favorite->setPost($post);
|
||||
$favorite->setTime($this->timeService->getCurrentTime());
|
||||
$this->favoritesDao->save($favorite);
|
||||
}
|
||||
$this->postScoreDao->setScore($user, $post, 1);
|
||||
|
||||
return $this->favoritesDao->set($user, $post);
|
||||
};
|
||||
return $this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
|
@ -56,9 +53,8 @@ class FavoritesService
|
|||
{
|
||||
$transactionFunc = function() use ($user, $post)
|
||||
{
|
||||
$favorite = $this->favoritesDao->findByUserAndPost($user, $post);
|
||||
$this->favoritesDao->deleteById($favorite->getId());
|
||||
$this->favoritesDao->delete($user, $post);
|
||||
};
|
||||
return $this->transactionManager->commit($transactionFunc);
|
||||
$this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
}
|
||||
|
|
49
src/Services/PostScoreService.php
Normal file
49
src/Services/PostScoreService.php
Normal file
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
namespace Szurubooru\Services;
|
||||
|
||||
class PostScoreService
|
||||
{
|
||||
private $postScoreDao;
|
||||
private $favoritesDao;
|
||||
private $userDao;
|
||||
private $transactionManager;
|
||||
private $timeService;
|
||||
|
||||
public function __construct(
|
||||
\Szurubooru\Dao\PostScoreDao $postScoreDao,
|
||||
\Szurubooru\Dao\FavoritesDao $favoritesDao,
|
||||
\Szurubooru\Dao\UserDao $userDao,
|
||||
\Szurubooru\Dao\TransactionManager $transactionManager,
|
||||
\Szurubooru\Services\TimeService $timeService)
|
||||
{
|
||||
$this->postScoreDao = $postScoreDao;
|
||||
$this->favoritesDao = $favoritesDao;
|
||||
$this->userDao = $userDao;
|
||||
$this->transactionManager = $transactionManager;
|
||||
$this->timeService = $timeService;
|
||||
}
|
||||
|
||||
public function getScore(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post)
|
||||
{
|
||||
$transactionFunc = function() use ($user, $post)
|
||||
{
|
||||
return $this->postScoreDao->getScore($user, $post);
|
||||
};
|
||||
return $this->transactionManager->rollback($transactionFunc);
|
||||
}
|
||||
|
||||
public function setScore(\Szurubooru\Entities\User $user, \Szurubooru\Entities\Post $post, $scoreValue)
|
||||
{
|
||||
if ($scoreValue !== 1 and $scoreValue !== 0 and $scoreValue !== -1)
|
||||
throw new \DomainException('Bad score');
|
||||
|
||||
$transactionFunc = function() use ($user, $post, $scoreValue)
|
||||
{
|
||||
if ($scoreValue !== 1)
|
||||
$this->favoritesDao->delete($user, $post);
|
||||
|
||||
return $this->postScoreDao->setScore($user, $post, $scoreValue);
|
||||
};
|
||||
return $this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
}
|
58
src/Upgrades/Upgrade11.php
Normal file
58
src/Upgrades/Upgrade11.php
Normal file
|
@ -0,0 +1,58 @@
|
|||
<?php
|
||||
namespace Szurubooru\Upgrades;
|
||||
|
||||
class Upgrade11 implements IUpgrade
|
||||
{
|
||||
public function run(\Szurubooru\DatabaseConnection $databaseConnection)
|
||||
{
|
||||
$pdo = $databaseConnection->getPDO();
|
||||
|
||||
$pdo->exec('ALTER TABLE posts ADD COLUMN score INTEGER NOT NULL DEFAULT 0');
|
||||
|
||||
$pdo->exec('CREATE TABLE postScores
|
||||
(
|
||||
id INTEGER PRIMARY KEY NOT NULL,
|
||||
userId INTEGER NOT NULL,
|
||||
postId INTEGER NOT NULL,
|
||||
time TIMESTAMP NOT NULL,
|
||||
score INTEGER NOT NULL,
|
||||
UNIQUE (userId, postId)
|
||||
)');
|
||||
|
||||
$pdo->exec('
|
||||
CREATE TRIGGER postScoresDelete AFTER DELETE ON postScores
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE posts SET score = (
|
||||
SELECT SUM(score) FROM postScores
|
||||
WHERE postScores.postId = posts.id)
|
||||
WHERE posts.id = OLD.postId;
|
||||
END');
|
||||
|
||||
$pdo->exec('
|
||||
CREATE TRIGGER postScoresInsert AFTER INSERT ON postScores
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE posts SET score = (
|
||||
SELECT SUM(score) FROM postScores
|
||||
WHERE postScores.postId = posts.id)
|
||||
WHERE posts.id = NEW.postId;
|
||||
END');
|
||||
|
||||
|
||||
$pdo->exec('
|
||||
CREATE TRIGGER postScoresUpdate AFTER UPDATE ON postScores
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
UPDATE posts SET score = (
|
||||
SELECT SUM(score) FROM postScores
|
||||
WHERE postScores.postId = posts.id)
|
||||
WHERE posts.id = OLD.postId;
|
||||
|
||||
UPDATE posts SET score = (
|
||||
SELECT SUM(score) FROM postScores
|
||||
WHERE postScores.postId = posts.id)
|
||||
WHERE posts.id = NEW.postId;
|
||||
END');
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ return [
|
|||
$container->get(\Szurubooru\Upgrades\Upgrade08::class),
|
||||
$container->get(\Szurubooru\Upgrades\Upgrade09::class),
|
||||
$container->get(\Szurubooru\Upgrades\Upgrade10::class),
|
||||
$container->get(\Szurubooru\Upgrades\Upgrade11::class),
|
||||
];
|
||||
}),
|
||||
|
||||
|
@ -39,6 +40,7 @@ return [
|
|||
$container->get(\Szurubooru\Controllers\GlobalParamController::class),
|
||||
$container->get(\Szurubooru\Controllers\HistoryController::class),
|
||||
$container->get(\Szurubooru\Controllers\FavoritesController::class),
|
||||
$container->get(\Szurubooru\Controllers\PostScoreController::class),
|
||||
];
|
||||
}),
|
||||
];
|
||||
|
|
|
@ -5,12 +5,14 @@ class FavoritesDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
{
|
||||
private $userDaoMock;
|
||||
private $postDaoMock;
|
||||
private $timeServiceMock;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||
$this->postDaoMock = $this->mock(\Szurubooru\Dao\PostDao::class);
|
||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||
}
|
||||
|
||||
public function testSaving()
|
||||
|
@ -39,39 +41,6 @@ class FavoritesDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
$this->assertEntitiesEqual($post, $savedFavorite->getPost());
|
||||
}
|
||||
|
||||
public function testFindingByUserAndPost()
|
||||
{
|
||||
$post1 = new \Szurubooru\Entities\Post(1);
|
||||
$post2 = new \Szurubooru\Entities\Post(2);
|
||||
$user1 = new \Szurubooru\Entities\User(3);
|
||||
$user2 = new \Szurubooru\Entities\User(4);
|
||||
|
||||
$fav1 = new \Szurubooru\Entities\Favorite();
|
||||
$fav1->setUser($user1);
|
||||
$fav1->setPost($post1);
|
||||
$fav1->setTime('time1');
|
||||
|
||||
$fav2 = new \Szurubooru\Entities\Favorite();
|
||||
$fav2->setUser($user2);
|
||||
$fav2->setPost($post2);
|
||||
$fav2->setTime('time2');
|
||||
|
||||
$fav3 = new \Szurubooru\Entities\Favorite();
|
||||
$fav3->setUser($user1);
|
||||
$fav3->setPost($post2);
|
||||
$fav3->setTime('time3');
|
||||
|
||||
$favoritesDao = $this->getFavoritesDao();
|
||||
$favoritesDao->save($fav1);
|
||||
$favoritesDao->save($fav2);
|
||||
$favoritesDao->save($fav3);
|
||||
|
||||
$this->assertEntitiesEqual($fav1, $favoritesDao->findByUserAndPost($user1, $post1));
|
||||
$this->assertEntitiesEqual($fav2, $favoritesDao->findByUserAndPost($user2, $post2));
|
||||
$this->assertEntitiesEqual($fav3, $favoritesDao->findByUserAndPost($user1, $post2));
|
||||
$this->assertNull($favoritesDao->findByUserAndPost($user2, $post1));
|
||||
}
|
||||
|
||||
public function findByPost(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return $this->findOneBy('postId', $post->getId());
|
||||
|
@ -82,6 +51,7 @@ class FavoritesDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
|||
return new \Szurubooru\Dao\FavoritesDao(
|
||||
$this->databaseConnection,
|
||||
$this->userDaoMock,
|
||||
$this->postDaoMock);
|
||||
$this->postDaoMock,
|
||||
$this->timeServiceMock);
|
||||
}
|
||||
}
|
||||
|
|
94
tests/Dao/PostScoreDaoTest.php
Normal file
94
tests/Dao/PostScoreDaoTest.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
namespace Szurubooru\Tests\Dao;
|
||||
|
||||
class PostScoreDaoTest extends \Szurubooru\Tests\AbstractDatabaseTestCase
|
||||
{
|
||||
private $userDaoMock;
|
||||
private $postDaoMock;
|
||||
private $timeServiceMock;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||
$this->postDaoMock = $this->mock(\Szurubooru\Dao\PostDao::class);
|
||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||
}
|
||||
|
||||
public function testSaving()
|
||||
{
|
||||
$user = new \Szurubooru\Entities\User(1);
|
||||
$user->setName('olivia');
|
||||
|
||||
$post = new \Szurubooru\Entities\Post(2);
|
||||
$post->setName('sword');
|
||||
|
||||
$postScore = new \Szurubooru\Entities\PostScore();
|
||||
$postScore->setUser($user);
|
||||
$postScore->setPost($post);
|
||||
$postScore->setTime('whatever');
|
||||
$postScore->setScore(1);
|
||||
$postScoreDao = $this->getPostScoreDao();
|
||||
$postScoreDao->save($postScore);
|
||||
|
||||
$this->userDaoMock->expects($this->once())->method('findById')->with(1)->willReturn($user);
|
||||
$this->postDaoMock->expects($this->once())->method('findById')->with(2)->willReturn($post);
|
||||
|
||||
$savedPostScore = $postScoreDao->findById($postScore->getId());
|
||||
$this->assertEquals(1, $savedPostScore->getUserId());
|
||||
$this->assertEquals(2, $savedPostScore->getPostId());
|
||||
$this->assertEquals('whatever', $savedPostScore->getTime());
|
||||
$this->assertEntitiesEqual($user, $savedPostScore->getUser());
|
||||
$this->assertEntitiesEqual($post, $savedPostScore->getPost());
|
||||
}
|
||||
|
||||
public function testFindingByUserAndPost()
|
||||
{
|
||||
$post1 = new \Szurubooru\Entities\Post(1);
|
||||
$post2 = new \Szurubooru\Entities\Post(2);
|
||||
$user1 = new \Szurubooru\Entities\User(3);
|
||||
$user2 = new \Szurubooru\Entities\User(4);
|
||||
|
||||
$postScore1 = new \Szurubooru\Entities\PostScore();
|
||||
$postScore1->setUser($user1);
|
||||
$postScore1->setPost($post1);
|
||||
$postScore1->setTime('time1');
|
||||
$postScore1->setScore(1);
|
||||
|
||||
$postScore2 = new \Szurubooru\Entities\PostScore();
|
||||
$postScore2->setUser($user2);
|
||||
$postScore2->setPost($post2);
|
||||
$postScore2->setTime('time2');
|
||||
$postScore2->setScore(0);
|
||||
|
||||
$postScore3 = new \Szurubooru\Entities\PostScore();
|
||||
$postScore3->setUser($user1);
|
||||
$postScore3->setPost($post2);
|
||||
$postScore3->setTime('time3');
|
||||
$postScore3->setScore(-1);
|
||||
|
||||
$postScoreDao = $this->getPostScoreDao();
|
||||
$postScoreDao->save($postScore1);
|
||||
$postScoreDao->save($postScore2);
|
||||
$postScoreDao->save($postScore3);
|
||||
|
||||
$this->assertEntitiesEqual($postScore1, $postScoreDao->getScore($user1, $post1));
|
||||
$this->assertEntitiesEqual($postScore2, $postScoreDao->getScore($user2, $post2));
|
||||
$this->assertEntitiesEqual($postScore3, $postScoreDao->getScore($user1, $post2));
|
||||
$this->assertNull($postScoreDao->getScore($user2, $post1));
|
||||
}
|
||||
|
||||
public function findByPost(\Szurubooru\Entities\Post $post)
|
||||
{
|
||||
return $this->findOneBy('postId', $post->getId());
|
||||
}
|
||||
|
||||
private function getPostScoreDao()
|
||||
{
|
||||
return new \Szurubooru\Dao\PostScoreDao(
|
||||
$this->databaseConnection,
|
||||
$this->userDaoMock,
|
||||
$this->postDaoMock,
|
||||
$this->timeServiceMock);
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ namespace Szurubooru\Tests\Services;
|
|||
final class FavoritesServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||
{
|
||||
private $favoritesDaoMock;
|
||||
private $postScoreDaoMock;
|
||||
private $userDaoMock;
|
||||
private $transactionManagerMock;
|
||||
private $timeServiceMock;
|
||||
|
@ -12,23 +13,12 @@ final class FavoritesServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
{
|
||||
parent::setUp();
|
||||
$this->favoritesDaoMock = $this->mock(\Szurubooru\Dao\FavoritesDao::class);
|
||||
$this->postScoreDaoMock = $this->mock(\Szurubooru\Dao\PostScoreDao::class);
|
||||
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||
$this->transactionManagerMock = $this->mockTransactionManager();
|
||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||
}
|
||||
|
||||
public function testAddingExisting()
|
||||
{
|
||||
$user = new \Szurubooru\Entities\User();
|
||||
$post = new \Szurubooru\Entities\Post();
|
||||
$fav = new \Szurubooru\Entities\Favorite(3);
|
||||
$this->favoritesDaoMock->expects($this->once())->method('findByUserAndPost')->with($user, $post)->willReturn($fav);
|
||||
$this->favoritesDaoMock->expects($this->never())->method('save');
|
||||
|
||||
$favoritesService = $this->getFavoritesService();
|
||||
$favoritesService->addFavorite($user, $post);
|
||||
}
|
||||
|
||||
public function testAdding()
|
||||
{
|
||||
$user = new \Szurubooru\Entities\User(1);
|
||||
|
@ -36,13 +26,7 @@ final class FavoritesServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$fav = new \Szurubooru\Entities\Favorite();
|
||||
$fav->setUserId($user->getId());
|
||||
$fav->setPostId($post->getId());
|
||||
$this->favoritesDaoMock->expects($this->once())->method('findByUserAndPost')->with($user, $post)->willReturn(null);
|
||||
$this->favoritesDaoMock->expects($this->once())->method('save')->with($this->callback(
|
||||
function($subject) use ($fav)
|
||||
{
|
||||
$this->assertEntitiesEqual($fav, $subject);
|
||||
return true;
|
||||
}));
|
||||
$this->favoritesDaoMock->expects($this->once())->method('set')->with($user, $post);
|
||||
|
||||
$favoritesService = $this->getFavoritesService();
|
||||
$favoritesService->addFavorite($user, $post);
|
||||
|
@ -53,8 +37,7 @@ final class FavoritesServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
$user = new \Szurubooru\Entities\User();
|
||||
$post = new \Szurubooru\Entities\Post();
|
||||
$fav = new \Szurubooru\Entities\Favorite(3);
|
||||
$this->favoritesDaoMock->expects($this->once())->method('findByUserAndPost')->with($user, $post)->willReturn($fav);
|
||||
$this->favoritesDaoMock->expects($this->once())->method('deleteById')->with($fav->getId());
|
||||
$this->favoritesDaoMock->expects($this->once())->method('delete')->with($user, $post);
|
||||
|
||||
$favoritesService = $this->getFavoritesService();
|
||||
$favoritesService->deleteFavorite($user, $post);
|
||||
|
@ -79,6 +62,7 @@ final class FavoritesServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
|||
{
|
||||
return new \Szurubooru\Services\FavoritesService(
|
||||
$this->favoritesDaoMock,
|
||||
$this->postScoreDaoMock,
|
||||
$this->userDaoMock,
|
||||
$this->transactionManagerMock,
|
||||
$this->timeServiceMock);
|
||||
|
|
66
tests/Services/PostScoreServiceTest.php
Normal file
66
tests/Services/PostScoreServiceTest.php
Normal file
|
@ -0,0 +1,66 @@
|
|||
<?php
|
||||
namespace Szurubooru\Tests\Services;
|
||||
|
||||
final class PostScoreServiceTest extends \Szurubooru\Tests\AbstractTestCase
|
||||
{
|
||||
private $postScoreDaoMock;
|
||||
private $favoritesDaoMock;
|
||||
private $userDaoMock;
|
||||
private $transactionManagerMock;
|
||||
private $timeServiceMock;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->postScoreDaoMock = $this->mock(\Szurubooru\Dao\PostScoreDao::class);
|
||||
$this->favoritesDaoMock = $this->mock(\Szurubooru\Dao\FavoritesDao::class);
|
||||
$this->userDaoMock = $this->mock(\Szurubooru\Dao\UserDao::class);
|
||||
$this->transactionManagerMock = $this->mockTransactionManager();
|
||||
$this->timeServiceMock = $this->mock(\Szurubooru\Services\TimeService::class);
|
||||
}
|
||||
|
||||
public function testSetting()
|
||||
{
|
||||
$user = new \Szurubooru\Entities\User(1);
|
||||
$post = new \Szurubooru\Entities\Post(2);
|
||||
$postScore = new \Szurubooru\Entities\PostScore();
|
||||
$postScore->setUserId($user->getId());
|
||||
$postScore->setPostId($post->getId());
|
||||
$postScore->setScore(1);
|
||||
$this->postScoreDaoMock->expects($this->once())->method('setScore')->with($user, $post)->willReturn(null);
|
||||
|
||||
$postScoreService = $this->getPostScoreService();
|
||||
$postScoreService->setScore($user, $post, 1);
|
||||
}
|
||||
|
||||
public function testSettingInvalid()
|
||||
{
|
||||
$user = new \Szurubooru\Entities\User(1);
|
||||
$post = new \Szurubooru\Entities\Post(2);
|
||||
$this->setExpectedException(\Exception::class);
|
||||
$postScoreService = $this->getPostScoreService();
|
||||
$postScoreService->setScore($user, $post, 2);
|
||||
}
|
||||
|
||||
public function testGetting()
|
||||
{
|
||||
$user = new \Szurubooru\Entities\User();
|
||||
$post = new \Szurubooru\Entities\Post();
|
||||
$postScore = new \Szurubooru\Entities\PostScore(3);
|
||||
$this->postScoreDaoMock->expects($this->once())->method('getScore')->with($user, $post)->willReturn($postScore);
|
||||
|
||||
$postScoreService = $this->getPostScoreService();
|
||||
$retrievedScore = $postScoreService->getScore($user, $post);
|
||||
$this->assertEquals($postScore, $retrievedScore);
|
||||
}
|
||||
|
||||
private function getPostScoreService()
|
||||
{
|
||||
return new \Szurubooru\Services\PostScoreService(
|
||||
$this->postScoreDaoMock,
|
||||
$this->favoritesDaoMock,
|
||||
$this->userDaoMock,
|
||||
$this->transactionManagerMock,
|
||||
$this->timeServiceMock);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue