##// END OF EJS Templates
Fixed reflink parsing
neko259 -
r556:10b29819 1.7-dev
parent child Browse files
Show More
@@ -1,198 +1,198 b''
1 1 from django.core.urlresolvers import reverse
2 2 import markdown
3 3 from markdown.inlinepatterns import Pattern
4 4 from markdown.util import etree
5 5 import boards
6 6
7 7 __author__ = 'neko259'
8 8
9 9
10 10 AUTOLINK_PATTERN = r'(https?://\S+)'
11 11 QUOTE_PATTERN = r'^(?<!>)(>[^>].+)$'
12 12 REFLINK_PATTERN = r'((>>)(\d+))'
13 13 SPOILER_PATTERN = r'%%([^(%%)]+)%%'
14 14 COMMENT_PATTERN = r'^(//(.+))'
15 15 STRIKETHROUGH_PATTERN = r'~(.+)~'
16 16
17 17
18 18 class TextFormatter():
19 19 """
20 20 An interface for formatter that can be used in the text format panel
21 21 """
22 22
23 23 name = ''
24 24
25 25 # Left and right tags for the button preview
26 26 preview_left = ''
27 27 preview_right = ''
28 28
29 29 # Left and right characters for the textarea input
30 30 format_left = ''
31 31 format_right = ''
32 32
33 33
34 34 class AutolinkPattern(Pattern):
35 35 def handleMatch(self, m):
36 36 link_element = etree.Element('a')
37 37 href = m.group(2)
38 38 link_element.set('href', href)
39 39 link_element.text = href
40 40
41 41 return link_element
42 42
43 43
44 44 class QuotePattern(Pattern, TextFormatter):
45 45 name = ''
46 46 preview_left = '<span class="quote">&gt; '
47 47 preview_right = '</span>'
48 48
49 49 format_left = '&gt;'
50 50
51 51 def handleMatch(self, m):
52 52 quote_element = etree.Element('span')
53 53 quote_element.set('class', 'quote')
54 54 quote_element.text = m.group(2)
55 55
56 56 return quote_element
57 57
58 58
59 59 class ReflinkPattern(Pattern):
60 60 def handleMatch(self, m):
61 61 post_id = m.group(4)
62 62
63 63 posts = boards.models.Post.objects.filter(id=post_id)
64 64 if posts.count() > 0:
65 65 ref_element = etree.Element('a')
66 66
67 67 post = posts[0]
68 68 if not post.is_opening():
69 link = reverse(boards.views.thread, kwargs={
69 link = reverse('thread', kwargs={
70 70 'post_id': post.thread_new.get_opening_post().id})\
71 71 + '#' + post_id
72 72 else:
73 link = reverse(boards.views.thread, kwargs={'post_id': post_id})
73 link = reverse('thread', kwargs={'post_id': post_id})
74 74
75 75 ref_element.set('href', link)
76 76 ref_element.text = m.group(2)
77 77
78 78 return ref_element
79 79
80 80
81 81 class SpoilerPattern(Pattern, TextFormatter):
82 82 name = 's'
83 83 preview_left = '<span class="spoiler">'
84 84 preview_right = '</span>'
85 85
86 86 format_left = '%%'
87 87 format_right = '%%'
88 88
89 89 def handleMatch(self, m):
90 90 quote_element = etree.Element('span')
91 91 quote_element.set('class', 'spoiler')
92 92 quote_element.text = m.group(2)
93 93
94 94 return quote_element
95 95
96 96
97 97 class CommentPattern(Pattern, TextFormatter):
98 98 name = ''
99 99 preview_left = '<span class="comment">// '
100 100 preview_right = '</span>'
101 101
102 102 format_left = '//'
103 103
104 104 def handleMatch(self, m):
105 105 quote_element = etree.Element('span')
106 106 quote_element.set('class', 'comment')
107 107 quote_element.text = '//' + m.group(3)
108 108
109 109 return quote_element
110 110
111 111
112 112 class StrikeThroughPattern(Pattern, TextFormatter):
113 113 name = 's'
114 114 preview_left = '<span class="strikethrough">'
115 115 preview_right = '</span>'
116 116
117 117 format_left = '~'
118 118 format_right = '~'
119 119
120 120 def handleMatch(self, m):
121 121 quote_element = etree.Element('span')
122 122 quote_element.set('class', 'strikethrough')
123 123 quote_element.text = m.group(2)
124 124
125 125 return quote_element
126 126
127 127
128 128 class ItalicPattern(TextFormatter):
129 129 name = 'i'
130 130 preview_left = '<i>'
131 131 preview_right = '</i>'
132 132
133 133 format_left = '_'
134 134 format_right = '_'
135 135
136 136
137 137 class BoldPattern(TextFormatter):
138 138 name = 'b'
139 139 preview_left = '<b>'
140 140 preview_right = '</b>'
141 141
142 142 format_left = '__'
143 143 format_right = '__'
144 144
145 145
146 146 class CodePattern(TextFormatter):
147 147 name = 'code'
148 148 preview_left = '<code>'
149 149 preview_right = '</code>'
150 150
151 151 format_left = ' '
152 152
153 153
154 154 class NeboardMarkdown(markdown.Extension):
155 155 def extendMarkdown(self, md, md_globals):
156 156 self._add_neboard_patterns(md)
157 157 self._delete_patterns(md)
158 158
159 159 def _delete_patterns(self, md):
160 160 del md.parser.blockprocessors['quote']
161 161
162 162 del md.inlinePatterns['image_link']
163 163 del md.inlinePatterns['image_reference']
164 164
165 165 def _add_neboard_patterns(self, md):
166 166 autolink = AutolinkPattern(AUTOLINK_PATTERN, md)
167 167 quote = QuotePattern(QUOTE_PATTERN, md)
168 168 reflink = ReflinkPattern(REFLINK_PATTERN, md)
169 169 spoiler = SpoilerPattern(SPOILER_PATTERN, md)
170 170 comment = CommentPattern(COMMENT_PATTERN, md)
171 171 strikethrough = StrikeThroughPattern(STRIKETHROUGH_PATTERN, md)
172 172
173 173 md.inlinePatterns[u'autolink_ext'] = autolink
174 174 md.inlinePatterns[u'spoiler'] = spoiler
175 175 md.inlinePatterns[u'strikethrough'] = strikethrough
176 176 md.inlinePatterns[u'comment'] = comment
177 177 md.inlinePatterns[u'reflink'] = reflink
178 178 md.inlinePatterns[u'quote'] = quote
179 179
180 180
181 181 def make_extension(configs=None):
182 182 return NeboardMarkdown(configs=configs)
183 183
184 184 neboard_extension = make_extension()
185 185
186 186
187 187 def markdown_extended(markup):
188 188 return markdown.markdown(markup, [neboard_extension], safe_mode=True)
189 189
190 190 formatters = [
191 191 QuotePattern,
192 192 SpoilerPattern,
193 193 ItalicPattern,
194 194 BoldPattern,
195 195 CommentPattern,
196 196 StrikeThroughPattern,
197 197 CodePattern,
198 198 ]
@@ -1,172 +1,165 b''
1 1 __author__ = 'neko259'
2 2
3 3 import hashlib
4 4
5 5 from django.core import serializers
6 6 from django.core.urlresolvers import reverse
7 7 from django.http import HttpResponseRedirect
8 8 from django.http.response import HttpResponse
9 9 from django.template import RequestContext
10 10 from django.shortcuts import render, redirect, get_object_or_404
11 11 from django.utils import timezone
12 12 from django.db import transaction
13 13 from django.views.decorators.cache import cache_page
14 14 from django.views.i18n import javascript_catalog
15 15
16 16 import boards
17 17 from boards.forms import PlainErrorList
18 18 from boards.models import Post, Tag, Ban, User
19 19 from boards.models.post import SETTING_MODERATE
20 20 from boards.models.user import RANK_USER
21 21 from boards import authors
22 22 import neboard
23 23
24 24
25 BAN_REASON_SPAM = 'Autoban: spam bot'
26
27 DEFAULT_PAGE = 1
28
29
30
31
32 25 @transaction.atomic
33 26 def tag_subscribe(request, tag_name):
34 27 """Add tag to favorites"""
35 28
36 29 user = _get_user(request)
37 30 tag = get_object_or_404(Tag, name=tag_name)
38 31
39 32 if not tag in user.fav_tags.all():
40 33 user.add_tag(tag)
41 34
42 35 return _redirect_to_next(request)
43 36
44 37
45 38 @transaction.atomic
46 39 def tag_unsubscribe(request, tag_name):
47 40 """Remove tag from favorites"""
48 41
49 42 user = _get_user(request)
50 43 tag = get_object_or_404(Tag, name=tag_name)
51 44
52 45 if tag in user.fav_tags.all():
53 46 user.remove_tag(tag)
54 47
55 48 return _redirect_to_next(request)
56 49
57 50
58 51 def static_page(request, name):
59 52 """Show a static page that needs only tags list and a CSS"""
60 53
61 54 context = _init_default_context(request)
62 55 return render(request, 'boards/staticpages/' + name + '.html', context)
63 56
64 57
65 58 # TODO This has to be moved under the api module
66 59 def api_get_post(request, post_id):
67 60 """
68 61 Get the JSON of a post. This can be
69 62 used as and API for external clients.
70 63 """
71 64
72 65 post = get_object_or_404(Post, id=post_id)
73 66
74 67 json = serializers.serialize("json", [post], fields=(
75 68 "pub_time", "_text_rendered", "title", "text", "image",
76 69 "image_width", "image_height", "replies", "tags"
77 70 ))
78 71
79 72 return HttpResponse(content=json)
80 73
81 74
82 75 @cache_page(86400)
83 76 def cached_js_catalog(request, domain='djangojs', packages=None):
84 77 return javascript_catalog(request, domain, packages)
85 78
86 79
87 80 # TODO This method is deprecated and should be removed after switching to
88 81 # class-based view
89 82 def _get_theme(request, user=None):
90 83 """Get user's CSS theme"""
91 84
92 85 if not user:
93 86 user = _get_user(request)
94 87 theme = user.get_setting('theme')
95 88 if not theme:
96 89 theme = neboard.settings.DEFAULT_THEME
97 90
98 91 return theme
99 92
100 93
101 94 # TODO This method is deprecated and should be removed after switching to
102 95 # class-based view
103 96 def _init_default_context(request):
104 97 """Create context with default values that are used in most views"""
105 98
106 99 context = RequestContext(request)
107 100
108 101 user = _get_user(request)
109 102 context['user'] = user
110 103 context['tags'] = user.get_sorted_fav_tags()
111 104 context['posts_per_day'] = float(Post.objects.get_posts_per_day())
112 105
113 106 theme = _get_theme(request, user)
114 107 context['theme'] = theme
115 108 context['theme_css'] = 'css/' + theme + '/base_page.css'
116 109
117 110 # This shows the moderator panel
118 111 moderate = user.get_setting(SETTING_MODERATE)
119 112 if moderate == 'True':
120 113 context['moderator'] = user.is_moderator()
121 114 else:
122 115 context['moderator'] = False
123 116
124 117 return context
125 118
126 119
127 120 # TODO This method is deprecated and should be removed after switching to
128 121 # class-based view
129 122 def _get_user(request):
130 123 """
131 124 Get current user from the session. If the user does not exist, create
132 125 a new one.
133 126 """
134 127
135 128 session = request.session
136 129 if not 'user_id' in session:
137 130 request.session.save()
138 131
139 132 md5 = hashlib.md5()
140 133 md5.update(session.session_key)
141 134 new_id = md5.hexdigest()
142 135
143 136 while User.objects.filter(user_id=new_id).exists():
144 137 md5.update(str(timezone.now()))
145 138 new_id = md5.hexdigest()
146 139
147 140 time_now = timezone.now()
148 141 user = User.objects.create(user_id=new_id, rank=RANK_USER,
149 142 registration_time=time_now)
150 143
151 144 # TODO This is just a test. This method should be removed
152 145 # _delete_old_users()
153 146
154 147 session['user_id'] = user.id
155 148 else:
156 149 user = User.objects.get(id=session['user_id'])
157 150
158 151 return user
159 152
160 153
161 154 def _redirect_to_next(request):
162 155 """
163 156 If a 'next' parameter was specified, redirect to the next page. This is
164 157 used when the user is required to return to some page after the current
165 158 view has finished its work.
166 159 """
167 160
168 161 if 'next' in request.GET:
169 162 next_page = request.GET['next']
170 163 return HttpResponseRedirect(next_page)
171 164 else:
172 165 return redirect('index')
General Comments 0
You need to be logged in to leave comments. Login now