server/tags: add tag deleting

This commit is contained in:
rr- 2016-04-16 17:03:28 +02:00
parent e4239a199c
commit 37a86816af
7 changed files with 99 additions and 13 deletions

36
API.md
View File

@ -17,12 +17,12 @@
- [Creating tag](#creating-tag) - [Creating tag](#creating-tag)
- [Updating tag](#updating-tag) - [Updating tag](#updating-tag)
- [Getting tag](#getting-tag) - [Getting tag](#getting-tag)
- [Removing tag](#removing-tag) - [Deleting tag](#deleting-tag)
- [Listing users](#listing-users) - [Listing users](#listing-users)
- [Creating user](#creating-user) - [Creating user](#creating-user)
- [Updating user](#updating-user) - [Updating user](#updating-user)
- [Getting user](#getting-user) - [Getting user](#getting-user)
- [Removing user](#removing-user) - [Deleting user](#deleting-user)
- [Password reset - step 1: mail request](#password-reset---step-2-confirmation) - [Password reset - step 1: mail request](#password-reset---step-2-confirmation)
- [Password reset - step 2: confirmation](#password-reset---step-2-confirmation) - [Password reset - step 2: confirmation](#password-reset---step-2-confirmation)
@ -183,8 +183,26 @@ Not yet implemented.
Not yet implemented. Not yet implemented.
## Removing tag ## Deleting tag
Not yet implemented. - **Request**
`DELETE /tag/<name>`
- **Output**
```json5
{}
```
- **Errors**
- the tag does not exist
- the tag is used by some posts
- privileges are too low
- **Description**
Deletes existing tag.
## Listing users ## Listing users
@ -253,6 +271,7 @@ Not yet implemented.
None. None.
## Creating user ## Creating user
- **Request** - **Request**
@ -293,7 +312,6 @@ Not yet implemented.
`default_rank` in the server's configuration. `default_rank` in the server's configuration.
## Updating user ## Updating user
- **Request** - **Request**
@ -345,7 +363,6 @@ Not yet implemented.
file - see [file uploads](#file-uploads) for details. file - see [file uploads](#file-uploads) for details.
## Getting user ## Getting user
- **Request** - **Request**
@ -370,8 +387,7 @@ Not yet implemented.
Retrieves information about an existing user. Retrieves information about an existing user.
## Deleting user
## Removing user
- **Request** - **Request**
`DELETE /user/<name>` `DELETE /user/<name>`
@ -392,7 +408,6 @@ Not yet implemented.
Deletes existing user. Deletes existing user.
## Password reset - step 1: mail request ## Password reset - step 1: mail request
- **Request** - **Request**
@ -418,7 +433,6 @@ Not yet implemented.
account. account.
## Password reset - step 2: confirmation ## Password reset - step 2: confirmation
- **Request** - **Request**
@ -483,6 +497,8 @@ Not yet implemented.
} }
``` ```
# Search # Search
Search queries are built of tokens that are separated by spaces. Each token can Search queries are built of tokens that are separated by spaces. Each token can

View File

@ -64,5 +64,16 @@ class TagDetailApi(BaseApi):
ctx.session.commit() ctx.session.commit()
return {'tag': _serialize_tag(tag)} return {'tag': _serialize_tag(tag)}
def delete(self, ctx): def delete(self, ctx, tag_name):
raise NotImplementedError() tag = tags.get_by_name(ctx.session, tag_name)
if not tag:
raise tags.TagNotFoundError('Tag %r not found.' % tag_name)
if tag.post_count > 0:
raise tags.TagIsInUseError(
'Tag has some usages and cannot be deleted. ' +
'Please untag relevant posts first.')
auth.verify_privilege(ctx.user, 'tags:delete')
ctx.session.delete(tag)
ctx.session.commit()
return {}

View File

@ -0,0 +1,59 @@
import pytest
from datetime import datetime
from szurubooru import api, db, errors
from szurubooru.util import misc, tags
@pytest.fixture
def test_ctx(
session, config_injector, context_factory, tag_factory, user_factory):
config_injector({
'privileges': {
'tags:delete': 'regular_user',
},
'ranks': ['anonymous', 'regular_user'],
})
ret = misc.dotdict()
ret.session = session
ret.context_factory = context_factory
ret.user_factory = user_factory
ret.tag_factory = tag_factory
ret.api = api.TagDetailApi()
return ret
def test_removing_tags(test_ctx):
test_ctx.session.add(test_ctx.tag_factory(names=['tag']))
test_ctx.session.commit()
result = test_ctx.api.delete(
test_ctx.context_factory(
user=test_ctx.user_factory(rank='regular_user')),
'tag')
assert result == {}
assert test_ctx.session.query(db.Tag).count() == 0
def test_removing_tags_without_privileges(test_ctx):
test_ctx.session.add(test_ctx.tag_factory(names=['tag']))
test_ctx.session.commit()
with pytest.raises(errors.AuthError):
test_ctx.api.delete(
test_ctx.context_factory(
user=test_ctx.user_factory(rank='anonymous')),
'tag')
assert test_ctx.session.query(db.Tag).count() == 1
def test_removing_tags_with_usages(test_ctx):
tag = test_ctx.tag_factory(names=['tag'])
tag.post_count = 5
test_ctx.session.add(tag)
test_ctx.session.commit()
with pytest.raises(tags.TagIsInUseError):
test_ctx.api.delete(
test_ctx.context_factory(
user=test_ctx.user_factory(rank='regular_user')),
'tag')
assert test_ctx.session.query(db.Tag).count() == 1
def test_removing_non_existing(test_ctx):
with pytest.raises(tags.TagNotFoundError):
test_ctx.api.delete(
test_ctx.context_factory(
user=test_ctx.user_factory(rank='regular_user')), 'bad')

View File

@ -149,7 +149,6 @@ def test_mods_trying_to_become_admin(test_ctx):
def test_uploading_avatar(test_ctx, tmpdir): def test_uploading_avatar(test_ctx, tmpdir):
config.config['data_dir'] = str(tmpdir.mkdir('data')) config.config['data_dir'] = str(tmpdir.mkdir('data'))
config.config['data_url'] = 'http://example.com/data/' config.config['data_url'] = 'http://example.com/data/'
user = test_ctx.user_factory(name='u1', rank='mod') user = test_ctx.user_factory(name='u1', rank='mod')
test_ctx.session.add(user) test_ctx.session.add(user)
empty_pixel = \ empty_pixel = \

View File

@ -9,6 +9,7 @@ class TagAlreadyExistsError(errors.ValidationError): pass
class InvalidNameError(errors.ValidationError): pass class InvalidNameError(errors.ValidationError): pass
class InvalidCategoryError(errors.ValidationError): pass class InvalidCategoryError(errors.ValidationError): pass
class RelationError(errors.ValidationError): pass class RelationError(errors.ValidationError): pass
class TagIsInUseError(errors.ValidationError): pass
def _verify_name_validity(name): def _verify_name_validity(name):
name_regex = config.config['tag_name_regex'] name_regex = config.config['tag_name_regex']