annotate forums/tools.py @ 861:e4f8d87c3d30

Configure Markdown logger to reduce noise in logs. Markdown is logging at the INFO level whenever it loads an extension. This looks like it has been fixed in master at GitHub. But until then we will explicitly configure the MARKDOWN logger to log at WARNING or higher.
author Brian Neal <bgneal@gmail.com>
date Mon, 01 Dec 2014 18:36:27 -0600
parents 9e803323a0d0
children c6c3ba5cf6eb
rev   line source
bgneal@147 1 """
bgneal@147 2 This module contains misc. utility functions for forum management.
bgneal@147 3 """
bgneal@228 4 import logging
bgneal@228 5
bgneal@147 6 from forums.models import Post, Topic, Forum, ForumLastVisit, TopicLastVisit
bgneal@781 7 from forums.signals import notify_new_topic, notify_new_post
bgneal@147 8
bgneal@147 9
bgneal@147 10 def delete_user_posts(user):
bgneal@147 11 """
bgneal@147 12 This function deletes all the posts for a given user.
bgneal@147 13 It also cleans up any last visit database records for the user.
bgneal@147 14 This function adjusts the last post foreign keys before deleting
bgneal@147 15 the posts to avoid the cascading delete behavior.
bgneal@147 16 """
bgneal@147 17 posts = Post.objects.filter(user=user).select_related()
bgneal@147 18
bgneal@285 19 # delete attachments
bgneal@285 20 for post in posts:
bgneal@285 21 post.attachments.clear()
bgneal@285 22
bgneal@147 23 # build a set of topics and forums affected by the post deletions
bgneal@147 24
bgneal@147 25 topics = set(post.topic for post in posts)
bgneal@147 26 forums = set(topic.forum for topic in topics)
bgneal@147 27
bgneal@147 28 post_ids = [post.pk for post in posts]
bgneal@147 29 pending_delete = []
bgneal@147 30
bgneal@147 31 for topic in topics:
bgneal@147 32 if topic.last_post.pk in post_ids:
bgneal@147 33 topic_posts = Post.objects.filter(topic=topic).exclude(
bgneal@147 34 pk__in=post_ids)
bgneal@147 35 topic.post_count = topic_posts.count()
bgneal@147 36 if topic.post_count > 0:
bgneal@147 37 topic.last_post = topic_posts.latest()
bgneal@147 38 topic.update_date = topic.last_post.creation_date
bgneal@147 39 topic.save()
bgneal@147 40 else:
bgneal@147 41 # Topic should be deleted, it has no posts;
bgneal@147 42 # We can't delete it now as it could cascade and take out a
bgneal@147 43 # forum. Remember it for later deletion.
bgneal@147 44 pending_delete.append(topic)
bgneal@147 45
bgneal@147 46 for forum in forums:
bgneal@147 47 if forum.last_post.pk in post_ids:
bgneal@147 48 forum_posts = Post.objects.filter(topic__forum=forum).exclude(
bgneal@147 49 pk__in=post_ids)
bgneal@147 50 forum.post_count = forum_posts.count()
bgneal@147 51 if forum.post_count > 0:
bgneal@147 52 forum.last_post = forum_posts.latest()
bgneal@147 53 else:
bgneal@147 54 forum.last_post = None
bgneal@147 55 forum.save()
bgneal@348 56
bgneal@147 57 # Delete pending topics now because forums have just adjusted their
bgneal@147 58 # foreign keys into Post
bgneal@147 59 if pending_delete:
bgneal@147 60 topic_ids = [topic.pk for topic in pending_delete]
bgneal@147 61 Topic.objects.filter(pk__in=topic_ids).delete()
bgneal@147 62
bgneal@147 63 # Topics have been deleted, re-compute topic counts for forums
bgneal@147 64 for forum in forums:
bgneal@147 65 forum.topic_count = Topic.objects.filter(forum=forum).count()
bgneal@147 66 forum.save()
bgneal@348 67
bgneal@147 68 # All foreign keys are accounted for, we can now delete the posts in bulk.
bgneal@147 69 # Since some posts in our original queryset may have been deleted already,
bgneal@147 70 # run a new query (although it may be ok)
bgneal@147 71 Post.objects.filter(pk__in=post_ids).delete()
bgneal@147 72
bgneal@147 73 # delete all the last visit records for this user
bgneal@147 74 TopicLastVisit.objects.filter(user=user).delete()
bgneal@147 75 ForumLastVisit.objects.filter(user=user).delete()
bgneal@147 76
bgneal@228 77
bgneal@228 78 def create_topic(forum_slug, user, topic_name, post_body, ip='', sticky=False,
bgneal@228 79 locked=False):
bgneal@228 80 """Programmatically create a topic & first post in a given forum.
bgneal@228 81
bgneal@228 82 This function creates a new topic in the forum that has the slug
bgneal@228 83 specified by the 'forum_slug' argument. Other arguments are as follows:
bgneal@228 84 'user' - create the topic and post with this user as the owner
bgneal@228 85 'topic_name' - topic name (title)
bgneal@228 86 'post_body' - topic post body (as markup, not HTML)
bgneal@228 87 'ip' - IP address for the post (as a string)
bgneal@228 88 'sticky' - if True, the post will be stickied
bgneal@228 89 'locked' - if True, the post will be locked
bgneal@228 90
bgneal@228 91 """
bgneal@228 92 try:
bgneal@228 93 forum = Forum.objects.get(slug=forum_slug)
bgneal@228 94 except Forum.DoesNotExist:
bgneal@316 95 logging.error('could not create_topic for forum_slug=%s', forum_slug)
bgneal@228 96 raise
bgneal@228 97
bgneal@228 98 topic = Topic(forum=forum,
bgneal@228 99 name=topic_name,
bgneal@228 100 user=user,
bgneal@228 101 sticky=sticky,
bgneal@228 102 locked=locked)
bgneal@228 103 topic.save()
bgneal@228 104
bgneal@228 105 post = Post(topic=topic,
bgneal@228 106 user=user,
bgneal@228 107 body=post_body,
bgneal@228 108 user_ip=ip)
bgneal@228 109 post.save()
bgneal@390 110
bgneal@781 111 notify_new_topic(topic)
bgneal@781 112 notify_new_post(post)
bgneal@781 113
bgneal@390 114
bgneal@390 115 def auto_favorite(post):
bgneal@390 116 """
bgneal@390 117 Given a newly created post, perform an auto-favorite action if the post
bgneal@390 118 creator has that option set in their profile.
bgneal@390 119
bgneal@390 120 """
bgneal@789 121 profile = post.user.profile
bgneal@390 122 if profile.auto_favorite:
bgneal@390 123 post.topic.bookmarkers.add(post.user)
bgneal@390 124
bgneal@390 125
bgneal@390 126 def auto_subscribe(post):
bgneal@390 127 """
bgneal@390 128 Given a newly created post, perform an auto-subscribe action if the post
bgneal@390 129 creator has that option set in their profile.
bgneal@390 130
bgneal@390 131 """
bgneal@789 132 profile = post.user.profile
bgneal@390 133 if profile.auto_subscribe:
bgneal@390 134 post.topic.subscribers.add(post.user)