mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-24 14:27:58 -05:00
/dev/api: Fully document the "subreddits" section.
This commit is contained in:
@@ -252,8 +252,16 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
queries.new_message(m, inbox_rel)
|
||||
|
||||
@json_validate()
|
||||
@api_doc(api_section.subreddits)
|
||||
@api_doc(api_section.subreddits, uses_site=True, extensions=["json"])
|
||||
def GET_submit_text(self, responder):
|
||||
"""Get the submission text for the subreddit.
|
||||
|
||||
This text is set by the subreddit moderators and intended to be
|
||||
displayed on the submission form.
|
||||
|
||||
See also: [/api/site_admin](#POST_api_site_admin).
|
||||
|
||||
"""
|
||||
if c.site.over_18 and not c.over18:
|
||||
submit_text = None
|
||||
submit_text_html = None
|
||||
@@ -903,7 +911,8 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
The authenticated user must have been invited to moderate the subreddit
|
||||
by one of its current moderators.
|
||||
|
||||
See also: [/api/friend](#POST_api_friend).
|
||||
See also: [/api/friend](#POST_api_friend) and
|
||||
[/subreddits/mine](#GET_subreddits_mine_{where}).
|
||||
|
||||
"""
|
||||
|
||||
@@ -1578,12 +1587,26 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
@validatedForm(VUser(),
|
||||
VModhash(),
|
||||
# nop is safe: handled after auth checks below
|
||||
stylesheet_contents = nop('stylesheet_contents'),
|
||||
prevstyle = VLength('prevstyle', max_length=36),
|
||||
stylesheet_contents=nop('stylesheet_contents',
|
||||
docs={"stylesheet_contents":
|
||||
"the new stylesheet content"}),
|
||||
prevstyle=VLength('prevstyle', max_length=36,
|
||||
docs={"prevstyle":
|
||||
"(optional) a revision ID"}),
|
||||
op = VOneOf('op',['save','preview']))
|
||||
@api_doc(api_section.subreddits, uses_site=True)
|
||||
def POST_subreddit_stylesheet(self, form, jquery,
|
||||
stylesheet_contents = '', prevstyle='', op='save'):
|
||||
"""Update a subreddit's stylesheet.
|
||||
|
||||
`op` should be `save` to update the contents of the stylesheet.
|
||||
|
||||
If `prevstyle` is specified, it should be the revision ID the submitted
|
||||
version is a modification of. Wiki-style edit conflict resolution will
|
||||
be done when this is specified, otherwise the content will be blindly
|
||||
overwritten.
|
||||
|
||||
"""
|
||||
|
||||
if form.has_errors("prevstyle", errors.TOO_LONG):
|
||||
return
|
||||
@@ -1681,10 +1704,16 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
name = VCssName('img_name'))
|
||||
@api_doc(api_section.subreddits, uses_site=True)
|
||||
def POST_delete_sr_img(self, form, jquery, name):
|
||||
"""
|
||||
Called upon requested delete on /about/stylesheet.
|
||||
Updates the site's image list, and causes the <li> which wraps
|
||||
the image to be hidden.
|
||||
"""Remove an image from the subreddit's custom image set.
|
||||
|
||||
The image will no longer count against the subreddit's image limit.
|
||||
However, the actual image data may still be accessible for an
|
||||
unspecified amount of time. If the image is currently referenced by the
|
||||
subreddit's stylesheet, that stylesheet will no longer validate and
|
||||
won't be editable until the image reference is removed.
|
||||
|
||||
See also: [/api/upload_sr_img](#POST_api_upload_sr_img).
|
||||
|
||||
"""
|
||||
# just in case we need to kill this feature from XSS
|
||||
if g.css_killswitch:
|
||||
@@ -1702,8 +1731,12 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
VModhash())
|
||||
@api_doc(api_section.subreddits, uses_site=True)
|
||||
def POST_delete_sr_header(self, form, jquery):
|
||||
"""
|
||||
Called when the user request that the header on a sr be reset.
|
||||
"""Remove the subreddit's custom header image.
|
||||
|
||||
The sitewide-default header image will be shown again after this call.
|
||||
|
||||
See also: [/api/upload_sr_img](#POST_api_upload_sr_img).
|
||||
|
||||
"""
|
||||
# just in case we need to kill this feature from XSS
|
||||
if g.css_killswitch:
|
||||
@@ -1740,24 +1773,32 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
file = VUploadLength('file', max_length=1024*500),
|
||||
name = VCssName("name"),
|
||||
img_type = VImageType('img_type'),
|
||||
form_id = VLength('formid', max_length = 100),
|
||||
form_id = VLength('formid', max_length = 100,
|
||||
docs={"formid": "(optional) can be ignored"}),
|
||||
header = VInt('header', max=1, min=0))
|
||||
@api_doc(api_section.subreddits, uses_site=True)
|
||||
def POST_upload_sr_img(self, file, header, name, form_id, img_type):
|
||||
"""
|
||||
Called on /about/stylesheet when an image needs to be replaced
|
||||
or uploaded, as well as on /about/edit for updating the
|
||||
header. Unlike every other POST in this controller, this
|
||||
method does not get called with Ajax but rather is from the
|
||||
original form POSTing to a hidden iFrame. Unfortunately, this
|
||||
means the response needs to generate an page with a script tag
|
||||
to fire the requisite updates to the parent document, and,
|
||||
more importantly, that we can't use our normal toolkit for
|
||||
passing those responses back.
|
||||
"""Add or replace a subreddit image or custom header logo.
|
||||
|
||||
If the `header` value is `0`, an image for use in the subreddit
|
||||
stylesheet is uploaded with the name specified in `name`. If the value
|
||||
of `header` is `1` then the image uploaded will be the subreddit's new
|
||||
logo and `name` will be ignored.
|
||||
|
||||
The `img_type` field specifies whether to store the uploaded image as a
|
||||
PNG or JPEG.
|
||||
|
||||
Subreddits have a limited number of images that can be in use at any
|
||||
given time. If no image with the specified name already exists, one of
|
||||
the slots will be consumed.
|
||||
|
||||
If an image with the specified name already exists, it will be
|
||||
replaced. This does not affect the stylesheet immediately, but will
|
||||
take effect the next time the stylesheet is saved.
|
||||
|
||||
See also: [/api/delete_sr_img](#POST_api_delete_sr_img) and
|
||||
[/api/delete_sr_header](#POST_api_delete_sr_header).
|
||||
|
||||
The result of this function is a rendered UploadedImage()
|
||||
object in charge of firing the completedUploadImage() call in
|
||||
JS.
|
||||
"""
|
||||
|
||||
# default error list (default values will reset the errors in
|
||||
@@ -1846,6 +1887,31 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
)
|
||||
@api_doc(api_section.subreddits)
|
||||
def POST_site_admin(self, form, jquery, name, ip, sr, **kw):
|
||||
"""Create or configure a subreddit.
|
||||
|
||||
If `sr` is specified, the request will attempt to modify the specified
|
||||
subreddit. If not, a subreddit with name `name` will be created.
|
||||
|
||||
This endpoint expects *all* values to be supplied on every request. If
|
||||
modifying a subset of options, it may be useful to get the current
|
||||
settings from [/about/edit.json](#GET_r_{subreddit}_about_edit.json)
|
||||
first.
|
||||
|
||||
The fields `prev_public_description_id`, `prev_description_id` and
|
||||
`prev_submit_text_id` are optional. If specified, they should be the
|
||||
wiki revision IDs of the last-seen versions of these pieces of text to
|
||||
allow for wiki-style edit conflict resolution.
|
||||
|
||||
For backwards compatibility, `description` is the sidebar text and
|
||||
`public_description` is the publicly visible subreddit description.
|
||||
|
||||
Most of the parameters for this endpoint are identical to options
|
||||
visible in the user interface and their meanings are best explained
|
||||
there.
|
||||
|
||||
See also: [/about/edit.json](#GET_r_{subreddit}_about_edit.json).
|
||||
|
||||
"""
|
||||
def apply_wikid_field(sr, form, pagename, value, prev, field, error):
|
||||
id_field_name = 'prev_%s_id' % field
|
||||
try:
|
||||
@@ -2677,6 +2743,15 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
sr = VSubscribeSR('sr', 'sr_name'))
|
||||
@api_doc(api_section.subreddits)
|
||||
def POST_subscribe(self, action, sr):
|
||||
"""Subscribe to or unsubscribe from a subreddit.
|
||||
|
||||
To subscribe, `action` should be `sub`. To unsubscribe, `action` should
|
||||
be `unsub`. The user must have access to the subreddit to be able to
|
||||
subscribe to it.
|
||||
|
||||
See also: [/subreddits/mine/](#GET_subreddits_mine_{where}).
|
||||
|
||||
"""
|
||||
# only users who can make edits are allowed to subscribe.
|
||||
# Anyone can leave.
|
||||
if sr and (action != 'sub' or sr.can_comment(c.user)):
|
||||
@@ -3382,6 +3457,7 @@ class ApiController(RedditController, OAuth2ResourceController):
|
||||
@json_validate(query=VLength("query", max_length=50))
|
||||
@api_doc(api_section.subreddits, extensions=["json"])
|
||||
def GET_subreddits_by_topic(self, responder, query):
|
||||
"""Return a list of subreddits that are relevant to a search query."""
|
||||
if not g.CLOUDSEARCH_SEARCH_API:
|
||||
return []
|
||||
|
||||
|
||||
@@ -752,8 +752,16 @@ class FrontController(RedditController, OAuth2ResourceController):
|
||||
@validate(location=nop('location'),
|
||||
created=VOneOf('created', ('true','false'),
|
||||
default='false'))
|
||||
@api_doc(api_section.subreddits, uri="/r/{subreddit}/about/edit",
|
||||
extensions=["json"])
|
||||
def GET_editreddit(self, location, created):
|
||||
"""Edit reddit form."""
|
||||
"""Get the current settings of a subreddit.
|
||||
|
||||
In the API, this returns the current settings of the subreddit as used
|
||||
by [/api/site_admin](#POST_api_site_admin). On the HTML site, it will
|
||||
display a form for editing the subreddit.
|
||||
|
||||
"""
|
||||
c.profilepage = True
|
||||
if isinstance(c.site, FakeSubreddit):
|
||||
return self.abort404()
|
||||
@@ -845,10 +853,10 @@ class FrontController(RedditController, OAuth2ResourceController):
|
||||
|
||||
|
||||
@base_listing
|
||||
@validate(query=nop('q'))
|
||||
@validate(query=nop('q', docs={"q": "a search query"}))
|
||||
@api_doc(api_section.subreddits, uri='/subreddits/search', extensions=['json', 'xml'])
|
||||
def GET_search_reddits(self, query, reverse, after, count, num):
|
||||
"""Search reddits by title and description."""
|
||||
"""Search subreddits by title and description."""
|
||||
q = SubredditSearchQuery(query)
|
||||
|
||||
results, etime, spane = self._search(q, num=num, reverse=reverse,
|
||||
|
||||
@@ -1023,8 +1023,16 @@ class RedditsController(ListingController):
|
||||
|
||||
@listing_api_doc(section=api_section.subreddits,
|
||||
uri='/subreddits/{where}',
|
||||
uri_variants=['/subreddits/popular', '/subreddits/new', '/subreddits/banned'])
|
||||
uri_variants=['/subreddits/popular', '/subreddits/new'])
|
||||
def GET_listing(self, where, **env):
|
||||
"""Get all subreddits.
|
||||
|
||||
The `where` parameter chooses the order in which the subreddits are
|
||||
displayed. `popular` sorts on the activity of the subreddit and the
|
||||
position of the subreddits can shift around. `new` sorts the subreddits
|
||||
based on their creation date, newest first.
|
||||
|
||||
"""
|
||||
self.where = where
|
||||
return ListingController.GET_listing(self, **env)
|
||||
|
||||
@@ -1098,6 +1106,19 @@ class MyredditsController(ListingController, OAuth2ResourceController):
|
||||
uri='/subreddits/mine/{where}',
|
||||
uri_variants=['/subreddits/mine/subscriber', '/subreddits/mine/contributor', '/subreddits/mine/moderator'])
|
||||
def GET_listing(self, where='subscriber', **env):
|
||||
"""Get subreddits the user has a relationship with.
|
||||
|
||||
The `where` parameter chooses which subreddits are returned as follows:
|
||||
|
||||
* `subscriber` - subreddits the user is subscribed to
|
||||
* `contributor` - subreddits the user is an approved submitter in
|
||||
* `moderator` - subreddits the user is a moderator of
|
||||
|
||||
See also: [/api/subscribe](#POST_api_subscribe),
|
||||
[/api/friend](#POST_api_friend), and
|
||||
[/api/accept_moderator_invite](#POST_api_accept_moderator_invite).
|
||||
|
||||
"""
|
||||
self.where = where
|
||||
return ListingController.GET_listing(self, **env)
|
||||
|
||||
|
||||
@@ -365,6 +365,11 @@ class VLang(Validator):
|
||||
def run(self, lang):
|
||||
return VLang.validate_lang(lang)
|
||||
|
||||
def param_docs(self):
|
||||
return {
|
||||
self.param: "a valid IETF language tag (underscore separated)",
|
||||
}
|
||||
|
||||
class VRequired(Validator):
|
||||
def __init__(self, param, error, *a, **kw):
|
||||
Validator.__init__(self, param, *a, **kw)
|
||||
@@ -559,6 +564,12 @@ class VLength(Validator):
|
||||
else:
|
||||
return text
|
||||
|
||||
def param_docs(self):
|
||||
return {
|
||||
self.param:
|
||||
"a string no longer than %d characters" % self.max_length,
|
||||
}
|
||||
|
||||
class VUploadLength(VLength):
|
||||
def run(self, upload, text2=''):
|
||||
# upload is expected to be a FieldStorage object
|
||||
@@ -567,6 +578,13 @@ class VUploadLength(VLength):
|
||||
else:
|
||||
self.set_error(self.empty_error, code=400)
|
||||
|
||||
def param_docs(self):
|
||||
kibibytes = self.max_length / 1024
|
||||
return {
|
||||
self.param:
|
||||
"file upload with maximum size of %d KiB" % kibibytes,
|
||||
}
|
||||
|
||||
class VPrintable(VLength):
|
||||
def run(self, text, text2 = ''):
|
||||
text = VLength.run(self, text, text2)
|
||||
@@ -1158,6 +1176,11 @@ class VSubscribeSR(VByName):
|
||||
|
||||
return sr
|
||||
|
||||
def param_docs(self):
|
||||
return {
|
||||
self.param[0]: "name of a subreddit",
|
||||
}
|
||||
|
||||
MIN_PASSWORD_LENGTH = 3
|
||||
|
||||
class VPassword(Validator):
|
||||
@@ -1495,6 +1518,11 @@ class VCssName(Validator):
|
||||
self.set_error(errors.BAD_CSS_NAME)
|
||||
return ''
|
||||
|
||||
def param_docs(self):
|
||||
return {
|
||||
self.param: "a valid subreddit image name",
|
||||
}
|
||||
|
||||
|
||||
class VMenu(Validator):
|
||||
|
||||
@@ -1715,6 +1743,11 @@ class VImageType(Validator):
|
||||
return 'png'
|
||||
return img_type
|
||||
|
||||
def param_docs(self):
|
||||
return {
|
||||
self.param: "one of `png` or `jpg` (default: `png`)",
|
||||
}
|
||||
|
||||
|
||||
class ValidEmails(Validator):
|
||||
"""Validates a list of email addresses passed in as a string and
|
||||
@@ -1837,6 +1870,10 @@ class VCnameDomain(Validator):
|
||||
except UnicodeEncodeError:
|
||||
self.set_error(errors.BAD_CNAME)
|
||||
|
||||
def param_docs(self):
|
||||
# cnames are dead; don't advertise this.
|
||||
return {}
|
||||
|
||||
|
||||
# NOTE: make sure *never* to have res check these are present
|
||||
# otherwise, the response could contain reference to these errors...!
|
||||
|
||||
Reference in New Issue
Block a user