mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-14 09:27:57 -05:00
Create quarantined subreddits content gate
When a user visits a quarantined subreddit for the first time, they are presented with a content gate so that they can choose to optin to view the subreddit's content. This preference is remembered per subreddit. If a user is logged out, it requires the user to log in before validating that the user has chosen to opt in to view the subreddit.
This commit is contained in:
committed by
Florence Yeun
parent
48e6429f7e
commit
ae1296cf87
@@ -70,6 +70,7 @@ def make_map():
|
||||
mc('/submit', controller='front', action='submit')
|
||||
|
||||
mc('/over18', controller='post', action='over18')
|
||||
mc('/quarantine', controller='post', action='quarantine')
|
||||
|
||||
mc('/rules', controller='front', action='rules')
|
||||
mc('/sup', controller='front', action='sup')
|
||||
|
||||
@@ -81,6 +81,16 @@ class PostController(ApiController):
|
||||
return BoringPage(_("over 18?"), content=Over18(),
|
||||
show_sidebar=False).render()
|
||||
|
||||
@validate(
|
||||
dest=VDestination(default='/'),
|
||||
)
|
||||
def GET_quarantine(self, dest):
|
||||
sr = UrlParser(dest).get_subreddit()
|
||||
return BoringPage(_("opt in to potentially offensive content?"),
|
||||
content=Quarantine(sr.name),
|
||||
show_sidebar=False,
|
||||
).render()
|
||||
|
||||
@validate(VModhash(fatal=False),
|
||||
over18 = nop('over18'),
|
||||
dest = VDestination(default = '/'))
|
||||
@@ -100,6 +110,23 @@ class PostController(ApiController):
|
||||
delete_over18_cookie()
|
||||
return self.redirect('/')
|
||||
|
||||
@validate(
|
||||
VModhash(),
|
||||
sr=VSRByName('sr_name'),
|
||||
accept=VBoolean('accept'),
|
||||
dest=VDestination(default='/'),
|
||||
)
|
||||
def POST_quarantine(self, sr, accept, dest):
|
||||
if not c.user_is_loggedin:
|
||||
return self.redirect(dest)
|
||||
|
||||
if accept:
|
||||
QuarantinedSubredditOptInsByAccount.opt_in(c.user, sr)
|
||||
return self.redirect(dest)
|
||||
else:
|
||||
QuarantinedSubredditOptInsByAccount.opt_out(c.user, sr)
|
||||
return self.redirect('/')
|
||||
|
||||
@csrf_exempt
|
||||
@validate(msg_hash = nop('x'))
|
||||
def POST_optout(self, msg_hash):
|
||||
|
||||
@@ -1668,13 +1668,11 @@ class RedditController(OAuth2ResourceController):
|
||||
# do not leak the existence of multis via 403.
|
||||
self.abort404()
|
||||
elif not c.site.is_exposed(c.user):
|
||||
errpage = pages.RedditError(
|
||||
strings.quarantine_subreddit_title,
|
||||
strings.quarantine_subreddit_message,
|
||||
image="subreddit-banned.png",
|
||||
)
|
||||
request.environ['usable_error_content'] = errpage.render()
|
||||
self.abort403()
|
||||
if not c.user_is_loggedin:
|
||||
return self.intermediate_redirect('/login', sr_path=False)
|
||||
else:
|
||||
return self.intermediate_redirect("/quarantine", sr_path=False)
|
||||
|
||||
elif c.site.type == 'gold_only' and not (c.user.gold or c.user.gold_charter):
|
||||
public_description = c.site.public_description
|
||||
errpage = pages.RedditError(
|
||||
|
||||
@@ -2457,6 +2457,13 @@ class Over18(Templated):
|
||||
"""The creepy 'over 18' check page for nsfw content."""
|
||||
pass
|
||||
|
||||
|
||||
class Quarantine(Templated):
|
||||
"""The opt in page for viewing quarantined content."""
|
||||
def __init__(self, sr_name):
|
||||
Templated.__init__(self, sr_name=sr_name)
|
||||
|
||||
|
||||
class SubredditTopBar(CachedTemplate):
|
||||
|
||||
"""The horizontal strip at the top of most pages for navigating
|
||||
|
||||
@@ -1076,3 +1076,33 @@ class SubredditParticipationByAccount(tdb_cassandra.DenormalizedRelation):
|
||||
@classmethod
|
||||
def mark_participated(cls, account, subreddit):
|
||||
cls.create(account, [subreddit])
|
||||
|
||||
|
||||
class QuarantinedSubredditOptInsByAccount(tdb_cassandra.DenormalizedRelation):
|
||||
_use_db = True
|
||||
_last_modified_name = 'QuarantineSubredditOptin'
|
||||
_read_consistency_level = tdb_cassandra.CL.QUORUM
|
||||
_write_consistency_level = tdb_cassandra.CL.QUORUM
|
||||
_connection_pool = 'main'
|
||||
_views = []
|
||||
|
||||
@classmethod
|
||||
def value_for(cls, thing1, thing2):
|
||||
return datetime.now(g.tz)
|
||||
|
||||
@classmethod
|
||||
def opt_in(cls, account, subreddit):
|
||||
if subreddit.quarantine:
|
||||
cls.create(account, subreddit)
|
||||
|
||||
@classmethod
|
||||
def opt_out(cls, account, subreddit):
|
||||
cls.destroy(account, subreddit)
|
||||
|
||||
@classmethod
|
||||
def is_opted_in(cls, user, subreddit):
|
||||
try:
|
||||
r = cls.fast_query(user, [subreddit])
|
||||
except tdb_cassandra.NotFound:
|
||||
return False
|
||||
return (user, subreddit) in r
|
||||
|
||||
@@ -37,7 +37,12 @@ from pylons import c, g, request
|
||||
from pylons.i18n import _, N_
|
||||
|
||||
from r2.lib.db.thing import Thing, Relation, NotFound
|
||||
from account import Account, AccountsActiveBySR, FakeAccount
|
||||
from account import (
|
||||
Account,
|
||||
AccountsActiveBySR,
|
||||
FakeAccount,
|
||||
QuarantinedSubredditOptInsByAccount,
|
||||
)
|
||||
from printable import Printable
|
||||
from r2.lib.db.userrel import UserRel, MigratingUserRel
|
||||
from r2.lib.db.operators import lower, or_, and_, not_, desc
|
||||
@@ -793,7 +798,7 @@ class Subreddit(Thing, Printable, BaseSite):
|
||||
def can_view(self, user):
|
||||
if c.user_is_admin:
|
||||
return True
|
||||
|
||||
|
||||
if self.spammy() or not self.is_exposed(user):
|
||||
return False
|
||||
elif self.type in ('public', 'restricted',
|
||||
@@ -811,9 +816,15 @@ class Subreddit(Thing, Printable, BaseSite):
|
||||
self.is_moderator_invite(user))
|
||||
|
||||
def is_exposed(self, user):
|
||||
"""Checks if visible to user based on the quarantine attribute."""
|
||||
return not self.quarantine or (c.user_is_loggedin and
|
||||
self.is_subscriber(user))
|
||||
if c.user_is_admin:
|
||||
return True
|
||||
elif not self.quarantine:
|
||||
return True
|
||||
elif (c.user_is_loggedin and
|
||||
QuarantinedSubredditOptInsByAccount.is_opted_in(user, self)):
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def can_demod(self, bully, victim):
|
||||
bully_rel = self.get_moderator(bully)
|
||||
|
||||
44
r2/r2/templates/quarantine.html
Normal file
44
r2/r2/templates/quarantine.html
Normal file
@@ -0,0 +1,44 @@
|
||||
## The contents of this file are subject to the Common Public Attribution
|
||||
## License Version 1.0. (the "License"); you may not use this file except in
|
||||
## compliance with the License. You may obtain a copy of the License at
|
||||
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
|
||||
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
|
||||
## software over a computer network and provide for limited attribution for the
|
||||
## Original Developer. In addition, Exhibit A has been modified to be
|
||||
## consistent with Exhibit B.
|
||||
##
|
||||
## Software distributed under the License is distributed on an "AS IS" basis,
|
||||
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
||||
## the specific language governing rights and limitations under the License.
|
||||
##
|
||||
## The Original Code is reddit.
|
||||
##
|
||||
## The Original Developer is the Initial Developer. The Initial Developer of
|
||||
## the Original Code is reddit Inc.
|
||||
##
|
||||
## All portions of the code written by reddit are Copyright (c) 2006-2015
|
||||
## reddit Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
<% from r2.lib.template_helpers import static %>
|
||||
|
||||
<div class="content over18" style="text-align: center">
|
||||
<p class="error">
|
||||
${_("the following content is questionable")}
|
||||
</p>
|
||||
<img src="${static('over18.png')}" alt="" height="254" width="180" />
|
||||
|
||||
<form method="post" action="" class="pretty-form"
|
||||
${"target='_top'" if c.cname else ""}>
|
||||
<input type="hidden" name="uh" value="${c.modhash}" />
|
||||
<input type="hidden" name="sr_name" value="${thing.sr_name}" />
|
||||
<p>
|
||||
${_("are you willing to see this questionable content?")}
|
||||
</p>
|
||||
<p>
|
||||
<button type="submit" name="accept" value="yes">yes</button>
|
||||
<button type="submit" name="accept" value="no">no</button>
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user