]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
Makes tags and users lists use the new paginators, completelly remove the old cnprog...
[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 from forum.utils import pagination\r
25 \r
26 import time\r
27 import decorators\r
28 \r
29 class UserReputationSort(pagination.SimpleSort):\r
30     def apply(self, objects):\r
31         return objects.order_by('-is_active', self.order_by)\r
32 \r
33 class UserListPaginatorContext(pagination.PaginatorContext):\r
34     def __init__(self):\r
35         super (UserListPaginatorContext, self).__init__('USERS_LIST', sort_methods=(\r
36             (_('reputation'), UserReputationSort(_('reputation'), '-reputation', _("sorted by reputation"))),\r
37             (_('newest'), pagination.SimpleSort(_('recent'), '-date_joined', _("newest members"))),\r
38             (_('last'), pagination.SimpleSort(_('oldest'), 'date_joined', _("oldest members"))),\r
39             (_('name'), pagination.SimpleSort(_('by username'), 'username', _("sorted by username"))),\r
40         ), pagesizes=(20, 35, 60))\r
41 \r
42 USERS_PAGE_SIZE = 35# refactor - move to some constants file\r
43 \r
44 @decorators.render('users/users.html', 'users', _('users'), weight=200)\r
45 def users(request):\r
46     suser = request.REQUEST.get('q', "")\r
47     users = User.objects.all()\r
48 \r
49     if suser == "":\r
50         users = users.filter(username__icontains=suser)\r
51 \r
52     return pagination.paginated(request, 'users', UserListPaginatorContext(), {\r
53         "users" : users,\r
54         "suser" : suser,\r
55     })\r
56 \r
57 \r
58 @login_required\r
59 def edit_user(request, id):\r
60     user = get_object_or_404(User, id=id)\r
61     if not (request.user.is_superuser or request.user == user):\r
62         return HttpResponseUnauthorized(request)\r
63     if request.method == "POST":\r
64         form = EditUserForm(user, request.POST)\r
65         if form.is_valid():\r
66             new_email = sanitize_html(form.cleaned_data['email'])\r
67 \r
68             if new_email != user.email:\r
69                 user.email = new_email\r
70                 user.email_isvalid = False\r
71 \r
72             if settings.EDITABLE_SCREEN_NAME:\r
73                 user.username = sanitize_html(form.cleaned_data['username'])\r
74             user.real_name = sanitize_html(form.cleaned_data['realname'])\r
75             user.website = sanitize_html(form.cleaned_data['website'])\r
76             user.location = sanitize_html(form.cleaned_data['city'])\r
77             user.date_of_birth = form.cleaned_data['birthday']\r
78             if user.date_of_birth == "None":\r
79                 user.date_of_birth = datetime(1900, 1, 1, 0, 0)\r
80             user.about = sanitize_html(form.cleaned_data['about'])\r
81 \r
82             user.save()\r
83             EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()\r
84 \r
85             request.user.message_set.create(message=_("Profile updated."))\r
86             return HttpResponseRedirect(user.get_profile_url())\r
87     else:\r
88         form = EditUserForm(user)\r
89     return render_to_response('users/edit.html', {\r
90     'user': user,\r
91     'form' : form,\r
92     'gravatar_faq_url' : reverse('faq') + '#gravatar',\r
93     }, context_instance=RequestContext(request))\r
94 \r
95 \r
96 @decorate.withfn(decorators.command)\r
97 def user_powers(request, id, action, status):\r
98     if not request.user.is_superuser:\r
99         raise decorators.CommandException(_("Only superusers are allowed to alter other users permissions."))\r
100 \r
101     if (action == 'remove' and 'status' == 'super') and not request.user.is_siteowner():\r
102         raise decorators.CommandException(_("Only the site owner can remove the super user status from other user."))\r
103 \r
104     user = get_object_or_404(User, id=id)\r
105     new_state = action == 'grant'\r
106 \r
107     if status == 'super':\r
108         user.is_superuser = new_state\r
109     elif status == 'staff':\r
110         user.is_staff = new_state\r
111     else:\r
112         raise Http404()\r
113 \r
114     user.save()\r
115     return decorators.RefreshPageCommand()\r
116 \r
117 \r
118 @decorate.withfn(decorators.command)\r
119 def award_points(request, id):\r
120     if not request.POST:\r
121         return render_to_response('users/karma_bonus.html')\r
122 \r
123     if not request.user.is_superuser:\r
124         raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
125 \r
126     try:\r
127         points = int(request.POST['points'])\r
128     except:\r
129         raise decorators.CommandException(_("Invalid number of points to award."))\r
130 \r
131     user = get_object_or_404(User, id=id)\r
132 \r
133     extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
134 \r
135     BonusRepAction(user=request.user, extra=extra).save(data=dict(value=points, affected=user))\r
136 \r
137     return {'commands': {\r
138             'update_profile_karma': [user.reputation]\r
139         }}\r
140     \r
141 \r
142 @decorate.withfn(decorators.command)\r
143 def suspend(request, id):\r
144     user = get_object_or_404(User, id=id)\r
145 \r
146     if not request.user.is_superuser:\r
147         raise decorators.CommandException(_("Only superusers can suspend other users"))\r
148 \r
149     if not request.POST.get('bantype', None):\r
150         if user.is_suspended():\r
151             suspension = user.suspension\r
152             suspension.cancel(user=request.user, ip=request.META['REMOTE_ADDR'])\r
153             return decorators.RefreshPageCommand()\r
154         else:\r
155             return render_to_response('users/suspend_user.html')\r
156 \r
157     data = {\r
158     'bantype': request.POST.get('bantype', 'indefinetly').strip(),\r
159     'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),\r
160     'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),\r
161     'suspended': user\r
162     }\r
163 \r
164     if data['bantype'] == 'forxdays':\r
165         try:\r
166             data['forxdays'] = int(request.POST['forxdays'])\r
167         except:\r
168             raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))\r
169 \r
170     SuspendAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=data)\r
171 \r
172     return decorators.RefreshPageCommand()\r
173 \r
174 \r
175 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, render_to=None, weight=500):\r
176     def decorator(fn):\r
177         def decorated(fn, request, id, slug=None):\r
178             user = get_object_or_404(User, id=id)\r
179             if private and not (user == request.user or request.user.is_superuser):\r
180                 return HttpResponseUnauthorized(request)\r
181 \r
182             if render_to and (not render_to(user)):\r
183                 return HttpResponseRedirect(user.get_profile_url())\r
184                 \r
185             context = fn(request, user)\r
186 \r
187             rev_page_title = user.username + " - " + tab_description\r
188 \r
189             context.update({\r
190             "tab": "users",\r
191             "active_tab" : tab_name,\r
192             "tab_description" : tab_description,\r
193             "page_title" : rev_page_title,\r
194             "can_view_private": (user == request.user) or request.user.is_superuser\r
195             })\r
196             return render_to_response(template, context, context_instance=RequestContext(request))\r
197 \r
198         if tabbed:\r
199             def url_getter(vu):\r
200                 try:\r
201                     return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})\r
202                 except NoReverseMatch:\r
203                     return reverse(fn.__name__, kwargs={'id': vu.id})\r
204 \r
205             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
206                 tab_name, tab_title, tab_description,url_getter, private, render_to, weight\r
207             ))\r
208 \r
209         return decorate.withfn(decorated)(fn)\r
210     return decorator\r
211 \r
212 \r
213 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))\r
214 def user_profile(request, user):\r
215     questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
216     answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
217 \r
218     up_votes = user.vote_up_count\r
219     down_votes = user.vote_down_count\r
220     votes_today = user.get_vote_count_today()\r
221     votes_total = int(settings.MAX_VOTES_PER_DAY)\r
222 \r
223     user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
224         .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
225 \r
226     awards = [(Badge.objects.get(id=b['id']), b['count']) for b in\r
227               Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]\r
228 \r
229     return {\r
230     "view_user" : user,\r
231     "questions" : questions,\r
232     "answers" : answers,\r
233     "up_votes" : up_votes,\r
234     "down_votes" : down_votes,\r
235     "total_votes": up_votes + down_votes,\r
236     "votes_today_left": votes_total-votes_today,\r
237     "votes_total_per_day": votes_total,\r
238     "user_tags" : user_tags[:50],\r
239     "awards": awards,\r
240     "total_awards" : len(awards),\r
241     }\r
242     \r
243 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))\r
244 def user_recent(request, user):\r
245     activities = user.actions.exclude(\r
246             action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(\r
247             '-action_date')[:USERS_PAGE_SIZE]\r
248 \r
249     return {"view_user" : user, "activities" : activities}\r
250 \r
251 \r
252 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))\r
253 def user_reputation(request, user):\r
254     rep = list(user.reputes.order_by('date'))\r
255     values = [r.value for r in rep]\r
256     redux = lambda x, y: x+y\r
257 \r
258     graph_data = simplejson.dumps([\r
259     (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))\r
260     for i in range(len(values))\r
261     ])\r
262 \r
263     rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]\r
264 \r
265     return {"view_user": user, "reputation": rep, "graph_data": graph_data}\r
266 \r
267 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)\r
268 def user_votes(request, user):\r
269     votes = user.votes.exclude(node__state_string__contains="(deleted").filter(\r
270             node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
271 \r
272     return {"view_user" : user, "votes" : votes}\r
273 \r
274 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))\r
275 def user_favorites(request, user):\r
276     favorites = FavoriteAction.objects.filter(canceled=False, user=user)\r
277 \r
278     return {"favorites" : favorites, "view_user" : user}\r
279 \r
280 @user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('subscriptions'), True, tabbed=False)\r
281 def user_subscriptions(request, user):\r
282     enabled = user.subscription_settings.enable_notifications\r
283 \r
284     if request.method == 'POST':        \r
285         form = SubscriptionSettingsForm(data=request.POST, instance=user.subscription_settings)\r
286 \r
287         if form.is_valid():\r
288             form.save()\r
289             message = _('New subscription settings are now saved')\r
290 \r
291             if 'notswitch' in request.POST:\r
292                 enabled = not enabled\r
293 \r
294                 if enabled:\r
295                     message = _('Notifications are now enabled')\r
296                 else:\r
297                     message = _('Notifications are now disabled')\r
298 \r
299             user.subscription_settings.enable_notifications = enabled\r
300             user.subscription_settings.save()\r
301 \r
302             request.user.message_set.create(message=message)\r
303     else:\r
304         form = SubscriptionSettingsForm(instance=user.subscription_settings)\r
305 \r
306     return {'view_user':user, 'notificatons_on': enabled, 'form':form}\r
307 \r
308 @login_required\r
309 def account_settings(request):\r
310     logging.debug('')\r
311     msg = request.GET.get('msg', '')\r
312     is_openid = False\r
313 \r
314     return render_to_response('account_settings.html', {\r
315     'msg': msg,\r
316     'is_openid': is_openid\r
317     }, context_instance=RequestContext(request))\r
318 \r