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
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 from forum.views.readers import QuestionListPaginatorContext, AnswerPaginatorContext
\r
30 class UserReputationSort(pagination.SimpleSort):
\r
31 def apply(self, objects):
\r
32 return objects.order_by('-is_active', self.order_by)
\r
34 class UserListPaginatorContext(pagination.PaginatorContext):
\r
36 super (UserListPaginatorContext, self).__init__('USERS_LIST', sort_methods=(
\r
37 (_('reputation'), UserReputationSort(_('reputation'), '-reputation', _("sorted by reputation"))),
\r
38 (_('newest'), pagination.SimpleSort(_('recent'), '-date_joined', _("newest members"))),
\r
39 (_('last'), pagination.SimpleSort(_('oldest'), 'date_joined', _("oldest members"))),
\r
40 (_('name'), pagination.SimpleSort(_('by username'), 'username', _("sorted by username"))),
\r
41 ), pagesizes=(20, 35, 60))
\r
43 class UserAnswersPaginatorContext(pagination.PaginatorContext):
\r
45 super (UserAnswersPaginatorContext, self).__init__('USER_ANSWER_LIST', sort_methods=(
\r
46 (_('oldest'), pagination.SimpleSort(_('oldest answers'), 'added_at', _("oldest answers will be shown first"))),
\r
47 (_('newest'), pagination.SimpleSort(_('newest answers'), '-added_at', _("newest answers will be shown first"))),
\r
48 (_('votes'), pagination.SimpleSort(_('popular answers'), '-score', _("most voted answers will be shown first"))),
\r
49 ), default_sort=_('votes'), pagesizes=(5, 10, 20), default_pagesize=20, prefix=_('answers'))
\r
51 USERS_PAGE_SIZE = 35# refactor - move to some constants file
\r
53 @decorators.render('users/users.html', 'users', _('users'), weight=200)
\r
55 suser = request.REQUEST.get('q', "")
\r
56 users = User.objects.all()
\r
59 users = users.filter(username__icontains=suser)
\r
61 return pagination.paginated(request, ('users', UserListPaginatorContext()), {
\r
68 def edit_user(request, id):
\r
69 user = get_object_or_404(User, id=id)
\r
70 if not (request.user.is_superuser or request.user == user):
\r
71 return HttpResponseUnauthorized(request)
\r
72 if request.method == "POST":
\r
73 form = EditUserForm(user, request.POST)
\r
75 new_email = sanitize_html(form.cleaned_data['email'])
\r
77 if new_email != user.email:
\r
78 user.email = new_email
\r
79 user.email_isvalid = False
\r
81 if settings.EDITABLE_SCREEN_NAME:
\r
82 user.username = sanitize_html(form.cleaned_data['username'])
\r
83 user.real_name = sanitize_html(form.cleaned_data['realname'])
\r
84 user.website = sanitize_html(form.cleaned_data['website'])
\r
85 user.location = sanitize_html(form.cleaned_data['city'])
\r
86 user.date_of_birth = form.cleaned_data['birthday']
\r
87 if user.date_of_birth == "None":
\r
88 user.date_of_birth = datetime(1900, 1, 1, 0, 0)
\r
89 user.about = sanitize_html(form.cleaned_data['about'])
\r
92 EditProfileAction(user=user, ip=request.META['REMOTE_ADDR']).save()
\r
94 request.user.message_set.create(message=_("Profile updated."))
\r
95 return HttpResponseRedirect(user.get_profile_url())
\r
97 form = EditUserForm(user)
\r
98 return render_to_response('users/edit.html', {
\r
101 'gravatar_faq_url' : reverse('faq') + '#gravatar',
\r
102 }, context_instance=RequestContext(request))
\r
105 @decorate.withfn(decorators.command)
\r
106 def user_powers(request, id, action, status):
\r
107 if not request.user.is_superuser:
\r
108 raise decorators.CommandException(_("Only superusers are allowed to alter other users permissions."))
\r
110 if (action == 'remove' and 'status' == 'super') and not request.user.is_siteowner():
\r
111 raise decorators.CommandException(_("Only the site owner can remove the super user status from other user."))
\r
113 user = get_object_or_404(User, id=id)
\r
114 new_state = action == 'grant'
\r
116 if status == 'super':
\r
117 user.is_superuser = new_state
\r
118 elif status == 'staff':
\r
119 user.is_staff = new_state
\r
124 return decorators.RefreshPageCommand()
\r
127 @decorate.withfn(decorators.command)
\r
128 def award_points(request, id):
\r
129 if not request.POST:
\r
130 return render_to_response('users/karma_bonus.html')
\r
132 if not request.user.is_superuser:
\r
133 raise decorators.CommandException(_("Only superusers are allowed to award reputation points"))
\r
136 points = int(request.POST['points'])
\r
138 raise decorators.CommandException(_("Invalid number of points to award."))
\r
140 user = get_object_or_404(User, id=id)
\r
142 extra = dict(message=request.POST.get('message', ''), awarding_user=request.user.id, value=points)
\r
144 BonusRepAction(user=request.user, extra=extra).save(data=dict(value=points, affected=user))
\r
146 return {'commands': {
\r
147 'update_profile_karma': [user.reputation]
\r
151 @decorate.withfn(decorators.command)
\r
152 def suspend(request, id):
\r
153 user = get_object_or_404(User, id=id)
\r
155 if not request.user.is_superuser:
\r
156 raise decorators.CommandException(_("Only superusers can suspend other users"))
\r
158 if not request.POST.get('bantype', None):
\r
159 if user.is_suspended():
\r
160 suspension = user.suspension
\r
161 suspension.cancel(user=request.user, ip=request.META['REMOTE_ADDR'])
\r
162 return decorators.RefreshPageCommand()
\r
164 return render_to_response('users/suspend_user.html')
\r
167 'bantype': request.POST.get('bantype', 'indefinetly').strip(),
\r
168 'publicmsg': request.POST.get('publicmsg', _('Bad behaviour')),
\r
169 'privatemsg': request.POST.get('privatemsg', None) or request.POST.get('publicmsg', ''),
\r
173 if data['bantype'] == 'forxdays':
\r
175 data['forxdays'] = int(request.POST['forxdays'])
\r
177 raise decorators.CommandException(_('Invalid numeric argument for the number of days.'))
\r
179 SuspendAction(user=request.user, ip=request.META['REMOTE_ADDR']).save(data=data)
\r
181 return decorators.RefreshPageCommand()
\r
184 def user_view(template, tab_name, tab_title, tab_description, private=False, tabbed=True, render_to=None, weight=500):
\r
186 def params(request, id, slug=None):
\r
187 user = get_object_or_404(User, id=id)
\r
188 if private and not (user == request.user or request.user.is_superuser):
\r
189 return HttpResponseUnauthorized(request)
\r
191 if render_to and (not render_to(user)):
\r
192 return HttpResponseRedirect(user.get_profile_url())
\r
194 return [request, user], {}
\r
196 decorated = decorate.params.withfn(params)(fn)
\r
198 def result(context, request, user):
\r
199 rev_page_title = user.username + " - " + tab_description
\r
203 "active_tab" : tab_name,
\r
204 "tab_description" : tab_description,
\r
205 "page_title" : rev_page_title,
\r
206 "can_view_private": (user == request.user) or request.user.is_superuser
\r
208 return render_to_response(template, context, context_instance=RequestContext(request))
\r
210 decorated = decorate.result.withfn(result, needs_params=True)(decorated)
\r
213 def url_getter(vu):
\r
215 return reverse(fn.__name__, kwargs={'id': vu.id, 'slug': slugify(vu.username)})
\r
216 except NoReverseMatch:
\r
217 return reverse(fn.__name__, kwargs={'id': vu.id})
\r
219 ui.register(ui.PROFILE_TABS, ui.ProfileTab(
\r
220 tab_name, tab_title, tab_description,url_getter, private, render_to, weight
\r
227 @user_view('users/stats.html', 'stats', _('overview'), _('user overview'))
\r
228 def user_profile(request, user):
\r
229 questions = Question.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')
\r
230 answers = Answer.objects.filter_state(deleted=False).filter(author=user).order_by('-added_at')
\r
232 up_votes = user.vote_up_count
\r
233 down_votes = user.vote_down_count
\r
234 votes_today = user.get_vote_count_today()
\r
235 votes_total = int(settings.MAX_VOTES_PER_DAY)
\r
237 user_tags = Tag.objects.filter(Q(nodes__author=user) | Q(nodes__children__author=user)) \
\r
238 .annotate(user_tag_usage_count=Count('name')).order_by('-user_tag_usage_count')
\r
240 awards = [(Badge.objects.get(id=b['id']), b['count']) for b in
\r
241 Badge.objects.filter(awards__user=user).values('id').annotate(count=Count('cls')).order_by('-count')]
\r
243 return pagination.paginated(request, (
\r
244 ('questions', QuestionListPaginatorContext('USER_QUESTION_LIST', _('questions'), 15)),
\r
245 ('answers', UserAnswersPaginatorContext())), {
\r
246 "view_user" : user,
\r
247 "questions" : questions,
\r
248 "answers" : answers,
\r
249 "up_votes" : up_votes,
\r
250 "down_votes" : down_votes,
\r
251 "total_votes": up_votes + down_votes,
\r
252 "votes_today_left": votes_total-votes_today,
\r
253 "votes_total_per_day": votes_total,
\r
254 "user_tags" : user_tags[:50],
\r
256 "total_awards" : len(awards),
\r
259 @user_view('users/recent.html', 'recent', _('recent activity'), _('recent user activity'))
\r
260 def user_recent(request, user):
\r
261 activities = user.actions.exclude(
\r
262 action_type__in=("voteup", "votedown", "voteupcomment", "flag", "newpage", "editpage")).order_by(
\r
263 '-action_date')[:USERS_PAGE_SIZE]
\r
265 return {"view_user" : user, "activities" : activities}
\r
268 @user_view('users/reputation.html', 'reputation', _('karma history'), _('graph of user karma'))
\r
269 def user_reputation(request, user):
\r
270 rep = list(user.reputes.order_by('date'))
\r
271 values = [r.value for r in rep]
\r
272 redux = lambda x, y: x+y
\r
274 graph_data = simplejson.dumps([
\r
275 (time.mktime(rep[i].date.timetuple()) * 1000, reduce(redux, values[:i], 0))
\r
276 for i in range(len(values))
\r
279 rep = user.reputes.filter(action__canceled=False).order_by('-date')[0:20]
\r
281 return {"view_user": user, "reputation": rep, "graph_data": graph_data}
\r
283 @user_view('users/votes.html', 'votes', _('votes'), _('user vote record'), True)
\r
284 def user_votes(request, user):
\r
285 votes = user.votes.exclude(node__state_string__contains="(deleted").filter(
\r
286 node__node_type__in=("question", "answer")).order_by('-voted_at')[:USERS_PAGE_SIZE]
\r
288 return {"view_user" : user, "votes" : votes}
\r
290 @user_view('users/questions.html', 'favorites', _('favorites'), _('questions that user selected as his/her favorite'))
\r
291 def user_favorites(request, user):
\r
292 favorites = FavoriteAction.objects.filter(canceled=False, user=user)
\r
294 return {"favorites" : favorites, "view_user" : user}
\r
296 @user_view('users/subscriptions.html', 'subscriptions', _('subscription settings'), _('subscriptions'), True, tabbed=False)
\r
297 def user_subscriptions(request, user):
\r
298 enabled = user.subscription_settings.enable_notifications
\r
300 if request.method == 'POST':
\r
301 form = SubscriptionSettingsForm(data=request.POST, instance=user.subscription_settings)
\r
303 if form.is_valid():
\r
305 message = _('New subscription settings are now saved')
\r
307 if 'notswitch' in request.POST:
\r
308 enabled = not enabled
\r
311 message = _('Notifications are now enabled')
\r
313 message = _('Notifications are now disabled')
\r
315 user.subscription_settings.enable_notifications = enabled
\r
316 user.subscription_settings.save()
\r
318 request.user.message_set.create(message=message)
\r
320 form = SubscriptionSettingsForm(instance=user.subscription_settings)
\r
322 return {'view_user':user, 'notificatons_on': enabled, 'form':form}
\r
324 @user_view('users/preferences.html', 'preferences', _('preferences'), _('preferences'), True, tabbed=False)
\r
325 def user_preferences(request, user):
\r
327 form = UserPreferencesForm(request.POST)
\r
329 if form.is_valid():
\r
330 user.prop.preferences = form.cleaned_data
\r
331 request.user.message_set.create(message=_('New preferences saved'))
\r
334 preferences = user.prop.preferences
\r
337 form = UserPreferencesForm(initial=preferences)
\r
339 form = UserPreferencesForm()
\r
341 return {'view_user': user, 'form': form}
\r
344 def account_settings(request):
\r
346 msg = request.GET.get('msg', '')
\r
349 return render_to_response('account_settings.html', {
\r
351 'is_openid': is_openid
\r
352 }, context_instance=RequestContext(request))
\r