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=user, extra=extra).save(data=dict(value=points))
\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.POST:
\r
160 if user.is_suspended():
\r
161 suspension = user.suspension
\r
162 suspension.cancel(ip=request.META['REMOTE_ADDR'])
\r
163 return decorators.RefreshPageCommand()
\r
165 return render_to_response('users/suspend_user.html')
\r
167 if not request.user.is_superuser:
\r
168 raise decorators.CommandException(_("Only superusers can ban other users"))
\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
174 'suspender': request.user.id
\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=user, ip=request.META['REMOTE_ADDR']).save(data=data)
\r
185 return decorators.RefreshPageCommand()
\r
187 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, weight=500):
\r
189 def decorated(fn, request, id, slug=None):
\r
190 user = get_object_or_404(User, id=id)
\r
191 if private and not (user == request.user or request.user.is_superuser):
\r
192 return HttpResponseUnauthorized(request)
\r
193 context = fn(request, user)
\r
195 rev_page_title = user.username + " - " + tab_description
\r
198 "active_tab" : tab_name,
\r
199 "tab_description" : tab_description,
\r
200 "page_title" : rev_page_title,
\r
201 "can_view_private": (user == request.user) or request.user.is_superuser
\r
203 return render_to_response(template, context, context_instance=RequestContext(request))
\r
206 def url_getter(vu):
\r
208 return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})
\r
209 except NoReverseMatch:
\r
210 return reverse(fn.__name__, kwargs={'id': vu.id})
\r
212 ui.register(ui.PROFILE_TABS, ui.ProfileTab(
\r
213 tab_name, tab_title, tab_description,url_getter, private, weight
\r
216 return decorate.withfn(decorated)(fn)
\r
220 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))
\r
221 def user_profile(request, user):
\r
222 questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')
\r
223 answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')
\r
225 up_votes = user.vote_up_count
\r
226 down_votes = user.vote_down_count
\r
227 votes_today = user.get_vote_count_today()
\r
228 votes_total = int(settings.MAX_VOTES_PER_DAY)
\r
230 user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \
\r
231 .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')
\r
233 awards = [(Badge.objects.get(id=b['id']), b['count']) for b in
\r
234 Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]
\r
237 "view_user" : user,
\r
238 "questions" : questions,
\r
239 "answers" : answers,
\r
240 "up_votes" : up_votes,
\r
241 "down_votes" : down_votes,
\r
242 "total_votes": up_votes + down_votes,
\r
243 "votes_today_left": votes_total-votes_today,
\r
244 "votes_total_per_day": votes_total,
\r
245 "user_tags" : user_tags[:50],
\r
247 "total_awards" : len(awards),
\r
250 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))
\r
251 def user_recent(request, user):
\r
252 activities = user.actions.exclude(
\r
253 action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(
\r
254 '-action_date')[:USERS_PAGE_SIZE]
\r
256 return {"view_user" : user, "activities" : activities}
\r
259 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))
\r
260 def user_reputation(request, user):
\r
261 rep = list(user.reputes.order_by('date'))
\r
262 values = [r.value for r in rep]
\r
263 redux = lambda x, y: x+y
\r
265 graph_data = simplejson.dumps([
\r
266 (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))
\r
267 for i in range(len(values))
\r
270 rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]
\r
272 return {"view_user": user, "reputation": rep, "graph_data": graph_data}
\r
274 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)
\r
275 def user_votes(request, user):
\r
276 votes = user.votes.exclude(node__state_string__contains="(deleted").filter(
\r
277 node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]
\r
279 return {"view_user" : user, "votes" : votes}
\r
281 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))
\r
282 def user_favorites(request, user):
\r
283 favorites = FavoriteAction.objects.filter(canceled=False, user=user)
\r
285 return {"favorites" : favorites, "view_user" : user}
\r
287 @user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('subscriptions'), True, tabbed=False)
\r
288 def user_subscriptions(request, user):
\r
289 if request.method == 'POST':
\r
290 form = SubscriptionSettingsForm(request.POST)
\r
292 if 'notswitch' in request.POST:
\r
293 user.subscription_settings.enable_notifications = not user.subscription_settings.enable_notifications
\r
294 user.subscription_settings.save()
\r
296 if user.subscription_settings.enable_notifications:
\r
297 request.user.message_set.create(message=_('Notifications are now enabled'))
\r
299 request.user.message_set.create(message=_('Notifications are now disabled'))
\r
302 for k, v in form.cleaned_data.items():
\r
303 setattr(user.subscription_settings, k, v)
\r
305 user.subscription_settings.save()
\r
306 request.user.message_set.create(message=_('New subscription settings are now saved'))
\r
308 form = SubscriptionSettingsForm(user.subscription_settings.__dict__)
\r
310 notificatons_on = user.subscription_settings.enable_notifications
\r
312 return {'view_user':user, 'notificatons_on': notificatons_on, 'form':form}
\r
315 def account_settings(request):
\r
317 msg = request.GET.get('msg', '')
\r
320 return render_to_response('account_settings.html', {
\r
322 'is_openid': is_openid
\r
323 }, context_instance=RequestContext(request))
\r