profile.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. from django.contrib import messages
  2. from django.contrib.auth import get_user_model
  3. from django.db.transaction import atomic
  4. from django.http import Http404, JsonResponse
  5. from django.shortcuts import redirect, render as django_render
  6. from django.utils.translation import ugettext as _
  7. from misago.acl import add_acl
  8. from misago.core.decorators import require_POST
  9. from misago.core.shortcuts import get_object_or_404, paginate, validate_slug
  10. from misago.core.utils import clean_return_path
  11. from misago.users import online
  12. from misago.users.bans import get_user_ban
  13. from misago.users.decorators import deny_guests
  14. from misago.users.permissions.profiles import (allow_follow_user,
  15. allow_block_user)
  16. from misago.users.sites import user_profile
  17. from misago.users.warnings import (get_warning_levels, get_user_warning_level,
  18. get_user_warning_obj)
  19. def profile_view(f):
  20. def decorator(request, *args, **kwargs):
  21. User = get_user_model()
  22. relations = ('rank', 'online_tracker', 'ban_cache')
  23. queryset = User.objects.select_related(*relations)
  24. profile = get_object_or_404(queryset, id=kwargs.pop('user_id'))
  25. validate_slug(profile, kwargs.pop('user_slug'))
  26. kwargs['profile'] = profile
  27. add_acl(request.user, profile)
  28. if profile.acl_['can_follow']:
  29. profile.is_followed = request.user.is_following(profile)
  30. else:
  31. profile.is_followed = False
  32. if profile.acl_['can_block'] and request.user.is_authenticated():
  33. profile.is_blocked = request.user.is_blocking(profile)
  34. else:
  35. profile.is_blocked = False
  36. return f(request, *args, **kwargs)
  37. return decorator
  38. def profile_view_restricted_visibility(f):
  39. @profile_view
  40. def decorator(request, *args, **kwargs):
  41. pages = user_profile.get_pages(request, kwargs['profile'])
  42. for page in pages:
  43. if page['is_active']:
  44. return f(request, *args, **kwargs)
  45. else:
  46. # we are trying to display page thats not in nav
  47. raise Http404()
  48. return decorator
  49. def render(request, template, context):
  50. context['pages'] = user_profile.get_pages(request, context['profile'])
  51. for page in context['pages']:
  52. if page['is_active']:
  53. context['active_page'] = page
  54. break
  55. if request.user.is_authenticated():
  56. is_authenticated_user = context['profile'].pk == request.user.pk
  57. else:
  58. is_authenticated_user = False
  59. context['is_authenticated_user'] = is_authenticated_user
  60. user_acl = request.user.acl
  61. if request.user.is_authenticated():
  62. if is_authenticated_user:
  63. context['show_email'] = True
  64. else:
  65. context['show_email'] = user_acl['can_see_users_emails']
  66. else:
  67. context['show_email'] = False
  68. context['state'] = online.state_for_acl(context['profile'], user_acl)
  69. return django_render(request, template, context)
  70. @profile_view
  71. def posts(request, profile, page=0):
  72. return render(request, 'misago/profile/posts.html', {'profile': profile})
  73. @profile_view
  74. def threads(request, profile, page=0):
  75. return render(request, 'misago/profile/threads.html', {'profile': profile})
  76. @profile_view
  77. def followers(request, profile, page=0):
  78. followers_qs = profile.followed_by.order_by('slug').select_related('rank')
  79. followers = paginate(followers_qs, page, 12, 2)
  80. items_left = followers.paginator.count - followers.end_index()
  81. return render(request, 'misago/profile/followers.html', {
  82. 'profile': profile,
  83. 'followers': followers,
  84. 'items_left': items_left,
  85. })
  86. @profile_view
  87. def follows(request, profile, page=0):
  88. followers_qs = profile.follows.order_by('slug').select_related('rank')
  89. followers = paginate(followers_qs, page, 12, 2)
  90. items_left = followers.paginator.count - followers.end_index()
  91. return render(request, 'misago/profile/follows.html', {
  92. 'profile': profile,
  93. 'followers': followers,
  94. 'items_left': items_left,
  95. })
  96. @profile_view_restricted_visibility
  97. def warnings(request, profile, page=0):
  98. warnings_qs = profile.warnings.order_by('-id')
  99. warnings = paginate(warnings_qs, page, 5, 2)
  100. items_left = warnings.paginator.count - warnings.end_index()
  101. add_acl(request.user, warnings.object_list)
  102. warning_level = get_user_warning_level(profile)
  103. warning_level_obj = get_user_warning_obj(profile)
  104. active_warnings = warning_level - warnings.start_index() + 1
  105. for warning in warnings.object_list:
  106. if warning.is_canceled:
  107. warning.is_active = False
  108. else:
  109. warning.is_active = active_warnings > 0
  110. active_warnings -= 1
  111. levels_total = len(get_warning_levels()) - 1
  112. if levels_total and warning_level:
  113. warning_progress = 100 - warning_level * 100 / levels_total
  114. else:
  115. warning_progress = 100
  116. if warning_level:
  117. warning_level_obj.level = warning_level
  118. return render(request, 'misago/profile/warnings.html', {
  119. 'profile': profile,
  120. 'warnings': warnings,
  121. 'warning_level': warning_level_obj,
  122. 'warning_progress': warning_progress,
  123. 'page_number': warnings.number,
  124. 'items_left': items_left
  125. })
  126. @profile_view_restricted_visibility
  127. def name_history(request, profile, page=0):
  128. name_changes_qs = profile.namechanges.all().order_by('-id')
  129. name_changes = paginate(name_changes_qs, page, 12, 4)
  130. items_left = name_changes.paginator.count - name_changes.end_index()
  131. return render(request, 'misago/profile/name_history.html', {
  132. 'profile': profile,
  133. 'name_changes': name_changes,
  134. 'page_number': name_changes.number,
  135. 'items_left': items_left
  136. })
  137. @profile_view_restricted_visibility
  138. def user_ban(request, profile):
  139. ban = get_user_ban(profile)
  140. if not ban:
  141. raise Http404()
  142. return render(request, 'misago/profile/ban_details.html', {
  143. 'profile': profile,
  144. 'ban': ban
  145. })
  146. """
  147. Profile actions
  148. """
  149. def action_view(f):
  150. @deny_guests
  151. @require_POST
  152. @profile_view
  153. @atomic
  154. def decorator(request, profile):
  155. response = f(request, profile.lock())
  156. if request.is_ajax():
  157. response['is_error'] = False
  158. return JsonResponse(response)
  159. else:
  160. messages.success(request, response['message'])
  161. return_path = clean_return_path(request)
  162. if return_path:
  163. return redirect(return_path)
  164. else:
  165. return redirect(user_profile.get_default_link(),
  166. user_slug=profile.slug, user_id=profile.id)
  167. return decorator
  168. @action_view
  169. def follow_user(request, profile):
  170. user_locked = request.user.lock()
  171. if request.user.is_following(profile):
  172. request.user.follows.remove(profile)
  173. followed = False
  174. else:
  175. followed = True
  176. request.user.follows.add(profile)
  177. profile.followers = profile.followed_by.count()
  178. profile.save(update_fields=['followers'])
  179. user_locked.following = user_locked.follows.count()
  180. user_locked.save(update_fields=['following'])
  181. if followed:
  182. message = _("You are now following %(user)s.")
  183. else:
  184. message = _("You have stopped following %(user)s.")
  185. message = message % {'user': profile.username}
  186. if request.is_ajax:
  187. return {'is_following': followed, 'message': message}
  188. else:
  189. messages.success(request, message)
  190. @action_view
  191. def block_user(request, profile):
  192. user_locked = request.user.lock()
  193. if request.user.is_blocking(profile):
  194. request.user.blocks.remove(profile)
  195. blocked = False
  196. else:
  197. blocked = True
  198. request.user.blocks.add(profile)
  199. if blocked:
  200. message = _("You are now blocking %(user)s.")
  201. else:
  202. message = _("You have stopped blocking %(user)s.")
  203. message = message % {'user': profile.username}
  204. if request.is_ajax:
  205. return {'is_blocking': blocked, 'message': message}
  206. else:
  207. messages.success(request, message)