From e19d24423069e0ee4f4b1fa2c0b079e57de83322 Mon Sep 17 00:00:00 2001
From: Evgeny Fadeev
Date: Wed, 5 Aug 2009 22:55:06 -0400
Subject: added some more files
---
forum/management/commands/send_email_alerts.py | 41 ++++++++++++++++++++++++++
1 file changed, 41 insertions(+)
create mode 100644 forum/management/commands/send_email_alerts.py
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
new file mode 100644
index 00000000..3c37aaa3
--- /dev/null
+++ b/forum/management/commands/send_email_alerts.py
@@ -0,0 +1,41 @@
+from django.core.management.base import NoArgsCommand
+from django.db import connection
+from forum.models import *
+import collections
+from django.core.mail import EmailMessage
+from django.utils.translation import ugettext as _
+import settings
+
+class Command(NoArgsCommand):
+ def handle_noargs(self,**options):
+ try:
+ self.send_email_alerts()
+ except Exception, e:
+ print e
+ finally:
+ connection.close()
+
+ def send_email_alerts(self):
+ report_time = datetime.datetime.now()
+ feeds = EmailFeed.objects.all()
+ user_ctype = ContentType.objects.get_for_model(User)
+
+ #lists of update messages keyed by email address
+ update_collection = collections.defaultdict(list)
+ for feed in feeds:
+ update_summary = feed.get_update_summary()
+ if update_summary != None:
+ email = feed.get_email()
+ update_collection[email].append(update_summary)
+ feed.reported_at = report_time
+ feed.save()
+
+ for email, updates in update_collection.items():
+ text = '\n'.join(updates)
+ subject = _('updates from website')
+ print 'sent %s to %s' % (updates,email)
+ msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [email])
+ msg.content_subtype = 'html'
+ msg.send()
+
+
--
cgit v1.2.3-1-g7c22
From 40b5c06085fe3d079094e8ef779a7b119586f9e8 Mon Sep 17 00:00:00 2001
From: root
Date: Fri, 13 Nov 2009 20:18:31 -0500
Subject: better comments, email subscriptions, corrected view counter, some
ie7 issues, wiki optional with settings.WIKI_ON, site can be mounted on
arbitrary url prefix, english language improvements, added feedback form,
versioned css and js files to force browser cache reload when
settings.RESOURCE_REVISION is incremented , other fixes
---
forum/management/commands/send_email_alerts.py | 139 ++++++++++++++++++++-----
1 file changed, 115 insertions(+), 24 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index 3c37aaa3..a25e4343 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -1,9 +1,11 @@
from django.core.management.base import NoArgsCommand
from django.db import connection
+from django.db.models import Q, F
from forum.models import *
-import collections
from django.core.mail import EmailMessage
from django.utils.translation import ugettext as _
+from django.utils.translation import ungettext
+import datetime
import settings
class Command(NoArgsCommand):
@@ -15,27 +17,116 @@ class Command(NoArgsCommand):
finally:
connection.close()
+ def get_updated_questions_for_user(self,user):
+ q_sel = []
+ q_ask = []
+ q_ans = []
+ q_all = []
+ now = datetime.datetime.now()
+ Q_set1 = Question.objects.exclude(
+ last_activity_by=user,
+ ).exclude(
+ last_activity_at__lt=user.date_joined
+ ).filter(
+ Q(viewed__who=user,viewed__when__lt=F('last_activity_at')) | \
+ ~Q(viewed__who=user)
+ ).exclude(
+ deleted=True
+ ).exclude(
+ closed=True
+ )
+ user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
+ 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)
+ 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
+ elif feed.feed_type == 'q_ask':
+ q_ask = Q_set.filter(author=user)
+ q_ask.cutoff_time = cutoff_time
+ elif feed.feed_type == 'q_ans':
+ q_ans = Q_set.filter(answers__author=user)
+ q_ans.cutoff_time = cutoff_time
+ elif feed.feed_type == 'q_all':
+ q_all = Q_set
+ q_all.cutoff_time = cutoff_time
+ #build list in this order
+ q_tbl = {}
+ def extend_question_list(src, dst):
+ if isinstance(src,list):
+ return
+ cutoff_time = src.cutoff_time
+ for q in src:
+ if q in dst:
+ if cutoff_time < dst[q]:
+ dst[q] = cutoff_time
+ else:
+ dst[q] = 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)
+
+ ctype = ContentType.objects.get_for_model(Question)
+ out = {}
+ for q, cutoff_time in q_tbl.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)
+ q_rev = q_rev.exclude(author=user)
+ out[q]['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
+ else:
+ out[q]['new_q'] = False
+
+ new_ans = Answer.objects.filter(question=q,added_at__lt=cutoff_time)
+ 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)
+ ans_rev = ans_rev.exclude(author=user)
+ out[q]['ans_rev'] = len(ans_rev)
+ return out
+
+ def __act_count(self,string,number,output):
+ if number > 0:
+ output.append(_(string) % {'num':number})
+
def send_email_alerts(self):
- report_time = datetime.datetime.now()
- feeds = EmailFeed.objects.all()
- user_ctype = ContentType.objects.get_for_model(User)
-
- #lists of update messages keyed by email address
- update_collection = collections.defaultdict(list)
- for feed in feeds:
- update_summary = feed.get_update_summary()
- if update_summary != None:
- email = feed.get_email()
- update_collection[email].append(update_summary)
- feed.reported_at = report_time
- feed.save()
-
- for email, updates in update_collection.items():
- text = '\n'.join(updates)
- subject = _('updates from website')
- print 'sent %s to %s' % (updates,email)
- msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [email])
- msg.content_subtype = 'html'
- msg.send()
-
-
+
+ for user in User.objects.all():
+ q_list = self.get_updated_questions_for_user(user)
+ num_q = len(q_list)
+ if num_q > 0:
+ url_prefix = settings.APP_URL
+ subject = _('email update message subject')
+ text = ungettext('%(name)s, this is an update message header for a question',
+ '%(name)s, this is an update message header for %(num)d questions',num_q) \
+ % {'num':num_q, 'name':user.username}
+
+ text += ''
+ for q, act 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 += '- %s (%s)
' \
+ % (url_prefix + q.get_absolute_url(), q.title, act_token)
+ text += '
'
+ 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]}
+ msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [user.email])
+ msg.content_subtype = 'html'
+ msg.send()
--
cgit v1.2.3-1-g7c22
From 59e445ae892cea104a7d5354027c72c60294815a Mon Sep 17 00:00:00 2001
From: Evgeny Fadeev
Date: Mon, 23 Nov 2009 21:16:31 -0500
Subject: improved email subscription job, some small fixes, users now can
change their screen name any time
---
forum/management/commands/send_email_alerts.py | 134 +++++++++++++++++--------
1 file changed, 93 insertions(+), 41 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
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 += ''
- 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 += '- %s (%s)
' \
- % (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 += '- %s (%s)
' \
+ % (url_prefix + q.get_absolute_url(), q.title, act_token)
text += '
'
+ if num_moot > 0:
+ text += ''
+ 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 += '
'
+
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]}
--
cgit v1.2.3-1-g7c22
From 86250a6d49e69ff04d128d11bfa82d9a7b345bbf Mon Sep 17 00:00:00 2001
From: Evgeny Fadeev
Date: Tue, 8 Dec 2009 22:50:21 -0500
Subject: added interesting and ignored tag selectors (works) and per-tag
subscription (not tested yet)
---
forum/management/commands/send_email_alerts.py | 139 +++++++++++++------------
1 file changed, 75 insertions(+), 64 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index 8d52ed64..563aab69 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -38,73 +38,84 @@ class Command(NoArgsCommand):
).exclude(
closed=True
)
- user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
- 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)#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 #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
- elif feed.feed_type == 'q_ans':
- q_ans = Q_set.filter(answers__author=user)
- q_ans.cutoff_time = cutoff_time
- elif feed.feed_type == 'q_all':
- q_all = Q_set
- q_all.cutoff_time = cutoff_time
- #build list in this order
- q_list = OrderedDict()
- def extend_question_list(src, dst):
- """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]['cutoff_time']:
- dst[q]['cutoff_time'] = cutoff_time
- else:
- #initialise a questions metadata dictionary to use for email reporting
- dst[q] = {'cutoff_time':cutoff_time}
+ #todo: still need to add back individually selected and other questions....
+ #these may be filtered out by tags
+ if user.tag_filter_setting == 'ignored':
+ ignored_tags = user.markedtag_set.filter(reason='bad').values_list('tag', flat=True).distinct()
+ Q_set1 = Q_set1.exclude( tags__in=ignored_tags )
+ logging.debug('removed ignored tags')
+ else:
+ selected_tags = user.markedtag_set.filter(reason='good').values_list('tag', flat=True).distinct()
+ Q_set1 = Q_set1.filter( tags__in=selected_tags )
+ logging.debug('filtered for only selected tags')
+
+ user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
+ 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)#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 #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
+ elif feed.feed_type == 'q_ans':
+ q_ans = Q_set.filter(answers__author=user)
+ q_ans.cutoff_time = cutoff_time
+ elif feed.feed_type == 'q_all':
+ q_all = Q_set
+ q_all.cutoff_time = cutoff_time
+ #build list in this order
+ q_list = OrderedDict()
+ def extend_question_list(src, dst):
+ """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]['cutoff_time']:
+ dst[q]['cutoff_time'] = cutoff_time
+ else:
+ #initialise a questions metadata dictionary to use for email reporting
+ dst[q] = {'cutoff_time':cutoff_time}
- 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)
+ 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)
- 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)
- #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')
+ ctype = ContentType.objects.get_for_model(Question)
+ 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)
+ #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)
- meta_data['q_rev'] = len(q_rev)
- if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
+ q_rev = QuestionRevision.objects.filter(question=q,\
+ revised_at__lt=cutoff_time,\
+ revised_at__gt=emailed_at)
+ q_rev = q_rev.exclude(author=user)
+ meta_data['q_rev'] = len(q_rev)
+ if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
meta_data['q_rev'] = 0
meta_data['new_q'] = True
else:
--
cgit v1.2.3-1-g7c22
From 368c62b96a13d4fc340c67bbfc4048e227269070 Mon Sep 17 00:00:00 2001
From: Evgeny Fadeev
Date: Wed, 9 Dec 2009 12:13:08 -0500
Subject: better selector of ignored questions, split javascript tag_selector
into separate file, fixed question counter messages in the english lang file
---
forum/management/commands/send_email_alerts.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index 563aab69..4a636e87 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -41,11 +41,11 @@ class Command(NoArgsCommand):
#todo: still need to add back individually selected and other questions....
#these may be filtered out by tags
if user.tag_filter_setting == 'ignored':
- ignored_tags = user.markedtag_set.filter(reason='bad').values_list('tag', flat=True).distinct()
+ ignored_tags = Tag.objects.filter(user_selections___reason='bad',user_selections__user=user)
Q_set1 = Q_set1.exclude( tags__in=ignored_tags )
logging.debug('removed ignored tags')
else:
- selected_tags = user.markedtag_set.filter(reason='good').values_list('tag', flat=True).distinct()
+ selected_tags = Tag.objects.filter(user_selections___reason='good',user_selections__user=user)
Q_set1 = Q_set1.filter( tags__in=selected_tags )
logging.debug('filtered for only selected tags')
--
cgit v1.2.3-1-g7c22
From 5841b2c222f6cca42ba793d5360f8ab704c61adc Mon Sep 17 00:00:00 2001
From: Evgeny Fadeev
Date: Wed, 9 Dec 2009 19:57:25 -0500
Subject: added sitemap at /sitemap.xml and fixed per tag subscription
(hopefully)
---
forum/management/commands/send_email_alerts.py | 145 ++++++++++++-------------
1 file changed, 70 insertions(+), 75 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index 4a636e87..777381ec 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -38,84 +38,79 @@ class Command(NoArgsCommand):
).exclude(
closed=True
)
- #todo: still need to add back individually selected and other questions....
- #these may be filtered out by tags
- if user.tag_filter_setting == 'ignored':
- ignored_tags = Tag.objects.filter(user_selections___reason='bad',user_selections__user=user)
- Q_set1 = Q_set1.exclude( tags__in=ignored_tags )
- logging.debug('removed ignored tags')
- else:
- selected_tags = Tag.objects.filter(user_selections___reason='good',user_selections__user=user)
- Q_set1 = Q_set1.filter( tags__in=selected_tags )
- logging.debug('filtered for only selected tags')
-
- user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
- 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)#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 #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
- elif feed.feed_type == 'q_ans':
- q_ans = Q_set.filter(answers__author=user)
- q_ans.cutoff_time = cutoff_time
- elif feed.feed_type == 'q_all':
- q_all = Q_set
- q_all.cutoff_time = cutoff_time
- #build list in this order
- q_list = OrderedDict()
- def extend_question_list(src, dst):
- """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]['cutoff_time']:
- dst[q]['cutoff_time'] = cutoff_time
- else:
- #initialise a questions metadata dictionary to use for email reporting
- dst[q] = {'cutoff_time':cutoff_time}
+
+ user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
+ 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)#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 #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
+ elif feed.feed_type == 'q_ans':
+ q_ans = Q_set.filter(answers__author=user)
+ q_ans.cutoff_time = cutoff_time
+ elif feed.feed_type == 'q_all':
+ if user.tag_filter_setting == 'ignored':
+ ignored_tags = Tag.objects.filter(user_selections___reason='bad',user_selections__user=user)
+ q_all = Q_set.exclude( tags__in=ignored_tags )
+ else:
+ selected_tags = Tag.objects.filter(user_selections___reason='good',user_selections__user=user)
+ q_all = Q_set.filter( tags__in=selected_tags )
+ q_all.cutoff_time = cutoff_time
+ #build list in this order
+ q_list = OrderedDict()
+ def extend_question_list(src, dst):
+ """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]['cutoff_time']:
+ dst[q]['cutoff_time'] = cutoff_time
+ else:
+ #initialise a questions metadata dictionary to use for email reporting
+ dst[q] = {'cutoff_time':cutoff_time}
- 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)
+ 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)
- 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)
- #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')
+ ctype = ContentType.objects.get_for_model(Question)
+ 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)
+ #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)
- meta_data['q_rev'] = len(q_rev)
- if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
+ q_rev = QuestionRevision.objects.filter(question=q,\
+ revised_at__lt=cutoff_time,\
+ revised_at__gt=emailed_at)
+ q_rev = q_rev.exclude(author=user)
+ meta_data['q_rev'] = len(q_rev)
+ if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
meta_data['q_rev'] = 0
meta_data['new_q'] = True
else:
--
cgit v1.2.3-1-g7c22
From ab7193ae3ca32958fa64cd5222919a4ca95a33c1 Mon Sep 17 00:00:00 2001
From: Rick Ross
Date: Sat, 16 Jan 2010 08:29:11 -0500
Subject: modified try-except-finally blocks for python 2.4 compatibility
---
forum/management/commands/send_email_alerts.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index 777381ec..f5974e6b 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -14,9 +14,10 @@ from utils.odict import OrderedDict
class Command(NoArgsCommand):
def handle_noargs(self,**options):
try:
- self.send_email_alerts()
- except Exception, e:
- print e
+ try:
+ self.send_email_alerts()
+ except Exception, e:
+ print e
finally:
connection.close()
--
cgit v1.2.3-1-g7c22
From 2156804d24b5a8a877f1ea36674ac7fe078be9a0 Mon Sep 17 00:00:00 2001
From: Evgeny Fadeev
Date: Sun, 24 Jan 2010 19:53:00 -0500
Subject: recaptcha for conventional registration\n\ simpler email subscription
form at registration\n\ fixed urls in rss feed\n\ added experimental remote
password login api (cleartext password for remote site entered locally)\n\
included example for Mediawiki Authentication plugin\n\ very simple message
to everyone management command
---
forum/management/commands/send_email_alerts.py | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
index f5974e6b..62f13d69 100644
--- a/forum/management/commands/send_email_alerts.py
+++ b/forum/management/commands/send_email_alerts.py
@@ -7,7 +7,7 @@ from django.core.mail import EmailMessage
from django.utils.translation import ugettext as _
from django.utils.translation import ungettext
import datetime
-import settings
+from django.conf import settings
import logging
from utils.odict import OrderedDict
@@ -58,10 +58,10 @@ class Command(NoArgsCommand):
q_ans.cutoff_time = cutoff_time
elif feed.feed_type == 'q_all':
if user.tag_filter_setting == 'ignored':
- ignored_tags = Tag.objects.filter(user_selections___reason='bad',user_selections__user=user)
+ ignored_tags = Tag.objects.filter(user_selections__reason='bad',user_selections__user=user)
q_all = Q_set.exclude( tags__in=ignored_tags )
else:
- selected_tags = Tag.objects.filter(user_selections___reason='good',user_selections__user=user)
+ selected_tags = Tag.objects.filter(user_selections__reason='good',user_selections__user=user)
q_all = Q_set.filter( tags__in=selected_tags )
q_all.cutoff_time = cutoff_time
#build list in this order
@@ -154,6 +154,7 @@ class Command(NoArgsCommand):
if num_q > 0:
url_prefix = settings.APP_URL
subject = _('email update message subject')
+ print 'have %d updated questions for %s' % (num_q, user.username)
text = ungettext('%(name)s, this is an update message header for a question',
'%(name)s, this is an update message header for %(num)d questions',num_q) \
% {'num':num_q, 'name':user.username}
--
cgit v1.2.3-1-g7c22
From abc5fe0302f513848ec50dd8e8cbf4754bb7f841 Mon Sep 17 00:00:00 2001
From: Joseph Turian
Date: Sun, 7 Feb 2010 22:57:47 -0500
Subject: Moved applications into apps/ directory
---
forum/management/commands/send_email_alerts.py | 192 -------------------------
1 file changed, 192 deletions(-)
delete mode 100644 forum/management/commands/send_email_alerts.py
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
deleted file mode 100644
index 62f13d69..00000000
--- a/forum/management/commands/send_email_alerts.py
+++ /dev/null
@@ -1,192 +0,0 @@
-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
-from django.conf import settings
-import logging
-from utils.odict import OrderedDict
-
-class Command(NoArgsCommand):
- def handle_noargs(self,**options):
- try:
- try:
- self.send_email_alerts()
- except Exception, e:
- print e
- finally:
- connection.close()
-
- def get_updated_questions_for_user(self,user):
- 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,
- ).exclude(
- last_activity_at__lt=user.date_joined
- ).filter(
- Q(viewed__who=user,viewed__when__lt=F('last_activity_at')) | \
- ~Q(viewed__who=user)
- ).exclude(
- deleted=True
- ).exclude(
- closed=True
- )
-
- user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
- 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)#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 #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
- elif feed.feed_type == 'q_ans':
- q_ans = Q_set.filter(answers__author=user)
- q_ans.cutoff_time = cutoff_time
- elif feed.feed_type == 'q_all':
- if user.tag_filter_setting == 'ignored':
- ignored_tags = Tag.objects.filter(user_selections__reason='bad',user_selections__user=user)
- q_all = Q_set.exclude( tags__in=ignored_tags )
- else:
- selected_tags = Tag.objects.filter(user_selections__reason='good',user_selections__user=user)
- q_all = Q_set.filter( tags__in=selected_tags )
- q_all.cutoff_time = cutoff_time
- #build list in this order
- q_list = OrderedDict()
- def extend_question_list(src, dst):
- """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]['cutoff_time']:
- dst[q]['cutoff_time'] = cutoff_time
- else:
- #initialise a questions metadata dictionary to use for email reporting
- dst[q] = {'cutoff_time':cutoff_time}
-
- 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)
- 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)
- #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)
- meta_data['q_rev'] = len(q_rev)
- if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
- meta_data['q_rev'] = 0
- meta_data['new_q'] = True
- else:
- meta_data['new_q'] = False
-
- new_ans = Answer.objects.filter(question=q,\
- added_at__lt=cutoff_time,\
- added_at__gt=emailed_at)
- new_ans = new_ans.exclude(author=user)
- 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)
- 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 __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 = 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')
- print 'have %d updated questions for %s' % (num_q, user.username)
- text = ungettext('%(name)s, this is an update message header for a question',
- '%(name)s, this is an update message header for %(num)d questions',num_q) \
- % {'num':num_q, 'name':user.username}
-
- text += ''
- for q, meta_data in q_list.items():
- act_list = []
- 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 += '- %s (%s)
' \
- % (url_prefix + q.get_absolute_url(), q.title, act_token)
- text += '
'
- if num_moot > 0:
- text += ''
- 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 += ''
-
- 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]}
- msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [user.email])
- msg.content_subtype = 'html'
- msg.send()
--
cgit v1.2.3-1-g7c22
From b2d9fb47fd657d2da515d7bb88bcc0fb2a9b5785 Mon Sep 17 00:00:00 2001
From: Joseph Turian
Date: Sun, 7 Feb 2010 23:55:58 -0500
Subject: Moved apps back into base dir
---
forum/management/commands/send_email_alerts.py | 192 +++++++++++++++++++++++++
1 file changed, 192 insertions(+)
create mode 100644 forum/management/commands/send_email_alerts.py
(limited to 'forum/management/commands/send_email_alerts.py')
diff --git a/forum/management/commands/send_email_alerts.py b/forum/management/commands/send_email_alerts.py
new file mode 100644
index 00000000..62f13d69
--- /dev/null
+++ b/forum/management/commands/send_email_alerts.py
@@ -0,0 +1,192 @@
+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
+from django.conf import settings
+import logging
+from utils.odict import OrderedDict
+
+class Command(NoArgsCommand):
+ def handle_noargs(self,**options):
+ try:
+ try:
+ self.send_email_alerts()
+ except Exception, e:
+ print e
+ finally:
+ connection.close()
+
+ def get_updated_questions_for_user(self,user):
+ 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,
+ ).exclude(
+ last_activity_at__lt=user.date_joined
+ ).filter(
+ Q(viewed__who=user,viewed__when__lt=F('last_activity_at')) | \
+ ~Q(viewed__who=user)
+ ).exclude(
+ deleted=True
+ ).exclude(
+ closed=True
+ )
+
+ user_feeds = EmailFeedSetting.objects.filter(subscriber=user).exclude(frequency='n')
+ 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)#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 #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
+ elif feed.feed_type == 'q_ans':
+ q_ans = Q_set.filter(answers__author=user)
+ q_ans.cutoff_time = cutoff_time
+ elif feed.feed_type == 'q_all':
+ if user.tag_filter_setting == 'ignored':
+ ignored_tags = Tag.objects.filter(user_selections__reason='bad',user_selections__user=user)
+ q_all = Q_set.exclude( tags__in=ignored_tags )
+ else:
+ selected_tags = Tag.objects.filter(user_selections__reason='good',user_selections__user=user)
+ q_all = Q_set.filter( tags__in=selected_tags )
+ q_all.cutoff_time = cutoff_time
+ #build list in this order
+ q_list = OrderedDict()
+ def extend_question_list(src, dst):
+ """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]['cutoff_time']:
+ dst[q]['cutoff_time'] = cutoff_time
+ else:
+ #initialise a questions metadata dictionary to use for email reporting
+ dst[q] = {'cutoff_time':cutoff_time}
+
+ 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)
+ 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)
+ #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)
+ meta_data['q_rev'] = len(q_rev)
+ if len(q_rev) > 0 and q.added_at == q_rev[0].revised_at:
+ meta_data['q_rev'] = 0
+ meta_data['new_q'] = True
+ else:
+ meta_data['new_q'] = False
+
+ new_ans = Answer.objects.filter(question=q,\
+ added_at__lt=cutoff_time,\
+ added_at__gt=emailed_at)
+ new_ans = new_ans.exclude(author=user)
+ 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)
+ 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 __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 = 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')
+ print 'have %d updated questions for %s' % (num_q, user.username)
+ text = ungettext('%(name)s, this is an update message header for a question',
+ '%(name)s, this is an update message header for %(num)d questions',num_q) \
+ % {'num':num_q, 'name':user.username}
+
+ text += ''
+ for q, meta_data in q_list.items():
+ act_list = []
+ 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 += '- %s (%s)
' \
+ % (url_prefix + q.get_absolute_url(), q.title, act_token)
+ text += '
'
+ if num_moot > 0:
+ text += ''
+ 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 += ''
+
+ 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]}
+ msg = EmailMessage(subject, text, settings.DEFAULT_FROM_EMAIL, [user.email])
+ msg.content_subtype = 'html'
+ msg.send()
--
cgit v1.2.3-1-g7c22