diff --git a/r2/r2/controllers/api.py b/r2/r2/controllers/api.py index a9521aea4..95091bada 100755 --- a/r2/r2/controllers/api.py +++ b/r2/r2/controllers/api.py @@ -1748,6 +1748,7 @@ class ApiController(RedditController, OAuth2ResourceController): show_cname_sidebar = VBoolean('show_cname_sidebar'), type = VOneOf('type', ('public', 'private', 'restricted', 'gold_restricted', 'archived')), link_type = VOneOf('link_type', ('any', 'link', 'self')), + sticky_permalink=VUrl('sticky_permalink'), submit_link_label=VLength('submit_link_label', max_length=60), submit_text_label=VLength('submit_text_label', max_length=60), comment_score_hide_mins=VInt('comment_score_hide_mins', @@ -1794,7 +1795,8 @@ class ApiController(RedditController, OAuth2ResourceController): if k in ('name', 'title', 'domain', 'description', 'show_media', 'exclude_banned_modqueue', 'show_cname_sidebar', 'type', 'public_traffic', - 'link_type', 'submit_link_label', 'comment_score_hide_mins', + 'link_type', 'sticky_permalink', + 'submit_link_label', 'comment_score_hide_mins', 'submit_text_label', 'lang', 'css_on_cname', 'header_title', 'over_18', 'wikimode', 'wiki_edit_karma', 'wiki_edit_age', 'allow_top', 'public_description')) @@ -1841,6 +1843,17 @@ class ApiController(RedditController, OAuth2ResourceController): if cname_sr and (not sr or sr != cname_sr): c.errors.add(errors.USED_CNAME) + sticky_fullname = None + if kw['sticky_permalink']: + sticky_url = UrlParser(kw['sticky_permalink']).path + if sticky_url: + try: + sticky_fullname = Link._by_url(sticky_url, sr)._fullname + except NotFound: + c.errors.add(errors.BAD_URL, field='sticky_permalink') + else: + c.errors.add(errors.BAD_URL, field='sticky_permalink') + can_set_archived = c.user_is_admin or (sr and sr.type == 'archived') if kw['type'] == 'archived' and not can_set_archived: c.errors.add(errors.INVALID_OPTION, field='type') @@ -1869,6 +1882,8 @@ class ApiController(RedditController, OAuth2ResourceController): elif (form.has_errors(('wiki_edit_karma', 'wiki_edit_age'), errors.BAD_NUMBER)): pass + elif form.has_errors('sticky_permalink', errors.BAD_URL): + pass elif form.has_errors('comment_score_hide_mins', errors.BAD_NUMBER): pass #creating a new reddit @@ -1902,6 +1917,8 @@ class ApiController(RedditController, OAuth2ResourceController): success = update_wiki_text(sr) + sr.sticky_fullname = sticky_fullname + if not sr.domain: del kw['css_on_cname'] for k, v in kw.iteritems(): diff --git a/r2/r2/controllers/listingcontroller.py b/r2/r2/controllers/listingcontroller.py index 9ea0a5ecf..68ce09671 100755 --- a/r2/r2/controllers/listingcontroller.py +++ b/r2/r2/controllers/listingcontroller.py @@ -358,6 +358,21 @@ class HotController(FixListing, ListingController): elif isinstance(c.site, MultiReddit): return normalized_hot(c.site.kept_sr_ids, obey_age_limit=False) else: + if c.site.sticky_fullname: + link_list = [c.site.sticky_fullname] + wrapped = wrap_links(link_list, + wrapper=self.builder_wrapper, + keep_fn=self.keep_fn(), + skip=True) + # add all other items and decrement count if sticky is visible + if wrapped.things: + link_list += [l for l in c.site.get_links('hot', 'all') + if l != c.site.sticky_fullname] + if not self.after: + self.count -= 1 + return link_list + + # no sticky or sticky hidden return c.site.get_links('hot', 'all') def content(self): diff --git a/r2/r2/lib/jsontemplates.py b/r2/r2/lib/jsontemplates.py index 265c97b5e..8bbff9a5a 100755 --- a/r2/r2/lib/jsontemplates.py +++ b/r2/r2/lib/jsontemplates.py @@ -371,7 +371,8 @@ class LinkJsonTemplate(ThingJsonTemplate): subreddit_id = "subreddit_id", is_self = "is_self", permalink = "permalink", - edited = "editted" + edited = "editted", + stickied = "stickied", ) def thing_attr(self, thing, attr): diff --git a/r2/r2/models/link.py b/r2/r2/models/link.py index b047c1ef3..11dd59357 100755 --- a/r2/r2/models/link.py +++ b/r2/r2/models/link.py @@ -242,13 +242,24 @@ class Link(Thing, Printable): #return False if user and not c.ignore_hide_rules: - if user.pref_hide_ups and wrapped.likes == True and self.author_id != user._id: + # whether the user must deliberately hide the item + # (not automatic due to score or having upvoted/downvoted it) + require_explicit_hide = wrapped.stickied + + if (user.pref_hide_ups and + wrapped.likes == True and + self.author_id != user._id and + not require_explicit_hide): return False - if user.pref_hide_downs and wrapped.likes == False and self.author_id != user._id: + if (user.pref_hide_downs and + wrapped.likes == False and + self.author_id != user._id and + not require_explicit_hide): return False - if wrapped._score < user.pref_min_link_score: + if (wrapped._score < user.pref_min_link_score and + not require_explicit_hide): return False if wrapped.hidden: @@ -483,6 +494,8 @@ class Link(Thing, Printable): # is this link a member of a different (non-c.site) subreddit? item.different_sr = (isinstance(site, FakeSubreddit) or site.name != item.subreddit.name) + item.stickied = (not item.different_sr and + site.sticky_fullname == item._fullname) if user_is_loggedin and item.author_id == user._id: item.nofollow = False diff --git a/r2/r2/models/subreddit.py b/r2/r2/models/subreddit.py index 429ffe6e8..76ca78966 100644 --- a/r2/r2/models/subreddit.py +++ b/r2/r2/models/subreddit.py @@ -206,6 +206,8 @@ class Subreddit(Thing, Printable, BaseSite): mod_actions=0, # do we allow self-posts, links only, or any? link_type='any', # one of ('link', 'self', 'any') + sticky_permalink=None, + sticky_fullname=None, submit_link_label='', submit_text_label='', comment_score_hide_mins=0, diff --git a/r2/r2/public/static/css/compact.css b/r2/r2/public/static/css/compact.css index 8dd30c2c1..3f5eaffb9 100644 --- a/r2/r2/public/static/css/compact.css +++ b/r2/r2/public/static/css/compact.css @@ -196,6 +196,8 @@ body[orient="landscape"] > #topbar > h1 { margin-left: -125px; width: 250px; } .link p.title > a { text-overflow: ellipsis; overflow: hidden; color: #25A; } +.link.stickied p.title > a { color: #228822; } + .link .domain { color: #737373; font-size: 9px; margin-left: 5px; } .link .domain a, .link .domain a:hover { color: inherit; } @@ -205,6 +207,8 @@ body[orient="landscape"] > #topbar > h1 { margin-left: -125px; width: 250px; } .link .tagline a { font-weight: bold; } +.link .tagline .stickied-tagline { color: #228822; } + /*Expando*/ .link .expando-button { float: left; display: block; height: auto; line-height: inherit; margin: 3px 10px 2px 0; width: 30px; height: 30px; background-image: url("../compact/selftext.png"); /*SPRITE*/ } .link .expando-button.expanded { background-image: url("../compact/selftext-active.png"); /*SPRITE*/ } diff --git a/r2/r2/public/static/css/compact.scss b/r2/r2/public/static/css/compact.scss index c4cd074c2..fa42d9857 100644 --- a/r2/r2/public/static/css/compact.scss +++ b/r2/r2/public/static/css/compact.scss @@ -621,6 +621,9 @@ body[orient="landscape"] > #topbar > h1 { text-overflow: ellipsis; overflow: hidden; color: #25A; } +.link.stickied p.title > a { + color: #228822; +} .link .domain { color: hsl(0,0%,45%); @@ -652,6 +655,10 @@ body[orient="landscape"] > #topbar > h1 { font-weight: bold; } +.link .tagline .stickied-tagline { + color: #228822; +} + /*Expando*/ .link .expando-button { float: left; diff --git a/r2/r2/public/static/css/reddit.less b/r2/r2/public/static/css/reddit.less index 1729af670..73d875de8 100755 --- a/r2/r2/public/static/css/reddit.less +++ b/r2/r2/public/static/css/reddit.less @@ -744,16 +744,19 @@ ul.flat-vert {text-align: left;} font-size:x-small; } +@moderator-color: #228822; + .tagline { color:#888; font-size:x-small; } .tagline a {color: #369; text-decoration: none; } .tagline .friend { color: orangered } .tagline .submitter { color: #0055df } -.tagline .moderator, .green { color: #228822 } +.tagline .moderator, .green { color: @moderator-color } .tagline .admin { color: #ff0011; } .tagline .alum { color: #BE1337; } .tagline a.author.admin { font-weight: bold } .tagline a:hover { text-decoration: underline } .tagline .edited-timestamp{ cursor: default } +.tagline .stickied-tagline { color: @moderator-color } a.author { margin-right: 0.5em; } @@ -930,6 +933,16 @@ a.author { margin-right: 0.5em; } .thing .title.loggedin.click { color: #551a8b } .thing .title.loggedin.click:visited { color: #551a8b } +.stickied-link { font-weight: bold; color: @moderator-color; } +.thing.stickied { + a.title { .stickied-link } + a.title:visited { .stickied-link } + a.title.loggedin { .stickied-link } + a.title.loggedin:visited { .stickied-link } + a.title.loggedin.click { .stickied-link } + a.title.loggedin.click:visited { .stickied-link } +} + .sitetable { list-style-type: none; } .ajaxhook { position: absolute; top: -1000px; left: 0px; } .nextprev { color: gray; font-size: larger; margin-top: 10px;} diff --git a/r2/r2/templates/createsubreddit.html b/r2/r2/templates/createsubreddit.html index 1c997ceda..d9154ccdd 100644 --- a/r2/r2/templates/createsubreddit.html +++ b/r2/r2/templates/createsubreddit.html @@ -275,6 +275,15 @@
+
+ + + ${error_field("BAD_URL", "sticky_permalink")} +
%if thing.site: diff --git a/r2/r2/templates/link.compact b/r2/r2/templates/link.compact index 579dae0c7..455f4f0a7 100644 --- a/r2/r2/templates/link.compact +++ b/r2/r2/templates/link.compact @@ -39,9 +39,16 @@ %endif -