server/tags: add JSON export
This commit is contained in:
parent
61d2fb88ea
commit
9247e11596
7 changed files with 101 additions and 6 deletions
6
API.md
6
API.md
|
@ -115,6 +115,12 @@ data.
|
||||||
|
|
||||||
Searches for tags.
|
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**
|
**Anonymous tokens**
|
||||||
|
|
||||||
Same as `name` token.
|
Same as `name` token.
|
||||||
|
|
|
@ -48,6 +48,7 @@ class TagListApi(BaseApi):
|
||||||
ctx.session, names, category, suggestions, implications)
|
ctx.session, names, category, suggestions, implications)
|
||||||
ctx.session.add(tag)
|
ctx.session.add(tag)
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
|
tags.export_to_json(ctx.session)
|
||||||
return {'tag': _serialize_tag(tag)}
|
return {'tag': _serialize_tag(tag)}
|
||||||
|
|
||||||
class TagDetailApi(BaseApi):
|
class TagDetailApi(BaseApi):
|
||||||
|
@ -84,6 +85,7 @@ class TagDetailApi(BaseApi):
|
||||||
|
|
||||||
tag.last_edit_time = datetime.datetime.now()
|
tag.last_edit_time = datetime.datetime.now()
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
|
tags.export_to_json(ctx.session)
|
||||||
return {'tag': _serialize_tag(tag)}
|
return {'tag': _serialize_tag(tag)}
|
||||||
|
|
||||||
def delete(self, ctx, tag_name):
|
def delete(self, ctx, tag_name):
|
||||||
|
@ -98,4 +100,5 @@ class TagDetailApi(BaseApi):
|
||||||
auth.verify_privilege(ctx.user, 'tags:delete')
|
auth.verify_privilege(ctx.user, 'tags:delete')
|
||||||
ctx.session.delete(tag)
|
ctx.session.delete(tag)
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
|
tags.export_to_json(ctx.session)
|
||||||
return {}
|
return {}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
from szurubooru import api, db, errors
|
from szurubooru import api, config, db, errors
|
||||||
from szurubooru.util import misc, tags
|
from szurubooru.util import misc, tags
|
||||||
|
|
||||||
def get_tag(session, name):
|
def get_tag(session, name):
|
||||||
|
@ -15,8 +16,14 @@ def assert_relations(relations, expected_tag_names):
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_ctx(
|
def test_ctx(
|
||||||
session, config_injector, context_factory, user_factory, tag_factory):
|
tmpdir,
|
||||||
|
session,
|
||||||
|
config_injector,
|
||||||
|
context_factory,
|
||||||
|
user_factory,
|
||||||
|
tag_factory):
|
||||||
config_injector({
|
config_injector({
|
||||||
|
'data_dir': str(tmpdir),
|
||||||
'tag_categories': ['meta', 'character', 'copyright'],
|
'tag_categories': ['meta', 'character', 'copyright'],
|
||||||
'tag_name_regex': '^[^!]*$',
|
'tag_name_regex': '^[^!]*$',
|
||||||
'ranks': ['anonymous', 'regular_user'],
|
'ranks': ['anonymous', 'regular_user'],
|
||||||
|
@ -58,6 +65,7 @@ def test_creating_simple_tags(test_ctx, fake_datetime):
|
||||||
assert tag.post_count == 0
|
assert tag.post_count == 0
|
||||||
assert_relations(tag.suggestions, [])
|
assert_relations(tag.suggestions, [])
|
||||||
assert_relations(tag.implications, [])
|
assert_relations(tag.implications, [])
|
||||||
|
assert os.path.exists(os.path.join(config.config['data_dir'], 'tags.json'))
|
||||||
|
|
||||||
def test_duplicating_names(test_ctx):
|
def test_duplicating_names(test_ctx):
|
||||||
result = test_ctx.api.post(
|
result = test_ctx.api.post(
|
||||||
|
|
|
@ -1,12 +1,19 @@
|
||||||
import pytest
|
import pytest
|
||||||
|
import os
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from szurubooru import api, db, errors
|
from szurubooru import api, config, db, errors
|
||||||
from szurubooru.util import misc, tags
|
from szurubooru.util import misc, tags
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_ctx(
|
def test_ctx(
|
||||||
session, config_injector, context_factory, tag_factory, user_factory):
|
tmpdir,
|
||||||
|
session,
|
||||||
|
config_injector,
|
||||||
|
context_factory,
|
||||||
|
tag_factory,
|
||||||
|
user_factory):
|
||||||
config_injector({
|
config_injector({
|
||||||
|
'data_dir': str(tmpdir),
|
||||||
'privileges': {
|
'privileges': {
|
||||||
'tags:delete': 'regular_user',
|
'tags:delete': 'regular_user',
|
||||||
},
|
},
|
||||||
|
@ -29,6 +36,7 @@ def test_removing_tags(test_ctx):
|
||||||
'tag')
|
'tag')
|
||||||
assert result == {}
|
assert result == {}
|
||||||
assert test_ctx.session.query(db.Tag).count() == 0
|
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):
|
def test_removing_tags_without_privileges(test_ctx):
|
||||||
test_ctx.session.add(test_ctx.tag_factory(names=['tag']))
|
test_ctx.session.add(test_ctx.tag_factory(names=['tag']))
|
||||||
|
|
42
server/szurubooru/tests/api/test_tag_export.py
Normal file
42
server/szurubooru/tests/api/test_tag_export.py
Normal 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},
|
||||||
|
]
|
|
@ -1,6 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
import pytest
|
import pytest
|
||||||
from szurubooru import api, db, errors
|
from szurubooru import api, config, db, errors
|
||||||
from szurubooru.util import misc, tags
|
from szurubooru.util import misc, tags
|
||||||
|
|
||||||
def get_tag(session, name):
|
def get_tag(session, name):
|
||||||
|
@ -15,8 +16,14 @@ def assert_relations(relations, expected_tag_names):
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def test_ctx(
|
def test_ctx(
|
||||||
session, config_injector, context_factory, user_factory, tag_factory):
|
tmpdir,
|
||||||
|
session,
|
||||||
|
config_injector,
|
||||||
|
context_factory,
|
||||||
|
user_factory,
|
||||||
|
tag_factory):
|
||||||
config_injector({
|
config_injector({
|
||||||
|
'data_dir': str(tmpdir),
|
||||||
'tag_categories': ['meta', 'character', 'copyright'],
|
'tag_categories': ['meta', 'character', 'copyright'],
|
||||||
'tag_name_regex': '^[^!]*$',
|
'tag_name_regex': '^[^!]*$',
|
||||||
'ranks': ['anonymous', 'regular_user'],
|
'ranks': ['anonymous', 'regular_user'],
|
||||||
|
@ -66,6 +73,7 @@ def test_simple_updating(test_ctx, fake_datetime):
|
||||||
assert tag.category == 'character'
|
assert tag.category == 'character'
|
||||||
assert tag.suggestions == []
|
assert tag.suggestions == []
|
||||||
assert tag.implications == []
|
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):
|
def test_trying_to_update_non_existing_tag(test_ctx):
|
||||||
with pytest.raises(tags.TagNotFoundError):
|
with pytest.raises(tags.TagNotFoundError):
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import datetime
|
import datetime
|
||||||
|
import os
|
||||||
|
import json
|
||||||
import re
|
import re
|
||||||
import sqlalchemy
|
import sqlalchemy
|
||||||
from szurubooru import config, db, errors
|
from szurubooru import config, db, errors
|
||||||
|
@ -25,6 +27,24 @@ def _lower_list(names):
|
||||||
def _check_name_intersection(names1, names2):
|
def _check_name_intersection(names1, names2):
|
||||||
return len(set(_lower_list(names1)).intersection(_lower_list(names2))) > 0
|
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):
|
def get_by_name(session, name):
|
||||||
return session.query(db.Tag) \
|
return session.query(db.Tag) \
|
||||||
.join(db.TagName) \
|
.join(db.TagName) \
|
||||||
|
|
Loading…
Reference in a new issue