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
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
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
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
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
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
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)
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)
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)