1a107601fa490ca69215facceebe3d0dc5e7f1f86bcef0037bdb2d139a15065c3f31e872bae79df3
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