def __init__( self, title, dest, sr_path=True, nocname=False, aliases=None, target="", use_params=False, css_class="", data=None, ): aliases = aliases or [] aliases = set(_force_unicode(a.rstrip("/")) for a in aliases) if dest: aliases.add(_force_unicode(dest.rstrip("/"))) self.title = title self.dest = dest self.selected = False self.sr_path = sr_path self.nocname = nocname self.aliases = aliases self.target = target self.use_params = use_params self.data = data Styled.__init__(self, self._style, css_class=css_class)
def __init__(self, link = None, comment = None, link_title = '', *a, **kw): # TODO: temp hack until we find place for builder_wrapper link.render_full = True from r2.controllers.listingcontroller import ListingController link_builder = IDBuilder(link._fullname, wrap = ListingController.builder_wrapper) # link_listing will be the one-element listing at the top self.link_listing = LinkListing(link_builder, nextprev=False).listing() # link is a wrapped Link object self.link = self.link_listing.things[0] link_title = ((self.link.title) if hasattr(self.link, 'title') else '') if comment: author = Account._byID(comment.author_id, data=True).name params = {'author' : author, 'title' : _force_unicode(link_title)} title = strings.permalink_title % params else: params = {'title':_force_unicode(link_title), 'site' : c.site.title} title = strings.link_info_title % params if not c.default_sr: # Not on the main page, so include a pointer to the canonical URL for this link self.canonical_link = link.canonical_url Reddit.__init__(self, title = title, body_class = 'post', *a, **kw)
def __init__(self, title, dest, sr_path=True, nocname=False, aliases=None, target="", use_params=False, css_class='', data=None): aliases = aliases or [] aliases = set(_force_unicode(a.rstrip('/')) for a in aliases) if dest: aliases.add(_force_unicode(dest.rstrip('/'))) self.title = title self.dest = dest self.selected = False self.sr_path = sr_path self.nocname = nocname self.aliases = aliases self.target = target self.use_params = use_params self.data = data Styled.__init__(self, self._style, css_class=css_class)
def __init__(self, title, dest, sr_path=True, nocname=False, opt='', aliases=[], target="", style="plain", **kw): # keep original dest to check against c.location when rendering aliases = set(_force_unicode(a.rstrip('/')) for a in aliases) if dest: aliases.add(_force_unicode(dest.rstrip('/'))) self.request_params = dict(request.GET) self.stripped_path = _force_unicode(request.path.rstrip('/').lower()) Styled.__init__(self, style=style, sr_path=sr_path, nocname=nocname, target=target, aliases=aliases, dest=dest, selected=False, title=title, opt=opt, **kw)
def make_permalink_title(self, link): author = Account._byID(self.author_id, data=True).name params = { 'author': _force_unicode(author), 'title': _force_unicode(link.title), 'site': c.site.title } return strings.permalink_title % params
def query_string(dict): pairs = [] for k, v in dict.iteritems(): if v is not None: try: k = url_escape(_force_unicode(k)) v = url_escape(_force_unicode(v)) pairs.append(k + '=' + v) except UnicodeDecodeError: continue if pairs: return '?' + '&'.join(pairs) else: return ''
def query_string(dict): pairs = [] for k,v in dict.iteritems(): if v is not None: try: k = url_escape(_force_unicode(k)) v = url_escape(_force_unicode(v)) pairs.append(k + '=' + v) except UnicodeDecodeError: continue if pairs: return '?' + '&'.join(pairs) else: return ''
def __init__(self, title, dest, sr_path = True, nocname=False, opt = '', aliases = [], target = "", style = "plain", **kw): # keep original dest to check against c.location when rendering aliases = set(_force_unicode(a.rstrip('/')) for a in aliases) aliases.add(_force_unicode(dest.rstrip('/'))) self.request_params = dict(request.GET) self.stripped_path = _force_unicode(request.path.rstrip('/').lower()) Styled.__init__(self, style = style, sr_path = sr_path, nocname = nocname, target = target, aliases = aliases, dest = dest, selected = False, title = title, opt = opt, **kw)
def build(self, base_path=""): """Generates the href of the button based on the base_path provided.""" if self.style == "external": self.path = self.dest self.bare_path = self.dest return # append to the path or update the get params dependent on presence # of opt if self.opt: p = request.get.copy() p[self.opt] = self.dest else: p = {} base_path = ("%s/%s/" % (base_path, self.dest)).replace("//", "/") p.update(self.dest_params) self.bare_path = _force_unicode(base_path.replace("//", "/")).lower() self.bare_path = self.bare_path.rstrip("/") # append the query string base_path += query_string(p) # since we've been sloppy of keeping track of "//", get rid # of any that may be present self.path = base_path.replace("//", "/")
def _by_domain(cls, domain, _update = False): sr_id = cls._by_domain_cache(_force_unicode(domain).lower(), _update = _update) if sr_id: return cls._byID(sr_id, True) else: return None
def email_password_change_email(user, new_email=None, password_change=False): """Queues a system email for email or password change notification.""" from r2.lib.pages import EmailPasswordChangeEmail token = make_reset_token(AccountRecoveryToken, user, issue_limit=1) if not token: return False passlink = token.make_token_url() if not passlink: return False g.log.info("Generated %s: %s", AccountRecoveryToken.__name__, passlink) signer = MessageSigner(g.secrets["outbound_url_secret"]) signature = base64.urlsafe_b64encode( signer.make_signature(_force_unicode(passlink), max_age=timedelta(days=180))) email_kind = Email.Kind.EMAIL_CHANGE if password_change: email_kind = Email.Kind.PASSWORD_CHANGE _system_email( user.email, EmailPasswordChangeEmail( user=user, new_email=new_email, passlink=passlink, email_kind=email_kind, signature=signature, ).render(style='email'), email_kind, reply_to=g.support_email, ) return True
def password_email(user): """For resetting a user's password.""" from r2.lib.pages import PasswordReset token = make_reset_token(PasswordResetToken, user, issue_limit=3) if not token: return False passlink = token.make_token_url() if not passlink: return False g.log.info("Generated %s: %s for user %s", PasswordResetToken.__name__, passlink, user.name) signer = MessageSigner(g.secrets["outbound_url_secret"]) signature = base64.urlsafe_b64encode( signer.make_signature(_force_unicode(passlink), max_age=timedelta(days=180))) _system_email( user.email, PasswordReset( user=user, passlink=passlink, signature=signature, ).render(style='email'), Email.Kind.RESET_PASSWORD, reply_to=g.support_email, user=user, ) return True
def build(self, base_path=''): '''Generates the href of the button based on the base_path provided.''' if self.style == "external": self.path = self.dest self.bare_path = self.dest return # append to the path or update the get params dependent on presence # of opt if self.opt: p = request.get.copy() p[self.opt] = self.dest else: p = {} base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') p.update(self.dest_params) self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() self.bare_path = self.bare_path.rstrip('/') # append the query string base_path += query_string(p) # since we've been sloppy of keeping track of "//", get rid # of any that may be present self.path = base_path.replace('//', '/')
def format_output_url(cls, url, **kw): """ Helper method used during redirect to ensure that the redirect url (assisted by frame busting code or javasctipt) will point to the correct domain and not have any extra dangling get parameters. The extensions are also made to match and the resulting url is utf8 encoded. Node: for development purposes, also checks that the port matches the request port """ preserve_extension = kw.pop("preserve_extension", True) u = UrlParser(url) if u.is_reddit_url(): # make sure to pass the port along if not 80 if not kw.has_key('port'): kw['port'] = request.port # disentangle the cname (for urls that would have # cnameframe=1 in them) u.mk_cname(**kw) # make sure the extensions agree with the current page if preserve_extension and c.extension: u.set_extension(c.extension) # unparse and encode it un utf8 rv = _force_unicode(u.unparse()).encode('utf8') if "\n" in rv or "\r" in rv: abort(400) return rv
def _by_domain(cls, domain, _update=False): sr_id = cls._by_domain_cache(_force_unicode(domain).lower(), _update=_update) if sr_id: return cls._byID(sr_id, True) else: return None
def __init__(self, query, sr=None, sort=None, syntax=None, raw_sort=None, faceting=None, recent=None, include_over18=True, rank_expressions=None, start=0, num=1000): if syntax is None: syntax = self.default_syntax elif syntax not in self.known_syntaxes: raise ValueError("Unknown search syntax: %s" % syntax) self.syntax = syntax self.query = filters._force_unicode(query or u'') self.converted_data = None self.bq = u'' # filters self.sr = sr self._recent = recent self.recent = self.recents[recent] self.include_over18 = include_over18 # rank / rank expressions self._sort = sort if raw_sort: self.sort = raw_sort else: self.sort = self.sorts[sort] self.rank_expressions = rank_expressions # pagination self.start = start self.num = num # facets self.faceting = faceting self.results = None
def renderpolls(text, thing): polls_not_voted = [] polls_voted = [] oldballots = [] def checkmatch(match): pollid = match.group(1) try: poll = Poll._byID(pollid, True) if poll.thingid != thing._id: return "Error: Poll belongs to a different comment" if poll.user_has_voted(c.user): polls_voted.append(pollid) return poll.render_results() else: polls_not_voted.append(pollid) return poll.render() except NotFound: return "Error: Poll not found!" text = re.sub(pollid_re, checkmatch, _force_unicode(text)) if polls_voted or polls_not_voted: voted_on_all = not polls_not_voted page = _get_pageclass('PollWrapper')(thing, text, voted_on_all) text = page.render('html') return text
def __init__(self, query, sr=None, sort=None, syntax=None, raw_sort=None, faceting=None, recent=None): if syntax is None: syntax = self.default_syntax elif syntax not in self.known_syntaxes: raise ValueError("Unknown search syntax: %s" % syntax) self.query = filters._force_unicode(query or u'') #self.query = query self.converted_data = None self.syntax = syntax self.sr = sr self._sort = sort if raw_sort: self.sort = raw_sort else: self.sort = self.sorts[sort] self._recent = recent self.recent = self.recents[recent] self.faceting = faceting self.bq = u'' self.results = None
def format_output_url(cls, url, **kw): """ Helper method used during redirect to ensure that the redirect url (assisted by frame busting code or javasctipt) will point to the correct domain and not have any extra dangling get parameters. The extensions are also made to match and the resulting url is utf8 encoded. Node: for development purposes, also checks that the port matches the request port """ u = UrlParser(url) if u.is_reddit_url(): # make sure to pass the port along if not 80 if not kw.has_key("port"): kw["port"] = request.port # disentagle the cname (for urls that would have # cnameframe=1 in them) u.mk_cname(**kw) # make sure the extensions agree with the current page if c.extension: u.set_extension(c.extension) # unparse and encode it un utf8 rv = _force_unicode(u.unparse()).encode("utf8") if any(ch.isspace() for ch in rv): raise ValueError("Space characters in redirect URL: [%r]" % rv) return rv
def build(self, base_path=''): '''Generates the href of the button based on the base_path provided.''' # append to the path or update the get params dependent on presence # of opt if self.opt: p = self.request_params.copy() if self.dest: p[self.opt] = self.dest elif self.opt in p: del p[self.opt] else: p = {} base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') self.action_params = p self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() self.bare_path = self.bare_path.rstrip('/') self.base_path = base_path # append the query string base_path += query_string(p) # since we've been sloppy of keeping track of "//", get rid # of any that may be present self.path = base_path.replace('//', '/')
def email_password_change_email(user, new_email=None, password_change=False): """Queues a system email for email or password change notification.""" from r2.lib.pages import EmailPasswordChangeEmail token = make_reset_token(AccountRecoveryToken, user, issue_limit=1) if not token: return False passlink = token.make_token_url() if not passlink: return False g.log.info("Generated %s: %s", AccountRecoveryToken.__name__, passlink) signer = MessageSigner(g.secrets["outbound_url_secret"]) signature = base64.urlsafe_b64encode( signer.make_signature( _force_unicode(passlink), max_age=timedelta(days=180)) ) email_kind = Email.Kind.EMAIL_CHANGE if password_change: email_kind = Email.Kind.PASSWORD_CHANGE _system_email( user.email, EmailPasswordChangeEmail( user=user, new_email=new_email, passlink=passlink, email_kind=email_kind, signature=signature, ).render(style='email'), email_kind, reply_to=g.support_email, ) return True
def build(self, base_path = ''): '''Generates the href of the button based on the base_path provided.''' # append to the path or update the get params dependent on presence # of opt if self.opt: p = self.request_params.copy() if self.dest: p[self.opt] = self.dest elif self.opt in p: del p[self.opt] else: p = {} base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') self.action_params = p self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() self.bare_path = self.bare_path.rstrip('/') self.base_path = base_path # append the query string base_path += query_string(p) # since we've been sloppy of keeping track of "//", get rid # of any that may be present self.path = base_path.replace('//', '/')
def renderpolls(text, thing): polls_not_voted = [] polls_voted = [] oldballots = [] def checkmatch(match): pollid = match.group(1) try: poll = Poll._byID(pollid, True) if poll.thingid != thing._id: return "Error: Poll belongs to a different comment" if poll.user_has_voted(c.user): polls_voted.append(pollid) return poll.render_results() else: polls_not_voted.append(pollid) return poll.render() except NotFound: return "Error: Poll not found!" text = re.sub(pollid_re, checkmatch, _force_unicode(text)) if polls_voted or polls_not_voted: voted_on_all = not polls_not_voted page = _get_pageclass('PollWrapper')(thing, text, voted_on_all) text = page.render('html') return text
def format_output_url(cls, url, **kw): """ Helper method used during redirect to ensure that the redirect url (assisted by frame busting code or javasctipt) will point to the correct domain and not have any extra dangling get parameters. The extensions are also made to match and the resulting url is utf8 encoded. Node: for development purposes, also checks that the port matches the request port """ u = UrlParser(url) if u.is_reddit_url(): # make sure to pass the port along if not 80 if not kw.has_key('port'): kw['port'] = request.port # disentagle the cname (for urls that would have # cnameframe=1 in them) u.mk_cname(**kw) # make sure the extensions agree with the current page if c.extension: u.set_extension(c.extension) # unparse and encode it un utf8 rv = _force_unicode(u.unparse()).encode('utf8') if "\n" in rv or "\r" in rv: abort(400) return rv
def GET_related(self, num, article, after, reverse, count): """Related page: performs a search using title of article as the search query. """ if not can_view_link_comments(article): abort(403, 'forbidden') query = self.related_replace_regex.sub(self.related_replace_with, article.title) query = _force_unicode(query) query = query[:1024] query = "|".join(query.split()) query = "title:'%s'" % query rel_range = timedelta(days=3) start = (article._date - rel_range).strftime("%s") end = (article._date + rel_range).strftime("%s") query = "(and %s timestamp:%s..%s)" % (query, start, end) q = SearchQuery(query, raw_sort="-text_relevance", syntax="cloudsearch") num, t, pane = self._search(q, num=num, after=after, reverse=reverse, count=count) return LinkInfoPage(link=article, content=pane, subtitle=_('related')).render()
def password_email(user): """For resetting a user's password.""" from r2.lib.pages import PasswordReset token = make_reset_token(PasswordResetToken, user, issue_limit=3) if not token: return False passlink = token.make_token_url() if not passlink: return False g.log.info("Generated %s: %s for user %s", PasswordResetToken.__name__, passlink, user.name) signer = MessageSigner(g.secrets["outbound_url_secret"]) signature = base64.urlsafe_b64encode( signer.make_signature( _force_unicode(passlink), max_age=timedelta(days=180)) ) _system_email( user.email, PasswordReset( user=user, passlink=passlink, signature=signature, ).render(style='email'), Email.Kind.RESET_PASSWORD, reply_to=g.support_email, user=user, ) return True
def submit_link(self): from r2.lib.template_helpers import get_domain from mako.filters import url_escape d = get_domain(subreddit=False) u = _force_unicode(self.url()) return "http://%s/r/ads/submit?url=%s" % (d, url_escape(u))
def POST_spendcreddits(self, form, jquery, months, passthrough): if months is None or months < 1: form.set_html(".status", _("nice try.")) return days = months * 31 if not passthrough: raise ValueError("/spendcreddits got no passthrough?") blob_key, payment_blob = get_blob(passthrough) if payment_blob["goldtype"] != "gift": raise ValueError("/spendcreddits payment_blob %s has goldtype %s" % (passthrough, payment_blob["goldtype"])) signed = payment_blob["signed"] giftmessage = _force_unicode(payment_blob["giftmessage"]) recipient_name = payment_blob["recipient"] if payment_blob["account_id"] != c.user._id: fmt = "/spendcreddits payment_blob %s has userid %d " + "but c.user._id is %d" raise ValueError(fmt % passthrough, payment_blob["account_id"], c.user._id) try: recipient = Account._by_name(recipient_name) except NotFound: raise ValueError("Invalid username %s in spendcreddits, buyer = %s" % (recipient_name, c.user.name)) if recipient._deleted: form.set_html(".status", _("that user has deleted their account")) return if not c.user.employee: if months > c.user.gold_creddits: raise ValueError("%s is trying to sneak around the creddit check" % c.user.name) c.user.gold_creddits -= months c.user.gold_creddit_escrow += months c.user._commit() comment_id = payment_blob.get("comment") comment = send_gift(c.user, recipient, months, days, signed, giftmessage, comment_id) if not c.user.employee: c.user.gold_creddit_escrow -= months c.user._commit() payment_blob["status"] = "processed" g.hardcache.set(blob_key, payment_blob, 86400 * 30) form.set_html(".status", _("the gold has been delivered!")) form.find("button").hide() if comment: gilding_message = make_comment_gold_message(comment, user_gilded=True) jquery.gild_comment(comment_id, gilding_message, comment.gildings)
def _update(obj): if isinstance(obj, (str, unicode)): return _force_unicode(obj) elif isinstance(obj, dict): return dict((k, _update(v)) for k, v in obj.iteritems()) elif isinstance(obj, (list, tuple)): return map(_update, obj) elif isinstance(obj, CacheStub) and kw.has_key(obj.name): return kw[obj.name] else: return obj
def get_message_subject(message): sr = Subreddit._byID(message.sr_id, data=True) if message.first_message: first_message = Message._byID(message.first_message, data=True) conversation_subject = first_message.subject else: conversation_subject = message.subject return u"[{brander_community_abbr}/{subreddit} mail]: {subject}".format( subreddit=sr.name, subject=_force_unicode(conversation_subject, brander_community_abbr=g.brander_community_abbr))
def is_selected(self): """Given the current request path, would the button be selected.""" if self.opt: return request.params.get(self.opt, '') in self.aliases else: stripped_path = request.path.rstrip('/').lower() ustripped_path = _force_unicode(stripped_path) if stripped_path == self.bare_path: return True if stripped_path in self.aliases: return True
def get_related_query(self, query, article, start, end, nsfw): '''build related query in cloudsearch syntax''' query = _force_unicode(query) query = query[:1024] query = u"|".join(query.split()) query = u"title:'%s'" % query nsfw = nsfw and u"nsfw:0" or u"" query = u"(and %s timestamp:%s..%s %s)" % (query, start, end, nsfw) return g.search.SearchQuery(query, raw_sort="-text_relevance", syntax="cloudsearch")
def _update(obj): if isinstance(obj, (str, unicode)): return _force_unicode(obj) elif isinstance(obj, dict): return dict((k, _update(v)) for k, v in obj.iteritems()) elif isinstance(obj, (list, tuple)): return map(_update, obj) elif isinstance(obj, CacheStub) and kw.has_key(obj.name): return kw[obj.name] else: return obj
def get_message_subject(message): sr = Subreddit._byID(message.sr_id, data=True) if message.first_message: first_message = Message._byID(message.first_message, data=True) conversation_subject = first_message.subject else: conversation_subject = message.subject return u"[r/{subreddit} mail]: {subject}".format( subreddit=sr.name, subject=_force_unicode(conversation_subject))
def title(self): titles = {'overview': _("Overview for %(user)s - %(site)s"), 'comments': _("Comments by %(user)s - %(site)s"), 'submitted': _("Submitted by %(user)s - %(site)s"), 'liked': _("Liked by %(user)s - %(site)s"), 'disliked': _("Disliked by %(user)s - %(site)s"), 'hidden': _("Hidden by %(user)s - %(site)s"), 'drafts': _("Drafts for %(user)s - %(site)s")} title = titles.get(self.where, _('Profile for %(user)s - %(site)s')) \ % dict(user = _force_unicode(self.vuser.name), site = c.site.title) return title
def title(self): titles = {'overview': _("Overview for %(user)s - %(site)s"), 'comments': _("Comments by %(user)s - %(site)s"), 'submitted': _("Submitted by %(user)s - %(site)s"), 'liked': _("Liked by %(user)s - %(site)s"), 'disliked': _("Disliked by %(user)s - %(site)s"), 'hidden': _("Hidden by %(user)s - %(site)s"), 'drafts': _("Drafts for %(user)s - %(site)s")} title = titles.get(self.where, _('Profile for %(user)s - %(site)s')) \ % dict(user = _force_unicode(self.vuser.name), site = c.site.title) return title
def get_related_query(self, query, article, start, end, nsfw): '''build related query in cloudsearch syntax''' query = _force_unicode(query) query = query[:1024] query = u"|".join(query.split()) query = u"title:'%s'" % query nsfw = nsfw and u"nsfw:0" or u"" query = u"(and %s timestamp:%s..%s %s)" % (query, start, end, nsfw) return g.search.SearchQuery(query, raw_sort="-text_relevance", syntax="cloudsearch")
def build(self, base_path=''): base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() self.bare_path = self.bare_path.rstrip('/') self.base_path = base_path if self.use_params: base_path += query_string(dict(request.GET)) # since we've been sloppy of keeping track of "//", get rid # of any that may be present self.path = base_path.replace('//', '/')
def is_selected(self): stripped_path = _force_unicode(request.path.rstrip('/').lower()) if stripped_path == self.bare_path: return True site_path = c.site.user_path.lower() + self.bare_path if self.sr_path and stripped_path == site_path: return True if self.bare_path and stripped_path.startswith(self.bare_path): return True if stripped_path in self.aliases: return True
def is_selected(self): stripped_path = _force_unicode(request.path.rstrip('/').lower()) if stripped_path == self.bare_path: return True site_path = c.site.user_path.lower() + self.bare_path if self.sr_path and stripped_path == site_path: return True if self.bare_path and stripped_path.startswith(self.bare_path): return True if stripped_path in self.aliases: return True
def build(self, base_path=''): base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() self.bare_path = self.bare_path.rstrip('/') self.base_path = base_path if self.use_params: base_path += query_string(dict(request.GET)) # since we've been sloppy of keeping track of "//", get rid # of any that may be present self.path = base_path.replace('//', '/')
def is_selected(self): """Given the current request path, would the button be selected.""" if hasattr(self, "name") and self.name == "home": return False if self.opt: return request.params.get(self.opt, "") in self.aliases else: stripped_path = request.path.rstrip("/").lower() ustripped_path = _force_unicode(stripped_path) if stripped_path == self.bare_path: return True if stripped_path in self.aliases: return True
def is_selected(self): """Given the current request path, would the button be selected.""" if hasattr(self, 'name') and self.name == 'home': return False if self.opt: return request.params.get(self.opt, '') in self.aliases else: stripped_path = request.path.rstrip('/').lower() ustripped_path = _force_unicode(stripped_path) if stripped_path == self.bare_path: return True if stripped_path in self.aliases: return True
def validate_blob(custom): """Validate payment_blob and return a dict with everything looked up.""" ret = {} if not custom: raise GoldException('no custom') payment_blob = g.hardcache.get('payment_blob-%s' % str(custom)) if not payment_blob: raise GoldException('no payment_blob') if 'account_id' in payment_blob and 'account_name' in payment_blob: try: buyer = Account._byID(payment_blob['account_id'], data=True) ret['buyer'] = buyer except NotFound: raise GoldException('bad account_id') if not buyer.name.lower() == payment_blob['account_name'].lower(): raise GoldException('buyer mismatch') elif 'email' in payment_blob: ret['email'] = payment_blob['email'] else: raise GoldException('no account_id or email') goldtype = payment_blob['goldtype'] ret['goldtype'] = goldtype if goldtype == 'gift': recipient_name = payment_blob.get('recipient', None) if not recipient_name: raise GoldException('gift missing recpient') try: recipient = Account._by_name(recipient_name) ret['recipient'] = recipient except NotFound: raise GoldException('bad recipient') thing_fullname = payment_blob.get('thing', None) if thing_fullname: try: ret['thing'] = Thing._by_fullname(thing_fullname) except NotFound: raise GoldException('bad thing') ret['signed'] = payment_blob.get('signed', False) giftmessage = payment_blob.get('giftmessage') giftmessage = _force_unicode(giftmessage) if giftmessage else None ret['giftmessage'] = giftmessage elif goldtype not in ('onetime', 'autorenew', 'creddits', 'code'): raise GoldException('bad goldtype') return ret
def validate_blob(custom): """Validate payment_blob and return a dict with everything looked up.""" ret = {} if not custom: raise GoldException('no custom') payment_blob = g.hardcache.get('payment_blob-%s' % str(custom)) if not payment_blob: raise GoldException('no payment_blob') if 'account_id' in payment_blob and 'account_name' in payment_blob: try: buyer = Account._byID(payment_blob['account_id'], data=True) ret['buyer'] = buyer except NotFound: raise GoldException('bad account_id') if not buyer.name.lower() == payment_blob['account_name'].lower(): raise GoldException('buyer mismatch') elif 'email' in payment_blob: ret['email'] = payment_blob['email'] else: raise GoldException('no account_id or email') goldtype = payment_blob['goldtype'] ret['goldtype'] = goldtype if goldtype == 'gift': recipient_name = payment_blob.get('recipient', None) if not recipient_name: raise GoldException('gift missing recpient') try: recipient = Account._by_name(recipient_name) ret['recipient'] = recipient except NotFound: raise GoldException('bad recipient') thing_fullname = payment_blob.get('thing', None) if thing_fullname: try: ret['thing'] = Thing._by_fullname(thing_fullname) except NotFound: raise GoldException('bad thing') ret['signed'] = payment_blob.get('signed', False) giftmessage = payment_blob.get('giftmessage') giftmessage = _force_unicode(giftmessage) if giftmessage else None ret['giftmessage'] = giftmessage elif goldtype not in ('onetime', 'autorenew', 'creddits', 'code'): raise GoldException('bad goldtype') return ret
def _run(self, start=0, num=1000, _update=False): """Run the search against self.query""" q = None if self.syntax == "cloudsearch": self.bq = self.customize_query(self.query) elif self.syntax == "lucene": bq = l2cs.convert(self.query, self.lucene_parser) self.converted_data = {"syntax": "cloudsearch", "converted": filters._force_unicode(bq)} self.bq = self.customize_query(bq) elif self.syntax == "plain": q = self.query if g.sqlprinting: g.log.info("%s", self) return self._run_cached(q, self.bq, self.sort, start=start, num=num, _update=_update)
def __init__(self, query, sr=None, sort=None, syntax=None, raw_sort=None, faceting=None, recent=None, include_over18=True, rank_expressions=None, bypass_l2cs=False, start=0, num=1000): if syntax is None: syntax = self.default_syntax elif syntax not in self.known_syntaxes: raise ValueError("Unknown search syntax: %s" % syntax) self.syntax = syntax self.query = filters._force_unicode(query or u'') # parsed query self.converted_data = None self.q = u'' self.bq = u'' # filters self.sr = sr self._recent = recent self.recent = self.recents[recent] self.include_over18 = include_over18 # rank / rank expressions self._sort = sort if raw_sort: self.sort = raw_sort else: self.sort = self.sorts.get(sort) self.rank_expressions = rank_expressions self.bypass_l2cs = bypass_l2cs # pagination self.start = start self.num = num # facets self.faceting = faceting self.results = None
def validate_blob(custom): """Validate payment_blob and return a dict with everything looked up.""" ret = {} if not custom: raise GoldException("no custom") payment_blob = g.hardcache.get("payment_blob-%s" % str(custom)) if not payment_blob: raise GoldException("no payment_blob") if not ("account_id" in payment_blob and "account_name" in payment_blob): raise GoldException("no account_id") try: buyer = Account._byID(payment_blob["account_id"], data=True) ret["buyer"] = buyer except NotFound: raise GoldException("bad account_id") if not buyer.name.lower() == payment_blob["account_name"].lower(): raise GoldException("buyer mismatch") goldtype = payment_blob["goldtype"] ret["goldtype"] = goldtype if goldtype == "gift": recipient_name = payment_blob.get("recipient", None) if not recipient_name: raise GoldException("gift missing recpient") try: recipient = Account._by_name(recipient_name) ret["recipient"] = recipient except NotFound: raise GoldException("bad recipient") comment_fullname = payment_blob.get("comment", None) if comment_fullname: try: ret["comment"] = Comment._by_fullname(comment_fullname) except NotFound: raise GoldException("bad comment") ret["signed"] = payment_blob.get("signed", False) giftmessage = payment_blob.get("giftmessage") giftmessage = _force_unicode(giftmessage) if giftmessage else None ret["giftmessage"] = giftmessage elif goldtype not in ("onetime", "autorenew", "creddits"): raise GoldException("bad goldtype") return ret
def _oembed_comment(thing, **embed_options): link = thing.link_slow subreddit = link.subreddit_slow if (not can_view_link_comments(link) or subreddit.type in Subreddit.private_types): raise ForbiddenError(errors.COMMENT_NOT_ACCESSIBLE) if not thing._deleted: author = thing.author_slow if author._deleted: author_name = _("[account deleted]") else: author_name = author.name title = _('%(author)s\'s comment from discussion "%(title)s"') % { "author": author_name, "title": _force_unicode(link.title), } else: author_name = "" title = "" parent = "true" if embed_options.get('parent') else "false" html = format_html( embeds.get_inject_template(embed_options.get('omitscript')), media=g.media_domain, parent=parent, live="true" if embed_options.get('live') else "false", created=datetime.now(g.tz).isoformat(), comment=thing.make_permalink_slow(force_domain=True), link=link.make_permalink_slow(force_domain=True), title=websafe(title), uuid=uuid1(), ) oembed_response = dict( _OEMBED_BASE, type="rich", title=title, author_name=author_name, html=html, ) if author_name: oembed_response['author_url'] = make_url_https('/user/' + author_name) return oembed_response
def title_to_url(title, max_length = 50): """Takes a string and makes it suitable for use in URLs""" title = _force_unicode(title) #make sure the title is unicode title = rx_whitespace.sub('_', title) #remove whitespace title = rx_notsafe.sub('', title) #remove non-printables title = rx_underscore.sub('_', title) #remove double underscores title = title.strip('_') #remove trailing underscores title = title.lower() #lowercase the title if len(title) > max_length: #truncate to nearest word title = title[:max_length] last_word = title.rfind('_') if (last_word > 0): title = title[:last_word] return title or "_"
def send_templated_orangered(message_type, title_type, user, url): title_template = wiki_template(title_type) message_template = wiki_template(message_type) if not title_template or not message_template: g.log.warning("Unable to send message: invalid wiki templates.") return message_template = message_template.format(user_email=_force_unicode( user.email), url=url) user.orangered_opt_in_message_timestamp = datetime.now(g.tz) user._commit() send_system_message(user, title_template, message_template)
def title_to_url(title, max_length=50): """Takes a string and makes it suitable for use in URLs""" title = _force_unicode(title) #make sure the title is unicode title = rx_whitespace.sub('_', title) #remove whitespace title = rx_notsafe.sub('', title) #remove non-printables title = rx_underscore.sub('_', title) #remove double underscores title = title.strip('_') #remove trailing underscores title = title.lower() #lowercase the title if len(title) > max_length: #truncate to nearest word title = title[:max_length] last_word = title.rfind('_') if (last_word > 0): title = title[:last_word] return title or "_"
def send_templated_orangered(message_type, title_type, user, url): title_template = wiki_template(title_type) message_template = wiki_template(message_type) if not title_template or not message_template: g.log.warning("Unable to send message: invalid wiki templates.") return message_template = message_template.format( user_email=_force_unicode(user.email), url=url) user.orangered_opt_in_message_timestamp = datetime.now(g.tz) user._commit() send_system_message(user, title_template, message_template)
def _run(self, start=0, num=1000, _update=False): '''Run the search against self.query''' q = None if self.syntax == "cloudsearch": self.bq = self.customize_query(self.query) elif self.syntax == "lucene": bq = l2cs.convert(self.query, self.lucene_parser) self.converted_data = {"syntax": "cloudsearch", "converted": filters._force_unicode(bq)} self.bq = self.customize_query(bq) elif self.syntax == "plain": q = self.query if g.sqlprinting: g.log.info("%s", self) return self._run_cached(q, self.bq, self.sort, start=start, num=num, _update=_update)
def _oembed_comment(thing, **embed_options): link = thing.link_slow subreddit = link.subreddit_slow if (not can_view_link_comments(link) or subreddit.type in Subreddit.private_types): raise ForbiddenError(errors.COMMENT_NOT_ACCESSIBLE) if not thing._deleted: author = thing.author_slow if author._deleted: author_name = _("[account deleted]") else: author_name = author.name title = _('%(author)s\'s comment from discussion "%(title)s"') % { "author": author_name, "title": _force_unicode(link.title), } else: author_name = "" title = "" parent = "true" if embed_options.get('parent') else "false" html = format_html(embeds.get_inject_template(embed_options.get('omitscript')), media=g.media_domain, parent=parent, live="true" if embed_options.get('live') else "false", created=datetime.now(g.tz).isoformat(), comment=thing.make_permalink_slow(force_domain=True), link=link.make_permalink_slow(force_domain=True), title=websafe(title), uuid=uuid1(), ) oembed_response = dict(_OEMBED_BASE, type="rich", title=title, author_name=author_name, html=html, ) if author_name: oembed_response['author_url'] = make_url_https('/user/' + author_name) return oembed_response
def _oembed_comment(thing, **embed_options): link = thing.link_slow if not can_view_link_comments(link): raise ForbiddenError("Cannot access this comment.") if not thing._deleted: author = thing.author_slow if author._deleted: author_name = _("[account deleted]") else: author_name = author.name title = _('%(author)s\'s comment from discussion "%(title)s"') % { "author": author_name, "title": _force_unicode(link.title), } else: author_name = "" title = "" html = format_html( embeds.get_inject_template(), media=g.media_domain, parent="true" if embed_options.get('parent') else "false", live="true" if embed_options.get('live') else "false", created=datetime.now(g.tz).isoformat(), comment=thing.make_permalink_slow(force_domain=True), link=link.make_permalink_slow(force_domain=True), title=websafe(title), ) oembed_response = dict( _OEMBED_BASE, type="rich", title=title, author_name=author_name, html=html, ) if author_name: oembed_response['author_url'] = make_url_https('/user/' + author_name) return oembed_response
def tag_cloud_for_subreddits(cls, sr_ids): from r2.lib.db import tdb_sql as tdb import sqlalchemy as sa type = tdb.rel_types_id[LinkTag._type_id] linktag_thing_table = type.rel_table[0] link_type = tdb.types_id[Link._type_id] link_data_table = link_type.data_table[0] link_thing_table = link_type.thing_table link_sr = sa.select([ link_data_table.c.thing_id, sa.cast(link_data_table.c.value, sa.INT).label('sr_id') ], link_data_table.c.key == 'sr_id').alias('link_sr') query = sa.select( [ linktag_thing_table.c.thing2_id, sa.func.count(linktag_thing_table.c.thing1_id) ], sa.and_( linktag_thing_table.c.thing1_id == link_sr.c.thing_id, linktag_thing_table.c.thing1_id == link_thing_table.c.thing_id, link_thing_table.c.spam == False, link_sr.c.sr_id.in_(*sr_ids)), group_by=[linktag_thing_table.c.thing2_id], having=sa.func.count(linktag_thing_table.c.thing1_id) > 1, order_by=sa.desc(sa.func.count(linktag_thing_table.c.thing1_id)), limit=100) rows = query.execute().fetchall() tags = [] for result in rows: tag = Tag._byID(result.thing2_id, data=True) tags.append((tag, result.count)) # Order by tag name tags.sort(key=lambda x: _force_unicode(x[0].name)) return cls.make_cloud(10, tags)
def __init__(self, link = None, comment = None, link_title = '', is_canonical = False, *a, **kw): link.render_full = True # TODO: temp hack until we find place for builder_wrapper from r2.controllers.listingcontroller import ListingController if comment: link_wrapper = lambda link: self.comment_permalink_wrapper(comment, link) else: link_wrapper = ListingController.builder_wrapper link_builder = IDBuilder(link._fullname, wrap = link_wrapper) # link_listing will be the one-element listing at the top self.link_listing = LinkListing(link_builder, nextprev=False).listing() # link is a wrapped Link object self.link = self.link_listing.things[0] link_title = ((self.link.title) if hasattr(self.link, 'title') else '') if comment: title = comment.make_permalink_title(link) # Comment permalinks should not be indexed, there's too many of them self.robots = 'noindex' if is_canonical == False: self.canonical_link = comment.make_permalink(link) else: params = {'title':_force_unicode(link_title), 'site' : c.site.title} title = strings.link_info_title % params if not (c.default_sr and is_canonical): # Not on the main page, so include a pointer to the canonical URL for this link self.canonical_link = link.canonical_url Reddit.__init__(self, title = title, body_class = 'post', robots = self.robots, *a, **kw)
def wrap_items(self, items): from r2.lib.db import queries from r2.lib.template_helpers import add_attr user = c.user if c.user_is_loggedin else None #get authors #TODO pull the author stuff into add_props for links and #comments and messages? aids = set(l.author_id for l in items if hasattr(l, 'author_id') and l.author_id is not None) authors = {} cakes = {} friend_rels = None if aids: authors = Account._byID(aids, data=True, stale=self.stale) if aids else {} now = datetime.datetime.now(g.tz) cakes = { a._id for a in authors.itervalues() if a.cake_expiration and a.cake_expiration >= now } if user and user.gold: friend_rels = user.friend_rels() subreddits = Subreddit.load_subreddits(items, stale=self.stale) can_ban_set = set() can_flair_set = set() can_own_flair_set = set() if user: for sr_id, sr in subreddits.iteritems(): if sr.can_ban(user): can_ban_set.add(sr_id) if sr.is_moderator_with_perms(user, 'flair'): can_flair_set.add(sr_id) if sr.link_flair_self_assign_enabled: can_own_flair_set.add(sr_id) #get likes/dislikes try: likes = queries.get_likes(user, items) except tdb_cassandra.TRANSIENT_EXCEPTIONS as e: g.log.warning("Cassandra vote lookup failed: %r", e) likes = {} uid = user._id if user else None types = {} wrapped = [] modlink = {} modlabel = {} for s in subreddits.values(): modlink[s._id] = '/r/%s/about/moderators' % s.name modlabel[s._id] = ( _('moderator of /r/%(reddit)s, speaking officially') % dict(reddit=s.name)) for item in items: w = self.wrap(item) wrapped.append(w) # add for caching (plus it should be bad form to use _ # variables in templates) w.fullname = item._fullname types.setdefault(w.render_class, []).append(w) #TODO pull the author stuff into add_props for links and #comments and messages? w.author = None w.friend = False # List of tuples (see add_attr() for details) w.attribs = [] w.distinguished = None if hasattr(item, "distinguished"): if item.distinguished == 'yes': w.distinguished = 'moderator' elif item.distinguished in ('admin', 'special', 'gold', 'gold-auto'): w.distinguished = item.distinguished try: w.author = authors.get(item.author_id) if user and item.author_id in user.friends: # deprecated old way: w.friend = True # new way: label = None if friend_rels: rel = friend_rels[item.author_id] note = getattr(rel, "note", None) if note: label = u"%s (%s)" % (_("friend"), _force_unicode(note)) add_attr(w.attribs, 'F', label) except AttributeError: pass if (w.distinguished == 'admin' and w.author): add_attr(w.attribs, 'A') if w.distinguished == 'moderator': add_attr(w.attribs, 'M', label=modlabel[item.sr_id], link=modlink[item.sr_id]) if w.distinguished == 'special': args = w.author.special_distinguish() args.pop('name') if not args.get('kind'): args['kind'] = 'special' add_attr(w.attribs, **args) if w.author and w.author._id in cakes and not c.profilepage: add_attr( w.attribs, kind="cake", label=(_("%(user)s just celebrated a reddit birthday!") % { "user": w.author.name }), link="/user/%s" % w.author.name, ) if hasattr(item, "sr_id") and item.sr_id is not None: w.subreddit = subreddits[item.sr_id] w.likes = likes.get((user, item)) # update vote tallies compute_votes(w, item) w.score = w.upvotes - w.downvotes if w.likes: base_score = w.score - 1 elif w.likes is None: base_score = w.score else: base_score = w.score + 1 # store the set of available scores based on the vote # for ease of i18n when there is a label w.voting_score = [(base_score + x - 1) for x in range(3)] w.deleted = item._deleted w.link_notes = [] if c.user_is_admin: if item._deleted: w.link_notes.append("deleted link") if getattr(item, "verdict", None): if not item.verdict.endswith("-approved"): w.link_notes.append(w.verdict) if c.user_is_admin and getattr(item, 'ip', None): w.ip_span = ip_span(item.ip) else: w.ip_span = "" # if the user can ban things on a given subreddit, or an # admin, then allow them to see that the item is spam, and # add the other spam-related display attributes w.show_reports = False w.show_spam = False w.can_ban = False w.can_flair = False w.use_big_modbuttons = self.spam_listing if (c.user_is_admin or (user and hasattr(item, 'sr_id') and item.sr_id in can_ban_set)): if getattr(item, "promoted", None) is None: w.can_ban = True ban_info = getattr(item, 'ban_info', {}) w.unbanner = ban_info.get('unbanner') if item._spam: w.show_spam = True w.moderator_banned = ban_info.get('moderator_banned', False) w.autobanned = ban_info.get('auto', False) w.banner = ban_info.get('banner') if ban_info.get('note', None) and w.banner: w.banner += ' (%s)' % ban_info['note'] w.use_big_modbuttons = True if getattr(w, "author", None) and w.author._spam: w.show_spam = "author" if c.user == w.author and c.user._spam: w.show_spam = False w._spam = False w.use_big_modbuttons = False elif (getattr(item, 'reported', 0) > 0 and (not getattr(item, 'ignore_reports', False) or c.user_is_admin)): w.show_reports = True w.use_big_modbuttons = True if (c.user_is_admin or (user and hasattr(item, 'sr_id') and (item.sr_id in can_flair_set or (w.author and w.author._id == user._id and item.sr_id in can_own_flair_set)))): w.can_flair = True w.approval_checkmark = None if w.can_ban: verdict = getattr(w, "verdict", None) if verdict in ('admin-approved', 'mod-approved'): approver = None approval_time = None baninfo = getattr(w, "ban_info", None) if baninfo: approver = baninfo.get("unbanner", None) approval_time = baninfo.get("unbanned_at", None) approver = approver or _("a moderator") if approval_time: text = _("approved by %(who)s %(when)s ago") % { "who": approver, "when": timesince(approval_time) } else: text = _("approved by %s") % approver w.approval_checkmark = text # recache the user object: it may be None if user is not logged in, # whereas now we are happy to have the UnloggedUser object user = c.user for cls in types.keys(): cls.add_props(user, types[cls]) return wrapped
def GET_comments(self, article, comment, context, sort, num_comments): """Comment page for a given 'article'.""" if comment and comment.link_id != article._id: return self.abort404() if not c.default_sr and c.site._id != article.sr_id: return self.redirect(article.make_permalink_slow(), 301) # moderator is either reddit's moderator or an admin is_moderator = c.user_is_loggedin and c.site.is_moderator( c.user) or c.user_is_admin if article._spam and not is_moderator: return self.abort404() if not article.subreddit_slow.can_view(c.user): abort(403, 'forbidden') #check for 304 self.check_modified(article, 'comments') # if there is a focal comment, communicate down to comment_skeleton.html who # that will be if comment: c.focal_comment = comment._id36 # check if we just came from the submit page infotext = None if request.get.get('already_submitted'): infotext = strings.already_submitted % article.resubmit_link() check_cheating('comments') # figure out number to show based on the menu user_num = c.user.pref_num_comments or g.num_comments num = g.max_comments if num_comments == 'true' else user_num # Override sort if the link has a default set if hasattr(article, 'comment_sort_order'): sort = article.comment_sort_order builder = CommentBuilder(article, CommentSortMenu.operator(sort), comment, context) listing = NestedListing(builder, num=num, parent_name=article._fullname) displayPane = PaneStack() # if permalink page, add that message first to the content if comment: permamessage = PermalinkMessage(comment.make_anchored_permalink( context=context + 1 if context else 1, anchor='comments'), has_more_comments=hasattr( comment, 'parent_id')) displayPane.append(permamessage) # insert reply box only for logged in user if c.user_is_loggedin and article.subreddit_slow.can_comment(c.user): displayPane.append(CommentReplyBox()) #no comment box for permalinks if not comment: displayPane.append( CommentReplyBox(link_name=article._fullname)) # finally add the comment listing displayPane.append(listing.listing()) loc = None if c.focal_comment or context is not None else 'comments' if article.comments_enabled: sort_menu = CommentSortMenu(default=sort, type='dropdown2') if hasattr(article, 'comment_sort_order'): sort_menu.enabled = False nav_menus = [ sort_menu, NumCommentsMenu(article.num_comments, default=num_comments) ] content = CommentListing( content=displayPane, num_comments=article.num_comments, nav_menus=nav_menus, ) else: content = PaneStack() is_canonical = article.canonical_url.endswith( _force_unicode(request.path)) and not request.GET res = LinkInfoPage(link=article, comment=comment, content=content, infotext=infotext, is_canonical=is_canonical).render() if c.user_is_loggedin: article._click(c.user) return res