diff --git a/TODO b/TODO
index 0a1a3eda..1747b543 100644
--- a/TODO
+++ b/TODO
@@ -2,10 +2,6 @@ This is transient file that lists functionalities to be implemented before
first major release.
everything related to posts:
- - single post view
- - editing
- - ability to loop video posts
-
- ability to paste many urls in post upload
- post notes
diff --git a/data/config.ini b/data/config.ini
index d652ddc2..ba628486 100644
--- a/data/config.ini
+++ b/data/config.ini
@@ -53,6 +53,7 @@ changePostTags = regularUser, powerUser, moderator, administrator
changePostContent = regularUser, powerUser, moderator, administrator
changePostThumbnail = powerUser, moderator, administrator
changePostRelations = regularUser, powerUser, moderator, administrator
+changePostFlags = regularUser, powerUser, moderator, administrator
listTags = anonymous, regularUser, powerUser, moderator, administrator
diff --git a/public_html/js/Auth.js b/public_html/js/Auth.js
index 1ae9f866..993cd6cc 100644
--- a/public_html/js/Auth.js
+++ b/public_html/js/Auth.js
@@ -32,6 +32,7 @@ App.Auth = function(_, jQuery, util, api, appState, promise) {
changePostContent: 'changePostContent',
changePostThumbnail: 'changePostThumbnail',
changePostRelations: 'changePostRelations',
+ changePostFlags: 'changePostFlags',
listComments: 'listComments',
addComments: 'addComments',
diff --git a/public_html/js/Presenters/PostPresenter.js b/public_html/js/Presenters/PostPresenter.js
index 2edef41c..8a3872c7 100644
--- a/public_html/js/Presenters/PostPresenter.js
+++ b/public_html/js/Presenters/PostPresenter.js
@@ -47,6 +47,7 @@ App.Presenters.PostPresenter = function(
editPrivileges.canChangeContent = auth.hasPrivilege(auth.privileges.changePostContent);
editPrivileges.canChangeThumbnail = auth.hasPrivilege(auth.privileges.changePostThumbnail);
editPrivileges.canChangeRelations = auth.hasPrivilege(auth.privileges.changePostRelations);
+ editPrivileges.canChangeFlags = auth.hasPrivilege(auth.privileges.changePostFlags);
promise.wait(
util.promiseTemplate('post'),
@@ -162,6 +163,11 @@ App.Presenters.PostPresenter = function(
attachLinksToPostsAround();
}
+ function softRender() {
+ renderSidebar();
+ $el.find('video').prop('loop', post.flags.loop);
+ }
+
function renderSidebar() {
$el.find('#sidebar').html(jQuery(renderPostTemplate()).find('#sidebar').html());
attachSidebarEvents();
@@ -262,6 +268,7 @@ App.Presenters.PostPresenter = function(
var $form = $el.find('form');
var formData = {};
formData.seenEditTime = post.lastEditTime;
+ formData.flags = {};
if (editPrivileges.canChangeContent && postContent) {
formData.content = postContent;
@@ -287,6 +294,12 @@ App.Presenters.PostPresenter = function(
formData.relations = $form.find('[name=relations]').val();
}
+ if (editPrivileges.canChangeFlags) {
+ if (post.contentType === 'video') {
+ formData.flags.loop = $form.find('[name=loop]').is(':checked') ? 1 : 0;
+ }
+ }
+
if (post.tags.length === 0) {
showEditError('No tags set.');
return;
@@ -296,7 +309,7 @@ App.Presenters.PostPresenter = function(
.then(function(response) {
post = response.json;
hideEditForm();
- renderSidebar();
+ softRender();
}).fail(function(response) {
showEditError(response);
});
@@ -344,14 +357,14 @@ App.Presenters.PostPresenter = function(
function addFavorite() {
promise.wait(api.post('/posts/' + post.id + '/favorites'))
.then(function(response) {
- promise.wait(refreshPost()).then(renderSidebar);
+ promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
function deleteFavorite() {
promise.wait(api.delete('/posts/' + post.id + '/favorites'))
.then(function(response) {
- promise.wait(refreshPost()).then(renderSidebar);
+ promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
@@ -370,7 +383,7 @@ App.Presenters.PostPresenter = function(
function score(scoreValue) {
promise.wait(api.post('/posts/' + post.id + '/score', {score: scoreValue}))
.then(function() {
- promise.wait(refreshPost()).then(renderSidebar);
+ promise.wait(refreshPost()).then(softRender);
}).fail(showGenericError);
}
diff --git a/public_html/templates/post-content.tpl b/public_html/templates/post-content.tpl
index 1b837c2f..cb210a72 100644
--- a/public_html/templates/post-content.tpl
+++ b/public_html/templates/post-content.tpl
@@ -2,15 +2,15 @@
- <% if (post.contentType == 'image') { %>
+ <% if (post.contentType === 'image') { %>
- <% } else if (post.contentType == 'youtube') { %>
+ <% } else if (post.contentType === 'youtube') { %>
- <% } else if (post.contentType == 'flash') { %>
+ <% } else if (post.contentType === 'flash') { %>
- <% } else if (post.contentType == 'video') { %>
+ <% } else if (post.contentType === 'video') { %>
+ <% if (post.flags.loop) { %>
+
<% } %>
+ <% if (privileges.canChangeFlags && post.contentType === 'video') { %>
+
+ <% } %>
+
<% if (privileges.canChangeContent) { %>
diff --git a/src/Controllers/ViewProxies/PostViewProxy.php b/src/Controllers/ViewProxies/PostViewProxy.php
index 31e83bd1..96ab15f7 100644
--- a/src/Controllers/ViewProxies/PostViewProxy.php
+++ b/src/Controllers/ViewProxies/PostViewProxy.php
@@ -8,6 +8,7 @@ use Szurubooru\Services\FavoritesService;
use Szurubooru\Services\HistoryService;
use Szurubooru\Services\PrivilegeService;
use Szurubooru\Services\ScoreService;
+use Szurubooru\Entities\Post;
class PostViewProxy extends AbstractViewProxy
{
@@ -72,6 +73,8 @@ class PostViewProxy extends AbstractViewProxy
$result->favoriteCount = $post->getFavoriteCount();
$result->score = $post->getScore();
$result->commentCount = $post->getCommentCount();
+ $result->flags = new \StdClass;
+ $result->flags->loop = ($post->getFlags() & Post::FLAG_LOOP);
if (!empty($config[self::FETCH_TAGS]))
$result->tags = $this->tagViewProxy->fromArray($post->getTags());
diff --git a/src/Dao/EntityConverters/PostEntityConverter.php b/src/Dao/EntityConverters/PostEntityConverter.php
index d9d89bdf..897bdb45 100644
--- a/src/Dao/EntityConverters/PostEntityConverter.php
+++ b/src/Dao/EntityConverters/PostEntityConverter.php
@@ -25,6 +25,7 @@ class PostEntityConverter extends AbstractEntityConverter implements IEntityConv
'originalFileName' => $entity->getOriginalFileName(),
'featureCount' => $entity->getFeatureCount(),
'lastFeatureTime' => $this->entityTimeToDbTime($entity->getLastFeatureTime()),
+ 'flags' => $entity->getFlags(),
];
}
@@ -46,6 +47,7 @@ class PostEntityConverter extends AbstractEntityConverter implements IEntityConv
$entity->setOriginalFileName($array['originalFileName']);
$entity->setFeatureCount(intval($array['featureCount']));
$entity->setLastFeatureTime($this->dbTimeToEntityTime($array['lastFeatureTime']));
+ $entity->setFlags(intval($array['flags']));
$entity->setMeta(Post::META_TAG_COUNT, intval($array['tagCount']));
$entity->setMeta(Post::META_FAV_COUNT, intval($array['favCount']));
$entity->setMeta(Post::META_COMMENT_COUNT, intval($array['commentCount']));
diff --git a/src/Entities/Post.php b/src/Entities/Post.php
index 661cc4a6..bc6d548b 100644
--- a/src/Entities/Post.php
+++ b/src/Entities/Post.php
@@ -13,6 +13,8 @@ final class Post extends Entity
const POST_TYPE_VIDEO = 3;
const POST_TYPE_YOUTUBE = 4;
+ const FLAG_LOOP = 1;
+
const LAZY_LOADER_USER = 'user';
const LAZY_LOADER_TAGS = 'tags';
const LAZY_LOADER_CONTENT = 'content';
@@ -39,6 +41,7 @@ final class Post extends Entity
private $originalFileName;
private $featureCount = 0;
private $lastFeatureTime;
+ private $flags = 0;
public function getIdMarkdown()
{
@@ -195,6 +198,16 @@ final class Post extends Entity
$this->lastFeatureTime = $lastFeatureTime;
}
+ public function getFlags()
+ {
+ return $this->flags;
+ }
+
+ public function setFlags($flags)
+ {
+ $this->flags = $flags;
+ }
+
public function getTags()
{
return $this->lazyLoad(self::LAZY_LOADER_TAGS, []);
diff --git a/src/FormData/PostEditFormData.php b/src/FormData/PostEditFormData.php
index 9e32775e..63d84de0 100644
--- a/src/FormData/PostEditFormData.php
+++ b/src/FormData/PostEditFormData.php
@@ -12,6 +12,7 @@ class PostEditFormData implements IValidatable
public $source;
public $tags;
public $relations;
+ public $flags;
public $seenEditTime;
@@ -26,6 +27,8 @@ class PostEditFormData implements IValidatable
$this->tags = preg_split('/[\s+]/', $inputReader->tags);
$this->relations = array_filter(preg_split('/[\s+]/', $inputReader->relations));
$this->seenEditTime = $inputReader->seenEditTime;
+ $this->flags = new \StdClass;
+ $this->flags->loop = !empty($inputReader->flags['loop']);
}
}
diff --git a/src/Privilege.php b/src/Privilege.php
index 15eda37a..487dc2f7 100644
--- a/src/Privilege.php
+++ b/src/Privilege.php
@@ -32,6 +32,7 @@ class Privilege
const CHANGE_POST_CONTENT = 'changePostContent';
const CHANGE_POST_THUMBNAIL = 'changePostThumbnail';
const CHANGE_POST_RELATIONS = 'changePostRelations';
+ const CHANGE_POST_FLAGS = 'changePostFlags';
const LIST_TAGS = 'listTags';
diff --git a/src/Services/HistoryService.php b/src/Services/HistoryService.php
index b6511289..3abb5aa8 100644
--- a/src/Services/HistoryService.php
+++ b/src/Services/HistoryService.php
@@ -105,6 +105,10 @@ class HistoryService
$featuredPostParam = $this->globalParamDao->findByKey(GlobalParam::KEY_FEATURED_POST);
$isFeatured = ($featuredPostParam and intval($featuredPostParam->getValue()) === $post->getId());
+ $flags = [];
+ if ($post->getFlags() & Post::FLAG_LOOP)
+ $flags []= 'loop';
+
$data =
[
'source' => $post->getSource(),
@@ -128,6 +132,7 @@ class HistoryService
},
$post->getRelatedPosts()),
+ 'flags' => $flags,
];
$snapshot = $this->getPostSnapshot($post);
diff --git a/src/Services/PostService.php b/src/Services/PostService.php
index 549b018e..acdc86d9 100644
--- a/src/Services/PostService.php
+++ b/src/Services/PostService.php
@@ -188,6 +188,9 @@ class PostService
if ($formData->relations !== null)
$this->updatePostRelations($post, $formData->relations);
+ if (count($formData->flags) > 0)
+ $this->updatePostFlags($post, $formData->flags);
+
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
return $this->postDao->save($post);
};
@@ -313,6 +316,14 @@ class PostService
$post->setRelatedPosts($relatedPosts);
}
+ private function updatePostFlags(Post $post, \StdClass $flags)
+ {
+ $value = 0;
+ if (!empty($flags->loop))
+ $value |= Post::FLAG_LOOP;
+ $post->setFlags($value);
+ }
+
public function deletePost(Post $post)
{
$transactionFunc = function() use ($post)
diff --git a/src/Upgrades/Upgrade19.php b/src/Upgrades/Upgrade19.php
new file mode 100644
index 00000000..02752275
--- /dev/null
+++ b/src/Upgrades/Upgrade19.php
@@ -0,0 +1,13 @@
+getPDO();
+
+ $pdo->exec('ALTER TABLE posts ADD COLUMN flags INT(8) NOT NULL DEFAULT 0');
+ }
+}
diff --git a/src/di.php b/src/di.php
index 1eadc921..1b592b80 100644
--- a/src/di.php
+++ b/src/di.php
@@ -34,6 +34,7 @@ return [
$container->get(\Szurubooru\Upgrades\Upgrade16::class),
$container->get(\Szurubooru\Upgrades\Upgrade17::class),
$container->get(\Szurubooru\Upgrades\Upgrade18::class),
+ $container->get(\Szurubooru\Upgrades\Upgrade19::class),
];
}),
diff --git a/tests/Services/HistoryServiceTest.php b/tests/Services/HistoryServiceTest.php
index 77d02e15..b1c33550 100644
--- a/tests/Services/HistoryServiceTest.php
+++ b/tests/Services/HistoryServiceTest.php
@@ -135,6 +135,7 @@ final class HistoryServiceTest extends AbstractTestCase
$post->setContentChecksum('checksum');
$post->setSafety(Post::POST_SAFETY_SKETCHY);
$post->setSource('amazing source');
+ $post->setFlags(Post::FLAG_LOOP);
$historyService = $this->getHistoryService();
$snapshot = $historyService->getPostChangeSnapshot($post);
@@ -145,7 +146,8 @@ final class HistoryServiceTest extends AbstractTestCase
'contentChecksum' => 'checksum',
'featured' => false,
'tags' => ['tag1', 'tag2'],
- 'relations' => [1, 2]
+ 'relations' => [1, 2],
+ 'flags' => ['loop'],
], $snapshot->getData());
$this->assertEquals(Snapshot::TYPE_POST, $snapshot->getType());