This commit is contained in:
Marcin Kurczewski 2013-10-20 00:31:22 +02:00
parent e15910b637
commit 3fc1046bb2
8 changed files with 185 additions and 46 deletions

View file

@ -92,3 +92,5 @@ deleteComment.own=registered
deleteComment.all=moderator
listTags=anonymous
mergeTags=moderator
renameTags=moderator

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

View file

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

View file

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

View file

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

View file

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

View file

@ -30,4 +30,6 @@ class Privilege extends Enum
const DeleteComment = 24;
const ListTags = 21;
const MergeTags = 27;
const RenameTags = 27;
}

View file

@ -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">&nbsp;</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">&nbsp;</label>
<button type="submit">Rename!</button>
</div>
</form>
</div>
<?php endif ?>