profile.py 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  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.db.transaction import atomic
  5. from django.http import Http404, JsonResponse
  6. from django.shortcuts import get_object_or_404, redirect, render as django_render
  7. from django.urls import reverse
  8. from django.utils import six
  9. from django.utils.translation import ugettext as _
  10. from misago.acl import add_acl
  11. from misago.conf import settings
  12. from misago.core.decorators import require_POST
  13. from misago.core.shortcuts import paginate, pagination_dict, validate_slug
  14. from misago.core.utils import clean_return_path
  15. from misago.threads.permissions import allow_message_user
  16. from misago.users.bans import get_user_ban
  17. from misago.users.decorators import deny_guests
  18. from misago.users.online.utils import get_user_status
  19. from misago.users.pages import user_profile
  20. from misago.users.permissions.profiles import allow_block_user, allow_follow_user
  21. from misago.users.serializers import (
  22. BanDetailsSerializer, UserSerializer, UserCardSerializer, UsernameChangeSerializer)
  23. from misago.users.viewmodels import UserPosts, UserThreads
  24. UserModel = get_user_model()
  25. def profile_view(f):
  26. def decorator(request, *args, **kwargs):
  27. relations = ('rank', 'online_tracker', 'ban_cache')
  28. queryset = UserModel.objects.select_related(*relations)
  29. profile = get_object_or_404(queryset, pk=kwargs.pop('pk'))
  30. if not profile.is_active and not request.user.is_staff:
  31. raise Http404()
  32. validate_slug(profile, kwargs.pop('slug'))
  33. kwargs['profile'] = profile
  34. add_acl(request.user, profile)
  35. return f(request, *args, **kwargs)
  36. return decorator
  37. def profile_view_restricted_visibility(f):
  38. @profile_view
  39. def decorator(request, *args, **kwargs):
  40. sections = user_profile.get_sections(request, kwargs['profile'])
  41. for section in sections:
  42. if section['is_active']:
  43. return f(request, *args, **kwargs)
  44. else:
  45. # we are trying to display page thats not in nav
  46. raise Http404()
  47. return decorator
  48. def render(request, template, context):
  49. request.frontend_context['PROFILE_PAGES'] = []
  50. context['sections'] = user_profile.get_sections(request, context['profile'])
  51. for section in context['sections']:
  52. request.frontend_context['PROFILE_PAGES'].append({
  53. 'name': six.text_type(section['name']),
  54. 'icon': section['icon'],
  55. 'meta': section.get('metadata'),
  56. 'component': section['component'],
  57. })
  58. if section['is_active']:
  59. context['active_section'] = section
  60. if request.user.is_authenticated:
  61. is_authenticated_user = context['profile'].pk == request.user.pk
  62. else:
  63. is_authenticated_user = False
  64. context['is_authenticated_user'] = is_authenticated_user
  65. if request.user.is_authenticated:
  66. if is_authenticated_user:
  67. context['show_email'] = True
  68. else:
  69. context['show_email'] = request.user.acl['can_see_users_emails']
  70. else:
  71. context['show_email'] = False
  72. context['profile'].status = get_user_status(request.user, context['profile'])
  73. request.frontend_context['PROFILE'] = UserProfileSerializer(
  74. context['profile'], context={'user': request.user}).data
  75. if not context['profile'].is_active:
  76. request.frontend_context['PROFILE']['is_active'] = False
  77. return django_render(request, template, context)
  78. @profile_view
  79. def landing(request, profile):
  80. return redirect(user_profile.get_default_link(), slug=profile.slug, pk=profile.pk)
  81. @profile_view
  82. def posts(request, profile):
  83. context = {
  84. 'profile': profile,
  85. }
  86. feed = UserPosts(request, profile)
  87. context.update(feed.get_template_context())
  88. request.frontend_context['POSTS'] = feed.get_frontend_context()
  89. return render(request, 'misago/profile/posts.html', context)
  90. @profile_view
  91. def threads(request, profile):
  92. context = {
  93. 'profile': profile
  94. }
  95. feed = UserThreads(request, profile)
  96. context.update(feed.get_template_context())
  97. request.frontend_context['POSTS'] = feed.get_frontend_context()
  98. return render(request, 'misago/profile/threads.html', context)
  99. @profile_view
  100. def followers(request, profile):
  101. queryset = profile.followed_by.select_related('rank').order_by('slug')
  102. page = paginate(queryset, None, 12, 4)
  103. paginator = pagination_dict(page)
  104. request.frontend_context['PROFILE_FOLLOWERS'] = dict(
  105. results=UserCardSerializer(page.object_list, many=True).data,
  106. **paginator
  107. )
  108. return render(request, 'misago/profile/followers.html', {
  109. 'profile': profile,
  110. 'followers': page.object_list,
  111. 'count': paginator['count'],
  112. })
  113. @profile_view
  114. def follows(request, profile):
  115. queryset = profile.follows.select_related('rank').order_by('slug')
  116. page = paginate(queryset, None, settings.MISAGO_USERS_PER_PAGE, 4)
  117. paginator = pagination_dict(page)
  118. request.frontend_context['PROFILE_FOLLOWS'] = dict(
  119. results=UserCardSerializer(page.object_list, many=True).data,
  120. **paginator
  121. )
  122. return render(request, 'misago/profile/follows.html', {
  123. 'profile': profile,
  124. 'follows': page.object_list,
  125. 'count': paginator['count'],
  126. })
  127. @profile_view_restricted_visibility
  128. def username_history(request, profile):
  129. queryset = profile.namechanges.select_related('user', 'changed_by')
  130. queryset = queryset.order_by('-id')
  131. page = paginate(queryset, None, 14, 4)
  132. data = pagination_dict(page)
  133. data.update({
  134. 'results': UsernameChangeSerializer(page.object_list, many=True).data
  135. })
  136. request.frontend_context['PROFILE_NAME_HISTORY'] = data
  137. return render(request, 'misago/profile/username_history.html', {
  138. 'profile': profile,
  139. 'history': page.object_list,
  140. 'count': data['count'],
  141. })
  142. @profile_view_restricted_visibility
  143. def user_ban(request, profile):
  144. ban = get_user_ban(profile)
  145. request.frontend_context['PROFILE_BAN'] = BanDetailsSerializer(ban).data
  146. return render(request, 'misago/profile/ban_details.html', {
  147. 'profile': profile,
  148. 'ban': ban,
  149. })
  150. UserProfileSerializer = UserSerializer.subset_fields(
  151. 'id', 'username', 'slug', 'email', 'joined_on', 'rank', 'title', 'avatars',
  152. 'is_avatar_locked', 'signature', 'is_signature_locked', 'followers', 'following',
  153. 'threads', 'posts', 'acl', 'is_followed', 'is_blocked', 'status', 'absolute_url',
  154. 'api_url')