]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
Adds the user menu to the injectable places, makes several improvements in the user...
[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             context = fn(request, user)\r
204 \r
205             rev_page_title = user.username + " - " + tab_description\r
206 \r
207             context.update({\r
208             "tab": "users",\r
209             "active_tab" : tab_name,\r
210             "tab_description" : tab_description,\r
211             "page_title" : rev_page_title,\r
212             "can_view_private": (user == request.user) or request.user.is_superuser\r
213             })\r
214             return render_to_response(template, context, context_instance=RequestContext(request))\r
215 \r
216         if tabbed:\r
217             def url_getter(vu):\r
218                 try:\r
219                     return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})\r
220                 except NoReverseMatch:\r
221                     return reverse(fn.__name__, kwargs={'id': vu.id})\r
222 \r
223             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
224                 tab_name, tab_title, tab_description,url_getter, private, render_to, weight\r
225             ))\r
226 \r
227         return decorate.withfn(decorated)(fn)\r
228     return decorator\r
229 \r
230 \r
231 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))\r
232 def user_profile(request, user):\r
233     questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
234     answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
235 \r
236     up_votes = user.vote_up_count\r
237     down_votes = user.vote_down_count\r
238     votes_today = user.get_vote_count_today()\r
239     votes_total = int(settings.MAX_VOTES_PER_DAY)\r
240 \r
241     user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
242         .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
243 \r
244     awards = [(Badge.objects.get(id=b['id']), b['count']) for b in\r
245               Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]\r
246 \r
247     return {\r
248     "view_user" : user,\r
249     "questions" : questions,\r
250     "answers" : answers,\r
251     "up_votes" : up_votes,\r
252     "down_votes" : down_votes,\r
253     "total_votes": up_votes + down_votes,\r
254     "votes_today_left": votes_total-votes_today,\r
255     "votes_total_per_day": votes_total,\r
256     "user_tags" : user_tags[:50],\r
257     "awards": awards,\r
258     "total_awards" : len(awards),\r
259     }\r
260     \r
261 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))\r
262 def user_recent(request, user):\r
263     activities = user.actions.exclude(\r
264             action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(\r
265             '-action_date')[:USERS_PAGE_SIZE]\r
266 \r
267     return {"view_user" : user, "activities" : activities}\r
268 \r
269 \r
270 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))\r
271 def user_reputation(request, user):\r
272     rep = list(user.reputes.order_by('date'))\r
273     values = [r.value for r in rep]\r
274     redux = lambda x, y: x+y\r
275 \r
276     graph_data = simplejson.dumps([\r
277     (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))\r
278     for i in range(len(values))\r
279     ])\r
280 \r
281     rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]\r
282 \r
283     return {"view_user": user, "reputation": rep, "graph_data": graph_data}\r
284 \r
285 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)\r
286 def user_votes(request, user):\r
287     votes = user.votes.exclude(node__state_string__contains="(deleted").filter(\r
288             node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
289 \r
290     return {"view_user" : user, "votes" : votes}\r
291 \r
292 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))\r
293 def user_favorites(request, user):\r
294     favorites = FavoriteAction.objects.filter(canceled=False, user=user)\r
295 \r
296     return {"favorites" : favorites, "view_user" : user}\r
297 \r
298 @user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('subscriptions'), True, tabbed=False)\r
299 def user_subscriptions(request, user):\r
300     enabled = user.subscription_settings.enable_notifications\r
301 \r
302     if request.method == 'POST':        \r
303         form = SubscriptionSettingsForm(data=request.POST, instance=user.subscription_settings)\r
304 \r
305         if form.is_valid():\r
306             form.save()\r
307             message = _('New subscription settings are now saved')\r
308 \r
309             if 'notswitch' in request.POST:\r
310                 enabled = not enabled\r
311 \r
312                 if enabled:\r
313                     message = _('Notifications are now enabled')\r
314                 else:\r
315                     message = _('Notifications are now disabled')\r
316 \r
317             user.subscription_settings.enable_notifications = enabled\r
318             user.subscription_settings.save()\r
319 \r
320             request.user.message_set.create(message=message)\r
321     else:\r
322         form = SubscriptionSettingsForm(instance=user.subscription_settings)\r
323 \r
324     return {'view_user':user, 'notificatons_on': enabled, 'form':form}\r
325 \r
326 @login_required\r
327 def account_settings(request):\r
328     logging.debug('')\r
329     msg = request.GET.get('msg', '')\r
330     is_openid = False\r
331 \r
332     return render_to_response('account_settings.html', {\r
333     'msg': msg,\r
334     'is_openid': is_openid\r
335     }, context_instance=RequestContext(request))\r
336 \r