Closed #14
This commit is contained in:
parent
e15910b637
commit
3fc1046bb2
8 changed files with 185 additions and 46 deletions
|
@ -92,3 +92,5 @@ deleteComment.own=registered
|
|||
deleteComment.all=moderator
|
||||
|
||||
listTags=anonymous
|
||||
mergeTags=moderator
|
||||
renameTags=moderator
|
||||
|
|
36
public_html/media/css/tag-list.css
Normal file
36
public_html/media/css/tag-list.css
Normal file
|
@ -0,0 +1,36 @@
|
|||
.tags ul {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
column-width: 14em;
|
||||
-moz-column-width: 14em;
|
||||
-webkit-column-width: 14em;
|
||||
}
|
||||
.tags li {
|
||||
margin: 0.2em 0.5em;
|
||||
text-align: top;
|
||||
width: 14em;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.form-wrapper {
|
||||
width: 50%;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
.small-screen .form-wrapper {
|
||||
width: 100%;
|
||||
}
|
||||
form.aligned {
|
||||
text-align: left;
|
||||
margin: 2em auto;
|
||||
}
|
||||
form.aligned label.left {
|
||||
width: 7em;
|
||||
}
|
||||
form.aligned input {
|
||||
width: 24em;
|
||||
}
|
||||
form h1 {
|
||||
text-align: center;
|
||||
}
|
|
@ -236,7 +236,7 @@ class PostController
|
|||
|
||||
/* tags */
|
||||
$suppliedTags = InputHelper::get('tags');
|
||||
$suppliedTags = Model_Post::validateTags($suppliedTags);
|
||||
$suppliedTags = Model_Tag::validateTags($suppliedTags);
|
||||
$dbTags = Model_Tag::insertOrUpdate($suppliedTags);
|
||||
|
||||
/* source */
|
||||
|
@ -301,7 +301,7 @@ class PostController
|
|||
if (InputHelper::get('tags-token') != $currentToken)
|
||||
throw new SimpleException('Someone else has changed the tags in the meantime');
|
||||
|
||||
$suppliedTags = Model_Post::validateTags($suppliedTags);
|
||||
$suppliedTags = Model_Tag::validateTags($suppliedTags);
|
||||
$dbTags = Model_Tag::insertOrUpdate($suppliedTags);
|
||||
$post->sharedTag = $dbTags;
|
||||
$edited = true;
|
||||
|
|
|
@ -6,6 +6,7 @@ class TagController
|
|||
*/
|
||||
public function listAction()
|
||||
{
|
||||
$this->context->stylesheets []= 'tag-list.css';
|
||||
$this->context->subTitle = 'tags';
|
||||
|
||||
PrivilegesHelper::confirmWithException(Privilege::ListTags);
|
||||
|
@ -16,7 +17,7 @@ class TagController
|
|||
$dbQuery->innerJoin('post_tag');
|
||||
$dbQuery->on('tag.id = post_tag.tag_id');
|
||||
$dbQuery->groupBy('tag.id');
|
||||
$dbQuery->orderBy('count desc, LOWER(tag.name) asc');
|
||||
$dbQuery->orderBy('LOWER(tag.name)')->asc();
|
||||
$rows = $dbQuery->get();
|
||||
|
||||
$tags = [];
|
||||
|
@ -30,4 +31,49 @@ class TagController
|
|||
$this->context->transport->tags = $tags;
|
||||
$this->context->transport->tagDistribution = $tagDistribution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /tags/merge
|
||||
*/
|
||||
public function mergeAction()
|
||||
{
|
||||
PrivilegesHelper::confirmWithException(Privilege::MergeTags);
|
||||
$sourceTag = Model_Tag::locate(InputHelper::get('source-tag'));
|
||||
$targetTag = Model_Tag::locate(InputHelper::get('target-tag'));
|
||||
|
||||
R::preload($sourceTag, 'post');
|
||||
|
||||
foreach ($sourceTag->sharedPost as $post)
|
||||
{
|
||||
foreach ($post->sharedTag as $key => $postTag)
|
||||
if ($postTag->id == $sourceTag->id)
|
||||
unset($post->sharedTag[$key]);
|
||||
$post->sharedTag []= $targetTag;
|
||||
R::store($post);
|
||||
}
|
||||
R::trash($sourceTag);
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('tag', 'list'));
|
||||
$this->view->context->success = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @route /tags/rename
|
||||
*/
|
||||
public function renameAction()
|
||||
{
|
||||
PrivilegesHelper::confirmWithException(Privilege::MergeTags);
|
||||
|
||||
$suppliedSourceTag = InputHelper::get('source-tag');
|
||||
$suppliedSourceTag = Model_Tag::validateTag($suppliedSourceTag);
|
||||
|
||||
$suppliedTargetTag = InputHelper::get('target-tag');
|
||||
$suppliedTargetTag = Model_Tag::validateTag($suppliedTargetTag);
|
||||
|
||||
$sourceTag = Model_Tag::locate($suppliedSourceTag);
|
||||
$sourceTag->name = $suppliedTargetTag;
|
||||
R::store($sourceTag);
|
||||
|
||||
\Chibi\UrlHelper::forward(\Chibi\UrlHelper::route('tag', 'list'));
|
||||
$this->context->transport->success = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,38 +38,4 @@ class Model_Post extends RedBean_SimpleModel
|
|||
|
||||
return $source;
|
||||
}
|
||||
|
||||
|
||||
public static function validateTag($tag)
|
||||
{
|
||||
$tag = trim($tag);
|
||||
|
||||
$minLength = 1;
|
||||
$maxLength = 64;
|
||||
if (strlen($tag) < $minLength)
|
||||
throw new SimpleException('Tag must have at least ' . $minLength . ' characters');
|
||||
if (strlen($tag) > $maxLength)
|
||||
throw new SimpleException('Tag must have at most ' . $maxLength . ' characters');
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/i', $tag))
|
||||
throw new SimpleException('Invalid tag "' . $tag . '"');
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
public static function validateTags($tags)
|
||||
{
|
||||
$tags = trim($tags);
|
||||
$tags = preg_split('/[,;\s]+/', $tags);
|
||||
$tags = array_filter($tags, function($x) { return $x != ''; });
|
||||
$tags = array_unique($tags);
|
||||
|
||||
foreach ($tags as $key => $tag)
|
||||
$tags[$key] = self::validateTag($tag);
|
||||
|
||||
if (empty($tags))
|
||||
throw new SimpleException('No tags set');
|
||||
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
<?php
|
||||
class Model_Tag extends RedBean_SimpleModel
|
||||
{
|
||||
public static function locate($key)
|
||||
{
|
||||
$user = R::findOne('tag', 'name = ?', [$key]);
|
||||
if (!$user)
|
||||
throw new SimpleException('Invalid tag name "' . $key . '"');
|
||||
return $user;
|
||||
}
|
||||
|
||||
public static function insertOrUpdate($tags)
|
||||
{
|
||||
$dbTags = [];
|
||||
|
@ -17,4 +25,37 @@ class Model_Tag extends RedBean_SimpleModel
|
|||
}
|
||||
return $dbTags;
|
||||
}
|
||||
|
||||
public static function validateTag($tag)
|
||||
{
|
||||
$tag = trim($tag);
|
||||
|
||||
$minLength = 1;
|
||||
$maxLength = 64;
|
||||
if (strlen($tag) < $minLength)
|
||||
throw new SimpleException('Tag must have at least ' . $minLength . ' characters');
|
||||
if (strlen($tag) > $maxLength)
|
||||
throw new SimpleException('Tag must have at most ' . $maxLength . ' characters');
|
||||
|
||||
if (!preg_match('/^[a-zA-Z0-9_-]+$/i', $tag))
|
||||
throw new SimpleException('Invalid tag "' . $tag . '"');
|
||||
|
||||
return $tag;
|
||||
}
|
||||
|
||||
public static function validateTags($tags)
|
||||
{
|
||||
$tags = trim($tags);
|
||||
$tags = preg_split('/[,;\s]+/', $tags);
|
||||
$tags = array_filter($tags, function($x) { return $x != ''; });
|
||||
$tags = array_unique($tags);
|
||||
|
||||
foreach ($tags as $key => $tag)
|
||||
$tags[$key] = self::validateTag($tag);
|
||||
|
||||
if (empty($tags))
|
||||
throw new SimpleException('No tags set');
|
||||
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,4 +30,6 @@ class Privilege extends Enum
|
|||
const DeleteComment = 24;
|
||||
|
||||
const ListTags = 21;
|
||||
const MergeTags = 27;
|
||||
const RenameTags = 27;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,55 @@
|
|||
<ul>
|
||||
<?php foreach ($this->context->transport->tagDistribution as $tagName => $count): ?>
|
||||
<li>
|
||||
<a href="<?php echo \Chibi\UrlHelper::route('post', 'list', ['query' => $tagName]) ?>">
|
||||
<?php echo $tagName . ' (' . $count . ')' ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
<div class="tags">
|
||||
<ul>
|
||||
<?php foreach ($this->context->transport->tagDistribution as $tagName => $count): ?>
|
||||
<li class="tag">
|
||||
<a href="<?php echo \Chibi\UrlHelper::route('post', 'list', ['query' => $tagName]) ?>">
|
||||
<?php echo $tagName . ' (' . $count . ')' ?>
|
||||
</a>
|
||||
</li>
|
||||
<?php endforeach ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<?php if (PrivilegesHelper::confirm(Privilege::MergeTags)): ?>
|
||||
<div class="form-wrapper">
|
||||
<form class="aligned" method="post" action="<?php echo \Chibi\UrlHelper::route('tag', 'merge') ?>">
|
||||
<h1>merge tags</h1>
|
||||
<div>
|
||||
<label class="left" for="merge-source-tag">Source tag:</label>
|
||||
<div class="input-wrapper"><input type="text" name="source-tag" id="merge-source-tag"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="left" for="merge-target-tag">Target tag:</label>
|
||||
<div class="input-wrapper"><input type="text" name="target-tag" id="merge-target-tag"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="left"> </label>
|
||||
<button type="submit">Merge!</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
||||
<?php if (PrivilegesHelper::confirm(Privilege::RenameTags)): ?>
|
||||
<div class="form-wrapper">
|
||||
<form class="aligned simple-action" method="post" action="<?php echo \Chibi\UrlHelper::route('tag', 'rename') ?>">
|
||||
<h1>rename tags</h1>
|
||||
<div>
|
||||
<label class="left" for="rename-source-tag">Source tag:</label>
|
||||
<div class="input-wrapper"><input type="text" name="source-tag" id="rename-source-tag"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="left" for="rename-target-tag">Target tag:</label>
|
||||
<div class="input-wrapper"><input type="text" name="target-tag" id="rename-target-tag"></div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="left"> </label>
|
||||
<button type="submit">Rename!</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<?php endif ?>
|
||||
|
|
Loading…
Reference in a new issue