Example #1
0
    def save(self, *args, **kwargs):
        # Sanitize the post body.
        self.html = html_util.parse_html(self.content)

        # Must add tags with instance method. This is just for safety.
        self.tag_val = html_util.strip_tags(self.tag_val)

        # Posts other than a question also carry the same tag
        if self.is_toplevel and self.type != Post.QUESTION:
            required_tag = self.get_type_display()
            if required_tag not in self.tag_val:
                self.tag_val += "," + required_tag

        if not self.id:
            # Set the titles
            if self.parent and not self.title:
                self.title = self.parent.title

            if self.parent and self.parent.type in (Post.ANSWER, Post.COMMENT):
                # Only comments may be added to a parent that is answer or comment.
                self.type = Post.COMMENT

            if self.type is None:
                # Set post type if it was left empty.
                self.type = self.COMMENT if self.parent else self.FORUM

            # This runs only once upon object creation.
            self.title = self.parent.title if self.parent else self.title
            self.lastedit_user = self.author
            self.status = self.status or Post.PENDING
            self.creation_date = self.creation_date or general_util.now()
            self.lastedit_date = self.creation_date

            # Set the timestamps on the parent
            if self.type == Post.ANSWER and self.parent:
                self.parent.lastedit_date = self.lastedit_date
                self.parent.lastedit_user = self.lastedit_user
                self.parent.save()

        # Recompute post reply count
        self.update_reply_count()

        super(Post, self).save(*args, **kwargs)
Example #2
0
def email_handler(request):
    key = request.POST.get("key")
    if key != settings.EMAIL_REPLY_SECRET_KEY:
        data = dict(status="error", msg="key does not match")
    else:
        body = request.POST.get("body")
        body = smart_text(body, errors="ignore")


        # This is for debug only
        #fname = "%s/email-debug.txt" % settings.LIVE_DIR
        #fp = file(fname, "wt")
        #fp.write(body.encode("utf-8"))
        #fp.close()

        try:
            # Parse the incoming email.
            # Emails can be malformed in which case we will force utf8 on them before parsing
            try:
                msg = pyzmail.PyzMessage.factory(body)
            except Exception, exc:
                body = body.encode('utf8', errors='ignore')
                msg = pyzmail.PyzMessage.factory(body)

            # Extract the address from the address tuples.
            address = msg.get_addresses('to')[0][1]

            # Parse the token from the address.
            start, token, rest = address.split('+')

            # Verify that the token exists.
            token = ReplyToken.objects.get(token=token)

            # Find the post that the reply targets
            post, author = token.post, token.user

            # Extract the body of the email.
            part = msg.text_part or msg.html_part
            text = part.get_payload()

            # Remove the reply related content
            if settings.EMAIL_REPLY_REMOVE_QUOTED_TEXT:
                text = EmailReplyParser.parse_reply(text)
            else:
                text = text.decode("utf8", errors='replace')
                text = u"<div class='preformatted'>%s</div>" % text

            # Apply server specific formatting
            text = html_util.parse_html(text)

            # Apply the markdown on the text
            text = markdown.markdown(text)

            # Rate-limit sanity check, potentially a runaway process
            since = html_util.now() - timedelta(days=1)
            if Post.objects.filter(author=author, creation_date__gt=since).count() > settings.MAX_POSTS_TRUSTED_USER:
                raise Exception("too many posts created %s" % author.id)

            # Create the new post.
            post_type = Post.ANSWER if post.is_toplevel else Post.COMMENT
            obj = Post.objects.create(type=post_type, parent=post, content=text, author=author)

            # Delete the token. Disabled for now.
            # Old token should be deleted in the data pruning
            #token.delete()

            # Form the return message.
            data = dict(status="ok", id=obj.id)

        except Exception, exc:
            output = StringIO.StringIO()
            traceback.print_exc(file=output)
            data = dict(status="error", msg=str(output.getvalue()))
Example #3
0
class NewPost(FormView):
    form_class = LongForm
    template_name = "post_edit.html"

    def get_context_data(self, **kwargs):
        context = super(NewPost, self).get_context_data(**kwargs)
        context['nodes_list'] = [n["node_name"] for n in ln.get_nodes_list()]
        return context

    def get(self, request, *args, **kwargs):

        initial = dict()

        if "memo" in kwargs:
            memo = json_util.deserialize_memo(kwargs["memo"])

            if "parent_post_id" in memo:
                expected_memo_keys = ["parent_post_id", "post_type", "content"]
                self.form_class = ShortForm
            else:
                expected_memo_keys = [
                    "title", "post_type", "tag_val", "content"
                ]

            for key in expected_memo_keys:
                initial[key] = memo[key]
        else:
            # Attempt to prefill from GET parameters
            for key in "title post_type tag_val content".split():
                value = request.GET.get(key)
                if value:
                    initial[key] = value

        try:
            context = self.get_context_data(**kwargs)
        except Exception as e:
            logger.exception(e)
            raise

        context['form'] = self.form_class(initial=initial)
        context['errors_detected'] = False

        return render(request, self.template_name, context)

    def post(self, request, *args, **kwargs):
        if "memo" in kwargs:
            post_preview = PostPreview()

            # Some data comes from memo
            memo = json_util.deserialize_memo(kwargs["memo"])

            if "parent_post_id" in memo:
                self.form_class = ShortForm

                parent_post_id = memo["parent_post_id"]

                # Find the parent.
                try:
                    parent = Post.objects.get(pk=parent_post_id)
                except ObjectDoesNotExist, e:
                    msg = "The post does not exist. Perhaps it was deleted request (Request: %s)".format(
                        request)
                    logger.error(msg)
                    raise PostViewException(msg)

                post_preview.parent_post_id = parent_post_id
                post_preview.title = parent.title
                post_preview.tag_val = parent.tag_val
                post_preview.tag_value = html_util.split_tags(parent.tag_val)
            else:
                post_preview.title = memo["title"]
                post_preview.tag_val = memo["tag_val"]
                post_preview.tag_value = html_util.split_tags(memo["tag_val"])

            post_preview.status = Post.OPEN
            post_preview.type = memo["post_type"]
            post_preview.date = datetime.utcfromtimestamp(
                memo["unixtime"]).replace(tzinfo=utc)

        # Validating the form.
        form = self.form_class(request.POST)
        if not form.is_valid():
            try:
                context = self.get_context_data(**kwargs)
            except Exception as e:
                logger.exception(e)
                raise

            context['form'] = form
            context['errors_detected'] = True

            return render(request, self.template_name, context)

        if "memo" in kwargs:
            # Only new data comes from the HTML form
            post_preview.content = form.cleaned_data.get("content")
            post_preview.html = html_util.parse_html(post_preview.content)
        else:
            # Valid forms start here.
            data = form.cleaned_data

            # All data comes from the HTML form
            post_preview = PostPreview(title=data.get('title'),
                                       content=data.get('content'),
                                       tag_val=data.get('tag_val'),
                                       type=int(data.get('post_type')),
                                       date=general_util.now())

        return HttpResponseRedirect(
            post_preview.get_absolute_url(memo=post_preview.serialize_memo()))
Example #4
0
class NewAnswer(FormView):
    """
    Creates a new post.
    """

    form_class = ShortForm
    template_name = "post_edit.html"
    type_map = dict(answer=Post.ANSWER, comment=Post.COMMENT)
    post_type = None

    def get_context_data(self, **kwargs):
        context = super(NewAnswer, self).get_context_data(**kwargs)
        context['nodes_list'] = [n["node_name"] for n in ln.get_nodes_list()]
        return context

    def post(self, request, *args, **kwargs):
        """
        This gets the initial "new answer" request, before the get method
        if everything looks good then we generate the memo (with parent post id)
        and re-direct to preview. If there are errors, we also render this
        back to the user directly from here. See `if not form.is_valid()`
        """

        parent_post_id = int(self.kwargs['pid'])

        # URL sets the type for this new post
        post_type = self.type_map.get(self.post_type)
        assert post_type in [
            Post.ANSWER, Post.COMMENT
        ], "I only support Answers and Comment types, got: {}".format(
            post_type)

        # Find the parent.
        try:
            parent = Post.objects.get(pk=parent_post_id)
        except ObjectDoesNotExist, exc:
            logger.error(
                "The post does not exist. Perhaps it was deleted request (Request: %s)",
                request)
            raise

        # Validating the form.
        form = self.form_class(request.POST)
        if not form.is_valid():
            try:
                context = self.get_context_data(**kwargs)
            except Exception as e:
                logger.exception(e)
                raise

            context["form"] = form
            context["errors_detected"] = True
            return render(request, self.template_name, context)

        # Valid forms start here
        content = form.cleaned_data.get("content")

        post_preview = PostPreview()
        post_preview.parent_post_id = parent_post_id
        post_preview.title = parent.title
        post_preview.tag_val = parent.tag_val
        post_preview.tag_value = html_util.split_tags(parent.tag_val)
        post_preview.status = Post.OPEN
        post_preview.type = post_type
        post_preview.content = content
        post_preview.html = html_util.parse_html(content)
        post_preview.date = general_util.now()
        post_preview.memo = post_preview.serialize_memo()

        post_preview.clean_fields()

        return HttpResponseRedirect(
            post_preview.get_absolute_url(memo=post_preview.memo))
Example #5
0
                raise

            post_preview.parent_post_id = parent_post_id
            post_preview.title = parent.title
            post_preview.tag_val = parent.tag_val
            post_preview.tag_value = html_util.split_tags(parent.tag_val)

        else:
            post_preview.title = memo["title"]
            post_preview.tag_val = memo["tag_val"]
            post_preview.tag_value = html_util.split_tags(memo["tag_val"])

        post_preview.status = Post.OPEN
        post_preview.type = memo["post_type"]
        post_preview.content = memo["content"]
        post_preview.html = html_util.parse_html(memo["content"])
        post_preview.date = datetime.utcfromtimestamp(
            memo["unixtime"]).replace(tzinfo=utc)

        post_preview.memo = post_preview.serialize_memo()

        post_preview.clean_fields()

        return post_preview

    def get_context_data(self, **kwargs):

        context = super(PostPreviewView, self).get_context_data(**kwargs)

        view_obj = context.get("view")
        memo_serialized = view_obj.kwargs["memo"]