summaryrefslogtreecommitdiffstats
path: root/forum
diff options
context:
space:
mode:
authorEvgeny Fadeev <evgeny.fadeev@gmail.com>2009-11-23 21:16:31 -0500
committerEvgeny Fadeev <evgeny.fadeev@gmail.com>2009-11-23 21:16:31 -0500
commit59e445ae892cea104a7d5354027c72c60294815a (patch)
treee4be42f89de6829588735822408a986eacbfd578 /forum
parent05c4a831e2ac4bb2dd5a2420741c02d5b6ac570d (diff)
downloadaskbot-59e445ae892cea104a7d5354027c72c60294815a.tar.gz
askbot-59e445ae892cea104a7d5354027c72c60294815a.tar.bz2
askbot-59e445ae892cea104a7d5354027c72c60294815a.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.py2
-rw-r--r--forum/forms.py4
-rw-r--r--forum/management/commands/send_email_alerts.py134
-rw-r--r--forum/views.py3
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