server/tags: add JSON export

This commit is contained in:
rr- 2016-04-16 22:57:02 +02:00
parent 61d2fb88ea
commit 9247e11596
7 changed files with 101 additions and 6 deletions

6
API.md
View File

@ -115,6 +115,12 @@ data.
Searches for tags.
**Note**: independently, the server exports current tag list snapshots to
the data directory under `tags.json` name. Its purpose is to reduce the
trips frontend needs to make when doing autocompletion, and ease caching.
The data directory and its URL are controlled with `data_dir` and
`data_url` variables in server's configuration.
**Anonymous tokens**
Same as `name` token.

View File

@ -48,6 +48,7 @@ class TagListApi(BaseApi):
ctx.session, names, category, suggestions, implications)
ctx.session.add(tag)
ctx.session.commit()
tags.export_to_json(ctx.session)
return {'tag': _serialize_tag(tag)}
class TagDetailApi(BaseApi):
@ -84,6 +85,7 @@ class TagDetailApi(BaseApi):
tag.last_edit_time = datetime.datetime.now()
ctx.session.commit()
tags.export_to_json(ctx.session)
return {'tag': _serialize_tag(tag)}
def delete(self, ctx, tag_name):
@ -98,4 +100,5 @@ class TagDetailApi(BaseApi):
auth.verify_privilege(ctx.user, 'tags:delete')
ctx.session.delete(tag)
ctx.session.commit()
tags.export_to_json(ctx.session)
return {}

View File

@ -1,6 +1,7 @@
import datetime
import os
import pytest
from szurubooru import api, db, errors
from szurubooru import api, config, db, errors
from szurubooru.util import misc, tags
def get_tag(session, name):
@ -15,8 +16,14 @@ def assert_relations(relations, expected_tag_names):
@pytest.fixture
def test_ctx(
session, config_injector, context_factory, user_factory, tag_factory):
tmpdir,
session,
config_injector,
context_factory,
user_factory,
tag_factory):
config_injector({
'data_dir': str(tmpdir),
'tag_categories': ['meta', 'character', 'copyright'],
'tag_name_regex': '^[^!]*$',
'ranks': ['anonymous', 'regular_user'],
@ -58,6 +65,7 @@ def test_creating_simple_tags(test_ctx, fake_datetime):
assert tag.post_count == 0
assert_relations(tag.suggestions, [])
assert_relations(tag.implications, [])
assert os.path.exists(os.path.join(config.config['data_dir'], 'tags.json'))
def test_duplicating_names(test_ctx):
result = test_ctx.api.post(

View File

@ -1,12 +1,19 @@
import pytest
import os
from datetime import datetime
from szurubooru import api, db, errors
from szurubooru import api, config, db, errors
from szurubooru.util import misc, tags
@pytest.fixture
def test_ctx(
session, config_injector, context_factory, tag_factory, user_factory):
tmpdir,
session,
config_injector,
context_factory,
tag_factory,
user_factory):
config_injector({
'data_dir': str(tmpdir),
'privileges': {
'tags:delete': 'regular_user',
},
@ -29,6 +36,7 @@ def test_removing_tags(test_ctx):
'tag')
assert result == {}
assert test_ctx.session.query(db.Tag).count() == 0
assert os.path.exists(os.path.join(config.config['data_dir'], 'tags.json'))
def test_removing_tags_without_privileges(test_ctx):
test_ctx.session.add(test_ctx.tag_factory(names=['tag']))

View File

@ -0,0 +1,42 @@
import datetime
import os
import json
from szurubooru import config, db
from szurubooru.util import tags
def test_export(tmpdir, session, config_injector, tag_factory):
config_injector({
'data_dir': str(tmpdir)
})
sug1 = tag_factory(names=['sug1'])
sug2 = tag_factory(names=['sug2'])
imp1 = tag_factory(names=['imp1'])
imp2 = tag_factory(names=['imp2'])
tag = tag_factory(names=['alias1', 'alias2'])
tag.post_count = 1
session.add_all([tag, sug1, sug2, imp1, imp2])
session.flush()
session.add_all([
db.TagSuggestion(tag.tag_id, sug1.tag_id),
db.TagSuggestion(tag.tag_id, sug2.tag_id),
db.TagImplication(tag.tag_id, imp1.tag_id),
db.TagImplication(tag.tag_id, imp2.tag_id),
])
session.flush()
tags.export_to_json(session)
export_path = os.path.join(config.config['data_dir'], 'tags.json')
assert os.path.exists(export_path)
with open(export_path, 'r') as handle:
assert json.loads(handle.read()) == [
{
'names': ['alias1', 'alias2'],
'usages': 1,
'suggestions': ['sug1', 'sug2'],
'implications': ['imp1', 'imp2'],
},
{'names': ['sug1'], 'usages': 0},
{'names': ['sug2'], 'usages': 0},
{'names': ['imp1'], 'usages': 0},
{'names': ['imp2'], 'usages': 0},
]

View File

@ -1,6 +1,7 @@
import datetime
import os
import pytest
from szurubooru import api, db, errors
from szurubooru import api, config, db, errors
from szurubooru.util import misc, tags
def get_tag(session, name):
@ -15,8 +16,14 @@ def assert_relations(relations, expected_tag_names):
@pytest.fixture
def test_ctx(
session, config_injector, context_factory, user_factory, tag_factory):
tmpdir,
session,
config_injector,
context_factory,
user_factory,
tag_factory):
config_injector({
'data_dir': str(tmpdir),
'tag_categories': ['meta', 'character', 'copyright'],
'tag_name_regex': '^[^!]*$',
'ranks': ['anonymous', 'regular_user'],
@ -66,6 +73,7 @@ def test_simple_updating(test_ctx, fake_datetime):
assert tag.category == 'character'
assert tag.suggestions == []
assert tag.implications == []
assert os.path.exists(os.path.join(config.config['data_dir'], 'tags.json'))
def test_trying_to_update_non_existing_tag(test_ctx):
with pytest.raises(tags.TagNotFoundError):

View File

@ -1,4 +1,6 @@
import datetime
import os
import json
import re
import sqlalchemy
from szurubooru import config, db, errors
@ -25,6 +27,24 @@ def _lower_list(names):
def _check_name_intersection(names1, names2):
return len(set(_lower_list(names1)).intersection(_lower_list(names2))) > 0
def export_to_json(session):
output = []
for tag in session.query(db.Tag).all():
item = {
'names': [tag_name.name for tag_name in tag.names],
'usages': tag.post_count
}
if len(tag.suggestions):
item['suggestions'] = \
[rel.child_tag.names[0].name for rel in tag.suggestions]
if len(tag.implications):
item['implications'] = \
[rel.child_tag.names[0].name for rel in tag.implications]
output.append(item)
export_path = os.path.join(config.config['data_dir'], 'tags.json')
with open(export_path, 'w') as handle:
handle.write(json.dumps(output, separators=(',', ':')))
def get_by_name(session, name):
return session.query(db.Tag) \
.join(db.TagName) \