Ejemplo n.º 1
0
class PluginForm(forms.Form):
    """The form for plugin activation and deactivation."""
    active_plugins = forms.MultiChoiceField(widget=forms.CheckboxGroup)
    disable_guard = forms.BooleanField(lazy_gettext(u'Disable plugin guard'),
        help_text=lazy_gettext(u'If the plugin guard is disabled errors '
                               u'on plugin setup are not caught.'))

    def __init__(self, initial=None):
        self.app = app = get_application()
        self.active_plugins.choices = sorted([(x.name, x.display_name)
                                              for x in app.plugins.values()],
                                             key=lambda x: x[1].lower())
        if initial is None:
            initial = dict(
                active_plugins=[x.name for x in app.plugins.itervalues()
                                if x.active],
                disable_guard=not app.cfg['plugin_guard']
            )
        forms.Form.__init__(self, initial)

    def apply(self):
        """Apply the changes."""
        t = self.app.cfg.edit()
        t['plugins'] = u', '.join(sorted(self.data['active_plugins']))
        t['plugin_guard'] = not self.data['disable_guard']
        t.commit()
Ejemplo n.º 2
0
class FeedImporter(Importer):
    name = 'feed'
    title = lazy_gettext(u'Feed Importer')
    description = lazy_gettext(u'Handles ATOM feeds with optional extensions '
                               u'such as those exported by Zine itself. '
                               u'Plugins can add further extensions to be '
                               u'recognized by this importer.')

    def configure(self, request):
        form = FeedImportForm()

        if request.method == 'POST' and form.validate(request.form):
            feed = request.files.get('feed')
            if form.data['download_url']:
                try:
                    feed = open_url(form.data['download_url']).stream
                except Exception, e:
                    log.exception(_('Error downloading feed'))
                    flash(_(u'Error downloading from URL: %s') % e, 'error')
            if not feed:
                return redirect_to('import/feed')

            try:
                blog = parse_feed(feed)
            except Exception, e:
                log.exception(_(u'Error parsing uploaded file'))
                flash(_(u'Error parsing feed: %s') % e, 'error')
            else:
Ejemplo n.º 3
0
class RstParser(BaseParser):
    """A parser for reStructuredText."""

    name = lazy_gettext('reStructuredText')
    extensions_registered = False

    def parse(self, input_data, reason):
        if not RstParser.extensions_registered:
            # need to do this only once...
            directives.register_directive('intro', IntroDirective)
            for extension in self.app.markup_extensions:
                if extension.is_block_level:
                    directives.register_directive(
                        extension.name,
                        make_extension_directive(self.app, extension))
                else:
                    roles.register_local_role(extension.name,
                                              make_extension_role(extension))
            RstParser.extensions_registered = True
        settings_overrides = {
            'file_insertion_enabled': False,
            'parsing_reason': reason,
        }
        rv = publish_string(source=input_data,
                            writer=ZemlWriter(),
                            settings_overrides=settings_overrides)
        if reason == 'comment':
            rv = sanitize(rv)
        return rv
Ejemplo n.º 4
0
class WordPressImporter(Importer):
    name = 'wordpress'
    title = 'WordPress'
    description = lazy_gettext(u'Handles import of WordPress "extended RSS" '
                               u' feeds.')

    def configure(self, request):
        form = WordPressImportForm()

        if request.method == 'POST' and form.validate(request.form):
            dump = request.files.get('dump')
            if form.data['download_url']:
                try:
                    dump = open_url(form.data['download_url']).stream
                except Exception, e:
                    log.exception(_('Error downloading feed'))
                    flash(_(u'Error downloading from URL: %s') % e, 'error')
            if not dump:
                return redirect_to('import/wordpress')

            try:
                blog = parse_feed(dump)
            except Exception, e:
                raise
                log.exception(_(u'Error parsing uploaded file'))
                flash(_(u'Error parsing uploaded file: %s') % e, 'error')
            else:
Ejemplo n.º 5
0
class EditCategoryForm(_CategoryBoundForm):
    """Form that is used to edit or create a category."""

    slug = forms.TextField(lazy_gettext(u'Slug'), validators=[is_valid_slug()])
    name = forms.TextField(lazy_gettext(u'Name'), max_length=50, required=True,
                           validators=[is_not_whitespace_only()])
    description = forms.TextField(lazy_gettext(u'Description'),
                                  max_length=5000, widget=forms.Textarea)

    def __init__(self, category=None, initial=None):
        if category is not None:
            initial = forms.fill_dict(initial,
                slug=category.slug,
                name=category.name,
                description=category.description
            )
        _CategoryBoundForm.__init__(self, category, initial)

    def validate_slug(self, value):
        """Make sure the slug is unique."""
        query = Category.query.filter_by(slug=value)
        if self.category is not None:
            query = query.filter(Category.id != self.category.id)
        existing = query.first()
        if existing is not None:
            raise ValidationError(_('This slug is already in use'))

    def make_category(self):
        """A helper function that creates a category object from the data."""
        category = Category(self.data['name'], self.data['description'],
                            self.data['slug'] or None)
        self.category = category
        return category

    def save_changes(self):
        """Save the changes back to the database.  This also adds a redirect
        if the slug changes.
        """
        old_slug = self.category.slug
        forms.set_fields(self.category, self.data, 'name', 'description')
        if self.data['slug']:
            self.category.slug = self.data['slug']
        elif not self.category.slug:
            self.category.set_auto_slug()
        if old_slug != self.category.slug:
            register_redirect(old_slug, self.category.slug)
Ejemplo n.º 6
0
class LoginForm(forms.Form):
    """The form for the login page."""
    user = forms.ModelField(User, 'username', required=True, messages=dict(
        not_found=lazy_gettext(u'User “%(value)s” does not exist.'),
        required=lazy_gettext(u'You have to enter a username.')
    ), on_not_found=lambda user:
        log.warning(_(u'Failed login attempt, user “%s” does not exist')
                      % user, 'auth')
    )
    password = forms.TextField(widget=forms.PasswordInput)
    permanent = forms.BooleanField()

    def context_validate(self, data):
        if not data['user'].check_password(data['password']):
            log.warning(_(u'Failed login attempt from “%s”, invalid password')
                        % data['user'].username, 'auth')
            raise ValidationError(_('Incorrect password.'))
Ejemplo n.º 7
0
    class _ImportForm(forms.Form):
        title = forms.BooleanField(lazy_gettext(u'Blog title'),
                                   help_text=blog.title)
        description = forms.BooleanField(lazy_gettext(u'Blog description'),
                                         help_text=blog.description)
        authors = forms.Mapping(_authors)
        posts = forms.Mapping(_posts)
        comments = forms.Mapping(_comments)
        load_config = forms.BooleanField(lazy_gettext(u'Load config values'),
                                         help_text=lazy_gettext(
                                         u'Load the configuration values '
                                         u'from the import.'))

        def perform_import(self):
            from zine.importers import perform_import
            return perform_import(get_application(), blog, self.data,
                                  stream=True)
Ejemplo n.º 8
0
class ZEMLParser(BaseParser):
    """The parser for the ZEML Markup language."""

    name = lazy_gettext('Zine-Markup')

    def parse(self, input_data, reason):
        rv = parse_zeml(input_data, reason, self.app.markup_extensions)
        if reason == 'comment':
            rv = sanitize(rv)
        return rv
Ejemplo n.º 9
0
class HTMLParser(BaseParser):
    """A parser that understands plain old HTML."""

    name = lazy_gettext('HTML')

    def parse(self, input_data, reason):
        rv = parse_html(input_data)
        if reason == 'comment':
            rv = sanitize(rv)
        return rv
Ejemplo n.º 10
0
class CacheOptionsForm(_ConfigForm):
    cache_system = config_field('cache_system', lazy_gettext(u'Cache system'))
    cache_timeout = config_field('cache_timeout',
                                 lazy_gettext(u'Default cache timeout'))
    enable_eager_caching = config_field('enable_eager_caching',
                                        lazy_gettext(u'Enable eager caching'),
                                        help_text=lazy_gettext(u'Enable'))
    memcached_servers = config_field('memcached_servers')
    filesystem_cache_path = config_field('filesystem_cache_path')

    def context_validate(self, data):
        if data['cache_system'] == 'memcached':
            if not data['memcached_servers']:
                raise ValidationError(_(u'You have to provide at least one '
                                        u'server to use memcached.'))
        elif data['cache_system'] == 'filesystem':
            if not data['filesystem_cache_path']:
                raise ValidationError(_(u'You have to provide cache folder to '
                                        u'use filesystem cache.'))
Ejemplo n.º 11
0
class DeleteGroupForm(_GroupBoundForm):
    """Used to delete a group from the admin panel."""

    action = forms.ChoiceField(lazy_gettext(u'What should Zine do with users '
                                            u'assigned to this group?'),
                              choices=[
        ('delete_membership', lazy_gettext(u'Do nothing, just detach the membership')),
        ('relocate', lazy_gettext(u'Move the users to another group'))
    ], widget=forms.RadioButtonGroup)
    relocate_to = forms.ModelField(Group, 'id', lazy_gettext(u'Relocate users to'),
                                   widget=forms.SelectBox)

    def __init__(self, group, initial=None):
        self.relocate_to.choices = [('', u'')] + [
            (g.id, g.name) for g in Group.query.filter(Group.id != group.id)
        ]

        _GroupBoundForm.__init__(self, group, forms.fill_dict(initial,
            action='delete_membership'))

    def context_validate(self, data):
        if data['action'] == 'relocate' and not data['relocate_to']:
            raise ValidationError(_('You have to select a group that '
                                    'gets the users assigned.'))

    def delete_group(self):
        """Deletes a group."""
        if self.data['action'] == 'relocate':
            new_group = Group.query.filter_by(data['reassign_to'].id).first()
            for user in self.group.users:
                if not new_group in user.groups:
                    user.groups.append(new_group)
        db.commit()

        #! plugins can use this to react to user deletes.  They can't stop
        #! the deleting of the group but they can delete information in
        #! their own tables so that the database is consistent afterwards.
        #! Additional to the group object the form data is submitted.
        emit_event('before-group-deleted', self.group, self.data)
        db.delete(self.group)
Ejemplo n.º 12
0
class EditCommentForm(_CommentBoundForm):
    """Form for comment editing in admin."""
    author = forms.TextField(lazy_gettext(u'Author'), required=True)
    email = forms.TextField(lazy_gettext(u'Email'),
                            validators=[is_valid_email()])
    www = forms.TextField(lazy_gettext(u'Website'),
                          validators=[is_valid_url()])
    text = forms.TextField(lazy_gettext(u'Text'), widget=forms.Textarea)
    pub_date = forms.DateTimeField(lazy_gettext(u'Date'), required=True)
    parser = forms.ChoiceField(lazy_gettext(u'Parser'), required=True)
    blocked = forms.BooleanField(lazy_gettext(u'Block Comment'))
    blocked_msg = forms.TextField(lazy_gettext(u'Reason'))

    def __init__(self, comment, initial=None):
        _CommentBoundForm.__init__(self, comment, forms.fill_dict(initial,
            author=comment.author,
            email=comment.email,
            www=comment.www,
            text=comment.text,
            pub_date=comment.pub_date,
            parser=comment.parser,
            blocked=comment.blocked,
            blocked_msg=comment.blocked_msg
        ))
        self.parser.choices = self.app.list_parsers()
        self.parser_missing = comment.parser_missing
        if self.parser_missing and comment.parser is not None:
            self.parser.choices.append((comment.parser, _('%s (missing)') %
                                        comment.parser.title()))

    def save_changes(self):
        """Save the changes back to the database."""
        old_parser = self.comment.parser
        forms.set_fields(self.comment, self.data, 'pub_date', 'parser',
                         'blocked_msg')

        if (self.data['text'] != self.comment.text
            or self.data['parser'] != old_parser):
            self.comment.text = self.data['text']

        # update status
        if self.data['blocked']:
            if not self.comment.blocked:
                self.comment.status = COMMENT_BLOCKED_USER
        else:
            self.comment.status = COMMENT_MODERATED

        # only apply these if the comment is not anonymous
        if self.comment.anonymous:
            forms.set_fields(self.comment, self.data, 'author', 'email', 'www')
Ejemplo n.º 13
0
class EditGroupForm(_GroupBoundForm):
    """Edit or create a group."""

    groupname = forms.TextField(lazy_gettext(u'Groupname'), max_length=30,
                                validators=[is_not_whitespace_only()],
                                required=True)
    privileges = forms.MultiChoiceField(lazy_gettext(u'Privileges'),
                                        widget=forms.CheckboxGroup)

    def __init__(self, group=None, initial=None):
        if group is not None:
            initial = forms.fill_dict(initial,
                groupname=group.name,
                privileges=[x.name for x in group.privileges]
            )
        _GroupBoundForm.__init__(self, group, initial)
        self.privileges.choices = self.app.list_privileges()

    def validate_groupname(self, value):
        query = Group.query.filter_by(name=value)
        if self.group is not None:
            query = query.filter(Group.id != self.group.id)
        if query.first() is not None:
            raise ValidationError(_('This groupname is already in use'))

    def _set_common_attributes(self, group):
        forms.set_fields(group, self.data)
        bind_privileges(group.privileges, self.data['privileges'])

    def make_group(self):
        """A helper function that creates a new group object."""
        group = Group(self.data['groupname'])
        self._set_common_attributes(group)
        self.group = group
        return group

    def save_changes(self):
        """Apply the changes."""
        self.group.name = self.data['groupname']
        self._set_common_attributes(self.group)
Ejemplo n.º 14
0
class ChangePasswordForm(forms.Form):
    """The form used on the password-change dialog in the admin panel."""
    old_password = forms.TextField(lazy_gettext(u'Old password'), required=True,
                                   widget=forms.PasswordInput)
    new_password = forms.TextField(lazy_gettext(u'New password'), required=True,
                                   widget=forms.PasswordInput)
    check_password = forms.TextField(lazy_gettext(u'Repeat password'),
                                     required=True,
                                     widget=forms.PasswordInput)

    def __init__(self, user, initial=None):
        forms.Form.__init__(self, initial)
        self.user = user

    def validate_old_password(self, value):
        if not self.user.check_password(value):
            raise ValidationError(_('The old password you\'ve '
                                    'entered is wrong.'))

    def context_validate(self, data):
        if data['new_password'] != data['check_password']:
            raise ValidationError(_('The two passwords don\'t match.'))
Ejemplo n.º 15
0
class DeleteUserForm(_UserBoundForm):
    """Used to delete a user from the admin panel."""

    action = forms.ChoiceField(lazy_gettext(u'What should Zine do with posts '
                                            u'written by this user?'), choices=[
        ('delete', lazy_gettext(u'Delete them permanently')),
        ('reassign', lazy_gettext(u'Reassign posts'))
    ], widget=forms.RadioButtonGroup)
    reassign_to = forms.ModelField(User, 'id',
                                   lazy_gettext(u'Reassign posts to'),
                                   widget=forms.SelectBox)

    def __init__(self, user, initial=None):
        self.reassign_to.choices = [('', u'')] + [
            (u.id, u.username)
            for u in User.query.filter(User.id != user.id)
        ]
        _UserBoundForm.__init__(self, user, forms.fill_dict(initial,
            action='reassign'
        ))

    def context_validate(self, data):
        if data['action'] == 'reassign' and not data['reassign_to']:
            # XXX: Bad wording
            raise ValidationError(_('You have to select the user that '
                                    'gets the posts assigned.'))

    def delete_user(self):
        """Deletes the user."""
        if self.data['action'] == 'reassign':
            db.execute(posts.update(posts.c.author_id == self.user.id), dict(
                author_id=self.data['reassign_to'].id
            ))
        #! plugins can use this to react to user deletes.  They can't stop
        #! the deleting of the user but they can delete information in
        #! their own tables so that the database is consistent afterwards.
        #! Additional to the user object the form data is submitted.
        emit_event('before-user-deleted', self.user, self.data)
        db.delete(self.user)
Ejemplo n.º 16
0
class InstallationError(UserException):
    """Raised during plugin installation."""

    MESSAGES = {
        'invalid':
        lazy_gettext('Could not install the plugin because the '
                     'uploaded file is not a valid plugin file.'),
        'version':
        lazy_gettext('The plugin uploaded has a newer package '
                     'version than this Zine installation '
                     'can handle.'),
        'exists':
        lazy_gettext('A plugin with the same UID is already '
                     'installed. Aborted.'),
        'ioerror':
        lazy_gettext('Could not install the package because the '
                     'installer wasn\'t able to write the package '
                     'information. Wrong permissions?')
    }

    def __init__(self, code):
        UserException.__init__(self, self.MESSAGES[code])
        self.code = code
Ejemplo n.º 17
0
class BlockCommentForm(_CommentBoundForm):
    """Form used to block comments."""

    message = forms.TextField(lazy_gettext(u'Reason'))

    def __init__(self, comment, initial=None):
        self.req = get_request()
        _CommentBoundForm.__init__(self, comment, initial)

    def block_comment(self):
        msg = self.data['message']
        if not msg and self.req:
            msg = _(u'blocked by %s') % self.req.user.display_name
        self.comment.status = COMMENT_BLOCKED_USER
        self.comment.bocked_msg = msg
Ejemplo n.º 18
0
def is_valid_email(message=None):
    """Check if the string passed is a valid mail address.

    >>> check(is_valid_email, '*****@*****.**')
    True
    >>> check(is_valid_email, 'somebody AT example DOT com')
    False
    >>> check(is_valid_email, 'some random string')
    False

    Because e-mail validation is painfully complex we just check the first
    part of the email if it looks okay (comments are not handled!) and ignore
    the second.
    """
    if message is None:
        message = lazy_gettext(u'You have to enter a valid e-mail address.')
    def validator(form, value):
        if len(value) > 250 or _mail_re.match(value) is None:
            raise ValidationError(message)
    return validator
Ejemplo n.º 19
0
def is_valid_url(message=None):
    """Check if the string passed is a valid URL.  We also blacklist some
    url schemes like javascript for security reasons.

    >>> check(is_valid_url, 'http://pocoo.org/')
    True
    >>> check(is_valid_url, 'http://zine.pocoo.org/archive')
    True
    >>> check(is_valid_url, 'zine.pocoo.org/archive')
    False
    >>> check(is_valid_url, 'javascript:alert("Zine rocks!");')
    False
    """
    if message is None:
        message = lazy_gettext(u'You have to enter a valid URL.')
    def validator(form, value):
        protocol = urlparse(value)[0]
        if not protocol or protocol == 'javascript':
            raise ValidationError(message)
    return validator
Ejemplo n.º 20
0
def is_valid_url(message=None):
    """Check if the string passed is a valid URL.  We also blacklist some
    url schemes like javascript for security reasons.

    >>> check(is_valid_url, 'http://pocoo.org/')
    True
    >>> check(is_valid_url, 'http://zine.pocoo.org/archive')
    True
    >>> check(is_valid_url, 'zine.pocoo.org/archive')
    False
    >>> check(is_valid_url, 'javascript:alert("Zine rocks!");')
    False
    """
    if message is None:
        message = lazy_gettext(u'You have to enter a valid URL.')

    def validator(form, value):
        protocol = urlparse(value)[0]
        if not protocol or protocol == 'javascript':
            raise ValidationError(message)

    return validator
Ejemplo n.º 21
0
class ConfigurationTransactionError(InternalError):
    """An exception that is raised if the transaction was unable to
    write the changes to the config file.
    """

    help_text = lazy_gettext(u'''
    <p>
      This error can happen if the configuration file is not writeable.
      Make sure the folder of the configuration file is writeable and
      that the file itself is writeable as well.
    ''')

    def __init__(self, message_or_exception):
        if isinstance(message_or_exception, basestring):
            message = message_or_exception
            error = None
        else:
            message = _(u'Could not save configuration file: %s') % \
                      str(message_or_exception).decode('utf-8', 'ignore')
            error = message_or_exception
        InternalError.__init__(self, message)
        self.original_exception = error
Ejemplo n.º 22
0
def is_valid_email(message=None):
    """Check if the string passed is a valid mail address.

    >>> check(is_valid_email, '*****@*****.**')
    True
    >>> check(is_valid_email, 'somebody AT example DOT com')
    False
    >>> check(is_valid_email, 'some random string')
    False

    Because e-mail validation is painfully complex we just check the first
    part of the email if it looks okay (comments are not handled!) and ignore
    the second.
    """
    if message is None:
        message = lazy_gettext(u'You have to enter a valid e-mail address.')

    def validator(form, value):
        if len(value) > 250 or _mail_re.match(value) is None:
            raise ValidationError(message)

    return validator
Ejemplo n.º 23
0
def make_config_form():
    """Returns the form for the configuration editor."""
    app = get_application()
    fields = {}
    values = {}
    use_default_label = lazy_gettext(u'Use default value')

    for category in app.cfg.get_detail_list():
        items = {}
        values[category['name']] = category_values = {}
        for item in category['items']:
            items[item['name']] = forms.Mapping(
                value=item['field'],
                use_default=forms.BooleanField(use_default_label)
            )
            category_values[item['name']] = {
                'value':        item['value'],
                'use_default':  False
            }
        fields[category['name']] = forms.Mapping(**items)

    class _ConfigForm(forms.Form):
        values = forms.Mapping(**fields)
        cfg = app.cfg

        def apply(self):
            t = self.cfg.edit()
            for category, items in self.data['values'].iteritems():
                for key, d in items.iteritems():
                    if category != 'zine':
                        key = '%s/%s' % (category, key)
                    if d['use_default']:
                        t.revert_to_default(key)
                    else:
                        t[key] = d['value']
            t.commit()

    return _ConfigForm({'values': values})
Ejemplo n.º 24
0
class FeedImporter(Importer):
    name = 'feed'
    title = lazy_gettext(u'Feed Importer')

    def configure(self, request):
        form = FeedImportForm()

        if request.method == 'POST' and form.validate(request.form):
            feed = request.files.get('feed')
            if form.data['download_url']:
                try:
                    feed = open_url(form.data['download_url']).stream
                except Exception, e:
                    error = _(u'Error downloading from URL: %s') % e
            elif not feed:
                return redirect_to('import/feed')

            try:
                blog = parse_feed(feed)
            except Exception, e:
                log.exception(_(u'Error parsing uploaded file'))
                flash(_(u'Error parsing feed: %s') % e, 'error')
            else:
Ejemplo n.º 25
0
class PlainTextParser(BaseParser):
    """Parses simple text into a ZEML tree by utilizing pottymouth."""

    name = lazy_gettext('Text')

    def _to_text(self, token):
        """Convert a token to normal text."""
        return replace_entities(unicode(token))

    def _to_zeml(self, node):
        """Convert a potty-mouth node into a ZEML tree."""
        from zine._ext.pottymouth import Token
        def convert(node, is_root):
            if is_root:
                result = RootElement()
            else:
                result = Element(node.name)
            if node._attributes:
                result.attributes.update(node._attributes)
            for item in node:
                if isinstance(item, (str, unicode, Token)):
                    text = self._to_text(item)
                    if result.children:
                        result.children[-1].tail += text
                    else:
                        result.text += text
                else:
                    result.children.append(convert(item, False))
            return result
        return convert(node, True)

    def parse(self, input_data, reason):
        from zine._ext.pottymouth import PottyMouth
        parser = PottyMouth(emdash=False, ellipsis=False, smart_quotes=False,
                            youtube=False, image=False, italic=False)
        node = parser.parse(input_data)
        return self._to_zeml(node)
Ejemplo n.º 26
0
class PlainTextParser(BaseParser):
    """Parses simple text into a ZEML tree by utilizing pottymouth."""

    name = lazy_gettext('Text')

    def _to_text(self, token):
        """Convert a token to normal text."""
        return replace_entities(unicode(token))

    def _to_zeml(self, node, untrusted=False):
        """Convert a potty-mouth node into a ZEML tree."""
        from zine._ext.pottymouth import Token

        def add_text(node, text):
            if node.children:
                node.children[-1].tail += text
            else:
                node.text += text

        def convert(node, is_root):
            if is_root:
                result = RootElement()
            else:
                result = Element(node.name)
            if node._attributes:
                result.attributes.update(node._attributes)

            for item in node:
                if isinstance(item, (str, unicode, Token)):
                    add_text(result, self._to_text(item))
                else:
                    child = convert(item, False)
                    # remove the useless empty spans
                    if child.name == 'span' and not child.attributes:
                        add_text(result, child.text)
                        result.children.extend(child.children)
                        add_text(result, child.tail)
                    else:
                        result.children.append(child)

            # fixes an output bug from pottymouth
            if len(result.children) == 1 and node.name == 'p' and \
               result.children[0].name == 'blockquote':
                result = result.children[0]

            # untrusted posts get nofollow on links
            if untrusted and result.name == 'a':
                result.attributes['rel'] = 'nofollow'

            return result

        return convert(node, True)

    def parse(self, input_data, reason):
        from zine._ext.pottymouth import PottyMouth
        parser = PottyMouth(
            emdash=False,
            ellipsis=False,
            smart_quotes=False,
            youtube=False,
            image=False,
            italic=False,
            all_links=not self.app.cfg['plaintext_parser_nolinks'])
        node = parser.parse(input_data)
        return self._to_zeml(node, reason == 'comment')
Ejemplo n.º 27
0
class LogOptionsForm(_ConfigForm):
    """A form for the logfiles."""
    log_file = config_field('log_file', lazy_gettext(u'Filename'))
    log_level = config_field('log_level', lazy_gettext(u'Log Level'))
Ejemplo n.º 28
0
class BasicOptionsForm(_ConfigForm):
    """The form where the basic options are changed."""
    blog_title = config_field('blog_title', lazy_gettext(u'Blog title'))
    blog_tagline = config_field('blog_tagline', lazy_gettext(u'Blog tagline'))
    blog_email = config_field('blog_email', lazy_gettext(u'Blog email'))
    language = config_field('language', lazy_gettext(u'Language'))
    timezone = config_field('timezone', lazy_gettext(u'Timezone'))
    session_cookie_name = config_field('session_cookie_name',
                                       lazy_gettext(u'Cookie Name'))
    comments_enabled = config_field('comments_enabled',
        label=lazy_gettext(u'Comments enabled'),
        help_text=lazy_gettext(u'enable comments per default'))
    moderate_comments = config_field('moderate_comments',
                                     lazy_gettext(u'Comment Moderation'),
                                     widget=forms.RadioButtonGroup)
    pings_enabled = config_field('pings_enabled',
        lazy_gettext(u'Pingbacks enabled'),
        help_text=lazy_gettext(u'enable pingbacks per default'))
    use_flat_comments = config_field('use_flat_comments',
        lazy_gettext(u'Use flat comments'),
        help_text=lazy_gettext(u'All comments are posted top-level'))
    default_parser = config_field('default_parser',
                                  lazy_gettext(u'Default parser'))
    comment_parser = config_field('comment_parser',
                                  lazy_gettext(u'Comment parser'))
    posts_per_page = config_field('posts_per_page',
                                  lazy_gettext(u'Posts per page'))

    def __init__(self, initial=None):
        _ConfigForm.__init__(self, initial)
        self.language.choices = list_languages()
        self.default_parser.choices = self.comment_parser.choices = \
            self.app.list_parsers()
Ejemplo n.º 29
0
            user = get_request().user
        for notification in self.notification_types.itervalues():
            if user.has_privilege(notification.privileges):
                yield notification

    def add_notification_type(self, notification):
        self.notification_types[type.name] = type


def _register(name, description, privileges=ENTER_ACCOUNT_PANEL):
    """Register a new builtin type of notifications."""
    nottype = NotificationType(name, description, privileges)
    DEFAULT_NOTIFICATION_TYPES[name] = nottype
    globals()[name] = nottype
    __all__.append(name)


_register('NEW_COMMENT',
          lazy_gettext(u'When a new comment is received.'))
_register('COMMENT_REQUIRES_MODERATION',
          lazy_gettext(u'When a comment requires moderation.'),
          (MODERATE_OWN_PAGES | MODERATE_OWN_ENTRIES | MODERATE_COMMENTS))
_register('SECURITY_ALERT',
          lazy_gettext(u'When Zine found an urgent security alarm.'),
          BLOG_ADMIN)
_register('ZINE_ERROR', lazy_gettext(u'When Zine throws errors.'), BLOG_ADMIN)


DEFAULT_NOTIFICATION_SYSTEMS = [EMailNotificationSystem]
del _register
Ejemplo n.º 30
0
        return priv

    return db.association_proxy(lowlevel_attribute,
                                'privilege',
                                creator=creator_func)


def _register(name, description):
    """Register a new builtin privilege."""
    priv = Privilege(name, description)
    DEFAULT_PRIVILEGES[name] = priv
    globals()[name] = priv
    __all__.append(name)


_register('ENTER_ADMIN_PANEL', lazy_gettext(u'can enter admin panel'))
_register('BLOG_ADMIN', lazy_gettext(u'can administer the blog'))
_register('CREATE_ENTRIES', lazy_gettext(u'can create new entries'))
_register('EDIT_OWN_ENTRIES', lazy_gettext(u'can edit their own entries'))
_register('EDIT_OTHER_ENTRIES',
          lazy_gettext(u'can edit another person\'s entries'))
_register('CREATE_PAGES', lazy_gettext(u'can create new pages'))
_register('EDIT_OWN_PAGES', lazy_gettext(u'can edit their own pages'))
_register('EDIT_OTHER_PAGES',
          lazy_gettext(u'can edit another person\'s pages'))
_register('VIEW_DRAFTS', lazy_gettext(u'can view drafts'))
_register('MANAGE_CATEGORIES', lazy_gettext(u'can manage categories'))
_register('MODERATE_COMMENTS', lazy_gettext(u'can moderate comments'))
_register('VIEW_PROTECTED', lazy_gettext(u'can view protected entries'))

CONTENT_TYPE_PRIVILEGES = {
Ejemplo n.º 31
0
class EMailNotificationSystem(NotificationSystem):
    """Sends notifications to user via E-Mail."""

    key = 'email'
    name = lazy_gettext(u'E-Mail')

    def send(self, user, notification):
        title = u'[%s] %s' % (self.app.cfg['blog_title'],
                              notification.title.to_text())
        text = self.mail_from_notification(notification)
        send_email(title, text, [user.email])

    def unquote_link(self, link):
        """Unquotes some kinds of links.  For example mailto:foo links are
        stripped and properly unquoted because the mails we write are in
        plain text and nobody is interested in URLs there.
        """
        scheme, netloc, path = urlsplit(link)[:3]
        if scheme == 'mailto':
            return url_unquote(path)
        return link

    def collect_list_details(self, container):
        """Returns the information collected from a single detail list item."""
        for item in container.children:
            if len(item.children) == 1 and item.children[0].name == 'a':
                link = item.children[0]
                href = link.attributes.get('href')
                yield dict(text=link.to_text(simple=True),
                           link=self.unquote_link(href),
                           is_textual=False)
            else:
                yield dict(text=item.to_text(multiline=False),
                           link=None,
                           is_textual=True)

    def find_details(self, container):
        # no container given, nothing can be found
        if container is None or not container.children:
            return []

        result = []
        for child in container.children:
            if child.name in ('ul', 'ol'):
                result.extend(self.collect_list_details(child))
            elif child.name == 'p':
                result.extend(
                    dict(text=child.to_text(), link=None, is_textual=True))
        return result

    def find_actions(self, container):
        if not container:
            return []
        ul = container.query('/ul').first
        if not ul:
            return []
        return list(self.collect_list_details(ul))

    def mail_from_notification(self, message):
        title = message.title.to_text()
        details = self.find_details(message.details)
        longtext = message.longtext.to_text(collect_urls=True,
                                            initial_indent=2)
        actions = self.find_actions(message.actions)
        return render_template('notifications/email.txt',
                               title=title,
                               details=details,
                               longtext=longtext,
                               actions=actions)
Ejemplo n.º 32
0
    def types(self, user=None):
        if not user:
            user = get_request().user
        for notification in self.notification_types.itervalues():
            if user.has_privilege(notification.privileges):
                yield notification

    def add_notification_type(self, notification):
        self.notification_types[type.name] = type


def _register(name, description, privileges=ENTER_ACCOUNT_PANEL):
    """Register a new builtin type of notifications."""
    nottype = NotificationType(name, description, privileges)
    DEFAULT_NOTIFICATION_TYPES[name] = nottype
    globals()[name] = nottype
    __all__.append(name)


_register('NEW_COMMENT', lazy_gettext(u'When a new comment is received.'))
_register('COMMENT_REQUIRES_MODERATION',
          lazy_gettext(u'When a comment requires moderation.'),
          (MODERATE_OWN_PAGES | MODERATE_OWN_ENTRIES | MODERATE_COMMENTS))
_register('SECURITY_ALERT',
          lazy_gettext(u'When Zine found an urgent security alarm.'),
          BLOG_ADMIN)
_register('ZINE_ERROR', lazy_gettext(u'When Zine throws errors.'), BLOG_ADMIN)

DEFAULT_NOTIFICATION_SYSTEMS = [EMailNotificationSystem]
del _register
Ejemplo n.º 33
0
class URLOptionsForm(_ConfigForm):
    """The form for url changes.  This form sends database queries, even
    though seems to only operate on the config.  Make sure to commit.
    """

    blog_url_prefix = config_field('blog_url_prefix',
                                   lazy_gettext(u'Blog URL prefix'))
    admin_url_prefix = config_field('admin_url_prefix',
                                    lazy_gettext(u'Admin URL prefix'))
    category_url_prefix = config_field('category_url_prefix',
                                       lazy_gettext(u'Category URL prefix'))
    tags_url_prefix = config_field('tags_url_prefix',
                                   lazy_gettext(u'Tag URL prefix'))
    profiles_url_prefix = config_field('profiles_url_prefix',
        lazy_gettext(u'Author Profiles URL prefix'))
    upload_url_prefix = config_field('upload_url_prefix',
        lazy_gettext(u'Uploaded files URL prefix'),
        help_text=lazy_gettext(u'If you change this, links to uploaded files '\
                               u'from existing posts will not be automatically '\
                               u'corrected. You must edit those posts manually. '\
                               u'This setting will take effect when Zine is '\
                               u'restarted.'))
    upload_path_format = config_field('upload_path_format',
        lazy_gettext(u'Uploaded files path format'),
        help_text=lazy_gettext(u'Path to which post attachments are saved.'))
    post_url_format = config_field('post_url_format',
        lazy_gettext(u'Post permalink URL format'),
        help_text=lazy_gettext(u'Use %year%, %month%, %day%, %hour%, '
                               u'%minute% and %second%. Changes here will '
                               u'only affect new posts. The slug will be '
                               u'appended to this.'))
    ascii_slugs = config_field('ascii_slugs',
                               lazy_gettext(u'Limit slugs to ASCII'),
                               help_text=lazy_gettext(u'Automatically '
                               u'generated slugs are limited to ASCII'))
    fixed_url_date_digits = config_field('fixed_url_date_digits',
                                     lazy_gettext(u'Use zero-padded dates'),
                                     help_text=lazy_gettext(u'Dates are zero '
                                     u'padded like 2009/04/22 instead of '
                                     u'2009/4/22'))

    def _apply(self, t, skip):
        for key, value in self.data.iteritems():
            if key not in skip:
                old = t[key]
                if old != value:
                    if key == 'blog_url_prefix':
                        change_url_prefix(old, value)
                    t[key] = value
Ejemplo n.º 34
0
        if priv is None:
            priv = _Privilege(privilege.name)
        return priv
    return db.association_proxy(lowlevel_attribute, 'privilege',
                                creator=creator_func)


def _register(name, description, privilege_dependencies=None):
    """Register a new builtin privilege."""
    priv = Privilege(name, description, privilege_dependencies)
    DEFAULT_PRIVILEGES[name] = priv
    globals()[name] = priv
    __all__.append(name)


_register('ENTER_ADMIN_PANEL', lazy_gettext(u'can enter admin panel'))
_register('BLOG_ADMIN', lazy_gettext(u'can administer the blog'))
_register('CREATE_ENTRIES', lazy_gettext(u'can create new entries'),
          ENTER_ADMIN_PANEL)
_register('EDIT_OWN_ENTRIES', lazy_gettext(u'can edit their own entries'),
          (ENTER_ADMIN_PANEL | CREATE_ENTRIES))
_register('EDIT_OTHER_ENTRIES', lazy_gettext(u'can edit another person\'s entries'),
          ENTER_ADMIN_PANEL)
_register('CREATE_PAGES', lazy_gettext(u'can create new pages'),
          ENTER_ADMIN_PANEL)
_register('EDIT_OWN_PAGES', lazy_gettext(u'can edit their own pages'),
          (ENTER_ADMIN_PANEL | CREATE_PAGES))
_register('EDIT_OTHER_PAGES', lazy_gettext(u'can edit another person\'s pages'),
          ENTER_ADMIN_PANEL)
_register('VIEW_DRAFTS', lazy_gettext(u'can view drafts'))
_register('MANAGE_CATEGORIES', lazy_gettext(u'can manage categories'),