Adding first JS to blurblogs: loading public comments.

This commit is contained in:
Samuel Clay 2012-06-29 21:06:33 -07:00
parent edb43558b8
commit db3a809dd1
18 changed files with 288 additions and 115 deletions

View file

@ -417,7 +417,7 @@ def load_single_feed(request, feed_id):
stories = feed.get_stories(offset, limit)
try:
stories, user_profiles = MSharedStory.stories_with_comments_and_profiles(stories, user)
stories, user_profiles = MSharedStory.stories_with_comments_and_profiles(stories, user.pk)
except redis.ConnectionError:
logging.user(request, "~BR~FK~SBRedis is unavailable for shared stories.")

View file

@ -1139,17 +1139,23 @@ class MSharedStory(mongo.Document):
return comments
@classmethod
def stories_with_comments_and_profiles(cls, stories, user, check_all=False):
def stories_with_comments_and_profiles(cls, stories, user_id, check_all=False, public=False,
attach_users=False):
r = redis.Redis(connection_pool=settings.REDIS_POOL)
friend_key = "F:%s:F" % (user.pk)
friend_key = "F:%s:F" % (user_id)
profile_user_ids = set()
for story in stories:
story['comments'] = []
if check_all or story['comment_count']:
comment_key = "C:%s:%s" % (story['story_feed_id'], story['guid_hash'])
if check_all:
story['comment_count'] = r.scard(comment_key)
friends_with_comments = r.sinter(comment_key, friend_key)
if public:
friends_with_comments = r.sdiff(comment_key, friend_key)
else:
friends_with_comments = r.sinter(comment_key, friend_key)
shared_stories = []
print friends_with_comments
if friends_with_comments:
params = {
'story_guid': story['id'],
@ -1157,7 +1163,6 @@ class MSharedStory(mongo.Document):
'user_id__in': friends_with_comments,
}
shared_stories = cls.objects.filter(**params)
story['comments'] = []
for shared_story in shared_stories:
comments = shared_story.comments_with_author()
story['comments'].append(comments)
@ -1185,6 +1190,20 @@ class MSharedStory(mongo.Document):
profiles = MSocialProfile.objects.filter(user_id__in=list(profile_user_ids))
profiles = [profile.to_json(compact=True) for profile in profiles]
if attach_users and story['share_count']:
profiles = dict([(p['user_id'], p) for p in profiles])
for s, story in enumerate(stories):
for u, user_id in enumerate(story['shared_by_friends']):
stories[s]['shared_by_friends'][u] = profiles[user_id]
for u, user_id in enumerate(story['shared_by_public']):
stories[s]['shared_by_public'][u] = profiles[user_id]
for c, comment in enumerate(story['comments']):
stories[s]['comments'][c]['user'] = profiles[comment['user_id']]
if comment['source_user_id']:
stories[s]['comments'][c]['source_user'] = profiles[comment['source_user_id']]
for r, reply in enumerate(comment['replies']):
stories[s]['comments'][c]['replies'][r]['user'] = profiles[reply['user_id']]
return stories, profiles
def blurblog_permalink(self):

View file

View file

@ -0,0 +1,15 @@
from django import template
register = template.Library()
@register.inclusion_tag('social/story_share.xhtml')
def render_story_share(story):
return {
'story': story,
}
@register.inclusion_tag('social/story_comments.xhtml')
def render_story_comments(story):
return {
'story': story,
}

View file

@ -1,12 +1,13 @@
import time
import datetime
import zlib
from django.shortcuts import get_object_or_404
from django.shortcuts import get_object_or_404, render_to_response
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.template.loader import render_to_string
from django.http import HttpResponse, HttpResponseRedirect, Http404
from django.conf import settings
from django.template import RequestContext
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
@ -52,7 +53,7 @@ def load_social_stories(request, user_id, username=None):
if not stories:
return dict(stories=[])
stories, user_profiles = MSharedStory.stories_with_comments_and_profiles(stories, user, check_all=True)
stories, user_profiles = MSharedStory.stories_with_comments_and_profiles(stories, user.pk, check_all=True)
story_feed_ids = list(set(s['story_feed_id'] for s in stories))
try:
@ -165,9 +166,9 @@ def load_social_stories(request, user_id, username=None):
@render_to('social/social_page.xhtml')
def load_social_page(request, user_id, username=None):
user = get_user(request)
social_user_id = int(user_id)
social_user = get_object_or_404(User, pk=social_user_id)
user = social_user
offset = int(request.REQUEST.get('offset', 0))
limit = int(request.REQUEST.get('limit', 12))
page = request.REQUEST.get('page')
@ -196,20 +197,9 @@ def load_social_page(request, user_id, username=None):
shared_date = localtime_for_timezone(story['shared_date'], social_user.profile.timezone)
story['shared_date'] = shared_date
stories, profiles = MSharedStory.stories_with_comments_and_profiles(stories, user, check_all=True)
profiles = dict([(p['user_id'], p) for p in profiles])
for s, story in enumerate(stories):
for u, user_id in enumerate(story['shared_by_friends']):
stories[s]['shared_by_friends'][u] = profiles[user_id]
for u, user_id in enumerate(story['shared_by_public']):
stories[s]['shared_by_public'][u] = profiles[user_id]
for c, comment in enumerate(story['comments']):
stories[s]['comments'][c]['user'] = profiles[comment['user_id']]
if comment['source_user_id']:
stories[s]['comments'][c]['source_user'] = profiles[comment['source_user_id']]
for r, reply in enumerate(comment['replies']):
stories[s]['comments'][c]['replies'][r]['user'] = profiles[reply['user_id']]
stories, profiles = MSharedStory.stories_with_comments_and_profiles(stories, user.pk,
check_all=True,
attach_users=True)
params = {
'user': user,
@ -221,22 +211,31 @@ def load_social_page(request, user_id, username=None):
return params
@json.json_view
def story_comments(request):
feed_id = int(request.REQUEST['feed_id'])
story_id = request.REQUEST['story_id']
format = request.REQUEST.get('format', 'json')
relative_user_id = request.REQUEST.get('user_id', None)
feed_id = int(request.REQUEST['feed_id'])
story_id = request.REQUEST['story_id']
if not relative_user_id:
relative_user_id = get_user(request).pk
shared_stories = MSharedStory.objects.filter(story_feed_id=feed_id,
story_guid=story_id,
has_comments=True)
comments = [s.comments_with_author() for s in shared_stories]
stories = MStory.objects.filter(story_feed_id=feed_id, story_guid=story_id)
stories = Feed.format_stories(stories)
stories, profiles = MSharedStory.stories_with_comments_and_profiles(stories, relative_user_id,
check_all=True,
public=True,
attach_users=True)
profile_user_ids = set([c['user_id'] for c in comments])
profile_user_ids = profile_user_ids.union([r['user_id'] for c in comments for r in c['replies']])
profiles = MSocialProfile.objects.filter(user_id__in=list(profile_user_ids))
profiles = [profile.to_json(compact=True) for profile in profiles]
return {'comments': comments, 'user_profiles': profiles}
if format == 'html':
return render_to_response('social/story_comments.xhtml', {
'story': stories[0],
}, context_instance=RequestContext(request))
else:
return json.json_response(request, {
'comments': stories[0]['comments'],
'user_profiles': profiles,
})
@ajax_login_required
@json.json_view
@ -323,7 +322,7 @@ def mark_story_as_unshared(request):
story = Feed.format_story(story)
stories, profiles = MSharedStory.stories_with_comments_and_profiles([story],
request.user,
request.user.pk,
check_all=True)
story = stories[0]

View file

@ -95,6 +95,9 @@ javascripts:
- media/js/vendor/underscore-*.js
- media/js/vendor/underscore.string.js
- media/js/vendor/backbone-*.js
- media/js/vendor/jquery.tipsy.js
- media/js/vendor/inflector.js
- media/js/newsblur/social_page/*.js
stylesheets:
common:
@ -111,4 +114,5 @@ stylesheets:
- media/css/bookmarklet/reset.css
- media/css/modals.css
blurblog:
- media/css/social/social_page.css
- media/css/jquery.tipsy.css
- media/css/social/social_page.css

View file

@ -2273,6 +2273,7 @@ background: transparent;
#story_pane .NB-story-comments-public-teaser-wrapper:hover .NB-story-comments-public-teaser {
background-color: #2B478C;
background-image: none;
text-shadow: 0 1px 0 #141F48;
}
#story_pane .NB-story-comments-public-teaser b {
padding: 0 1px;

View file

@ -25,6 +25,13 @@ body {
line-height: 12px;
}
.tipsy {
font-size: 11px;
}
.tipsy-inner {
padding: 2px 9px 2px;
}
/* ========== */
/* = Layout = */
/* ========== */
@ -34,6 +41,13 @@ body {
padding: 0 12px;
}
@media all and (max-width: 500px) {
.NB-page {
padding: 0 6px;
}
}
/* ========== */
/* = Header = */
/* ========== */
@ -637,6 +651,7 @@ header {
.NB-story-comments-public-teaser-wrapper:hover .NB-story-comments-public-teaser {
background-color: #2B478C;
background-image: none;
text-shadow: 0 1px 0 #141F48;
}
.NB-story-comments-public-teaser b {
padding: 0 1px;

View file

@ -1256,6 +1256,7 @@
// ==================
open_social_stories: function(feed_id, options) {
debugger;
// console.log(["open_social_stories", feed_id, options]);
options = options || {};
if (_.isNumber(feed_id)) feed_id = "social:" + feed_id;
@ -1264,6 +1265,15 @@
var $story_titles = this.$s.$story_titles;
var $social_feed = this.find_social_feed_with_feed_id(feed_id);
if (!feed && !options.try_feed) {
// Setup tryfeed views first, then come back here.
var socialsub = this.model.add_social_feed({
id: feed_id,
user_id: parseInt(feed_id.replace('social:', ''), 10)
});
return this.load_social_feed_in_tryfeed_view(socialsub, options);
}
this.reset_feed();
this.hide_splash_page();
@ -1721,6 +1731,7 @@
make_content_pane_feed_counter: function(feed_id) {
var $content_pane = this.$s.$content_pane;
feed_id = feed_id || this.active_feed;
if (!feed_id) return;
var feed = this.model.get_feed(feed_id);
if (NEWSBLUR.app.story_unread_counter) {

View file

@ -0,0 +1,23 @@
NEWSBLUR.Views.SocialPage = Backbone.View.extend({
el: 'body',
initialize: function() {
this.initialize_stories();
},
initialize_stories: function($stories) {
$stories = $stories || this.$el;
$('.NB-story', $stories).each(function() {
new NEWSBLUR.Views.SocialPageStory({el: $(this)});
});
}
});
$(document).ready(function() {
NEWSBLUR.app.social_page = new NEWSBLUR.Views.SocialPage();
});

View file

@ -0,0 +1,31 @@
NEWSBLUR.Views.SocialPageComments = Backbone.View.extend({
events: {
"click .NB-story-comments-public-teaser": "load_public_story_comments"
},
initialize: function() {
},
load_public_story_comments: function() {
$.get('/social/comments', {
story_id: this.options.story_id,
feed_id: this.options.feed_id,
format: "html"
}, _.bind(function(template) {
var $template = $(template);
console.log(["data", $template.length]);
var $header = this.make('div', {
"class": 'NB-story-comments-public-header-wrapper'
}, this.make('div', {
"class": 'NB-story-comments-public-header'
}, Inflector.pluralize(' public comment', $template.length, true)));
this.$(".NB-story-comments-public-teaser-wrapper").replaceWith($template);
$template.before($header);
}, this));
}
});

View file

@ -0,0 +1,18 @@
NEWSBLUR.Views.SocialPageStory = Backbone.View.extend({
initialize: function() {
this.comments_view = new NEWSBLUR.Views.SocialPageComments({
el: this.$('.NB-story-comments'),
story_id: this.$el.data("storyId"),
feed_id: this.$el.data("feedId")
});
this.$('.NB-user-avatar').tipsy({
delayIn: 50,
gravity: 's',
fade: true,
offset: 3
});
}
});

View file

@ -19,7 +19,6 @@
'username' : "{{ user.username|safe }}",
'user_id' : "{{ user.pk|safe }}",
'email' : "{{ user.email|safe }}",
'google_favicon_url' : 'http://www.google.com/s2/favicons?domain_url=',
'MEDIA_URL' : "{{ MEDIA_URL }}",
'debug' : {{ debug|yesno:"true,false" }}
};

View file

@ -21,7 +21,6 @@
'secret_token' : "{{ user.profile.secret_token }}",
'username' : "{{ user.username|safe }}",
'email' : "{{ user.email|safe }}",
'google_favicon_url' : 'http://www.google.com/s2/favicons?domain_url=',
'MEDIA_URL' : "{{ MEDIA_URL }}"
};
NEWSBLUR.Flags = {

View file

@ -1,4 +1,4 @@
{% load utils_tags %}
{% load utils_tags social_tags %}
<!DOCTYPE html>
<html>
@ -7,6 +7,7 @@
<title>{{ social_profile.feed_title }}</title>
<link rel="alternate" type="application/rss+xml" href="{% url shared-stories-rss-feed social_profile.user_id social_profile.username|slugify %}" title="{{ social_profile.feed_title }} RSS feed">
<link rel="shortcut icon" HREF="{{ social_profile.photo_url }}">
<meta name="viewport" content="width=440px">
{% include_stylesheets "blurblog" %}
@ -15,6 +16,27 @@
{{ social_profile.custom_css|safe }}
</style>
{% endif %}
<script type="text/javascript" charset="utf-8">
window.NEWSBLUR = {};
NEWSBLUR.Globals = {
'is_authenticated' : {{ user.is_authenticated|yesno:"true,false" }},
'is_anonymous' : {{ user.is_anonymous|yesno:"true,false" }},
'is_premium' : {{ user.profile.is_premium|yesno:"true,false" }},
'is_admin' : {{ user.is_staff|yesno:"true,false" }},
'is_staff' : {{ user.is_staff|yesno:"true,false" }},
'secret_token' : "{{ user.profile.secret_token }}",
'username' : "{{ user.username|safe }}",
'user_id' : "{{ user.pk|safe }}",
'email' : "{{ user.email|safe }}",
'MEDIA_URL' : "{{ MEDIA_URL }}",
};
NEWSBLUR.Models = {};
NEWSBLUR.Collections = {};
NEWSBLUR.Views = {};
NEWSBLUR.app = {};
</script>
</head>
<body>
@ -100,82 +122,11 @@
</div>
</div>
<div class="NB-story">
<div class="NB-story" data-feed-id="{{ story.story_feed_id }}" data-story-id="{{ story.id }}">
<div class="NB-story-content">{{ story.story_content|safe }}</div>
{% if story.share_count %}
<div class="NB-story-comments">
<div class="NB-story-comments-shares-teaser-wrapper">
<div class="NB-story-comments-shares-teaser">
{% if story.share_count %}
<div class="NB-right">
Shared by
<b>{{ story.share_count }}</b>
{{ story.share_count|pluralize:"person, people" }}
</div>
{% if story.share_count_public %}
<div class="NB-story-share-profiles NB-story-share-profiles-public">
{% for share_user in story.shared_by_public %}
<a href="{{ share_user.feed_link }}" class="NB-user-avatar" title="{{ share_user.username }}">
<img src="{{ share_user.photo_url }}">
</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% if story.share_count %}
{% if story.share_count_friends %}
<div class="NB-story-share-label">Shared by: </div>
<div class="NB-story-share-profiles NB-story-share-profiles-friends">
{% for share_user in story.shared_by_friends %}
<a href="{{ share_user.feed_link }}" class="NB-user-avatar" title="{{ share_user.username }}">
<img src="{{ share_user.photo_url }}">
</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
</div>
</div>
{% for comment in story.comments %}
<div class="NB-story-comment">
<a href="{{ comment.user.feed_link }}" class="NB-user-avatar {% if comment.source_user_id %}NB-story-comment-reshare{% endif %}">
<img src="{{ comment.user.photo_url }}">
</a>
<div class="NB-story-comment-author-container">
{% if comment.source_user_id %}
<div class="NB-story-comment-reshares">
<a href="{{ comment.source_user.feed_link }}" class="NB-user-avatar" title="{{ comment.source_user.username }}">
<img src="{{ comment.source_user.photo_url }}">
</a>
</div>
{% endif %}
<a href="{{ comment.user.feed_link }}" class="NB-story-comment-username">{{ comment.user.username }}</a>
<div class="NB-story-comment-date">{{ comment.shared_date }} ago</div>
<div class="NB-story-comment-reply-button">
<div class="NB-story-comment-reply-button-wrapper">reply</div>
</div>
</div>
<div class="NB-story-comment-content">
{{ comment.comments }}
</div>
{% if comment.replies %}
<div class="NB-story-comment-replies">
{% for reply in comment.replies %}
<div class="NB-story-comment-reply">
<a href="{{ reply.user.feed_link }}">
<img class="NB-user-avatar NB-story-comment-reply-photo" src="{{ reply.user.photo_url }}" />
</a>
<a href="{{ reply.user.feed_link }}" class="NB-story-comment-username NB-story-comment-reply-username">{{ reply.user.username }}</a>
<div class="NB-story-comment-date NB-story-comment-reply-date">{{ reply.publish_date }} ago</div>
<div class="NB-story-comment-reply-content">{{ reply.comments }}</div>
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}
</div>
{% render_story_share story %}
{% endif %}
</div>
</div>

View file

@ -0,0 +1,40 @@
{% load social_tags %}
{% for comment in story.comments %}
<div class="NB-story-comment">
<a href="{{ comment.user.feed_link }}" class="NB-user-avatar {% if comment.source_user_id %}NB-story-comment-reshare{% endif %}">
<img src="{{ comment.user.photo_url }}">
</a>
<div class="NB-story-comment-author-container">
{% if comment.source_user_id %}
<div class="NB-story-comment-reshares">
<a href="{{ comment.source_user.feed_link }}" class="NB-user-avatar" title="{{ comment.source_user.username }}">
<img src="{{ comment.source_user.photo_url }}">
</a>
</div>
{% endif %}
<a href="{{ comment.user.feed_link }}" class="NB-story-comment-username">{{ comment.user.username }}</a>
<div class="NB-story-comment-date">{{ comment.shared_date }} ago</div>
<div class="NB-story-comment-reply-button">
<div class="NB-story-comment-reply-button-wrapper">reply</div>
</div>
</div>
<div class="NB-story-comment-content">
{{ comment.comments }}
</div>
{% if comment.replies %}
<div class="NB-story-comment-replies">
{% for reply in comment.replies %}
<div class="NB-story-comment-reply">
<a href="{{ reply.user.feed_link }}">
<img class="NB-user-avatar NB-story-comment-reply-photo" src="{{ reply.user.photo_url }}" />
</a>
<a href="{{ reply.user.feed_link }}" class="NB-story-comment-username NB-story-comment-reply-username">{{ reply.user.username }}</a>
<div class="NB-story-comment-date NB-story-comment-reply-date">{{ reply.publish_date }} ago</div>
<div class="NB-story-comment-reply-content">{{ reply.comments }}</div>
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endfor %}

View file

@ -0,0 +1,46 @@
{% load social_tags %}
<div class="NB-story-comments">
<div class="NB-story-comments-shares-teaser-wrapper">
<div class="NB-story-comments-shares-teaser">
{% if story.share_count %}
<div class="NB-right">
Shared by
<b>{{ story.share_count }}</b>
{{ story.share_count|pluralize:"person, people" }}
</div>
{% if story.share_count_public %}
<div class="NB-story-share-profiles NB-story-share-profiles-public">
{% for share_user in story.shared_by_public %}
<a href="{{ share_user.feed_link }}" class="NB-user-avatar" title="{{ share_user.username }}">
<img src="{{ share_user.photo_url }}">
</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
{% if story.share_count %}
{% if story.share_count_friends %}
<div class="NB-story-share-label">Shared by: </div>
<div class="NB-story-share-profiles NB-story-share-profiles-friends">
{% for share_user in story.shared_by_friends %}
<a href="{{ share_user.feed_link }}" class="NB-user-avatar" title="{{ share_user.username }}">
<img src="{{ share_user.photo_url }}">
</a>
{% endfor %}
</div>
{% endif %}
{% endif %}
</div>
</div>
{% render_story_comments story %}
{% if story.comment_count_public %}
<div class="NB-story-comments-public-teaser-wrapper">
<div class="NB-story-comments-public-teaser">
There {{ story.comment_count_public|pluralize:"is,are" }} {{ story.comment_count_public}} public comment{{ story.comment_count_public|pluralize }}
</div>
</div>
{% endif %}
</div>

View file

@ -115,6 +115,10 @@ def json_view(func):
def json_response(request, response=None):
code = 200
if isinstance(response, HttpResponseForbidden):
return response
try:
if isinstance(response, dict):
response = dict(response)
@ -149,8 +153,6 @@ def json_response(request, response=None):
else:
print '\n'.join(traceback.format_exception(*exc_info))
if isinstance(response, HttpResponseForbidden):
return response
json = json_encode(response)
return HttpResponse(json, mimetype='application/json', status=code)