]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
Adapts user views to a more manageable decoration schema.
[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 @login_required\r
119 def user_powers(request, id, action, status):\r
120     if not request.user.is_superuser:\r
121         return HttpResponseUnauthorized(request)\r
122 \r
123     user = get_object_or_404(User, id=id)\r
124     new_state = action == 'grant'\r
125 \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
130     else:\r
131         raise Http404()\r
132 \r
133     user.save()\r
134     return HttpResponseRedirect(user.get_profile_url())\r
135 \r
136 \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
141 \r
142     if not request.user.is_superuser:\r
143         raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
144 \r
145     user = get_object_or_404(User, id=id)\r
146     points = int(request.POST['points'])\r
147 \r
148     extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
149 \r
150     BonusRepAction(user=user, extra=extra).save(data=dict(value=points))\r
151 \r
152     return dict(reputation=user.reputation)\r
153 \r
154 \r
155 @decorate.withfn(decorators.command)\r
156 def suspend(request, id):\r
157     user = get_object_or_404(User, id=id)\r
158 \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
164         else:\r
165             return render_to_response('users/suspend_user.html')\r
166 \r
167     if not request.user.is_superuser:\r
168         raise decorators.CommandException(_("Only superusers can ban other users"))\r
169 \r
170     data = {\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
175     }\r
176 \r
177     if data['bantype'] == 'forxdays':\r
178         try:\r
179             data['forxdays'] = int(request.POST['forxdays'])\r
180         except:\r
181             raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))\r
182 \r
183     SuspendAction(user=user, ip=request.META['REMOTE_ADDR']).save(data=data)\r
184 \r
185     return decorators.RefreshPageCommand()\r
186 \r
187 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, weight=500):\r
188     def decorator(fn):\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
194 \r
195             rev_page_title = user.username + " - " + tab_description\r
196 \r
197             context.update({\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
202             })\r
203             return render_to_response(template, context, context_instance=RequestContext(request))\r
204 \r
205         if tabbed:\r
206             def url_getter(vu):\r
207                 try:\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
211 \r
212             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
213                 tab_name, tab_title, tab_description,url_getter, private, weight\r
214             ))\r
215 \r
216         return decorate.withfn(decorated)(fn)\r
217     return decorator\r
218 \r
219 \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
224 \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
229 \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
232 \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
235 \r
236     return {\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
246     "awards": awards,\r
247     "total_awards" : len(awards),\r
248     }\r
249     \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
255 \r
256     return {"view_user" : user, "activities" : activities}\r
257 \r
258 \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
264 \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
268     ])\r
269 \r
270     rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]\r
271 \r
272     return {"view_user": user, "reputation": rep, "graph_data": graph_data}\r
273 \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
278 \r
279     return {"view_user" : user, "votes" : votes}\r
280 \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
284 \r
285     return {"favorites" : favorites, "view_user" : user}\r
286 \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
291 \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
295 \r
296             if user.subscription_settings.enable_notifications:\r
297                 request.user.message_set.create(message=_('Notifications are now enabled'))\r
298             else:\r
299                 request.user.message_set.create(message=_('Notifications are now disabled'))\r
300 \r
301         form.is_valid()\r
302         for k, v in form.cleaned_data.items():\r
303             setattr(user.subscription_settings, k, v)\r
304 \r
305         user.subscription_settings.save()\r
306         request.user.message_set.create(message=_('New subscription settings are now saved'))\r
307     else:\r
308         form = SubscriptionSettingsForm(user.subscription_settings.__dict__)\r
309 \r
310     notificatons_on = user.subscription_settings.enable_notifications\r
311 \r
312     return {'view_user':user, 'notificatons_on': notificatons_on, 'form':form}\r
313 \r
314 @login_required\r
315 def account_settings(request):\r
316     logging.debug('')\r
317     msg = request.GET.get('msg', '')\r
318     is_openid = False\r
319 \r
320     return render_to_response('account_settings.html', {\r
321     'msg': msg,\r
322     'is_openid': is_openid\r
323     }, context_instance=RequestContext(request))\r
324 \r