Added post scoring

This commit is contained in:
Marcin Kurczewski 2014-09-28 15:21:25 +02:00
parent 23a5a8afeb
commit 6d7566ee2f
20 changed files with 638 additions and 102 deletions

3
TODO
View file

@ -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

View file

@ -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);
}

View file

@ -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>
<% } %>

View file

@ -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)) { %>

View 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()];
}
}

View file

@ -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());

View file

@ -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;
}
}

View 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;
}
}

View file

@ -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
View 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());
});
}
}

View file

@ -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);
}
}

View 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();
}
}

View file

@ -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);
}
}

View 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);
}
}

View 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');
}
}

View file

@ -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),
];
}),
];

View file

@ -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);
}
}

View 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);
}
}

View file

@ -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);

View 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);
}
}