profile.py 10 KB

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