mirror of
https://github.com/viq/NewsBlur.git
synced 2025-11-01 09:09:16 +00:00
Splitting interactions into public/private interactions and activities.
This commit is contained in:
parent
b9d8b91f6d
commit
451485d32e
11 changed files with 186 additions and 98 deletions
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
||||
|
|
|
|||
|
|
@ -176,6 +176,6 @@ class MFeedback(mongo.Document):
|
|||
|
||||
@classmethod
|
||||
def all(cls):
|
||||
feedbacks = cls.objects.all()[:5]
|
||||
feedbacks = cls.objects.all()[:3]
|
||||
|
||||
return feedbacks
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 =====================================================
|
||||
|
||||
|
|
|
|||
46
templates/reader/activities_module.xhtml
Normal file
46
templates/reader/activities_module.xhtml
Normal 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 %}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue