server/general: improve versioning effectiveness
...by integrating it with sqlalchemy that adds WHERE conditions for each UPDATE and DELETE statement.
This commit is contained in:
parent
ef4af697c4
commit
0320a0b55b
|
@ -1,7 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
from szurubooru import search
|
from szurubooru import search
|
||||||
from szurubooru.func import auth, comments, posts, scores, util
|
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
|
from szurubooru.func import auth, comments, posts, scores, util, versions
|
||||||
|
|
||||||
|
|
||||||
_search_executor = search.Executor(search.configs.CommentSearchConfig())
|
_search_executor = search.Executor(search.configs.CommentSearchConfig())
|
||||||
|
@ -43,12 +43,12 @@ def get_comment(ctx, params):
|
||||||
@routes.put('/comment/(?P<comment_id>[^/]+)/?')
|
@routes.put('/comment/(?P<comment_id>[^/]+)/?')
|
||||||
def update_comment(ctx, params):
|
def update_comment(ctx, params):
|
||||||
comment = comments.get_comment_by_id(params['comment_id'])
|
comment = comments.get_comment_by_id(params['comment_id'])
|
||||||
util.verify_version(comment, ctx)
|
versions.verify_version(comment, ctx)
|
||||||
|
versions.bump_version(comment)
|
||||||
infix = 'own' if ctx.user.user_id == comment.user_id else 'any'
|
infix = 'own' if ctx.user.user_id == comment.user_id else 'any'
|
||||||
text = ctx.get_param_as_string('text', required=True)
|
text = ctx.get_param_as_string('text', required=True)
|
||||||
auth.verify_privilege(ctx.user, 'comments:edit:%s' % infix)
|
auth.verify_privilege(ctx.user, 'comments:edit:%s' % infix)
|
||||||
comments.update_comment_text(comment, text)
|
comments.update_comment_text(comment, text)
|
||||||
util.bump_version(comment)
|
|
||||||
comment.last_edit_time = datetime.datetime.utcnow()
|
comment.last_edit_time = datetime.datetime.utcnow()
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
return _serialize(ctx, comment)
|
return _serialize(ctx, comment)
|
||||||
|
@ -57,7 +57,7 @@ def update_comment(ctx, params):
|
||||||
@routes.delete('/comment/(?P<comment_id>[^/]+)/?')
|
@routes.delete('/comment/(?P<comment_id>[^/]+)/?')
|
||||||
def delete_comment(ctx, params):
|
def delete_comment(ctx, params):
|
||||||
comment = comments.get_comment_by_id(params['comment_id'])
|
comment = comments.get_comment_by_id(params['comment_id'])
|
||||||
util.verify_version(comment, ctx)
|
versions.verify_version(comment, ctx)
|
||||||
infix = 'own' if ctx.user.user_id == comment.user_id else 'any'
|
infix = 'own' if ctx.user.user_id == comment.user_id else 'any'
|
||||||
auth.verify_privilege(ctx.user, 'comments:delete:%s' % infix)
|
auth.verify_privilege(ctx.user, 'comments:delete:%s' % infix)
|
||||||
ctx.session.delete(comment)
|
ctx.session.delete(comment)
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import datetime
|
import datetime
|
||||||
import os
|
import os
|
||||||
from szurubooru import config
|
from szurubooru import config
|
||||||
from szurubooru.func import posts, users, util
|
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
|
from szurubooru.func import posts, users, util
|
||||||
|
|
||||||
|
|
||||||
_cache_time = None
|
_cache_time = None
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from szurubooru import config, errors
|
from szurubooru import config, errors
|
||||||
from szurubooru.func import auth, mailer, users, util
|
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
|
from szurubooru.func import auth, mailer, users, versions
|
||||||
|
|
||||||
|
|
||||||
MAIL_SUBJECT = 'Password reset for {name}'
|
MAIL_SUBJECT = 'Password reset for {name}'
|
||||||
|
@ -40,6 +40,6 @@ def finish_password_reset(ctx, params):
|
||||||
if token != good_token:
|
if token != good_token:
|
||||||
raise errors.ValidationError('Invalid password reset token.')
|
raise errors.ValidationError('Invalid password reset token.')
|
||||||
new_password = users.reset_user_password(user)
|
new_password = users.reset_user_password(user)
|
||||||
util.bump_version(user)
|
versions.bump_version(user)
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
return {'password': new_password}
|
return {'password': new_password}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import datetime
|
||||||
from szurubooru import search
|
from szurubooru import search
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
from szurubooru.func import (
|
from szurubooru.func import (
|
||||||
auth, tags, posts, snapshots, favorites, scores, util)
|
auth, tags, posts, snapshots, favorites, scores, util, versions)
|
||||||
|
|
||||||
|
|
||||||
_search_executor = search.Executor(search.configs.PostSearchConfig())
|
_search_executor = search.Executor(search.configs.PostSearchConfig())
|
||||||
|
@ -68,7 +68,8 @@ def get_post(ctx, params):
|
||||||
@routes.put('/post/(?P<post_id>[^/]+)/?')
|
@routes.put('/post/(?P<post_id>[^/]+)/?')
|
||||||
def update_post(ctx, params):
|
def update_post(ctx, params):
|
||||||
post = posts.get_post_by_id(params['post_id'])
|
post = posts.get_post_by_id(params['post_id'])
|
||||||
util.verify_version(post, ctx)
|
versions.verify_version(post, ctx)
|
||||||
|
versions.bump_version(post)
|
||||||
if ctx.has_file('content'):
|
if ctx.has_file('content'):
|
||||||
auth.verify_privilege(ctx.user, 'posts:edit:content')
|
auth.verify_privilege(ctx.user, 'posts:edit:content')
|
||||||
posts.update_post_content(post, ctx.get_file('content'))
|
posts.update_post_content(post, ctx.get_file('content'))
|
||||||
|
@ -97,7 +98,6 @@ def update_post(ctx, params):
|
||||||
if ctx.has_file('thumbnail'):
|
if ctx.has_file('thumbnail'):
|
||||||
auth.verify_privilege(ctx.user, 'posts:edit:thumbnail')
|
auth.verify_privilege(ctx.user, 'posts:edit:thumbnail')
|
||||||
posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
|
posts.update_post_thumbnail(post, ctx.get_file('thumbnail'))
|
||||||
util.bump_version(post)
|
|
||||||
post.last_edit_time = datetime.datetime.utcnow()
|
post.last_edit_time = datetime.datetime.utcnow()
|
||||||
ctx.session.flush()
|
ctx.session.flush()
|
||||||
snapshots.save_entity_modification(post, ctx.user)
|
snapshots.save_entity_modification(post, ctx.user)
|
||||||
|
@ -110,7 +110,7 @@ def update_post(ctx, params):
|
||||||
def delete_post(ctx, params):
|
def delete_post(ctx, params):
|
||||||
auth.verify_privilege(ctx.user, 'posts:delete')
|
auth.verify_privilege(ctx.user, 'posts:delete')
|
||||||
post = posts.get_post_by_id(params['post_id'])
|
post = posts.get_post_by_id(params['post_id'])
|
||||||
util.verify_version(post, ctx)
|
versions.verify_version(post, ctx)
|
||||||
snapshots.save_entity_deletion(post, ctx.user)
|
snapshots.save_entity_deletion(post, ctx.user)
|
||||||
posts.delete(post)
|
posts.delete(post)
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from szurubooru import search
|
from szurubooru import search
|
||||||
from szurubooru.func import auth, snapshots
|
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
|
from szurubooru.func import auth, snapshots
|
||||||
|
|
||||||
|
|
||||||
_search_executor = search.Executor(search.configs.SnapshotSearchConfig())
|
_search_executor = search.Executor(search.configs.SnapshotSearchConfig())
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
from szurubooru import db, search
|
from szurubooru import db, search
|
||||||
from szurubooru.func import auth, tags, util, snapshots
|
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
|
from szurubooru.func import auth, tags, snapshots, util, versions
|
||||||
|
|
||||||
|
|
||||||
_search_executor = search.Executor(search.configs.TagSearchConfig())
|
_search_executor = search.Executor(search.configs.TagSearchConfig())
|
||||||
|
@ -66,7 +66,8 @@ def get_tag(ctx, params):
|
||||||
@routes.put('/tag/(?P<tag_name>[^/]+)/?')
|
@routes.put('/tag/(?P<tag_name>[^/]+)/?')
|
||||||
def update_tag(ctx, params):
|
def update_tag(ctx, params):
|
||||||
tag = tags.get_tag_by_name(params['tag_name'])
|
tag = tags.get_tag_by_name(params['tag_name'])
|
||||||
util.verify_version(tag, ctx)
|
versions.verify_version(tag, ctx)
|
||||||
|
versions.bump_version(tag)
|
||||||
if ctx.has_param('names'):
|
if ctx.has_param('names'):
|
||||||
auth.verify_privilege(ctx.user, 'tags:edit:names')
|
auth.verify_privilege(ctx.user, 'tags:edit:names')
|
||||||
tags.update_tag_names(tag, ctx.get_param_as_list('names'))
|
tags.update_tag_names(tag, ctx.get_param_as_list('names'))
|
||||||
|
@ -88,7 +89,6 @@ def update_tag(ctx, params):
|
||||||
implications = ctx.get_param_as_list('implications')
|
implications = ctx.get_param_as_list('implications')
|
||||||
_create_if_needed(implications, ctx.user)
|
_create_if_needed(implications, ctx.user)
|
||||||
tags.update_tag_implications(tag, implications)
|
tags.update_tag_implications(tag, implications)
|
||||||
util.bump_version(tag)
|
|
||||||
tag.last_edit_time = datetime.datetime.utcnow()
|
tag.last_edit_time = datetime.datetime.utcnow()
|
||||||
ctx.session.flush()
|
ctx.session.flush()
|
||||||
snapshots.save_entity_modification(tag, ctx.user)
|
snapshots.save_entity_modification(tag, ctx.user)
|
||||||
|
@ -100,7 +100,7 @@ def update_tag(ctx, params):
|
||||||
@routes.delete('/tag/(?P<tag_name>[^/]+)/?')
|
@routes.delete('/tag/(?P<tag_name>[^/]+)/?')
|
||||||
def delete_tag(ctx, params):
|
def delete_tag(ctx, params):
|
||||||
tag = tags.get_tag_by_name(params['tag_name'])
|
tag = tags.get_tag_by_name(params['tag_name'])
|
||||||
util.verify_version(tag, ctx)
|
versions.verify_version(tag, ctx)
|
||||||
auth.verify_privilege(ctx.user, 'tags:delete')
|
auth.verify_privilege(ctx.user, 'tags:delete')
|
||||||
snapshots.save_entity_deletion(tag, ctx.user)
|
snapshots.save_entity_deletion(tag, ctx.user)
|
||||||
tags.delete(tag)
|
tags.delete(tag)
|
||||||
|
@ -115,12 +115,12 @@ def merge_tags(ctx, _params=None):
|
||||||
target_tag_name = ctx.get_param_as_string('mergeTo', required=True) or ''
|
target_tag_name = ctx.get_param_as_string('mergeTo', required=True) or ''
|
||||||
source_tag = tags.get_tag_by_name(source_tag_name)
|
source_tag = tags.get_tag_by_name(source_tag_name)
|
||||||
target_tag = tags.get_tag_by_name(target_tag_name)
|
target_tag = tags.get_tag_by_name(target_tag_name)
|
||||||
util.verify_version(source_tag, ctx, 'removeVersion')
|
versions.verify_version(source_tag, ctx, 'removeVersion')
|
||||||
util.verify_version(target_tag, ctx, 'mergeToVersion')
|
versions.verify_version(target_tag, ctx, 'mergeToVersion')
|
||||||
|
versions.bump_version(target_tag)
|
||||||
auth.verify_privilege(ctx.user, 'tags:merge')
|
auth.verify_privilege(ctx.user, 'tags:merge')
|
||||||
tags.merge_tags(source_tag, target_tag)
|
tags.merge_tags(source_tag, target_tag)
|
||||||
snapshots.save_entity_deletion(source_tag, ctx.user)
|
snapshots.save_entity_deletion(source_tag, ctx.user)
|
||||||
util.bump_version(target_tag)
|
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
tags.export_to_json()
|
tags.export_to_json()
|
||||||
return _serialize(ctx, target_tag)
|
return _serialize(ctx, target_tag)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
from szurubooru.func import auth, tags, tag_categories, util, snapshots
|
from szurubooru.func import (
|
||||||
|
auth, tags, tag_categories, snapshots, util, versions)
|
||||||
|
|
||||||
|
|
||||||
def _serialize(ctx, category):
|
def _serialize(ctx, category):
|
||||||
|
@ -40,7 +41,8 @@ def get_tag_category(ctx, params):
|
||||||
@routes.put('/tag-category/(?P<category_name>[^/]+)/?')
|
@routes.put('/tag-category/(?P<category_name>[^/]+)/?')
|
||||||
def update_tag_category(ctx, params):
|
def update_tag_category(ctx, params):
|
||||||
category = tag_categories.get_category_by_name(params['category_name'])
|
category = tag_categories.get_category_by_name(params['category_name'])
|
||||||
util.verify_version(category, ctx)
|
versions.verify_version(category, ctx)
|
||||||
|
versions.bump_version(category)
|
||||||
if ctx.has_param('name'):
|
if ctx.has_param('name'):
|
||||||
auth.verify_privilege(ctx.user, 'tag_categories:edit:name')
|
auth.verify_privilege(ctx.user, 'tag_categories:edit:name')
|
||||||
tag_categories.update_category_name(
|
tag_categories.update_category_name(
|
||||||
|
@ -49,7 +51,6 @@ def update_tag_category(ctx, params):
|
||||||
auth.verify_privilege(ctx.user, 'tag_categories:edit:color')
|
auth.verify_privilege(ctx.user, 'tag_categories:edit:color')
|
||||||
tag_categories.update_category_color(
|
tag_categories.update_category_color(
|
||||||
category, ctx.get_param_as_string('color'))
|
category, ctx.get_param_as_string('color'))
|
||||||
util.bump_version(category)
|
|
||||||
ctx.session.flush()
|
ctx.session.flush()
|
||||||
snapshots.save_entity_modification(category, ctx.user)
|
snapshots.save_entity_modification(category, ctx.user)
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
|
@ -60,7 +61,7 @@ def update_tag_category(ctx, params):
|
||||||
@routes.delete('/tag-category/(?P<category_name>[^/]+)/?')
|
@routes.delete('/tag-category/(?P<category_name>[^/]+)/?')
|
||||||
def delete_tag_category(ctx, params):
|
def delete_tag_category(ctx, params):
|
||||||
category = tag_categories.get_category_by_name(params['category_name'])
|
category = tag_categories.get_category_by_name(params['category_name'])
|
||||||
util.verify_version(category, ctx)
|
versions.verify_version(category, ctx)
|
||||||
auth.verify_privilege(ctx.user, 'tag_categories:delete')
|
auth.verify_privilege(ctx.user, 'tag_categories:delete')
|
||||||
tag_categories.delete_category(category)
|
tag_categories.delete_category(category)
|
||||||
snapshots.save_entity_deletion(category, ctx.user)
|
snapshots.save_entity_deletion(category, ctx.user)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from szurubooru import search
|
from szurubooru import search
|
||||||
from szurubooru.func import auth, users, util
|
|
||||||
from szurubooru.rest import routes
|
from szurubooru.rest import routes
|
||||||
|
from szurubooru.func import auth, users, util, versions
|
||||||
|
|
||||||
|
|
||||||
_search_executor = search.Executor(search.configs.UserSearchConfig())
|
_search_executor = search.Executor(search.configs.UserSearchConfig())
|
||||||
|
@ -52,7 +52,8 @@ def get_user(ctx, params):
|
||||||
@routes.put('/user/(?P<user_name>[^/]+)/?')
|
@routes.put('/user/(?P<user_name>[^/]+)/?')
|
||||||
def update_user(ctx, params):
|
def update_user(ctx, params):
|
||||||
user = users.get_user_by_name(params['user_name'])
|
user = users.get_user_by_name(params['user_name'])
|
||||||
util.verify_version(user, ctx)
|
versions.verify_version(user, ctx)
|
||||||
|
versions.bump_version(user)
|
||||||
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
||||||
if ctx.has_param('name'):
|
if ctx.has_param('name'):
|
||||||
auth.verify_privilege(ctx.user, 'users:edit:%s:name' % infix)
|
auth.verify_privilege(ctx.user, 'users:edit:%s:name' % infix)
|
||||||
|
@ -74,7 +75,6 @@ def update_user(ctx, params):
|
||||||
user,
|
user,
|
||||||
ctx.get_param_as_string('avatarStyle'),
|
ctx.get_param_as_string('avatarStyle'),
|
||||||
ctx.get_file('avatar'))
|
ctx.get_file('avatar'))
|
||||||
util.bump_version(user)
|
|
||||||
ctx.session.commit()
|
ctx.session.commit()
|
||||||
return _serialize(ctx, user)
|
return _serialize(ctx, user)
|
||||||
|
|
||||||
|
@ -82,7 +82,7 @@ def update_user(ctx, params):
|
||||||
@routes.delete('/user/(?P<user_name>[^/]+)/?')
|
@routes.delete('/user/(?P<user_name>[^/]+)/?')
|
||||||
def delete_user(ctx, params):
|
def delete_user(ctx, params):
|
||||||
user = users.get_user_by_name(params['user_name'])
|
user = users.get_user_by_name(params['user_name'])
|
||||||
util.verify_version(user, ctx)
|
versions.verify_version(user, ctx)
|
||||||
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
infix = 'self' if ctx.user.user_id == user.user_id else 'any'
|
||||||
auth.verify_privilege(ctx.user, 'users:delete:%s' % infix)
|
auth.verify_privilege(ctx.user, 'users:delete:%s' % infix)
|
||||||
ctx.session.delete(user)
|
ctx.session.delete(user)
|
||||||
|
|
|
@ -48,3 +48,8 @@ class Comment(Base):
|
||||||
.query(func.sum(CommentScore.score)) \
|
.query(func.sum(CommentScore.score)) \
|
||||||
.filter(CommentScore.comment_id == self.comment_id) \
|
.filter(CommentScore.comment_id == self.comment_id) \
|
||||||
.one()[0] or 0
|
.one()[0] or 0
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'version_id_col': version,
|
||||||
|
'version_id_generator': False,
|
||||||
|
}
|
||||||
|
|
|
@ -237,3 +237,8 @@ class Post(Base):
|
||||||
(PostRelation.parent_id == post_id)
|
(PostRelation.parent_id == post_id)
|
||||||
| (PostRelation.child_id == post_id))
|
| (PostRelation.child_id == post_id))
|
||||||
.correlate_except(PostRelation))
|
.correlate_except(PostRelation))
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'version_id_col': version,
|
||||||
|
'version_id_generator': False,
|
||||||
|
}
|
||||||
|
|
|
@ -115,3 +115,8 @@ class Tag(Base):
|
||||||
.where(TagImplication.parent_id == tag_id)
|
.where(TagImplication.parent_id == tag_id)
|
||||||
.as_scalar(),
|
.as_scalar(),
|
||||||
deferred=True)
|
deferred=True)
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'version_id_col': version,
|
||||||
|
'version_id_generator': False,
|
||||||
|
}
|
||||||
|
|
|
@ -21,3 +21,8 @@ class TagCategory(Base):
|
||||||
select([func.count('Tag.tag_id')])
|
select([func.count('Tag.tag_id')])
|
||||||
.where(Tag.category_id == tag_category_id)
|
.where(Tag.category_id == tag_category_id)
|
||||||
.correlate_except(table('Tag')))
|
.correlate_except(table('Tag')))
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'version_id_col': version,
|
||||||
|
'version_id_generator': False,
|
||||||
|
}
|
||||||
|
|
|
@ -75,3 +75,8 @@ class User(Base):
|
||||||
.filter(PostScore.user_id == self.user_id)
|
.filter(PostScore.user_id == self.user_id)
|
||||||
.filter(PostScore.score == -1)
|
.filter(PostScore.score == -1)
|
||||||
.one()[0] or 0)
|
.one()[0] or 0)
|
||||||
|
|
||||||
|
__mapper_args__ = {
|
||||||
|
'version_id_col': version,
|
||||||
|
'version_id_generator': False,
|
||||||
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import os
|
import os
|
||||||
import logging
|
import logging
|
||||||
import coloredlogs
|
import coloredlogs
|
||||||
|
import sqlalchemy.orm.exc
|
||||||
from szurubooru import config, errors, rest
|
from szurubooru import config, errors, rest
|
||||||
# pylint: disable=unused-import
|
# pylint: disable=unused-import
|
||||||
from szurubooru import api, middleware
|
from szurubooru import api, middleware
|
||||||
|
@ -38,6 +39,11 @@ def _on_processing_error(ex):
|
||||||
title='Processing error', description=str(ex))
|
title='Processing error', description=str(ex))
|
||||||
|
|
||||||
|
|
||||||
|
def _on_stale_data_error(_ex):
|
||||||
|
raise rest.errors.HttpConflict(
|
||||||
|
'Someone else modified this in the meantime. Please try again.')
|
||||||
|
|
||||||
|
|
||||||
def validate_config():
|
def validate_config():
|
||||||
'''
|
'''
|
||||||
Check whether config doesn't contain errors that might prove
|
Check whether config doesn't contain errors that might prove
|
||||||
|
@ -83,5 +89,6 @@ def create_app():
|
||||||
rest.errors.handle(errors.IntegrityError, _on_integrity_error)
|
rest.errors.handle(errors.IntegrityError, _on_integrity_error)
|
||||||
rest.errors.handle(errors.NotFoundError, _on_not_found_error)
|
rest.errors.handle(errors.NotFoundError, _on_not_found_error)
|
||||||
rest.errors.handle(errors.ProcessingError, _on_processing_error)
|
rest.errors.handle(errors.ProcessingError, _on_processing_error)
|
||||||
|
rest.errors.handle(sqlalchemy.orm.exc.StaleDataError, _on_stale_data_error)
|
||||||
|
|
||||||
return rest.application
|
return rest.application
|
||||||
|
|
|
@ -154,16 +154,3 @@ def value_exceeds_column_size(value, column):
|
||||||
if max_length is None:
|
if max_length is None:
|
||||||
return False
|
return False
|
||||||
return len(value) > max_length
|
return len(value) > max_length
|
||||||
|
|
||||||
|
|
||||||
def verify_version(entity, context, field_name='version'):
|
|
||||||
actual_version = context.get_param_as_int(field_name, required=True)
|
|
||||||
expected_version = entity.version
|
|
||||||
if actual_version != expected_version:
|
|
||||||
raise errors.InvalidParameterError(
|
|
||||||
'Someone else modified this in the meantime. ' +
|
|
||||||
'Please try again.')
|
|
||||||
|
|
||||||
|
|
||||||
def bump_version(entity):
|
|
||||||
entity.version += 1
|
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
from szurubooru import errors
|
||||||
|
|
||||||
|
|
||||||
|
def verify_version(entity, context, field_name='version'):
|
||||||
|
actual_version = context.get_param_as_int(field_name, required=True)
|
||||||
|
expected_version = entity.version
|
||||||
|
if actual_version != expected_version:
|
||||||
|
raise errors.InvalidParameterError(
|
||||||
|
'Someone else modified this in the meantime. ' +
|
||||||
|
'Please try again.')
|
||||||
|
|
||||||
|
|
||||||
|
def bump_version(entity):
|
||||||
|
entity.version = entity.version + 1
|
|
@ -136,6 +136,7 @@ def test_trying_to_create_tags_without_privileges(
|
||||||
params={'suggestions': ['tag1', 'tag2'], 'version': 1},
|
params={'suggestions': ['tag1', 'tag2'], 'version': 1},
|
||||||
user=user_factory(rank=db.User.RANK_REGULAR)),
|
user=user_factory(rank=db.User.RANK_REGULAR)),
|
||||||
{'tag_name': 'tag'})
|
{'tag_name': 'tag'})
|
||||||
|
db.session.rollback()
|
||||||
with pytest.raises(errors.AuthError):
|
with pytest.raises(errors.AuthError):
|
||||||
api.tag_api.update_tag(
|
api.tag_api.update_tag(
|
||||||
context_factory(
|
context_factory(
|
||||||
|
|
Loading…
Reference in New Issue