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)
|
- [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
|
||||||
|
|
|
@ -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 {}
|
||||||
|
|
|
@ -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):
|
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 = \
|
||||||
|
|
|
@ -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']
|
||||||
|
|
Loading…
Reference in New Issue