1 from django.contrib.auth.decorators import login_required
\r
2 from forum.models import User
\r
3 from django.db.models import Q, Count
\r
4 from django.core.paginator import Paginator, EmptyPage, InvalidPage
\r
5 from django.template.defaultfilters import slugify
\r
6 from django.contrib.contenttypes.models import ContentType
\r
7 from django.core.urlresolvers import reverse
\r
8 from django.shortcuts import render_to_response, get_object_or_404
\r
9 from django.template import RequestContext
\r
10 from django.http import HttpResponse, HttpResponseRedirect, Http404
\r
11 from forum.http_responses import HttpResponseUnauthorized
\r
12 from django.utils.translation import ugettext as _
\r
13 from django.utils.http import urlquote_plus
\r
14 from django.utils.html import strip_tags
\r
15 from django.utils import simplejson
\r
16 from django.core.urlresolvers import reverse, NoReverseMatch
\r
17 from forum.forms import *
\r
18 from forum.utils.html import sanitize_html
\r
19 from forum.modules import decorate
\r
20 from datetime import datetime, date
\r
22 from forum.actions import EditProfileAction, FavoriteAction, BonusRepAction, SuspendAction
\r
23 from forum.modules import ui
\r
28 USERS_PAGE_SIZE = 35# refactor - move to some constants file
\r
30 @decorators.render('users/users.html', 'users', _('users'), weight=200)
\r
33 sortby = request.GET.get('sort', 'reputation')
\r
34 suser = request.REQUEST.get('q', "")
\r
36 page = int(request.GET.get('page', '1'))
\r
41 if sortby == "newest":
\r
42 objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE)
\r
43 elif sortby == "last":
\r
44 objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE)
\r
45 elif sortby == "user":
\r
46 objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE)
\r
49 objects_list = Paginator(User.objects.all().order_by('-is_active', '-reputation'), USERS_PAGE_SIZE)
\r
50 base_url = reverse('users') + '?sort=%s&' % sortby
\r
52 sortby = "reputation"
\r
53 objects_list = Paginator(User.objects.filter(username__icontains=suser).order_by('-reputation'), USERS_PAGE_SIZE
\r
55 base_url = reverse('users') + '?name=%s&sort=%s&' % (suser, sortby)
\r
58 users = objects_list.page(page)
\r
59 except (EmptyPage, InvalidPage):
\r
60 users = objects_list.page(objects_list.num_pages)
\r
68 'is_paginated' : is_paginated,
\r
69 'pages': objects_list.num_pages,
\r
71 'has_previous': users.has_previous(),
\r
72 'has_next': users.has_next(),
\r
73 'previous': users.previous_page_number(),
\r
74 'next': users.next_page_number(),
\r
75 'base_url' : base_url
\r
81 def edit_user(request, id):
\r
82 user = get_object_or_404(User, id=id)
\r
83 if not (request.user.is_superuser or request.user == user):
\r
84 return HttpResponseUnauthorized(request)
\r
85 if request.method == "POST":
\r
86 form = EditUserForm(user, request.POST)
\r
88 new_email = sanitize_html(form.cleaned_data['email'])
\r
90 if new_email != user.email:
\r
91 user.email = new_email
\r
92 user.email_isvalid = False
\r
94 if settings.EDITABLE_SCREEN_NAME:
\r
95 user.username = sanitize_html(form.cleaned_data['username'])
\r
96 user.real_name = sanitize_html(form.cleaned_data['realname'])
\r
97 user.website = sanitize_html(form.cleaned_data['website'])
\r
98 user.location = sanitize_html(form.cleaned_data['city'])
\r
99 user.date_of_birth = form.cleaned_data['birthday']
\r
100 if user.date_of_birth == "None":
\r
101 user.date_of_birth = datetime(1900, 1, 1, 0, 0)
\r
102 user.about = sanitize_html(form.cleaned_data['about'])
\r
105 EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()
\r
107 request.user.message_set.create(message=_("Profile updated."))
\r
108 return HttpResponseRedirect(user.get_profile_url())
\r
110 form = EditUserForm(user)
\r
111 return render_to_response('users/edit.html', {
\r
114 'gravatar_faq_url' : reverse('faq') + '#gravatar',
\r
115 }, context_instance=RequestContext(request))
\r
119 def user_powers(request, id, action, status):
\r
120 if not request.user.is_superuser:
\r
121 return HttpResponseUnauthorized(request)
\r
123 user = get_object_or_404(User, id=id)
\r
124 new_state = action == 'grant'
\r
126 if status == 'super':
\r
127 user.is_superuser = new_state
\r
128 elif status == 'staff':
\r
129 user.is_staff = new_state
\r
134 return HttpResponseRedirect(user.get_profile_url())
\r
137 @decorate.withfn(decorators.command)
\r
138 def award_points(request, id):
\r
139 if (not request.POST) and request.POST.get('points', None):
\r
140 raise decorators.CommandException(_("Invalid request type"))
\r
142 if not request.user.is_superuser:
\r
143 raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))
\r
145 user = get_object_or_404(User, id=id)
\r
146 points = int(request.POST['points'])
\r
148 extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)
\r
150 BonusRepAction(user=request.user, extra=extra).save(data=dict(value=points, affected=user))
\r
152 return dict(reputation=user.reputation)
\r
155 @decorate.withfn(decorators.command)
\r
156 def suspend(request, id):
\r
157 user = get_object_or_404(User, id=id)
\r
159 if not request.user.is_superuser:
\r
160 raise decorators.CommandException(_("Only superusers can suspend other users"))
\r
162 if not request.POST:
\r
163 if user.is_suspended():
\r
164 suspension = user.suspension
\r
165 suspension.cancel(user=request.user, ip=request.META['REMOTE_ADDR'])
\r
166 return decorators.RefreshPageCommand()
\r
168 return render_to_response('users/suspend_user.html')
\r
171 'bantype': request.POST.get('bantype', 'indefinetly').strip(),
\r
172 'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),
\r
173 'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),
\r
177 if data['bantype'] == 'forxdays':
\r
179 data['forxdays'] = int(request.POST['forxdays'])
\r
181 raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))
\r
183 SuspendAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=data)
\r
185 return decorators.RefreshPageCommand()
\r
188 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, render_to=None, weight=500):
\r
190 def decorated(fn, request, id, slug=None):
\r
191 user = get_object_or_404(User, id=id)
\r
192 if private and not (user == request.user or request.user.is_superuser):
\r
193 return HttpResponseUnauthorized(request)
\r
194 context = fn(request, user)
\r
196 rev_page_title = user.username + " - " + tab_description
\r
199 "active_tab" : tab_name,
\r
200 "tab_description" : tab_description,
\r
201 "page_title" : rev_page_title,
\r
202 "can_view_private": (user == request.user) or request.user.is_superuser
\r
204 return render_to_response(template, context, context_instance=RequestContext(request))
\r
207 def url_getter(vu):
\r
209 return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})
\r
210 except NoReverseMatch:
\r
211 return reverse(fn.__name__, kwargs={'id': vu.id})
\r
213 ui.register(ui.PROFILE_TABS, ui.ProfileTab(
\r
214 tab_name, tab_title, tab_description,url_getter, private, render_to, weight
\r
217 return decorate.withfn(decorated)(fn)
\r
221 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))
\r
222 def user_profile(request, user):
\r
223 questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')
\r
224 answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')
\r
226 up_votes = user.vote_up_count
\r
227 down_votes = user.vote_down_count
\r
228 votes_today = user.get_vote_count_today()
\r
229 votes_total = int(settings.MAX_VOTES_PER_DAY)
\r
231 user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \
\r
232 .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')
\r
234 awards = [(Badge.objects.get(id=b['id']), b['count']) for b in
\r
235 Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]
\r
238 "view_user" : user,
\r
239 "questions" : questions,
\r
240 "answers" : answers,
\r
241 "up_votes" : up_votes,
\r
242 "down_votes" : down_votes,
\r
243 "total_votes": up_votes + down_votes,
\r
244 "votes_today_left": votes_total-votes_today,
\r
245 "votes_total_per_day": votes_total,
\r
246 "user_tags" : user_tags[:50],
\r
248 "total_awards" : len(awards),
\r
251 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))
\r
252 def user_recent(request, user):
\r
253 activities = user.actions.exclude(
\r
254 action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(
\r
255 '-action_date')[:USERS_PAGE_SIZE]
\r
257 return {"view_user" : user, "activities" : activities}
\r
260 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))
\r
261 def user_reputation(request, user):
\r
262 rep = list(user.reputes.order_by('date'))
\r
263 values = [r.value for r in rep]
\r
264 redux = lambda x, y: x+y
\r
266 graph_data = simplejson.dumps([
\r
267 (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))
\r
268 for i in range(len(values))
\r
271 rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]
\r
273 return {"view_user": user, "reputation": rep, "graph_data": graph_data}
\r
275 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)
\r
276 def user_votes(request, user):
\r
277 votes = user.votes.exclude(node__state_string__contains="(deleted").filter(
\r
278 node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]
\r
280 return {"view_user" : user, "votes" : votes}
\r
282 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))
\r
283 def user_favorites(request, user):
\r
284 favorites = FavoriteAction.objects.filter(canceled=False, user=user)
\r
286 return {"favorites" : favorites, "view_user" : user}
\r
288 @user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('subscriptions'), True, tabbed=False)
\r
289 def user_subscriptions(request, user):
\r
290 if request.method == 'POST':
\r
291 form = SubscriptionSettingsForm(data=request.POST, instance=user.subscription_settings)
\r
293 if form.is_valid():
\r
294 if form.cleaned_data['user'] != user.id:
\r
295 return HttpResponseUnauthorized(request)
\r
297 if 'notswitch' in request.POST:
\r
298 user.subscription_settings.enable_notifications = not user.subscription_settings.enable_notifications
\r
299 user.subscription_settings.save()
\r
301 if user.subscription_settings.enable_notifications:
\r
302 request.user.message_set.create(message=_('Notifications are now enabled'))
\r
304 request.user.message_set.create(message=_('Notifications are now disabled'))
\r
307 request.user.message_set.create(message=_('New subscription settings are now saved'))
\r
311 form = SubscriptionSettingsForm(instance=user.subscription_settings)
\r
313 notificatons_on = user.subscription_settings.enable_notifications
\r
315 return {'view_user':user, 'notificatons_on': notificatons_on, 'form':form}
\r
318 def account_settings(request):
\r
320 msg = request.GET.get('msg', '')
\r
323 return render_to_response('account_settings.html', {
\r
325 'is_openid': is_openid
\r
326 }, context_instance=RequestContext(request))
\r