Esempio n. 1
0
def decorate_posts(posts, user):
    """
    Decorates a queryset so that each returned object has extra attributes.
    For efficiency it mutates the original query. Works well for dozens of objects but
    would need to be reworked for use cases involving more than that.
    """
    
    for post in posts :
        post.has_revisions = post.creation_date != post.lastedit_date
        
    if not user.is_authenticated():
        return posts

    pids  = [ post.id for post in posts ]
    votes = Vote.objects.filter(author=user, post__id__in=pids)
    up_votes  = set(vote.post.id for vote in votes if vote.type == VOTE_UP)
    down_votes = set(vote.post.id for vote in votes if vote.type == VOTE_DOWN)
    bookmarks = set(vote.post.id for vote in votes if vote.type == VOTE_BOOKMARK)
    for post in posts :
        post.writeable  = auth.authorize_post_edit(post=post, user=user, strict=False)
        post.upvoted    = post.id in up_votes
        post.downvoted  = post.id in down_votes
        post.bookmarked = post.id in bookmarks
        
    return posts
Esempio n. 2
0
def decorate_posts(posts, user):
    """
    Decorates a queryset so that each returned object has extra attributes.
    For efficiency it mutates the original query. Works well for dozens of objects but
    would need to be reworked for use cases involving more than that.
    """

    for post in posts:
        post.has_revisions = post.creation_date != post.lastedit_date

    if not user.is_authenticated():
        return posts

    pids = [post.id for post in posts]
    votes = Vote.objects.filter(author=user, post__id__in=pids)
    up_votes = set(vote.post.id for vote in votes if vote.type == VOTE_UP)
    down_votes = set(vote.post.id for vote in votes if vote.type == VOTE_DOWN)
    bookmarks = set(vote.post.id for vote in votes if vote.type == VOTE_BOOKMARK)
    for post in posts:
        post.writeable = auth.authorize_post_edit(post=post, user=user, strict=False)
        post.upvoted = post.id in up_votes
        post.downvoted = post.id in down_votes
        post.bookmarked = post.id in bookmarks

    return posts
Esempio n. 3
0
def post_moderate(request, post, user, status, date=None):
    """
    Performs a moderator action on the post. 
    """

    # most actions will return the original post
    url = post.get_absolute_url()
    
    # setting posts to open require more than one permission
    if status == POST_OPEN and not user.profile.can_moderate:
        msg = 'User %s not a moderator' % user.id
        messages.error(request, msg) if request else None
        return url

    if post.top_level and post.answer_count > 0 and (not user.profile.can_moderate):
        msg = 'The post already has one or more answers. Only a moderator may delete it.'
        messages.error(request, msg) if request else None
        return url

    # check that user may write the post
    if not auth.authorize_post_edit(user=user, post=post, strict=False):
        msg = 'User %s may not moderate post %s' % (user.id, post.id)
        messages.error(request, msg) if request else None
        return url

    if status == POST_CLOSED:
        # closing posts is only possible by someone that left a comment on the main post
        has_comment = Post.objects.filter(parent=post, type=POST_COMMENT, author=user).count()
        if not has_comment:
            msg = '<b>Note</b>: post closing require that you add a comment that explains the rationale for closing it.'
            messages.error(request, msg)
            return url

    # stop any ads that may be attached to this post
    if status in (POST_CLOSED, POST_DELETED):
        post.ad_set.update(status=Ad.STOPPED)

    # special treatment for deletion
    no_orphans = (Post.objects.filter(parent=post).exclude(id=post.id).count() == 0)

    # authors may remove their post/comments without a trace as long as it has
    if status == POST_DELETED and no_orphans and (user==post.author):
        # destroy the post with no trace
        Vote.objects.filter(post=post).delete()
        post.delete()
        return "/"

    post.status = status
    post.save()
   
    text = notegen.post_moderator_action(user=user, post=post)
    send_note(target=post.author, sender=user, content=text,  type=NOTE_MODERATOR, both=True, url=post.get_absolute_url() )
    
    msg = 'Post status set to %s' % post.get_status_display()
    messages.info(request, msg) if request else None
    
    return url
Esempio n. 4
0
def post_moderate(request, post, user, status, date=None):
    """
    Performs a moderator action on the post. 
    """

    # most actions will return the original post
    url = post.get_absolute_url()
    
    # setting posts to open require more than one permission
    if status == POST_OPEN and not user.profile.can_moderate:
        msg = 'User %s not a moderator' % user.id
        messages.error(request, msg) if request else None
        return url

    if post.top_level and post.answer_count > 0 and (not user.profile.can_moderate):
        msg = 'The post already has one or more answers. Only a moderator may delete it.'
        messages.error(request, msg) if request else None
        return url

    # check that user may write the post
    if not auth.authorize_post_edit(user=user, post=post, strict=False):
        msg = 'User %s may not moderate post %s' % (user.id, post.id)
        messages.error(request, msg) if request else None
        return url

    if status == POST_CLOSED:
        # closing posts is only possible by someone that left a comment on the main post
        has_comment = Post.objects.filter(parent=post, type=POST_COMMENT, author=user).count()
        if not has_comment:
            msg = '<b>Note</b>: post closing require that you add a comment that explains the rationale for closing it.'
            messages.error(request, msg)
            return url

    # stop any ads that may be attached to this post
    if status in (POST_CLOSED, POST_DELETED):
        post.ad_set.update(status=Ad.STOPPED)

    # special treatment for deletion
    no_orphans = (Post.objects.filter(parent=post).exclude(id=post.id).count() == 0)

    # authors may remove their post/comments without a trace as long as it has
    if status == POST_DELETED and no_orphans and (user==post.author):
        # destroy the post with no trace
        Vote.objects.filter(post=post).delete()
        post.delete()
        return "/"

    post.status = status
    post.save()
   
    text = notegen.post_moderator_action(user=user, post=post)
    send_note(target=post.author, sender=user, content=text,  type=NOTE_MODERATOR, both=True, url=post.get_absolute_url() )
    
    msg = 'Post status set to %s' % post.get_status_display()
    messages.info(request, msg) if request else None
    
    return url
Esempio n. 5
0
def post_moderate(request, post, user, status, date=None):
    """
    Performs a moderator action on the post. 
    """

    # most actions will return the original post
    url = post.get_absolute_url()

    # setting posts to open require more than one permission
    if status == POST_OPEN and not user.profile.can_moderate:
        msg = 'User %s not a moderator' % user.id
        messages.error(request, msg) if request else None
        return url

    # check that user may write the post
    if not auth.authorize_post_edit(user=user, post=post, strict=False):
        msg = 'User %s may not moderate post %s' % (user.id, post.id)
        messages.error(request, msg) if request else None
        return url

    # special treatment for deletion
    no_orphans = (Post.objects.filter(parent=post).exclude(
        id=post.id).count() == 0)

    # authors may remove their post/comments without a trace as long as it has
    if status == POST_DELETED and no_orphans and (user == post.author):
        # destroy the post with no trace
        Vote.objects.filter(post=post).delete()
        post.delete()
        return "/"

    # replace tags with the word deleted
    if status == POST_DELETED:
        post.tag_val = "deleted-post"
        post.set_tags()

    post.status = status
    post.save()

    text = notegen.post_moderator_action(user=user, post=post)
    send_note(target=post.author,
              sender=user,
              content=text,
              type=NOTE_MODERATOR,
              both=True,
              url=post.get_absolute_url())

    msg = 'Post status set to %s' % post.get_status_display()
    messages.info(request, msg) if request else None

    return url
Esempio n. 6
0
def post_moderate(request, post, user, status, date=None):
    """
    Performs a moderator action on the post. 
    """

    # most actions will return the original post
    url = post.get_absolute_url()

    # setting posts to open require more than one permission
    if status == POST_OPEN and not user.profile.can_moderate:
        msg = "User %s not a moderator" % user.id
        messages.error(request, msg) if request else None
        return url

    # check that user may write the post
    if not auth.authorize_post_edit(user=user, post=post, strict=False):
        msg = "User %s may not moderate post %s" % (user.id, post.id)
        messages.error(request, msg) if request else None
        return url

    # special treatment for deletion
    no_orphans = Post.objects.filter(parent=post).exclude(id=post.id).count() == 0

    # authors may remove their post/comments without a trace as long as it has
    if status == POST_DELETED and no_orphans and (user == post.author):
        # destroy the post with no trace
        Vote.objects.filter(post=post).delete()
        post.delete()
        return "/"

    # replace tags with the word deleted
    if status == POST_DELETED:
        post.tag_val = "deleted-post"
        post.set_tags()

    post.status = status
    post.save()

    text = notegen.post_moderator_action(user=user, post=post)
    send_note(
        target=post.author, sender=user, content=text, type=NOTE_MODERATOR, both=True, url=post.get_absolute_url()
    )

    msg = "Post status set to %s" % post.get_status_display()
    messages.info(request, msg) if request else None

    return url
Esempio n. 7
0
def post_edit(request, pid=0):
    "Handles the editing of an existing post"

    user = request.user
    name = "post.edit.html"
    post = models.Post.objects.get(pk=pid)

    if not post.open and not user.can_moderate:
        messages.error(request, 'Post is closed. It may not be edited.')
        return redirect(post.root)

    # verify that this user may indeed modify the post
    if not auth.authorize_post_edit(post=post, user=request.user,
                                    strict=False):
        messages.error(request, 'User may not edit the post.')
        return redirect(post.root)

    toplevel = post.top_level
    factory = formdef.TopLevelContent if toplevel else formdef.ChildContent

    params = html.Params(tab='edit', title="Edit post", toplevel=toplevel)
    if request.method == 'GET':
        # no incoming data, render prefilled form
        form = factory(initial=dict(title=post.title,
                                    content=post.content,
                                    tag_val=post.tag_val,
                                    type=post.type,
                                    context=post.context))
        return html.template(request, name=name, form=form, params=params)

    # process the incoming data
    assert request.method == 'POST', "Method=%s" % request.method
    form = factory(request.POST)
    if not form.is_valid():
        # returns with an error message
        return html.template(request, name=name, form=form, params=params)

    # form is valid now set the attributes
    for key, value in form.cleaned_data.items():
        setattr(post, key, value)
        post.lastedit_user = user
        post.lastedit_date = datetime.now()
        post.set_tags()  # this saves the post

    return redirect(post)
Esempio n. 8
0
def post_reparent(request, pid, rid=0):
    "Reparent a post"
    
    post = models.Post.objects.get(id=pid)
    root = post.root
    parent = post.parent

    allow = auth.authorize_post_edit(post=post, user=request.user, strict=False)
    
    if not allow:
        messages.error(request, "Reparent access denied")
        return html.redirect(post.get_absolute_url())

    if post.type in POST_TOPLEVEL or post == post.root:
        messages.error(request, "Cannot reparent a toplevel post")
        return html.redirect(post.get_absolute_url())

    # these are the valid targets
    targets = models.Post.objects.filter(root=root).select_related('author', 'author__profile').exclude(id__in=(post.id, parent.id))

    target = request.REQUEST.get('target')
    if target:
        target =  models.Post.objects.get(id=target)
        
        if target not in targets:
            messages.error(request, "Invalid reparent %s -> %s" % (post.id, target.id) )
            return html.redirect(post.get_absolute_url())
        
        # comment to comment reparent is not yet supported
        if target.type == POST_COMMENT and post.type == POST_COMMENT:
            messages.error(request, "Comment to comment reparent %s -> %s not implemented" % (post.id, target.id) )
            return html.redirect(post.get_absolute_url())

        # perfomr the reparent
        post.parent = target
        question = (target.type == POST_QUESTION)
        post.type = POST_ANSWER if question else POST_COMMENT
        post.save()

        # valid target to be applied
        messages.info(request, "Reparenting %s to %s" % (post.id, target.id))
        return html.redirect(post.get_absolute_url())
        
    return html.template(request, name='post.reparent.html', post=post, targets=targets)
Esempio n. 9
0
def post_edit(request, pid=0):
    "Handles the editing of an existing post"
    
    user = request.user
    name = "post.edit.html"
    post = models.Post.objects.get(pk=pid)

    if not post.open and not user.can_moderate:
        messages.error(request, 'Post is closed. It may not be edited.')
        return redirect(post.root)
        
    # verify that this user may indeed modify the post
    if not auth.authorize_post_edit(post=post, user=request.user, strict=False):
        messages.error(request, 'User may not edit the post.')
        return redirect(post.root)
  
    toplevel = post.top_level
    factory  = formdef.TopLevelContent if toplevel else formdef.ChildContent

    params = html.Params(tab='edit', title="Edit post", toplevel=toplevel)
    if request.method == 'GET':
        # no incoming data, render prefilled form
        form = factory(initial=dict(title=post.title, content=post.content, tag_val=post.tag_val, type=post.type))
        return html.template(request, name=name, form=form, params=params)

    # process the incoming data
    assert request.method == 'POST', "Method=%s" % request.method
    form = factory(request.POST)
    if not form.is_valid():
        # returns with an error message
        return html.template(request, name=name, form=form, params=params)

    # form is valid now set the attributes
    for key, value in form.cleaned_data.items():
        setattr(post, key, value)
        post.lastedit_user = user
        post.lastedit_date = datetime.now()
        post.set_tags() # this saves the post
    
    return redirect(post)