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