]> git.openstreetmap.org Git - osqa.git/blob - forum/views/users.py
made some changes to the subscriptions view. works much better now. I was doing...
[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 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 \r
26 import time\r
27 import datetime\r
28 import decorators\r
29 import unicodedata\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):\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=(20, 35, 60))\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)\r
73 def online_users(request):\r
74     suser = request.REQUEST.get('q', "")\r
75 \r
76     one_hour_ago = datetime.datetime.now() - datetime.timedelta(hours=1)\r
77     sql_datetime = datetime.datetime.strftime(one_hour_ago, '%Y-%m-%d %H:%M:%S')\r
78     users = User.objects.order_by('-last_seen')\r
79 \r
80     return pagination.paginated(request, ('users', UserListPaginatorContext()), {\r
81         "users" : users,\r
82         "suser" : suser,\r
83     })\r
84 \r
85 \r
86 @login_required\r
87 def edit_user(request, id):\r
88     user = get_object_or_404(User, id=id)\r
89     if not (request.user.is_superuser or request.user == user):\r
90         return HttpResponseUnauthorized(request)\r
91     if request.method == "POST":\r
92         form = EditUserForm(user, request.POST)\r
93         if form.is_valid():\r
94             new_email = sanitize_html(form.cleaned_data['email'])\r
95 \r
96             if new_email != user.email:\r
97                 user.email = new_email\r
98                 user.email_isvalid = False\r
99 \r
100                 try:\r
101                     hash = ValidationHash.objects.get(user=request.user, type='email')\r
102                     hash.delete()\r
103                 except:\r
104                     pass\r
105 \r
106             if settings.EDITABLE_SCREEN_NAME:\r
107                 user.username = sanitize_html(form.cleaned_data['username'])\r
108             user.real_name = sanitize_html(form.cleaned_data['realname'])\r
109             user.website = sanitize_html(form.cleaned_data['website'])\r
110             user.location = sanitize_html(form.cleaned_data['city'])\r
111             user.date_of_birth = form.cleaned_data['birthday']\r
112             if user.date_of_birth == "None":\r
113                 user.date_of_birth = datetime(1900, 1, 1, 0, 0)\r
114             user.about = sanitize_html(form.cleaned_data['about'])\r
115 \r
116             user.save()\r
117             EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()\r
118 \r
119             request.user.message_set.create(message=_("Profile updated."))\r
120             return HttpResponseRedirect(user.get_profile_url())\r
121     else:\r
122         form = EditUserForm(user)\r
123     return render_to_response('users/edit.html', {\r
124     'user': user,\r
125     'form' : form,\r
126     'gravatar_faq_url' : reverse('faq') + '#gravatar',\r
127     }, context_instance=RequestContext(request))\r
128 \r
129 \r
130 @decorate.withfn(decorators.command)\r
131 def user_powers(request, id, action, status):\r
132     if not request.user.is_superuser:\r
133         raise decorators.CommandException(_("Only superusers are allowed to alter other users permissions."))\r
134 \r
135     if (action == 'remove' and 'status' == 'super') and not request.user.is_siteowner():\r
136         raise decorators.CommandException(_("Only the site owner can remove the super user status from other user."))\r
137 \r
138     user = get_object_or_404(User, id=id)\r
139     new_state = action == 'grant'\r
140 \r
141     if status == 'super':\r
142         user.is_superuser = new_state\r
143     elif status == 'staff':\r
144         user.is_staff = new_state\r
145     else:\r
146         raise Http404()\r
147 \r
148     user.save()\r
149     return decorators.RefreshPageCommand()\r
150 \r
151 \r
152 @decorate.withfn(decorators.command)\r
153 def award_points(request, id):\r
154     if not request.POST:\r
155         return render_to_response('users/karma_bonus.html')\r
156 \r
157     if not request.user.is_superuser:\r
158         raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))\r
159 \r
160     try:\r
161         points = int(request.POST['points'])\r
162     except:\r
163         raise decorators.CommandException(_("Invalid number of points to award."))\r
164 \r
165     user = get_object_or_404(User, id=id)\r
166 \r
167     extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)\r
168 \r
169     BonusRepAction(user=request.user, extra=extra).save(data=dict(value=points, affected=user))\r
170 \r
171     return {'commands': {\r
172             'update_profile_karma': [user.reputation]\r
173         }}\r
174     \r
175 \r
176 @decorate.withfn(decorators.command)\r
177 def suspend(request, id):\r
178     user = get_object_or_404(User, id=id)\r
179 \r
180     if not request.user.is_superuser:\r
181         raise decorators.CommandException(_("Only superusers can suspend other users"))\r
182 \r
183     if not request.POST.get('bantype', None):\r
184         if user.is_suspended():\r
185             suspension = user.suspension\r
186             suspension.cancel(user=request.user, ip=request.META['REMOTE_ADDR'])\r
187             return decorators.RefreshPageCommand()\r
188         else:\r
189             return render_to_response('users/suspend_user.html')\r
190 \r
191     data = {\r
192     'bantype': request.POST.get('bantype', 'indefinetly').strip(),\r
193     'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),\r
194     'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),\r
195     'suspended': user\r
196     }\r
197 \r
198     if data['bantype'] == 'forxdays':\r
199         try:\r
200             data['forxdays'] = int(request.POST['forxdays'])\r
201         except:\r
202             raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))\r
203 \r
204     SuspendAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=data)\r
205 \r
206     return decorators.RefreshPageCommand()\r
207 \r
208 \r
209 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, render_to=None, weight=500):\r
210     def decorator(fn):\r
211         def params(request, id, slug=None):\r
212             user = get_object_or_404(User, id=id)\r
213             if private and not (user == request.user or request.user.is_superuser):\r
214                 return HttpResponseUnauthorized(request)\r
215 \r
216             if render_to and (not render_to(user)):\r
217                 return HttpResponseRedirect(user.get_profile_url())\r
218 \r
219             return [request, user], {}\r
220 \r
221         decorated = decorate.params.withfn(params)(fn)\r
222 \r
223         def result(context, request, user):\r
224             rev_page_title = user.username + " - " + tab_description\r
225 \r
226             context.update({\r
227                 "tab": "users",\r
228                 "active_tab" : tab_name,\r
229                 "tab_description" : tab_description,\r
230                 "page_title" : rev_page_title,\r
231                 "can_view_private": (user == request.user) or request.user.is_superuser\r
232             })\r
233             return render_to_response(template, context, context_instance=RequestContext(request))\r
234 \r
235         decorated = decorate.result.withfn(result, needs_params=True)(decorated)\r
236 \r
237         if tabbed:\r
238             def url_getter(vu):\r
239                 try:\r
240                     return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})\r
241                 except NoReverseMatch:\r
242                     return reverse(fn.__name__, kwargs={'id': vu.id})\r
243 \r
244             ui.register(ui.PROFILE_TABS, ui.ProfileTab(\r
245                 tab_name, tab_title, tab_description,url_getter, private, render_to, weight\r
246             ))\r
247 \r
248         return decorated\r
249     return decorator\r
250 \r
251 \r
252 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))\r
253 def user_profile(request, user):\r
254     questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
255     answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')\r
256 \r
257     up_votes = user.vote_up_count\r
258     down_votes = user.vote_down_count\r
259     votes_today = user.get_vote_count_today()\r
260     votes_total = int(settings.MAX_VOTES_PER_DAY)\r
261 \r
262     user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \\r
263         .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')\r
264 \r
265     awards = [(Badge.objects.get(id=b['id']), b['count']) for b in\r
266               Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]\r
267 \r
268     return pagination.paginated(request, (\r
269     ('questions', QuestionListPaginatorContext('USER_QUESTION_LIST', _('questions'), 15)),\r
270     ('answers', UserAnswersPaginatorContext())), {\r
271     "view_user" : user,\r
272     "questions" : questions,\r
273     "answers" : answers,\r
274     "up_votes" : up_votes,\r
275     "down_votes" : down_votes,\r
276     "total_votes": up_votes + down_votes,\r
277     "votes_today_left": votes_total-votes_today,\r
278     "votes_total_per_day": votes_total,\r
279     "user_tags" : user_tags[:50],\r
280     "awards": awards,\r
281     "total_awards" : len(awards),\r
282     })\r
283     \r
284 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))\r
285 def user_recent(request, user):\r
286     activities = user.actions.exclude(\r
287             action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(\r
288             '-action_date')[:USERS_PAGE_SIZE]\r
289 \r
290     return {"view_user" : user, "activities" : activities}\r
291 \r
292 \r
293 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))\r
294 def user_reputation(request, user):\r
295     rep = list(user.reputes.order_by('date'))\r
296     values = [r.value for r in rep]\r
297     redux = lambda x, y: x+y\r
298 \r
299     graph_data = simplejson.dumps([\r
300     (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))\r
301     for i in range(len(values))\r
302     ])\r
303 \r
304     rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]\r
305 \r
306     return {"view_user": user, "reputation": rep, "graph_data": graph_data}\r
307 \r
308 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)\r
309 def user_votes(request, user):\r
310     votes = user.votes.exclude(node__state_string__contains="(deleted").filter(\r
311             node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]\r
312 \r
313     return {"view_user" : user, "votes" : votes}\r
314 \r
315 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))\r
316 def user_favorites(request, user):\r
317     favorites = FavoriteAction.objects.filter(canceled=False, user=user)\r
318 \r
319     return {"favorites" : favorites, "view_user" : user}\r
320 \r
321 @user_view('users/subscriptions.html', 'subscriptions', _('subscription'), _('subscriptions'), True, tabbed=False)\r
322 def user_subscriptions(request, user):\r
323     enabled = user.subscription_settings.enable_notifications\r
324 \r
325     tab = request.GET.get('tab', "settings")\r
326 \r
327     if tab == 'settings':\r
328         manage_open = False\r
329         if request.method == 'POST':\r
330             manage_open = False\r
331             form = SubscriptionSettingsForm(data=request.POST, instance=user.subscription_settings)\r
332 \r
333             if form.is_valid():\r
334                 form.save()\r
335                 message = _('New subscription settings are now saved')\r
336 \r
337                 if 'notswitch' in request.POST:\r
338                     enabled = not enabled\r
339 \r
340                     if enabled:\r
341                         message = _('Notifications are now enabled')\r
342                     else:\r
343                         message = _('Notifications are now disabled')\r
344 \r
345                 user.subscription_settings.enable_notifications = enabled\r
346                 user.subscription_settings.save()\r
347 \r
348                 request.user.message_set.create(message=message)\r
349         else:\r
350             form = SubscriptionSettingsForm(instance=user.subscription_settings)\r
351 \r
352         return {\r
353             'view_user':user,\r
354             'notificatons_on': enabled,\r
355             'form':form,\r
356             'manage_open':manage_open,\r
357         }\r
358 \r
359     elif tab == 'manage':\r
360         manage_open = True\r
361 \r
362         auto = request.GET.get('auto')\r
363         if auto == 'True':\r
364             show_auto = True\r
365             subscriptions = QuestionSubscription.objects.filter(user=user).order_by('-last_view')\r
366         else:\r
367             show_auto = False\r
368             subscriptions = QuestionSubscription.objects.filter(user=user, auto_subscription=False).order_by('-last_view')\r
369 \r
370         return pagination.paginated(request, ('subscriptions', SubscriptionListPaginatorContext()), {\r
371             'subscriptions':subscriptions,\r
372             'view_user':user,\r
373             "auto":show_auto,\r
374             'manage_open':manage_open,\r
375         })\r
376 \r
377     # else:\r
378         # todo: probably want to throw an error\r
379         # error = "error to throw"\r
380 \r
381 \r
382 \r
383 \r
384 \r
385 \r
386 \r
387 @user_view('users/preferences.html', 'preferences', _('preferences'), _('preferences'), True, tabbed=False)\r
388 def user_preferences(request, user):\r
389     if request.POST:\r
390         form = UserPreferencesForm(request.POST)\r
391 \r
392         if form.is_valid():\r
393             user.prop.preferences = form.cleaned_data\r
394             request.user.message_set.create(message=_('New preferences saved'))\r
395 \r
396     else:\r
397         preferences = user.prop.preferences\r
398 \r
399         if preferences:\r
400             form = UserPreferencesForm(initial=preferences)\r
401         else:\r
402             form = UserPreferencesForm()\r
403             \r
404     return {'view_user': user, 'form': form}\r
405 \r
406 @login_required\r
407 def account_settings(request):\r
408     logging.debug('')\r
409     msg = request.GET.get('msg', '')\r
410     is_openid = False\r
411 \r
412     return render_to_response('account_settings.html', {\r
413     'msg': msg,\r
414     'is_openid': is_openid\r
415     }, context_instance=RequestContext(request))\r