Adding popularity query email.

This commit is contained in:
Samuel Clay 2017-01-05 18:26:50 -08:00
parent 52a76e7811
commit 0235cb38b0
11 changed files with 232 additions and 18 deletions

32
apps/analyzer/forms.py Normal file
View file

@ -0,0 +1,32 @@
import re
import requests
from django import forms
from vendor.zebra.forms import StripePaymentForm
from django.utils.safestring import mark_safe
from django.contrib.auth import authenticate
from django.contrib.auth.models import User
from apps.profile.models import change_password, blank_authenticate, MGiftCode
from apps.social.models import MSocialProfile
class PopularityQueryForm(forms.Form):
email = forms.CharField(widget=forms.TextInput(),
label="Your email address",
required=False)
query = forms.CharField(widget=forms.TextInput(),
label="Keywords",
required=False)
def __init__(self, *args, **kwargs):
super(PopularityQueryForm, self).__init__(*args, **kwargs)
def clean_email(self):
if not self.cleaned_data['email']:
raise forms.ValidationError('Please enter in an email address.')
return self.cleaned_data['email']
def clean_query(self):
if not self.cleaned_data['query']:
raise forms.ValidationError('Please enter in a keyword search query.')
return self.cleaned_data['query']

View file

@ -1,8 +1,14 @@
import datetime
import mongoengine as mongo
from collections import defaultdict
from django.db import models
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives
from django.conf import settings
from apps.rss_feeds.models import Feed
from apps.analyzer.tasks import EmailPopularityQuery
from utils import log as logging
class FeatureCategory(models.Model):
user = models.ForeignKey(User)
@ -23,6 +29,44 @@ class Category(models.Model):
def __unicode__(self):
return '%s (%s)' % (self.category, self.count)
class MPopularityQuery(mongo.Document):
email = mongo.StringField()
query = mongo.StringField()
is_emailed = mongo.BooleanField()
creation_date = mongo.DateTimeField(default=datetime.datetime.now)
meta = {
'collection': 'popularity_query',
'allow_inheritance': False,
}
def __unicode__(self):
return "%s - \"%s\"" % (self.email, self.query)
def queue_email(self):
EmailPopularityQuery.delay(pk=self.pk)
def send_email(self):
filename = Feed.xls_query_popularity(self.query, limit=10)
xlsx = open(filename, "r")
params = {
'query': self.query
}
text = render_to_string('mail/email_popularity_query.txt', params)
html = render_to_string('mail/email_popularity_query.xhtml', params)
subject = "Keyword popularity spreadsheet: \"%s\"" % self.query
msg = EmailMultiAlternatives(subject, text,
from_email='NewsBlur <%s>' % settings.HELLO_EMAIL,
to=['<%s>' % (self.email)])
msg.attach_alternative(html, "text/html")
msg.attach(filename, xlsx.read(), 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
msg.send()
logging.debug(" -> ~BB~FM~SBSent email for popularity query: %s" % self)
class MClassifierTitle(mongo.Document):
user_id = mongo.IntField()
feed_id = mongo.IntField()
@ -241,4 +285,4 @@ def sort_classifiers_by_feed(user, feed_ids=None,
classifier_titles=classifier_titles[feed_id],
classifier_tags=classifier_tags[feed_id])
return classifiers
return classifiers

16
apps/analyzer/tasks.py Normal file
View file

@ -0,0 +1,16 @@
import datetime
from celery.task import Task
from utils import log as logging
class EmailPopularityQuery(Task):
def run(self, pk):
from apps.analyzer.models import MPopularityQuery
query = MPopularityQuery.objects.get(pk=pk)
logging.user(self.user, "~BB~FCRunning popularity query: ~SB%s" % query)
query.send_email()
query.is_emailed = True
query.save()

View file

@ -4,5 +4,6 @@ from apps.analyzer import views
urlpatterns = patterns('',
(r'^$', views.index),
(r'^save/?', views.save_classifier),
(r'^popularity/?', views.popularity_query),
(r'^(?P<feed_id>\d+)', views.get_classifiers_feed),
)

View file

@ -3,15 +3,19 @@ from utils import log as logging
from django.shortcuts import get_object_or_404
from django.views.decorators.http import require_POST
from django.conf import settings
from django.template import RequestContext
from django.shortcuts import render_to_response
from mongoengine.queryset import NotUniqueError
from apps.rss_feeds.models import Feed
from apps.reader.models import UserSubscription
from apps.analyzer.models import MClassifierTitle, MClassifierAuthor, MClassifierFeed, MClassifierTag
from apps.analyzer.models import get_classifiers_for_user
from apps.analyzer.models import get_classifiers_for_user, MPopularityQuery
from apps.analyzer.forms import PopularityQueryForm
from apps.social.models import MSocialSubscription
from utils import json_functions as json
from utils.user_functions import get_user
from utils.user_functions import ajax_login_required
from utils.view_functions import render_to
def index(requst):
pass
@ -116,4 +120,31 @@ def get_classifiers_feed(request, feed_id):
response = dict(code=code, payload=payload)
return response
def popularity_query(request):
if request.method == 'POST':
form = PopularityQueryForm(request.POST)
if form.is_valid():
logging.user(request.user, "~BC~FRPopularity query: ~SB%s~SN requests \"~SB~FM%s~SN~FR\"" % (request.POST['email'], request.POST['query']))
query = MPopularityQuery.objects.create(email=request.POST['email'],
query=request.POST['query'])
query.queue_email()
response = render_to_response('analyzer/popularity_query.xhtml', {
'success': True,
'popularity_query_form': form,
}, context_instance=RequestContext(request))
response.set_cookie('newsblur_popularity_query', request.POST['query'])
return response
else:
logging.user(request.user, "~BC~FRFailed popularity query: ~SB%s~SN requests \"~SB~FM%s~SN~FR\"" % (request.POST['email'], request.POST['query']))
else:
logging.user(request.user, "~BC~FRPopularity query form loading")
form = PopularityQueryForm(initial={'query': request.COOKIES.get('newsblur_popularity_query', "")})
response = render_to_response('analyzer/popularity_query.xhtml', {
'popularity_query_form': form,
}, context_instance=RequestContext(request))
return response

View file

@ -1590,33 +1590,37 @@ class Feed(models.Model):
@classmethod
def xls_query_popularity(cls, queries, limit):
import xlsxwriter
workbook = xlsxwriter.Workbook('NewsBlurPopularity.xlsx')
from xlsxwriter.utility import xl_rowcol_to_cell
if isinstance(queries, unicode):
queries = [q.strip() for q in queries.split(',')]
title = 'NewsBlur-%s.xlsx' % slugify('-'.join(queries))
workbook = xlsxwriter.Workbook(title)
bold = workbook.add_format({'bold': 1})
date_format = workbook.add_format({'num_format': 'mmm d yyyy'})
unread_format = workbook.add_format({'font_color': '#E0E0E0'})
if isinstance(queries, str):
queries = [q.strip() for q in queries.split(',')]
for query in queries:
worksheet = workbook.add_worksheet(query)
row = 1
col = 0
worksheet.write(0, col, 'Publisher', bold)
worksheet.write(0, col, 'Publisher', bold)
worksheet.set_column(col, col, 15); col += 1
worksheet.write(0, col, 'Feed URL', bold)
worksheet.set_column(col, col, 20); col += 1
worksheet.write(0, col, 'Reach score', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 9); col += 1
worksheet.write(0, col, '# subs', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 5); col += 1
worksheet.write(0, col, '# readers', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.write(0, col, 'Read %', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.write(0, col, "read %", bold)
worksheet.set_column(col, col, 6); col += 1
worksheet.write(0, col, '# stories 30d', bold)
worksheet.set_column(col, col, 10); col += 1
worksheet.write(0, col, '# shared', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 7); col += 1
worksheet.write(0, col, '# feed pos', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.write(0, col, '# feed neg', bold)
@ -1624,9 +1628,9 @@ class Feed(models.Model):
worksheet.write(0, col, 'Author', bold)
worksheet.set_column(col, col, 15); col += 1
worksheet.write(0, col, '# author pos', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 10); col += 1
worksheet.write(0, col, '# author neg', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 10); col += 1
worksheet.write(0, col, 'Story title', bold)
worksheet.set_column(col, col, 30); col += 1
worksheet.write(0, col, 'Story URL', bold)
@ -1638,16 +1642,20 @@ class Feed(models.Model):
worksheet.write(0, col, 'Tag Count', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.write(0, col, '# tag pos', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 7); col += 1
worksheet.write(0, col, '# tag neg', bold)
worksheet.set_column(col, col, 8); col += 1
worksheet.set_column(col, col, 7); col += 1
popularity = cls.query_popularity(query, limit=limit)
for feed in popularity:
col = 0
worksheet.write(row, col, feed['feed_title']); col += 1
worksheet.write_url(row, col, feed['feed_url']); col += 1
worksheet.write(row, col, feed['reach_score']); col += 1
worksheet.write(row, col, "=%s*%s*%s" % (
xl_rowcol_to_cell(row, col+2),
xl_rowcol_to_cell(row, col+3),
xl_rowcol_to_cell(row, col+4),
)); col += 1
worksheet.write(row, col, feed['num_subscribers']); col += 1
worksheet.write(row, col, feed['reader_count']); col += 1
worksheet.write(row, col, feed['read_pct']); col += 1
@ -1688,6 +1696,7 @@ class Feed(models.Model):
'value': 0,
'format': unread_format})
workbook.close()
return title
def find_stories(self, query, order="newest", offset=0, limit=25):
story_ids = SearchStory.query(feed_ids=[self.pk], query=query, order=order,

View file

@ -70,7 +70,13 @@
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.NB-static-form .NB-label-right {
margin: 0 0 24px 206px;
width: 200px;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
}
.NB-static-form input.error,

View file

@ -0,0 +1,46 @@
{% extends 'base.html' %}
{% load typogrify_tags utils_tags %}
{% block bodyclass %}NB-static{% endblock %}
{% block extra_head_js %}
{% include_stylesheets "common" %}
{% endblock %}
{% block content %}
<div class="NB-static-form-wrapper">
<div class="NB-delete-form NB-static-form">
<h2>NewsBlur Publisher Keyword Popularity XLSX Creator for YC Founders</h2>
<h5>Search for topics across millions of stories from millions of publishers</h5>
{% if success %}
<h4 style="color: #1C6130; text-align: center">Got it!<br>Email should be sent within the next minute.</h4>
{% else %}
<form action="" method="POST">{% csrf_token %}
<div class="NB-fields">
{{ popularity_query_form.email.label_tag }}
{{ popularity_query_form.email }}
{{ popularity_query_form.query.label_tag }}
{{ popularity_query_form.query }}
<h6 class="NB-label-right">Example: <i>phillips hue, wemo, alexa</i></h6>
</div>
{% if popularity_query_form.errors %}
<div class="NB-errors">
{% for field, error in popularity_query_form.errors.items %}
{{ error|safe }}
{% endfor %}
</div>
{% endif %}
<input type="submit" class="submit-button NB-modal-submit-button NB-modal-submit-green" value="Email it to me"></button>
</form>
{% endif %}
</div>
</div>
{% endblock %}

View file

@ -0,0 +1,9 @@
{% extends "mail/email_base.txt" %}
{% load utils_tags %}
{% block body %}Here's your keyword popularity spreadsheet
This service is provided for free to YC companies. In the attached spreadsheet, you should note that individual fields have comments where appropriate. Feel free to reply directly if you have any questions.
- Sam Clay{% endblock body %}

View file

@ -0,0 +1,19 @@
{% extends "mail/email_base.xhtml" %}
{% load utils_tags %}
{% block body %}
<h2 style="color: #282F33; font-size: 18px; font-weight: bold;">
Here's your keyword popularity spreadsheet
</h2>
<p style="line-height: 20px;">
This service is provided for free to YC companies. In the attached spreadsheet, you should note that individual fields have comments where appropriate. Feel free to reply directly if you have any questions.
</p>
<p style="line-height: 20px;">
- Sam Clay
</p>
{% endblock %}

View file

@ -24,6 +24,7 @@ urlpatterns = patterns('',
(r'^story/.*?', reader_views.index),
(r'^feed/?', social_views.shared_stories_rss_feed_noid),
(r'^rss_feeds/', include('apps.rss_feeds.urls')),
(r'^analyzer/', include('apps.analyzer.urls')),
(r'^classifier/', include('apps.analyzer.urls')),
(r'^profile/', include('apps.profile.urls')),
(r'^folder_rss/', include('apps.profile.urls')),