Splitting interactions into public/private interactions and activities.

This commit is contained in:
Samuel Clay 2012-04-11 12:14:18 -07:00
parent b9d8b91f6d
commit 451485d32e
11 changed files with 186 additions and 98 deletions

View file

@ -178,18 +178,18 @@ NewsBlur""" % {'user': self.user.username, 'feeds': subs.count()}
class MInteraction(mongo.Document):
user_id = mongo.IntField()
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()
user_id = mongo.IntField()
date = mongo.DateTimeField(default=datetime.datetime.now)
category = mongo.StringField()
title = mongo.StringField()
content = mongo.StringField()
with_user_id = mongo.IntField()
feed_id = mongo.IntField()
content_id = mongo.StringField()
meta = {
'collection': 'interactions',
'indexes': [('user_id', 'date'), 'activity'],
'indexes': [('user_id', 'date'), 'category'],
'allow_inheritance': False,
'index_drop_dups': True,
'ordering': ['-date'],
@ -197,38 +197,71 @@ class MInteraction(mongo.Document):
def __unicode__(self):
user = User.objects.get(pk=self.user_id)
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])
with_user = self.with_user_id and User.objects.get(pk=self.with_user_id)
return "<%s> %s on %s: %s - %s" % (user.username, with_user and with_user.username, self.date,
self.category, 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='follow')
with_user_id=follower_user_id,
category='follow')
@classmethod
def new_comment_reply(cls, user_id, reply_user_id, reply_content):
def new_comment_reply(cls, user_id, reply_user_id, reply_content, social_feed_id, story_id):
cls.objects.create(user_id=user_id,
activity_user_id=reply_user_id,
activity='comment_reply',
content=reply_content)
with_user_id=reply_user_id,
category='comment_reply',
content=reply_content,
feed_id=social_feed_id,
content_id=story_id)
@classmethod
def new_reply_reply(cls, user_id, reply_user_id, reply_content):
def new_reply_reply(cls, user_id, reply_user_id, reply_content, social_feed_id, story_id):
cls.objects.create(user_id=user_id,
activity_user_id=reply_user_id,
activity='reply_reply',
content=reply_content)
with_user_id=reply_user_id,
category='reply_reply',
content=reply_content,
feed_id=social_feed_id,
content_id=story_id)
class MActivity(mongo.Document):
user_id = mongo.IntField()
date = mongo.DateTimeField(default=datetime.datetime.now)
category = mongo.StringField()
title = mongo.StringField()
content = mongo.StringField()
feed_id = mongo.IntField()
content_id = mongo.StringField()
meta = {
'collection': 'activities',
'indexes': [('user_id', 'date'), 'category'],
'allow_inheritance': False,
'index_drop_dups': True,
'ordering': ['-date'],
}
def __unicode__(self):
user = User.objects.get(pk=self.user_id)
return "<%s> %s - %s" % (user.username, self.category, self.content and self.content[:20])
@classmethod
def new_starred_story(cls, user_id, story_title, story_feed_id, story_id):
cls.objects.create(user_id=user_id,
activity='star',
category='star',
content=story_title,
feed_id=story_feed_id,
content_id=story_id)
@classmethod
def new_feed_subscription(cls, user_id, feed_id, feed_title):
cls.objects.create(user_id=user_id,
category='feed_sub',
content=feed_title,
feed_id=feed_id)
def create_profile(sender, instance, created, **kwargs):
if created:

View file

@ -118,16 +118,20 @@ class UserSubscription(models.Model):
user_sub_folders_object.folders = json.encode(user_sub_folders)
user_sub_folders_object.save()
if not auto_active:
if auto_active:
us.active = True
else:
feed_count = cls.objects.filter(user=user).count()
if feed_count < 64 or user.profile.is_premium:
us.active = True
us.save()
feed.setup_feed_for_premium_subscribers()
us.save()
if feed.last_update < datetime.datetime.utcnow() - datetime.timedelta(days=1):
feed.update()
feed = feed.update()
from apps.profile.models import MActivity
MActivity.new_feed_subscription(cls, user_id=user.pk, feed_id=feed.pk, feed_title=feed.title)
feed.setup_feed_for_premium_subscribers()
return code, message, us

View file

@ -25,7 +25,7 @@ from apps.analyzer.models import MClassifierTitle, MClassifierAuthor, MClassifie
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, MInteraction
from apps.profile.models import Profile, MActivity
from apps.reader.models import UserSubscription, UserSubscriptionFolders, MUserStory, Feature
from apps.reader.forms import SignupForm, LoginForm, FeatureForm
from apps.rss_feeds.models import MFeedIcon
@ -1200,10 +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)
MActivity.new_starred_story(user_id=request.user.pk,
story_title=story[0].story_title,
story_feed_id=feed_id,
story_id=starred_story.story_guid)
else:
logging.user(request, "~FC~BRAlready stared:~SN~FC ~SB%s" % (story[0].story_title[:50]))
else:

View file

@ -266,11 +266,15 @@ def save_comment_reply(request):
# 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']]):
reply_content=reply_comments,
social_feed_id=comment_user_id,
story_id=story_id)
for user_id in set(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)
reply_content=reply_comments,
social_feed_id=comment_user_id,
story_id=story_id)
return {'code': code, 'comment': comment, 'user_profiles': profiles}

View file

@ -176,6 +176,6 @@ class MFeedback(mongo.Document):
@classmethod
def all(cls):
feedbacks = cls.objects.all()[:5]
feedbacks = cls.objects.all()[:3]
return feedbacks

View file

@ -3961,7 +3961,7 @@ background: transparent;
.NB-module.NB-loading .NB-spinner {
display: block;
}
.NB-module h3.NB-module-content-header {
.NB-module .NB-module-content-header {
border-bottom: 1px solid #F0F0F0;
padding: 4px 0 0px;
margin: 12px 0 4px 12px;
@ -3972,7 +3972,7 @@ background: transparent;
clear: both;
}
.NB-modules-center .NB-module h3.NB-module-content-header {
.NB-modules-center .NB-module-content-header {
margin-right: 12px;
}
.NB-module .NB-module-content-subtitle {
@ -4022,10 +4022,10 @@ background: transparent;
.NB-module .NB-module-item.NB-done .NB-done-label {
display: block;
}
.NB-module .NB-module-item .NB-module-content-header {
.NB-module.NB-module-account .NB-module-content-header {
margin-left: 128px;
}
.NB-module .NB-module-item .NB-module-item-image {
.NB-module .NB-module-item-image {
position: absolute;
left: 0;
top: 0;
@ -4089,6 +4089,14 @@ background: transparent;
margin: 0 0 0 72px;
clear: none;
}
.NB-account .NB-module-account-stats {
margin-top: 0;
overflow: hidden;
}
.NB-module .NB-module-activity .NB-module-content-header {
margin-left: 12px;
padding-right: 12px;
}
/* ======================= */
/* = How it Works Module = */
@ -7720,8 +7728,8 @@ background: transparent;
.NB-interaction {
list-style: none;
position: relative;
margin: 0;
padding: 6px 12px 6px 36px;
margin: 0 12px;
padding: 6px 0 6px 24px;
border-bottom: 1px solid #F0F0F0;
overflow: hidden;
}
@ -7735,7 +7743,7 @@ background: transparent;
width: 16px;
height: 16px;
border-radius: 3px;
left: 12px;
left: 0;
top: 10px;
cursor: pointer;
}

View file

@ -2067,7 +2067,7 @@
}
},
open_starred_stories: function() {
open_starred_stories: function(story_guid) {
var $story_titles = this.$s.$story_titles;
$story_titles.empty().scrollTop('0px');
@ -7583,6 +7583,11 @@
self.model.add_user_profiles([{user_id: user_id, username: username}]);
self.open_social_profile_modal(user_id);
});
$.targetIs(e, { tagSelector: '.NB-interaction-starred-story-title' }, function($t, $p){
e.preventDefault();
var story_guid = $t.closest('.NB-interaction').data('contentId');
self.open_starred_stories(story_guid);
});
// = One-offs =====================================================

View file

@ -0,0 +1,46 @@
{% load utils_tags typogrify_tags statistics_tags %}
{% if activities %}
<div class="NB-module-item NB-module-activity">
<h3 class="NB-module-content-header">
<div class="NB-module-header-right">
<div class="NB-spinner NB-left"></div>
<a href="#" class="NB-module-direction NB-module-next-page NB-javascript {% if activities|length <= 5 %}NB-disabled{% endif %}"></a>
<a href="#" class="NB-module-direction NB-module-previous-page NB-disabled"></a>
</div>
Your Activity
</h3>
<ul class="NB-interactions">
{% for activity in activities|slice:":5" %}
<li class="NB-interaction NB-interaction-{{ activity.category }}"
{% if activity.content_id %}data-content-id="{{ activity.content_id }}"{% endif %}>
{% if activity.category == 'star' %}
<img class="NB-interaction-photo" src="/rss_feeds/icon/{{ activity.feed_id }}">
<div class="NB-interaction-date">
{{ activity.date }} ago
</div>
<div class="NB-interaction-title">
You starred "<span class="NB-interaction-starred-story-title NB-splash-link">{{ activity.content|truncatewords:8 }}</span>".
</div>
{% endif %}
{% if activity.category == 'feed_sub' %}
<img class="NB-interaction-photo" src="/rss_feeds/icon/{{ activity.feed_id }}">
<div class="NB-interaction-date">
{{ activity.date }} ago
</div>
<div class="NB-interaction-title">
You subscribed to "<span class="NB-interaction-feed-title NB-splash-link">{{ activity.content|truncatewords:8 }}</span>".
</div>
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% endif %}

View file

@ -256,26 +256,6 @@
{% endif %}
</h3>
<div class="NB-module-item-title">
{% if user.profile.is_premium %}
{% else %}
<div class="NB-modal-submit">
{% if feed_count == 0 %}
{# <div class="NB-modal-submit-green NB-modal-submit-button NB-task-add NB-javascript">Add Sites</div> #}
{% else %}
<div class="{% if active_count == 0 %}NB-modal-submit-green{% else %}NB-modal-submit-close{% endif %} NB-modal-submit-button NB-module-account-upgrade NB-javascript">Choose Your 64 Sites</div>
{% endif %}
</div>
{% endif %}
</div>
</div>
<div class="NB-module-user-statistics {% if not user_statistics.shared_stories or not user_statistics %}NB-hidden{% endif %}">
<h3 class="NB-module-content-header">
Your statistics
</h3>
<div class="NB-module-item NB-module-stats NB-module-account-stats">
<div class="NB-module-stats-count">
<div class="NB-module-stats-count-number">{{ user_statistics.shared_stories|commify }}</div>
@ -290,6 +270,10 @@
<div class="NB-module-stats-count-description">Follower{{ user_statistics.followers|pluralize }}</div>
</div>
</div>
</div>
{% render_activities_module %}
</div>
</div>

View file

@ -6,50 +6,40 @@
<h5 class="NB-module-header">
<div class="NB-module-header-right">
<div class="NB-spinner NB-left"></div>
<a href="#" class="NB-module-direction NB-module-next-page NB-javascript"></a>
<a href="#" class="NB-module-direction NB-module-next-page NB-javascript {% if interactions|length <= 5 %}NB-disabled{% endif %}"></a>
<a href="#" class="NB-module-direction NB-module-previous-page NB-disabled"></a>
</div>
Interactions
</h5>
<ul class="NB-interactions">
{% for interaction in interactions %}
<li class="NB-interaction NB-interaction-{{ interaction.activity }}"
{% for interaction in interactions|slice:":5" %}
<li class="NB-interaction NB-interaction-{{ interaction.category }}"
{% if interaction.content_id %}data-content-id="{{ interaction.content_id }}"{% endif %}>
{% if interaction.activity == 'follow' %}
<img class="NB-interaction-photo NB-interaction-profile-photo" src="{{ interaction.photo_url }}" data-user-id="{{ interaction.activity_user_id }}">
{% if interaction.category == 'follow' %}
<img class="NB-interaction-photo NB-interaction-profile-photo" src="{{ interaction.photo_url }}" data-user-id="{{ interaction.with_user_id }}">
<div class="NB-interaction-date">
{{ interaction.date }} ago
</div>
<div class="NB-interaction-title">
<span class="NB-interaction-username NB-splash-link" data-user-id="{{ interaction.activity_user_id }}">
{{ interaction.activity_user.username }}
<span class="NB-interaction-username NB-splash-link" data-user-id="{{ interaction.with_user_id }}">
{{ interaction.with_user.username }}
</span> started following you.
</div>
{% endif %}
{% if interaction.activity == 'star' %}
<img class="NB-interaction-photo" src="/rss_feeds/icon/{{ interaction.feed_id }}">
{% if interaction.category == 'comment_reply' or interaction.category == 'reply_reply' %}
<img class="NB-interaction-photo NB-interaction-profile-photo" src="{{ interaction.photo_url }}" data-user-id="{{ interaction.with_user_id }}">
<div class="NB-interaction-date">
{{ interaction.date }} ago
</div>
<div class="NB-interaction-title">
You starred "<span class="NB-interaction-starred-story-title NB-splash-link">{{ interaction.content|truncatewords:8 }}</span>".
</div>
{% endif %}
{% if interaction.activity == 'comment_reply' or interaction.activity == 'reply_reply' %}
<img class="NB-interaction-photo NB-interaction-profile-photo" src="{{ interaction.photo_url }}" data-user-id="{{ interaction.activity_user_id }}">
<div class="NB-interaction-date">
{{ interaction.date }} ago
</div>
<div class="NB-interaction-title">
<span class="NB-interaction-username NB-splash-link" data-user-id="{{ interaction.activity_user_id }}">
{{ interaction.activity_user.username }}
</span> replied to your {% if interaction.activity == 'comment_reply' %}comment{% else %}reply{% endif %}:
<span class="NB-interaction-username NB-splash-link" data-user-id="{{ interaction.with_user_id }}">
{{ interaction.with_user.username }}
</span> replied to your {% if interaction.category == 'comment_reply' %}comment{% else %}reply{% endif %}:
</div>
<div class="NB-interaction-content">
"<span class="NB-interaction-starred-story-title NB-splash-link">{{ interaction.content|truncatewords:16 }}</span>"
"<span class="NB-interaction-starred-story-title NB-splash-link" data-social-user-id="{{ interaction.feed_id }}">{{ interaction.content|truncatewords:16 }}</span>"
</div>
{% endif %}
</li>

View file

@ -1,10 +1,9 @@
from django.contrib.sites.models import Site
from django.contrib.auth.models import User
from django.conf import settings
from django import template
from apps.reader.forms import FeatureForm
from apps.reader.models import Feature
from apps.profile.models import MInteraction
from apps.profile.models import MInteraction, MActivity
from apps.social.models import MSocialProfile
from vendor.timezones.utilities import localtime_for_timezone
from utils.feed_functions import relative_timesince
@ -39,23 +38,38 @@ def render_features_module(context):
def render_interactions_module(context):
user = get_user(context['user'])
interactions_db = MInteraction.objects.filter(user_id=user.pk)[0:5]
user_ids = [i.activity_user_id for i in interactions_db if i.activity_user_id]
users = dict((u.pk, u) for u in User.objects.filter(pk__in=user_ids))
social_profiles = dict((p.user_id, p) for p in MSocialProfile.objects.filter(user_id__in=user_ids))
with_user_ids = [i.with_user_id for i in interactions_db if i.with_user_id]
social_profiles = dict((p.user_id, p) for p in MSocialProfile.objects.filter(user_id__in=with_user_ids))
interactions = []
for interaction_db in interactions_db:
interaction = interaction_db.to_mongo()
interaction['photo_url'] = getattr(social_profiles.get(interaction_db.activity_user_id), 'photo_url', None)
interaction['activity_user'] = social_profiles.get(interaction_db.activity_user_id)
interaction['photo_url'] = getattr(social_profiles.get(interaction_db.with_user_id), 'photo_url', None)
interaction['with_user'] = social_profiles.get(interaction_db.with_user_id)
interaction['date'] = relative_timesince(interaction_db.date)
interactions.append(interaction)
return {
'user': user,
'interactions': interactions,
'users': users,
'social_profiles': social_profiles,
}
@register.inclusion_tag('reader/activities_module.xhtml', takes_context=True)
def render_activities_module(context):
user = get_user(context['user'])
activities_db = MActivity.objects.filter(user_id=user.pk)[:6]
activities = []
for activity_db in activities_db[:5]:
activity = activity_db.to_mongo()
activity['date'] = relative_timesince(activity_db.date)
activities.append(activity)
if len(activities_db) > 5:
activities.append(activities_db[5].to_mongo())
return {
'user': user,
'activities': activities,
}
@register.filter