diff --git a/API.md b/API.md index 5a2c629..40898d6 100644 --- a/API.md +++ b/API.md @@ -19,6 +19,7 @@ - [Updating tag category](#updating-tag-category) - [Getting tag category](#getting-tag-category) - [Deleting tag category](#deleting-tag-category) + - [Setting default tag category](#setting-default-tag-category) - Tags - [Listing tags](#listing-tags) - [Creating tag](#creating-tag) @@ -185,7 +186,8 @@ data. - **Description** Creates a new tag category using specified parameters. Name must match - `tag_category_name_regex` from server's configuration. + `tag_category_name_regex` from server's configuration. First category + created becomes the default category. ## Updating tag category - **Request** @@ -260,6 +262,31 @@ data. Deletes existing tag category. The tag category to be deleted must have no usages. +## Setting default tag category +- **Request** + + `PUT /tag-category//default` + +- **Input** + + ```json5 + {} + ``` + +- **Output** + + A [detailed tag category resource](#detailed-tag-category). + +- **Errors** + + - the tag category does not exist + - privileges are too low + +- **Description** + + Sets given tag category as default. All new tags created manually or + automatically will have this category. + ## Listing tags - **Request** @@ -1405,6 +1432,7 @@ experience. "name": , "color": , "usages": + "default": } ``` @@ -1413,6 +1441,7 @@ experience. - ``: the category name. - ``: the category color. - ``: how many tags is the given category used with. +- ``: whether the tag category is the default one. ## Detailed tag category **Description** @@ -1723,7 +1752,8 @@ A snapshot is a version of a database resource. ```json5 { "name": "character", - "color": "#FF0000" + "color": "#FF0000", + "default": false } ``` diff --git a/config.yaml.dist b/config.yaml.dist index 4effc07..a6c48c8 100644 --- a/config.yaml.dist +++ b/config.yaml.dist @@ -98,6 +98,7 @@ privileges: 'tag_categories:list': anonymous # note: will be available as data_url/tags.json anyway 'tag_categories:view': anonymous 'tag_categories:delete': moderator + 'tag_categories:set_default': moderator 'comments:create': regular 'comments:delete:any': moderator diff --git a/server/szurubooru/api/__init__.py b/server/szurubooru/api/__init__.py index 6649bf7..3f0c7e2 100644 --- a/server/szurubooru/api/__init__.py +++ b/server/szurubooru/api/__init__.py @@ -9,7 +9,8 @@ from szurubooru.api.tag_api import ( TagSiblingsApi) from szurubooru.api.tag_category_api import ( TagCategoryListApi, - TagCategoryDetailApi) + TagCategoryDetailApi, + DefaultTagCategoryApi) from szurubooru.api.comment_api import ( CommentListApi, CommentDetailApi, diff --git a/server/szurubooru/api/tag_category_api.py b/server/szurubooru/api/tag_category_api.py index 2b48b2b..ba1d786 100644 --- a/server/szurubooru/api/tag_category_api.py +++ b/server/szurubooru/api/tag_category_api.py @@ -60,3 +60,13 @@ class TagCategoryDetailApi(BaseApi): ctx.session.commit() tags.export_to_json() return {} + +class DefaultTagCategoryApi(BaseApi): + def put(self, ctx, category_name): + auth.verify_privilege(ctx.user, 'tag_categories:set_default') + category = tag_categories.get_category_by_name(category_name) + tag_categories.set_default_category(category) + snapshots.save_entity_modification(category, ctx.user) + ctx.session.commit() + tags.export_to_json() + return tag_categories.serialize_category_with_details(category) diff --git a/server/szurubooru/app.py b/server/szurubooru/app.py index c73fed5..ec1a131 100644 --- a/server/szurubooru/app.py +++ b/server/szurubooru/app.py @@ -98,6 +98,7 @@ def create_app(): app.add_route('/tag-categories/', api.TagCategoryListApi()) app.add_route('/tag-category/{category_name}', api.TagCategoryDetailApi()) + app.add_route('/tag-category/{category_name}/default', api.DefaultTagCategoryApi()) app.add_route('/tags/', api.TagListApi()) app.add_route('/tag/{tag_name}', api.TagDetailApi()) app.add_route('/tag-merge/', api.TagMergeApi()) diff --git a/server/szurubooru/db/tag_category.py b/server/szurubooru/db/tag_category.py index d82a7c5..43f07ea 100644 --- a/server/szurubooru/db/tag_category.py +++ b/server/szurubooru/db/tag_category.py @@ -1,4 +1,4 @@ -from sqlalchemy import Column, Integer, Unicode, table +from sqlalchemy import Column, Integer, Unicode, Boolean, table from sqlalchemy.orm import column_property from sqlalchemy.sql.expression import func, select from szurubooru.db.base import Base @@ -10,6 +10,7 @@ class TagCategory(Base): tag_category_id = Column('id', Integer, primary_key=True) name = Column('name', Unicode(32), nullable=False) color = Column('color', Unicode(32), nullable=False, default='#000000') + default = Column('default', Boolean, nullable=False, default=False) def __init__(self, name=None): self.name = name diff --git a/server/szurubooru/func/snapshots.py b/server/szurubooru/func/snapshots.py index 44deb62..7fceeea 100644 --- a/server/szurubooru/func/snapshots.py +++ b/server/szurubooru/func/snapshots.py @@ -28,6 +28,7 @@ def get_tag_category_snapshot(category): return { 'name': category.name, 'color': category.color, + 'default': True if category.default else False, } # pylint: disable=invalid-name diff --git a/server/szurubooru/func/tag_categories.py b/server/szurubooru/func/tag_categories.py index b4da67c..6bd7601 100644 --- a/server/szurubooru/func/tag_categories.py +++ b/server/szurubooru/func/tag_categories.py @@ -19,6 +19,7 @@ def serialize_category(category): 'name': category.name, 'color': category.color, 'usages': category.tag_count, + 'default': category.default, } def serialize_category_with_details(category): @@ -31,6 +32,8 @@ def create_category(name, color): category = db.TagCategory() update_category_name(category, name) update_category_color(category, color) + if not get_all_categories(): + category.default = True return category def update_category_name(category, name): @@ -76,14 +79,27 @@ def get_all_categories(): return db.session.query(db.TagCategory).all() def try_get_default_category(): - return db.session \ + category = db.session \ .query(db.TagCategory) \ - .order_by(db.TagCategory.tag_category_id.asc()) \ - .limit(1) \ + .filter(db.TagCategory.default) \ .first() + # if for some reason (e.g. as a result of migration) there's no default + # category, get the first record available. + if not category: + category = db.session \ + .query(db.TagCategory) \ + .order_by(db.TagCategory.tag_category_id.asc()) \ + .first() + return category def get_default_category(): category = try_get_default_category() if not category: raise TagCategoryNotFoundError('No tag category created yet.') return category + +def set_default_category(category): + old_category = try_get_default_category() + if old_category: + old_category.default = False + category.default = True diff --git a/server/szurubooru/migrations/versions/055d0e048fb3_add_default_column_to_tag_categories.py b/server/szurubooru/migrations/versions/055d0e048fb3_add_default_column_to_tag_categories.py new file mode 100644 index 0000000..9c4efc4 --- /dev/null +++ b/server/szurubooru/migrations/versions/055d0e048fb3_add_default_column_to_tag_categories.py @@ -0,0 +1,22 @@ +''' +Add default column to tag categories + +Revision ID: 055d0e048fb3 +Created at: 2016-05-22 18:12:58.149678 +''' + +import sqlalchemy as sa +from alembic import op + +revision = '055d0e048fb3' +down_revision = '49ab4e1139ef' +branch_labels = None +depends_on = None + +def upgrade(): + op.add_column('tag_category', sa.Column('default', sa.Boolean(), nullable=True)) + op.execute(sa.table('tag_category', sa.column('default')).update().values(default=False)) + op.alter_column('tag_category', 'default', nullable=False) + +def downgrade(): + op.drop_column('tag_category', 'default') diff --git a/server/szurubooru/tests/api/test_tag_category_creating.py b/server/szurubooru/tests/api/test_tag_category_creating.py index ba51aa1..a16b5f9 100644 --- a/server/szurubooru/tests/api/test_tag_category_creating.py +++ b/server/szurubooru/tests/api/test_tag_category_creating.py @@ -25,6 +25,7 @@ def test_creating_category(test_ctx): 'name': 'meta', 'color': 'black', 'usages': 0, + 'default': True, } assert len(result['snapshots']) == 1 category = db.session.query(db.TagCategory).one() diff --git a/server/szurubooru/tests/api/test_tag_category_retrieving.py b/server/szurubooru/tests/api/test_tag_category_retrieving.py index e4f6651..3dcdc40 100644 --- a/server/szurubooru/tests/api/test_tag_category_retrieving.py +++ b/server/szurubooru/tests/api/test_tag_category_retrieving.py @@ -42,6 +42,7 @@ def test_retrieving_single(test_ctx): 'name': 'cat', 'color': 'dummy', 'usages': 0, + 'default': False, }, 'snapshots': [], } diff --git a/server/szurubooru/tests/api/test_tag_category_updating.py b/server/szurubooru/tests/api/test_tag_category_updating.py index 15a100a..b6e373b 100644 --- a/server/szurubooru/tests/api/test_tag_category_updating.py +++ b/server/szurubooru/tests/api/test_tag_category_updating.py @@ -41,6 +41,7 @@ def test_simple_updating(test_ctx): 'name': 'changed', 'color': 'white', 'usages': 0, + 'default': False, } assert len(result['snapshots']) == 1 assert tag_categories.try_get_category_by_name('name') is None diff --git a/server/szurubooru/tests/func/test_snapshots.py b/server/szurubooru/tests/func/test_snapshots.py index 64ee47a..c82b82f 100644 --- a/server/szurubooru/tests/func/test_snapshots.py +++ b/server/szurubooru/tests/func/test_snapshots.py @@ -92,6 +92,13 @@ def test_serializing_tag_category(tag_category_factory): assert snapshots.get_tag_category_snapshot(category) == { 'name': 'name', 'color': 'color', + 'default': False, + } + category.default = True + assert snapshots.get_tag_category_snapshot(category) == { + 'name': 'name', + 'color': 'color', + 'default': True, } def test_merging_modification_to_creation(tag_factory, user_factory):