server/tags: add tag deleting
This commit is contained in:
parent
e4239a199c
commit
37a86816af
36
API.md
36
API.md
|
@ -17,12 +17,12 @@
|
|||
- [Creating tag](#creating-tag)
|
||||
- [Updating tag](#updating-tag)
|
||||
- [Getting tag](#getting-tag)
|
||||
- [Removing tag](#removing-tag)
|
||||
- [Deleting tag](#deleting-tag)
|
||||
- [Listing users](#listing-users)
|
||||
- [Creating user](#creating-user)
|
||||
- [Updating user](#updating-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 2: confirmation](#password-reset---step-2-confirmation)
|
||||
|
||||
|
@ -183,8 +183,26 @@ Not yet implemented.
|
|||
Not yet implemented.
|
||||
|
||||
|
||||
## Removing tag
|
||||
Not yet implemented.
|
||||
## Deleting tag
|
||||
- **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
|
||||
|
@ -253,6 +271,7 @@ Not yet implemented.
|
|||
|
||||
None.
|
||||
|
||||
|
||||
## Creating user
|
||||
- **Request**
|
||||
|
||||
|
@ -293,7 +312,6 @@ Not yet implemented.
|
|||
`default_rank` in the server's configuration.
|
||||
|
||||
|
||||
|
||||
## Updating user
|
||||
- **Request**
|
||||
|
||||
|
@ -345,7 +363,6 @@ Not yet implemented.
|
|||
file - see [file uploads](#file-uploads) for details.
|
||||
|
||||
|
||||
|
||||
## Getting user
|
||||
- **Request**
|
||||
|
||||
|
@ -370,8 +387,7 @@ Not yet implemented.
|
|||
Retrieves information about an existing user.
|
||||
|
||||
|
||||
|
||||
## Removing user
|
||||
## Deleting user
|
||||
- **Request**
|
||||
|
||||
`DELETE /user/<name>`
|
||||
|
@ -392,7 +408,6 @@ Not yet implemented.
|
|||
Deletes existing user.
|
||||
|
||||
|
||||
|
||||
## Password reset - step 1: mail request
|
||||
- **Request**
|
||||
|
||||
|
@ -418,7 +433,6 @@ Not yet implemented.
|
|||
account.
|
||||
|
||||
|
||||
|
||||
## Password reset - step 2: confirmation
|
||||
- **Request**
|
||||
|
||||
|
@ -483,6 +497,8 @@ Not yet implemented.
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
# Search
|
||||
|
||||
Search queries are built of tokens that are separated by spaces. Each token can
|
||||
|
|
|
@ -64,5 +64,16 @@ class TagDetailApi(BaseApi):
|
|||
ctx.session.commit()
|
||||
return {'tag': _serialize_tag(tag)}
|
||||
|
||||
def delete(self, ctx):
|
||||
raise NotImplementedError()
|
||||
def delete(self, ctx, tag_name):
|
||||
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 {}
|
||||
|
|
|
@ -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')
|
|
@ -149,7 +149,6 @@ def test_mods_trying_to_become_admin(test_ctx):
|
|||
def test_uploading_avatar(test_ctx, tmpdir):
|
||||
config.config['data_dir'] = str(tmpdir.mkdir('data'))
|
||||
config.config['data_url'] = 'http://example.com/data/'
|
||||
|
||||
user = test_ctx.user_factory(name='u1', rank='mod')
|
||||
test_ctx.session.add(user)
|
||||
empty_pixel = \
|
||||
|
|
|
@ -9,6 +9,7 @@ class TagAlreadyExistsError(errors.ValidationError): pass
|
|||
class InvalidNameError(errors.ValidationError): pass
|
||||
class InvalidCategoryError(errors.ValidationError): pass
|
||||
class RelationError(errors.ValidationError): pass
|
||||
class TagIsInUseError(errors.ValidationError): pass
|
||||
|
||||
def _verify_name_validity(name):
|
||||
name_regex = config.config['tag_name_regex']
|
||||
|
|
Loading…
Reference in New Issue