diff options
author | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2009-11-23 21:16:55 -0500 |
---|---|---|
committer | Evgeny Fadeev <evgeny.fadeev@gmail.com> | 2009-11-23 21:16:55 -0500 |
commit | fa98d95d8c675f37c321c40e0151624dca240efc (patch) | |
tree | e4be42f89de6829588735822408a986eacbfd578 /forum | |
parent | 007d4522c2999188d77bde9ba5059231ccc53f73 (diff) | |
download | askbot-fa98d95d8c675f37c321c40e0151624dca240efc.tar.gz askbot-fa98d95d8c675f37c321c40e0151624dca240efc.tar.bz2 askbot-fa98d95d8c675f37c321c40e0151624dca240efc.zip |
improved email subscription job, some small fixes, users now can change their screen name any time
Diffstat (limited to 'forum')
-rw-r--r-- | forum/const.py | 2 | ||||
-rw-r--r-- | forum/forms.py | 4 | ||||
-rw-r--r-- | forum/management/commands/send_email_alerts.py | 134 | ||||
-rw-r--r-- | forum/views.py | 3 |
4 files changed, 100 insertions, 43 deletions
diff --git a/forum/const.py b/forum/const.py index 9b9230c0..312dde26 100644 --- a/forum/const.py +++ b/forum/const.py @@ -49,6 +49,7 @@ TYPE_ACTIVITY_MARK_OFFENSIVE=14 TYPE_ACTIVITY_UPDATE_TAGS=15 TYPE_ACTIVITY_FAVORITE=16 TYPE_ACTIVITY_USER_FULL_UPDATED = 17 +TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT = 18 #TYPE_ACTIVITY_EDIT_QUESTION=17 #TYPE_ACTIVITY_EDIT_ANSWER=18 @@ -70,6 +71,7 @@ TYPE_ACTIVITY = ( (TYPE_ACTIVITY_UPDATE_TAGS, _('updated tags')), (TYPE_ACTIVITY_FAVORITE, _('selected favorite')), (TYPE_ACTIVITY_USER_FULL_UPDATED, _('completed user profile')), + (TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT, _('email update sent to user')), ) TYPE_RESPONSE = { diff --git a/forum/forms.py b/forum/forms.py index 5b181d48..511a0a0d 100644 --- a/forum/forms.py +++ b/forum/forms.py @@ -4,7 +4,7 @@ from django import forms from models import * from const import * from django.utils.translation import ugettext as _ -from django_authopenid.forms import NextUrlField +from django_authopenid.forms import NextUrlField, UserNameField import settings class TitleField(forms.CharField): @@ -195,6 +195,7 @@ class EditAnswerForm(forms.Form): class EditUserForm(forms.Form): email = forms.EmailField(label=u'Email', help_text=_('this email does not have to be linked to gravatar'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) + username = UserNameField(label=_('Screen name')) realname = forms.CharField(label=_('Real name'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) website = forms.URLField(label=_('Website'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) city = forms.CharField(label=_('Location'), required=False, max_length=255, widget=forms.TextInput(attrs={'size' : 35})) @@ -203,6 +204,7 @@ class EditUserForm(forms.Form): def __init__(self, user, *args, **kwargs): super(EditUserForm, self).__init__(*args, **kwargs) + self.fields['username'].initial = user.username self.fields['email'].initial = user.email self.fields['realname'].initial = user.real_name self.fields['website'].initial = user.website diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py index a25e4343..8d52ed64 100644 --- a/forum/management/commands/send_email_alerts.py +++ b/forum/management/commands/send_email_alerts.py @@ -2,11 +2,14 @@ from django.core.management.base import NoArgsCommand from django.db import connection from django.db.models import Q, F from forum.models import * +from forum import const from django.core.mail import EmailMessage from django.utils.translation import ugettext as _ from django.utils.translation import ungettext import datetime import settings +import logging +from utils.odict import OrderedDict class Command(NoArgsCommand): def handle_noargs(self,**options): @@ -18,10 +21,10 @@ class Command(NoArgsCommand): connection.close() def get_updated_questions_for_user(self,user): - q_sel = [] - q_ask = [] - q_ans = [] - q_all = [] + q_sel = None + q_ask = None + q_ans = None + q_all = None now = datetime.datetime.now() Q_set1 = Question.objects.exclude( last_activity_by=user, @@ -39,12 +42,12 @@ class Command(NoArgsCommand): for feed in user_feeds: cutoff_time = now - EmailFeedSetting.DELTA_TABLE[feed.frequency] if feed.reported_at == None or feed.reported_at <= cutoff_time: - Q_set = Q_set1.exclude(last_activity_at__gt=cutoff_time) + Q_set = Q_set1.exclude(last_activity_at__gt=cutoff_time)#report these excluded later feed.reported_at = now feed.save()#may not actually report anything, depending on filters below if feed.feed_type == 'q_sel': q_sel = Q_set.filter(followed_by=user) - q_sel.cutoff_time = cutoff_time + q_sel.cutoff_time = cutoff_time #store cutoff time per query set elif feed.feed_type == 'q_ask': q_ask = Q_set.filter(author=user) q_ask.cutoff_time = cutoff_time @@ -55,56 +58,92 @@ class Command(NoArgsCommand): q_all = Q_set q_all.cutoff_time = cutoff_time #build list in this order - q_tbl = {} + q_list = OrderedDict() def extend_question_list(src, dst): - if isinstance(src,list): - return + """src is a query set with questions + or an empty list + dst - is an ordered dictionary + """ + if src is None: + return #will not do anything if subscription of this type is not used cutoff_time = src.cutoff_time for q in src: if q in dst: - if cutoff_time < dst[q]: - dst[q] = cutoff_time + if cutoff_time < dst[q]['cutoff_time']: + dst[q]['cutoff_time'] = cutoff_time else: - dst[q] = cutoff_time + #initialise a questions metadata dictionary to use for email reporting + dst[q] = {'cutoff_time':cutoff_time} - extend_question_list(q_sel, q_tbl) - extend_question_list(q_ask, q_tbl) - extend_question_list(q_ans, q_tbl) - extend_question_list(q_all, q_tbl) + extend_question_list(q_sel, q_list) + extend_question_list(q_ask, q_list) + extend_question_list(q_ans, q_list) + extend_question_list(q_all, q_list) ctype = ContentType.objects.get_for_model(Question) - out = {} - for q, cutoff_time in q_tbl.items(): + EMAIL_UPDATE_ACTIVITY = const.TYPE_ACTIVITY_QUESTION_EMAIL_UPDATE_SENT + for q, meta_data in q_list.items(): #todo use Activity, but first start keeping more Activity records #act = Activity.objects.filter(content_type=ctype, object_id=q.id) - #get info on question edits, answer edits, comments - out[q] = {} - q_rev = QuestionRevision.objects.filter(question=q,revised_at__lt=cutoff_time) + #because currently activity is not fully recorded to through + #revision records to see what kind modifications were done on + #the questions and answers + try: + update_info = Activity.objects.get(content_type=ctype, + object_id=q.id, + activity_type=EMAIL_UPDATE_ACTIVITY) + emailed_at = update_info.active_at + except Activity.DoesNotExist: + update_info = Activity(user=user, content_object=q, activity_type=EMAIL_UPDATE_ACTIVITY) + emailed_at = datetime.datetime(1970,1,1)#long time ago + except Activity.MultipleObjectsReturned: + raise Exception('server error - multiple question email activities found per user-question pair') + + q_rev = QuestionRevision.objects.filter(question=q,\ + revised_at__lt=cutoff_time,\ + revised_at__gt=emailed_at) q_rev = q_rev.exclude(author=user) - out[q]['q_rev'] = len(q_rev) + meta_data['q_rev'] = len(q_rev) if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at: - out[q]['q_rev'] = 0 - out[q]['new_q'] = True + meta_data['q_rev'] = 0 + meta_data['new_q'] = True else: - out[q]['new_q'] = False + meta_data['new_q'] = False - new_ans = Answer.objects.filter(question=q,added_at__lt=cutoff_time) + new_ans = Answer.objects.filter(question=q,\ + added_at__lt=cutoff_time,\ + added_at__gt=emailed_at) new_ans = new_ans.exclude(author=user) - out[q]['new_ans'] = len(new_ans) - ans_rev = AnswerRevision.objects.filter(answer__question=q,revised_at__lt=cutoff_time) + meta_data['new_ans'] = len(new_ans) + ans_rev = AnswerRevision.objects.filter(answer__question=q,\ + revised_at__lt=cutoff_time,\ + revised_at__gt=emailed_at) ans_rev = ans_rev.exclude(author=user) - out[q]['ans_rev'] = len(ans_rev) - return out + meta_data['ans_rev'] = len(ans_rev) + if len(q_rev) == 0 and len(new_ans) == 0 and len(ans_rev) == 0: + meta_data['nothing_new'] = True + else: + meta_data['nothing_new'] = False + update_info.active_at = now + update_info.save() #save question email update activity + return q_list - def __act_count(self,string,number,output): + def __action_count(self,string,number,output): if number > 0: output.append(_(string) % {'num':number}) def send_email_alerts(self): + #todo: move this to template for user in User.objects.all(): q_list = self.get_updated_questions_for_user(user) - num_q = len(q_list) + num_q = 0 + num_moot = 0 + for meta_data in q_list.values(): + if meta_data['nothing_new'] == False: + num_q += 1 + else: + num_moot += 1 if num_q > 0: url_prefix = settings.APP_URL subject = _('email update message subject') @@ -113,17 +152,30 @@ class Command(NoArgsCommand): % {'num':num_q, 'name':user.username} text += '<ul>' - for q, act in q_list.items(): + for q, meta_data in q_list.items(): act_list = [] - if act['new_q']: - act_list.append(_('new question')) - self.__act_count('%(num)d rev', act['q_rev'],act_list) - self.__act_count('%(num)d ans', act['new_ans'],act_list) - self.__act_count('%(num)d ans rev',act['ans_rev'],act_list) - act_token = ', '.join(act_list) - text += '<li><a href="%s?sort=latest">%s</a> <font color="#777777">(%s)</font></li>' \ - % (url_prefix + q.get_absolute_url(), q.title, act_token) + if meta_data['nothing_new']: + continue + else: + if meta_data['new_q']: + act_list.append(_('new question')) + self.__action_count('%(num)d rev', meta_data['q_rev'],act_list) + self.__action_count('%(num)d ans', meta_data['new_ans'],act_list) + self.__action_count('%(num)d ans rev',meta_data['ans_rev'],act_list) + act_token = ', '.join(act_list) + text += '<li><a href="%s?sort=latest">%s</a> <font color="#777777">(%s)</font></li>' \ + % (url_prefix + q.get_absolute_url(), q.title, act_token) text += '</ul>' + if num_moot > 0: + text += '<p></p>' + text += ungettext('There is also one question which was recently '\ + +'updated but you might not have seen its latest version.', + 'There are also %(num)d more questions which were recently updated '\ + +'but you might not have seen their latest version.',num_moot) \ + % {'num':num_moot,} + text += _('Perhaps you could look up previously sent forum reminders in your mailbox.') + text += '</p>' + link = url_prefix + user.get_profile_url() + '?sort=email_subscriptions' text += _('go to %(link)s to change frequency of email updates or %(email)s administrator') \ % {'link':link, 'email':settings.ADMINS[0][1]} diff --git a/forum/views.py b/forum/views.py index a1b37717..d9d87e02 100644 --- a/forum/views.py +++ b/forum/views.py @@ -1130,6 +1130,7 @@ def edit_user(request, id): from django_authopenid.views import set_new_email set_new_email(user, new_email) + user.username = sanitize_html(form.cleaned_data['username']) user.real_name = sanitize_html(form.cleaned_data['realname']) user.website = sanitize_html(form.cleaned_data['website']) user.location = sanitize_html(form.cleaned_data['city']) @@ -1529,7 +1530,7 @@ def user_responses(request, user_id, user_view): def __init__(self, type, title, question_id, answer_id, time, username, user_id, content): self.type = type self.title = title - self.titlelink = reverse('questions') + u'%s/%s#%s' % (question_id, title, answer_id) + self.titlelink = reverse('question', args=[question_id]) + u'%s#%s' % (slugify(title), answer_id) self.time = time self.userlink = reverse('users') + u'%s/%s/' % (user_id, username) self.username = username |