Beispiel #1
0
 def get_error_404(self, req):
     """
     Show a simple error 404 page.
     """
     return Response(render_template(req, 'not_found.html',
                                     self.globalcontext),
                     status=404)
Beispiel #2
0
    def _insert_comments(self, req, url, context, mode):
        """
        Insert inline comments into a page context.
        """
        if 'body' not in context:
            return

        comment_url = '@comments/%s/' % url
        page_id = self.env.get_real_filename(url)[:-4]
        tx = context['body']
        all_comments = Comment.get_for_page(page_id)
        global_comments = []
        for name, comments in groupby(all_comments,
                                      lambda x: x.associated_name):
            if not name:
                global_comments.extend(comments)
                continue
            comments = list(comments)
            if not comments:
                continue
            tx = re.sub(
                '<!--#%s#-->' % name,
                render_template(
                    req, 'inlinecomments.html', {
                        'comments': comments,
                        'id': name,
                        'comment_url': comment_url,
                        'mode': mode
                    }), tx)
            if mode == 'bottom':
                global_comments.extend(comments)
        if mode == 'inline':
            # replace all markers for items without comments
            tx = re.sub('<!--#([^#]*)#-->', (lambda match: render_template(
                req,
                'inlinecomments.html',
                {
                    'id': match.group(1),
                    'mode': 'inline',
                    'comment_url': comment_url
                },
            )), tx)
        tx += render_template(req, 'comments.html', {
            'comments': global_comments,
            'comment_url': comment_url
        })
        context['body'] = tx
Beispiel #3
0
 def get_special_page(self, req, name):
     yield '@' + name
     filename = path.join(self.data_root, name + '.fpickle')
     f = open(filename, 'rb')
     try:
         context = pickle.load(f)
     finally:
         f.close()
     yield render_template(req, name + '.html', self.globalcontext, context)
Beispiel #4
0
 def get_special_page(self, req, name):
     yield '@'+name
     filename = path.join(self.data_root, name + '.fpickle')
     f = open(filename, 'rb')
     try:
         context = pickle.load(f)
     finally:
         f.close()
     yield render_template(req, name+'.html',
                           self.globalcontext, context)
Beispiel #5
0
    def _insert_comments(self, req, url, context, mode):
        """
        Insert inline comments into a page context.
        """
        if 'body' not in context:
            return

        comment_url = '@comments/%s/' % url
        page_id = self.env.get_real_filename(url)[:-4]
        tx = context['body']
        all_comments = Comment.get_for_page(page_id)
        global_comments = []
        for name, comments in groupby(all_comments, lambda x: x.associated_name):
            if not name:
                global_comments.extend(comments)
                continue
            comments = list(comments)
            if not comments:
                continue
            tx = re.sub('<!--#%s#-->' % name,
                        render_template(req, 'inlinecomments.html', {
                            'comments':     comments,
                            'id':           name,
                            'comment_url':  comment_url,
                            'mode':         mode}),
                        tx)
            if mode == 'bottom':
                global_comments.extend(comments)
        if mode == 'inline':
            # replace all markers for items without comments
            tx = re.sub('<!--#([^#]*)#-->',
                        (lambda match:
                         render_template(req, 'inlinecomments.html', {
                             'id':          match.group(1),
                             'mode':        'inline',
                             'comment_url': comment_url
                         },)),
                        tx)
        tx += render_template(req, 'comments.html', {
            'comments':         global_comments,
            'comment_url':      comment_url
        })
        context['body'] = tx
Beispiel #6
0
    def suggest_changes(self, req, page):
        """
        Show a "suggest changes" form.
        """
        page_id, contents = self.get_page_source(page)

        return Response(render_template(req, 'edit.html', self.globalcontext, dict(
            contents=contents,
            pagename=page,
            doctitle=self.globalcontext['titles'].get(page_id+'.rst') or 'this page',
            submiturl=relative_uri('/@edit/'+page+'/', '/@submit/'+page),
        )))
Beispiel #7
0
    def get_keyword_matches(self,
                            req,
                            term=None,
                            avoid_fuzzy=False,
                            is_error_page=False):
        """
        Find keyword matches. If there is an exact match, just redirect:
        http://docs.python.org/os.path.exists would automatically
        redirect to http://docs.python.org/library/os.path/#os.path.exists.
        Else, show a page with close matches.

        Module references are processed first so that "os.path" is handled as
        a module and not as member of os.
        """
        if term is None:
            term = req.path.strip('/')

        matches = self.env.find_keyword(term, avoid_fuzzy)

        # if avoid_fuzzy is False matches can be None
        if matches is None:
            return

        if isinstance(matches, tuple):
            url = get_target_uri(matches[1])
            if matches[0] != 'module':
                url += '#' + matches[2]
            return RedirectResponse(url)
        else:
            # get some close matches
            close_matches = []
            good_matches = 0
            for ratio, type, filename, anchorname, desc in matches:
                link = get_target_uri(filename)
                if type != 'module':
                    link += '#' + anchorname
                good_match = ratio > 0.75
                good_matches += good_match
                close_matches.append({
                    'href': relative_uri(req.path, link),
                    'title': anchorname,
                    'good_match': good_match,
                    'type': self.pretty_type.get(type, type),
                    'description': desc,
                })
            return Response(render_template(
                req, 'keyword_not_found.html', {
                    'close_matches': close_matches,
                    'good_matches_count': good_matches,
                    'keyword': term
                }, self.globalcontext),
                            status=404)
Beispiel #8
0
    def get_module_index(self, req):
        """
        Get the module index or redirect to a module from the module index.
        """
        most_frequent = heapq.nlargest(30, self.freqmodules.iteritems(),
                                       lambda x: x[1])
        if most_frequent:
            base_count = most_frequent[-1][1]
            most_frequent = [{
                'name': x[0],
                'size': 100 + math.log((x[1] - base_count) + 1) * 20,
                'count': x[1]
            } for x in sorted(most_frequent)]

        showpf = None
        newpf = req.args.get('newpf')
        sesspf = req.session.get('pf')
        if newpf or sesspf:
            yield NoCache
            if newpf:
                req.session['pf'] = showpf = req.args.getlist('pf')
            else:
                showpf = sesspf
        else:
            if most_frequent != self.last_most_frequent:
                self.cache.pop('@modindex', None)
            yield '@modindex'

        filename = path.join(self.data_root, 'modindex.fpickle')
        f = open(filename, 'rb')
        try:
            context = pickle.load(f)
        finally:
            f.close()
        if showpf:
            entries = context['modindexentries']
            i = 0
            while i < len(entries):
                if entries[i][6]:
                    for pform in entries[i][6]:
                        if pform in showpf:
                            break
                    else:
                        del entries[i]
                        continue
                i += 1
        context['freqentries'] = most_frequent
        context['showpf'] = showpf or context['platforms']
        self.last_most_frequent = most_frequent
        yield render_template(req, 'modindex.html', self.globalcontext,
                              context)
Beispiel #9
0
    def get_module_index(self, req):
        """
        Get the module index or redirect to a module from the module index.
        """
        most_frequent = heapq.nlargest(30, self.freqmodules.iteritems(),
                                       lambda x: x[1])
        if most_frequent:
            base_count = most_frequent[-1][1]
            most_frequent = [{
                'name':         x[0],
                'size':         100 + math.log((x[1] - base_count) + 1) * 20,
                'count':        x[1]
                } for x in sorted(most_frequent)]

        showpf = None
        newpf = req.args.get('newpf')
        sesspf = req.session.get('pf')
        if newpf or sesspf:
            yield NoCache
            if newpf:
                req.session['pf'] = showpf = req.args.getlist('pf')
            else:
                showpf = sesspf
        else:
            if most_frequent != self.last_most_frequent:
                self.cache.pop('@modindex', None)
            yield '@modindex'

        filename = path.join(self.data_root, 'modindex.fpickle')
        f = open(filename, 'rb')
        try:
            context = pickle.load(f)
        finally:
            f.close()
        if showpf:
            entries = context['modindexentries']
            i = 0
            while i < len(entries):
                if entries[i][6]:
                    for pform in entries[i][6]:
                        if pform in showpf:
                            break
                    else:
                        del entries[i]
                        continue
                i += 1
        context['freqentries'] = most_frequent
        context['showpf'] = showpf or context['platforms']
        self.last_most_frequent = most_frequent
        yield render_template(req, 'modindex.html',
                               self.globalcontext, context)
Beispiel #10
0
    def get_keyword_matches(self, req, term=None, avoid_fuzzy=False,
                            is_error_page=False):
        """
        Find keyword matches. If there is an exact match, just redirect:
        http://docs.python.org/os.path.exists would automatically
        redirect to http://docs.python.org/library/os.path/#os.path.exists.
        Else, show a page with close matches.

        Module references are processed first so that "os.path" is handled as
        a module and not as member of os.
        """
        if term is None:
            term = req.path.strip('/')

        matches = self.env.find_keyword(term, avoid_fuzzy)

        # if avoid_fuzzy is False matches can be None
        if matches is None:
            return

        if isinstance(matches, tuple):
            url = get_target_uri(matches[1])
            if matches[0] != 'module':
                url += '#' + matches[2]
            return RedirectResponse(url)
        else:
            # get some close matches
            close_matches = []
            good_matches = 0
            for ratio, type, filename, anchorname, desc in matches:
                link = get_target_uri(filename)
                if type != 'module':
                    link += '#' + anchorname
                good_match = ratio > 0.75
                good_matches += good_match
                close_matches.append({
                    'href':         relative_uri(req.path, link),
                    'title':        anchorname,
                    'good_match':   good_match,
                    'type':         self.pretty_type.get(type, type),
                    'description':  desc,
                })
            return Response(render_template(req, 'keyword_not_found.html', {
                'close_matches':        close_matches,
                'good_matches_count':   good_matches,
                'keyword':              term
            }, self.globalcontext), status=404)
Beispiel #11
0
    def suggest_changes(self, req, page):
        """
        Show a "suggest changes" form.
        """
        page_id, contents = self.get_page_source(page)

        return Response(
            render_template(
                req, 'edit.html', self.globalcontext,
                dict(
                    contents=contents,
                    pagename=page,
                    doctitle=self.globalcontext['titles'].get(page_id + '.rst')
                    or 'this page',
                    submiturl=relative_uri('/@edit/' + page + '/',
                                           '/@submit/' + page),
                )))
Beispiel #12
0
 def do_login(self, req):
     """
     Display login form and do the login procedure.
     """
     if req.user is not None:
         return RedirectResponse('@admin/')
     login_failed = False
     if req.method == 'POST':
         if req.form.get('cancel'):
             return RedirectResponse('')
         username = req.form.get('username')
         password = req.form.get('password')
         if self.userdb.check_password(username, password):
             req.login(username)
             return RedirectResponse('@admin/')
         login_failed = True
     return Response(render_template(req, 'admin/login.html', {
         'login_failed': login_failed
     }))
Beispiel #13
0
 def do_change_password(self, req):
     """
     Allows the user to change his password.
     """
     change_failed = change_successful = False
     if req.method == 'POST':
         if req.form.get('cancel'):
             return RedirectResponse('@admin/')
         pw = req.form.get('pw1')
         if pw and pw == req.form.get('pw2'):
             self.userdb.set_password(req.user, pw)
             self.userdb.save()
             change_successful = True
         else:
             change_failed = True
     return Response(render_template(req, 'admin/change_password.html', {
         'change_failed':        change_failed,
         'change_successful':    change_successful
     }))
Beispiel #14
0
 def do_login(self, req):
     """
     Display login form and do the login procedure.
     """
     if req.user is not None:
         return RedirectResponse('@admin/')
     login_failed = False
     if req.method == 'POST':
         if req.form.get('cancel'):
             return RedirectResponse('')
         username = req.form.get('username')
         password = req.form.get('password')
         if self.userdb.check_password(username, password):
             req.login(username)
             return RedirectResponse('@admin/')
         login_failed = True
     return Response(
         render_template(req, 'admin/login.html',
                         {'login_failed': login_failed}))
Beispiel #15
0
 def do_change_password(self, req):
     """
     Allows the user to change his password.
     """
     change_failed = change_successful = False
     if req.method == 'POST':
         if req.form.get('cancel'):
             return RedirectResponse('@admin/')
         pw = req.form.get('pw1')
         if pw and pw == req.form.get('pw2'):
             self.userdb.set_password(req.user, pw)
             self.userdb.save()
             change_successful = True
         else:
             change_failed = True
     return Response(
         render_template(
             req, 'admin/change_password.html', {
                 'change_failed': change_failed,
                 'change_successful': change_successful
             }))
Beispiel #16
0
    def dispatch(self, req, page):
        """
        Dispatch the requests for the current user in the admin panel.
        """
        is_logged_in = req.user is not None
        if is_logged_in:
            privileges = self.userdb.privileges[req.user]
            is_master_admin = 'master' in privileges
            can_change_password = '******' not in privileges
        else:
            privileges = set()
            can_change_password = is_master_admin = False

        # login and logout
        if page == 'login':
            return self.do_login(req)
        elif not is_logged_in:
            return RedirectResponse('@admin/login/')
        elif page == 'logout':
            return self.do_logout(req)

        # account maintance
        elif page == 'change_password' and can_change_password:
            return self.do_change_password(req)
        elif page == 'manage_users' and is_master_admin:
            return self.do_manage_users(req)

        # moderate comments
        elif page.split('/')[0] == 'moderate_comments':
            return self.do_moderate_comments(req, page[18:])

        # missing page
        elif page != '':
            raise NotFound()
        return Response(
            render_template(
                req, 'admin/index.html', {
                    'is_master_admin': is_master_admin,
                    'can_change_password': can_change_password
                }))
Beispiel #17
0
    def get_page(self, req, url):
        """
        Show the requested documentation page or raise an
        `NotFound` exception to display a page with close matches.
        """
        page_id = self.env.get_real_filename(url)[:-4]
        if page_id is None:
            raise NotFound(show_keyword_matches=True)
        # increment view count of all modules on that page
        for modname in self.env.filemodules.get(page_id+'.rst', ()):
            self.freqmodules[modname] = self.freqmodules.get(modname, 0) + 1
        # comments enabled?
        comments = self.env.metadata[page_id+'.rst'].get('nocomments', False)

        # how does the user want to view comments?
        commentmode = comments and req.session.get('comments', 'inline') or ''

        # show "old URL" message? -> no caching possible
        oldurl = req.args.get('oldurl')
        if oldurl:
            yield NoCache
        else:
            # there must be different cache entries per comment mode
            yield page_id + '|' + commentmode

        # cache miss; load the page and render it
        filename = path.join(self.data_root, page_id + '.fpickle')
        f = open(filename, 'rb')
        try:
            context = pickle.load(f)
        finally:
            f.close()

        # add comments to paqe text
        if commentmode != 'none':
            self._insert_comments(req, url, context, commentmode)

        yield render_template(req, 'page.html', self.globalcontext, context,
                              {'oldurl': oldurl})
Beispiel #18
0
    def get_settings_page(self, req):
        """
        Handle the settings page.
        """
        referer = req.environ.get('HTTP_REFERER') or ''
        if referer:
            base = get_base_uri(req.environ)
            if not referer.startswith(base):
                referer = ''
            else:
                referer = referer[len(base):]
                referer = referer.split('?')[0] or referer

        if req.method == 'POST':
            if req.form.get('cancel'):
                if req.form.get('referer'):
                    return RedirectResponse(req.form['referer'])
                return RedirectResponse('')
            new_style = req.form.get('design')
            if new_style and new_style in known_designs:
                req.session['design'] = new_style
            new_comments = req.form.get('comments')
            if new_comments and new_comments in comments_methods:
                req.session['comments'] = new_comments
            if req.form.get('goback') and req.form.get('referer'):
                return RedirectResponse(req.form['referer'])
            # else display the same page again
            referer = ''

        context = {
            'known_designs':    sorted(known_designs.iteritems()),
            'comments_methods': comments_methods.items(),
            'curdesign':        req.session.get('design') or 'default',
            'curcomments':      req.session.get('comments') or 'inline',
            'referer':          referer,
        }

        return Response(render_template(req, 'settings.html',
                                        self.globalcontext, context))
Beispiel #19
0
    def get_settings_page(self, req):
        """
        Handle the settings page.
        """
        referer = req.environ.get('HTTP_REFERER') or ''
        if referer:
            base = get_base_uri(req.environ)
            if not referer.startswith(base):
                referer = ''
            else:
                referer = referer[len(base):]
                referer = referer.split('?')[0] or referer

        if req.method == 'POST':
            if req.form.get('cancel'):
                if req.form.get('referer'):
                    return RedirectResponse(req.form['referer'])
                return RedirectResponse('')
            new_style = req.form.get('design')
            if new_style and new_style in known_designs:
                req.session['design'] = new_style
            new_comments = req.form.get('comments')
            if new_comments and new_comments in comments_methods:
                req.session['comments'] = new_comments
            if req.form.get('goback') and req.form.get('referer'):
                return RedirectResponse(req.form['referer'])
            # else display the same page again
            referer = ''

        context = {
            'known_designs': sorted(known_designs.iteritems()),
            'comments_methods': comments_methods.items(),
            'curdesign': req.session.get('design') or 'default',
            'curcomments': req.session.get('comments') or 'inline',
            'referer': referer,
        }

        return Response(
            render_template(req, 'settings.html', self.globalcontext, context))
Beispiel #20
0
    def get_page(self, req, url):
        """
        Show the requested documentation page or raise an
        `NotFound` exception to display a page with close matches.
        """
        page_id = self.env.get_real_filename(url)[:-4]
        if page_id is None:
            raise NotFound(show_keyword_matches=True)
        # increment view count of all modules on that page
        for modname in self.env.filemodules.get(page_id + '.rst', ()):
            self.freqmodules[modname] = self.freqmodules.get(modname, 0) + 1
        # comments enabled?
        comments = self.env.metadata[page_id + '.rst'].get('nocomments', False)

        # how does the user want to view comments?
        commentmode = comments and req.session.get('comments', 'inline') or ''

        # show "old URL" message? -> no caching possible
        oldurl = req.args.get('oldurl')
        if oldurl:
            yield NoCache
        else:
            # there must be different cache entries per comment mode
            yield page_id + '|' + commentmode

        # cache miss; load the page and render it
        filename = path.join(self.data_root, page_id + '.fpickle')
        f = open(filename, 'rb')
        try:
            context = pickle.load(f)
        finally:
            f.close()

        # add comments to paqe text
        if commentmode != 'none':
            self._insert_comments(req, url, context, commentmode)

        yield render_template(req, 'page.html', self.globalcontext, context,
                              {'oldurl': oldurl})
Beispiel #21
0
    def dispatch(self, req, page):
        """
        Dispatch the requests for the current user in the admin panel.
        """
        is_logged_in = req.user is not None
        if is_logged_in:
            privileges = self.userdb.privileges[req.user]
            is_master_admin = 'master' in privileges
            can_change_password = '******' not in privileges
        else:
            privileges = set()
            can_change_password = is_master_admin = False

        # login and logout
        if page == 'login':
            return self.do_login(req)
        elif not is_logged_in:
            return RedirectResponse('@admin/login/')
        elif page == 'logout':
            return self.do_logout(req)

        # account maintance
        elif page == 'change_password' and can_change_password:
            return self.do_change_password(req)
        elif page == 'manage_users' and is_master_admin:
            return self.do_manage_users(req)

        # moderate comments
        elif page.split('/')[0] == 'moderate_comments':
            return self.do_moderate_comments(req, page[18:])

        # missing page
        elif page != '':
            raise NotFound()
        return Response(render_template(req, 'admin/index.html', {
            'is_master_admin':      is_master_admin,
            'can_change_password':  can_change_password
        }))
Beispiel #22
0
    def show_comment_form(self, req, page):
        """
        Show the "new comment" form.
        """
        page_id = self.env.get_real_filename(page)[:-4]
        ajax_mode = req.args.get('mode') == 'ajax'
        target = req.args.get('target')
        page_comment_mode = not target

        form_error = preview = None
        title = req.form.get('title', '').strip()
        if 'author' in req.form:
            author = req.form['author']
        else:
            author = req.session.get('author', '')
        if 'author_mail' in req.form:
            author_mail = req.form['author_mail']
        else:
            author_mail = req.session.get('author_mail', '')
        comment_body = req.form.get('comment_body', '')
        fields = (title, author, author_mail, comment_body)

        if req.method == 'POST':
            if req.form.get('preview'):
                preview = Comment(page_id, target, title, author, author_mail,
                                  comment_body)
            # 'homepage' is a forbidden field to thwart bots
            elif req.form.get('homepage') or self.antispam.is_spam(fields):
                form_error = 'Your text contains blocked URLs or words.'
            else:
                if not all(fields):
                    form_error = 'You have to fill out all fields.'
                elif _mail_re.search(author_mail) is None:
                    form_error = 'You have to provide a valid e-mail address.'
                elif len(comment_body) < 20:
                    form_error = 'You comment is too short ' \
                                 '(must have at least 20 characters).'
                else:
                    # '|none' can stay since it doesn't include comments
                    self.cache.pop(page_id + '|inline', None)
                    self.cache.pop(page_id + '|bottom', None)
                    comment = Comment(page_id, target,
                                      title, author, author_mail,
                                      comment_body)
                    comment.save()
                    req.session['author'] = author
                    req.session['author_mail'] = author_mail
                    if ajax_mode:
                        return JSONResponse({'posted': True, 'error': False,
                                             'commentID': comment.comment_id})
                    return RedirectResponse(comment.url)

        output = render_template(req, '_commentform.html', {
            'ajax_mode':    ajax_mode,
            'preview':      preview,
            'suggest_url':  '@edit/%s/' % page,
            'comments_form': {
                'target':       target,
                'title':        title,
                'author':       author,
                'author_mail':  author_mail,
                'comment_body': comment_body,
                'error':        form_error
            }
        })

        if ajax_mode:
            return JSONResponse({
                'body':         output,
                'error':        bool(form_error),
                'posted':       False
            })
        return Response(render_template(req, 'commentform.html', {
            'form':     output
        }))
Beispiel #23
0
    def show_comment_form(self, req, page):
        """
        Show the "new comment" form.
        """
        page_id = self.env.get_real_filename(page)[:-4]
        ajax_mode = req.args.get('mode') == 'ajax'
        target = req.args.get('target')
        page_comment_mode = not target

        form_error = preview = None
        title = req.form.get('title', '').strip()
        if 'author' in req.form:
            author = req.form['author']
        else:
            author = req.session.get('author', '')
        if 'author_mail' in req.form:
            author_mail = req.form['author_mail']
        else:
            author_mail = req.session.get('author_mail', '')
        comment_body = req.form.get('comment_body', '')
        fields = (title, author, author_mail, comment_body)

        if req.method == 'POST':
            if req.form.get('preview'):
                preview = Comment(page_id, target, title, author, author_mail,
                                  comment_body)
            # 'homepage' is a forbidden field to thwart bots
            elif req.form.get('homepage') or self.antispam.is_spam(fields):
                form_error = 'Your text contains blocked URLs or words.'
            else:
                if not all(fields):
                    form_error = 'You have to fill out all fields.'
                elif _mail_re.search(author_mail) is None:
                    form_error = 'You have to provide a valid e-mail address.'
                elif len(comment_body) < 20:
                    form_error = 'You comment is too short ' \
                                 '(must have at least 20 characters).'
                else:
                    # '|none' can stay since it doesn't include comments
                    self.cache.pop(page_id + '|inline', None)
                    self.cache.pop(page_id + '|bottom', None)
                    comment = Comment(page_id, target, title, author,
                                      author_mail, comment_body)
                    comment.save()
                    req.session['author'] = author
                    req.session['author_mail'] = author_mail
                    if ajax_mode:
                        return JSONResponse({
                            'posted': True,
                            'error': False,
                            'commentID': comment.comment_id
                        })
                    return RedirectResponse(comment.url)

        output = render_template(
            req, '_commentform.html', {
                'ajax_mode': ajax_mode,
                'preview': preview,
                'suggest_url': '@edit/%s/' % page,
                'comments_form': {
                    'target': target,
                    'title': title,
                    'author': author,
                    'author_mail': author_mail,
                    'comment_body': comment_body,
                    'error': form_error
                }
            })

        if ajax_mode:
            return JSONResponse({
                'body': output,
                'error': bool(form_error),
                'posted': False
            })
        return Response(
            render_template(req, 'commentform.html', {'form': output}))
Beispiel #24
0
    def submit_changes(self, req, page):
        """
        Submit the suggested changes as a patch.
        """
        if req.method != 'POST':
            # only available via POST
            raise NotFound()
        if req.form.get('cancel'):
            # handle cancel requests directly
            return RedirectResponse(page)
        # raises NotFound if page doesn't exist
        page_id, orig_contents = self.get_page_source(page)
        author = req.form.get('name')
        email = req.form.get('email')
        summary = req.form.get('summary')
        contents = req.form.get('contents')
        fields = (author, email, summary, contents)

        form_error = None
        rendered = None

        if not all(fields):
            form_error = 'You have to fill out all fields.'
        elif not _mail_re.search(email):
            form_error = 'You have to provide a valid e-mail address.'
        elif req.form.get('homepage') or self.antispam.is_spam(fields):
            form_error = 'Your text contains blocked URLs or words.'
        else:
            if req.form.get('preview'):
                rendered = self._generate_preview(page_id, contents)

            else:
                asctime = time.asctime()
                contents = contents.splitlines()
                orig_contents = orig_contents.splitlines()
                diffname = 'suggestion on %s by %s <%s>' % (asctime, author, email)
                diff = difflib.unified_diff(orig_contents, contents, n=3,
                                            fromfile=page_id, tofile=diffname,
                                            lineterm='')
                diff_text = '\n'.join(diff)
                try:
                    mail = Email(
                        self.config['patch_mail_from'], 'Python Documentation Patches',
                        self.config['patch_mail_to'], '',
                        'Patch for %s by %s' % (page_id, author),
                        PATCH_MESSAGE % locals(),
                        self.config['patch_mail_smtp'],
                    )
                    mail.attachments.add_string('patch.diff', diff_text, 'text/x-diff')
                    mail.send()
                except:
                    import traceback
                    traceback.print_exc()
                    # XXX: how to report?
                    pass
                return Response(render_template(req, 'submitted.html',
                                                self.globalcontext, dict(
                    backlink=relative_uri('/@submit/'+page+'/', page+'/')
                )))

        return Response(render_template(req, 'edit.html', self.globalcontext, dict(
            contents=contents,
            author=author,
            email=email,
            summary=summary,
            pagename=page,
            form_error=form_error,
            rendered=rendered,
            submiturl=relative_uri('/@edit/'+page+'/', '/@submit/'+page),
        )))
Beispiel #25
0
    def submit_changes(self, req, page):
        """
        Submit the suggested changes as a patch.
        """
        if req.method != 'POST':
            # only available via POST
            raise NotFound()
        if req.form.get('cancel'):
            # handle cancel requests directly
            return RedirectResponse(page)
        # raises NotFound if page doesn't exist
        page_id, orig_contents = self.get_page_source(page)
        author = req.form.get('name')
        email = req.form.get('email')
        summary = req.form.get('summary')
        contents = req.form.get('contents')
        fields = (author, email, summary, contents)

        form_error = None
        rendered = None

        if not all(fields):
            form_error = 'You have to fill out all fields.'
        elif not _mail_re.search(email):
            form_error = 'You have to provide a valid e-mail address.'
        elif req.form.get('homepage') or self.antispam.is_spam(fields):
            form_error = 'Your text contains blocked URLs or words.'
        else:
            if req.form.get('preview'):
                rendered = self._generate_preview(page_id, contents)

            else:
                asctime = time.asctime()
                contents = contents.splitlines()
                orig_contents = orig_contents.splitlines()
                diffname = 'suggestion on %s by %s <%s>' % (asctime, author,
                                                            email)
                diff = difflib.unified_diff(orig_contents,
                                            contents,
                                            n=3,
                                            fromfile=page_id,
                                            tofile=diffname,
                                            lineterm='')
                diff_text = '\n'.join(diff)
                try:
                    mail = Email(
                        self.config['patch_mail_from'],
                        'Python Documentation Patches',
                        self.config['patch_mail_to'],
                        '',
                        'Patch for %s by %s' % (page_id, author),
                        PATCH_MESSAGE % locals(),
                        self.config['patch_mail_smtp'],
                    )
                    mail.attachments.add_string('patch.diff', diff_text,
                                                'text/x-diff')
                    mail.send()
                except:
                    import traceback
                    traceback.print_exc()
                    # XXX: how to report?
                    pass
                return Response(
                    render_template(
                        req, 'submitted.html', self.globalcontext,
                        dict(backlink=relative_uri('/@submit/' + page +
                                                   '/', page + '/'))))

        return Response(
            render_template(
                req, 'edit.html', self.globalcontext,
                dict(
                    contents=contents,
                    author=author,
                    email=email,
                    summary=summary,
                    pagename=page,
                    form_error=form_error,
                    rendered=rendered,
                    submiturl=relative_uri('/@edit/' + page + '/',
                                           '/@submit/' + page),
                )))
Beispiel #26
0
 def get_error_404(self, req):
     """
     Show a simple error 404 page.
     """
     return Response(render_template(req, 'not_found.html', self.globalcontext),
                     status=404)
Beispiel #27
0
    def do_moderate_comments(self, req, url):
        """
        Comment moderation panel.
        """
        if url == 'recent_comments':
            details_for = None
            recent_comments = Comment.get_recent(20)
        else:
            details_for = url and self.env.get_real_filename(url) or None
            recent_comments = None
        to_delete = set()
        edit_detail = None

        if 'edit' in req.args:
            try:
                edit_detail = Comment.get(int(req.args['edit']))
            except ValueError:
                pass

        if req.method == 'POST':
            for item in req.form.getlist('delete'):
                try:
                    to_delete.add(int(item))
                except ValueError:
                    pass
            if req.form.get('cancel'):
                return RedirectResponse('@admin/')
            elif req.form.get('confirmed'):
                for comment_id in to_delete:
                    try:
                        Comment.get(comment_id).delete()
                    except ValueError:
                        pass
                return RedirectResponse(req.path)
            elif req.form.get('aborted'):
                return RedirectResponse(req.path)
            elif req.form.get('edit') and not to_delete:
                if 'delete_this' in req.form:
                    try:
                        to_delete.add(req.form['delete_this'])
                    except ValueError:
                        pass
                else:
                    try:
                        edit_detail = c = Comment.get(int(req.args['edit']))
                    except ValueError:
                        pass
                    else:
                        if req.form.get('view'):
                            return RedirectResponse(c.url)
                        c.author = req.form.get('author', '')
                        c.author_mail = req.form.get('author_mail', '')
                        c.title = req.form.get('title', '')
                        c.comment_body = req.form.get('comment_body', '')
                        c.save()
                        self.app.cache.pop(edit_detail.associated_page, None)
                    return RedirectResponse(req.path)

        return Response(
            render_template(
                req,
                'admin/moderate_comments.html',
                {
                    'pages_with_comments': [
                        {
                            'page_id': page_id,
                            'title': page_id,  #XXX: get title somehow
                            'has_details': details_for == page_id,
                            'comments': comments
                        } for page_id, comments in Comment.get_overview(
                            details_for)
                    ],
                    'recent_comments':
                    recent_comments,
                    'to_delete':
                    to_delete,
                    'ask_confirmation':
                    req.method == 'POST' and to_delete,
                    'edit_detail':
                    edit_detail
                }))
Beispiel #28
0
    def do_moderate_comments(self, req, url):
        """
        Comment moderation panel.
        """
        if url == 'recent_comments':
            details_for = None
            recent_comments = Comment.get_recent(20)
        else:
            details_for = url and self.env.get_real_filename(url) or None
            recent_comments = None
        to_delete = set()
        edit_detail = None

        if 'edit' in req.args:
            try:
                edit_detail = Comment.get(int(req.args['edit']))
            except ValueError:
                pass

        if req.method == 'POST':
            for item in req.form.getlist('delete'):
                try:
                    to_delete.add(int(item))
                except ValueError:
                    pass
            if req.form.get('cancel'):
                return RedirectResponse('@admin/')
            elif req.form.get('confirmed'):
                for comment_id in to_delete:
                    try:
                        Comment.get(comment_id).delete()
                    except ValueError:
                        pass
                return RedirectResponse(req.path)
            elif req.form.get('aborted'):
                return RedirectResponse(req.path)
            elif req.form.get('edit') and not to_delete:
                if 'delete_this' in req.form:
                    try:
                        to_delete.add(req.form['delete_this'])
                    except ValueError:
                        pass
                else:
                    try:
                        edit_detail = c = Comment.get(int(req.args['edit']))
                    except ValueError:
                        pass
                    else:
                        if req.form.get('view'):
                            return RedirectResponse(c.url)
                        c.author = req.form.get('author', '')
                        c.author_mail = req.form.get('author_mail', '')
                        c.title = req.form.get('title', '')
                        c.comment_body = req.form.get('comment_body', '')
                        c.save()
                        self.app.cache.pop(edit_detail.associated_page, None)
                    return RedirectResponse(req.path)

        return Response(render_template(req, 'admin/moderate_comments.html', {
            'pages_with_comments': [{
                'page_id':      page_id,
                'title':        page_id,        #XXX: get title somehow
                'has_details':  details_for == page_id,
                'comments':     comments
            } for page_id, comments in Comment.get_overview(details_for)],
            'recent_comments':  recent_comments,
            'to_delete':        to_delete,
            'ask_confirmation': req.method == 'POST' and to_delete,
            'edit_detail':      edit_detail
        }))
Beispiel #29
0
    def do_manage_users(self, req):
        """
        Manage other user accounts. Requires master privileges.
        """
        add_user_mode = False
        user_privileges = {}
        users = sorted((user, []) for user in self.userdb.users)
        to_delete = set()
        generated_user = generated_password = None
        user_exists = False

        if req.method == 'POST':
            for item in req.form.getlist('delete'):
                try:
                    to_delete.add(item)
                except ValueError:
                    pass
            for name, item in req.form.iteritems():
                if name.startswith('privileges-'):
                    user_privileges[name[11:]] = [x.strip() for x
                                                  in item.split(',')]
            if req.form.get('cancel'):
                return RedirectResponse('@admin/')
            elif req.form.get('add_user'):
                username = req.form.get('username')
                if username:
                    if username in self.userdb.users:
                        user_exists = username
                    else:
                        generated_password = self.userdb.add_user(username)
                        self.userdb.save()
                        generated_user = username
                else:
                    add_user_mode = True
            elif req.form.get('aborted'):
                return RedirectResponse('@admin/manage_users/')

        users = {}
        for user in self.userdb.users:
            if user not in user_privileges:
                users[user] = sorted(self.userdb.privileges[user])
            else:
                users[user] = user_privileges[user]

        new_users = users.copy()
        for user in to_delete:
            new_users.pop(user, None)

        self_destruction = req.user not in new_users or \
                           'master' not in new_users[req.user]

        if req.method == 'POST' and (not to_delete or
           (to_delete and req.form.get('confirmed'))) and \
           req.form.get('update'):
            old_users = self.userdb.users.copy()
            for user in old_users:
                if user not in new_users:
                    del self.userdb.users[user]
                else:
                    self.userdb.privileges[user].clear()
                    self.userdb.privileges[user].update(new_users[user])
            self.userdb.save()
            return RedirectResponse('@admin/manage_users/')

        return Response(render_template(req, 'admin/manage_users.html', {
            'users':                users,
            'add_user_mode':        add_user_mode,
            'to_delete':            to_delete,
            'ask_confirmation':     req.method == 'POST' and to_delete \
                                    and not self_destruction,
            'generated_user':       generated_user,
            'generated_password':   generated_password,
            'self_destruction':     self_destruction,
            'user_exists':          user_exists
        }))
Beispiel #30
0
    def do_manage_users(self, req):
        """
        Manage other user accounts. Requires master privileges.
        """
        add_user_mode = False
        user_privileges = {}
        users = sorted((user, []) for user in self.userdb.users)
        to_delete = set()
        generated_user = generated_password = None
        user_exists = False

        if req.method == 'POST':
            for item in req.form.getlist('delete'):
                try:
                    to_delete.add(item)
                except ValueError:
                    pass
            for name, item in req.form.iteritems():
                if name.startswith('privileges-'):
                    user_privileges[name[11:]] = [
                        x.strip() for x in item.split(',')
                    ]
            if req.form.get('cancel'):
                return RedirectResponse('@admin/')
            elif req.form.get('add_user'):
                username = req.form.get('username')
                if username:
                    if username in self.userdb.users:
                        user_exists = username
                    else:
                        generated_password = self.userdb.add_user(username)
                        self.userdb.save()
                        generated_user = username
                else:
                    add_user_mode = True
            elif req.form.get('aborted'):
                return RedirectResponse('@admin/manage_users/')

        users = {}
        for user in self.userdb.users:
            if user not in user_privileges:
                users[user] = sorted(self.userdb.privileges[user])
            else:
                users[user] = user_privileges[user]

        new_users = users.copy()
        for user in to_delete:
            new_users.pop(user, None)

        self_destruction = req.user not in new_users or \
                           'master' not in new_users[req.user]

        if req.method == 'POST' and (not to_delete or
           (to_delete and req.form.get('confirmed'))) and \
           req.form.get('update'):
            old_users = self.userdb.users.copy()
            for user in old_users:
                if user not in new_users:
                    del self.userdb.users[user]
                else:
                    self.userdb.privileges[user].clear()
                    self.userdb.privileges[user].update(new_users[user])
            self.userdb.save()
            return RedirectResponse('@admin/manage_users/')

        return Response(render_template(req, 'admin/manage_users.html', {
            'users':                users,
            'add_user_mode':        add_user_mode,
            'to_delete':            to_delete,
            'ask_confirmation':     req.method == 'POST' and to_delete \
                                    and not self_destruction,
            'generated_user':       generated_user,
            'generated_password':   generated_password,
            'self_destruction':     self_destruction,
            'user_exists':          user_exists
        }))