]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
removing unused imports that confuse and reorganizing them in the views module
[osqa.git] / forum / views / users.py
1 from forum.models import User\r
2 from django.db.models import Q, Count\r
3 from django.core.paginator import Paginator, EmptyPage, InvalidPage\r
4 from django.template.defaultfilters import slugify\r
5 from django.contrib.contenttypes.models import ContentType\r
6 from django.core.urlresolvers import reverse\r
7 from django.shortcuts import render_to_response, get_object_or_404\r
8 from django.template import RequestContext\r
9 from django.http import HttpResponse, HttpResponseRedirect, Http404\r
10 from forum.http_responses import HttpResponseUnauthorized\r
11 from django.utils.translation import ugettext as _\r
12 from django.utils.http import urlquote_plus\r
13 from django.utils.html import strip_tags\r
14 from django.utils.encoding import smart_unicode\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, ReturnImediatelyException\r
20 from datetime import datetime, date\r
21 from forum.actions import EditProfileAction, FavoriteAction, BonusRepAction, SuspendAction\r
22 from forum.modules import ui\r
23 from forum.utils import pagination\r
24 from forum.views.readers import QuestionListPaginatorContext, AnswerPaginatorContext\r
25 from forum.settings import ONLINE_USERS\r
26  \r
27 import time\r
28 import datetime\r
29 import decorators\r
30 \r
31 class UserReputationSort(pagination.SimpleSort):\r
32     def apply(self, objects):\r
33         return objects.order_by('-is_active', self.order_by)\r
34 \r
35 class UserListPaginatorContext(pagination.PaginatorContext):\r
36     def __init__(self, pagesizes=(20, 35, 60)):\r
37         super (UserListPaginatorContext, self).__init__('USERS_LIST', sort_methods=(\r
38             (_('reputation'), UserReputationSort(_('reputation'), '-reputation', _("sorted by reputation"))),\r
39             (_('newest'), pagination.SimpleSort(_('recent'), '-date_joined', _("newest members"))),\r
40             (_('last'), pagination.SimpleSort(_('oldest'), 'date_joined', _("oldest members"))),\r
41             (_('name'), pagination.SimpleSort(_('by username'), 'username', _("sorted by username"))),\r
42         ), pagesizes=pagesizes)\r
43 \r
44 class SubscriptionListPaginatorContext(pagination.PaginatorContext):\r
45     def __init__(self):\r
46         super (SubscriptionListPaginatorContext, self).__init__('SUBSCRIPTION_LIST', pagesizes=(5, 10, 20), default_pagesize=20)\r
47 \r
48 class UserAnswersPaginatorContext(pagination.PaginatorContext):\r
49     def __init__(self):\r
50         super (UserAnswersPaginatorContext, self).__init__('USER_ANSWER_LIST', sort_methods=(\r
51             (_('oldest'), pagination.SimpleSort(_('oldest answers'), 'added_at', _("oldest answers will be shown first"))),\r
52             (_('newest'), pagination.SimpleSort(_('newest answers'), '-added_at', _("newest answers will be shown first"))),\r
53             (_('votes'), pagination.SimpleSort(_('popular answers'), '-score', _("most voted answers will be shown first"))),\r
54         ), default_sort=_('votes'), pagesizes=(5, 10, 20), default_pagesize=20, prefix=_('answers'))\r
55 \r
56 USERS_PAGE_SIZE = 35# refactor - move to some constants file\r
57 \r
58 @decorators.render('users/users.html', 'users', _('users'), weight=200)\r
59 def users(request):\r
60     suser = request.REQUEST.get('q', "")\r
61     users = User.objects.all()\r
62 \r
63     if suser != "":\r
64         users = users.filter(username__icontains=suser)\r
65 \r
66     return pagination.paginated(request, ('users', UserListPaginatorContext()), {\r
67         "users" : users,\r
68         "suser" : suser,\r
69     })\r
70 \r
71 \r
72 @decorators.render('users/online_users.html', 'online_users', _('Online Users'), weight=200, tabbed=False)\r
73 def online_users(request):\r
74     suser = request.REQUEST.get('q', "")\r
75 \r
76     sort = ""\r
77     if request.GET.get("sort", None):\r
78         try:\r
79             sort = int(request.GET["sort"])\r
80         except ValueError:\r
81             logging.error('Found invalid sort "%s", loading %s, refered by %s' % (\r
82                 request.GET.get("sort", ''), request.path, request.META.get('HTTP_REFERER', 'UNKNOWN')\r
83             ))\r
84             raise Http404()\r
85 \r
86     page = 0\r
87     if request.GET.get("page", None):\r
88         try:\r
89             page = int(request.GET["page"])\r
90         except ValueError:\r
91             logging.error('Found invalid page "%s", loading %s, refered by %s' % (\r
92                 request.GET.get("page", ''), request.path, request.META.get('HTTP_REFERER', 'UNKNOWN')\r
93             ))\r
94             raise Http404()\r
95 \r
96     pagesize = 10\r
97     if request.GET.get("pagesize", None):\r
98         try:\r
99             pagesize = int(request.GET["pagesize"])\r
100         except ValueError:\r
101             logging.error('Found invalid pagesize "%s", loading %s, refered by %s' % (\r
102                 request.GET.get("pagesize", ''), request.path, request.META.get('HTTP_REFERER', 'UNKNOWN')\r
103             ))\r
104             raise Http404()\r
105 \r
106 \r
107     users = None\r
108     if sort == "reputation":\r
109         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.reputation)\r
110     elif sort == "newest" :\r
111         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.newest)\r
112     elif sort == "last":\r
113         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.last)\r
114     elif sort == "name":\r
115         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.name)\r
116     elif sort == "oldest":\r
117         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.oldest)\r
118     elif sort == "newest":\r
119         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.newest)\r
120     elif sort == "votes":\r
121         users = sorted(ONLINE_USERS.sets.keys(), key=lambda user: user.votes)\r
122     else:\r
123         users = sorted(ONLINE_USERS.iteritems(), key=lambda x: x[1])\r
124 \r
125     return render_to_response('users/online_users.html', {\r
126         "users" : users,\r
127         "suser" : suser,\r
128         "sort" : sort,\r
129         "page" : page,\r
130         "pageSize" : pagesize,\r
131     })\r
132 \r
133 \r
134 def edit_user(request, id):\r
135     user = get_object_or_404(User, id=id)\r
136     if not (request.user.is_superuser or request.user == user):\r
137         return HttpResponseUnauthorized(request)\r
138     if request.method == "POST":\r
139         form = EditUserForm(user, request.POST)\r
140         if form.is_valid():\r
141             new_email = sanitize_html(form.cleaned_data['email'])\r
142 \r
143             if new_email != user.email:\r
144                 user.email = new_email\r
145                 user.email_isvalid = False\r
146 \r
147                 try:\r
148                     hash = ValidationHash.objects.get(user=request.user, type='email')\r
149                     hash.delete()\r
150                 except:\r
151                     pass\r
152 \r
153             if settings.EDITABLE_SCREEN_NAME:\r
154                 user.username = sanitize_html(form.cleaned_data['username'])\r
155             user.real_name = sanitize_html(form.cleaned_data['realname'])\r
156             user.website = sanitize_html(form.cleaned_data['website'])\r
157             user.location = sanitize_html(form.cleaned_data['city'])\r
158             user.date_of_birth = form.cleaned_data['birthday']\r
159             if user.date_of_birth == "None":\r
160                 user.date_of_birth = datetime(1900, 1, 1, 0, 0)\r
161             user.about = sanitize_html(form.cleaned_data['about'])\r
162 \r
163             user.save()\r
164             EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()\r
165 \r
166             request.user.message_set.create(message=_("Profile updated."))\r
167             return HttpResponseRedirect(user.get_profile_url())\r
168     else:\r
169         form = EditUserForm(user)\r
170     return render_to_response('users/edit.html', {\r
171     'user': user,\r
172     'form' : form,\r
173     'gravatar_faq_url' : reverse('faq') + '#gravatar',\r
174     }, context_instance=RequestContext(request))\r
175 \r
176 \r
177 @decorate.withfn(decorators.command)\r
178 def user_powers(request, id, action, status):\r
179     if not request.user.is_superuser:\r
180         raise decorators.CommandException(_("Only superusers are allowed to alter other users permissions."))\r
181 \r
182     if (action == 'remove' and 'status' == 'super') and not request.user.is_siteowner():\r
183         raise decorators.CommandException(_("Only the site owner can remove the super user status from other user."))\r
184 \r
185     user = get_object_or_404(User, id=id)\r
186     new_state = action == 'grant'\r
187 \r
188     if status == 'super':\r
189         user.is_superuser = new_state\r
190     elif status == 'staff':\r
191         user.is_staff = new_state\r
192     else:\r
193         raise Http404()\r
194 \r
195     user.save()\r
196     return decorators.RefreshPageCommand()\r
197 \r
198 \r
199 @decorate.withfn(decorators.command)\r
200 def award_points(request, id):\r
201     if not request.POST:\r
202         return render_to_response('users/karma_bonus.html')\r
203 \r
204     if not request.user.is_superuser:\r
205         raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
206 \r
207     try:\r
208         points = int(request.POST['points'])\r
209     except:\r
210         raise decorators.CommandException(_("Invalid number of points to award."))\r
211 \r
212     user = get_object_or_404(User, id=id)\r
213 \r
214     extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
215 \r
216     BonusRepAction(user=request.user, extra=extra).save(data=dict(value=points, affected=user))\r
217 \r
218     return {'commands': {\r
219             'update_profile_karma': [user.reputation]\r
220         }}\r
221     \r
222 \r
223 @decorate.withfn(decorators.command)\r
224 def suspend(request, id):\r
225     user = get_object_or_404(User, id=id)\r
226 \r
227     if not request.user.is_superuser:\r
228         raise decorators.CommandException(_("Only superusers can suspend other users"))\r
229 \r
230     if not request.POST.get('bantype', None):\r
231         if user.is_suspended():\r
232             suspension = user.suspension\r
233             suspension.cancel(user=request.user, ip=request.META['REMOTE_ADDR'])\r
234             return decorators.RefreshPageCommand()\r
235         else:\r
236             return render_to_response('users/suspend_user.html')\r
237 \r
238     data = {\r
239         'bantype': request.POST.get('bantype', 'indefinetly').strip(),\r
240         'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),\r
241         'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),\r
242         'suspended': user\r
243     }\r
244 \r
245     if data['bantype'] == 'forxdays':\r
246         try:\r
247             data['forxdays'] = int(request.POST['forxdays'])\r
248         except:\r
249             raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))\r
250 \r
251     SuspendAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=data)\r
252 \r
253     return decorators.RefreshPageCommand()\r
254 \r
255 \r
256 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, render_to=None, weight=500):\r
257     def decorator(fn):\r
258         def params(request, id, slug=None):\r
259             user = get_object_or_404(User, id=id)\r
260             if private and not (user == request.user or request.user.is_superuser):\r
261                 raise ReturnImediatelyException(HttpResponseUnauthorized(request))\r
262 \r
263             if render_to and (not render_to(user)):\r
264                 raise ReturnImediatelyException(HttpResponseRedirect(user.get_profile_url()))\r
265 \r
266             return [request, user], {}\r
267 \r
268         decorated = decorate.params.withfn(params)(fn)\r
269 \r
270         def result(context, request, user):\r
271             rev_page_title = smart_unicode(user.username) + " - " + tab_description\r
272 \r
273             context.update({\r
274                 "tab": "users",\r
275                 "active_tab" : tab_name,\r
276                 "tab_description" : tab_description,\r
277                 "page_title" : rev_page_title,\r
278                 "can_view_private": (user == request.user) or request.user.is_superuser\r
279             })\r
280             return render_to_response(template, context, context_instance=RequestContext(request))\r
281 \r
282         decorated = decorate.result.withfn(result, needs_params=True)(decorated)\r
283 \r
284         if tabbed:\r
285             def url_getter(vu):\r
286                 try:\r
287                     return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(smart_unicode(vu.username))})\r
288                 except NoReverseMatch:\r
289                     return reverse(fn.__name__, kwargs={'id': vu.id})\r
290 \r
291             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
292                 tab_name, tab_title, tab_description,url_getter, private, render_to, weight\r
293             ))\r
294 \r
295         return decorated\r
296     return decorator\r
297 \r
298 \r
299 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))\r
300 def user_profile(request, user):\r
301     questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
302     answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
303 \r
304     up_votes = user.vote_up_count\r
305     down_votes = user.vote_down_count\r
306     votes_today = user.get_vote_count_today()\r
307     votes_total = user.can_vote_count_today()\r
308 \r
309     user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
310         .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
311 \r
312     awards = [(Badge.objects.get(id=b['id']), b['count']) for b in\r
313               Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]\r
314 \r
315     return pagination.paginated(request, (\r
316     ('questions', QuestionListPaginatorContext('USER_QUESTION_LIST', _('questions'), default_pagesize=15)),\r
317     ('answers', UserAnswersPaginatorContext())), {\r
318     "view_user" : user,\r
319     "questions" : questions,\r
320     "answers" : answers,\r
321     "up_votes" : up_votes,\r
322     "down_votes" : down_votes,\r
323     "total_votes": up_votes + down_votes,\r
324     "votes_today_left": votes_total-votes_today,\r
325     "votes_total_per_day": votes_total,\r
326     "user_tags" : user_tags[:50],\r
327     "awards": awards,\r
328     "total_awards" : len(awards),\r
329     })\r
330     \r
331 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))\r
332 def user_recent(request, user):\r
333     activities = user.actions.exclude(\r
334             action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(\r
335             '-action_date')[:USERS_PAGE_SIZE]\r
336 \r
337     return {"view_user" : user, "activities" : activities}\r
338 \r
339 \r
340 @user_view('users/reputation.html', 'reputation', _('reputation history'), _('graph of user karma'))\r
341 def user_reputation(request, user):\r
342     rep = list(user.reputes.order_by('date'))\r
343     values = [r.value for r in rep]\r
344     redux = lambda x, y: x+y\r
345 \r
346     graph_data = simplejson.dumps([\r
347     (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))\r
348     for i in range(len(values))\r
349     ])\r
350 \r
351     rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]\r
352 \r
353     return {"view_user": user, "reputation": rep, "graph_data": graph_data}\r
354 \r
355 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)\r
356 def user_votes(request, user):\r
357     votes = user.votes.exclude(node__state_string__contains="(deleted").filter(\r
358             node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
359 \r
360     return {"view_user" : user, "votes" : votes}\r
361 \r
362 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))\r
363 def user_favorites(request, user):\r
364     favorites = FavoriteAction.objects.filter(canceled=False, user=user)\r
365 \r
366     return {"favorites" : favorites, "view_user" : user}\r
367 \r
368 @user_view('users/subscriptions.html', 'subscriptions', _('subscription'), _('subscriptions'), True, tabbed=False)\r
369 def user_subscriptions(request, user):\r
370     enabled = True\r
371 \r
372     tab = request.GET.get('tab', "settings")\r
373 \r
374     if tab == 'settings':\r
375         manage_open = False\r
376         if request.method == 'POST':\r
377             manage_open = False\r
378             form = SubscriptionSettingsForm(data=request.POST, instance=user.subscription_settings)\r
379 \r
380             if form.is_valid():\r
381                 form.save()\r
382                 message = _('New subscription settings are now saved')\r
383 \r
384                 user.subscription_settings.enable_notifications = enabled\r
385                 user.subscription_settings.save()\r
386 \r
387                 request.user.message_set.create(message=message)\r
388         else:\r
389             form = SubscriptionSettingsForm(instance=user.subscription_settings)\r
390 \r
391         return {\r
392             'view_user':user,\r
393             'notificatons_on': enabled,\r
394             'form':form,\r
395             'manage_open':manage_open,\r
396         }\r
397 \r
398     elif tab == 'manage':\r
399         manage_open = True\r
400 \r
401         auto = request.GET.get('auto', 'True')\r
402         if auto == 'True':\r
403             show_auto = True\r
404             subscriptions = QuestionSubscription.objects.filter(user=user).order_by('-last_view')\r
405         else:\r
406             show_auto = False\r
407             subscriptions = QuestionSubscription.objects.filter(user=user, auto_subscription=False).order_by('-last_view')\r
408 \r
409         return pagination.paginated(request, ('subscriptions', SubscriptionListPaginatorContext()), {\r
410             'subscriptions':subscriptions,\r
411             'view_user':user,\r
412             "auto":show_auto,\r
413             'manage_open':manage_open,\r
414         })\r
415 \r
416     # else:\r
417         # todo: probably want to throw an error\r
418         # error = "error to throw"\r
419 \r
420 \r
421 \r
422 \r
423 \r
424 \r
425 \r
426 @user_view('users/preferences.html', 'preferences', _('preferences'), _('preferences'), True, tabbed=False)\r
427 def user_preferences(request, user):\r
428     if request.POST:\r
429         form = UserPreferencesForm(request.POST)\r
430 \r
431         if form.is_valid():\r
432             user.prop.preferences = form.cleaned_data\r
433             request.user.message_set.create(message=_('New preferences saved'))\r
434 \r
435     else:\r
436         preferences = user.prop.preferences\r
437 \r
438         if preferences:\r
439             form = UserPreferencesForm(initial=preferences)\r
440         else:\r
441             form = UserPreferencesForm()\r
442             \r
443     return {'view_user': user, 'form': form}\r
444 \r
445 \r