Added tag name changing
This commit is contained in:
parent
74e6e008dc
commit
672185f959
13 changed files with 199 additions and 13 deletions
1
TODO
1
TODO
|
@ -26,7 +26,6 @@ everything related to tags:
|
|||
- basic tags
|
||||
- merging
|
||||
- tag editing
|
||||
- name
|
||||
- category (from config.ini)
|
||||
- description
|
||||
- related tags
|
||||
|
|
|
@ -57,6 +57,7 @@ changePostFlags = regularUser, powerUser, moderator, administrator
|
|||
|
||||
listTags = anonymous, regularUser, powerUser, moderator, administrator
|
||||
massTag = powerUser, moderator, administrator
|
||||
changeTagName = moderator, administrator
|
||||
|
||||
listComments = anonymous, regularUser, powerUser, moderator, administrator
|
||||
addComments = regularUser, powerUser, moderator, administrator
|
||||
|
|
|
@ -17,3 +17,9 @@
|
|||
#tag-view h3 {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
#tag-view form {
|
||||
text-align: left;
|
||||
max-width: 20em;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ App.Auth = function(_, jQuery, util, api, appState, promise) {
|
|||
|
||||
listTags: 'listTags',
|
||||
massTag: 'massTag',
|
||||
changeTagName: 'changeTagName',
|
||||
|
||||
viewHistory: 'viewHistory',
|
||||
};
|
||||
|
|
|
@ -6,19 +6,28 @@ App.Presenters.TagPresenter = function(
|
|||
jQuery,
|
||||
util,
|
||||
promise,
|
||||
auth,
|
||||
api,
|
||||
router,
|
||||
keyboard,
|
||||
topNavigationPresenter) {
|
||||
topNavigationPresenter,
|
||||
messagePresenter) {
|
||||
|
||||
var $el = jQuery('#content');
|
||||
var $messages = $el;
|
||||
var templates = {};
|
||||
|
||||
var tag;
|
||||
var tagName;
|
||||
|
||||
var privileges = {};
|
||||
|
||||
function init(params, loaded) {
|
||||
topNavigationPresenter.select('tags');
|
||||
topNavigationPresenter.changeTitle('Tags');
|
||||
|
||||
privileges.canChangeName = auth.hasPrivilege(auth.privileges.changeTagName);
|
||||
|
||||
promise.wait(
|
||||
util.promiseTemplate('tag'),
|
||||
util.promiseTemplate('post-list-item'))
|
||||
|
@ -33,22 +42,50 @@ App.Presenters.TagPresenter = function(
|
|||
function reinit(params, loaded) {
|
||||
tagName = params.tagName;
|
||||
|
||||
render();
|
||||
loaded();
|
||||
messagePresenter.hideMessages($messages);
|
||||
|
||||
promise.wait(api.get('posts', {query: tagName}))
|
||||
.then(function(response) {
|
||||
var posts = response.json.data;
|
||||
promise.wait(
|
||||
api.get('tags/' + tagName),
|
||||
api.get('posts', {query: tagName}))
|
||||
.then(function(tagResponse, postsResponse) {
|
||||
tag = tagResponse.json;
|
||||
var posts = postsResponse.json.data;
|
||||
posts = posts.slice(0, 8);
|
||||
|
||||
render();
|
||||
loaded();
|
||||
|
||||
renderPosts(posts);
|
||||
}).fail(function(response) {
|
||||
console.log(new Error(response));
|
||||
}).fail(function(tagResponse, postsResponse) {
|
||||
messagePresenter.showError($messages, tagResponse.json.error || postsResponse.json.error);
|
||||
loaded();
|
||||
});
|
||||
}
|
||||
|
||||
function render() {
|
||||
$el.html(templates.tag({tagName: tagName}));
|
||||
$el.html(templates.tag({privileges: privileges, tag: tag, tagName: tagName}));
|
||||
$el.find('.post-list').hide();
|
||||
$el.find('form').submit(editFormSubmitted);
|
||||
}
|
||||
|
||||
function editFormSubmitted(e) {
|
||||
e.preventDefault();
|
||||
var $form = $el.find('form');
|
||||
var formData = {};
|
||||
|
||||
if (privileges.canChangeName) {
|
||||
formData.name = $form.find('[name=name]').val();
|
||||
}
|
||||
|
||||
promise.wait(api.put('/tags/' + tag.name, formData))
|
||||
.then(function(response) {
|
||||
tag = response.json;
|
||||
render();
|
||||
router.navigate('#/tag/' + tag.name);
|
||||
}).fail(function(response) {
|
||||
console.log(response);
|
||||
window.alert('An error occurred');
|
||||
});
|
||||
}
|
||||
|
||||
function renderPosts(posts) {
|
||||
|
@ -76,4 +113,4 @@ App.Presenters.TagPresenter = function(
|
|||
|
||||
};
|
||||
|
||||
App.DI.register('tagPresenter', ['_', 'jQuery', 'util', 'promise', 'api', 'keyboard', 'topNavigationPresenter'], App.Presenters.TagPresenter);
|
||||
App.DI.register('tagPresenter', ['_', 'jQuery', 'util', 'promise', 'auth', 'api', 'router', 'keyboard', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.TagPresenter);
|
||||
|
|
|
@ -3,6 +3,26 @@
|
|||
<h1><%= tagName %></h1>
|
||||
</div>
|
||||
|
||||
<% if (_.any(privileges)) { %>
|
||||
<form class="edit">
|
||||
<% if (privileges.canChangeName) { %>
|
||||
<div class="form-row">
|
||||
<label class="form-label" for="tag-name">Name:</label>
|
||||
<div class="form-input">
|
||||
<input maxlength="200" type="text" name="name" id="tag-name" placeholder="New tag name" value="<%= tag.name %>"/>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<div class="form-row">
|
||||
<label class="form-label"></label>
|
||||
<div class="form-input">
|
||||
<button type="submit">Update</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<% } %>
|
||||
|
||||
<div class="post-list">
|
||||
<h3>Example usages</h3>
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
namespace Szurubooru\Controllers;
|
||||
use Szurubooru\Controllers\ViewProxies\TagViewProxy;
|
||||
use Szurubooru\FormData\TagEditFormData;
|
||||
use Szurubooru\Helpers\InputReader;
|
||||
use Szurubooru\Privilege;
|
||||
use Szurubooru\Router;
|
||||
|
@ -33,6 +34,16 @@ final class TagController extends AbstractController
|
|||
public function registerRoutes(Router $router)
|
||||
{
|
||||
$router->get('/api/tags', [$this, 'getTags']);
|
||||
$router->get('/api/tags/:tagName', [$this, 'getTag']);
|
||||
$router->put('/api/tags/:tagName', [$this, 'updateTag']);
|
||||
}
|
||||
|
||||
public function getTag($tagName)
|
||||
{
|
||||
$this->privilegeService->assertPrivilege(Privilege::LIST_TAGS);
|
||||
|
||||
$tag = $this->tagService->getByName($tagName);
|
||||
return $this->tagViewProxy->fromEntity($tag);
|
||||
}
|
||||
|
||||
public function getTags()
|
||||
|
@ -49,4 +60,16 @@ final class TagController extends AbstractController
|
|||
'pageSize' => $result->getPageSize(),
|
||||
'totalRecords' => $result->getTotalRecords()];
|
||||
}
|
||||
|
||||
public function updateTag($tagName)
|
||||
{
|
||||
$tag = $this->tagService->getByName($tagName);
|
||||
$formData = new TagEditFormData($this->inputReader);
|
||||
|
||||
if ($formData->name !== null)
|
||||
$this->privilegeService->assertPrivilege(Privilege::CHANGE_TAG_NAME);
|
||||
|
||||
$tag = $this->tagService->updateTag($tag, $formData);
|
||||
return $this->tagViewProxy->fromEntity($tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -242,12 +242,15 @@ abstract class AbstractDao implements ICrudDao, IBatchDao
|
|||
$query->where($sql, ...$bindings);
|
||||
}
|
||||
|
||||
protected function arrayToEntities(array $arrayEntities)
|
||||
protected function arrayToEntities(array $arrayEntities, $entityConverter = null)
|
||||
{
|
||||
if ($entityConverter === null)
|
||||
$entityConverter = $this->entityConverter;
|
||||
|
||||
$entities = [];
|
||||
foreach ($arrayEntities as $arrayEntity)
|
||||
{
|
||||
$entity = $this->entityConverter->toEntity($arrayEntity);
|
||||
$entity = $entityConverter->toEntity($arrayEntity);
|
||||
$entities[$entity->getId()] = $entity;
|
||||
}
|
||||
return $entities;
|
||||
|
|
|
@ -52,6 +52,17 @@ class PostDao extends AbstractDao implements ICrudDao
|
|||
return $this->findOneBy('name', $name);
|
||||
}
|
||||
|
||||
public function findByTagName($tagName)
|
||||
{
|
||||
$query = $this->fpdo->from('posts')
|
||||
->disableSmartJoin()
|
||||
->innerJoin('postTags ON postTags.postId = posts.id')
|
||||
->innerJoin('tags ON postTags.tagId = tags.id')
|
||||
->where('tags.name', $tagName);
|
||||
$arrayEntities = iterator_to_array($query);
|
||||
return $this->arrayToEntities($arrayEntities);
|
||||
}
|
||||
|
||||
public function findByContentChecksum($checksum)
|
||||
{
|
||||
return $this->findOneBy('contentChecksum', $checksum);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<?php
|
||||
namespace Szurubooru\Dao;
|
||||
use Szurubooru\Dao\EntityConverters\PostEntityConverter;
|
||||
use Szurubooru\Dao\EntityConverters\TagEntityConverter;
|
||||
use Szurubooru\DatabaseConnection;
|
||||
|
||||
|
@ -13,6 +14,11 @@ class TagDao extends AbstractDao implements ICrudDao
|
|||
new TagEntityConverter());
|
||||
}
|
||||
|
||||
public function findByName($tagName)
|
||||
{
|
||||
return $this->findOneBy('name', $tagName);
|
||||
}
|
||||
|
||||
public function findByNames($tagNames)
|
||||
{
|
||||
return $this->findBy('name', $tagNames);
|
||||
|
|
24
src/FormData/TagEditFormData.php
Normal file
24
src/FormData/TagEditFormData.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
namespace Szurubooru\FormData;
|
||||
use Szurubooru\IValidatable;
|
||||
use Szurubooru\Validator;
|
||||
|
||||
class TagEditFormData implements IValidatable
|
||||
{
|
||||
public $name;
|
||||
|
||||
public function __construct($inputReader = null)
|
||||
{
|
||||
if ($inputReader !== null)
|
||||
{
|
||||
$this->name = $inputReader->name;
|
||||
}
|
||||
}
|
||||
|
||||
public function validate(Validator $validator)
|
||||
{
|
||||
if ($this->name !== null)
|
||||
$validator->validatePostTags([$this->name]);
|
||||
}
|
||||
}
|
||||
|
|
@ -36,6 +36,7 @@ class Privilege
|
|||
|
||||
const LIST_TAGS = 'listTags';
|
||||
const MASS_TAG = 'massTag';
|
||||
const CHANGE_TAG_NAME = 'changeTagName';
|
||||
|
||||
const LIST_COMMENTS = 'listComments';
|
||||
const ADD_COMMENTS = 'addComments';
|
||||
|
|
|
@ -1,31 +1,55 @@
|
|||
<?php
|
||||
namespace Szurubooru\Services;
|
||||
use Szurubooru\Dao\PublicFileDao;
|
||||
use Szurubooru\Dao\PostDao;
|
||||
use Szurubooru\Dao\TagDao;
|
||||
use Szurubooru\Dao\TransactionManager;
|
||||
use Szurubooru\Entities\Tag;
|
||||
use Szurubooru\FormData\TagEditFormData;
|
||||
use Szurubooru\SearchServices\Filters\TagFilter;
|
||||
use Szurubooru\Services\TimeService;
|
||||
use Szurubooru\Validator;
|
||||
|
||||
class TagService
|
||||
{
|
||||
private $validator;
|
||||
private $transactionManager;
|
||||
private $postDao;
|
||||
private $tagDao;
|
||||
private $fileDao;
|
||||
private $timeService;
|
||||
private $historyService;
|
||||
|
||||
public function __construct(
|
||||
Validator $validator,
|
||||
TransactionManager $transactionManager,
|
||||
PostDao $postDao,
|
||||
TagDao $tagDao,
|
||||
PublicFileDao $fileDao,
|
||||
HistoryService $historyService,
|
||||
TimeService $timeService)
|
||||
{
|
||||
$this->validator = $validator;
|
||||
$this->transactionManager = $transactionManager;
|
||||
$this->postDao = $postDao;
|
||||
$this->tagDao = $tagDao;
|
||||
$this->fileDao = $fileDao;
|
||||
$this->historyService = $historyService;
|
||||
$this->timeService = $timeService;
|
||||
}
|
||||
|
||||
public function getByName($tagName)
|
||||
{
|
||||
$transactionFunc = function() use ($tagName)
|
||||
{
|
||||
$tag = $this->tagDao->findByName($tagName);
|
||||
if (!$tag)
|
||||
throw new \InvalidArgumentException('Tag with name "' . $tagName . '" was not found.');
|
||||
return $tag;
|
||||
};
|
||||
return $this->transactionManager->rollback($transactionFunc);
|
||||
}
|
||||
|
||||
public function getFiltered(TagFilter $filter)
|
||||
{
|
||||
$transactionFunc = function() use ($filter)
|
||||
|
@ -96,4 +120,34 @@ class TagService
|
|||
};
|
||||
return $this->transactionManager->commit($transactionFunc);
|
||||
}
|
||||
|
||||
public function updateTag(Tag $tag, TagEditFormData $formData)
|
||||
{
|
||||
$transactionFunc = function() use ($tag, $formData)
|
||||
{
|
||||
$this->validator->validate($formData);
|
||||
|
||||
if ($formData->name !== null)
|
||||
$this->updateTagName($tag, $formData->name);
|
||||
|
||||
return $this->tagDao->save($tag);
|
||||
};
|
||||
$ret = $this->transactionManager->commit($transactionFunc);
|
||||
|
||||
$transactionFunc = function() use ($tag)
|
||||
{
|
||||
$posts = $this->postDao->findByTagName($tag->getName());
|
||||
foreach ($posts as $post)
|
||||
$this->historyService->saveSnapshot($this->historyService->getPostChangeSnapshot($post));
|
||||
};
|
||||
$this->transactionManager->commit($transactionFunc);
|
||||
|
||||
$this->exportJson();
|
||||
return $ret;
|
||||
}
|
||||
|
||||
private function updateTagName(Tag $tag, $newName)
|
||||
{
|
||||
$tag->setName($newName);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue