]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
More polished PAI for module html injection and added a couple more places to inject...
[osqa.git] / forum / views / users.py
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 datetime import datetime, date\r
20 import decorators\r
21 from forum.actions import EditProfileAction, FavoriteAction, BonusRepAction, SuspendAction\r
22 from forum.modules import ui\r
23 \r
24 import time\r
25 import decorators\r
26 \r
27 USERS_PAGE_SIZE = 35# refactor - move to some constants file\r
28 \r
29 @decorators.render('users/users.html', 'users', _('users'), weight=200)\r
30 def users(request):\r
31     is_paginated = True\r
32     sortby = request.GET.get('sort', 'reputation')\r
33     suser = request.REQUEST.get('q', "")\r
34     try:\r
35         page = int(request.GET.get('page', '1'))\r
36     except ValueError:\r
37         page = 1\r
38 \r
39     if suser == "":\r
40         if sortby == "newest":\r
41             objects_list = Paginator(User.objects.all().order_by('-date_joined'), USERS_PAGE_SIZE)\r
42         elif sortby == "last":\r
43             objects_list = Paginator(User.objects.all().order_by('date_joined'), USERS_PAGE_SIZE)\r
44         elif sortby == "user":\r
45             objects_list = Paginator(User.objects.all().order_by('username'), USERS_PAGE_SIZE)\r
46         # default\r
47         else:\r
48             objects_list = Paginator(User.objects.all().order_by('-is_active', '-reputation'), USERS_PAGE_SIZE)\r
49         base_url = reverse('users') + '?sort=%s&' % sortby\r
50     else:\r
51         sortby = "reputation"\r
52         objects_list = Paginator(User.objects.filter(username__icontains=suser).order_by('-reputation'), USERS_PAGE_SIZE\r
53                                  )\r
54         base_url = reverse('users') + '?name=%s&sort=%s&' % (suser, sortby)\r
55 \r
56     try:\r
57         users = objects_list.page(page)\r
58     except (EmptyPage, InvalidPage):\r
59         users = objects_list.page(objects_list.num_pages)\r
60 \r
61     return {\r
62         "users" : users,\r
63         "suser" : suser,\r
64         "keywords" : suser,\r
65         "tab_id" : sortby,\r
66         "context" : {\r
67             'is_paginated' : is_paginated,\r
68             'pages': objects_list.num_pages,\r
69             'page': page,\r
70             'has_previous': users.has_previous(),\r
71             'has_next': users.has_next(),\r
72             'previous': users.previous_page_number(),\r
73             'next': users.next_page_number(),\r
74             'base_url' : base_url\r
75         }\r
76     }\r
77 \r
78 def set_new_email(user, new_email, nomessage=False):\r
79     if new_email != user.email:\r
80         user.email = new_email\r
81         user.email_isvalid = False\r
82         user.save()\r
83     #if settings.EMAIL_VALIDATION == 'on':\r
84     #    send_new_email_key(user,nomessage=nomessage)\r
85 \r
86 @login_required\r
87 def edit_user(request, id):\r
88     user = get_object_or_404(User, id=id)\r
89     if not (request.user.is_superuser or request.user == user):\r
90         return HttpResponseUnauthorized(request)\r
91     if request.method == "POST":\r
92         form = EditUserForm(user, request.POST)\r
93         if form.is_valid():\r
94             new_email = sanitize_html(form.cleaned_data['email'])\r
95 \r
96             set_new_email(user, new_email)\r
97 \r
98             if settings.EDITABLE_SCREEN_NAME:\r
99                 user.username = sanitize_html(form.cleaned_data['username'])\r
100             user.real_name = sanitize_html(form.cleaned_data['realname'])\r
101             user.website = sanitize_html(form.cleaned_data['website'])\r
102             user.location = sanitize_html(form.cleaned_data['city'])\r
103             user.date_of_birth = form.cleaned_data['birthday']\r
104             if user.date_of_birth == "None":\r
105                 user.date_of_birth = datetime(1900, 1, 1, 0, 0)\r
106             user.about = sanitize_html(form.cleaned_data['about'])\r
107 \r
108             user.save()\r
109             EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()\r
110 \r
111             return HttpResponseRedirect(user.get_profile_url())\r
112     else:\r
113         form = EditUserForm(user)\r
114     return render_to_response('users/edit.html', {\r
115     'user': user,\r
116     'form' : form,\r
117     'gravatar_faq_url' : reverse('faq') + '#gravatar',\r
118     }, context_instance=RequestContext(request))\r
119 \r
120 \r
121 @login_required\r
122 def user_powers(request, id, action, status):\r
123     if not request.user.is_superuser:\r
124         return HttpResponseUnauthorized(request)\r
125 \r
126     user = get_object_or_404(User, id=id)\r
127     new_state = action == 'grant'\r
128 \r
129     if status == 'super':\r
130         user.is_superuser = new_state\r
131     elif status == 'staff':\r
132         user.is_staff = new_state\r
133     else:\r
134         raise Http404()\r
135 \r
136     user.save()\r
137     return HttpResponseRedirect(user.get_profile_url())\r
138 \r
139 \r
140 @decorators.command\r
141 def award_points(request, id):\r
142     if (not request.POST) and request.POST.get('points', None):\r
143         raise decorators.CommandException(_("Invalid request type"))\r
144 \r
145     if not request.user.is_superuser:\r
146         raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
147 \r
148     user = get_object_or_404(User, id=id)\r
149     points = int(request.POST['points'])\r
150 \r
151     extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
152 \r
153     BonusRepAction(user=user, extra=extra).save(data=dict(value=points))\r
154 \r
155     return dict(reputation=user.reputation)\r
156 \r
157 \r
158 @decorators.command\r
159 def suspend(request, id):\r
160     user = get_object_or_404(User, id=id)\r
161 \r
162     if not request.POST:\r
163         if user.is_suspended():\r
164             suspension = user.suspension\r
165             suspension.cancel(ip=request.META['REMOTE_ADDR'])\r
166             return decorators.RefreshPageCommand()\r
167         else:\r
168             return render_to_response('users/suspend_user.html')\r
169 \r
170     if not request.user.is_superuser:\r
171         raise decorators.CommandException(_("Only superusers can ban other users"))\r
172 \r
173     data = {\r
174     'bantype': request.POST.get('bantype', 'indefinetly').strip(),\r
175     'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),\r
176     'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),\r
177     'suspender': request.user.id\r
178     }\r
179 \r
180     if data['bantype'] == 'forxdays':\r
181         try:\r
182             data['forxdays'] = int(request.POST['forxdays'])\r
183         except:\r
184             raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))\r
185 \r
186     SuspendAction(user=user, ip=request.META['REMOTE_ADDR']).save(data=data)\r
187 \r
188     return decorators.RefreshPageCommand()\r
189 \r
190 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, weight=500):\r
191     def decorator(fn):\r
192         def decorated(request, id, slug=None):\r
193             user = get_object_or_404(User, id=id)\r
194             if private and not (user == request.user or request.user.is_superuser):\r
195                 return HttpResponseUnauthorized(request)\r
196             context = fn(request, user)\r
197 \r
198             rev_page_title = user.username + " - " + tab_description\r
199 \r
200             context.update({\r
201             "active_tab" : tab_name,\r
202             "tab_description" : tab_description,\r
203             "page_title" : rev_page_title,\r
204             "can_view_private": (user == request.user) or request.user.is_superuser\r
205             })\r
206             return render_to_response(template, context, context_instance=RequestContext(request))\r
207 \r
208         if tabbed:\r
209             def url_getter(vu):\r
210                 try:\r
211                     return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})\r
212                 except NoReverseMatch:\r
213                     return reverse(fn.__name__, kwargs={'id': vu.id})\r
214 \r
215             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
216                 tab_name, tab_title, tab_description,url_getter, private, weight\r
217             ))\r
218 \r
219         return decorated\r
220 \r
221     return decorator\r
222 \r
223 \r
224 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))\r
225 def user_profile(request, user):\r
226     questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
227     answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
228 \r
229     up_votes = user.vote_up_count\r
230     down_votes = user.vote_down_count\r
231     votes_today = user.get_vote_count_today()\r
232     votes_total = int(settings.MAX_VOTES_PER_DAY)\r
233 \r
234     user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
235         .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
236 \r
237     awards = [(Badge.objects.get(id=b['id']), b['count']) for b in\r
238               Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]\r
239 \r
240     return {\r
241     "view_user" : user,\r
242     "questions" : questions,\r
243     "answers" : answers,\r
244     "up_votes" : up_votes,\r
245     "down_votes" : down_votes,\r
246     "total_votes": up_votes + down_votes,\r
247     "votes_today_left": votes_total-votes_today,\r
248     "votes_total_per_day": votes_total,\r
249     "user_tags" : user_tags[:50],\r
250     "awards": awards,\r
251     "total_awards" : len(awards),\r
252     }\r
253 \r
254 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))\r
255 def user_recent(request, user):\r
256     activities = user.actions.exclude(\r
257             action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(\r
258             '-action_date')[:USERS_PAGE_SIZE]\r
259 \r
260     return {"view_user" : user, "activities" : activities}\r
261 \r
262 \r
263 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))\r
264 def user_reputation(request, user):\r
265     rep = list(user.reputes.order_by('date'))\r
266     values = [r.value for r in rep]\r
267     redux = lambda x, y: x+y\r
268 \r
269     graph_data = simplejson.dumps([\r
270     (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))\r
271     for i in range(len(values))\r
272     ])\r
273 \r
274     rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]\r
275 \r
276     return {"view_user": user, "reputation": rep, "graph_data": graph_data}\r
277 \r
278 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)\r
279 def user_votes(request, user):\r
280     votes = user.votes.exclude(node__state_string__contains="(deleted").filter(\r
281             node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
282 \r
283     return {"view_user" : user, "votes" : votes}\r
284 \r
285 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))\r
286 def user_favorites(request, user):\r
287     favorites = FavoriteAction.objects.filter(canceled=False, user=user)\r
288 \r
289     return {"favorites" : favorites, "view_user" : user}\r
290 \r
291 @user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('subscriptions'), True, tabbed=False)\r
292 def user_subscriptions(request, user):\r
293     if request.method == 'POST':\r
294         form = SubscriptionSettingsForm(request.POST)\r
295 \r
296         if 'notswitch' in request.POST:\r
297             user.subscription_settings.enable_notifications = not user.subscription_settings.enable_notifications\r
298             user.subscription_settings.save()\r
299 \r
300             if user.subscription_settings.enable_notifications:\r
301                 request.user.message_set.create(message=_('Notifications are now enabled'))\r
302             else:\r
303                 request.user.message_set.create(message=_('Notifications are now disabled'))\r
304 \r
305         form.is_valid()\r
306         for k, v in form.cleaned_data.items():\r
307             setattr(user.subscription_settings, k, v)\r
308 \r
309         user.subscription_settings.save()\r
310         request.user.message_set.create(message=_('New subscription settings are now saved'))\r
311     else:\r
312         form = SubscriptionSettingsForm(user.subscription_settings.__dict__)\r
313 \r
314     notificatons_on = user.subscription_settings.enable_notifications\r
315 \r
316     return {'view_user':user, 'notificatons_on': notificatons_on, 'form':form}\r
317 \r
318 @login_required\r
319 def account_settings(request):\r
320     logging.debug('')\r
321     msg = request.GET.get('msg', '')\r
322     is_openid = False\r
323 \r
324     return render_to_response('account_settings.html', {\r
325     'msg': msg,\r
326     'is_openid': is_openid\r
327     }, context_instance=RequestContext(request))\r
328 \r