Beispiel #1
0
    def GET_wiki_create(self, may_create, page, view=False):
        api = c.extension == 'json'

        if c.error and c.error['reason'] == 'PAGE_EXISTS':
            return self.redirect(join_urls(c.wiki_base_url, page))
        elif not may_create or api:
            if may_create and c.error:
                self.handle_error(403, **c.error)
            else:
                self.handle_error(404, 'PAGE_NOT_FOUND', may_create=may_create)
        elif c.error:
            error = ''
            if c.error['reason'] == 'PAGE_NAME_LENGTH':
                error = _(
                    "this wiki cannot handle page names of that magnitude!  please select a page name shorter than %d characters"
                ) % c.error['max_length']
            elif c.error['reason'] == 'PAGE_CREATED_ELSEWHERE':
                error = _(
                    "this page is a special page, please go into the subreddit settings and save the field once to create this special page"
                )
            elif c.error['reason'] == 'PAGE_NAME_MAX_SEPARATORS':
                error = _(
                    'a max of %d separators "/" are allowed in a wiki page name.'
                ) % c.error['MAX_SEPARATORS']
            return BoringPage(_("Wiki error"), infotext=error).render()
        elif view:
            return WikiNotFound().render()
        elif may_create:
            WikiPage.create(c.site, page)
            url = join_urls(c.wiki_base_url, '/edit/', page)
            return self.redirect(url)
Beispiel #2
0
 def GET_wiki_create(self, may_create, page, view=False):
     api = c.extension == 'json'
     
     if c.error and c.error['reason'] == 'PAGE_EXISTS':
         return self.redirect(join_urls(c.wiki_base_url, page))
     elif not may_create or api:
         if may_create and c.error:
             self.handle_error(403, **c.error)
         else:
             self.handle_error(404, 'PAGE_NOT_FOUND', may_create=may_create)
     elif c.error:
         error = ''
         if c.error['reason'] == 'PAGE_NAME_LENGTH':
             error = _("this wiki cannot handle page names of that magnitude!  please select a page name shorter than %d characters") % c.error['max_length']
         elif c.error['reason'] == 'PAGE_CREATED_ELSEWHERE':
             error = _("this page is a special page, please go into the subreddit settings and save the field once to create this special page")
         elif c.error['reason'] == 'PAGE_NAME_MAX_SEPARATORS':
             error = _('a max of %d separators "/" are allowed in a wiki page name.') % c.error['MAX_SEPARATORS']
         return BoringPage(_("Wiki error"), infotext=error).render()
     elif view:
         return WikiNotFound().render()
     elif may_create:
         WikiPage.create(c.site, page)
         url = join_urls(c.wiki_base_url, '/edit/', page)
         return self.redirect(url)
Beispiel #3
0
    def may_not_create(self, page):
        if not page:
            # Should not happen, but just in case
            self.set_error('EMPTY_PAGE_NAME', 403)
            return

        page = normalize_page(page)

        if WikiPage.is_automatically_created(page):
            return {'reason': 'PAGE_CREATED_ELSEWHERE'}
        elif WikiPage.is_special(page):
            if not (c.user_is_admin
                    or c.site.is_moderator_with_perms(c.user, 'config')):
                self.set_error('RESTRICTED_PAGE', code=403)
                return
        elif (not c.user_is_admin) and WikiPage.is_restricted(page):
            self.set_error('RESTRICTED_PAGE', code=403)
            return
        elif page.count('/') > MAX_SEPARATORS:
            return {
                'reason': 'PAGE_NAME_MAX_SEPARATORS',
                'max_separators': MAX_SEPARATORS
            }
        elif len(page) > MAX_PAGE_NAME_LENGTH:
            return {
                'reason': 'PAGE_NAME_LENGTH',
                'max_length': MAX_PAGE_NAME_LENGTH
            }
def post_if_goal_reached(date):
    # bail out if this day's already been submitted
    for link in get_recent_name_submissions():
        if link.revenue_date == date:
            return

    revenue = gold_revenue_multi([date]).get(date, 0)
    goal = gold_goal_on(date)
    percent = revenue / float(goal)
    bucket = int(percent)
    if bucket == 0:
        return

    buyer_count = len(gold_buyers_on(date))
    template_wp = WikiPage.get(SERVERNAME_SR, "templates/selftext")
    template = random.choice(template_wp._get("content").split("\r\n---\r\n"))
    boilerplate = WikiPage.get(SERVERNAME_SR, "templates/boilerplate")._get("content")
    selftext_template = template + "\n\n---\n\n" + boilerplate

    link = Link._submit(
        is_self=True,
        title=date.strftime("%a %Y-%m-%d"),
        content=selftext_template % {
            "percent": int(percent * 100),
            "buyers": buyer_count,
        },
        author=SYSTEM_ACCOUNT,
        sr=SERVERNAME_SR,
        ip="127.0.0.1",
        spam=False,
    )

    link.flair_text = "Name pending..."
    link.flair_css_class = "goal-bucket-%d-active" % bucket
    link.revenue_date = date
    link.revenue_bucket = bucket
    link.server_names = []
    link._commit()

    UPVOTE = True
    queries.queue_vote(SYSTEM_ACCOUNT, link, UPVOTE, "127.0.0.1")
    queries.new_link(link)
    link.update_search_index()

    template = WikiPage.get(SERVERNAME_SR, "templates/notification-message")._get("content")
    subject_template, sep, body_template = template.partition("\r\n")
    for id in gold_buyers_on(date):
        recipient = Account._byID(id, data=True)
        send_system_message(
            recipient,
            subject_template,
            body_template % {
                "percent": int(percent * 100),
                "buyers": buyer_count,
                "user": recipient.name,
                "link": link.url,
            },
        )
Beispiel #5
0
def post_if_goal_reached(date):
    # bail out if this day's already been submitted
    for link in get_recent_name_submissions():
        if link.revenue_date == date:
            return

    revenue = gold_revenue_multi([date]).get(date, 0)
    goal = gold_goal_on(date)
    percent = revenue / float(goal)
    bucket = int(percent)
    if bucket == 0:
        return

    buyer_count = len(gold_buyers_on(date))
    template_wp = WikiPage.get(SERVERNAME_SR, "templates/selftext")
    template = random.choice(template_wp._get("content").split("\r\n---\r\n"))
    boilerplate = WikiPage.get(SERVERNAME_SR,
                               "templates/boilerplate")._get("content")
    selftext_template = template + "\n\n---\n\n" + boilerplate

    link = Link._submit(
        is_self=True,
        title=date.strftime("%a %Y-%m-%d"),
        content=selftext_template % {
            "percent": int(percent * 100),
            "buyers": buyer_count,
        },
        author=SYSTEM_ACCOUNT,
        sr=SERVERNAME_SR,
        ip="127.0.0.1",
        spam=False,
    )

    link.flair_text = "Name pending..."
    link.flair_css_class = "goal-bucket-%d-active" % bucket
    link.revenue_date = date
    link.revenue_bucket = bucket
    link.server_names = []
    link._commit()

    queries.new_link(link)
    link.update_search_index()

    template = WikiPage.get(SERVERNAME_SR,
                            "templates/notification-message")._get("content")
    subject_template, sep, body_template = template.partition("\r\n")
    for id in gold_buyers_on(date):
        recipient = Account._byID(id, data=True)
        send_system_message(
            recipient,
            subject_template,
            body_template % {
                "percent": int(percent * 100),
                "buyers": buyer_count,
                "user": recipient.name,
                "link": link.url,
            },
        )
Beispiel #6
0
 def may_not_create(self, page):
     if c.is_wiki_mod and WikiPage.is_special(page):
         return {'reason': 'PAGE_CREATED_ELSEWHERE'}
     elif (not c.user_is_admin) and WikiPage.is_restricted(page):
         self.set_error('RESTRICTED_PAGE', code=403)
         return
     elif page.count('/') > MAX_SEPARATORS:
         return {'reason': 'PAGE_NAME_MAX_SEPARATORS', 'max_separators': MAX_SEPARATORS}
     elif len(page) > MAX_PAGE_NAME_LENGTH:
         return {'reason': 'PAGE_NAME_LENGTH', 'max_length': MAX_PAGE_NAME_LENGTH}
Beispiel #7
0
    def change_css(self,
                   content,
                   parsed,
                   prev=None,
                   reason=None,
                   author=None,
                   force=False):
        from r2.models import ModAction
        author = author if author else c.user.name
        if content is None:
            content = ''
        try:
            wiki = WikiPage.get(self, 'config/stylesheet')
        except tdb_cassandra.NotFound:
            wiki = WikiPage.create(self, 'config/stylesheet')
        wr = wiki.revise(content,
                         previous=prev,
                         author=author,
                         reason=reason,
                         force=force)

        minified = cssmin(parsed)
        if minified:
            if g.static_stylesheet_bucket:
                digest = hashlib.sha1(minified).digest()
                self.stylesheet_hash = (
                    base64.urlsafe_b64encode(digest).rstrip("="))

                s3cp.send_file(
                    g.static_stylesheet_bucket,
                    self.static_stylesheet_name,
                    minified,
                    content_type="text/css",
                    never_expire=True,
                    replace=False,
                )

                self.stylesheet_contents = ""
                self.stylesheet_modified = None
            else:
                self.stylesheet_hash = hashlib.md5(minified).hexdigest()
                self.stylesheet_contents = minified
                self.stylesheet_modified = datetime.datetime.now(g.tz)
        else:
            self.stylesheet_contents = ""
            self.stylesheet_hash = ""
            self.stylesheet_modified = datetime.datetime.now(g.tz)
        self.stylesheet_contents_user = ""  # reads from wiki; ensure pg clean
        self._commit()

        ModAction.create(self,
                         c.user,
                         action='wikirevise',
                         details='Updated subreddit stylesheet')
        return wr
Beispiel #8
0
def activate_names(link, names):
    for comment, name in names:
        # find a slot to assign a name to. we'll prefer nodes that are
        # currently empty, and failing that find the least-recently-modified
        # node.
        ROOT = "/gold/server-names"
        slot_names = g.zookeeper.get_children(ROOT)
        slots = [(slot_name, g.zookeeper.get(os.path.join(ROOT, slot_name)))
                 for slot_name in slot_names]
        slots.sort(key=lambda (path, (data, stat)): (bool(data), stat.mtime))
        slot_path = os.path.join(ROOT, slots[0][0])

        comment_data = {
            'name': str(name),
            'permalink': comment.make_permalink_slow()
        }
        g.zookeeper.set(slot_path, json.dumps(comment_data))

        lock = g.zookeeper.Lock(slot_path)
        lock_contenders = lock.contenders()
        old_name = lock_contenders[0] if lock_contenders else ""
        old_name = old_name or "one of our servers"

        # reply to the user
        wp = WikiPage.get(SERVERNAME_SR, "templates/success-reply")
        template = random.choice(wp._get("content").split("\r\n---\r\n"))
        comment, inbox_rel = Comment._new(
            author=SYSTEM_ACCOUNT,
            link=link,
            parent=comment,
            body=template % {
                "old-name": old_name,
                "new-name": name,
            },
            ip="127.0.0.1",
        )
        queries.new_comment(comment, inbox_rel)

        # update the link's text
        wp = WikiPage.get(SERVERNAME_SR, "templates/goldisms")
        goldism = random.choice(wp._get("content").split("\r\n---\r\n"))
        wp = WikiPage.get(SERVERNAME_SR, "templates/selftext-success")
        template = wp._get("content")
        link.selftext = template % {
            "old-name": old_name,
            "new-name": name,
            "goldism": goldism,
        }
        link._commit()
def activate_names(link, names):
    for comment, name in names:
        # find a slot to assign a name to. we'll prefer nodes that are
        # currently empty, and failing that find the least-recently-modified
        # node.
        ROOT = "/gold/server-names"
        slot_names = g.zookeeper.get_children(ROOT)
        slots = [(slot_name, g.zookeeper.get(os.path.join(ROOT, slot_name)))
                 for slot_name in slot_names]
        slots.sort(key=lambda (path, (data, stat)): (bool(data), stat.mtime))
        slot_path = os.path.join(ROOT, slots[0][0])

        comment_data = {'name': str(name),
                        'permalink': comment.make_permalink_slow()}
        g.zookeeper.set(slot_path, json.dumps(comment_data))

        lock = g.zookeeper.Lock(slot_path)
        lock_contenders = lock.contenders()
        old_name = lock_contenders[0] if lock_contenders else ""
        old_name = old_name or "one of our servers"

        # reply to the user
        wp = WikiPage.get(SERVERNAME_SR, "templates/success-reply")
        template = random.choice(wp._get("content").split("\r\n---\r\n"))
        comment, inbox_rel = Comment._new(
            author=SYSTEM_ACCOUNT,
            link=link,
            parent=comment,
            body=template % {
                "old-name": old_name,
                "new-name": name,
            },
            ip="127.0.0.1",
        )
        queries.queue_vote(SYSTEM_ACCOUNT, comment, dir=True, ip="127.0.0.1")
        queries.new_comment(comment, inbox_rel)

        # update the link's text
        wp = WikiPage.get(SERVERNAME_SR, "templates/goldisms")
        goldism = random.choice(wp._get("content").split("\r\n---\r\n"))
        wp = WikiPage.get(SERVERNAME_SR, "templates/selftext-success")
        template = wp._get("content")
        link.selftext = template % {
            "old-name": old_name,
            "new-name": name,
            "goldism": goldism,
        }
        link._commit()
Beispiel #10
0
    def GET_wiki_listing(self):
        def check_hidden(page):
            g.log.debug("Got here %s" % str(this_may_view(page)))
            return this_may_view(page)

        pages = WikiPage.get_listing(c.site, filter_check=check_hidden)
        return WikiListing(pages).render()
Beispiel #11
0
def may_view(sr, user, page):
    # User being None means not logged in
    mod = sr.is_moderator_with_perms(user, 'wiki') if user else False
    
    if mod:
        # Mods may always view
        return True
    
    if page.special:
        level = WikiPage.get_special_view_permlevel(page.name)
    else:
        level = page.permlevel
    
    if level < 2:
        # Everyone may view in levels below 2
        return True
    
    if level == 2:
        # Only mods may view in level 2
        return mod
    
    # In any other obscure level,
    # (This should not happen but just in case)
    # nobody may view.
    return False
Beispiel #12
0
 def run(self, page):
     original_page = page
     if not page:
         # If no page is specified, give the index page
         page = "index"
     
     try:
         page = str(page)
     except UnicodeEncodeError:
         return self.set_error('INVALID_PAGE_NAME', code=400)
     
     if ' ' in page:
         page = page.replace(' ', '_')
     
     if not page_match_regex.match(page):
         return self.set_error('INVALID_PAGE_NAME', code=400)
     
     page = normalize_page(page)
     
     if WikiPage.is_impossible(page):
         return self.set_error('INVALID_PAGE_NAME', code=400)
     
     if self.error_on_name_normalized and page != original_page:
         self.set_error('PAGE_NAME_NORMALIZED')
     
     return page
Beispiel #13
0
 def change_css(self, content, parsed, prev=None, reason=None, author=None, force=False):
     from r2.models import ModAction
     author = author if author else c.user.name
     if content is None:
         content = ''
     try:
         wiki = WikiPage.get(self, 'config/stylesheet')
     except tdb_cassandra.NotFound:
         wiki = WikiPage.create(self, 'config/stylesheet')
     wr = wiki.revise(content, previous=prev, author=author, reason=reason, force=force)
     self.stylesheet_contents = parsed
     self.stylesheet_hash = md5(parsed).hexdigest()
     set_last_modified(self, 'stylesheet_contents')
     c.site._commit()
     ModAction.create(self, c.user, action='wikirevise', details='Updated subreddit stylesheet')
     return wr
Beispiel #14
0
 def run(self, page):
     wp = VWikiPage.run(self, page)
     if c.errors:
         return
     if wp:
         c.error = {"reason": "PAGE_EXISTS"}
     elif c.is_wiki_mod and WikiPage.is_special(page):
         c.error = {"reason": "PAGE_CREATED_ELSEWHERE"}
     elif WikiPage.is_restricted(page):
         self.set_error("RESTRICTED_PAGE", code=403)
         return
     elif page.count("/") > MAX_SEPARATORS:
         c.error = {"reason": "PAGE_NAME_MAX_SEPARATORS", "MAX_SEPARATORS": MAX_SEPARATORS}
     elif len(page) > MAX_PAGE_NAME_LENGTH:
         c.error = {"reason": "PAGE_NAME_LENGTH", "max_length": MAX_PAGE_NAME_LENGTH}
     return this_may_revise()
Beispiel #15
0
 def change_css(self, content, parsed, prev=None, reason=None, author=None, force=False):
     from r2.models import ModAction
     author = author if author else c.user.name
     if content is None:
         content = ''
     try:
         wiki = WikiPage.get(self, 'config/stylesheet')
     except tdb_cassandra.NotFound:
         wiki = WikiPage.create(self, 'config/stylesheet')
     wr = wiki.revise(content, previous=prev, author=author, reason=reason, force=force)
     self.stylesheet_contents = parsed
     self.stylesheet_hash = md5(parsed).hexdigest()
     set_last_modified(self, 'stylesheet_contents')
     c.site._commit()
     ModAction.create(self, c.user, action='wikirevise', details='Updated subreddit stylesheet')
     return wr
Beispiel #16
0
    def POST_wiki_edit(self, pageandprevious, content, page_name, reason):
        """Edit a wiki `page`"""
        page, previous = pageandprevious

        if not page:
            error = c.errors.get(("WIKI_CREATE_ERROR", "page"))
            if error:
                self.handle_error(403, **(error.msg_params or {}))
            if not c.user._spam:
                page = WikiPage.create(c.site, page_name)
        if c.user._spam:
            error = _("You are doing that too much, please try again later.")
            self.handle_error(415, "SPECIAL_ERRORS", special_errors=[error])

        renderer = RENDERERS_BY_PAGE.get(page.name, "wiki")
        if renderer in ("wiki", "reddit"):
            content = VMarkdown(("content"), renderer=renderer).run(content)

        # Use the raw POST value as we need to tell the difference between
        # None/Undefined and an empty string.  The validators use a default
        # value with both of those cases and would need to be changed.
        # In order to avoid breaking functionality, this was done instead.
        previous = previous._id if previous else request.POST.get("previous")
        try:
            # special validation methods
            if page.name == "config/stylesheet":
                css_errors, parsed = c.site.parse_css(content, verify=False)
                if g.css_killswitch:
                    self.handle_error(403, "STYLESHEET_EDIT_DENIED")
                if css_errors:
                    error_items = [CssError(x).message for x in css_errors]
                    self.handle_error(415, "SPECIAL_ERRORS", special_errors=error_items)
            elif page.name == "config/automoderator":
                try:
                    rules = Ruleset(content)
                except ValueError as e:
                    error_items = [e.message]
                    self.handle_error(415, "SPECIAL_ERRORS", special_errors=error_items)

            # special saving methods
            if page.name == "config/stylesheet":
                c.site.change_css(content, parsed, previous, reason=reason)
            else:
                try:
                    page.revise(content, previous, c.user._id36, reason=reason)
                except ContentLengthError as e:
                    self.handle_error(403, "CONTENT_LENGTH_ERROR", max_length=e.max_length)

                # continue storing the special pages as data attributes on the subreddit
                # object. TODO: change this to minimize subreddit get sizes.
                if page.special and page.name in ATTRIBUTE_BY_PAGE:
                    setattr(c.site, ATTRIBUTE_BY_PAGE[page.name], content)
                    c.site._commit()

                if page.special or c.is_wiki_mod:
                    description = modactions.get(page.name, "Page %s edited" % page.name)
                    ModAction.create(c.site, c.user, "wikirevise", details=description)
        except ConflictException as e:
            self.handle_error(409, "EDIT_CONFLICT", newcontent=e.new, newrevision=page.revision, diffcontent=e.htmldiff)
        return json.dumps({})
Beispiel #17
0
    def GET_policy_page(self, page, requested_rev):
        if c.render_style == 'compact':
            self.redirect('/wiki/' + page)
        if page == 'privacypolicy':
            wiki_name = g.wiki_page_privacy_policy
            pagename = _('privacy policy')
        elif page == 'useragreement':
            wiki_name = g.wiki_page_user_agreement
            pagename = _('user agreement')
        elif page == 'contentpolicy':
            wiki_name = g.wiki_page_content_policy
            pagename = _('content policy')
        else:
            abort(404)

        wp = WikiPage.get(Frontpage, wiki_name)

        revs = list(wp.get_revisions())

        # collapse minor edits into revisions with reasons
        rev_info = []
        last_edit = None
        for rev in revs:
            if rev.is_hidden:
                continue

            if not last_edit:
                last_edit = rev

            if rev._get('reason'):
                rev_info.append({
                    'id': str(last_edit._id),
                    'title': rev._get('reason'),
                })
                last_edit = None

        if requested_rev:
            try:
                display_rev = WikiRevision.get(requested_rev, wp._id)
            except (tdb_cassandra.NotFound, WikiBadRevision):
                abort(404)
        else:
            display_rev = revs[0]

        doc_html = wikimarkdown(display_rev.content, include_toc=False)
        soup = BeautifulSoup(doc_html.decode('utf-8'))
        toc = generate_table_of_contents(soup, prefix='section')
        self._number_sections(soup)
        self._linkify_headings(soup)

        content = PolicyView(
            body_html=unsafe(soup),
            toc_html=unsafe(toc),
            revs=rev_info,
            display_rev=str(display_rev._id),
        )
        return PolicyPage(
            pagename=pagename,
            content=content,
        ).render()
Beispiel #18
0
def may_view(sr, user, page):
    # User being None means not logged in
    mod = sr.is_moderator_with_perms(user, 'wiki') if user else False

    if mod:
        # Mods may always view
        return True

    if page.special:
        level = WikiPage.get_special_view_permlevel(page.name)
    else:
        level = page.permlevel

    if level < 2:
        # Everyone may view in levels below 2
        return True

    if level == 2:
        # Only mods may view in level 2
        return mod

    # In any other obscure level,
    # (This should not happen but just in case)
    # nobody may view.
    return False
Beispiel #19
0
    def GET_wiki_listing(self):
        """Retrieve a list of wiki pages in this subreddit"""
        def check_hidden(page):
            return page.listed and this_may_view(page)

        pages, linear_pages = WikiPage.get_listing(c.site,
                                                   filter_check=check_hidden)
        return WikiListing(pages, linear_pages).render()
Beispiel #20
0
    def may_not_create(self, page):
        if not page:
            # Should not happen, but just in case
            self.set_error("EMPTY_PAGE_NAME", 403)
            return

        page = normalize_page(page)

        if c.is_wiki_mod and WikiPage.is_special(page):
            return {"reason": "PAGE_CREATED_ELSEWHERE"}
        elif (not c.user_is_admin) and WikiPage.is_restricted(page):
            self.set_error("RESTRICTED_PAGE", code=403)
            return
        elif page.count("/") > MAX_SEPARATORS:
            return {"reason": "PAGE_NAME_MAX_SEPARATORS", "max_separators": MAX_SEPARATORS}
        elif len(page) > MAX_PAGE_NAME_LENGTH:
            return {"reason": "PAGE_NAME_LENGTH", "max_length": MAX_PAGE_NAME_LENGTH}
Beispiel #21
0
    def GET_wiki_listing(self):
        """Retrieve a list of wiki pages in this subreddit"""

        def check_hidden(page):
            return page.listed and this_may_view(page)

        pages, linear_pages = WikiPage.get_listing(c.site, filter_check=check_hidden)
        return WikiListing(pages, linear_pages).render()
Beispiel #22
0
    def change_css(self, content, parsed, prev=None, reason=None, author=None, force=False):
        from r2.models import ModAction

        author = author if author else c.user.name
        if content is None:
            content = ""
        try:
            wiki = WikiPage.get(self, "config/stylesheet")
        except tdb_cassandra.NotFound:
            wiki = WikiPage.create(self, "config/stylesheet")
        wr = wiki.revise(content, previous=prev, author=author, reason=reason, force=force)

        minified = cssmin(parsed)
        if minified:
            if g.static_stylesheet_bucket:
                digest = hashlib.sha1(minified).digest()
                self.stylesheet_hash = base64.urlsafe_b64encode(digest).rstrip("=")

                s3cp.send_file(
                    g.static_stylesheet_bucket,
                    self.static_stylesheet_name,
                    minified,
                    content_type="text/css",
                    never_expire=True,
                    replace=False,
                )

                self.stylesheet_contents = ""
                self.stylesheet_modified = None
            else:
                self.stylesheet_hash = hashlib.md5(minified).hexdigest()
                self.stylesheet_contents = minified
                self.stylesheet_modified = datetime.datetime.now(g.tz)
        else:
            self.stylesheet_contents = ""
            self.stylesheet_hash = ""
            self.stylesheet_modified = datetime.datetime.now(g.tz)
        self.stylesheet_contents_user = ""  # reads from wiki; ensure pg clean
        self._commit()

        ModAction.create(self, c.user, action="wikirevise", details="Updated subreddit stylesheet")
        return wr
Beispiel #23
0
def wiki_template(template_slug, sr=None):
    """Pull content from a subreddit's wiki page for internal use."""
    if not sr:
        sr = Subreddit._by_name(g.default_sr)

    try:
        wiki = WikiPage.get(sr, "templates/%s" % template_slug)
    except tdb_cassandra.NotFound:
        return None

    return wiki._get("content")
Beispiel #24
0
def wiki_template(template_slug, sr=None):
    """Pull content from a subreddit's wiki page for internal use."""
    if not sr:
        sr = Subreddit._by_name(g.default_sr)

    try:
        wiki = WikiPage.get(sr, "templates/%s" % template_slug)
    except tdb_cassandra.NotFound:
        return None

    return wiki._get("content")
Beispiel #25
0
 def may_not_create(self, page):
     if not page:
         # Should not happen, but just in case
         self.set_error('EMPTY_PAGE_NAME', 403)
         return
     
     page = normalize_page(page)
     
     if WikiPage.is_automatically_created(page):
         return {'reason': 'PAGE_CREATED_ELSEWHERE'}
     elif WikiPage.is_special(page):
         if not (c.user_is_admin or
                 c.site.is_moderator_with_perms(c.user, 'config')):
             self.set_error('RESTRICTED_PAGE', code=403)
             return
     elif (not c.user_is_admin) and WikiPage.is_restricted(page):
         self.set_error('RESTRICTED_PAGE', code=403)
         return
     elif page.count('/') > MAX_SEPARATORS:
         return {'reason': 'PAGE_NAME_MAX_SEPARATORS', 'max_separators': MAX_SEPARATORS}
     elif len(page) > MAX_PAGE_NAME_LENGTH:
         return {'reason': 'PAGE_NAME_LENGTH', 'max_length': MAX_PAGE_NAME_LENGTH}
Beispiel #26
0
 def run(self, page):
     wp = VWikiPage.run(self, page)
     if c.errors:
         return
     if wp:
         c.error = {'reason': 'PAGE_EXISTS'}
     elif c.is_wiki_mod and WikiPage.is_special(page):
         c.error = {'reason': 'PAGE_CREATED_ELSEWHERE'}
     elif WikiPage.is_restricted(page):
         self.set_error('RESTRICTED_PAGE', code=403)
         return
     elif page.count('/') > MAX_SEPARATORS:
         c.error = {
             'reason': 'PAGE_NAME_MAX_SEPARATORS',
             'MAX_SEPARATORS': MAX_SEPARATORS
         }
     elif len(page) > MAX_PAGE_NAME_LENGTH:
         c.error = {
             'reason': 'PAGE_NAME_LENGTH',
             'max_length': MAX_PAGE_NAME_LENGTH
         }
     return this_may_revise()
Beispiel #27
0
    def POST_wiki_edit(self, pageandprevious, content, page_name, reason):
        """Edit a wiki `page`"""
        page, previous = pageandprevious

        if not page:
            error = c.errors.get(('WIKI_CREATE_ERROR', 'page'))
            if error:
                self.handle_error(403, **(error.msg_params or {}))
            if not c.user._spam:
                page = WikiPage.create(c.site, page_name)
        if c.user._spam:
            error = _("You are doing that too much, please try again later.")
            self.handle_error(415, 'SPECIAL_ERRORS', special_errors=[error])

        renderer = RENDERERS_BY_PAGE.get(page.name, 'wiki')
        if renderer in ('wiki', 'reddit'):
            content = VMarkdown(('content'), renderer=renderer).run(content)

        # Use the raw POST value as we need to tell the difference between
        # None/Undefined and an empty string.  The validators use a default
        # value with both of those cases and would need to be changed.
        # In order to avoid breaking functionality, this was done instead.
        previous = previous._id if previous else request.POST.get('previous')
        try:
            if page.name == 'config/stylesheet':
                report, parsed = c.site.parse_css(content, verify=False)
                if report is None:  # g.css_killswitch
                    self.handle_error(403, 'STYLESHEET_EDIT_DENIED')
                if report.errors:
                    error_items = [x.message for x in sorted(report.errors)]
                    self.handle_error(415, 'SPECIAL_ERRORS', special_errors=error_items)
                c.site.change_css(content, parsed, previous, reason=reason)
            else:
                try:
                    page.revise(content, previous, c.user._id36, reason=reason)
                except ContentLengthError as e:
                    self.handle_error(403, 'CONTENT_LENGTH_ERROR', max_length=e.max_length)

                # continue storing the special pages as data attributes on the subreddit
                # object. TODO: change this to minimize subreddit get sizes.
                if page.special:
                    setattr(c.site, ATTRIBUTE_BY_PAGE[page.name], content)
                    setattr(c.site, "prev_" + ATTRIBUTE_BY_PAGE[page.name] + "_id", page.revision)
                    c.site._commit()

                if page.special or c.is_wiki_mod:
                    description = modactions.get(page.name, 'Page %s edited' % page.name)
                    ModAction.create(c.site, c.user, 'wikirevise', details=description)
        except ConflictException as e:
            self.handle_error(409, 'EDIT_CONFLICT', newcontent=e.new, newrevision=page.revision, diffcontent=e.htmldiff)
        return json.dumps({})
Beispiel #28
0
    def POST_wiki_edit(self, pageandprevious, content, page_name, reason):
        page, previous = pageandprevious

        if not page:
            error = c.errors.get(('WIKI_CREATE_ERROR', 'page'))
            if error:
                self.handle_error(403, **(error.msg_params or {}))
            if not c.user._spam:
                page = WikiPage.create(c.site, page_name)
        if c.user._spam:
            error = _("You are doing that too much, please try again later.")
            self.handle_error(415, 'SPECIAL_ERRORS', special_errors=[error])

        renderer = RENDERERS_BY_PAGE.get(page.name, 'wiki')
        if renderer in ('wiki', 'reddit'):
            content = VMarkdown(('content'), renderer=renderer).run(content)

        # Use the raw POST value as we need to tell the difference between
        # None/Undefined and an empty string.  The validators use a default
        # value with both of those cases and would need to be changed.
        # In order to avoid breaking functionality, this was done instead.
        previous = previous._id if previous else request.post.get('previous')
        try:
            if page.name == 'config/stylesheet':
                report, parsed = c.site.parse_css(content, verify=False)
                if report is None:  # g.css_killswitch
                    self.handle_error(403, 'STYLESHEET_EDIT_DENIED')
                if report.errors:
                    error_items = [x.message for x in sorted(report.errors)]
                    self.handle_error(415, 'SPECIAL_ERRORS', special_errors=error_items)
                c.site.change_css(content, parsed, previous, reason=reason)
            else:
                try:
                    page.revise(content, previous, c.user._id36, reason=reason)
                except ContentLengthError as e:
                    self.handle_error(403, 'CONTENT_LENGTH_ERROR', max_length=e.max_length)

                # continue storing the special pages as data attributes on the subreddit
                # object. TODO: change this to minimize subreddit get sizes.
                if page.special:
                    setattr(c.site, ATTRIBUTE_BY_PAGE[page.name], content)
                    setattr(c.site, "prev_" + ATTRIBUTE_BY_PAGE[page.name] + "_id", str(page.revision))
                    c.site._commit()

                if page.special or c.is_wiki_mod:
                    description = modactions.get(page.name, 'Page %s edited' % page.name)
                    ModAction.create(c.site, c.user, 'wikirevise', details=description)
        except ConflictException as e:
            self.handle_error(409, 'EDIT_CONFLICT', newcontent=e.new, newrevision=page.revision, diffcontent=e.htmldiff)
        return json.dumps({})
Beispiel #29
0
 def validpage(self, page):
     try:
         wp = WikiPage.get(c.site, page)
         if self.restricted and wp.restricted:
             if not (c.is_wiki_mod or wp.special):
                 self.set_error('RESTRICTED_PAGE', code=403)
                 raise AbortWikiError
         if not this_may_view(wp):
             self.set_error('MAY_NOT_VIEW', code=403)
             raise AbortWikiError
         return wp
     except tdb_cassandra.NotFound:
         if self.required:
             self.set_error('PAGE_NOT_FOUND', code=404)
             raise AbortWikiError
         return None
Beispiel #30
0
 def validpage(self, page):
     try:
         wp = WikiPage.get(c.site, page)
         if self.restricted and wp.restricted:
             if not (c.is_wiki_mod or wp.special):
                 self.set_error('RESTRICTED_PAGE', code=403)
                 raise AbortWikiError
         if not this_may_view(wp):
             self.set_error('MAY_NOT_VIEW', code=403)
             raise AbortWikiError
         return wp
     except tdb_cassandra.NotFound:
         if self.required:
             self.set_error('PAGE_NOT_FOUND', code=404)
             raise AbortWikiError
         return None
Beispiel #31
0
def wiki_template(template_slug, sr=None):
    """Pull content from a subreddit's wiki page for internal use."""
    if not sr:
        try:
            sr = Subreddit._by_name(g.default_sr)
        except NotFound:
            # a freshly-build dev instance with no pre-populated data
            # will die on account creation (and other user actions) if a
            # default is not set.  Guard against that for testing.
            if g.debug:
                return
            raise

    try:
        wiki = WikiPage.get(sr, "templates/%s" % template_slug)
    except tdb_cassandra.NotFound:
        return None

    return wiki._get("content")
Beispiel #32
0
def wiki_template(template_slug, sr=None):
    """Pull content from a subreddit's wiki page for internal use."""
    if not sr:
        try:
            sr = Subreddit._by_name(g.default_sr)
        except NotFound:
            # a freshly-build dev instance with no pre-populated data
            # will die on account creation (and other user actions) if a
            # default is not set.  Guard against that for testing.
            if g.debug:
                return
            raise

    try:
        wiki = WikiPage.get(sr, "templates/%s" % template_slug)
    except tdb_cassandra.NotFound:
        return None

    return wiki._get("content")
Beispiel #33
0
def append_random_bottlecap_phrase(message):
    """Appends a random "bottlecap" phrase from the wiki page.

    The wiki page should be an unordered list with each item a separate
    bottlecap.
    """

    bottlecap = None
    try:
        wp = WikiPage.get(Frontpage, g.wiki_page_gold_bottlecaps)

        split_list = re.split('^[*-] ', wp.content, flags=re.MULTILINE)
        choices = [item.strip() for item in split_list if item.strip()]
        if len(choices):
            bottlecap = choice(choices)
    except NotFound:
        pass

    if bottlecap:
        message += '\n\n> ' + bottlecap
    return message
Beispiel #34
0
def append_random_bottlecap_phrase(message):
    """Appends a random "bottlecap" phrase from the wiki page.

    The wiki page should be an unordered list with each item a separate
    bottlecap.
    """

    bottlecap = None
    try:
        wp = WikiPage.get(Frontpage, g.wiki_page_gold_bottlecaps)

        split_list = re.split('^[*-] ', wp.content, flags=re.MULTILINE)
        choices = [item.strip() for item in split_list if item.strip()]
        if len(choices):
            bottlecap = choice(choices)
    except NotFound:
        pass

    if bottlecap:
        message += '\n\n> ' + bottlecap
    return message
Beispiel #35
0
    def run(self, page):
        original_page = page

        try:
            page = str(page) if page else ""
        except UnicodeEncodeError:
            return self.set_error('INVALID_PAGE_NAME', code=400)

        page = normalize_page(page)

        if page and not page_match_regex.match(page):
            return self.set_error('INVALID_PAGE_NAME', code=400)

        # If no page is specified, give the index page
        page = page or "index"

        if WikiPage.is_impossible(page):
            return self.set_error('INVALID_PAGE_NAME', code=400)

        if self.error_on_name_normalized and page != original_page:
            self.set_error('PAGE_NAME_NORMALIZED')

        return page
Beispiel #36
0
    def run(self, page):
        original_page = page

        try:
            page = str(page) if page else ""
        except UnicodeEncodeError:
            return self.set_error("INVALID_PAGE_NAME", code=400)

        page = normalize_page(page)

        if page and not page_match_regex.match(page):
            return self.set_error("INVALID_PAGE_NAME", code=400)

        # If no page is specified, give the index page
        page = page or "index"

        if WikiPage.is_impossible(page):
            return self.set_error("INVALID_PAGE_NAME", code=400)

        if self.error_on_name_normalized and page != original_page:
            self.set_error("PAGE_NAME_NORMALIZED")

        return page
Beispiel #37
0
 def run(self, page):
     self.perms = ['wiki']
     if page and WikiPage.is_special(page):
         self.perms += ['config']
     VSrModerator.run(self)
Beispiel #38
0
 def GET_wiki_listing(self):
     def check_hidden(page):
         return this_may_view(page)
     pages, linear_pages = WikiPage.get_listing(c.site, filter_check=check_hidden)
     return WikiListing(pages, linear_pages).render()
Beispiel #39
0
 def prev_stylesheet(self):
     try:
         return WikiPage.get(self, 'config/stylesheet')._get('revision', '')
     except tdb_cassandra.NotFound:
         return ''
Beispiel #40
0
 def stylesheet_contents_user(self):
     try:
         return WikiPage.get(self, 'config/stylesheet')._get('content', '')
     except tdb_cassandra.NotFound:
         return self._t.get('stylesheet_contents_user')
Beispiel #41
0
 def public_description(self):
     try:
         return WikiPage.get(self, 'config/description')._get('content','')
     except tdb_cassandra.NotFound:
         return self._t.get('public_description')
Beispiel #42
0
 def prev_stylesheet(self):
     try:
         return WikiPage.get(self, 'config/stylesheet')._get('revision','')
     except tdb_cassandra.NotFound:
         return ''
Beispiel #43
0
 def prev_stylesheet(self):
     try:
         return WikiPage.get(self, "config/stylesheet")._get("revision", "")
     except tdb_cassandra.NotFound:
         return ""
Beispiel #44
0
from r2.lib.media import upload_media
from r2.models.subreddit import Subreddit
from r2.models.wiki import WikiPage, ImagesByWikiPage

all_subreddits = Subreddit._query(sort=desc("_date"))
for sr in fetch_things2(all_subreddits):
    images = sr.images.copy()
    images.pop("/empties/", None)

    if not images:
        continue

    print 'Processing /r/%s (id36: %s)' % (sr.name, sr._id36)

    # upgrade old-style image ids to urls
    for name, image_url in images.items():
        if not isinstance(image_url, int):
            continue

        print "  upgrading image %r" % image_url
        url = "http://%s/%s_%d.png" % (g.s3_old_thumb_bucket, sr._fullname,
                                       image_url)
        image_data = urllib2.urlopen(url).read()
        new_url = upload_media(image_data, file_type=".png")
        images[name] = new_url

    # use a timestamp of zero to make sure that we don't overwrite any changes
    # from live dual-writes.
    rowkey = WikiPage.id_for(sr, "config/stylesheet")
    ImagesByWikiPage._cf.insert(rowkey, images, timestamp=0)
Beispiel #45
0
 def run(self, page):
     self.perms = ['wiki']
     if page and WikiPage.is_special(page):
         self.perms += ['config']
     VSrModerator.run(self)
Beispiel #46
0
 def GET_wiki_listing(self):
     def check_hidden(page):
         return this_may_view(page)
     pages, linear_pages = WikiPage.get_listing(c.site, filter_check=check_hidden)
     return WikiListing(pages, linear_pages).render()
Beispiel #47
0
 def stylesheet_contents_user(self):
     try:
         return WikiPage.get(self, 'config/stylesheet')._get('content','')
     except tdb_cassandra.NotFound:
        return  self._t.get('stylesheet_contents_user')
Beispiel #48
0
 def prev_public_description_id(self):
     try:
         return WikiPage.get(self, 'config/description')._get('revision','')
     except tdb_cassandra.NotFound:
         return ''
Beispiel #49
0
 def stylesheet_contents_user(self):
     try:
         return WikiPage.get(self, "config/stylesheet")._get("content", "")
     except tdb_cassandra.NotFound:
         return self._t.get("stylesheet_contents_user")
Beispiel #50
0
from r2.models.subreddit import Subreddit
from r2.models.wiki import WikiPage, ImagesByWikiPage


all_subreddits = Subreddit._query(sort=desc("_date"))
for sr in fetch_things2(all_subreddits):
    images = sr.images.copy()
    images.pop("/empties/", None)

    if not images:
        continue

    print 'Processing /r/%s (id36: %s)' % (sr.name, sr._id36)

    # upgrade old-style image ids to urls
    for name, image_url in images.items():
        if not isinstance(image_url, int):
            continue

        print "  upgrading image %r" % image_url
        url = "http://%s/%s_%d.png" % (g.s3_old_thumb_bucket,
                                       sr._fullname, image_url)
        image_data = urllib2.urlopen(url).read()
        new_url = upload_media(image_data, file_type=".png")
        images[name] = new_url

    # use a timestamp of zero to make sure that we don't overwrite any changes
    # from live dual-writes.
    rowkey = WikiPage.id_for(sr, "config/stylesheet")
    ImagesByWikiPage._cf.insert(rowkey, images, timestamp=0)
Beispiel #51
0
    def POST_wiki_edit(self, pageandprevious, content, page_name, reason):
        """Edit a wiki `page`"""
        page, previous = pageandprevious

        if c.user._spam:
            error = _("You are doing that too much, please try again later.")
            self.handle_error(415, 'SPECIAL_ERRORS', special_errors=[error])

        if not page:
            error = c.errors.get(('WIKI_CREATE_ERROR', 'page'))
            if error:
                self.handle_error(403, **(error.msg_params or {}))
            VNotInTimeout().run(action_name="wikirevise",
                                details_text="create")
            page = WikiPage.create(c.site, page_name)
        else:
            VNotInTimeout().run(action_name="wikirevise",
                                details_text="edit",
                                target=page)
            error = c.errors.get(('MAY_NOT_REVISE', 'page'))
            if error:
                self.handle_error(403, **(error.msg_params or {}))

        renderer = RENDERERS_BY_PAGE.get(page.name, 'wiki')
        if renderer in ('wiki', 'reddit'):
            content = VMarkdown(('content'), renderer=renderer).run(content)

        # Use the raw POST value as we need to tell the difference between
        # None/Undefined and an empty string.  The validators use a default
        # value with both of those cases and would need to be changed.
        # In order to avoid breaking functionality, this was done instead.
        previous = previous._id if previous else request.POST.get('previous')
        try:
            # special validation methods
            if page.name == 'config/stylesheet':
                css_errors, parsed = c.site.parse_css(content, verify=False)
                if g.css_killswitch:
                    self.handle_error(403, 'STYLESHEET_EDIT_DENIED')
                if css_errors:
                    error_items = [CssError(x).message for x in css_errors]
                    self.handle_error(415,
                                      'SPECIAL_ERRORS',
                                      special_errors=error_items)
            elif page.name == "config/automoderator":
                try:
                    rules = Ruleset(content)
                except ValueError as e:
                    error_items = [e.message]
                    self.handle_error(415,
                                      "SPECIAL_ERRORS",
                                      special_errors=error_items)

            # special saving methods
            if page.name == "config/stylesheet":
                c.site.change_css(content, parsed, previous, reason=reason)
            else:
                try:
                    page.revise(content, previous, c.user._id36, reason=reason)
                except ContentLengthError as e:
                    self.handle_error(403,
                                      'CONTENT_LENGTH_ERROR',
                                      max_length=e.max_length)

                # continue storing the special pages as data attributes on the subreddit
                # object. TODO: change this to minimize subreddit get sizes.
                if page.special and page.name in ATTRIBUTE_BY_PAGE:
                    setattr(c.site, ATTRIBUTE_BY_PAGE[page.name], content)
                    c.site._commit()

                if page.special or c.is_wiki_mod:
                    description = modactions.get(page.name,
                                                 'Page %s edited' % page.name)
                    ModAction.create(c.site,
                                     c.user,
                                     "wikirevise",
                                     details=description,
                                     description=reason)
        except ConflictException as e:
            self.handle_error(409,
                              'EDIT_CONFLICT',
                              newcontent=e.new,
                              newrevision=page.revision,
                              diffcontent=e.htmldiff)
        return json.dumps({})
Beispiel #52
0
    def sr_admin_menu(self):
        buttons = []
        is_single_subreddit = not isinstance(c.site, (ModSR, MultiReddit))
        is_admin = c.user_is_loggedin and c.user_is_admin
        is_moderator_with_perms = lambda *perms: (
            is_admin or c.site.is_moderator_with_perms(c.user, *perms))

        if is_single_subreddit and is_moderator_with_perms('config'):
            buttons.append(NavButton(menu.community_settings,
                                     css_class="reddit-edit",
                                     dest="edit"))
            buttons.append(NavButton(menu.edit_stylesheet,
                                     css_class="edit-stylesheet",
                                     dest="stylesheet"))

        if is_moderator_with_perms('mail'):
            buttons.append(NamedButton("modmail",
                                    dest="message/inbox",
                                    css_class="moderator-mail"))

        if is_single_subreddit:
            if is_moderator_with_perms('access'):
                buttons.append(NamedButton("moderators",
                                           css_class="reddit-moderators"))

                if not c.site.hide_contributors:
                    buttons.append(NavButton(
                            menu.contributors,
                            "contributors",
                            css_class="reddit-contributors"))

            buttons.append(NamedButton("traffic", css_class="reddit-traffic"))

        if is_moderator_with_perms('posts'):
            buttons += [NamedButton("modqueue", css_class="reddit-modqueue"),
                        NamedButton("reports", css_class="reddit-reported"),
                        NamedButton("spam", css_class="reddit-spam"),
                        NamedButton("edited", css_class="reddit-edited")]

        if is_single_subreddit:
            if is_moderator_with_perms('access'):
                buttons.append(NamedButton("banned", css_class="reddit-ban"))
            if is_moderator_with_perms('flair'):
                buttons.append(NamedButton("flair", css_class="reddit-flair"))

        if is_single_subreddit and is_moderator_with_perms('wiki'):
            # append automod button if they have an AutoMod configuration
            try:
                WikiPage.get(c.site, "config/automoderator")
                buttons.append(NamedButton(
                    "automod",
                    dest="../wiki/config/automoderator",
                    css_class="reddit-automod",
                ))
            except tdb_cassandra.NotFound:
                pass

        buttons.append(NamedButton("log", css_class="reddit-moderationlog"))
        if is_moderator_with_perms('posts'):
            buttons.append(
                NamedButton("unmoderated", css_class="reddit-unmoderated"))

        return SideContentBox(_('moderation tools'),
                              [NavMenu(buttons,
                                       type="flat_vert",
                                       base_path="/about/",
                                       css_class="icon-menu",
                                       separator="")],
                              _id="moderation_tools",
                              collapsible=True)