]> git.openstreetmap.org Git - osqa.git/blob - osqa/forum/views/writers.py
f65c4f4dc21c0d77c6080c7dc471e6691a46a21f
[osqa.git] / osqa / forum / views / writers.py
1 # encoding:utf-8
2 import os.path
3 import time, datetime, random
4 import logging
5 from django.core.files.storage import FileSystemStorage
6 from django.shortcuts import render_to_response, get_object_or_404
7 from django.contrib.auth.decorators import login_required
8 from django.http import HttpResponseRedirect, HttpResponse, HttpResponseForbidden, Http404
9 from django.template import RequestContext
10 from django.utils.html import *
11 from django.utils import simplejson
12 from django.utils.translation import ugettext as _
13 from django.core.urlresolvers import reverse
14 from django.core.exceptions import PermissionDenied
15
16 from forum.utils.html import sanitize_html
17 from markdown2 import Markdown
18 from forum.forms import *
19 from forum.models import *
20 from forum.const import *
21 from forum.utils.forms import get_next_url
22 from forum.views.readers import _get_tags_cache_json
23
24 # used in index page
25 INDEX_PAGE_SIZE = 20
26 INDEX_AWARD_SIZE = 15
27 INDEX_TAGS_SIZE = 100
28 # used in tags list
29 DEFAULT_PAGE_SIZE = 60
30 # used in questions
31 QUESTIONS_PAGE_SIZE = 10
32 # used in answers
33 ANSWERS_PAGE_SIZE = 10
34
35 markdowner = Markdown(html4tags=True)
36
37 def upload(request):#ajax upload file to a question or answer
38     class FileTypeNotAllow(Exception):
39         pass
40     class FileSizeNotAllow(Exception):
41         pass
42     class UploadPermissionNotAuthorized(Exception):
43         pass
44
45     #<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>
46     xml_template = "<result><msg><![CDATA[%s]]></msg><error><![CDATA[%s]]></error><file_url>%s</file_url></result>"
47
48     try:
49         f = request.FILES['file-upload']
50         # check upload permission
51         if not request.user.can_upload_files():
52             raise UploadPermissionNotAuthorized()
53
54         # check file type
55         file_name_suffix = os.path.splitext(f.name)[1].lower()
56
57         if not file_name_suffix in ('.jpg', '.jpeg', '.gif', '.png', '.bmp', '.tiff', '.ico'):
58             raise FileTypeNotAllow()
59
60         storage = FileSystemStorage(str(settings.UPFILES_FOLDER), str(settings.UPFILES_ALIAS))
61         new_file_name = storage.save(f.name, f)
62         # check file size
63         # byte
64         size = storage.size(new_file_name)
65
66         if size > float(settings.ALLOW_MAX_FILE_SIZE) * 1024 * 1024:
67             storage.delete(new_file_name)
68             raise FileSizeNotAllow()
69
70         result = xml_template % ('Good', '', str(settings.UPFILES_ALIAS) + new_file_name)
71     except UploadPermissionNotAuthorized:
72         result = xml_template % ('', _('uploading images is limited to users with >60 reputation points'), '')
73     except FileTypeNotAllow:
74         result = xml_template % ('', _("allowed file types are 'jpg', 'jpeg', 'gif', 'bmp', 'png', 'tiff'"), '')
75     except FileSizeNotAllow:
76         result = xml_template % ('', _("maximum upload file size is %sM") % settings.ALLOW_MAX_FILE_SIZE, '')
77     except Exception, e:
78         result = xml_template % ('', _('Error uploading file. Please contact the site administrator. Thank you. %s' % e), '')
79
80     return HttpResponse(result, mimetype="application/xml")
81
82
83 def ask(request):
84     if request.method == "POST" and "text" in request.POST:
85         form = AskForm(request.POST)
86         if form.is_valid():
87
88             added_at = datetime.datetime.now()
89             title = strip_tags(form.cleaned_data['title'].strip())
90             wiki = form.cleaned_data['wiki']
91             tagnames = form.cleaned_data['tags'].strip()
92             text = form.cleaned_data['text']
93             html = sanitize_html(markdowner.convert(text))
94             summary = strip_tags(html)[:120]
95             
96             if request.user.is_authenticated():
97                 author = request.user 
98
99                 question = Question.objects.create_new(
100                     title            = title,
101                     author           = author, 
102                     added_at         = added_at,
103                     wiki             = wiki,
104                     tagnames         = tagnames,
105                     summary          = summary,
106                     text = sanitize_html(markdowner.convert(text))
107                 )
108
109                 return HttpResponseRedirect(question.get_absolute_url())
110             else:
111                 request.session.flush()
112                 session_key = request.session.session_key
113                 question = AnonymousQuestion(
114                     session_key = session_key,
115                     title       = title,
116                     tagnames = tagnames,
117                     wiki = wiki,
118                     text = text,
119                     summary = summary,
120                     added_at = added_at,
121                     ip_addr = request.META['REMOTE_ADDR'],
122                 )
123                 question.save()
124                 return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newquestion'}))
125     elif request.method == "POST" and "go" in request.POST:
126         form = AskForm({'title': request.POST['q']})
127     else:
128         form = AskForm()
129
130     tags = _get_tags_cache_json()
131     return render_to_response('ask.html', {
132         'form' : form,
133         'tags' : tags,
134         'email_validation_faq_url':reverse('faq') + '#validate',
135         }, context_instance=RequestContext(request))
136
137 @login_required
138 def edit_question(request, id):#edit or retag a question
139     """view to edit question
140     """
141     question = get_object_or_404(Question, id=id)
142     if question.deleted and not request.user.can_view_deleted_post(question):
143         raise Http404
144     if request.user.can_edit_post(question):
145         return _edit_question(request, question)
146     elif request.user.can_retag_questions():
147         return _retag_question(request, question)
148     else:
149         raise Http404
150
151 def _retag_question(request, question):#non-url subview of edit question - just retag
152     """retag question sub-view used by
153     view "edit_question"
154     """
155     if request.method == 'POST':
156         form = RetagQuestionForm(question, request.POST)
157         if form.is_valid():
158             if form.has_changed():
159                 latest_revision = question.get_latest_revision()
160                 retagged_at = datetime.datetime.now()
161
162                 question.tagnames = form.cleaned_data['tags']
163                 question.last_edited_at = retagged_at
164                 question.last_edited_by = request.user
165                 question.last_activity_at = retagged_at
166                 question.last_activity_by = request.user
167                 question.save()
168
169                 # Create a new revision
170                 QuestionRevision.objects.create(
171                     question   = question,
172                     title      = latest_revision.title,
173                     author     = request.user,
174                     revised_at = retagged_at,
175                     tagnames   = form.cleaned_data['tags'],
176                     summary    = CONST['retagged'],
177                     text       = latest_revision.text
178                 )
179
180             return HttpResponseRedirect(question.get_absolute_url())
181     else:
182         form = RetagQuestionForm(question)
183     return render_to_response('question_retag.html', {
184         'question': question,
185         'form' : form,
186         'tags' : _get_tags_cache_json(),
187     }, context_instance=RequestContext(request))
188
189 def _edit_question(request, question):#non-url subview of edit_question - just edit the body/title
190     latest_revision = question.get_latest_revision()
191     revision_form = None
192     if request.method == 'POST':
193         if 'select_revision' in request.POST:
194             # user has changed revistion number
195             revision_form = RevisionForm(question, latest_revision, request.POST)
196             if revision_form.is_valid():
197                 # Replace with those from the selected revision
198                 form = EditQuestionForm(question,
199                     QuestionRevision.objects.get(question=question,
200                         revision=revision_form.cleaned_data['revision']))
201             else:
202                 form = EditQuestionForm(question, latest_revision, request.POST)
203         else:
204             # Always check modifications against the latest revision
205             form = EditQuestionForm(question, latest_revision, request.POST)
206             if form.is_valid():
207                 html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
208                 if form.has_changed():
209                     edited_at = datetime.datetime.now()
210                     tags_changed = (latest_revision.tagnames !=
211                                     form.cleaned_data['tags'])
212
213                     # Update the Question itself
214                     question.title = form.cleaned_data['title']
215                     question.last_edited_at = edited_at
216                     question.last_edited_by = request.user
217                     question.last_activity_at = edited_at
218                     question.last_activity_by = request.user
219                     question.tagnames = form.cleaned_data['tags']
220                     question.summary = strip_tags(html)[:120]
221                     question.html = html
222
223                     # only save when it's checked
224                     # because wiki doesn't allow to be edited if last version has been enabled already
225                     # and we make sure this in forms.
226                     if ('wiki' in form.cleaned_data and
227                         form.cleaned_data['wiki']):
228                         question.wiki = True
229                         question.wikified_at = edited_at
230
231                     question.save()
232
233                     # Create a new revision
234                     revision = QuestionRevision(
235                         question   = question,
236                         title      = form.cleaned_data['title'],
237                         author     = request.user,
238                         revised_at = edited_at,
239                         tagnames   = form.cleaned_data['tags'],
240                         text       = form.cleaned_data['text'],
241                     )
242                     if form.cleaned_data['summary']:
243                         revision.summary = form.cleaned_data['summary']
244                     else:
245                         revision.summary = 'No.%s Revision' % latest_revision.revision
246                     revision.save()
247
248                 return HttpResponseRedirect(question.get_absolute_url())
249     else:
250
251         revision_form = RevisionForm(question, latest_revision)
252         form = EditQuestionForm(question, latest_revision)
253     return render_to_response('question_edit.html', {
254         'question': question,
255         'revision_form': revision_form,
256         'form' : form,
257         'tags' : _get_tags_cache_json()
258     }, context_instance=RequestContext(request))
259
260 @login_required
261 def edit_answer(request, id):
262     answer = get_object_or_404(Answer, id=id)
263     if answer.deleted and not request.user.can_view_deleted_post(answer):
264         raise Http404
265     elif not request.user.can_edit_post(answer):
266         raise Http404
267     else:
268         latest_revision = answer.get_latest_revision()
269         if request.method == "POST":
270             if 'select_revision' in request.POST:
271                 # user has changed revistion number
272                 revision_form = RevisionForm(answer, latest_revision, request.POST)
273                 if revision_form.is_valid():
274                     # Replace with those from the selected revision
275                     form = EditAnswerForm(answer,
276                                           AnswerRevision.objects.get(answer=answer,
277                                           revision=revision_form.cleaned_data['revision']))
278                 else:
279                     form = EditAnswerForm(answer, latest_revision, request.POST)
280             else:
281                 form = EditAnswerForm(answer, latest_revision, request.POST)
282                 if form.is_valid():
283                     html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
284                     if form.has_changed():
285                         edited_at = datetime.datetime.now()
286                         updated_fields = {
287                             'last_edited_at': edited_at,
288                             'last_edited_by': request.user,
289                             'html': html,
290                         }
291                         Answer.objects.filter(id=answer.id).update(**updated_fields)
292
293                         revision = AnswerRevision(
294                                                   answer=answer,
295                                                   author=request.user,
296                                                   revised_at=edited_at,
297                                                   text=form.cleaned_data['text']
298                                                   )
299
300                         if form.cleaned_data['summary']:
301                             revision.summary = form.cleaned_data['summary']
302                         else:
303                             revision.summary = 'No.%s Revision' % latest_revision.revision
304                         revision.save()
305
306                         answer.question.last_activity_at = edited_at
307                         answer.question.last_activity_by = request.user
308                         answer.question.save()
309
310                     return HttpResponseRedirect(answer.get_absolute_url())
311         else:
312             revision_form = RevisionForm(answer, latest_revision)
313             form = EditAnswerForm(answer, latest_revision)
314         return render_to_response('answer_edit.html', {
315                                   'answer': answer,
316                                   'revision_form': revision_form,
317                                   'form': form,
318                                   }, context_instance=RequestContext(request))
319
320 def answer(request, id):#process a new answer
321     question = get_object_or_404(Question, id=id)
322     if request.method == "POST":
323         form = AnswerForm(question, request.user, request.POST)
324         if form.is_valid():
325             wiki = form.cleaned_data['wiki']
326             text = form.cleaned_data['text']
327             update_time = datetime.datetime.now()
328
329             if request.user.is_authenticated():
330                 Answer.objects.create_new(
331                                   question=question,
332                                   author=request.user,
333                                   added_at=update_time,
334                                   wiki=wiki,
335                                   text=sanitize_html(markdowner.convert(text)),
336                                   email_notify=form.cleaned_data['email_notify']
337                                   )
338             else:
339                 request.session.flush()
340                 html = sanitize_html(markdowner.convert(text))
341                 summary = strip_tags(html)[:120]
342                 anon = AnonymousAnswer(
343                                        question=question,
344                                        wiki=wiki,
345                                        text=text,
346                                        summary=summary,
347                                        session_key=request.session.session_key,
348                                        ip_addr=request.META['REMOTE_ADDR'],
349                                        )
350                 anon.save()
351                 return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newanswer'}))
352
353     return HttpResponseRedirect(question.get_absolute_url())
354