3 import time, datetime, random
 
   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
 
  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
 
  29 DEFAULT_PAGE_SIZE = 60
 
  31 QUESTIONS_PAGE_SIZE = 10
 
  33 ANSWERS_PAGE_SIZE = 10
 
  35 markdowner = Markdown(html4tags=True)
 
  37 def upload(request):#ajax upload file to a question or answer
 
  38     class FileTypeNotAllow(Exception):
 
  40     class FileSizeNotAllow(Exception):
 
  42     class UploadPermissionNotAuthorized(Exception):
 
  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>"
 
  49         f = request.FILES['file-upload']
 
  50         # check upload permission
 
  51         if not request.user.can_upload_files():
 
  52             raise UploadPermissionNotAuthorized()
 
  55         file_name_suffix = os.path.splitext(f.name)[1].lower()
 
  57         if not file_name_suffix in ('.jpg', '.jpeg', '.gif', '.png', '.bmp', '.tiff', '.ico'):
 
  58             raise FileTypeNotAllow()
 
  60         storage = FileSystemStorage(str(settings.UPFILES_FOLDER), str(settings.UPFILES_ALIAS))
 
  61         new_file_name = storage.save(f.name, f)
 
  64         size = storage.size(new_file_name)
 
  66         if size > float(settings.ALLOW_MAX_FILE_SIZE) * 1024 * 1024:
 
  67             storage.delete(new_file_name)
 
  68             raise FileSizeNotAllow()
 
  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, '')
 
  78         result = xml_template % ('', _('Error uploading file. Please contact the site administrator. Thank you. %s' % e), '')
 
  80     return HttpResponse(result, mimetype="application/xml")
 
  84     if request.method == "POST" and "text" in request.POST:
 
  85         form = AskForm(request.POST)
 
  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]
 
  96             if request.user.is_authenticated():
 
  99                 question = Question.objects.create_new(
 
 106                     text = sanitize_html(markdowner.convert(text))
 
 109                 return HttpResponseRedirect(question.get_absolute_url())
 
 111                 request.session.flush()
 
 112                 session_key = request.session.session_key
 
 113                 question = AnonymousQuestion(
 
 114                     session_key = session_key,
 
 121                     ip_addr = request.META['REMOTE_ADDR'],
 
 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']})
 
 130     tags = _get_tags_cache_json()
 
 131     return render_to_response('ask.html', {
 
 134         'email_validation_faq_url':reverse('faq') + '#validate',
 
 135         }, context_instance=RequestContext(request))
 
 138 def edit_question(request, id):#edit or retag a question
 
 139     """view to edit question
 
 141     question = get_object_or_404(Question, id=id)
 
 142     if question.deleted and not request.user.can_view_deleted_post(question):
 
 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)
 
 151 def _retag_question(request, question):#non-url subview of edit question - just retag
 
 152     """retag question sub-view used by
 
 155     if request.method == 'POST':
 
 156         form = RetagQuestionForm(question, request.POST)
 
 158             if form.has_changed():
 
 159                 latest_revision = question.get_latest_revision()
 
 160                 retagged_at = datetime.datetime.now()
 
 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
 
 169                 # Create a new revision
 
 170                 QuestionRevision.objects.create(
 
 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
 
 180             return HttpResponseRedirect(question.get_absolute_url())
 
 182         form = RetagQuestionForm(question)
 
 183     return render_to_response('question_retag.html', {
 
 184         'question': question,
 
 186         'tags' : _get_tags_cache_json(),
 
 187     }, context_instance=RequestContext(request))
 
 189 def _edit_question(request, question):#non-url subview of edit_question - just edit the body/title
 
 190     latest_revision = question.get_latest_revision()
 
 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']))
 
 202                 form = EditQuestionForm(question, latest_revision, request.POST)
 
 204             # Always check modifications against the latest revision
 
 205             form = EditQuestionForm(question, latest_revision, request.POST)
 
 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'])
 
 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]
 
 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']):
 
 229                         question.wikified_at = edited_at
 
 233                     # Create a new revision
 
 234                     revision = QuestionRevision(
 
 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'],
 
 242                     if form.cleaned_data['summary']:
 
 243                         revision.summary = form.cleaned_data['summary']
 
 245                         revision.summary = 'No.%s Revision' % latest_revision.revision
 
 248                 return HttpResponseRedirect(question.get_absolute_url())
 
 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,
 
 257         'tags' : _get_tags_cache_json()
 
 258     }, context_instance=RequestContext(request))
 
 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):
 
 265     elif not request.user.can_edit_post(answer):
 
 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']))
 
 279                     form = EditAnswerForm(answer, latest_revision, request.POST)
 
 281                 form = EditAnswerForm(answer, latest_revision, request.POST)
 
 283                     html = sanitize_html(markdowner.convert(form.cleaned_data['text']))
 
 284                     if form.has_changed():
 
 285                         edited_at = datetime.datetime.now()
 
 287                             'last_edited_at': edited_at,
 
 288                             'last_edited_by': request.user,
 
 291                         Answer.objects.filter(id=answer.id).update(**updated_fields)
 
 293                         revision = AnswerRevision(
 
 296                                                   revised_at=edited_at,
 
 297                                                   text=form.cleaned_data['text']
 
 300                         if form.cleaned_data['summary']:
 
 301                             revision.summary = form.cleaned_data['summary']
 
 303                             revision.summary = 'No.%s Revision' % latest_revision.revision
 
 306                         answer.question.last_activity_at = edited_at
 
 307                         answer.question.last_activity_by = request.user
 
 308                         answer.question.save()
 
 310                     return HttpResponseRedirect(answer.get_absolute_url())
 
 312             revision_form = RevisionForm(answer, latest_revision)
 
 313             form = EditAnswerForm(answer, latest_revision)
 
 314         return render_to_response('answer_edit.html', {
 
 316                                   'revision_form': revision_form,
 
 318                                   }, context_instance=RequestContext(request))
 
 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)
 
 325             wiki = form.cleaned_data['wiki']
 
 326             text = form.cleaned_data['text']
 
 327             update_time = datetime.datetime.now()
 
 329             if request.user.is_authenticated():
 
 330                 Answer.objects.create_new(
 
 333                                   added_at=update_time,
 
 335                                   text=sanitize_html(markdowner.convert(text)),
 
 336                                   email_notify=form.cleaned_data['email_notify']
 
 339                 request.session.flush()
 
 340                 html = sanitize_html(markdowner.convert(text))
 
 341                 summary = strip_tags(html)[:120]
 
 342                 anon = AnonymousAnswer(
 
 347                                        session_key=request.session.session_key,
 
 348                                        ip_addr=request.META['REMOTE_ADDR'],
 
 351                 return HttpResponseRedirect(reverse('auth_action_signin', kwargs={'action': 'newanswer'}))
 
 353     return HttpResponseRedirect(question.get_absolute_url())