Example #1
0
    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
Example #2
0
    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
Example #3
0
    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
Example #4
0
    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
Example #5
0
    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
Example #6
0
    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
Example #7
0
    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
Example #8
0
    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
Example #9
0
    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
Example #10
0
    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
Example #11
0
    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
Example #12
0
    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
Example #13
0
    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
Example #14
0
    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
Example #15
0
    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
Example #16
0
    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))
Example #17
0
    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
Example #18
0
    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))
Example #19
0
    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
Example #20
0
    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