mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-08-05 16:58:59 +00:00
Adding post to twitter/facebook during share. Also adding email for new followers, which includes common followers and common followings.
This commit is contained in:
parent
63988e9e15
commit
16781c6450
12 changed files with 234 additions and 24 deletions
|
@ -34,7 +34,8 @@ try:
|
|||
from apps.rss_feeds.models import Feed, MFeedPage, DuplicateFeed, MStory, MStarredStory, FeedLoadtime
|
||||
except:
|
||||
pass
|
||||
from apps.social.models import MSharedStory, MSocialProfile, MSocialSubscription, MActivity
|
||||
from apps.social.models import MSharedStory, MSocialProfile, MSocialServices
|
||||
from apps.social.models import MSocialSubscription, MActivity
|
||||
from apps.social.views import load_social_page
|
||||
from utils import json_functions as json
|
||||
from utils.user_functions import get_user, ajax_login_required
|
||||
|
@ -223,6 +224,7 @@ def load_feeds(request):
|
|||
}
|
||||
social_feeds = MSocialSubscription.feeds(**social_params)
|
||||
social_profile = MSocialProfile.profile(user.pk)
|
||||
social_services = MSocialServices.profile(user.pk)
|
||||
|
||||
user.profile.dashboard_date = datetime.datetime.now()
|
||||
user.profile.save()
|
||||
|
@ -231,6 +233,7 @@ def load_feeds(request):
|
|||
'feeds': feeds.values() if version == 2 else feeds,
|
||||
'social_feeds': social_feeds,
|
||||
'social_profile': social_profile,
|
||||
'social_services': social_services,
|
||||
'folders': json.decode(folders.folders),
|
||||
'starred_count': starred_count,
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ from vendor import facebook
|
|||
from vendor import tweepy
|
||||
from utils import log as logging
|
||||
from utils.feed_functions import relative_timesince
|
||||
from utils.story_functions import truncate_chars
|
||||
from utils import json_functions as json
|
||||
|
||||
RECOMMENDATIONS_LIMIT = 5
|
||||
|
@ -271,6 +272,15 @@ class MSocialProfile(mongo.Document):
|
|||
if self.photo_url:
|
||||
return self.photo_url
|
||||
return settings.MEDIA_URL + 'img/reader/default_profile_photo.png'
|
||||
|
||||
@property
|
||||
def email_photo_url(self):
|
||||
if self.photo_url:
|
||||
if self.photo_url.startswith('//'):
|
||||
self.photo_url = 'http:' + self.photo_url
|
||||
return self.photo_url
|
||||
domain = Site.objects.get_current().domain
|
||||
return 'http://' + domain + settings.MEDIA_URL + 'img/reader/default_profile_photo.png'
|
||||
|
||||
def to_json(self, compact=False, include_follows=False, common_follows_with_user=None):
|
||||
# domain = Site.objects.get_current().domain
|
||||
|
@ -375,6 +385,9 @@ class MSocialProfile(mongo.Document):
|
|||
subscription_user_id=user_id)
|
||||
socialsub.needs_unread_recalc = True
|
||||
socialsub.save()
|
||||
|
||||
from apps.social.tasks import EmailNewFollower
|
||||
EmailNewFollower.delay(follower_user_id=self.user_id, followee_user_id=user_id)
|
||||
|
||||
def is_following_user(self, user_id):
|
||||
return user_id in self.following_user_ids
|
||||
|
@ -425,6 +438,43 @@ class MSocialProfile(mongo.Document):
|
|||
follows_diff.remove(user_id)
|
||||
|
||||
return follows_inter, follows_diff
|
||||
|
||||
def send_email_for_new_follower(self, follower_user_id):
|
||||
user = User.objects.get(pk=self.user_id)
|
||||
if not user.email or not user.profile.send_emails:
|
||||
return
|
||||
|
||||
follower_profile = MSocialProfile.objects.get(user_id=follower_user_id)
|
||||
photo_url = follower_profile.profile_photo_url
|
||||
if 'graph.facebook.com' in photo_url:
|
||||
follower_profile.photo_url = photo_url + '?type=large'
|
||||
elif 'twimg' in photo_url:
|
||||
follower_profile.photo_url = photo_url.replace('_normal', '')
|
||||
|
||||
common_followers, _ = self.common_follows(follower_user_id, direction='followers')
|
||||
common_followings, _ = self.common_follows(follower_user_id, direction='following')
|
||||
common_followers.remove(self.user_id)
|
||||
common_followings.remove(self.user_id)
|
||||
common_followers = MSocialProfile.profiles(common_followers)
|
||||
common_followings = MSocialProfile.profiles(common_followings)
|
||||
|
||||
data = {
|
||||
'user': user,
|
||||
'follower_profile': follower_profile,
|
||||
'common_followers': common_followers,
|
||||
'common_followings': common_followings,
|
||||
}
|
||||
|
||||
text = render_to_string('mail/email_new_follower.txt', data)
|
||||
html = render_to_string('mail/email_new_follower.xhtml', data)
|
||||
subject = "%s is now following your Blurblog on NewsBlur!" % follower_profile.username
|
||||
msg = EmailMultiAlternatives(subject, text,
|
||||
from_email='NewsBlur <%s>' % settings.HELLO_EMAIL,
|
||||
to=['%s <%s>' % (user.username, user.email)])
|
||||
msg.attach_alternative(html, "text/html")
|
||||
msg.send()
|
||||
|
||||
logging.user(user, "~BB~FM~SBSending email for new follower: %s" % follower_profile.username)
|
||||
|
||||
def save_feed_story_history_statistics(self):
|
||||
"""
|
||||
|
@ -870,6 +920,7 @@ class MSharedStory(mongo.Document):
|
|||
story_permalink = mongo.StringField()
|
||||
story_guid = mongo.StringField(unique_with=('user_id',))
|
||||
story_tags = mongo.ListField(mongo.StringField(max_length=250))
|
||||
posted_to_services = mongo.ListField(mongo.StringField(max_length=20))
|
||||
|
||||
meta = {
|
||||
'collection': 'shared_stories',
|
||||
|
@ -1129,6 +1180,40 @@ class MSharedStory(mongo.Document):
|
|||
profiles = [profile.to_json(compact=True) for profile in profiles]
|
||||
|
||||
return stories, profiles
|
||||
|
||||
def blurblog_permalink(self):
|
||||
profile = MSocialProfile.objects.get(user_id=self.user_id)
|
||||
return "http://%s.%s/story/%s" % (
|
||||
profile.username_slug,
|
||||
Site.objects.get_current().domain.replace('www', 'dev'),
|
||||
self.guid_hash[:6]
|
||||
)
|
||||
|
||||
def generate_post_to_service_message(self):
|
||||
message = self.comments
|
||||
if not message or len(message) < 1:
|
||||
message = self.story_title
|
||||
|
||||
message = truncate_chars(message, 116)
|
||||
message += " " + self.blurblog_permalink()
|
||||
print message
|
||||
|
||||
return message
|
||||
|
||||
def post_to_service(self, service):
|
||||
if service in self.posted_to_services:
|
||||
return
|
||||
|
||||
message = self.generate_post_to_service_message()
|
||||
social_service = MSocialServices.objects.get(user_id=self.user_id)
|
||||
if service == 'twitter':
|
||||
posted = social_service.post_to_twitter(message)
|
||||
elif service == 'facebook':
|
||||
posted = social_service.post_to_facebook(message)
|
||||
|
||||
if posted:
|
||||
self.posted_to_services.append(service)
|
||||
self.save()
|
||||
|
||||
|
||||
class MSocialServices(mongo.Document):
|
||||
|
@ -1179,6 +1264,14 @@ class MSocialServices(mongo.Document):
|
|||
}
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def profile(cls, user_id):
|
||||
try:
|
||||
profile = cls.objects.get(user_id=user_id)
|
||||
except cls.DoesNotExist:
|
||||
return {}
|
||||
return profile.to_json()
|
||||
|
||||
def twitter_api(self):
|
||||
twitter_consumer_key = settings.TWITTER_CONSUMER_KEY
|
||||
twitter_consumer_secret = settings.TWITTER_CONSUMER_SECRET
|
||||
|
@ -1325,7 +1418,26 @@ class MSocialServices(mongo.Document):
|
|||
hashlib.md5(user.email).hexdigest()
|
||||
profile.save()
|
||||
return profile
|
||||
|
||||
def post_to_twitter(self, message):
|
||||
try:
|
||||
api = self.twitter_api()
|
||||
api.update_status(status=message)
|
||||
except tweepy.TweepError, e:
|
||||
print e
|
||||
return
|
||||
|
||||
return True
|
||||
|
||||
def post_to_facebook(self, message):
|
||||
try:
|
||||
api = self.facebook_api()
|
||||
api.put_wall_post(message=message)
|
||||
except facebook.GraphAPIError, e:
|
||||
print e
|
||||
return
|
||||
|
||||
return True
|
||||
|
||||
class MInteraction(mongo.Document):
|
||||
user_id = mongo.IntField()
|
||||
|
|
|
@ -10,6 +10,7 @@ from django.conf import settings
|
|||
from apps.rss_feeds.models import MStory, Feed, MStarredStory
|
||||
from apps.social.models import MSharedStory, MSocialServices, MSocialProfile, MSocialSubscription, MCommentReply
|
||||
from apps.social.models import MRequestInvite, MInteraction, MActivity
|
||||
from apps.social.tasks import PostToService
|
||||
from apps.analyzer.models import MClassifierTitle, MClassifierAuthor, MClassifierFeed, MClassifierTag
|
||||
from apps.analyzer.models import apply_classifier_titles, apply_classifier_feeds, apply_classifier_authors, apply_classifier_tags
|
||||
from apps.analyzer.models import get_classifiers_for_user, sort_classifiers_by_feed
|
||||
|
@ -239,6 +240,7 @@ def mark_story_as_shared(request):
|
|||
story_id = request.POST['story_id']
|
||||
comments = request.POST.get('comments', '')
|
||||
source_user_id = request.POST.get('source_user_id')
|
||||
post_to_services = request.POST.getlist('post_to_services')
|
||||
|
||||
story = MStory.objects(story_feed_id=feed_id, story_guid=story_id).limit(1).first()
|
||||
if not story:
|
||||
|
@ -279,6 +281,11 @@ def mark_story_as_shared(request):
|
|||
story = stories[0]
|
||||
story['shared_comments'] = shared_story['comments'] or ""
|
||||
|
||||
if post_to_services:
|
||||
for service in post_to_services:
|
||||
if service not in shared_story.posted_to_services:
|
||||
PostToService.delay(shared_story_id=shared_story.id, service=service)
|
||||
|
||||
return {'code': code, 'story': story, 'user_profiles': profiles}
|
||||
|
||||
@ajax_login_required
|
||||
|
|
|
@ -2428,12 +2428,34 @@ background: transparent;
|
|||
text-shadow: 0 1px 0 #F6F6F6;
|
||||
color: #202020;
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-optional {
|
||||
text-transform: uppercase;
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost {
|
||||
margin-right: -4px;
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-twitter,
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-facebook {
|
||||
float: right;
|
||||
color: #808080;
|
||||
font-size: 10px;
|
||||
text-shadow: 0 1px 0 #F6F6F6;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin: 0 0 0 6px;
|
||||
opacity: .4;
|
||||
cursor: pointer;
|
||||
-webkit-filter: grayscale(100%);
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-twitter:hover,
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-facebook:hover {
|
||||
opacity: .7;
|
||||
-webkit-filter: none;
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-twitter.NB-active,
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-facebook.NB-active {
|
||||
opacity: 1;
|
||||
-webkit-filter: none;
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-twitter {
|
||||
background: transparent url('/media/embed/reader/twitter_icon.png') no-repeat 0 0;
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-crosspost-facebook {
|
||||
background: transparent url('/media/embed/reader/facebook_icon.png') no-repeat 0 0;
|
||||
}
|
||||
.NB-sideoption-share .NB-sideoption-share-comments {
|
||||
width: 100%;
|
||||
|
|
|
@ -19,6 +19,7 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
|
|||
this.friends = {};
|
||||
this.profile = {};
|
||||
this.user_profile = new NEWSBLUR.Models.User();
|
||||
this.social_services = {};
|
||||
this.user_profiles = new NEWSBLUR.Collections.Users();
|
||||
this.follower_profiles = new NEWSBLUR.Collections.Users();
|
||||
this.following_profiles = new NEWSBLUR.Collections.Users();
|
||||
|
@ -216,7 +217,8 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
|
|||
}, callback);
|
||||
},
|
||||
|
||||
mark_story_as_shared: function(story_id, feed_id, comments, source_user_id, callback, error_callback) {
|
||||
mark_story_as_shared: function(story_id, feed_id, comments, source_user_id, post_to_services,
|
||||
callback, error_callback) {
|
||||
var pre_callback = _.bind(function(data) {
|
||||
if (data.user_profiles) {
|
||||
this.add_user_profiles(data.user_profiles);
|
||||
|
@ -231,7 +233,8 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
|
|||
story_id: story_id,
|
||||
feed_id: feed_id,
|
||||
comments: comments,
|
||||
source_user_id: source_user_id
|
||||
source_user_id: source_user_id,
|
||||
post_to_services: post_to_services
|
||||
}, pre_callback, error_callback);
|
||||
} else {
|
||||
error_callback();
|
||||
|
@ -292,6 +295,7 @@ NEWSBLUR.AssetModel = Backbone.Router.extend({
|
|||
self.starred_count = subscriptions.starred_count;
|
||||
self.social_feeds.reset(subscriptions.social_feeds);
|
||||
self.user_profile.set(subscriptions.social_profile);
|
||||
self.social_services = subscriptions.social_services;
|
||||
|
||||
if (!_.isEqual(self.favicons, {})) {
|
||||
self.feeds.each(function(feed) {
|
||||
|
|
|
@ -47,7 +47,8 @@ NEWSBLUR.Views.StoryDetailView = Backbone.View.extend({
|
|||
model: this.model,
|
||||
el: this.el
|
||||
}).template({
|
||||
story: this.model
|
||||
story: this.model,
|
||||
social_services: NEWSBLUR.assets.social_services
|
||||
});
|
||||
this.$el.html(this.template(params));
|
||||
this.toggle_classes();
|
||||
|
|
|
@ -4,6 +4,8 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
"click .NB-feed-story-share" : "toggle_feed_story_share_dialog",
|
||||
"click .NB-sideoption-share-save" : "mark_story_as_shared",
|
||||
"click .NB-sideoption-share-unshare" : "mark_story_as_unshared",
|
||||
"click .NB-sideoption-share-crosspost-twitter" : "toggle_twitter",
|
||||
"click .NB-sideoption-share-crosspost-facebook" : "toggle_facebook",
|
||||
"keyup .NB-sideoption-share-comments" : "update_share_button_label"
|
||||
},
|
||||
|
||||
|
@ -13,7 +15,8 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
|
||||
render: function() {
|
||||
this.$el.html(this.template({
|
||||
story: this.model
|
||||
story: this.model,
|
||||
social_services: NEWSBLUR.assets.social_services
|
||||
}));
|
||||
|
||||
return this;
|
||||
|
@ -23,7 +26,14 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
<div class="NB-sideoption-share-wrapper">\
|
||||
<div class="NB-sideoption-share">\
|
||||
<div class="NB-sideoption-share-wordcount"></div>\
|
||||
<div class="NB-sideoption-share-optional">Optional</div>\
|
||||
<div class="NB-sideoption-share-crosspost">\
|
||||
<% if (social_services.twitter.twitter_uid) { %>\
|
||||
<div class="NB-sideoption-share-crosspost-twitter"></div>\
|
||||
<% } %>\
|
||||
<% if (social_services.facebook.facebook_uid) { %>\
|
||||
<div class="NB-sideoption-share-crosspost-facebook"></div>\
|
||||
<% } %>\
|
||||
</div>\
|
||||
<div class="NB-sideoption-share-title">Comments:</div>\
|
||||
<textarea class="NB-sideoption-share-comments"><%= story.get("shared_comments") %></textarea>\
|
||||
<div class="NB-menu-manage-story-share-save NB-modal-submit-green NB-sideoption-share-save NB-modal-submit-button">Share</div>\
|
||||
|
@ -41,6 +51,8 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
var $comment_input = this.$('.NB-sideoption-share-comments');
|
||||
var $story_comments = this.$('.NB-feed-story-comments');
|
||||
var $unshare_button = this.$('.NB-sideoption-share-unshare');
|
||||
var $twitter_button = this.$('.NB-sideoption-share-crosspost-twitter');
|
||||
var $facebook_button = this.$('.NB-sideoption-share-crosspost-facebook');
|
||||
|
||||
if (options.close ||
|
||||
($sideoption.hasClass('NB-active') && !options.resize_open)) {
|
||||
|
@ -71,8 +83,11 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
}
|
||||
} else {
|
||||
// Open/resize
|
||||
this.$('.NB-error').remove();
|
||||
$sideoption.addClass('NB-active');
|
||||
$unshare_button.toggleClass('NB-hidden', !this.model.get("shared"));
|
||||
$twitter_button.toggleClass('NB-active', !!NEWSBLUR.assets.preference('post_to_twitter'));
|
||||
$facebook_button.toggleClass('NB-active', !!NEWSBLUR.assets.preference('post_to_facebook'));
|
||||
var $share_clone = $share.clone();
|
||||
var full_height = $share_clone.css({
|
||||
'height': 'auto',
|
||||
|
@ -135,10 +150,14 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
var comments = _.string.trim((options.source == 'menu' ? $comments_menu : $comments_sideoptions).val());
|
||||
var feed = NEWSBLUR.assets.get_feed(NEWSBLUR.reader.active_feed);
|
||||
var source_user_id = feed && feed.get('user_id');
|
||||
var post_to_services = _.compact([
|
||||
NEWSBLUR.assets.preference('post_to_twitter') && 'twitter',
|
||||
NEWSBLUR.assets.preference('post_to_facebook') && 'facebook'
|
||||
]);
|
||||
|
||||
$share_button.addClass('NB-saving').addClass('NB-disabled').text('Sharing...');
|
||||
$share_button_menu.addClass('NB-saving').addClass('NB-disabled').text('Sharing...');
|
||||
NEWSBLUR.assets.mark_story_as_shared(this.model.id, this.model.get('story_feed_id'), comments, source_user_id, _.bind(this.post_share_story, this, true), _.bind(function(data) {
|
||||
NEWSBLUR.assets.mark_story_as_shared(this.model.id, this.model.get('story_feed_id'), comments, source_user_id, post_to_services, _.bind(this.post_share_story, this, true), _.bind(function(data) {
|
||||
this.post_share_error(data, true);
|
||||
}, this));
|
||||
|
||||
|
@ -242,6 +261,30 @@ NEWSBLUR.Views.StoryShareView = Backbone.View.extend({
|
|||
count_selected_words_when_sharing_story: function($feed_story) {
|
||||
var $wordcount = $('.NB-sideoption-share-wordcount', $feed_story);
|
||||
|
||||
},
|
||||
|
||||
toggle_twitter: function() {
|
||||
var $twitter_button = this.$('.NB-sideoption-share-crosspost-twitter');
|
||||
|
||||
if (NEWSBLUR.assets.preference('post_to_twitter')) {
|
||||
NEWSBLUR.assets.preference('post_to_twitter', false);
|
||||
} else {
|
||||
NEWSBLUR.assets.preference('post_to_twitter', true);
|
||||
}
|
||||
|
||||
$twitter_button.toggleClass('NB-active', NEWSBLUR.assets.preference('post_to_twitter'));
|
||||
},
|
||||
|
||||
toggle_facebook: function() {
|
||||
var $facebook_button = this.$('.NB-sideoption-share-crosspost-facebook');
|
||||
|
||||
if (NEWSBLUR.assets.preference('post_to_facebook')) {
|
||||
NEWSBLUR.assets.preference('post_to_facebook', false);
|
||||
} else {
|
||||
NEWSBLUR.assets.preference('post_to_facebook', true);
|
||||
}
|
||||
|
||||
$facebook_button.toggleClass('NB-active', NEWSBLUR.assets.preference('post_to_facebook'));
|
||||
}
|
||||
|
||||
});
|
|
@ -1,16 +1,17 @@
|
|||
{% block body %}{% endblock body %}
|
||||
|
||||
- Samuel Clay, @samuelclay
|
||||
- Samuel & Roy
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
Stay up to date and in touch with me, yr. developer, in a few different ways:
|
||||
NewsBlur is your social news reader with intelligence. A new sound of an old instrument.
|
||||
|
||||
Stay up to date and in touch with us, yr. developers, in a few different ways:
|
||||
|
||||
* Follow @samuelclay on Twitter: http://twitter.com/samuelclay/
|
||||
* Follow @newsblur on Twitter: http://twitter.com/newsblur/
|
||||
* Follow @samuelclay on GitHub: http://github.com/samuelclay/
|
||||
|
||||
{% block resources_header %}There are a few resources you can use if you end up loving NewsBlur:{% endblock resources_header %}
|
||||
{% block resources_header %}To get the most out of NewsBlur, here are a few resources:{% endblock resources_header %}
|
||||
|
||||
* Read the NewsBlur Blog: http://blog.newsblur.com
|
||||
* Get support on NewsBlur's Get Satisfaction: http://getsatisfaction.com/newsblur/
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
|
||||
{% block body %}{% endblock %}
|
||||
|
||||
<p style="line-height:20px;">- Samuel Clay, <a href="http://twitter.com/samuelclay" style="text-decoration:none">@samuelclay</a></p>
|
||||
<p style="line-height:20px;clear: both;">- Samuel & Roy</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
@ -28,22 +28,22 @@
|
|||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<p style="line-height:20px;">Stay up to date and in touch with me, yr. developer, in a few different ways:</p>
|
||||
<p style="line-height:20px;">NewsBlur is your social news reader with intelligence. A new sound of an old instrument.</p>
|
||||
<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/samuelclay/" style="text-decoration:none"><img src="http://www.newsblur.com/media/img/reader/twitter_icon.png" style="width:16px;height:16px;vertical-align:top;padding-top:3px;"> Follow @samuelclay on Twitter</a>.</li>
|
||||
<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>. ← I live on props.</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>
|
||||
</ul>
|
||||
</p>
|
||||
<p style="line-height: 20px;">{% block resources_header %}There are a couple resources you can use if you end up loving NewsBlur:{% endblock resources_header %}</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>
|
||||
</ul>
|
||||
</p>
|
||||
<p style="line-height: 20px;">There's plenty of ways to use NewsBlur beyond the website:</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>
|
||||
|
|
|
@ -6,3 +6,5 @@
|
|||
<p style="line-height: 20px;">Spend a few days trying out NewsBlur. I hope you end up loving it.</p>
|
||||
<p style="line-height: 20px;">If you really do love using NewsBlur you should purchase a fancy <b>premium account</b> for only $12/year (nights and weekends and all major public holidays included). You get to support an independent developer, help feed his dog, and contribute to the long-term health of NewsBlur.</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block resources_header %}There are a couple resources you can use if you end up loving NewsBlur:{% endblock resources_header %}
|
|
@ -337,6 +337,10 @@
|
|||
user_id of the original sharer.
|
||||
optional: true
|
||||
example: "128"
|
||||
- key: post_to_services
|
||||
desc: "List of services to cross-post to. Can be 'twitter' and/or 'facebook'."
|
||||
optional: true
|
||||
example: "['twitter', 'facebook']"
|
||||
- url: /social/unshare_story
|
||||
method: POST
|
||||
short_desc: "Remove a shared story from user's blurblog."
|
||||
|
|
|
@ -146,7 +146,6 @@ class bunch(dict):
|
|||
else:
|
||||
self.__setitem__(item, value)
|
||||
|
||||
|
||||
class MLStripper(HTMLParser):
|
||||
def __init__(self):
|
||||
self.reset()
|
||||
|
@ -159,4 +158,16 @@ class MLStripper(HTMLParser):
|
|||
def strip_tags(html):
|
||||
s = MLStripper()
|
||||
s.feed(html)
|
||||
return s.get_data()
|
||||
return s.get_data()
|
||||
|
||||
def truncate_chars(value, max_length):
|
||||
if len(value) <= max_length:
|
||||
return value
|
||||
|
||||
truncd_val = value[:max_length]
|
||||
if value[max_length] != " ":
|
||||
rightmost_space = truncd_val.rfind(" ")
|
||||
if rightmost_space != -1:
|
||||
truncd_val = truncd_val[:rightmost_space]
|
||||
|
||||
return truncd_val + "..."
|
Loading…
Add table
Reference in a new issue