threads.py 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. from __future__ import unicode_literals
  2. from django.contrib.auth import get_user_model
  3. from django.utils import timezone
  4. from misago.categories.models import Category
  5. from misago.threads.models import Post, PostEdit, PostLike, Thread, ThreadParticipant
  6. from . import fetch_assoc, localise_datetime, markup, movedids
  7. UserModel = get_user_model()
  8. def move_threads(stdout, style):
  9. special_categories = get_special_categories_dict()
  10. for thread in fetch_assoc('SELECT * FROM misago_thread ORDER BY id'):
  11. if special_categories.get(thread['forum_id']) == 'reports':
  12. stdout.write(style.WARNING("Skipping report: %s" % thread['name']))
  13. continue
  14. if not thread['start_post_id']:
  15. stdout.write(style.ERROR("Corrupted thread: %s" % thread['name']))
  16. continue
  17. if special_categories.get(thread['forum_id']) == 'private_threads':
  18. category = Category.objects.private_threads()
  19. else:
  20. if thread['prefix_id']:
  21. label_id = '%s-%s' % (thread['prefix_id'], thread['forum_id'])
  22. category_pk = movedids.get('label', label_id)
  23. else:
  24. category_pk = movedids.get('category', thread['forum_id'])
  25. category = Category.objects.get(pk=category_pk)
  26. new_thread = Thread.objects.create(
  27. category=category,
  28. title=thread['name'],
  29. slug=thread['slug'],
  30. started_on=timezone.now(),
  31. last_post_on=timezone.now(),
  32. starter_name='none',
  33. starter_slug='none',
  34. weight=thread['weight'],
  35. is_hidden=thread['deleted'],
  36. is_closed=thread['closed'],
  37. )
  38. movedids.set('thread', thread['id'], new_thread.pk)
  39. def move_posts():
  40. special_categories = get_special_categories_dict()
  41. for post in fetch_assoc('SELECT * FROM misago_post ORDER BY id'):
  42. if special_categories.get(post['forum_id']) == 'reports':
  43. continue
  44. thread_pk = movedids.get('thread', post['thread_id'])
  45. thread = Thread.objects.select_related('category').get(pk=thread_pk)
  46. poster = None
  47. last_editor = None
  48. if post['user_id']:
  49. poster_id = movedids.get('user', post['user_id'])
  50. poster = UserModel.objects.get(pk=poster_id)
  51. if post['edit_user_id']:
  52. last_editor_id = movedids.get('user', post['edit_user_id'])
  53. last_editor = UserModel.objects.get(pk=last_editor_id)
  54. deleter = None
  55. deleter_name = None
  56. deleter_slug = None
  57. if post['deleted']:
  58. deleter = UserModel.objects.filter(is_staff=True).order_by('id').last()
  59. if deleter:
  60. deleter_name = deleter.username
  61. deleter_slug = deleter.slug
  62. else:
  63. deleter = poster
  64. deleter_name = poster.username
  65. deleter_slug = poster.slug
  66. new_post = Post.objects.create(
  67. category=thread.category,
  68. thread=thread,
  69. poster=poster,
  70. poster_name=post['user_name'],
  71. poster_ip=post['ip'],
  72. original=post['post'],
  73. parsed=post['post_preparsed'],
  74. posted_on=localise_datetime(post['date']),
  75. updated_on=localise_datetime(post['current_date'] or post['date']),
  76. hidden_on=localise_datetime(post['delete_date'] or post['date']),
  77. edits=post['edits'],
  78. last_editor=last_editor,
  79. last_editor_name=post['edit_user_name'],
  80. last_editor_slug=post['edit_user_slug'],
  81. hidden_by=deleter,
  82. hidden_by_name=deleter_name,
  83. hidden_by_slug=deleter_slug,
  84. is_hidden=post['deleted'],
  85. is_protected=post['protected'],
  86. likes=post['upvotes']
  87. )
  88. movedids.set('post', post['id'], new_post.pk)
  89. def move_mentions():
  90. for metion in fetch_assoc('SELECT * FROM misago_post_mentions'):
  91. try:
  92. post_pk = movedids.get('post', metion['post_id'])
  93. user_pk = movedids.get('user', metion['user_id'])
  94. post = Post.objects.get(pk=post_pk)
  95. user = UserModel.objects.get(pk=user_pk)
  96. post.mentions.add(user)
  97. except:
  98. continue
  99. def move_edits():
  100. query = 'SELECT DISTINCT post_id FROM misago_change ORDER BY post_id'
  101. for edit in fetch_assoc(query):
  102. post_pk = movedids.get('post', edit['post_id'])
  103. post = Post.objects.select_related().get(pk=post_pk)
  104. move_post_edits(post, edit['post_id'])
  105. def move_post_edits(post, old_id):
  106. query = '''
  107. SELECT *
  108. FROM
  109. misago_change
  110. WHERE
  111. post_id = %s AND `change` <> 0
  112. ORDER BY
  113. id
  114. '''
  115. changelog = []
  116. for edit in fetch_assoc(query, [old_id]):
  117. if edit['user_id']:
  118. editor_pk = movedids.get('user', edit['user_id'])
  119. editor = UserModel.objects.get(pk=editor_pk)
  120. else:
  121. editor = None
  122. if changelog:
  123. changelog[-1].edited_to = markup.clean_original(edit['post_content'])
  124. changelog.append(
  125. PostEdit(
  126. category=post.category,
  127. thread=post.thread,
  128. post=post,
  129. edited_on=localise_datetime(edit['date']),
  130. editor=editor,
  131. editor_name=edit['user_name'],
  132. editor_slug=edit['user_slug'],
  133. editor_ip=edit['ip'],
  134. edited_from=markup.clean_original(edit['post_content']),
  135. edited_to=markup.clean_original(post.original),
  136. )
  137. )
  138. if changelog:
  139. PostEdit.objects.bulk_create(changelog)
  140. def move_likes():
  141. query = '''
  142. SELECT *
  143. FROM
  144. misago_karma
  145. WHERE
  146. score > 0
  147. ORDER BY
  148. id
  149. '''
  150. posts = []
  151. for karma in fetch_assoc(query):
  152. post_pk = movedids.get('post', karma['post_id'])
  153. post = Post.objects.select_related().get(pk=post_pk)
  154. if karma['user_id']:
  155. liker_pk = movedids.get('user', karma['user_id'])
  156. liker = UserModel.objects.get(pk=liker_pk)
  157. else:
  158. liker = None
  159. PostLike.objects.create(
  160. category=post.category,
  161. thread=post.thread,
  162. post=post,
  163. liker=liker,
  164. liker_name=karma['user_name'],
  165. liker_slug=karma['user_slug'],
  166. liker_ip=karma['ip'],
  167. liked_on=localise_datetime(karma['date']),
  168. )
  169. posts.append(post_pk)
  170. for post in Post.objects.filter(id__in=posts).iterator():
  171. post.last_likes = []
  172. for like in post.postlike_set.all()[:4]:
  173. post.last_likes.append({'id': like.liker_id, 'username': like.liker_name})
  174. post.save(update_fields=['last_likes'])
  175. def move_participants():
  176. for participant in fetch_assoc('SELECT * FROM misago_thread_participants'):
  177. thread_pk = movedids.get('thread', participant['thread_id'])
  178. thread = Thread.objects.get(pk=thread_pk)
  179. user_pk = movedids.get('user', participant['user_id'])
  180. user = UserModel.objects.get(pk=user_pk)
  181. starter = thread.post_set.order_by('id').first().poster
  182. ThreadParticipant.objects.create(thread=thread, user=user, is_owner=(user == starter))
  183. def clean_private_threads(stdout, style):
  184. category = Category.objects.private_threads()
  185. # prune threads without participants
  186. participated_threads = ThreadParticipant.objects.values_list('thread_id', flat=True).distinct()
  187. for thread in category.thread_set.exclude(pk__in=participated_threads):
  188. thread.delete()
  189. # close threads with single participant, delete empty ones
  190. for thread in category.thread_set.iterator():
  191. participants_count = thread.participants.count()
  192. if participants_count == 1:
  193. thread.is_closed = True
  194. thread.save()
  195. elif participants_count == 0:
  196. thread.delete()
  197. stdout.write(style.ERROR("Delete empty private thread: %s" % thread.title))
  198. def get_special_categories_dict():
  199. special_categories = {}
  200. query = '''
  201. SELECT
  202. id, special
  203. FROM
  204. misago_forum
  205. WHERE
  206. special IS NOT NULL
  207. '''
  208. for special in fetch_assoc(query):
  209. special_categories[special['id']] = special['special']
  210. return special_categories