<commit_before>from django.core.management.base import NoArgsCommand
from django.contrib.auth.models import User,Group
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.utils.translation import ugettext as _
from django.utils import translation
from django.template.loader import render_to_string
from django.template import TemplateDoesNotExist
from django.conf import settings
import datetime
from optparse import make_option
import logging
logger = logging.getLogger("open-knesset.notify") 

from actstream.models import Follow, Action
from mailer import send_html_mail
from knesset.mks.models import Member
from knesset.agendas.models import Agenda
from knesset.notify.models import LastSent
from knesset.user.models import UserProfile

class Command(NoArgsCommand):
    help = "Send e-mail notification to users that requested it."

    requires_model_validation = False

    update_models = [Member,Agenda,None]
    from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', '<EMAIL>')
    days_back = getattr(settings, 'DEFAULT_NOTIFICATION_DAYS_BACK', 10)
    lang = getattr(settings, 'LANGUAGE_CODE', 'he')
    domain = Site.objects.get_current().domain

    option_list = NoArgsCommand.option_list + (
        make_option('--daily', action='store_true', dest='daily',
            help="send notifications to users that requested a daily update"),
        make_option('--weekly', action='store_true', dest='weekly',
            help="send notifications to users that requested a weekly update"))
            
    
    @classmethod
    def get_model_headers(cls, model):
        ''' for a given model this function returns a tuple with 
            (model, text_header, html_header)
        '''
        try:
            template_name = 'notify/%s_section' % model.__name__.lower()
            return (model, render_to_string(template_name + '.txt'), render_to_string(template_name + '.html')) 
        except TemplateDoesNotExist:
            return (model, model._meta.verbose_name_plural, '<h2>%s</h2>' % model._meta.verbose_name_plural.format()) 
        except AttributeError:
            return (model, _('Other Updates'), _('Other Updates')) 

    def get_email_for_user(self, user):
        updates = dict(zip(self.update_models, ([] for x in self.update_models))) # will contain the updates to be sent
        updates_html = dict(zip(self.update_models, ([] for x in self.update_models)))
        follows = Follow.objects.filter(user=user) # everything this user is following
        # sometime a user follows something several times. we want to filter that out:
        follows = set([f.actor for f in follows])
        for f in follows:
            model_class = f.__class__
            model_template = f.__class__.__name__.lower()
            try: 
                model_name = f.__class__._meta.verbose_name
            except AttributeError:
                logger.warning('follows %d has no __class__?' % f.id)
                model_name = ""
            content_type = ContentType.objects.get_for_model(f)
            if model_class in updates:
                key = model_class
            else:
                key = None # put all updates for 'other' classes at the 'None' group
            try: # get actions that happened since last update
                last_sent = LastSent.objects.get(user=user, content_type=content_type, object_pk=f.id)
                last_sent_time = last_sent.time
                stream = Action.objects.filter(actor_content_type = content_type,
                                               actor_object_id = f.id,
                                               timestamp__gt=last_sent_time,
                                               ).order_by('-timestamp')
                last_sent.save() # update timestamp
            except LastSent.DoesNotExist: # never updates about this actor, send some updates 
                stream = Action.objects.filter(actor_content_type = content_type,
                                               actor_object_id = f.id,
                                               timestamp__gt=datetime.datetime.now()-datetime.timedelta(self.days_back),
                                               ).order_by('-timestamp')
                last_sent = LastSent.objects.create(user=user,content_type=content_type, object_pk=f.id)
            if stream: # this actor has some updates
                try: # genereate the appropriate header for this actor class
                    header = render_to_string(('notify/%(model)s_header.txt' % {'model': model_template}),{'model':model_name,'object':f})
                except TemplateDoesNotExist:
                    header = render_to_string(('notify/model_header.txt'),{'model':model_name,'object':f})<commit_msg>ignore follow relationships with None actor in sending notifications.<commit_after>from django.core.management.base import NoArgsCommand
from django.contrib.auth.models import User,Group
from django.contrib.contenttypes.models import ContentType
from django.contrib.sites.models import Site
from django.utils.translation import ugettext as _
from django.utils import translation
from django.template.loader import render_to_string
from django.template import TemplateDoesNotExist
from django.conf import settings
import datetime
from optparse import make_option
import logging
logger = logging.getLogger("open-knesset.notify") 

from actstream.models import Follow, Action
from mailer import send_html_mail
from knesset.mks.models import Member
from knesset.agendas.models import Agenda
from knesset.notify.models import LastSent
from knesset.user.models import UserProfile

class Command(NoArgsCommand):
    help = "Send e-mail notification to users that requested it."

    requires_model_validation = False

    update_models = [Member,Agenda,None]
    from_email = getattr(settings, 'DEFAULT_FROM_EMAIL', '<EMAIL>')
    days_back = getattr(settings, 'DEFAULT_NOTIFICATION_DAYS_BACK', 10)
    lang = getattr(settings, 'LANGUAGE_CODE', 'he')
    domain = Site.objects.get_current().domain

    option_list = NoArgsCommand.option_list + (
        make_option('--daily', action='store_true', dest='daily',
            help="send notifications to users that requested a daily update"),
        make_option('--weekly', action='store_true', dest='weekly',
            help="send notifications to users that requested a weekly update"))
            
    
    @classmethod
    def get_model_headers(cls, model):
        ''' for a given model this function returns a tuple with 
            (model, text_header, html_header)
        '''
        try:
            template_name = 'notify/%s_section' % model.__name__.lower()
            return (model, render_to_string(template_name + '.txt'), render_to_string(template_name + '.html')) 
        except TemplateDoesNotExist:
            return (model, model._meta.verbose_name_plural, '<h2>%s</h2>' % model._meta.verbose_name_plural.format()) 
        except AttributeError:
            return (model, _('Other Updates'), _('Other Updates')) 

    def get_email_for_user(self, user):
        updates = dict(zip(self.update_models, ([] for x in self.update_models))) # will contain the updates to be sent
        updates_html = dict(zip(self.update_models, ([] for x in self.update_models)))
        follows = Follow.objects.filter(user=user) # everything this user is following
        # sometime a user follows something several times. we want to filter that out:
        follows = set([f.actor for f in follows])
        for f in follows:
            if not f:
                logger.warning('Follow object with None actor. ignoring')
                continue
            model_class = f.__class__
            model_template = f.__class__.__name__.lower()
            try: 
                model_name = f.__class__._meta.verbose_name
            except AttributeError:
                logger.warning('follows %d has no __class__?' % f.id)
                model_name = ""
            content_type = ContentType.objects.get_for_model(f)
            if model_class in updates:
                key = model_class
            else:
                key = None # put all updates for 'other' classes at the 'None' group
            try: # get actions that happened since last update
                last_sent = LastSent.objects.get(user=user, content_type=content_type, object_pk=f.id)
                last_sent_time = last_sent.time
                stream = Action.objects.filter(actor_content_type = content_type,
                                               actor_object_id = f.id,
                                               timestamp__gt=last_sent_time,
                                               ).order_by('-timestamp')
                last_sent.save() # update timestamp
            except LastSent.DoesNotExist: # never updates about this actor, send some updates 
                stream = Action.objects.filter(actor_content_type = content_type,
                                               actor_object_id = f.id,
                                               timestamp__gt=datetime.datetime.now()-datetime.timedelta(self.days_back),
                                               ).order_by('-timestamp')
                last_sent = LastSent.objects.create(user=user,content_type=content_type, object_pk=f.id)
            if stream: # this actor has some updates
                try: # genereate the appropriate header for this actor class
                    header = render_to_string(('notify/%(model)s_header.txt' % {'model': model_template}),{'model':model_name,'object':f})
                except TemplateDoesNotExist:
                    header = render_to_string(('notify/model_header.txt'),{'model':model_name,'object':f})
{'fraction_non_alphanumeric': 0.0871339659218447, 'fraction_numerical': 0.0008162432404856647, 'mean_word_length': 2.4392982456140353, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3394110', 'n_tokens_mistral': 2535, 'n_tokens_neox': 2471, 'n_words': 669}