def email_new_user_summary(self, frequency_of_timed_task="days=1"): """ query for all users in last <timedelta> and email """ frequency_of_timed_task = timedelta_from_str(frequency_of_timed_task) from civicboom.model import Member members = Session.query(Member) \ .with_polymorphic('*') \ .filter(Member.join_date>=normalize_datetime(now()) - frequency_of_timed_task) \ .all() if not members: log.debug('Report not generated: no new members in %s' % frequency_of_timed_task) return response_completed_ok from civicboom.lib.communication.email_lib import send_email send_email( config['email.event_alert'], subject ='new user registration summary', content_html = render( '/email/admin/summary_new_users.mako', extra_vars = { "members" : members , "timedelta" : frequency_of_timed_task , } ), ) return response_completed_ok
def assignment_near_expire(self, frequency_of_timed_task="days=1"): """ Users who have accepted assigments but have not posted response question should be reminded via a notification that the assingment has not long left """ from civicboom.model.content import AssignmentContent from civicboom.lib.communication import messages def get_assignments_by_date(date_start, date_end): return Session.query(AssignmentContent).filter(and_(AssignmentContent.due_date >= date_start, AssignmentContent.due_date <= date_end)).all() def get_responded(assignment): return [response.creator_id for response in assignment.responses] frequency_of_timed_task = timedelta_from_str(frequency_of_timed_task) date_7days_time = normalize_datetime(now() + datetime.timedelta(days=7)) date_1days_time = normalize_datetime(now() + datetime.timedelta(days=1)) for assignment in get_assignments_by_date(date_start=date_7days_time, date_end=date_7days_time + frequency_of_timed_task): # Get all assignments due in 7 days responded_member_ids = get_responded(assignment) # Get a list of all the members that have responded to this assignment for member in [member for member in assignment.accepted_by if member.id not in responded_member_ids]: # For all members accepted this assignment # Check if they have responded with an article member.send_notification( messages.assignment_due_7days(you=member, assignment=assignment) ) # if not send a reminder notification for assignment in get_assignments_by_date(date_start=date_1days_time, date_end=date_1days_time + frequency_of_timed_task): #Same as above but on day before responded_member_ids = get_responded(assignment) for member in [member for member in assignment.accepted_by if member.id not in responded_member_ids]: member.send_notification( messages.assignment_due_1day (you=member, assignment=assignment) ) Session.commit() return response_completed_ok
def _to_python(self, value, state): timedelta_kwargs = validators.UnicodeString._to_python( self, value, state) try: value = timedelta_from_str(timedelta_kwargs) except Exception as e: raise formencode.Invalid(self.message("invalid_format", state), value, state) return value
def remind_pending_users(self, remind_after="hours=24", frequency_of_timed_task="hours=1"): """ Users who try to sign up but don't complete the registration within one day get a reminder email to be run once every 24 hours """ from civicboom.model.member import User from civicboom.lib.accounts import validation_url frequency_of_timed_task = timedelta_from_str(frequency_of_timed_task) remind_after = timedelta_from_str(remind_after ) reminder_start = normalize_datetime(now() - remind_after ) reminder_end = normalize_datetime(reminder_start + frequency_of_timed_task) users_to_remind = Session.query(User).filter(User.status=='pending').filter(and_(User.join_date <= reminder_end, User.join_date >= reminder_start)).all() #.filter(~User.login_details.any()). for user in users_to_remind: log.info('Reminding pending user %s - %s' % (user.username, user.email_normalized)) register_url = validation_url(user, controller='register', action='new_user') user.send_email(subject=_('_site_name: reminder'), content_html=render('/email/user_pending_reminder.mako', extra_vars={'register_url':register_url})) return response_completed_ok
def summary_notification_email(self, frequency_of_timed_task="hours=1"): """ users that have flag themselfs as requesting summary emails can have 24 hours of notifications summerised TODO: In future this could take into account utc offset TODO: don't change the frequencey from 1 hour as this break interval_anchor """ from civicboom.model import User, Message from sqlalchemy import null frequency_of_timed_task = timedelta_from_str(frequency_of_timed_task) datetime_now = normalize_datetime(now()) def summary_notification_email_user(user): """ All users passed to this methdod have been selected using a query to ensure they have the field 'summary_email_interval' """ # Normalize the interval and ancor to the previous hour to assess if we are on a interval boundary if user.summary_email_start: interval_ancor = datetime_now - normalize_datetime(user.summary_email_start, accuracy='hour') # todo ... this really should be linked the frequncy of timed task else: interval_ancor = datetime_now - normalize_datetime(datetime_now , accuracy='week') interval_ancor = interval_ancor.total_seconds() interval = user.summary_email_interval.total_seconds() # If on interval boundary if (interval_ancor % interval) == 0: # Select all messages from since the previous interval messages = Session.query(Message).filter(or_(Message.target_id==user.id,Message.source_id==user.id)).filter(Message.timestamp >= (datetime_now-user.summary_email_interval)).order_by(Message.timestamp).all() # No need to send email summary if no messages have been generated in the last interval if messages: content_html = render('/email/notifications/summary.mako', extra_vars={'messages':messages, 'user':user}) user.send_email( subject = _('_site_name: Summary'), content_html = content_html, ) # Test output - used to debug email layout #import os #file = open(os.path.expanduser("~/Temp/out.html"), 'w') #file.write(content_html) #file.close() process_db_chunk( Session.query(User).filter(User.summary_email_interval!=null()), #and_(User.summary_email_start, summary_notification_email_user ) return response_completed_ok
def remove_pending_users(self, delete_older_than="days=7"): """ Users who do not complete the signup process by entering an email address that is incorrect or a bots or cant use email should be removed if they have still not signed up after 7 Days """ from civicboom.model.member import User ghost_expire = normalize_datetime(now() - timedelta_from_str(delete_older_than)) for user in Session.query(User).filter(User.status=='pending').filter(User.join_date <= ghost_expire).all(): # .filter(~User.login_details.any()). Session.delete(user) log.info('Deleting pending user %s - %s' % (user.username, user.email_normalized)) # It may be nice to log numbers here to aid future business desctions Session.commit() # AllanC - the method above could be inefficent. could just do it at the DB side? return response_completed_ok
def publish_scheduled_content(self, frequency_of_timed_task="hours=1"): """ query for all users in last <timedelta> and email """ frequency_of_timed_task = timedelta_from_str(frequency_of_timed_task) datetime_now = normalize_datetime(now()) from civicboom.model.content import DraftContent from civicboom.controllers.contents import ContentsController content_publish = ContentsController().update def get_content_to_publish(date_start, date_end): return Session.query(DraftContent).filter(and_(DraftContent.auto_publish_trigger_datetime >= date_start, DraftContent.auto_publish_trigger_datetime <= date_end)).all() # AllanC - calls will be made to content.py:update this will trigger the normal decorators, we need to ensure that these dont prohibit the update call's we are about to make c.authenticated_form = True # AllanC - Fake the authenticated status so that the auth decorator does not tigger c.format = 'python' for content in get_content_to_publish(datetime_now, datetime_now + frequency_of_timed_task): log.info('Auto publishing content #%s - %s' % (content.id, content.title)) # By calling the content:update method with no param with the content as a draft, it automatically pubishs the content content_publish(content, submit_publish=True) return response_completed_ok