server/tags: add description field
This commit is contained in:
parent
a6d6aa2f4d
commit
7eec347bca
5
API.md
5
API.md
|
@ -379,6 +379,7 @@ data.
|
||||||
{
|
{
|
||||||
"names": [<name1>, <name2>, ...],
|
"names": [<name1>, <name2>, ...],
|
||||||
"category": <category>,
|
"category": <category>,
|
||||||
|
"description": <description>, // optional
|
||||||
"implications": [<name1>, <name2>, ...], // optional
|
"implications": [<name1>, <name2>, ...], // optional
|
||||||
"suggestions": [<name1>, <name2>, ...] // optional
|
"suggestions": [<name1>, <name2>, ...] // optional
|
||||||
}
|
}
|
||||||
|
@ -421,6 +422,7 @@ data.
|
||||||
{
|
{
|
||||||
"names": [<name1>, <name2>, ...], // optional
|
"names": [<name1>, <name2>, ...], // optional
|
||||||
"category": <category>, // optional
|
"category": <category>, // optional
|
||||||
|
"description": <description>, // optional
|
||||||
"implications": [<name1>, <name2>, ...], // optional
|
"implications": [<name1>, <name2>, ...], // optional
|
||||||
"suggestions": [<name1>, <name2>, ...] // optional
|
"suggestions": [<name1>, <name2>, ...] // optional
|
||||||
}
|
}
|
||||||
|
@ -1514,6 +1516,7 @@ A single tag. Tags are used to let users search for posts.
|
||||||
"creationTime": <creation-time>,
|
"creationTime": <creation-time>,
|
||||||
"lastEditTime": <last-edit-time>,
|
"lastEditTime": <last-edit-time>,
|
||||||
"usages": <usage-count>,
|
"usages": <usage-count>,
|
||||||
|
"description": <description>,
|
||||||
"snapshots": [
|
"snapshots": [
|
||||||
<snapshot>,
|
<snapshot>,
|
||||||
<snapshot>,
|
<snapshot>,
|
||||||
|
@ -1534,6 +1537,8 @@ A single tag. Tags are used to let users search for posts.
|
||||||
- `<creation-time>`: time the tag was created, formatted as per RFC 3339.
|
- `<creation-time>`: time the tag was created, formatted as per RFC 3339.
|
||||||
- `<last-edit-time>`: time the tag was edited, formatted as per RFC 3339.
|
- `<last-edit-time>`: time the tag was edited, formatted as per RFC 3339.
|
||||||
- `<usage-count>`: the number of posts the tag was used in.
|
- `<usage-count>`: the number of posts the tag was used in.
|
||||||
|
- `<description>`: the tag description (instructions how to use, history etc.)
|
||||||
|
The client should render is as Markdown.
|
||||||
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the tag's
|
- `<snapshot>`: a [snapshot resource](#snapshot) that contains the tag's
|
||||||
earlier versions.
|
earlier versions.
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ privileges:
|
||||||
'tags:create': regular
|
'tags:create': regular
|
||||||
'tags:edit:names': power
|
'tags:edit:names': power
|
||||||
'tags:edit:category': power
|
'tags:edit:category': power
|
||||||
|
'tags:edit:description': power
|
||||||
'tags:edit:implications': power
|
'tags:edit:implications': power
|
||||||
'tags:edit:suggestions': power
|
'tags:edit:suggestions': power
|
||||||
'tags:list': regular # note: will be available as data_url/tags.json anyway
|
'tags:list': regular # note: will be available as data_url/tags.json anyway
|
||||||
|
|
|
@ -32,6 +32,8 @@ class TagListApi(BaseApi):
|
||||||
|
|
||||||
names = ctx.get_param_as_list('names', required=True)
|
names = ctx.get_param_as_list('names', required=True)
|
||||||
category = ctx.get_param_as_string('category', required=True)
|
category = ctx.get_param_as_string('category', required=True)
|
||||||
|
description = ctx.get_param_as_string(
|
||||||
|
'description', required=False, default=None)
|
||||||
suggestions = ctx.get_param_as_list(
|
suggestions = ctx.get_param_as_list(
|
||||||
'suggestions', required=False, default=[])
|
'suggestions', required=False, default=[])
|
||||||
implications = ctx.get_param_as_list(
|
implications = ctx.get_param_as_list(
|
||||||
|
@ -41,6 +43,7 @@ class TagListApi(BaseApi):
|
||||||
_create_if_needed(implications, ctx.user)
|
_create_if_needed(implications, ctx.user)
|
||||||
|
|
||||||
tag = tags.create_tag(names, category, suggestions, implications)
|
tag = tags.create_tag(names, category, suggestions, implications)
|
||||||
|
tags.update_tag_description(tag, description)
|
||||||
ctx.session.add(tag)
|
ctx.session.add(tag)
|
||||||
ctx.session.flush()
|
ctx.session.flush()
|
||||||
snapshots.save_entity_creation(tag, ctx.user)
|
snapshots.save_entity_creation(tag, ctx.user)
|
||||||
|
@ -63,6 +66,10 @@ class TagDetailApi(BaseApi):
|
||||||
auth.verify_privilege(ctx.user, 'tags:edit:category')
|
auth.verify_privilege(ctx.user, 'tags:edit:category')
|
||||||
tags.update_tag_category_name(
|
tags.update_tag_category_name(
|
||||||
tag, ctx.get_param_as_string('category'))
|
tag, ctx.get_param_as_string('category'))
|
||||||
|
if ctx.has_param('description'):
|
||||||
|
auth.verify_privilege(ctx.user, 'tags:edit:description')
|
||||||
|
tags.update_tag_description(
|
||||||
|
tag, ctx.get_param_as_string('description', default=None))
|
||||||
if ctx.has_param('suggestions'):
|
if ctx.has_param('suggestions'):
|
||||||
auth.verify_privilege(ctx.user, 'tags:edit:suggestions')
|
auth.verify_privilege(ctx.user, 'tags:edit:suggestions')
|
||||||
suggestions = ctx.get_param_as_list('suggestions')
|
suggestions = ctx.get_param_as_list('suggestions')
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
from sqlalchemy import Column, Integer, DateTime, Unicode, ForeignKey
|
from sqlalchemy import Column, Integer, DateTime, Unicode, UnicodeText, ForeignKey
|
||||||
from sqlalchemy.orm import relationship, column_property
|
from sqlalchemy.orm import relationship, column_property
|
||||||
from sqlalchemy.sql.expression import func, select
|
from sqlalchemy.sql.expression import func, select
|
||||||
from szurubooru.db.base import Base
|
from szurubooru.db.base import Base
|
||||||
|
@ -46,6 +46,7 @@ class Tag(Base):
|
||||||
'category_id', Integer, ForeignKey('tag_category.id'), nullable=False, index=True)
|
'category_id', Integer, ForeignKey('tag_category.id'), nullable=False, index=True)
|
||||||
creation_time = Column('creation_time', DateTime, nullable=False)
|
creation_time = Column('creation_time', DateTime, nullable=False)
|
||||||
last_edit_time = Column('last_edit_time', DateTime)
|
last_edit_time = Column('last_edit_time', DateTime)
|
||||||
|
description = Column('description', UnicodeText, default=None)
|
||||||
|
|
||||||
category = relationship('TagCategory', lazy='joined')
|
category = relationship('TagCategory', lazy='joined')
|
||||||
names = relationship(
|
names = relationship(
|
||||||
|
|
|
@ -42,6 +42,7 @@ def serialize_tag(tag, options=None):
|
||||||
{
|
{
|
||||||
'names': lambda: [tag_name.name for tag_name in tag.names],
|
'names': lambda: [tag_name.name for tag_name in tag.names],
|
||||||
'category': lambda: tag.category.name,
|
'category': lambda: tag.category.name,
|
||||||
|
'description': lambda: tag.description,
|
||||||
'creationTime': lambda: tag.creation_time,
|
'creationTime': lambda: tag.creation_time,
|
||||||
'lastEditTime': lambda: tag.last_edit_time,
|
'lastEditTime': lambda: tag.last_edit_time,
|
||||||
'usages': lambda: tag.post_count,
|
'usages': lambda: tag.post_count,
|
||||||
|
@ -218,3 +219,6 @@ def update_tag_suggestions(tag, relations):
|
||||||
if _check_name_intersection(_get_plain_names(tag), relations):
|
if _check_name_intersection(_get_plain_names(tag), relations):
|
||||||
raise InvalidTagRelationError('Tag cannot suggest itself.')
|
raise InvalidTagRelationError('Tag cannot suggest itself.')
|
||||||
tag.suggestions = get_tags_by_names(relations)
|
tag.suggestions = get_tags_by_names(relations)
|
||||||
|
|
||||||
|
def update_tag_description(tag, description):
|
||||||
|
tag.description = description
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
'''
|
||||||
|
Add description to tags
|
||||||
|
|
||||||
|
Revision ID: 4c526f869323
|
||||||
|
Created at: 2016-06-21 17:56:34.979741
|
||||||
|
'''
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
revision = '4c526f869323'
|
||||||
|
down_revision = '055d0e048fb3'
|
||||||
|
branch_labels = None
|
||||||
|
depends_on = None
|
||||||
|
|
||||||
|
def upgrade():
|
||||||
|
op.add_column('tag', sa.Column('description', sa.UnicodeText(), nullable=True))
|
||||||
|
|
||||||
|
def downgrade():
|
||||||
|
op.drop_column('tag', 'description')
|
|
@ -34,6 +34,7 @@ def test_creating_simple_tags(test_ctx, fake_datetime):
|
||||||
input={
|
input={
|
||||||
'names': ['tag1', 'tag2'],
|
'names': ['tag1', 'tag2'],
|
||||||
'category': 'meta',
|
'category': 'meta',
|
||||||
|
'description': 'desc',
|
||||||
'suggestions': [],
|
'suggestions': [],
|
||||||
'implications': [],
|
'implications': [],
|
||||||
},
|
},
|
||||||
|
@ -43,6 +44,7 @@ def test_creating_simple_tags(test_ctx, fake_datetime):
|
||||||
assert result == {
|
assert result == {
|
||||||
'names': ['tag1', 'tag2'],
|
'names': ['tag1', 'tag2'],
|
||||||
'category': 'meta',
|
'category': 'meta',
|
||||||
|
'description': 'desc',
|
||||||
'suggestions': [],
|
'suggestions': [],
|
||||||
'implications': [],
|
'implications': [],
|
||||||
'creationTime': datetime.datetime(1997, 12, 1),
|
'creationTime': datetime.datetime(1997, 12, 1),
|
||||||
|
|
|
@ -38,6 +38,7 @@ def test_merging_without_usages(test_ctx, fake_datetime):
|
||||||
assert result == {
|
assert result == {
|
||||||
'names': ['target'],
|
'names': ['target'],
|
||||||
'category': 'meta',
|
'category': 'meta',
|
||||||
|
'description': None,
|
||||||
'suggestions': [],
|
'suggestions': [],
|
||||||
'implications': [],
|
'implications': [],
|
||||||
'creationTime': datetime.datetime(1996, 1, 1),
|
'creationTime': datetime.datetime(1996, 1, 1),
|
||||||
|
|
|
@ -50,6 +50,7 @@ def test_retrieving_single(test_ctx):
|
||||||
assert result == {
|
assert result == {
|
||||||
'names': ['tag'],
|
'names': ['tag'],
|
||||||
'category': 'dummy',
|
'category': 'dummy',
|
||||||
|
'description': None,
|
||||||
'creationTime': datetime.datetime(1996, 1, 1),
|
'creationTime': datetime.datetime(1996, 1, 1),
|
||||||
'lastEditTime': None,
|
'lastEditTime': None,
|
||||||
'suggestions': [],
|
'suggestions': [],
|
||||||
|
|
|
@ -19,6 +19,7 @@ def test_ctx(
|
||||||
'tags:create': db.User.RANK_REGULAR,
|
'tags:create': db.User.RANK_REGULAR,
|
||||||
'tags:edit:names': db.User.RANK_REGULAR,
|
'tags:edit:names': db.User.RANK_REGULAR,
|
||||||
'tags:edit:category': db.User.RANK_REGULAR,
|
'tags:edit:category': db.User.RANK_REGULAR,
|
||||||
|
'tags:edit:description': db.User.RANK_REGULAR,
|
||||||
'tags:edit:suggestions': db.User.RANK_REGULAR,
|
'tags:edit:suggestions': db.User.RANK_REGULAR,
|
||||||
'tags:edit:implications': db.User.RANK_REGULAR,
|
'tags:edit:implications': db.User.RANK_REGULAR,
|
||||||
},
|
},
|
||||||
|
@ -43,6 +44,7 @@ def test_simple_updating(test_ctx, fake_datetime):
|
||||||
input={
|
input={
|
||||||
'names': ['tag3'],
|
'names': ['tag3'],
|
||||||
'category': 'character',
|
'category': 'character',
|
||||||
|
'description': 'desc',
|
||||||
},
|
},
|
||||||
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)),
|
user=test_ctx.user_factory(rank=db.User.RANK_REGULAR)),
|
||||||
'tag1')
|
'tag1')
|
||||||
|
@ -51,6 +53,7 @@ def test_simple_updating(test_ctx, fake_datetime):
|
||||||
assert result == {
|
assert result == {
|
||||||
'names': ['tag3'],
|
'names': ['tag3'],
|
||||||
'category': 'character',
|
'category': 'character',
|
||||||
|
'description': 'desc',
|
||||||
'suggestions': [],
|
'suggestions': [],
|
||||||
'implications': [],
|
'implications': [],
|
||||||
'creationTime': datetime.datetime(1996, 1, 1),
|
'creationTime': datetime.datetime(1996, 1, 1),
|
||||||
|
@ -91,13 +94,14 @@ def test_trying_to_pass_invalid_input(test_ctx, input, expected_exception):
|
||||||
'tag1')
|
'tag1')
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
'field', ['names', 'category', 'implications', 'suggestions'])
|
'field', ['names', 'category', 'description', 'implications', 'suggestions'])
|
||||||
def test_omitting_optional_field(test_ctx, field):
|
def test_omitting_optional_field(test_ctx, field):
|
||||||
db.session.add(test_ctx.tag_factory(names=['tag'], category_name='meta'))
|
db.session.add(test_ctx.tag_factory(names=['tag'], category_name='meta'))
|
||||||
db.session.commit()
|
db.session.commit()
|
||||||
input = {
|
input = {
|
||||||
'names': ['tag1', 'tag2'],
|
'names': ['tag1', 'tag2'],
|
||||||
'category': 'meta',
|
'category': 'meta',
|
||||||
|
'description': 'desc',
|
||||||
'suggestions': [],
|
'suggestions': [],
|
||||||
'implications': [],
|
'implications': [],
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue