def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(STATIC_PAGE).validated(data, update=True) staticpage = self.model if not author.is_superuser and (staticpage.is_template or data.get('is_template')): raise ValidationError({'is_template': [lazy_gettext('Access denied')]}) if ('name' in data and data['name'] != staticpage.name) or ('lang' in data and data['lang'] != staticpage.lang): raise ValidationError({ 'name': [lazy_gettext('Cannot change primary key')], 'lang': [lazy_gettext('Cannot change primary key')], }) if data.get('is_template', staticpage.is_template) and 'content' in data: self.check_renderability(author, data.get('name', staticpage.name), data['content']) changed_fields = set() for key, value in data.items(): if getattr(staticpage, key) != value: setattr(staticpage, key, value) changed_fields |= {key,} if changed_fields: AdminLog.bl.create( user=author, obj=staticpage, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return staticpage
def create(self, author, data): from mini_fiction.models import AdminLog data = Validator(STATIC_PAGE).validated(data) if not author.is_superuser and data.get('is_template'): raise ValidationError( {'is_template': [lazy_gettext('Access denied')]}) if data.get('is_template'): self.check_renderability(author, data['name'], data['content']) if not data.get('lang'): data['lang'] = 'none' exist_staticpage = self.model.get(name=data['name'], lang=data['lang']) if exist_staticpage: raise ValidationError( {'name': [lazy_gettext('Page already exists')]}) staticpage = self.model(**data) staticpage.flush() AdminLog.bl.create(user=author, obj=staticpage, action=AdminLog.ADDITION) return staticpage
def authenticate_by_username(self, data, remote_addr=None): raw_data = data data = Validator(LOGIN).validated(data) user = None # Сначала достаём пользователя из базы # (без чувствительности к регистру) user = self.get_by_username(data.get('username')) # Пресекаем перебор пароля капчей (по IP и по юзеру) if remote_addr: if current_app.captcha and self.need_captcha_for_auth( remote_addr, user.id if user else None): current_app.captcha.check_or_raise(raw_data) self.track_auth(remote_addr, user.id if user else None) # Проверяем пароль if not user or not user.bl.check_password(data['password']): if remote_addr and current_app.config['AUTH_LOG']: if not user: current_app.logger.info( '%s tried to log in, but account not found (ID: N/A, IP: %s)', data.get('username', '?'), remote_addr) else: current_app.logger.info( '%s tried to log in with incorrect password (ID: %s, IP: %s)', user.username, user.id, remote_addr) raise ValidationError({ 'username': [ lazy_gettext( 'Please enter a correct username and password.') ] }) # Проверяем бан if not user.is_active: if remote_addr and current_app.config['AUTH_LOG']: current_app.logger.info( '%s tried to log in, but account is disabled (ID: %s, IP: %s)', user.username, user.id, remote_addr) raise ValidationError({ 'username': [user.ban_reason or lazy_gettext('Account is disabled')] }) # Если дошли сюда, значит всё хорошо if remote_addr and current_app.config['AUTH_LOG']: current_app.logger.info('%s logged in (ID: %s, IP: %s)', user.username, user.id, remote_addr) return user
def authenticate_by_username(self, data, remote_addr=None): raw_data = data data = Validator(LOGIN).validated(data) user = None # Сначала достаём пользователя из базы # (без чувствительности к регистру) user = self.get_by_username(data.get('username')) # Пресекаем перебор пароля капчей (по IP и по юзеру) if remote_addr: if current_app.captcha and self.need_captcha_for_auth(remote_addr, user.id if user else None): current_app.captcha.check_or_raise(raw_data) self.track_auth(remote_addr, user.id if user else None) # Проверяем пароль if not user or not user.bl.check_password(data['password']): if remote_addr and current_app.config['AUTH_LOG']: if not user: current_app.logger.info('%s tried to log in, but account not found (ID: N/A, IP: %s)', data.get('username', '?'), remote_addr) else: current_app.logger.info('%s tried to log in with incorrect password (ID: %s, IP: %s)', user.username, user.id, remote_addr) raise ValidationError({'username': [lazy_gettext('Please enter a correct username and password.')]}) # Проверяем бан if not user.is_active: if remote_addr and current_app.config['AUTH_LOG']: current_app.logger.info('%s tried to log in, but account is disabled (ID: %s, IP: %s)', user.username, user.id, remote_addr) raise ValidationError({'username': [user.ban_reason or lazy_gettext('Account is disabled')]}) # Если дошли сюда, значит всё хорошо if remote_addr and current_app.config['AUTH_LOG']: current_app.logger.info('%s logged in (ID: %s, IP: %s)', user.username, user.id, remote_addr) return user
def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(CHARACTER_FOR_UPDATE).validated(data, update=True) character = self.model errors = {} if 'name' in data: from mini_fiction.models import Character exist_character = Character.get(name=data['name']) if exist_character and exist_character.id != character.id: errors['name'] = [lazy_gettext('Character already exists')] if 'group' in data: from mini_fiction.models import CharacterGroup group = CharacterGroup.get(id=data['group']) if not group: errors['group'] = [lazy_gettext('Group not found')] else: group = None if errors: raise ValidationError(errors) changed_fields = set() if data.get('picture'): picture = self.validate_and_get_picture_data(data['picture']) else: picture = None for key, value in data.items(): if key == 'picture': if picture is not None: self.set_picture_data(picture) changed_fields |= {'picture',} elif key == 'group': if character.group.id != value: setattr(character, key, value) changed_fields |= {key,} elif getattr(character, key) != value: setattr(character, key, value) changed_fields |= {key,} if changed_fields: AdminLog.bl.create( user=author, obj=character, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return character
def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(NEWS_ITEM).validated(data, update=True) newsitem = self.model if not author.is_superuser and (newsitem.is_template or data.get('is_template')): raise ValidationError( {'is_template': [lazy_gettext('Access denied')]}) if 'name' in data: from mini_fiction.models import NewsItem exist_newsitem = NewsItem.get(name=data['name']) if exist_newsitem and exist_newsitem.id != newsitem.id: raise ValidationError( {'name': [lazy_gettext('Page already exists')]}) if data.get('is_template', newsitem.is_template) and 'content' in data: self.check_renderability(author, data.get('name', newsitem.name), data['content']) if data.get('show') and not newsitem.show: self.hide_shown_newsitem() changed_fields = set() for key, value in data.items(): if getattr(newsitem, key) != value: setattr(newsitem, key, value) changed_fields |= { key, } if changed_fields: AdminLog.bl.create( user=author, obj=newsitem, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return newsitem
def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(STATIC_PAGE).validated(data, update=True) staticpage = self.model if not author.is_superuser and (staticpage.is_template or data.get('is_template')): raise ValidationError( {'is_template': [lazy_gettext('Access denied')]}) if ('name' in data and data['name'] != staticpage.name) or ( 'lang' in data and data['lang'] != staticpage.lang): raise ValidationError({ 'name': [lazy_gettext('Cannot change primary key')], 'lang': [lazy_gettext('Cannot change primary key')], }) if data.get('is_template', staticpage.is_template) and 'content' in data: self.check_renderability(author, data.get('name', staticpage.name), data['content']) changed_fields = set() for key, value in data.items(): if getattr(staticpage, key) != value: setattr(staticpage, key, value) changed_fields |= { key, } if changed_fields: AdminLog.bl.create( user=author, obj=staticpage, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return staticpage
def create(self, author, data): from mini_fiction.models import AdminLog data = Validator(NEWS_ITEM).validated(data) if not author.is_superuser and data.get('is_template'): raise ValidationError({'is_template': [lazy_gettext('Access denied')]}) if data.get('is_template'): self.check_renderability(author, data['name'], data['content']) exist_newsitem = self.model.get(name=data['name']) if exist_newsitem: raise ValidationError({'name': [lazy_gettext('Page already exists')]}) if data.get('show'): self.hide_shown_newsitem() newsitem = self.model(author=author, **data) newsitem.flush() AdminLog.bl.create(user=author, obj=newsitem, action=AdminLog.ADDITION) return newsitem
def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(HTML_BLOCK).validated(data, update=True) htmlblock = self.model if not author.is_superuser and (htmlblock.is_template or data.get('is_template')): raise ValidationError({'is_template': [lazy_gettext('Access denied')]}) if ('name' in data and data['name'] != htmlblock.name) or ('lang' in data and data['lang'] != htmlblock.lang): raise ValidationError({ 'name': [lazy_gettext('Cannot change primary key')], 'lang': [lazy_gettext('Cannot change primary key')], }) if data.get('is_template', htmlblock.is_template) and 'content' in data: self.check_renderability(author, data.get('name', htmlblock.name), data['content']) changed_fields = set() old_name = htmlblock.name for key, value in data.items(): if getattr(htmlblock, key) != value: setattr(htmlblock, key, value) changed_fields |= {key,} later(self.clear_cache, old_name) if htmlblock.name != old_name: later(self.clear_cache, htmlblock.name) if changed_fields: AdminLog.bl.create( user=author, obj=htmlblock, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return htmlblock
def create(self, author, data): from mini_fiction.models import AdminLog data = Validator(STATIC_PAGE).validated(data) if not author.is_superuser and data.get('is_template'): raise ValidationError({'is_template': [lazy_gettext('Access denied')]}) if data.get('is_template'): self.check_renderability(author, data['name'], data['content']) if not data.get('lang'): data['lang'] = 'none' exist_staticpage = self.model.get(name=data['name'], lang=data['lang']) if exist_staticpage: raise ValidationError({'name': [lazy_gettext('Page already exists')]}) staticpage = self.model(**data) staticpage.flush() AdminLog.bl.create(user=author, obj=staticpage, action=AdminLog.ADDITION) return staticpage
def create(self, author, data): from mini_fiction.models import AdminLog data = Validator(HTML_BLOCK).validated(data) if not author.is_superuser and data.get('is_template'): raise ValidationError({'is_template': [lazy_gettext('Access denied')]}) if data.get('is_template'): self.check_renderability(author, data['name'], data['content']) if not data.get('lang'): data['lang'] = 'none' exist_htmlblock = self.model.get(name=data['name'], lang=data['lang']) if exist_htmlblock: raise ValidationError({'name': [lazy_gettext('Block already exists')]}) htmlblock = self.model(**data) htmlblock.flush() AdminLog.bl.create(user=author, obj=htmlblock, action=AdminLog.ADDITION) later(self.clear_cache, htmlblock.name) # avoid race condition by `later` (runs after commit) return htmlblock
def create(self, author, data): from mini_fiction.models import AdminLog data = Validator(NEWS_ITEM).validated(data) if not author.is_superuser and data.get('is_template'): raise ValidationError( {'is_template': [lazy_gettext('Access denied')]}) if data.get('is_template'): self.check_renderability(author, data['name'], data['content']) exist_newsitem = self.model.get(name=data['name']) if exist_newsitem: raise ValidationError( {'name': [lazy_gettext('Page already exists')]}) if data.get('show'): self.hide_shown_newsitem() newsitem = self.model(author=author, **data) newsitem.flush() AdminLog.bl.create(user=author, obj=newsitem, action=AdminLog.ADDITION) return newsitem
def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(NEWS_ITEM).validated(data, update=True) newsitem = self.model if not author.is_superuser and (newsitem.is_template or data.get('is_template')): raise ValidationError({'is_template': [lazy_gettext('Access denied')]}) if 'name' in data: from mini_fiction.models import NewsItem exist_newsitem = NewsItem.get(name=data['name']) if exist_newsitem and exist_newsitem.id != newsitem.id: raise ValidationError({'name': [lazy_gettext('Page already exists')]}) if data.get('is_template', newsitem.is_template) and 'content' in data: self.check_renderability(author, data.get('name', newsitem.name), data['content']) if data.get('show') and not newsitem.show: self.hide_shown_newsitem() changed_fields = set() for key, value in data.items(): if getattr(newsitem, key) != value: setattr(newsitem, key, value) changed_fields |= {key,} if changed_fields: AdminLog.bl.create( user=author, obj=newsitem, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return newsitem
def create(self, user, data): from mini_fiction.models import Tag, AdminLog if not user or not user.is_staff: raise ValueError('Not authorized') data = Validator(TAG).validated(data) errors = {} bad_reason = self.validate_tag_name(data['name']) if bad_reason: errors['name'] = [bad_reason] iname = normalize_tag(data['name']) if not bad_reason and Tag.get(iname=iname): errors['name'] = [lazy_gettext('Tag already exists')] canonical_tag = None if data.get('is_alias_for'): canonical_tag = Tag.get(iname=normalize_tag(data['is_alias_for'])) if not canonical_tag: errors['is_alias_for'] = [lazy_gettext('Tag not found')] if errors: raise ValidationError(errors) tag = Tag( name=data['name'], iname=iname, category=data.get('category'), color=data.get('color') or '', description=data.get('description') or '', is_main_tag=data.get('is_main_tag', False), created_by=user, is_alias_for=None, reason_to_blacklist='', ) tag.flush() AdminLog.bl.create(user=user, obj=tag, action=AdminLog.ADDITION) if data.get('reason_to_blacklist'): tag.bl.set_blacklist(user, data['reason_to_blacklist']) elif canonical_tag: tag.bl.make_alias_for(user, canonical_tag, hidden=data.get('is_hidden_alias', False)) return tag
def update(self, user, data): from mini_fiction.models import Tag, AdminLog if not user or not user.is_staff: raise ValueError('Not authorized') tag = self.model data = Validator(TAG).validated(data, update=True) changes = {} errors = {} if 'name' in data and data['name'] != tag.name: bad_reason = self.validate_tag_name(data['name']) if bad_reason: errors['name'] = [bad_reason] iname = normalize_tag(data['name']) if not bad_reason and iname != tag.iname and Tag.get(iname=iname): errors['name'] = [lazy_gettext('Tag already exists')] changes['name'] = data['name'] if iname != tag.iname: changes['iname'] = iname if 'category' in data: old_category_id = tag.category.id if tag.category else None if old_category_id != data['category']: changes['category'] = data['category'] for key in ('color', 'description', 'is_main_tag'): if key in data and data[key] != getattr(tag, key): changes[key] = data[key] canonical_tag = tag.is_alias_for if 'is_alias_for' in data: if data.get('is_alias_for'): canonical_tag = Tag.get(iname=normalize_tag(data['is_alias_for'])) if not canonical_tag: errors['is_alias_for'] = [lazy_gettext('Tag not found')] elif canonical_tag == tag or canonical_tag.is_alias_for and canonical_tag.is_alias_for == tag: errors['is_alias_for'] = [lazy_gettext('Tag cannot refer to itself')] else: canonical_tag = None if errors: raise ValidationError(errors) if changes: changes['updated_at'] = datetime.utcnow() tag.set(**changes) AdminLog.bl.create( user=user, obj=tag, action=AdminLog.CHANGE, fields=set(changes) - {'updated_at'}, ) if 'reason_to_blacklist' in data: self.set_blacklist(user, data['reason_to_blacklist']) if not tag.is_blacklisted and ('is_alias_for' in data or 'is_hidden_alias' in data): self.make_alias_for(user, canonical_tag, data.get('is_hidden_alias', tag.is_hidden_alias))
def create(self, target, author, ip, data): if self.schema is None: raise NotImplementedError reqs = self.access_for_commenting_by(target, author) if not reqs: # нет доступа raise ValueError('Permission denied') # TODO: refactor exceptions if reqs.get('captcha'): if current_app.captcha: current_app.captcha.check_or_raise(data) if self.schema: data = Validator(self.schema).validated(data) if data.get('parent'): parent = target.comments.select(lambda x: x.local_id == data[ 'parent'] and not x.deleted).first() if not parent: raise ValidationError( {'parent': [lazy_gettext('Parent comment not found')]}) if not parent.bl.access_for_answer_by(author): raise ValueError('Permission denied') else: parent = None tm = datetime.utcnow() data = { self.target_attr: target, 'author': author if author and author.is_authenticated else None, 'author_username': author.username if author and author.is_authenticated else '', 'ip': ipaddress.ip_address(ip).exploded, 'parent': parent, 'tree_depth': parent.tree_depth + 1 if parent else 0, 'text': data['text'], 'date': tm, 'edits_count': 0, 'last_edited_at': tm, 'last_edited_by': author if author and author.is_authenticated else None, } if parent: assert parent.root_id data['root_id'] = parent.root_id else: data['root_id'] = 0 # заполним после flush last_comment = target.comments.select().order_by( self.model.id.desc()).first() data['local_id'] = (last_comment.local_id + 1) if last_comment else 1 data.update(self._attributes_for(data)) comment = self.model(**data) comment.flush() assert comment.id if not parent: comment.root_id = comment.id if hasattr(target, 'comments_count'): target.comments_count += 1 if hasattr(target, 'last_comment_id'): target.last_comment_id = comment.id if parent: parent.answers_count += 1 current_app.cache.delete('index_comments_html') return comment
def update(self, user, data): from mini_fiction.models import Tag, AdminLog if not user or not user.is_staff: raise ValueError('Not authorized') tag = self.model data = Validator(TAG).validated(data, update=True) changes = {} errors = {} if 'name' in data and data['name'] != tag.name: bad_reason = self.validate_tag_name(data['name']) if bad_reason: errors['name'] = [bad_reason] iname = normalize_tag(data['name']) if not bad_reason and iname != tag.iname and Tag.get(iname=iname): errors['name'] = [lazy_gettext('Tag already exists')] changes['name'] = data['name'] if iname != tag.iname: changes['iname'] = iname if 'category' in data: old_category_id = tag.category.id if tag.category else None if old_category_id != data['category']: changes['category'] = data['category'] for key in ('color', 'description', 'is_main_tag'): if key in data and data[key] != getattr(tag, key): changes[key] = data[key] canonical_tag = tag.is_alias_for if 'is_alias_for' in data: if data.get('is_alias_for'): canonical_tag = Tag.get( iname=normalize_tag(data['is_alias_for'])) if not canonical_tag: errors['is_alias_for'] = [lazy_gettext('Tag not found')] elif canonical_tag == tag or canonical_tag.is_alias_for and canonical_tag.is_alias_for == tag: errors['is_alias_for'] = [ lazy_gettext('Tag cannot refer to itself') ] else: canonical_tag = None if errors: raise ValidationError(errors) if changes: changes['updated_at'] = datetime.utcnow() tag.set(**changes) AdminLog.bl.create( user=user, obj=tag, action=AdminLog.CHANGE, fields=set(changes) - {'updated_at'}, ) if 'reason_to_blacklist' in data: self.set_blacklist(user, data['reason_to_blacklist']) if not tag.is_blacklisted and ('is_alias_for' in data or 'is_hidden_alias' in data): self.make_alias_for( user, canonical_tag, data.get('is_hidden_alias', tag.is_hidden_alias))
def update(self, author, data): from mini_fiction.models import AdminLog data = Validator(CHARACTER_FOR_UPDATE).validated(data, update=True) character = self.model errors = {} if 'name' in data: from mini_fiction.models import Character exist_character = Character.get(name=data['name']) if exist_character and exist_character.id != character.id: errors['name'] = [lazy_gettext('Character already exists')] if 'group' in data: from mini_fiction.models import CharacterGroup group = CharacterGroup.get(id=data['group']) if not group: errors['group'] = [lazy_gettext('Group not found')] else: group = None if errors: raise ValidationError(errors) changed_fields = set() if data.get('picture'): picture = self.validate_and_get_picture_data(data['picture']) else: picture = None for key, value in data.items(): if key == 'picture': if picture is not None: self.set_picture_data(picture) changed_fields |= { 'picture', } elif key == 'group': if character.group.id != value: setattr(character, key, value) changed_fields |= { key, } elif getattr(character, key) != value: setattr(character, key, value) changed_fields |= { key, } if changed_fields: AdminLog.bl.create( user=author, obj=character, action=AdminLog.CHANGE, fields=sorted(changed_fields), ) return character
def create(self, target, author, ip, data): if self.schema is None: raise NotImplementedError reqs = self.access_for_commenting_by(target, author) if not reqs: # нет доступа raise ValueError('Permission denied') # TODO: refactor exceptions if reqs.get('captcha'): if current_app.captcha: current_app.captcha.check_or_raise(data) if self.schema: data = Validator(self.schema).validated(data) if data.get('parent'): parent = target.comments.select(lambda x: x.local_id == data['parent'] and not x.deleted).first() if not parent: raise ValidationError({'parent': [lazy_gettext('Parent comment not found')]}) if not parent.bl.access_for_answer_by(author): raise ValueError('Permission denied') else: parent = None tm = datetime.utcnow() data = { self.target_attr: target, 'author': author if author and author.is_authenticated else None, 'author_username': author.username if author and author.is_authenticated else '', 'ip': ipaddress.ip_address(ip).exploded, 'parent': parent, 'tree_depth': parent.tree_depth + 1 if parent else 0, 'text': data['text'], 'date': tm, 'edits_count': 0, 'last_edited_at': tm, 'last_edited_by': author if author and author.is_authenticated else None, } if parent: assert parent.root_id data['root_id'] = parent.root_id else: data['root_id'] = 0 # заполним после flush last_comment = target.comments.select().order_by(self.model.id.desc()).first() data['local_id'] = (last_comment.local_id + 1) if last_comment else 1 data.update(self._attributes_for(data)) comment = self.model(**data) comment.flush() assert comment.id if not parent: comment.root_id = comment.id if hasattr(target, 'comments_count'): target.comments_count += 1 if hasattr(target, 'last_comment_id'): target.last_comment_id = comment.id if parent: parent.answers_count += 1 current_app.cache.delete('index_comments_html') return comment