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