def feedback(request): data = {'page_class': 'meta'} form = None if openode_settings.ALLOW_ANONYMOUS_FEEDBACK is False: if request.user.is_anonymous(): message = _('Please sign in or register to send your feedback') request.user.message_set.create(message=message) redirect_url = get_login_url() + '?next=' + request.path return HttpResponseRedirect(redirect_url) if request.method == "POST": form = FeedbackForm( is_auth=request.user.is_authenticated(), data=request.POST ) if form.is_valid(): if not request.user.is_authenticated(): data['email'] = form.cleaned_data.get('email',None) data['message'] = form.cleaned_data['message'] data['name'] = form.cleaned_data.get('name',None) template = get_template('email/feedback_email.txt', request) message = template.render(RequestContext(request, data)) mail_moderators(_('Q&A forum feedback'), message) msg = _('Thanks for the feedback!') request.user.message_set.create(message=msg) return HttpResponseRedirect(get_next_url(request)) else: form = FeedbackForm(is_auth = request.user.is_authenticated(), initial={'next':get_next_url(request)}) data['form'] = form return render_into_skin('feedback.html', data, request)
def feedback(request): data = {'page_class': 'meta'} form = None if openode_settings.ALLOW_ANONYMOUS_FEEDBACK is False: if request.user.is_anonymous(): message = _('Please sign in or register to send your feedback') request.user.message_set.create(message=message) redirect_url = get_login_url() + '?next=' + request.path return HttpResponseRedirect(redirect_url) if request.method == "POST": form = FeedbackForm(is_auth=request.user.is_authenticated(), data=request.POST) if form.is_valid(): if not request.user.is_authenticated(): data['email'] = form.cleaned_data.get('email', None) data['message'] = form.cleaned_data['message'] data['name'] = form.cleaned_data.get('name', None) template = get_template('email/feedback_email.txt', request) message = template.render(RequestContext(request, data)) mail_moderators(_('Q&A forum feedback'), message) msg = _('Thanks for the feedback!') request.user.message_set.create(message=msg) return HttpResponseRedirect(get_next_url(request)) else: form = FeedbackForm(is_auth=request.user.is_authenticated(), initial={'next': get_next_url(request)}) data['form'] = form return render_into_skin('feedback.html', data, request)
def process_reply(func): @functools.wraps(func) def wrapped(message, host = None, address = None): """processes forwarding rules, and run the handler in the case of error, send a bounce email """ try: for rule in django_settings.LAMSON_FORWARD: if re.match(rule['pattern'], message.base['to']): relay = Relay(host=rule['host'], port=rule['port'], debug=1) relay.deliver(message) return except AttributeError: pass error = None try: reply_address = ReplyAddress.objects.get( address = address, allowed_from_email = message.From ) #here is the business part of this function parts = get_parts(message) for part_type, content in parts: if part_type == 'body': print '===============================' print 'message :', content break else: continue func( from_address = message.From, subject_line = message['Subject'], parts = parts, reply_address_object = reply_address ) except ReplyAddress.DoesNotExist: error = _("You were replying to an email address\ unknown to the system or you were replying from a different address from the one where you\ received the notification.") except Exception, e: import sys sys.stderr.write(str(e)) import traceback sys.stderr.write(traceback.format_exc()) if error is not None: template = get_template('email/reply_by_email_error.html') body_text = template.render(Context({'error':error})) mail.send_mail( subject_line = "Error posting your reply", body_text = body_text, recipient_list = [message.From], )
def PROCESS( parts = None, reply_address_object = None, subject_line = None, from_address = None, **kwargs ): """handler to process the emailed message and make a post to openode based on the contents of the email, including the text body and the file attachments""" #1) get actual email content # todo: factor this out into the process_reply decorator reply_code = reply_address_object.address body_text, stored_files, signature = mail.process_parts(parts, reply_code) #2) process body text and email signature user = reply_address_object.user if signature:#if there, then it was stripped if signature != user.email_signature: user.email_signature = signature else:#try to strip signature stripped_body_text = user.strip_email_signature(body_text) #todo: add test cases for emails without the signature if stripped_body_text == body_text and user.email_signature: #todo: send an email asking to update the signature raise ValueError('email signature changed or unknown') body_text = stripped_body_text #3) validate email address and save user user.email_isvalid = True user.save()#todo: actually, saving is not necessary, if nothing changed #4) actually make an edit in the forum robj = reply_address_object add_post_actions = ('post_comment', 'post_answer', 'auto_answer_or_comment') if robj.reply_action == 'replace_content': robj.edit_post(body_text, title = subject_line) elif robj.reply_action == 'append_content': robj.edit_post(body_text)#in this case we don't touch the title elif robj.reply_action in add_post_actions: if robj.was_used: robj.edit_post(body_text, edit_response = True) else: robj.create_reply(body_text) elif robj.reply_action == 'validate_email': #todo: this is copy-paste - factor it out to openode.mail.messages data = { 'site_name': openode_settings.APP_SHORT_NAME, 'site_url': openode_settings.APP_URL, 'ask_address': 'ask@' + openode_settings.REPLY_BY_EMAIL_HOSTNAME } template = get_template('email/re_welcome_lamson_on.html') mail.send_mail( subject_line = _('Re: %s') % subject_line, body_text = template.render(Context(data)), recipient_list = [from_address,] )
def create_response(self): term = self.request.GET.get('autoq', '').strip() self.query = term sqs = self.update_search_query(SearchQuerySet().all(), # term=term, )[:self.RESULTS_COUNT + 1] templates = { "openode.node": get_template("search/results/autocomplete_node.html"), "openode.questionproxy": get_template("search/results/autocomplete_question.html"), "openode.answerproxy": get_template("search/results/autocomplete_answer.html"), "openode.discussionpostproxy": get_template("search/results/autocomplete_discussion_post.html"), "document.document": get_template("search/results/autocomplete_document.html"), "document.page": get_template("search/results/autocomplete_document.html"), "openode.organization": get_template("search/results/autocomplete_organization.html"), "auth.user": get_template("search/results/autocomplete_user.html"), } suggestions = [] for i, result in enumerate(sqs): if i < self.RESULTS_COUNT: suggestions.append({ "label": templates[result.content_type()].render({"result": result}), "value": result.title.strip(), "url": result.url, }) if len(sqs) > self.RESULTS_COUNT: suggestions.append({ "label": u'<span class="more-results">%s</span>' % _('more results'), "value": term, "url": u'%s?q=%s' % (reverse('search'), term), }) json_data = json.dumps({"results": suggestions}) return HttpResponse(json_data, content_type='application/json')
def notify_about_requests(user_list, subject, text): data = { 'text': text, 'site_name': openode_settings.APP_SHORT_NAME, 'site_url': openode_settings.APP_URL } template = get_template('email/notification.html') message = template.render(data) email_list = [user.email for user in user_list] mail.send_mail(subject, message, django_settings.DEFAULT_FROM_EMAIL, email_list, raise_on_failure=True)
def create_response(self): term = self.request.GET.get('autoq', '').strip() self.query = term sqs = self.update_search_query( SearchQuerySet().all(), # term=term, )[:self.RESULTS_COUNT + 1] templates = { "openode.node": get_template("search/results/autocomplete_node.html"), "openode.questionproxy": get_template("search/results/autocomplete_question.html"), "openode.answerproxy": get_template("search/results/autocomplete_answer.html"), "openode.discussionpostproxy": get_template("search/results/autocomplete_discussion_post.html"), "document.document": get_template("search/results/autocomplete_document.html"), "document.page": get_template("search/results/autocomplete_document.html"), "openode.organization": get_template("search/results/autocomplete_organization.html"), "auth.user": get_template("search/results/autocomplete_user.html"), } suggestions = [] for i, result in enumerate(sqs): if i < self.RESULTS_COUNT: suggestions.append( { "label": templates[result.content_type()].render({"result": result}), "value": result.title.strip(), "url": result.url, } ) if len(sqs) > self.RESULTS_COUNT: suggestions.append( { "label": u'<span class="more-results">%s</span>' % _('more results'), "value": term, "url": u'%s?q=%s' % (reverse('search'), term), } ) json_data = json.dumps({ "results": suggestions }) return HttpResponse(json_data, content_type='application/json')
def VALIDATE_EMAIL( parts = None, reply_address_object = None, from_address = None, **kwargs ): """process the validation email and save the email signature todo: go a step further and """ reply_code = reply_address_object.address try: content, stored_files, signature = mail.process_parts(parts, reply_code) user = reply_address_object.user if signature and signature != user.email_signature: user.email_signature = signature user.email_isvalid = True user.save() data = { 'site_name': openode_settings.APP_SHORT_NAME, 'site_url': openode_settings.APP_URL, 'ask_address': 'ask@' + openode_settings.REPLY_BY_EMAIL_HOSTNAME } template = get_template('email/re_welcome_lamson_on.html') mail.send_mail( subject_line = _('Re: Welcome to %(site_name)s') % data, body_text = template.render(Context(data)), recipient_list = [from_address,] ) except ValueError: raise ValueError( _( 'Please reply to the welcome email ' 'without editing it' ) )
def handle_noargs(self, **options): if openode_settings.ENABLE_EMAIL_ALERTS == False: return if openode_settings.ENABLE_UNANSWERED_REMINDERS == False: return #get questions without answers, excluding closed and deleted #order it by descending added_at date schedule = ReminderSchedule( openode_settings.DAYS_BEFORE_SENDING_UNANSWERED_REMINDER, openode_settings.UNANSWERED_REMINDER_FREQUENCY, max_reminders = openode_settings.MAX_UNANSWERED_REMINDERS ) questions = models.Post.objects.get_questions().exclude( thread__closed = True ).exclude( deleted = True ).added_between( start = schedule.start_cutoff_date, end = schedule.end_cutoff_date ).filter( thread__answer_count = 0 ).order_by('-added_at') #for all users, excluding blocked #for each user, select a tag filtered subset #format the email reminder and send it for user in models.User.objects.exclude(status = 'b'): user_questions = questions.exclude(author = user) user_questions = user.get_tag_filtered_questions(user_questions) user_groups = user.get_groups() user_questions = user_questions.filter(groups__in = user_groups) final_question_list = user_questions.get_questions_needing_reminder( user = user, activity_type = const.TYPE_ACTIVITY_UNANSWERED_REMINDER_SENT, recurrence_delay = schedule.recurrence_delay ) question_count = len(final_question_list) if question_count == 0: continue threads = Thread.objects.filter(id__in=[qq.thread_id for qq in final_question_list]) tag_summary = Thread.objects.get_tag_summary_from_threads(threads) subject_line = ungettext( '%(question_count)d unanswered question about %(topics)s', '%(question_count)d unanswered questions about %(topics)s', question_count ) % { 'question_count': question_count, 'topics': tag_summary } data = { 'site_url': openode_settings.APP_URL, 'questions': final_question_list, 'subject_line': subject_line } template = get_template('email/unanswered_question_reminder.html') body_text = template.render(Context(data)) if DEBUG_THIS_COMMAND: print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \ (user.email, subject_line, body_text) else: mail.send_mail( subject_line = subject_line, body_text = body_text, recipient_list = (user.email,) )
def immediately_notify_users(post): # we don't want to disturb original routine try: # set default language TODO - language per user - add user atribute old_lang = get_language() activate(django_settings.LANGUAGE_CODE) DEBUG_THIS_COMMAND = getattr(django_settings, 'DEBUG_SEND_EMAIL_NOTIFICATIONS', True) # compose subject according to the post type subject_line = _('Notification') if post.post_type == const.POST_TYPE_QUESTION: subject_line += ': ' + _('Question') elif post.post_type == const.POST_TYPE_DOCUMENT: subject_line += ': ' + _('Document') elif post.post_type == const.POST_TYPE_COMMENT: subject_line += ': ' + _('Comment') elif post.post_type == const.POST_TYPE_THREAD_POST: if post.thread.thread_type == const.THREAD_TYPE_QUESTION: subject_line += ': ' + _('Answer') elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION: subject_line += ': ' + _('Discussion post') else: # post type is probably only a description, do nothing activate(old_lang) return False subject_line += ' - ' + post.thread.title # compose message according to post type url_prefix = openode_settings.APP_URL # link to node # text = u'<p>%s: <a href="%s">%s</a></p>' % (_('Node'), url_prefix + post.thread.node.get_absolute_url(), post.thread.node.full_title()) text = u'<p>%s: %s</p>' % (_('Node'), post.thread.node.full_title()) # title according to the post type text += '<h2>' if post.last_edited_by: # post was updated if post.post_type == const.POST_TYPE_QUESTION: text += _('Updated question') elif post.post_type == const.POST_TYPE_DOCUMENT: text += _('Updated document') elif post.post_type == const.POST_TYPE_COMMENT: text += _('Updated comment') elif post.post_type == const.POST_TYPE_THREAD_POST: if post.thread.thread_type == const.THREAD_TYPE_QUESTION: text += _('Updated answer') elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION: text += _('Updated discussion post') else: # post is new if post.post_type == const.POST_TYPE_QUESTION: text += _('New question') elif post.post_type == const.POST_TYPE_DOCUMENT: text += _('New document') elif post.post_type == const.POST_TYPE_COMMENT: text += _('New comment') elif post.post_type == const.POST_TYPE_THREAD_POST: if post.thread.thread_type == const.THREAD_TYPE_QUESTION: text += _('New answer') elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION: text += _('New discussion post') text += '</h2>' # link to post if post.post_type == const.POST_TYPE_DOCUMENT: url = url_prefix + post.thread.get_absolute_url() else: url = url_prefix + post.get_absolute_url() text += '<p><a href="%(url)s">%(url)s</a></p>' % {"url": url} # author text += '<p>' if post.last_edited_by: # post was updated text += _(u'%(datetime)s changed by <strong>%(user)s</strong>') % { 'datetime': humanize_datetime(post.last_edited_at, 0), 'user': post.last_edited_by.screen_name } else: # post is new text += _(u'%(datetime)s created by <strong>%(user)s</strong>') % { 'datetime': humanize_datetime(post.added_at, 0), 'user': post.author.screen_name } text += '</p>' # show post text text += post.html # show related post if convenient if post.post_type == const.POST_TYPE_THREAD_POST and post.thread.thread_type == const.THREAD_TYPE_QUESTION: text += '<h3>' text += _('Question') text += '</h3>' # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.thread._main_post().get_absolute_url(), url_prefix + post.thread._main_post().get_absolute_url()) text += post.thread._main_post().html elif post.post_type == const.POST_TYPE_COMMENT: text += '<h3>' text += _('Commented post') text += '</h3>' # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.parent.get_absolute_url(), url_prefix + post.parent.get_absolute_url()) text += post.parent.html # message bottom text += '<hr />' text += '<p>' text += _( 'Please remember that you can always adjust frequency of the email updates or turn them off entirely in your profile.' ) text += '</p>' text += '<p>' text += _( 'If you believe that this message was sent in an error, please contact us.' ) text += '</p>' # render email data = { 'text': text, 'site_name': openode_settings.APP_SHORT_NAME, 'site_url': openode_settings.APP_URL } template = get_template('email/instant_notification.html') message = template.render(data) recipients = {} # get all thread followers for user in post.thread.followed_by.filter( notification_subscriptions__frequency='i', notification_subscriptions__feed_type='q_sel'): recipients[user.pk] = user # get all node followers for user in post.thread.node.followed_by.filter( notification_subscriptions__frequency='i', notification_subscriptions__feed_type='q_sel'): recipients[user.pk] = user # remove author of this editation from recipients if post.last_edited_by: # post was updated recipients.pop(post.last_edited_by.pk, None) else: # post is new recipients.pop(post.author.pk, None) # send all emails for user in recipients.values(): if DEBUG_THIS_COMMAND: recipient_email = django_settings.ADMINS[0][1] else: recipient_email = user.email mail.send_mail(subject_line, message, django_settings.DEFAULT_FROM_EMAIL, [recipient_email], raise_on_failure=True) logging.info('Email notification sent: %s' % repr({ "user": user.screen_name, "user_email": recipient_email, "user_pk": user.pk, "post_pk": post.pk })) activate(old_lang) return True except Exception, e: logging.error( 'Email notification - failed to send immediate notification for post: %s' % repr({ "post_pk": post.pk, "error": e }))
def render(self, context): request = self.request_var.resolve(context) jinja_template = get_template(self.filename, request) return jinja_template.render(context)
def handle_noargs(self, **options): if openode_settings.ENABLE_EMAIL_ALERTS == False: return if openode_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False: return #get questions without answers, excluding closed and deleted #order it by descending added_at date schedule = ReminderSchedule( openode_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER, openode_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY, openode_settings.MAX_ACCEPT_ANSWER_REMINDERS ) questions = models.Post.objects.get_questions().exclude( deleted = True ).added_between( start = schedule.start_cutoff_date, end = schedule.end_cutoff_date ).filter( thread__answer_count__gt = 0 ).filter( thread__accepted_answer__isnull=True #answer_accepted = False ).order_by('-added_at') #for all users, excluding blocked #for each user, select a tag filtered subset #format the email reminder and send it for user in models.User.objects.exclude(status = 'b'): user_questions = questions.filter(author = user) final_question_list = user_questions.get_questions_needing_reminder( activity_type = const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT, user = user, recurrence_delay = schedule.recurrence_delay ) #todo: rewrite using query set filter #may be a lot more efficient question_count = len(final_question_list) if question_count == 0: continue subject_line = _( 'Accept the best answer for %(question_count)d of your questions' ) % {'question_count': question_count} #todo - make a template for these if question_count == 1: reminder_phrase = _('Please accept the best answer for this question:') else: reminder_phrase = _('Please accept the best answer for these questions:') data = { 'site_url': openode_settings.APP_URL, 'questions': final_question_list, 'reminder_phrase': reminder_phrase } template = get_template('email/accept_answer_reminder.html') body_text = template.render(Context(data)) if DEBUG_THIS_COMMAND: print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \ (user.email, subject_line, body_text) else: mail.send_mail( subject_line = subject_line, body_text = body_text, recipient_list = (user.email,) )
def send_email_alerts(self): #does not change the database, only sends the email #todo: move this to template for user in User.objects.filter(is_active=True): user.add_missing_openode_subscriptions() #todo: q_list is a dictionary, not a list # print 'user:'******'skip']: del q_list[question] else: num_q += 1 logging.info(u'Notification: %s (pk=%s) will recieve %s notices' % (user.screen_name, user.pk, num_q)) # print 'pocet:', num_q if num_q > 0: url_prefix = openode_settings.APP_URL # threads = Thread.objects.filter(id__in=[qq.thread_id for qq in q_list.keys()]) # tag_summary = Thread.objects.get_tag_summary_from_threads(threads) #TODO # tag_summary = '' # question_count = len(q_list.keys()) subject_line = _('Updates overview') #todo: send this to special log #print 'have %d updated questions for %s' % (num_q, user.username) text = '' items_added = 0 # items_unreported = 0 for q, meta_data in q_list.items(): act_list = [] if meta_data['skip']: continue # if items_added >= openode_settings.MAX_ALERTS_PER_EMAIL: # items_unreported = num_q - items_added # may be inaccurate actually, but it's ok else: items_added += 1 if meta_data['new_q']: if q.post_type == const.POST_TYPE_QUESTION: act_list.append(_('new question')) elif q.post_type == const.POST_TYPE_DISCUSSION: act_list.append(_('new discussion')) elif q.post_type == const.POST_TYPE_DOCUMENT: act_list.append(_('new document')) if meta_data['q_rev']: if q.post_type == const.POST_TYPE_QUESTION: act_list.append(_('changed question')) elif q.post_type == const.POST_TYPE_DISCUSSION: act_list.append(_('changed discussion')) elif q.post_type == const.POST_TYPE_DOCUMENT: act_list.append(_('changed document')) if meta_data['new_ans']: if q.post_type == const.POST_TYPE_QUESTION: act_list.append(_('%(num)d new answers') % {'num': meta_data['new_ans']}) elif q.post_type == const.POST_TYPE_DISCUSSION: act_list.append(_('%(num)d new posts') % {'num': meta_data['new_ans']}) if meta_data['ans_rev']: if q.post_type == const.POST_TYPE_QUESTION: act_list.append(_('%(num)d changed answers') % {'num': meta_data['ans_rev']}) elif q.post_type == const.POST_TYPE_DISCUSSION: act_list.append(_('%(num)d changed posts') % {'num': meta_data['ans_rev']}) # format_action_count('%(num)d rev', meta_data['q_rev'], act_list) # format_action_count('%(num)d ans', meta_data['new_ans'], act_list) # format_action_count('%(num)d ans rev', meta_data['ans_rev'], act_list) act_token = ', '.join(act_list) text += '<a href="%s">%s</a> (%s)<br />' % (url_prefix + q.get_absolute_url(), q.thread.title, act_token) #if len(q_list.keys()) >= openode_settings.MAX_ALERTS_PER_EMAIL: # text += _('There may be more questions updated since ' # 'you have logged in last time as this list is ' # 'abridged for your convinience. Please visit ' # 'the openode and see what\'s new!<br>' # ) # link = url_prefix + reverse( # 'user_profile', # kwargs={ # 'id': user.id, # 'tab_name': 'email_subscriptions' # } # ) text += '<hr />' text += '<p>' text += _('Please remember that you can always adjust frequency of the email updates or turn them off entirely in your profile.') text += '</p>' text += '<p>' text += _('If you believe that this message was sent in an error, please contact us.') text += '</p>' if DEBUG_THIS_COMMAND == True: recipient_email = django_settings.ADMINS[0][1] else: recipient_email = user.email # print 'odeslan email' data = { 'text': text, 'site_name': openode_settings.APP_SHORT_NAME, 'site_url': openode_settings.APP_URL } from openode.skins.loaders import get_template template = get_template('email/notification.html') message = template.render(data) mail.send_mail(subject_line, message, django_settings.DEFAULT_FROM_EMAIL, [recipient_email], raise_on_failure=True) logging.info('Notification: %s (pk=%s) mail sent' % (user.screen_name, user.pk))
def immediately_notify_users(post): # we don't want to disturb original routine try: # set default language TODO - language per user - add user atribute old_lang = get_language() activate(django_settings.LANGUAGE_CODE) DEBUG_THIS_COMMAND = getattr(django_settings, 'DEBUG_SEND_EMAIL_NOTIFICATIONS', True) # compose subject according to the post type subject_line = _('Notification') if post.post_type == const.POST_TYPE_QUESTION: subject_line += ': ' + _('Question') elif post.post_type == const.POST_TYPE_DOCUMENT: subject_line += ': ' + _('Document') elif post.post_type == const.POST_TYPE_COMMENT: subject_line += ': ' + _('Comment') elif post.post_type == const.POST_TYPE_THREAD_POST: if post.thread.thread_type == const.THREAD_TYPE_QUESTION: subject_line += ': ' + _('Answer') elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION: subject_line += ': ' + _('Discussion post') else: # post type is probably only a description, do nothing activate(old_lang) return False subject_line += ' - ' + post.thread.title # compose message according to post type url_prefix = openode_settings.APP_URL # link to node # text = u'<p>%s: <a href="%s">%s</a></p>' % (_('Node'), url_prefix + post.thread.node.get_absolute_url(), post.thread.node.full_title()) text = u'<p>%s: %s</p>' % (_('Node'), post.thread.node.full_title()) # title according to the post type text += '<h2>' if post.last_edited_by: # post was updated if post.post_type == const.POST_TYPE_QUESTION: text += _('Updated question') elif post.post_type == const.POST_TYPE_DOCUMENT: text += _('Updated document') elif post.post_type == const.POST_TYPE_COMMENT: text += _('Updated comment') elif post.post_type == const.POST_TYPE_THREAD_POST: if post.thread.thread_type == const.THREAD_TYPE_QUESTION: text += _('Updated answer') elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION: text += _('Updated discussion post') else: # post is new if post.post_type == const.POST_TYPE_QUESTION: text += _('New question') elif post.post_type == const.POST_TYPE_DOCUMENT: text += _('New document') elif post.post_type == const.POST_TYPE_COMMENT: text += _('New comment') elif post.post_type == const.POST_TYPE_THREAD_POST: if post.thread.thread_type == const.THREAD_TYPE_QUESTION: text += _('New answer') elif post.thread.thread_type == const.THREAD_TYPE_DISCUSSION: text += _('New discussion post') text += '</h2>' # link to post if post.post_type == const.POST_TYPE_DOCUMENT: url = url_prefix + post.thread.get_absolute_url() else: url = url_prefix + post.get_absolute_url() text += '<p><a href="%(url)s">%(url)s</a></p>' % {"url": url} # author text += '<p>' if post.last_edited_by: # post was updated text += _(u'%(datetime)s changed by <strong>%(user)s</strong>') % {'datetime': humanize_datetime(post.last_edited_at, 0), 'user': post.last_edited_by.screen_name} else: # post is new text += _(u'%(datetime)s created by <strong>%(user)s</strong>') % {'datetime': humanize_datetime(post.added_at, 0), 'user': post.author.screen_name} text += '</p>' # show post text text += post.html # show related post if convenient if post.post_type == const.POST_TYPE_THREAD_POST and post.thread.thread_type == const.THREAD_TYPE_QUESTION: text += '<h3>' text += _('Question') text += '</h3>' # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.thread._main_post().get_absolute_url(), url_prefix + post.thread._main_post().get_absolute_url()) text += post.thread._main_post().html elif post.post_type == const.POST_TYPE_COMMENT: text += '<h3>' text += _('Commented post') text += '</h3>' # text += '<p><a href="%s">%s</a></p>' % (url_prefix + post.parent.get_absolute_url(), url_prefix + post.parent.get_absolute_url()) text += post.parent.html # message bottom text += '<hr />' text += '<p>' text += _('Please remember that you can always adjust frequency of the email updates or turn them off entirely in your profile.') text += '</p>' text += '<p>' text += _('If you believe that this message was sent in an error, please contact us.') text += '</p>' # render email data = { 'text': text, 'site_name': openode_settings.APP_SHORT_NAME, 'site_url': openode_settings.APP_URL } template = get_template('email/instant_notification.html') message = template.render(data) recipients = {} # get all thread followers for user in post.thread.followed_by.filter(notification_subscriptions__frequency='i', notification_subscriptions__feed_type='q_sel'): recipients[user.pk] = user # get all node followers for user in post.thread.node.followed_by.filter(notification_subscriptions__frequency='i', notification_subscriptions__feed_type='q_sel'): recipients[user.pk] = user # remove author of this editation from recipients if post.last_edited_by: # post was updated recipients.pop(post.last_edited_by.pk, None) else: # post is new recipients.pop(post.author.pk, None) # send all emails for user in recipients.values(): if DEBUG_THIS_COMMAND: recipient_email = django_settings.ADMINS[0][1] else: recipient_email = user.email mail.send_mail(subject_line, message, django_settings.DEFAULT_FROM_EMAIL, [recipient_email], raise_on_failure=True) logging.info('Email notification sent: %s' % repr({ "user": user.screen_name, "user_email": recipient_email, "user_pk": user.pk, "post_pk": post.pk })) activate(old_lang) return True except Exception, e: logging.error('Email notification - failed to send immediate notification for post: %s' % repr({ "post_pk": post.pk, "error": e }))
def handle_noargs(self, **options): if openode_settings.ENABLE_EMAIL_ALERTS == False: return if openode_settings.ENABLE_ACCEPT_ANSWER_REMINDERS == False: return #get questions without answers, excluding closed and deleted #order it by descending added_at date schedule = ReminderSchedule( openode_settings.DAYS_BEFORE_SENDING_ACCEPT_ANSWER_REMINDER, openode_settings.ACCEPT_ANSWER_REMINDER_FREQUENCY, openode_settings.MAX_ACCEPT_ANSWER_REMINDERS) questions = models.Post.objects.get_questions().exclude( deleted=True).added_between( start=schedule.start_cutoff_date, end=schedule.end_cutoff_date ).filter(thread__answer_count__gt=0).filter( thread__accepted_answer__isnull=True #answer_accepted = False ).order_by('-added_at') #for all users, excluding blocked #for each user, select a tag filtered subset #format the email reminder and send it for user in models.User.objects.exclude(status='b'): user_questions = questions.filter(author=user) final_question_list = user_questions.get_questions_needing_reminder( activity_type=const.TYPE_ACTIVITY_ACCEPT_ANSWER_REMINDER_SENT, user=user, recurrence_delay=schedule.recurrence_delay) #todo: rewrite using query set filter #may be a lot more efficient question_count = len(final_question_list) if question_count == 0: continue subject_line = _( 'Accept the best answer for %(question_count)d of your questions' ) % { 'question_count': question_count } #todo - make a template for these if question_count == 1: reminder_phrase = _( 'Please accept the best answer for this question:') else: reminder_phrase = _( 'Please accept the best answer for these questions:') data = { 'site_url': openode_settings.APP_URL, 'questions': final_question_list, 'reminder_phrase': reminder_phrase } template = get_template('email/accept_answer_reminder.html') body_text = template.render(Context(data)) if DEBUG_THIS_COMMAND: print "User: %s<br>\nSubject:%s<br>\nText: %s<br>\n" % \ (user.email, subject_line, body_text) else: mail.send_mail(subject_line=subject_line, body_text=body_text, recipient_list=(user.email, ))
def user_overview(request, user, context): question_filter = {} # # Questions # questions = user.posts.get_questions( user=request.user ).filter( **question_filter ).order_by( '-points', '-thread__last_activity_at' ).select_related( 'thread', 'thread__last_activity_by' )[:100] #added this if to avoid another query if questions is less than 100 if len(questions) < 100: question_count = len(questions) else: question_count = user.posts.get_questions().filter(**question_filter).count() # # Top answers # top_answers = user.posts.get_answers( request.user ).filter( deleted=False, thread__posts__deleted=False, thread__posts__post_type='question', ).select_related( 'thread' ).order_by( '-points', '-added_at' )[:100] top_answer_count = len(top_answers) # # Votes # up_votes = models.Vote.objects.get_up_vote_count_from_user(user) down_votes = models.Vote.objects.get_down_vote_count_from_user(user) votes_today = models.Vote.objects.get_votes_count_today_from_user(user) votes_total = openode_settings.MAX_VOTES_PER_USER_PER_DAY # # Tags # # INFO: There's bug in Django that makes the following query kind of broken (GROUP BY clause is problematic): # http://stackoverflow.com/questions/7973461/django-aggregation-does-excessive-organization-by-clauses # Fortunately it looks like it returns correct results for the test data user_tags = models.Tag.objects.filter( threads__posts__author=user ).distinct().annotate( user_tag_usage_count=Count('threads') ).order_by( '-user_tag_usage_count' )[:const.USER_VIEW_DATA_SIZE] user_tags = list(user_tags) # evaluate when = openode_settings.MARKED_TAGS_ARE_PUBLIC_WHEN if when == 'always' or \ (when == 'when-user-wants' and user.show_marked_tags == True): #refactor into: user.get_marked_tag_names('good'/'bad'/'subscribed') interesting_tag_names = user.get_marked_tag_names('good') ignored_tag_names = user.get_marked_tag_names('bad') subscribed_tag_names = user.get_marked_tag_names('subscribed') else: interesting_tag_names = None ignored_tag_names = None subscribed_tag_names = None # tags = models.Post.objects.filter(author=user).values('id', 'thread', 'thread__tags') # post_ids = set() # thread_ids = set() # tag_ids = set() # for t in tags: # post_ids.add(t['id']) # thread_ids.add(t['thread']) # tag_ids.add(t['thread__tags']) # if t['thread__tags'] == 11: # print t['thread'], t['id'] # import ipdb; ipdb.set_trace() # # # post_type = ContentType.objects.get_for_model(models.Post) if request.user != user and request.user.is_authenticated() and user.privacy_email_form: if request.method == 'POST': email_form = UserEmailForm(request.POST) if email_form.is_valid(): subject = email_form.cleaned_data['subject'] text = email_form.cleaned_data['text'] url = urlparse(openode_settings.APP_URL) data = { 'from_user_url': url.scheme + '://' + url.netloc + reverse('user_profile', args=[request.user.pk]), 'from_user_screen_name': request.user.screen_name, 'text': text, "request": request } template = get_template('email/user_profile_email.html') message = template.render(data) send_mail(subject_line=subject, body_text=message, from_email=django_settings.DEFAULT_FROM_EMAIL, recipient_list=[user.email], ) request.user.log(user, const.LOG_ACTION_SEND_EMAIL_TO_USER) request.user.message_set.create(message=_('Email has been succesfully sent.')) email_form = UserEmailForm() else: email_form = UserEmailForm() else: email_form = None # if request.user.is_authenticated(): # managed_nodes = user.nodes.filter(node_users__role=const.NODE_USER_ROLE_MANAGER) # else: # managed_nodes = None # TODO not all variables are necessary data = { 'active_tab': 'users', 'page_class': 'user-profile-page', 'support_custom_avatars': ('avatar' in django_settings.INSTALLED_APPS), 'tab_description': _('user profile'), 'page_title': _('user profile overview'), 'user_status_for_display': user.get_status_display(soft=True), 'questions': questions, 'question_count': question_count, 'top_answers': top_answers, 'top_answer_count': top_answer_count, 'up_votes': up_votes, 'down_votes': down_votes, 'total_votes': up_votes + down_votes, 'votes_today_left': votes_total - votes_today, 'votes_total_per_day': votes_total, # 'managed_nodes': managed_nodes, 'user_tags': user_tags, 'interesting_tag_names': interesting_tag_names, 'ignored_tag_names': ignored_tag_names, 'subscribed_tag_names': subscribed_tag_names, 'email_form': email_form } context.update(data) view_user = context.get('view_user') if view_user is not None and not view_user.is_active: return render_into_skin('user_profile/user_overview_disabled.html', context, request) return render_into_skin('user_profile/user_overview.html', context, request)
def wrapped(*args, **kwargs): template_object = get_template(template) data = func(*args, **kwargs) return template_object.render(Context(data))