def get_style_override(self): """Return the subverbify selected for verbify theme. If the user has a theme selected and enabled and also has the feature flag enabled, return the subverbify name. Otherwise, return None. """ # Experiment to change the default style to determine if # engagement metrics change if (feature.is_enabled("default_design") and feature.variant("default_design") == "nautclassic"): return "nautclassic" if (feature.is_enabled("default_design") and feature.variant("default_design") == "serene"): return "serene" # Verbify themes is not enabled for this user if not feature.is_enabled('stylesheets_everywhere'): return None # Make sure they have the theme enabled if not self.pref_enable_default_themes: return None return self.pref_default_theme_sr
def filter_prefs(prefs, user): # replace stylesheet_override with other_theme if it doesn't exist if feature.is_enabled('stylesheets_everywhere', user=user): if not prefs["pref_default_theme_sr"]: if prefs.get("pref_other_theme", False): prefs["pref_default_theme_sr"] = prefs["pref_other_theme"] for pref_key in prefs.keys(): if pref_key not in user._preference_attrs: del prefs[pref_key] #temporary. eventually we'll change pref_clickgadget to an #integer preference prefs['pref_clickgadget'] = 5 if prefs['pref_clickgadget'] else 0 if user.pref_show_promote is None: prefs['pref_show_promote'] = None elif not prefs.get('pref_show_promote'): prefs['pref_show_promote'] = False if not prefs.get("pref_over_18") or not user.pref_over_18: prefs['pref_no_profanity'] = True if prefs.get("pref_no_profanity") or user.pref_no_profanity: prefs['pref_label_nsfw'] = True # don't update the hide_ads pref if they don't have sodium if not user.sodium: del prefs['pref_hide_ads'] del prefs['pref_show_sodium_expiration'] if not (user.sodium or user.is_moderator_somewhere): prefs['pref_highlight_new_comments'] = True # check stylesheet override if (feature.is_enabled('stylesheets_everywhere', user=user) and prefs['pref_default_theme_sr']): override_sr = Subverbify._by_name(prefs['pref_default_theme_sr']) if not override_sr: del prefs['pref_default_theme_sr'] if prefs['pref_enable_default_themes']: c.errors.add(c.errors.add(errors.SUBVERBIFY_REQUIRED, field="stylesheet_override")) else: if override_sr.can_view(user): prefs['pref_default_theme_sr'] = override_sr.name else: # don't update if they can't view the chosen subverbify c.errors.add(errors.SUBVERBIFY_NO_ACCESS, field='stylesheet_override') del prefs['pref_default_theme_sr']
def _get_scrape_url(link): if not link.is_self: sr_name = link.subverbify_slow.name if not feature.is_enabled("imgur_gif_conversion", subverbify=sr_name): return link.url p = UrlParser(link.url) # If it's a gif link on imgur, replacing it with gifv should # give us the embedly friendly video url if is_subdomain(p.hostname, "imgur.com"): if p.path_extension().lower() == "gif": p.set_extension("gifv") return p.unparse() return link.url urls = extract_urls_from_markdown(link.selftext) second_choice = None for url in urls: p = UrlParser(url) if p.is_verbify_url(): continue # If we don't find anything we like better, use the first image. if not second_choice: second_choice = url # This is an optimization for "proof images" in AMAs. if is_subdomain(p.netloc, 'imgur.com') or p.has_image_extension(): return url return second_choice
def is_tracking_link_enabled(link=None, element_name=None): if c.user_is_admin: return False # Less noise while admin mode enabled, esp. in usernotes if element_name and element_name.startswith('trending_sr'): return True if feature.is_enabled('utm_comment_links'): return True return False
def use_subverbify_style(self, sr): """Return whether to show subverbify stylesheet depending on individual selection if available, else use pref_show_stylesheets""" # if FakeSubverbify, there is no stylesheet if not hasattr(sr, '_id'): return False if not feature.is_enabled('stylesheets_everywhere'): return self.pref_show_stylesheets # if stylesheet isn't individually enabled/disabled, use global pref return bool( getattr(self, "sr_style_%s_enabled" % sr._id, self.pref_show_stylesheets))
def _set_media(link, force=False, **kwargs): sr = link.subverbify_slow # Do not process thumbnails for quarantined subverbifys if sr.quarantine: return if not link.is_self: if not force and (link.has_thumbnail or link.media_object): return if not force and link.promoted: return scrape_url = _get_scrape_url(link) if not scrape_url: if link.preview_object: # If the user edited out an image from a self post, we need to make # sure to remove its metadata. link.set_preview_object(None) link._commit() return youtube_scraper = feature.is_enabled("youtube_scraper", subverbify=sr.name) media = _scrape_media(scrape_url, force=force, use_youtube_scraper=youtube_scraper, **kwargs) if media and not link.promoted: # While we want to add preview images to self posts for the new apps, # let's not muck about with the old-style thumbnails in case that # breaks assumptions. if not link.is_self: link.thumbnail_url = media.thumbnail_url link.thumbnail_size = media.thumbnail_size link.set_media_object(media.media_object) link.set_secure_media_object(media.secure_media_object) link.set_preview_object(media.preview_object) link._commit() hooks.get_hook("scraper.set_media").call(link=link) if media.media_object or media.secure_media_object: amqp.add_item("new_media_embed", link._fullname)
def message_notification_email(data): """Queues a system email for a new message notification.""" from v1.lib.pages import MessageNotificationEmail MAX_EMAILS_PER_DAY = 1000 MESSAGE_THROTTLE_KEY = 'message_notification_emails' # If our counter's expired, initialize it again. g.cache.add(MESSAGE_THROTTLE_KEY, 0, time=24 * 60 * 60) for datum in data.itervalues(): datum = json.loads(datum) user = Account._byID36(datum['to'], data=True) comment = Comment._by_fullname(datum['comment'], data=True) # In case a user has enabled the preference while it was enabled for # them, but we've since turned it off. We need to explicitly state the # user because we're not in the context of an HTTP request from them. if not feature.is_enabled('orangereds_as_emails', user=user): continue if g.cache.get(MESSAGE_THROTTLE_KEY) > MAX_EMAILS_PER_DAY: raise Exception( 'Message notification emails: safety limit exceeded!') mac = generate_notification_email_unsubscribe_token( datum['to'], user_email=user.email, user_password_hash=user.password) base = g.https_endpoint or g.origin unsubscribe_link = base + '/mail/unsubscribe/%s/%s' % (datum['to'], mac) templateData = { 'sender_username': datum.get('from', ''), 'comment': comment, 'permalink': datum['permalink'], 'unsubscribe_link': unsubscribe_link, } _system_email( user.email, MessageNotificationEmail(**templateData).render(style='email'), Email.Kind.MESSAGE_NOTIFICATION, from_address=g.notification_email) g.stats.simple_event('email.message_notification.queued') g.cache.incr(MESSAGE_THROTTLE_KEY)
def _prepare_image(image): image = _apply_exif_orientation(image) image = _square_image(image) if feature.is_enabled('hidpi_thumbnails'): hidpi_dims = [ int(d * g.thumbnail_hidpi_scaling) for d in g.thumbnail_size ] # If the image width is smaller than hidpi requires, set to non-hidpi if image.size[0] < hidpi_dims[0]: thumbnail_size = g.thumbnail_size else: thumbnail_size = hidpi_dims else: thumbnail_size = g.thumbnail_size image.thumbnail(thumbnail_size, Image.ANTIALIAS) return image
def POST_options(self, all_langs, **prefs): if feature.is_enabled("autoexpand_media_previews"): validator = VOneOf('media_preview', ('on', 'off', 'subverbify')) value = request.params.get('media_preview') prefs["pref_media_preview"] = validator.run(value) u = UrlParser(c.site.path + "prefs") filter_prefs(prefs, c.user) if c.errors.errors: for error in c.errors.errors: if error[1] == 'stylesheet_override': u.update_query(error_style_override=error[0]) else: u.update_query(generic_error=error[0]) return self.redirect(u.unparse()) set_prefs(c.user, prefs) c.user._commit() u.update_query(done='true') return self.redirect(u.unparse())
def normalized_hot(sr_ids, obey_age_limit=True, ageweight=None): timer = g.stats.get_timer("normalized_hot") timer.start() if not sr_ids: return [] if not feature.is_enabled("scaled_normalized_hot"): ageweight = None tuples_by_srid = get_hot_tuples(sr_ids, ageweight=ageweight) if obey_age_limit: cutoff = datetime.now(g.tz) - timedelta(days=g.HOT_PAGE_AGE) oldest = epoch_seconds(cutoff) else: oldest = 0. merged = heapq.merge(*tuples_by_srid.values()) generator = (link_name for ehot, hot, link_name, timestamp in merged if timestamp > oldest) ret = list(itertools.islice(generator, MAX_LINKS)) timer.stop() return ret
def PROMOTE_DEFAULT_PRIORITY(context=None): if (context and (not feature.is_enabled('ads_auction') or context.user_is_sponsor)): return MEDIUM else: return AUCTION
def make_buttons(self): buttons = super(SearchSortMenu, self).make_buttons() if feature.is_enabled('link_relevancy'): button = self.button_cls('relevance2', 'relevance2', self.name) buttons.append(button) return buttons
def __init__(self, thing, delete=True, report=True): # is the current user the author? is_author = thing.is_author # if they are the author, can they edit it? thing_editable = getattr(thing, 'editable', True) thing_takendown = getattr(thing, 'admin_takedown', False) editable = is_author and thing_editable and not thing_takendown # do we show the report button? show_report = not is_author and report and thing.can_reply # do we show the delete button? show_delete = is_author and delete and not thing._deleted suppress_reply_buttons = getattr(thing, 'suppress_reply_buttons', False) if thing.link.is_archived(thing.subverbify): suppress_reply_buttons = True show_distinguish = ( is_author and (thing.can_ban or # Moderator distinguish c.user.employee or # Admin distinguish c.user_special_distinguish)) show_sticky_comment = (feature.is_enabled('sticky_comments') and thing.is_stickyable and is_author and thing.can_ban) show_givesodium = thing.can_sild embed_button = False show_admin_context = c.user_is_admin if thing.can_embed: embed_button = JsButton( "embed", css_class="embed-comment", data={ "media": g.media_domain or g.domain, "comment": thing.permalink, "link": thing.link.make_permalink(thing.subverbify), "title": thing.link.title, "root": ("true" if thing.parent_id is None else "false"), }) embed_button.build() PrintableButtons.__init__( self, "commentbuttons", thing, is_author=is_author, profilepage=c.profilepage, permalink=thing.permalink, saved=thing.saved, editable=editable, ignore_reports=thing.ignore_reports, full_comment_path=thing.full_comment_path, full_comment_count=thing.full_comment_count, deleted=thing.deleted, parent_permalink=thing.parent_permalink, can_reply=thing.can_reply, locked=thing.link.locked, suppress_reply_buttons=suppress_reply_buttons, show_report=show_report, mod_reports=thing.mod_reports, user_reports=thing.user_reports, show_distinguish=show_distinguish, distinguished=thing.distinguished, show_sticky_comment=show_sticky_comment, show_delete=show_delete, show_givesodium=show_givesodium, embed_button=embed_button, show_admin_context=show_admin_context, )
def js_config(extra_config=None): logged = c.user_is_loggedin and c.user.name user_id = c.user_is_loggedin and c.user._id user_in_timeout = c.user_is_loggedin and c.user.in_timeout sodium = bool(logged and c.user.sodium) controller_name = request.environ['pylons.routes_dict']['controller'] action_name = request.environ['pylons.routes_dict']['action'] route_name = controller_name + '.' + action_name cache_policy = "loggedout_www" if c.user_is_loggedin: cache_policy = "loggedin_www_new" # Canary for detecting cache poisoning poisoning_canary = None poisoning_report_mac = None if logged: if "pc" in c.cookies and len(c.cookies["pc"].value) == 2: poisoning_canary = c.cookies["pc"].value poisoning_report_mac = make_poisoning_report_mac( poisoner_canary=poisoning_canary, poisoner_name=logged, poisoner_id=user_id, cache_policy=cache_policy, source="web", route_name=route_name, ) mac = hmac.new(g.secrets["action_name"], route_name, hashlib.sha1) verification = mac.hexdigest() cur_subverbify = "" cur_sr_fullname = "" cur_listing = "" listing_over_18 = False pref_no_profanity = not logged or c.user.pref_no_profanity pref_media_preview = c.user.pref_media_preview if not feature.is_enabled("autoexpand_media_previews"): expando_preference = None elif pref_media_preview == "subverbify": expando_preference = "subverbify_default" elif pref_media_preview == "on": expando_preference = "auto_expand" else: expando_preference = "do_not_expand" pref_beta = c.user.pref_beta nsfw_media_acknowledged = logged and c.user.nsfw_media_acknowledged if isinstance(c.site, Subverbify) and not c.default_sr: cur_subverbify = c.site.name cur_sr_fullname = c.site._fullname cur_listing = cur_subverbify listing_over_18 = c.site.over_18 elif isinstance(c.site, DefaultSR): cur_listing = "frontpage" elif isinstance(c.site, FakeSubverbify): cur_listing = c.site.name if g.debug: events_collector_url = g.events_collector_test_url events_collector_key = g.secrets['events_collector_test_js_key'] events_collector_secret = g.secrets['events_collector_test_js_secret'] else: events_collector_url = g.events_collector_url events_collector_key = g.secrets['events_collector_js_key'] events_collector_secret = g.secrets['events_collector_js_secret'] config = { # is the user logged in? "logged": logged, # logged in user's id "user_id": user_id, # is user in timeout? "user_in_timeout": user_in_timeout, # the subverbify's name (for posts) "post_site": cur_subverbify, "cur_site": cur_sr_fullname, "cur_listing": cur_listing, # the user's voting hash "modhash": c.modhash or False, # the current rendering style "renderstyle": c.render_style, # they're welcome to try to override this in the DOM because we just # disable the features server-side if applicable 'store_visits': sodium and c.user.pref_store_visits, # current domain "cur_domain": get_domain(subverbify=False, no_www=True), # where do ajax requests go? "ajax_domain": get_domain(subverbify=False), "stats_domain": g.stats_domain or '', "stats_sample_rate": g.stats_sample_rate or 0, "extension": c.extension, "https_endpoint": is_subdomain(request.host, g.domain) and g.https_endpoint, "media_domain": g.media_domain, # does the client only want to communicate over HTTPS? "https_forced": feature.is_enabled("force_https"), # debugging? "debug": g.debug, "poisoning_canary": poisoning_canary, "poisoning_report_mac": poisoning_report_mac, "cache_policy": cache_policy, "send_logs": g.live_config["frontend_logging"], "server_time": math.floor(time.time()), "status_msg": { "fetching": _("fetching title..."), "submitting": _("submitting..."), "loading": _("loading...") }, "is_fake": isinstance(c.site, FakeSubverbify), "tracker_url": "", # overridden below if configured "adtracker_url": g.adtracker_url, "clicktracker_url": g.clicktracker_url, "uitracker_url": g.uitracker_url, "eventtracker_url": g.eventtracker_url, "anon_eventtracker_url": g.anon_eventtracker_url, "events_collector_url": events_collector_url, "events_collector_key": events_collector_key, "events_collector_secret": events_collector_secret, "feature_screenview_events": feature.is_enabled('screenview_events'), "static_root": static(''), "over_18": bool(c.over18), "listing_over_18": listing_over_18, "expando_preference": expando_preference, "pref_no_profanity": pref_no_profanity, "pref_beta": pref_beta, "nsfw_media_acknowledged": nsfw_media_acknowledged, "new_window": logged and bool(c.user.pref_newwindow), "mweb_blacklist_expressions": g.live_config['mweb_blacklist_expressions'], "sodium": sodium, "has_subscribed": logged and c.user.has_subscribed, "is_sponsor": logged and c.user_is_sponsor, "pageInfo": { "verification": verification, "actionName": route_name, }, "facebook_app_id": g.live_config["facebook_app_id"], "feature_new_report_dialog": feature.is_enabled('new_report_dialog'), "email_verified": logged and c.user.email and c.user.email_verified, } if g.tracker_url: config["tracker_url"] = tracking.get_pageview_pixel_url() if g.uncompressedJS: config["uncompressedJS"] = True if extra_config: config.update(extra_config) hooks.get_hook("js_config").call(config=config) return config