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(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
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(request.POST)
\r
293 if 'notswitch' in request.POST:
\r
294 user.subscription_settings.enable_notifications = not user.subscription_settings.enable_notifications
\r
295 user.subscription_settings.save()
\r
297 if user.subscription_settings.enable_notifications:
\r
298 request.user.message_set.create(message=_('Notifications are now enabled'))
\r
300 request.user.message_set.create(message=_('Notifications are now disabled'))
\r
303 for k, v in form.cleaned_data.items():
\r
304 setattr(user.subscription_settings, k, v)
\r
306 user.subscription_settings.save()
\r
307 request.user.message_set.create(message=_('New subscription settings are now saved'))
\r
309 form = SubscriptionSettingsForm(user.subscription_settings.__dict__)
\r
311 notificatons_on = user.subscription_settings.enable_notifications
\r
313 return {'view_user':user, 'notificatons_on': notificatons_on, 'form':form}
\r
316 def account_settings(request):
\r
318 msg = request.GET.get('msg', '')
\r
321 return render_to_response('account_settings.html', {
\r
323 'is_openid': is_openid
\r
324 }, context_instance=RequestContext(request))
\r