mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-31 21:41:33 +00:00
Deferring OPML import if it takes > 20 seconds. Email user when complete. Also, hamburgers. This one's for @torrez.
This commit is contained in:
parent
9c479e5c43
commit
d3b58e7cc9
18 changed files with 231 additions and 74 deletions
|
@ -1,5 +1,6 @@
|
|||
import datetime
|
||||
import oauth2 as oauth
|
||||
import mongoengine as mongo
|
||||
from collections import defaultdict
|
||||
from StringIO import StringIO
|
||||
from xml.etree.ElementTree import Element, SubElement, Comment, tostring
|
||||
|
@ -13,7 +14,7 @@ from apps.rss_feeds.models import Feed, DuplicateFeed, MStarredStory
|
|||
from apps.reader.models import UserSubscription, UserSubscriptionFolders
|
||||
from utils import json_functions as json, urlnorm
|
||||
from utils import log as logging
|
||||
|
||||
from utils.feed_functions import timelimit
|
||||
|
||||
class OAuthToken(models.Model):
|
||||
user = models.OneToOneField(User, null=True, blank=True)
|
||||
|
@ -96,12 +97,17 @@ class OPMLImporter(Importer):
|
|||
def __init__(self, opml_xml, user):
|
||||
self.user = user
|
||||
self.opml_xml = opml_xml
|
||||
|
||||
|
||||
def try_processing(self):
|
||||
folders = timelimit(20)(self.process)()
|
||||
return folders
|
||||
|
||||
def process(self):
|
||||
outline = opml.from_string(self.opml_xml)
|
||||
self.clear_feeds()
|
||||
outline = opml.from_string(self.opml_xml)
|
||||
folders = self.process_outline(outline)
|
||||
UserSubscriptionFolders.objects.create(user=self.user, folders=json.encode(folders))
|
||||
|
||||
return folders
|
||||
|
||||
def process_outline(self, outline):
|
||||
|
@ -169,7 +175,30 @@ class OPMLImporter(Importer):
|
|||
us.save()
|
||||
folders.append(feed_db.pk)
|
||||
return folders
|
||||
|
||||
def count_feeds_in_opml(self):
|
||||
|
||||
opml_count = len(opml.from_string(self.opml_xml))
|
||||
sub_count = UserSubscription.objects.filter(user=self.user).count()
|
||||
return opml_count + sub_count
|
||||
|
||||
|
||||
class UploadedOPML(mongo.Document):
|
||||
user_id = mongo.IntField()
|
||||
opml_file = mongo.StringField()
|
||||
upload_date = mongo.DateTimeField(default=datetime.datetime.now)
|
||||
|
||||
def __unicode__(self):
|
||||
user = User.objects.get(pk=self.user_id)
|
||||
return "%s: %s characters" % (user.username, len(self.opml_file))
|
||||
|
||||
meta = {
|
||||
'collection': 'uploaded_opml',
|
||||
'allow_inheritance': False,
|
||||
'order': '-upload_date',
|
||||
'indexes': ['user_id', '-upload_date'],
|
||||
}
|
||||
|
||||
|
||||
class GoogleReaderImporter(Importer):
|
||||
|
||||
|
|
21
apps/feed_import/tasks.py
Normal file
21
apps/feed_import/tasks.py
Normal file
|
@ -0,0 +1,21 @@
|
|||
from celery.task import Task
|
||||
from django.contrib.auth.models import User
|
||||
from apps.feed_import.models import UploadedOPML, OPMLImporter
|
||||
from apps.reader.models import UserSubscription
|
||||
from utils import log as logging
|
||||
|
||||
|
||||
class ProcessOPML(Task):
|
||||
|
||||
def run(self, user_id):
|
||||
user = User.objects.get(pk=user_id)
|
||||
logging.user(user, "~FR~SBOPML upload (task) starting...")
|
||||
|
||||
opml = UploadedOPML.objects.filter(user_id=user_id).first()
|
||||
opml_importer = OPMLImporter(opml.opml_file, user)
|
||||
opml_importer.process()
|
||||
|
||||
feed_count = UserSubscription.objects.filter(user=user).count()
|
||||
user.profile.send_upload_opml_finished_email(feed_count)
|
||||
logging.user(user, "~FR~SBOPML upload (task): ~SK%s~SN~SB~FR feeds" % (feed_count))
|
||||
|
|
@ -14,9 +14,12 @@ from django.contrib.auth import login as login_user
|
|||
from django.shortcuts import render_to_response
|
||||
from apps.reader.forms import SignupForm
|
||||
from apps.reader.models import UserSubscription
|
||||
from apps.feed_import.models import OAuthToken, OPMLImporter, OPMLExporter, GoogleReaderImporter
|
||||
from apps.feed_import.models import OAuthToken, GoogleReaderImporter
|
||||
from apps.feed_import.models import OPMLImporter, OPMLExporter, UploadedOPML
|
||||
from apps.feed_import.tasks import ProcessOPML
|
||||
from utils import json_functions as json
|
||||
from utils.user_functions import ajax_login_required, get_user
|
||||
from utils.feed_functions import TimeoutError
|
||||
|
||||
|
||||
@ajax_login_required
|
||||
|
@ -31,11 +34,24 @@ def opml_upload(request):
|
|||
logging.user(request, "~FR~SBOPML upload starting...")
|
||||
file = request.FILES['file']
|
||||
xml_opml = file.read()
|
||||
UploadedOPML.objects.create(user_id=request.user.pk, opml_file=xml_opml)
|
||||
|
||||
opml_importer = OPMLImporter(xml_opml, request.user)
|
||||
folders = opml_importer.process()
|
||||
feeds = UserSubscription.objects.filter(user=request.user).values()
|
||||
payload = dict(folders=folders, feeds=feeds)
|
||||
logging.user(request, "~FR~SBOPML Upload: ~SK%s~SN~SB~FR feeds" % (len(feeds)))
|
||||
try:
|
||||
folders = opml_importer.try_processing()
|
||||
except TimeoutError:
|
||||
folders = None
|
||||
ProcessOPML.delay(request.user.pk)
|
||||
feed_count = opml_importer.count_feeds_in_opml()
|
||||
logging.user(request, "~FR~SBOPML pload took too long, found %s feeds. Tasking..." % feed_count)
|
||||
payload = dict(folders=folders, delayed=True, feed_count=feed_count)
|
||||
code = 2
|
||||
message = ""
|
||||
|
||||
if folders:
|
||||
feeds = UserSubscription.objects.filter(user=request.user).values()
|
||||
payload = dict(folders=folders, feeds=feeds)
|
||||
logging.user(request, "~FR~SBOPML Upload: ~SK%s~SN~SB~FR feeds" % (len(feeds)))
|
||||
|
||||
request.session['import_from_google_reader'] = False
|
||||
else:
|
||||
|
|
|
@ -214,6 +214,23 @@ NewsBlur""" % {'user': self.user.username, 'feeds': subs.count()}
|
|||
|
||||
logging.user(self.user, "~BB~FM~SBSending email for social beta: %s" % self.user.email)
|
||||
|
||||
def send_upload_opml_finished_email(self, feed_count):
|
||||
if not self.user.email:
|
||||
print "Please provide an email address."
|
||||
return
|
||||
|
||||
user = self.user
|
||||
text = render_to_string('mail/email_upload_opml_finished.txt', locals())
|
||||
html = render_to_string('mail/email_upload_opml_finished.xhtml', locals())
|
||||
subject = "Your OPML upload is complete. Get going with NewsBlur!"
|
||||
msg = EmailMultiAlternatives(subject, text,
|
||||
from_email='NewsBlur <%s>' % settings.HELLO_EMAIL,
|
||||
to=['%s <%s>' % (user, user.email)])
|
||||
msg.attach_alternative(html, "text/html")
|
||||
msg.send()
|
||||
|
||||
logging.user(self.user, "~BB~FM~SBSending email for OPML upload: %s" % self.user.email)
|
||||
|
||||
def autologin_url(self, next=None):
|
||||
return reverse('autologin', kwargs={
|
||||
'username': self.user.username,
|
||||
|
|
2
fabfile.py
vendored
2
fabfile.py
vendored
|
@ -374,7 +374,7 @@ def setup_psycopg():
|
|||
|
||||
def setup_python():
|
||||
# sudo('easy_install -U pip')
|
||||
sudo('easy_install -U fabric django==1.3.1 readline pyflakes iconv celery django-celery django-celery-with-redis django-compress South django-extensions pymongo==2.2.0 stripe BeautifulSoup pyyaml nltk lxml oauth2 pytz boto seacucumber django_ses mongoengine redis requests')
|
||||
sudo('easy_install -U fabric django==1.3.1 readline pyflakes iconv celery django-celery django-celery-with-redis django-compress South django-extensions pymongo==2.2.0 stripe BeautifulSoup pyyaml nltk lxml oauth2 pytz boto seacucumber django_ses mongoengine redis requests psutil')
|
||||
|
||||
put('config/pystartup.py', '.pystartup')
|
||||
# with cd(os.path.join(env.NEWSBLUR_PATH, 'vendor/cjson')):
|
||||
|
|
|
@ -5872,6 +5872,13 @@ form.opml_import_form input {
|
|||
min-height: 234px;
|
||||
}
|
||||
|
||||
.NB-modal-intro .NB-intro-import-delayed {
|
||||
color: #808080;
|
||||
margin: 12px 0 0;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
display: none;
|
||||
}
|
||||
.NB-modal-intro .NB-intro-import {
|
||||
width: 300px;
|
||||
float: left;
|
||||
|
@ -6337,16 +6344,15 @@ form.opml_import_form input {
|
|||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-modal-subtitle {
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: #606060;
|
||||
text-shadow: 1px 1px 0 #F0F0F0;
|
||||
width: 715px;
|
||||
font-weight: normal;
|
||||
font-size: 12px;
|
||||
color: #606060;
|
||||
text-shadow: 1px 1px 0 #F0F0F0;
|
||||
width: 715px;
|
||||
}
|
||||
.NB-modal-feedchooser .NB-modal-subtitle b {
|
||||
/* margin: 0 0 4px 0;*/
|
||||
padding-right: 8px;
|
||||
color: #303030;
|
||||
color: #303030;
|
||||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-subtitle-type-prefix {
|
||||
|
@ -6354,19 +6360,33 @@ form.opml_import_form input {
|
|||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-type {
|
||||
float: left;
|
||||
width: 345px;
|
||||
margin: 0 12px 0 0;
|
||||
padding: 0 12px 0 0;
|
||||
float: left;
|
||||
width: 345px;
|
||||
margin: 0 52px 0 26px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-type.NB-last {
|
||||
margin: 0 0 0 0;
|
||||
padding: 0 0 0 24px;
|
||||
margin-right: 0;
|
||||
border-left: 1px solid #B0B0B0;
|
||||
margin: 0 0 0 0;
|
||||
padding: 0 0 0 52px;
|
||||
margin-right: 0;
|
||||
border-left: 1px solid #B0B0B0;
|
||||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-porpoise {
|
||||
border-radius: 16px;
|
||||
line-height: 48px;
|
||||
color: #808080;
|
||||
font-size: 18px;
|
||||
padding: 8px 2px;
|
||||
background-color: white;
|
||||
position: absolute;
|
||||
margin-top: -24px;
|
||||
width: 30px;
|
||||
text-align: center;
|
||||
top: 50%;
|
||||
left: -17px
|
||||
}
|
||||
.NB-modal-feedchooser .NB-feedchooser-info {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
@ -6510,22 +6530,20 @@ form.opml_import_form input {
|
|||
position: absolute;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
top: 0;
|
||||
top: -10px;
|
||||
left: -40px;
|
||||
display: none;
|
||||
}
|
||||
.NB-modal-feedchooser .NB-feedchooser-dollar-value.NB-selected.NB-1 .NB-feedchooser-dollar-image {
|
||||
top: -8px;
|
||||
background: transparent url('/media/embed/reader/hamburgers.png') no-repeat 0 0;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-dollar-value.NB-selected.NB-2 .NB-feedchooser-dollar-image {
|
||||
top: -8px;
|
||||
background: transparent url('/media/embed/reader/hamburgers.png') no-repeat 0 -36px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-dollar-value.NB-selected.NB-3 .NB-feedchooser-dollar-image {
|
||||
top: -10px;
|
||||
background: transparent url('/media/embed/reader/hamburgers.png') no-repeat 0 -72px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.NB-modal-feedchooser .NB-feedchooser-dollar-month {
|
||||
|
|
BIN
media/img/reader/hamburger_l.png
Normal file
BIN
media/img/reader/hamburger_l.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
media/img/reader/hamburger_m.png
Normal file
BIN
media/img/reader/hamburger_m.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
media/img/reader/hamburger_s.png
Normal file
BIN
media/img/reader/hamburger_s.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.5 KiB |
|
@ -774,11 +774,14 @@
|
|||
this.hide_progress_bar();
|
||||
},
|
||||
|
||||
open_dialog_after_feeds_loaded: function() {
|
||||
open_dialog_after_feeds_loaded: function(options) {
|
||||
options = options || {};
|
||||
if (!NEWSBLUR.Globals.is_authenticated) return;
|
||||
|
||||
if (!NEWSBLUR.assets.folders.length || !NEWSBLUR.assets.preference('has_setup_feeds')) {
|
||||
if (NEWSBLUR.assets.preference('has_setup_feeds')) {
|
||||
if (options.delayed_import || this.flags.delayed_import) {
|
||||
this.setup_ftux_add_feed_callout("Check your email...");
|
||||
} else if (NEWSBLUR.assets.preference('has_setup_feeds')) {
|
||||
this.setup_ftux_add_feed_callout();
|
||||
} else if (!NEWSBLUR.intro || !NEWSBLUR.intro.flags.open) {
|
||||
_.defer(_.bind(this.open_intro_modal, this), 100);
|
||||
|
@ -3774,11 +3777,11 @@
|
|||
// = FTUX =
|
||||
// ========
|
||||
|
||||
setup_ftux_add_feed_callout: function() {
|
||||
setup_ftux_add_feed_callout: function(message) {
|
||||
var self = this;
|
||||
if (this.flags['bouncing_callout']) return;
|
||||
|
||||
$('.NB-callout-ftux .NB-callout-text').text('First things first...');
|
||||
$('.NB-callout-ftux .NB-callout-text').text(message || 'First things first...');
|
||||
$('.NB-callout-ftux').corner('5px');
|
||||
$('.NB-callout-ftux').css({
|
||||
'opacity': 0,
|
||||
|
|
|
@ -60,7 +60,9 @@ NEWSBLUR.ReaderFeedchooser.prototype = {
|
|||
return false;
|
||||
})
|
||||
]),
|
||||
$.make('div', { className: 'NB-feedchooser-type NB-last'}, [
|
||||
$.make('div', { className: 'NB-feedchooser-type NB-last', style: 'position: relative'}, [
|
||||
$.make('div', { className: 'NB-feedchooser-porpoise' }, 'OR'),
|
||||
|
||||
$.make('div', { className: 'NB-feedchooser-info'}, [
|
||||
$.make('div', { className: 'NB-feedchooser-info-type' }, [
|
||||
$.make('span', { className: 'NB-feedchooser-subtitle-type-prefix' }, 'Super-Mega'),
|
||||
|
@ -105,21 +107,30 @@ NEWSBLUR.ReaderFeedchooser.prototype = {
|
|||
$.make('div', { className: 'NB-feedchooser-dollar' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-value NB-1' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-month' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-image' }),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-image' }, [
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/hamburger_s.png' })
|
||||
]),
|
||||
'$12/year'
|
||||
]),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-year' }, '($1/month)')
|
||||
]),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-value NB-2' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-month' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-image' }),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-image' }, [
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/hamburger_s.png', style: "position: absolute; left: -26px;top: 1px" }),
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/hamburger_m.png', style: "position: absolute; left: 0px;top: 2px" })
|
||||
]),
|
||||
'$24/year'
|
||||
]),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-year' }, '($2/month)')
|
||||
]),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-value NB-3' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-month' }, [
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-image' }),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-image' }, [
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/hamburger_s.png', style: "position: absolute; left: -58px;top: 0" }),
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/hamburger_m.png', style: "position: absolute; left: -31px;top: 2px" }),
|
||||
$.make('img', { src: NEWSBLUR.Globals.MEDIA_URL + '/img/reader/hamburger_l.png', style: "position: absolute; left: 0; top: 0" })
|
||||
]),
|
||||
'$36/year'
|
||||
]),
|
||||
$.make('div', { className: 'NB-feedchooser-dollar-year' }, '($3/month)')
|
||||
|
@ -205,8 +216,8 @@ NEWSBLUR.ReaderFeedchooser.prototype = {
|
|||
open_modal: function() {
|
||||
var self = this;
|
||||
this.$modal.modal({
|
||||
'minWidth': 780,
|
||||
'maxWidth': 780,
|
||||
'minWidth': 860,
|
||||
'maxWidth': 860,
|
||||
'overlayClose': true,
|
||||
'onOpen': function (dialog) {
|
||||
dialog.overlay.fadeIn(200, function () {
|
||||
|
|
|
@ -10,6 +10,7 @@ NEWSBLUR.ReaderIntro = function(options) {
|
|||
'twitter': {},
|
||||
'facebook': {}
|
||||
};
|
||||
this.flags = {};
|
||||
this.autofollow = true;
|
||||
|
||||
this.page_number = this.options.page_number;
|
||||
|
@ -79,6 +80,11 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
$.make('h4'),
|
||||
$.make('div', { className: 'NB-intro-import-restart NB-modal-submit-grey NB-modal-submit-button' }, [
|
||||
'« Restart and re-import your sites'
|
||||
]),
|
||||
$.make('div', { className: 'NB-intro-import-delayed' }, [
|
||||
'There are too many sites to process...',
|
||||
$.make('br'),
|
||||
'You will be emailed within a minute or three.'
|
||||
])
|
||||
])
|
||||
]),
|
||||
|
@ -303,9 +309,9 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
} else if (page_number > page_count) {
|
||||
NEWSBLUR.assets.preference('has_setup_feeds', true);
|
||||
NEWSBLUR.reader.check_hide_getting_started();
|
||||
this.close(function() {
|
||||
NEWSBLUR.reader.open_dialog_after_feeds_loaded();
|
||||
});
|
||||
this.close(_.bind(function() {
|
||||
NEWSBLUR.reader.open_dialog_after_feeds_loaded({delayed_import: this.flags.delayed_import});
|
||||
}, this));
|
||||
return;
|
||||
} else if (page_number == 1) {
|
||||
$('.NB-tutorial-next-page-text', this.$modal).text("Let's Get Started ");
|
||||
|
@ -345,6 +351,7 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
if (NEWSBLUR.assets.feeds.size() && !this.options.force_import) {
|
||||
page = 2;
|
||||
$('.NB-intro-imports-sites', this.$modal).addClass('active');
|
||||
$('.NB-intro-import-delayed', this.$modal).hide();
|
||||
} else {
|
||||
page = 0;
|
||||
$('.NB-intro-imports-start', this.$modal).addClass('active');
|
||||
|
@ -360,11 +367,12 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
this.count_feeds();
|
||||
},
|
||||
|
||||
count_feeds: function() {
|
||||
var feed_count = NEWSBLUR.assets.feeds.size();
|
||||
count_feeds: function(fake_feed_count) {
|
||||
var feed_count = fake_feed_count || NEWSBLUR.assets.feeds.size();
|
||||
|
||||
$(".NB-intro-imports-sites h4", this.$modal).text([
|
||||
'You are subscribed to ',
|
||||
(fake_feed_count && 'at least '),
|
||||
Inflector.pluralize(' site', feed_count, true),
|
||||
'.'
|
||||
].join(""));
|
||||
|
@ -464,10 +472,16 @@ _.extend(NEWSBLUR.ReaderIntro.prototype, {
|
|||
var params = {
|
||||
url: NEWSBLUR.URLs['opml-upload'],
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
success: function (data, status) {
|
||||
NEWSBLUR.assets.load_feeds(function() {
|
||||
$loading.removeClass('NB-active');
|
||||
self.advance_import_carousel(2);
|
||||
if (data.payload.delayed) {
|
||||
NEWSBLUR.reader.flags.delayed_import = true;
|
||||
self.count_feeds(data.payload.feed_count);
|
||||
$('.NB-intro-import-delayed', self.$modal).show();
|
||||
}
|
||||
});
|
||||
NEWSBLUR.reader.load_recommended_feed();
|
||||
},
|
||||
|
|
|
@ -310,7 +310,10 @@ BROKER_URL = "redis://db01:6379/0"
|
|||
CELERY_REDIS_HOST = "db01"
|
||||
|
||||
CELERYD_PREFETCH_MULTIPLIER = 1
|
||||
CELERY_IMPORTS = ("apps.rss_feeds.tasks", "apps.social.tasks", "apps.reader.tasks",)
|
||||
CELERY_IMPORTS = ("apps.rss_feeds.tasks",
|
||||
"apps.social.tasks",
|
||||
"apps.reader.tasks",
|
||||
"apps.feed_import.tasks",)
|
||||
CELERYD_CONCURRENCY = 4
|
||||
CELERY_IGNORE_RESULT = True
|
||||
CELERY_ACKS_LATE = True # Retry if task fails
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
{% load utils_tags %}
|
||||
|
||||
{% block body %}{% endblock body %}
|
||||
|
||||
- Samuel & Roy
|
||||
|
@ -18,10 +20,10 @@ Stay up to date and in touch with us, yr. developers, in a few different ways:
|
|||
|
||||
There's plenty of ways to use NewsBlur beyond the website:
|
||||
|
||||
* Download the free iPhone App: http://www.newsblur.com/iphone/
|
||||
* Download the free iPhone App: http://{% current_domain %}/iphone/
|
||||
* Download the Android App on the Android Market: https://market.android.com/details?id=bitwrit.Blar
|
||||
* Download browser extensions for Safari, Firefox, and Chrome: http://www.newsblur.com{{ user.profile.autologin_url }}?next=goodies
|
||||
* Download browser extensions for Safari, Firefox, and Chrome: http://{% current_domain %}{{ user.profile.autologin_url }}?next=goodies
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Don't want to be notified about anything NewsBlur related? Opt-out of emails from NewsBlur: http://www.newsblur.com{{ user.profile.autologin_url }}?next=optout
|
||||
Don't want to be notified about anything NewsBlur related? Opt-out of emails from NewsBlur: http://{% current_domain %}{{ user.profile.autologin_url }}?next=optout
|
|
@ -1,3 +1,5 @@
|
|||
{% load utils_tags %}
|
||||
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
<html>
|
||||
<head>
|
||||
|
@ -12,11 +14,11 @@
|
|||
<table cellpadding="0" cellspacing="0" border="0" bgcolor="#FFFFFF" align="left" width="644" style="padding: 20px; margin-top: 24px;align:center;border: 1px solid #BABABA;font-family:'Helvetica Neue', Helvetica, Arial, sans-serif;font-size:16px;color:#333;">
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="http://www.newsblur.com{{ user.profile.autologin_url }}"><img alt="NewsBlur" src="http://www.newsblur.com/media/img/logo_newsblur_blur.png" title="NewsBlur" style="width:312px;height:55px;border: none;"></a>
|
||||
<a href="http://{% current_domain %}{{ user.profile.autologin_url }}"><img alt="NewsBlur" src="http://{% current_domain %}/media/img/logo_newsblur_blur.png" title="NewsBlur" style="width:312px;height:55px;border: none;"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<td style="padding-top: 12px;">
|
||||
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
|
@ -32,23 +34,23 @@
|
|||
<p style="line-height:20px;">Stay up to date and in touch with us, yr. developers, in a few different ways:</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/newsblur/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/twitter.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @newsblur on Twitter</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://github.com/samuelclay/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/github_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @samuelclay on GitHub</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://twitter.com/newsblur/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/twitter.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @newsblur on Twitter</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://github.com/samuelclay/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/github_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @samuelclay on GitHub</a>.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p style="line-height: 20px;">{% block resources_header %}To get the most out of NewsBlur, here are a few resources:{% endblock resources_header %}</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://blog.newsblur.com" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/favicon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Read the NewsBlur Blog</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://getsatisfaction.com/newsblur/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/getsatisfaction.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Get support on NewsBlur's Get Satisfaction</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://blog.newsblur.com" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/favicon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Read the NewsBlur Blog</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://getsatisfaction.com/newsblur/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/getsatisfaction.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Get support on NewsBlur's Get Satisfaction</a>.</li>
|
||||
</ul>
|
||||
</p>
|
||||
<p style="line-height: 20px;">There's plenty of ways to use NewsBlur beyond the web:</p>
|
||||
<p style="line-height: 20px;">
|
||||
<ul style="list-style: none;">
|
||||
<li style="line-height:22px;"><a href="http://www.newsblur.com/iphone/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/iphone_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download the free iPhone App</a>.</li>
|
||||
<li style="line-height:22px;"><a href="https://market.android.com/details?id=bitwrit.Blar" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/android_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download the Android App on the Android Market</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://www.newsblur.com{{ user.profile.autologin_url }}?next=goodies" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/icons/silk/package_green.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download browser extensions for Safari, Firefox, and Chrome</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}/iphone/" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/iphone_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download the free iPhone App</a>.</li>
|
||||
<li style="line-height:22px;"><a href="https://market.android.com/details?id=bitwrit.Blar" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/reader/android_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download the Android App on the Android Market</a>.</li>
|
||||
<li style="line-height:22px;"><a href="http://{% current_domain %}{{ user.profile.autologin_url }}?next=goodies" style="text-decoration:none"><img src="http://{% current_domain %}/media/img/icons/silk/package_green.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Download browser extensions for Safari, Firefox, and Chrome</a>.</li>
|
||||
</ul>
|
||||
</p>
|
||||
</td>
|
||||
|
@ -62,7 +64,7 @@
|
|||
<tr>
|
||||
<td>
|
||||
<p style="font-size:12px;">
|
||||
Don't want to be notified about anything NewsBlur related? <a href="http://www.newsblur.com{{ user.profile.autologin_url }}?next=optout" style="text-decoration:none;">Opt-out of emails from NewsBlur</a>.
|
||||
Don't want to be notified about anything NewsBlur related? <a href="http://{% current_domain %}{{ user.profile.autologin_url }}?next=optout" style="text-decoration:none;">Opt-out of emails from NewsBlur</a>.
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
|
@ -71,7 +73,7 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td align="center" style="padding-top: 12px;">
|
||||
<a href="http://www.newsblur.com{{ user.profile.autologin_url }}"><img alt="NewsBlur" src="http://www.newsblur.com/media/img/logo_newsblur.png" title="NewsBlur" style="width:312px;height:55px;border: none;"></a>
|
||||
<a href="http://{% current_domain %}{{ user.profile.autologin_url }}"><img alt="NewsBlur" src="http://{% current_domain %}/media/img/logo_newsblur.png" title="NewsBlur" style="width:312px;height:55px;border: none;"></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
7
templates/mail/email_upload_opml_finished.txt
Normal file
7
templates/mail/email_upload_opml_finished.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
{% extends "mail/email_base.txt" %}
|
||||
|
||||
{% load utils_tags %}
|
||||
|
||||
{% block body %}Good news! NewsBlur has finished importing your OPML file. You are now subscribed to <b>{{ feed_count }}</b> site{{ feed_count|pluralize }}.
|
||||
|
||||
Head over to NewsBlur and get reading: http://{% current_domain %}{% endblock body %}
|
15
templates/mail/email_upload_opml_finished.xhtml
Normal file
15
templates/mail/email_upload_opml_finished.xhtml
Normal file
|
@ -0,0 +1,15 @@
|
|||
{% extends "mail/email_base.xhtml" %}
|
||||
|
||||
{% load utils_tags %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<p style="margin-top: 12px;">
|
||||
Good news! NewsBlur has finished importing your OPML file. You are now
|
||||
subscribed to <b>{{ feed_count }}</b> site{{ feed_count|pluralize }}.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Head over to <a href="http://{% current_domain %}">NewsBlur</a> and get reading.
|
||||
</p>
|
||||
{% endblock %}
|
|
@ -27,19 +27,18 @@ def timelimit(timeout):
|
|||
self.result = function(*args, **kw)
|
||||
except:
|
||||
self.error = sys.exc_info()
|
||||
if not settings.DEBUG and not settings.TEST_DEBUG:
|
||||
c = Dispatch()
|
||||
c.join(timeout)
|
||||
if c.isAlive():
|
||||
raise TimeoutError, 'took too long'
|
||||
if c.error:
|
||||
tb = ''.join(traceback.format_exception(c.error[0], c.error[1], c.error[2]))
|
||||
logging.debug(tb)
|
||||
mail_admins('Error in timeout: %s' % c.error[0], tb)
|
||||
raise c.error[0], c.error[1]
|
||||
return c.result
|
||||
else:
|
||||
return function(*args, **kw)
|
||||
c = Dispatch()
|
||||
c.join(timeout)
|
||||
if c.isAlive():
|
||||
raise TimeoutError, 'took too long'
|
||||
if not settings.DEBUG and not settings.TEST_DEBUG and c.error:
|
||||
tb = ''.join(traceback.format_exception(c.error[0], c.error[1], c.error[2]))
|
||||
logging.debug(tb)
|
||||
mail_admins('Error in timeout: %s' % c.error[0], tb)
|
||||
raise c.error[0], c.error[1]
|
||||
return c.result
|
||||
# else:
|
||||
# return function(*args, **kw)
|
||||
return _2
|
||||
return _1
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue