1a107601fa490ca69215facceebe3d0dc5e7f1f8 | 6bcef0037bdb2d139a15065c3f31e872bae79df3 | ||
---|---|---|---|
27 | from validator import * | 27 | from validator import * |
28 | 28 | ||
29 | from r2.models import * | 29 | from r2.models import * |
30 | from r2.models.subreddit import Default as DefaultSR | ||
30 | import r2.models.thing_changes as tc | 31 | import r2.models.thing_changes as tc |
31 | 32 | ||
32 | from r2.lib.utils import get_title, sanitize_url, timeuntil, set_last_modified | 33 | from r2.lib.utils import get_title, sanitize_url, timeuntil, set_last_modified |
33 | from r2.lib.wrapped import Wrapped | 34 | from r2.lib.wrapped import Wrapped |
34 | from r2.lib.pages import FriendList, ContributorList, ModList, \ | 35 | from r2.lib.pages import FriendList, ContributorList, ModList, \ |
35 | BannedList, BoringPage, FormPage, NewLink | 36 | BannedList, BoringPage, FormPage, NewLink, CssError, UploadedImage |
36 | 37 | ||
37 | from r2.lib.menus import CommentSortMenu | 38 | from r2.lib.menus import CommentSortMenu |
38 | from r2.lib.translation import Translator | 39 | from r2.lib.translation import Translator |
... | ... | ||
40 | from r2.lib.captcha import get_iden | 41 | from r2.lib.captcha import get_iden |
41 | from r2.lib import emailer | 42 | from r2.lib import emailer |
42 | from r2.lib.strings import strings | 43 | from r2.lib.strings import strings |
44 | from r2.lib.memoize import clear_memo | ||
45 | from r2.lib.filters import _force_unicode | ||
43 | from r2.lib.db import queries | 46 | from r2.lib.db import queries |
44 | from r2.config import cache | 47 | from r2.config import cache |
45 | |||
46 | from simplejson import dumps | ||
47 | |||
48 | from r2.lib.jsonresponse import JsonResponse, Json | 48 | from r2.lib.jsonresponse import JsonResponse, Json |
49 | from r2.lib.jsontemplates import api_type | 49 | from r2.lib.jsontemplates import api_type |
50 | from r2.lib import cssfilter | ||
51 | |||
52 | from simplejson import dumps | ||
50 | 53 | ||
51 | from datetime import datetime, timedelta | 54 | from datetime import datetime, timedelta |
55 | from md5 import md5 | ||
52 | from r2.lib.organic import update_pos | 56 | from r2.lib.organic import update_pos |
53 | 57 | ||
54 | def link_listing_by_url(url, count = None): | 58 | def link_listing_by_url(url, count = None): |
... | ... | ||
64 | builder = IDBuilder(names, num = 25) | 68 | builder = IDBuilder(names, num = 25) |
65 | listing = LinkListing(builder).listing() | 69 | listing = LinkListing(builder).listing() |
66 | return listing | 70 | return listing |
67 | | 71 | |
68 | 72 | ||
69 | class ApiController(RedditController): | 73 | class ApiController(RedditController): |
70 | def response_func(self, **kw): | 74 | def response_func(self, **kw): |
... | ... | ||
74 | try: | 78 | try: |
75 | l = Link._by_url(url, sr) | 79 | l = Link._by_url(url, sr) |
76 | if message: | 80 | if message: |
77 | return l.permalink + '?already_submitted=true' | 81 | return l.already_submitted_link() |
78 | else: | 82 | else: |
79 | return l.permalink | 83 | return l.make_permalink_slow() |
80 | except NotFound: | 84 | except NotFound: |
81 | pass | 85 | pass |
82 | 86 | ||
... | ... | ||
272 | # well, nothing left to do but submit it | 276 | # well, nothing left to do but submit it |
273 | l = Link._submit(request.post.title, url, c.user, sr, ip, spam) | 277 | l = Link._submit(request.post.title, url, c.user, sr, ip, spam) |
274 | if url.lower() == 'self': | 278 | if url.lower() == 'self': |
275 | l.url = l.permalink | 279 | l.url = l.make_permalink_slow() |
276 | l.is_self = True | 280 | l.is_self = True |
277 | l._commit() | 281 | l._commit() |
278 | Vote.vote(c.user, l, True, ip, spam) | 282 | Vote.vote(c.user, l, True, ip, spam) |
... | ... | ||
292 | 296 | ||
293 | # flag search indexer that something has changed | 297 | # flag search indexer that something has changed |
294 | tc.changed(l) | 298 | tc.changed(l) |
299 | |||
300 | # make_permalink is designed for links that can be set to _top | ||
301 | # here, we need to generate an ajax redirect as if we were not on a | ||
302 | # cname. | ||
303 | cname = c.cname | ||
304 | c.cname = False | ||
305 | path = l.make_permalink_slow() | ||
306 | c.cname = cname | ||
295 | 307 | ||
296 | res._redirect(l.permalink) | 308 | res._redirect(path) |
297 | 309 | ||
298 | 310 | ||
299 | def _login(self, res, user, dest='', rem = None): | 311 | def _login(self, res, user, dest='', rem = None): |
... | ... | ||
719 | # flag search indexer that something has changed | 731 | # flag search indexer that something has changed |
720 | tc.changed(thing) | 732 | tc.changed(thing) |
721 | 733 | ||
734 | @Json | ||
735 | @validate(VUser(), | ||
736 | VModhash(), | ||
737 | stylesheet_contents = nop('stylesheet_contents'), | ||
738 | op = VOneOf('op',['save','preview'])) | ||
739 | def POST_subreddit_stylesheet(self, res, stylesheet_contents = '', op='save'): | ||
740 | if not c.site.can_change_stylesheet(c.user): | ||
741 | return self.abort(403,'forbidden') | ||
742 | |||
743 | if g.css_killswitch: | ||
744 | return self.abort(403,'forbidden') | ||
745 | |||
746 | parsed, report = cssfilter.validate_css(stylesheet_contents) | ||
747 | |||
748 | if report.errors: | ||
749 | error_items = [ CssError(x).render(style='html') | ||
750 | for x in sorted(report.errors) ] | ||
751 | |||
752 | res._update('status', innerHTML = _('validation errors')) | ||
753 | res._update('validation-errors', innerHTML = ''.join(error_items)) | ||
754 | res._show('error-header') | ||
755 | else: | ||
756 | res._hide('error-header') | ||
757 | res._update('status', innerHTML = '') | ||
758 | res._update('validation-errors', innerHTML = '') | ||
759 | |||
760 | if not report.errors and op == 'save': | ||
761 | stylesheet_contents_user = stylesheet_contents | ||
762 | stylesheet_contents_parsed = parsed.cssText if parsed else '' | ||
763 | |||
764 | c.site.stylesheet_contents = stylesheet_contents_parsed | ||
765 | c.site.stylesheet_contents_user = stylesheet_contents_user | ||
766 | |||
767 | c.site.stylesheet_hash = md5(stylesheet_contents_parsed).hexdigest() | ||
768 | |||
769 | set_last_modified(c.site,'stylesheet_contents') | ||
770 | tc.changed(c.site) | ||
771 | c.site._commit() | ||
772 | |||
773 | res._update('status', innerHTML = 'saved') | ||
774 | res._call('applyStylesheetFromTextbox("stylesheet_contents");') | ||
775 | res._update('validation-errors', innerHTML = '') | ||
776 | |||
777 | elif op == 'preview': | ||
778 | # try to find a link to use, otherwise give up and | ||
779 | # return | ||
780 | links = cssfilter.find_preview_links(c.site) | ||
781 | if not links: | ||
782 | # we're probably not going to be able to find any | ||
783 | # comments, either; screw it | ||
784 | return | ||
785 | |||
786 | res._show('preview-table') | ||
787 | |||
788 | # do a regular link | ||
789 | cssfilter.rendered_link('preview_link_normal', | ||
790 | res, links, | ||
791 | media = 'off', compress=False) | ||
792 | # now do one with media | ||
793 | cssfilter.rendered_link('preview_link_media', | ||
794 | res, links, | ||
795 | media = 'on', compress=False) | ||
796 | # do a compressed link | ||
797 | cssfilter.rendered_link('preview_link_compressed', | ||
798 | res, links, | ||
799 | media = 'off', compress=True) | ||
800 | # and do a comment | ||
801 | comments = cssfilter.find_preview_comments(c.site) | ||
802 | if not comments: | ||
803 | return | ||
804 | cssfilter.rendered_comment('preview_comment',res,comments) | ||
805 | |||
806 | @validate(VUser(), | ||
807 | VModhash(), | ||
808 | VRatelimit(rate_user = True, | ||
809 | rate_ip = True, | ||
810 | prefix = 'upload_reddit_img_'), | ||
811 | file = VLength('file',length=1024*500), | ||
812 | op = VOneOf('op',['upload','delete'])) | ||
813 | def POST_upload_header_img(self, file, op): | ||
814 | if not c.site.can_change_stylesheet(c.user): | ||
815 | return self.abort403() | ||
816 | |||
817 | if g.css_killswitch: | ||
818 | return self.abort(403,'forbidden') | ||
819 | |||
820 | if op == 'upload': | ||
821 | try: | ||
822 | cleaned = cssfilter.clean_image(file,'PNG') | ||
823 | new_url = cssfilter.save_header_image(c.site, cleaned) | ||
824 | except cssfilter.BadImage: | ||
825 | return UploadedImage(_('bad image'),c.site.header).render() | ||
826 | |||
827 | c.site.header = new_url | ||
828 | c.site._commit() | ||
829 | |||
830 | return UploadedImage(_('saved'),new_url,'upload').render() | ||
831 | elif op == 'delete': | ||
832 | c.site.header = None | ||
833 | c.site._commit() | ||
834 | |||
835 | return UploadedImage(_('deleted'),DefaultSR.header,'delete').render() | ||
836 | |||
722 | @Json | 837 | @Json |
723 | @validate(VUser(), | 838 | @validate(VUser(), |
724 | VModhash(), | 839 | VModhash(), |
... | ... | ||
727 | prefix = 'create_reddit_'), | 842 | prefix = 'create_reddit_'), |
728 | name = VSubredditName("name"), | 843 | name = VSubredditName("name"), |
729 | title = VSubredditTitle("title"), | 844 | title = VSubredditTitle("title"), |
845 | domain = VCnameDomain("domain"), | ||
730 | description = VSubredditDesc("description"), | 846 | description = VSubredditDesc("description"), |
731 | firsttext = nop("firsttext"), | 847 | firsttext = nop("firsttext"), |
732 | header = nop("headerfile"), | 848 | header = nop("headerfile"), |
... | ... | ||
740 | type = VOneOf('type', ('public', 'private', 'restricted')) | 856 | type = VOneOf('type', ('public', 'private', 'restricted')) |
741 | ) | 857 | ) |
742 | def POST_site_admin(self, res, name ='', sr = None, **kw): | 858 | def POST_site_admin(self, res, name ='', sr = None, **kw): |
743 | res._update('status', innerHTML = '') | ||
744 | redir = False | 859 | redir = False |
745 | kw = dict((k, v) for k, v in kw.iteritems() | 860 | kw = dict((k, v) for k, v in kw.iteritems() |
746 | if v is not None | 861 | if v is not None |
747 | and k in ('name', 'title', 'description', 'firsttext', | 862 | and k in ('name', 'title', 'domain', 'description', 'firsttext', |
748 | 'static_path', 'ad_file', 'over_18', 'show_media', | 863 | 'static_path', 'ad_file', 'over_18', 'show_media', |
749 | 'type', 'header', 'lang', 'stylesheet')) | 864 | 'type', 'header', 'lang', 'stylesheet')) |
750 | 865 | ||
... | ... | ||
753 | time = timeuntil(datetime.now(g.tz) + timedelta(seconds=600)) | 868 | time = timeuntil(datetime.now(g.tz) + timedelta(seconds=600)) |
754 | c.errors.add(errors.RATELIMIT, {'time': time}) | 869 | c.errors.add(errors.RATELIMIT, {'time': time}) |
755 | 870 | ||
871 | domain = kw['domain'] | ||
872 | cname_sr = domain and Subreddit._by_domain(domain) | ||
873 | if cname_sr and (not sr or sr != cname_sr): | ||
874 | kw['domain'] = None | ||
875 | c.errors.add(errors.USED_CNAME) | ||
876 | |||
756 | if not sr and res._chk_error(errors.RATELIMIT): | 877 | if not sr and res._chk_error(errors.RATELIMIT): |
757 | pass | 878 | pass |
758 | elif not sr and res._chk_errors((errors.SUBREDDIT_EXISTS, | 879 | elif not sr and res._chk_errors((errors.SUBREDDIT_EXISTS, |
... | ... | ||
764 | res._focus('title') | 885 | res._focus('title') |
765 | elif res._chk_error(errors.INVALID_SUBREDDIT_TYPE): | 886 | elif res._chk_error(errors.INVALID_SUBREDDIT_TYPE): |
766 | pass | 887 | pass |
888 | elif res._chk_errors((errors.BAD_CNAME, errors.USED_CNAME)): | ||
889 | res._hide('example_domain') | ||
890 | res._focus('domain') | ||
767 | elif res._chk_error(errors.DESC_TOO_LONG): | 891 | elif res._chk_error(errors.DESC_TOO_LONG): |
768 | res._focus('description') | 892 | res._focus('description') |
769 | 893 | ||
... | ... | ||
784 | 908 | ||
785 | if not res.error: | 909 | if not res.error: |
786 | #assume sr existed, or was just built | 910 | #assume sr existed, or was just built |
911 | clear_memo('subreddit._by_domain', Subreddit, _force_unicode(sr.domain)) | ||
787 | for k, v in kw.iteritems(): | 912 | for k, v in kw.iteritems(): |
788 | setattr(sr, k, v) | 913 | setattr(sr, k, v) |
789 | sr._commit() | 914 | sr._commit() |
... | ... | ||
791 | # flag search indexer that something has changed | 916 | # flag search indexer that something has changed |
792 | tc.changed(sr) | 917 | tc.changed(sr) |
793 | 918 | ||
919 | res._update('status', innerHTML = _('saved')) | ||
920 | |||
921 | |||
794 | if redir: | 922 | if redir: |
795 | res._redirect(redir) | 923 | res._redirect(redir) |
796 | 924 |