diff --git a/apps/profile/models.py b/apps/profile/models.py index 7ef441a2e..20612511a 100644 --- a/apps/profile/models.py +++ b/apps/profile/models.py @@ -179,41 +179,55 @@ NewsBlur""" % {'user': self.user.username, 'feeds': subs.count()} class MInteraction(mongo.Document): user_id = mongo.IntField() - activity_date = mongo.DateTimeField(default=datetime.datetime.now) - activity_type = mongo.StringField() - activity_content = mongo.StringField() + date = mongo.DateTimeField(default=datetime.datetime.now) + activity = mongo.StringField() + title = mongo.StringField() + content = mongo.StringField() activity_user_id = mongo.IntField() + feed_id = mongo.IntField() + content_id = mongo.StringField() meta = { 'collection': 'interactions', - 'indexes': [('user_id', 'activity_date')], + 'indexes': [('user_id', 'date'), 'activity'], 'allow_inheritance': False, 'index_drop_dups': True, + 'ordering': ['-date'], } def __unicode__(self): user = User.objects.get(pk=self.user_id) - return "%s on %s: %s - %s" % (user.username, self.activity_date, - self.activity_type, self.activity_content[:20]) + activity_user = self.activity_user_id and User.objects.get(pk=self.activity_user_id) + return "<%s> %s on %s: %s - %s" % (user.username, activity_user and activity_user.username, self.date, + self.activity, self.content and self.content[:20]) @classmethod def new_follow(cls, follower_user_id, followee_user_id): cls.objects.create(user_id=followee_user_id, activity_user_id=follower_user_id, - activity_type='follow') + activity='follow') @classmethod - def new_reply(cls, user_id, reply_user_id, reply_content): + def new_comment_reply(cls, user_id, reply_user_id, reply_content): cls.objects.create(user_id=user_id, activity_user_id=reply_user_id, - activity_type='reply', - activity_content=reply_content) + activity='comment_reply', + content=reply_content) + @classmethod - def new_starred_story(cls, user_id, story_title, story_feed_id): - feed = Feed.objects.get(pk=story_feed_id) + def new_reply_reply(cls, user_id, reply_user_id, reply_content): cls.objects.create(user_id=user_id, - activity_type='star', - activity_content=story_title) + activity_user_id=reply_user_id, + activity='reply_reply', + content=reply_content) + + @classmethod + def new_starred_story(cls, user_id, story_title, story_feed_id, story_id): + cls.objects.create(user_id=user_id, + activity='star', + content=story_title, + feed_id=story_feed_id, + content_id=story_id) def create_profile(sender, instance, created, **kwargs): diff --git a/apps/reader/views.py b/apps/reader/views.py index 37603818b..94650fb30 100644 --- a/apps/reader/views.py +++ b/apps/reader/views.py @@ -22,9 +22,10 @@ from collections import defaultdict from operator import itemgetter from apps.recommendations.models import RecommendedFeed 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 apply_classifier_titles, apply_classifier_feeds +from apps.analyzer.models import apply_classifier_authors, apply_classifier_tags from apps.analyzer.models import get_classifiers_for_user -from apps.profile.models import Profile +from apps.profile.models import Profile, MInteraction from apps.reader.models import UserSubscription, UserSubscriptionFolders, MUserStory, Feature from apps.reader.forms import SignupForm, LoginForm, FeatureForm from apps.rss_feeds.models import MFeedIcon @@ -1199,6 +1200,10 @@ def mark_story_as_starred(request): defaults=story_values) if created: logging.user(request, "~FCStarring: ~SB%s" % (story[0].story_title[:50])) + MInteraction.new_starred_story(user_id=request.user.pk, + story_title=story[0].story_title, + story_feed_id=feed_id, + content_id=starred_story.story_guid) else: logging.user(request, "~FC~BRAlready stared:~SN~FC ~SB%s" % (story[0].story_title[:50])) else: diff --git a/apps/social/views.py b/apps/social/views.py index 43051155f..5f8c0e415 100644 --- a/apps/social/views.py +++ b/apps/social/views.py @@ -12,6 +12,7 @@ from apps.analyzer.models import MClassifierTitle, MClassifierAuthor, MClassifie 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 from apps.reader.models import MUserStory, UserSubscription +from apps.profile.models import MInteraction from utils import json_functions as json from utils import log as logging from utils import PyRSS2Gen as RSS @@ -252,14 +253,25 @@ def save_comment_reply(request): reply.comments = reply_comments shared_story.replies.append(reply) shared_story.save() + logging.user(request, "~FCReplying to comment in: ~SB~FM%s (~FB%s~FM)" % (story.story_title[:50], reply_comments[:100])) comment = shared_story.comments_with_author() profile_user_ids = set([comment['user_id']]) - profile_user_ids = profile_user_ids.union([reply['user_id'] for reply in comment['replies']]) + reply_user_ids = [reply['user_id'] for reply in comment['replies']] + profile_user_ids = profile_user_ids.union(reply_user_ids) profiles = MSocialProfile.objects.filter(user_id__in=list(profile_user_ids)) profiles = [profile.to_json(compact=True) for profile in profiles] + # Interaction for every other replier and original commenter + MInteraction.new_comment_reply(user_id=comment['user_id'], + reply_user_id=request.user.pk, + reply_content=reply_comments) + for user_id in reply_user_ids.difference([comment['user_id']]): + MInteraction.new_reply_reply(user_id=user_id, + reply_user_id=request.user.pk, + reply_content=reply_comments) + return {'code': code, 'comment': comment, 'user_profiles': profiles} def shared_stories_public(request, username): @@ -299,7 +311,7 @@ def profile(request): def load_user_profile(request): social_profile, _ = MSocialProfile.objects.get_or_create(user_id=request.user.pk) social_services, _ = MSocialServices.objects.get_or_create(user_id=request.user.pk) - + return { 'services': social_services, 'user_profile': social_profile.to_json(full=True), diff --git a/media/css/reader.css b/media/css/reader.css index 8c9e96be9..eef82c617 100644 --- a/media/css/reader.css +++ b/media/css/reader.css @@ -7707,3 +7707,60 @@ background: transparent; color: #909090; text-transform: uppercase; } + +/* ======================= */ +/* = Interactions Module = */ +/* ======================= */ + +.NB-interactions { + list-style: none; + padding: 0; + margin: 12px 0; +} +.NB-interaction { + list-style: none; + position: relative; + margin: 0; + padding: 6px 12px 6px 36px; + border-bottom: 1px solid #F0F0F0; + overflow: hidden; +} +.NB-interaction:last-child { + border-bottom: none; + padding-bottom: 0; + margin-bottom: 0; +} +.NB-interaction-photo { + position: absolute; + width: 16px; + height: 16px; + border-radius: 3px; + left: 12px; + top: 10px; + cursor: pointer; +} +.NB-interaction-date { + color: #B0B0B0; + font-size: 11px; + float: right; + text-transform: uppercase; + padding: 4px 0 4px 4px; +} +.NB-interaction-title { + font-size: 13px; + line-height: 18px; + color: #404040; + padding: 2px 0 0 0; +} +.NB-interaction-content { + font-size: 11px; + padding-top: 2px; + line-height: 14px; + color: #808080; +} +.NB-interaction-username { + cursor: pointer; +} +.NB-interaction-starred-story-title { + cursor: pointer; +} \ No newline at end of file diff --git a/media/js/newsblur/common/assetmodel.js b/media/js/newsblur/common/assetmodel.js index 29815d3fd..8c3328db0 100644 --- a/media/js/newsblur/common/assetmodel.js +++ b/media/js/newsblur/common/assetmodel.js @@ -1123,7 +1123,10 @@ NEWSBLUR.AssetModel.Reader.prototype = { }, fetch_user_profile: function(user_id, callback) { - this.make_request('/social/profile', {'user_id': user_id}, callback, callback, { + this.make_request('/social/profile', {'user_id': user_id}, _.bind(function(data) { + this.add_user_profiles(data.profiles); + callback(data); + }, this), callback, { request_type: 'GET' }); }, diff --git a/media/js/newsblur/reader/reader.js b/media/js/newsblur/reader/reader.js index 3d16c5a99..046a739fd 100644 --- a/media/js/newsblur/reader/reader.js +++ b/media/js/newsblur/reader/reader.js @@ -7567,6 +7567,23 @@ self.save_social_comment_reply($comment); }); + // = Interactions Module ========================================== + + $.targetIs(e, { tagSelector: '.NB-interaction-username' }, function($t, $p){ + e.preventDefault(); + var user_id = $t.data('userId'); + var username = $t.text(); + self.model.add_user_profiles([{user_id: user_id, username: username}]); + self.open_social_profile_modal(user_id); + }); + $.targetIs(e, { tagSelector: '.NB-interaction-profile-photo' }, function($t, $p){ + e.preventDefault(); + var user_id = $t.data('userId'); + var username = $t.closest('.NB-interaction').find('.NB-interaction-username').text(); + self.model.add_user_profiles([{user_id: user_id, username: username}]); + self.open_social_profile_modal(user_id); + }); + // = One-offs ===================================================== var clicked = false; diff --git a/media/js/newsblur/reader/reader_social_profile.js b/media/js/newsblur/reader/reader_social_profile.js index 468e54ee9..491b64134 100644 --- a/media/js/newsblur/reader/reader_social_profile.js +++ b/media/js/newsblur/reader/reader_social_profile.js @@ -6,7 +6,8 @@ NEWSBLUR.ReaderSocialProfile = function(user_id, options) { this.options = $.extend({}, defaults, options); this.model = NEWSBLUR.AssetModel.reader(); this.profiles = new NEWSBLUR.Collections.Users(); - user_id = _.string.ltrim(user_id, 'social:'); + user_id = parseInt(_.string.ltrim(user_id, 'social:'), 10); + console.log(["user_id", user_id]); this.runner(user_id); }; @@ -19,7 +20,7 @@ _.extend(NEWSBLUR.ReaderSocialProfile.prototype, { this.make_modal(); this.open_modal(); _.defer(_.bind(this.fetch_profile, this, user_id)); - + this.$modal.bind('click', $.rescope(this.handle_click, this)); }, diff --git a/templates/reader/interactions_module.xhtml b/templates/reader/interactions_module.xhtml index a2b7e864f..d26802b72 100644 --- a/templates/reader/interactions_module.xhtml +++ b/templates/reader/interactions_module.xhtml @@ -1,18 +1,60 @@ {% load utils_tags typogrify_tags statistics_tags %} +{% if interactions %}