]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
Closes OSQA 175 and OSQA 318. Added a bunch of options to configure the email validat...
[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 \r
79 @login_required\r
80 def edit_user(request, id):\r
81     user = get_object_or_404(User, id=id)\r
82     if not (request.user.is_superuser or request.user == user):\r
83         return HttpResponseUnauthorized(request)\r
84     if request.method == "POST":\r
85         form = EditUserForm(user, request.POST)\r
86         if form.is_valid():\r
87             new_email = sanitize_html(form.cleaned_data['email'])\r
88 \r
89             if new_email != user.email:\r
90                 user.email = new_email\r
91                 user.email_isvalid = False\r
92 \r
93             if settings.EDITABLE_SCREEN_NAME:\r
94                 user.username = sanitize_html(form.cleaned_data['username'])\r
95             user.real_name = sanitize_html(form.cleaned_data['realname'])\r
96             user.website = sanitize_html(form.cleaned_data['website'])\r
97             user.location = sanitize_html(form.cleaned_data['city'])\r
98             user.date_of_birth = form.cleaned_data['birthday']\r
99             if user.date_of_birth == "None":\r
100                 user.date_of_birth = datetime(1900, 1, 1, 0, 0)\r
101             user.about = sanitize_html(form.cleaned_data['about'])\r
102 \r
103             user.save()\r
104             EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()\r
105 \r
106             request.user.message_set.create(message=_("Profile updated."))\r
107             return HttpResponseRedirect(user.get_profile_url())\r
108     else:\r
109         form = EditUserForm(user)\r
110     return render_to_response('users/edit.html', {\r
111     'user': user,\r
112     'form' : form,\r
113     'gravatar_faq_url' : reverse('faq') + '#gravatar',\r
114     }, context_instance=RequestContext(request))\r
115 \r
116 \r
117 @login_required\r
118 def user_powers(request, id, action, status):\r
119     if not request.user.is_superuser:\r
120         return HttpResponseUnauthorized(request)\r
121 \r
122     user = get_object_or_404(User, id=id)\r
123     new_state = action == 'grant'\r
124 \r
125     if status == 'super':\r
126         user.is_superuser = new_state\r
127     elif status == 'staff':\r
128         user.is_staff = new_state\r
129     else:\r
130         raise Http404()\r
131 \r
132     user.save()\r
133     return HttpResponseRedirect(user.get_profile_url())\r
134 \r
135 \r
136 @decorators.command\r
137 def award_points(request, id):\r
138     if (not request.POST) and request.POST.get('points', None):\r
139         raise decorators.CommandException(_("Invalid request type"))\r
140 \r
141     if not request.user.is_superuser:\r
142         raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
143 \r
144     user = get_object_or_404(User, id=id)\r
145     points = int(request.POST['points'])\r
146 \r
147     extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
148 \r
149     BonusRepAction(user=user, extra=extra).save(data=dict(value=points))\r
150 \r
151     return dict(reputation=user.reputation)\r
152 \r
153 \r
154 @decorators.command\r
155 def suspend(request, id):\r
156     user = get_object_or_404(User, id=id)\r
157 \r
158     if not request.POST:\r
159         if user.is_suspended():\r
160             suspension = user.suspension\r
161             suspension.cancel(ip=request.META['REMOTE_ADDR'])\r
162             return decorators.RefreshPageCommand()\r
163         else:\r
164             return render_to_response('users/suspend_user.html')\r
165 \r
166     if not request.user.is_superuser:\r
167         raise decorators.CommandException(_("Only superusers can ban other users"))\r
168 \r
169     data = {\r
170     'bantype': request.POST.get('bantype', 'indefinetly').strip(),\r
171     'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),\r
172     'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),\r
173     'suspender': request.user.id\r
174     }\r
175 \r
176     if data['bantype'] == 'forxdays':\r
177         try:\r
178             data['forxdays'] = int(request.POST['forxdays'])\r
179         except:\r
180             raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))\r
181 \r
182     SuspendAction(user=user, ip=request.META['REMOTE_ADDR']).save(data=data)\r
183 \r
184     return decorators.RefreshPageCommand()\r
185 \r
186 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, weight=500):\r
187     def decorator(fn):\r
188         def decorated(request, id, slug=None):\r
189             user = get_object_or_404(User, id=id)\r
190             if private and not (user == request.user or request.user.is_superuser):\r
191                 return HttpResponseUnauthorized(request)\r
192             context = fn(request, user)\r
193 \r
194             rev_page_title = user.username + " - " + tab_description\r
195 \r
196             context.update({\r
197             "active_tab" : tab_name,\r
198             "tab_description" : tab_description,\r
199             "page_title" : rev_page_title,\r
200             "can_view_private": (user == request.user) or request.user.is_superuser\r
201             })\r
202             return render_to_response(template, context, context_instance=RequestContext(request))\r
203 \r
204         if tabbed:\r
205             def url_getter(vu):\r
206                 try:\r
207                     return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})\r
208                 except NoReverseMatch:\r
209                     return reverse(fn.__name__, kwargs={'id': vu.id})\r
210 \r
211             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
212                 tab_name, tab_title, tab_description,url_getter, private, weight\r
213             ))\r
214 \r
215         return decorated\r
216 \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