2011-12-21 09:43:17 -08:00
|
|
|
import datetime
|
2011-12-14 09:52:06 -08:00
|
|
|
import zlib
|
2011-12-22 13:36:03 -08:00
|
|
|
import hashlib
|
2011-12-14 09:52:06 -08:00
|
|
|
import mongoengine as mongo
|
2011-12-21 09:43:17 -08:00
|
|
|
from django.conf import settings
|
2011-12-22 13:36:03 -08:00
|
|
|
from django.contrib.auth.models import User
|
2011-12-25 20:50:59 -08:00
|
|
|
from apps.reader.models import UserSubscription
|
2011-12-20 11:49:49 -08:00
|
|
|
from vendor import facebook
|
|
|
|
from vendor import tweepy
|
2011-12-24 00:30:37 -08:00
|
|
|
from utils import log as logging
|
2011-12-14 09:52:06 -08:00
|
|
|
|
|
|
|
|
|
|
|
class MSharedStory(mongo.Document):
|
|
|
|
user_id = mongo.IntField()
|
|
|
|
shared_date = mongo.DateTimeField()
|
|
|
|
comments = mongo.StringField()
|
2011-12-19 09:24:19 -08:00
|
|
|
has_comments = mongo.BooleanField(default=False)
|
2011-12-14 09:52:06 -08:00
|
|
|
story_feed_id = mongo.IntField()
|
|
|
|
story_date = mongo.DateTimeField()
|
|
|
|
story_title = mongo.StringField(max_length=1024)
|
|
|
|
story_content = mongo.StringField()
|
|
|
|
story_content_z = mongo.BinaryField()
|
|
|
|
story_original_content = mongo.StringField()
|
|
|
|
story_original_content_z = mongo.BinaryField()
|
|
|
|
story_content_type = mongo.StringField(max_length=255)
|
|
|
|
story_author_name = mongo.StringField()
|
|
|
|
story_permalink = mongo.StringField()
|
|
|
|
story_guid = mongo.StringField(unique_with=('user_id',))
|
|
|
|
story_tags = mongo.ListField(mongo.StringField(max_length=250))
|
|
|
|
|
|
|
|
meta = {
|
|
|
|
'collection': 'shared_stories',
|
|
|
|
'indexes': [('user_id', '-shared_date'), ('user_id', 'story_feed_id'), 'story_feed_id'],
|
|
|
|
'index_drop_dups': True,
|
|
|
|
'ordering': ['-shared_date'],
|
|
|
|
'allow_inheritance': False,
|
|
|
|
}
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
if self.story_content:
|
|
|
|
self.story_content_z = zlib.compress(self.story_content)
|
|
|
|
self.story_content = None
|
|
|
|
if self.story_original_content:
|
|
|
|
self.story_original_content_z = zlib.compress(self.story_original_content)
|
|
|
|
self.story_original_content = None
|
|
|
|
super(MSharedStory, self).save(*args, **kwargs)
|
2011-12-20 11:49:49 -08:00
|
|
|
|
|
|
|
|
2012-01-04 09:42:35 -08:00
|
|
|
class MSocialProfile(mongo.Document):
|
|
|
|
user_id = mongo.IntField()
|
|
|
|
username = mongo.StringField(max_length=30)
|
|
|
|
email = mongo.StringField()
|
|
|
|
bio = mongo.StringField(max_length=80)
|
|
|
|
photo_url = mongo.StringField()
|
|
|
|
photo_service = mongo.StringField()
|
|
|
|
location = mongo.StringField(max_length=40)
|
|
|
|
website = mongo.StringField(max_length=200)
|
|
|
|
subscription_count = mongo.IntField(default=0)
|
|
|
|
shared_stories_count = mongo.IntField(default=0)
|
|
|
|
following_count = mongo.IntField(default=0)
|
|
|
|
follower_count = mongo.IntField(default=0)
|
|
|
|
following_user_ids = mongo.ListField(mongo.IntField())
|
|
|
|
follower_user_ids = mongo.ListField(mongo.IntField())
|
|
|
|
unfollowed_user_ids = mongo.ListField(mongo.IntField())
|
|
|
|
|
|
|
|
meta = {
|
|
|
|
'collection': 'social_profile',
|
|
|
|
'indexes': ['user_id', 'following_user_ids', 'follower_user_ids', 'unfollowed_user_ids'],
|
|
|
|
'allow_inheritance': False,
|
|
|
|
}
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return "%s [%s] %s/%s" % (self.username, self.user_id,
|
|
|
|
self.subscription_count, self.shared_stories_count)
|
|
|
|
|
|
|
|
def save(self, *args, **kwargs):
|
|
|
|
if not self.username:
|
|
|
|
self.update_user(skip_save=True)
|
|
|
|
if not self.subscription_count:
|
|
|
|
self.count(skip_save=True)
|
|
|
|
super(MSocialProfile, self).save(*args, **kwargs)
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def profiles(cls, user_ids):
|
|
|
|
profiles = cls.objects.filter(user_id__in=user_ids)
|
|
|
|
return profiles
|
|
|
|
|
|
|
|
def to_json(self, full=False):
|
|
|
|
params = {
|
|
|
|
'user_id': self.user_id,
|
|
|
|
'username': self.username,
|
|
|
|
'photo_url': self.photo_url,
|
|
|
|
'bio': self.bio,
|
|
|
|
'location': self.location,
|
|
|
|
'website': self.website,
|
|
|
|
'subscription_count': self.subscription_count,
|
|
|
|
'shared_stories_count': self.shared_stories_count,
|
|
|
|
'following_count': self.following_count,
|
|
|
|
'follower_count': self.follower_count,
|
|
|
|
}
|
|
|
|
if full:
|
|
|
|
params['photo_service'] = self.photo_service
|
|
|
|
params['following_user_ids'] = self.following_user_ids
|
|
|
|
params['follower_user_ids'] = self.follower_user_ids
|
|
|
|
params['unfollowed_user_ids'] = self.unfollowed_user_ids
|
|
|
|
return params
|
|
|
|
|
|
|
|
def update_user(self, skip_save=False):
|
|
|
|
user = User.objects.get(pk=self.user_id)
|
|
|
|
self.username = user.username
|
|
|
|
self.email = user.email
|
|
|
|
if not skip_save:
|
|
|
|
self.save()
|
|
|
|
|
|
|
|
def count(self, skip_save=False):
|
|
|
|
self.subscription_count = UserSubscription.objects.filter(user__pk=self.user_id).count()
|
|
|
|
self.shared_stories_count = MSharedStory.objects.filter(user_id=self.user_id).count()
|
|
|
|
self.following_count = len(self.following_user_ids)
|
|
|
|
self.follower_count = len(self.follower_user_ids)
|
|
|
|
if not skip_save:
|
|
|
|
self.save()
|
|
|
|
|
|
|
|
def follow_user(self, user_id, check_unfollowed=False):
|
|
|
|
if check_unfollowed and user_id in self.unfollowed_user_ids:
|
|
|
|
return
|
|
|
|
|
|
|
|
if user_id not in self.following_user_ids:
|
|
|
|
self.following_user_ids.append(user_id)
|
|
|
|
if user_id in self.unfollowed_user_ids:
|
|
|
|
self.unfollowed_user_ids.remove(user_id)
|
|
|
|
self.save()
|
|
|
|
|
|
|
|
followee, _ = MSocialProfile.objects.get_or_create(user_id=user_id)
|
|
|
|
if self.user_id not in followee.follower_user_ids:
|
|
|
|
followee.follower_user_ids.append(self.user_id)
|
|
|
|
followee.save()
|
|
|
|
self.count()
|
|
|
|
|
|
|
|
def unfollow_user(self, user_id):
|
|
|
|
if user_id in self.following_user_ids:
|
|
|
|
self.following_user_ids.remove(user_id)
|
|
|
|
if user_id not in self.unfollowed_user_ids:
|
|
|
|
self.unfollowed_user_ids.append(user_id)
|
|
|
|
self.save()
|
|
|
|
|
|
|
|
followee = MSocialProfile.objects.get(user_id=user_id)
|
|
|
|
if self.user_id in followee.follower_user_ids:
|
|
|
|
followee.follower_user_ids.remove(self.user_id)
|
|
|
|
followee.save()
|
|
|
|
self.count()
|
|
|
|
|
|
|
|
|
2011-12-20 11:49:49 -08:00
|
|
|
class MSocialServices(mongo.Document):
|
|
|
|
user_id = mongo.IntField()
|
2011-12-22 13:36:03 -08:00
|
|
|
autofollow = mongo.BooleanField(default=True)
|
2011-12-20 11:49:49 -08:00
|
|
|
twitter_uid = mongo.StringField()
|
|
|
|
twitter_access_key = mongo.StringField()
|
|
|
|
twitter_access_secret = mongo.StringField()
|
|
|
|
twitter_friend_ids = mongo.ListField(mongo.StringField())
|
|
|
|
twitter_picture_url = mongo.StringField()
|
|
|
|
twitter_username = mongo.StringField()
|
|
|
|
twitter_refresh_date = mongo.DateTimeField()
|
|
|
|
facebook_uid = mongo.StringField()
|
|
|
|
facebook_access_token = mongo.StringField()
|
|
|
|
facebook_friend_ids = mongo.ListField(mongo.StringField())
|
|
|
|
facebook_picture_url = mongo.StringField()
|
|
|
|
facebook_refresh_date = mongo.DateTimeField()
|
2011-12-24 00:30:37 -08:00
|
|
|
upload_picture_url = mongo.StringField()
|
2011-12-20 11:49:49 -08:00
|
|
|
|
|
|
|
meta = {
|
|
|
|
'collection': 'social_services',
|
|
|
|
'indexes': ['user_id', 'twitter_friend_ids', 'facebook_friend_ids', 'twitter_uid', 'facebook_uid'],
|
|
|
|
'allow_inheritance': False,
|
|
|
|
}
|
2011-12-25 20:50:59 -08:00
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
return "%s" % self.user_id
|
2011-12-22 13:36:03 -08:00
|
|
|
|
|
|
|
def to_json(self):
|
|
|
|
user = User.objects.get(pk=self.user_id)
|
|
|
|
return {
|
2011-12-25 12:27:05 -08:00
|
|
|
'twitter': {
|
|
|
|
'twitter_username': self.twitter_username,
|
|
|
|
'twitter_picture_url': self.twitter_picture_url,
|
|
|
|
'twitter_uid': self.twitter_uid,
|
|
|
|
},
|
|
|
|
'facebook': {
|
|
|
|
'facebook_uid': self.facebook_uid,
|
|
|
|
'facebook_picture_url': self.facebook_picture_url,
|
|
|
|
},
|
|
|
|
'gravatar': {
|
|
|
|
'gravatar_picture_url': "http://www.gravatar.com/avatar/" + \
|
|
|
|
hashlib.md5(user.email).hexdigest()
|
|
|
|
},
|
|
|
|
'upload': {
|
|
|
|
'upload_picture_url': self.upload_picture_url
|
2011-12-22 13:36:03 -08:00
|
|
|
}
|
|
|
|
}
|
2011-12-20 11:49:49 -08:00
|
|
|
|
2011-12-21 09:43:17 -08:00
|
|
|
def twitter_api(self):
|
|
|
|
twitter_consumer_key = settings.TWITTER_CONSUMER_KEY
|
|
|
|
twitter_consumer_secret = settings.TWITTER_CONSUMER_SECRET
|
|
|
|
auth = tweepy.OAuthHandler(twitter_consumer_key, twitter_consumer_secret)
|
|
|
|
auth.set_access_token(self.twitter_access_key, self.twitter_access_secret)
|
|
|
|
api = tweepy.API(auth)
|
|
|
|
return api
|
|
|
|
|
|
|
|
def facebook_api(self):
|
2011-12-20 11:49:49 -08:00
|
|
|
graph = facebook.GraphAPI(self.facebook_access_token)
|
2011-12-21 09:43:17 -08:00
|
|
|
return graph
|
|
|
|
|
|
|
|
def sync_twitter_friends(self):
|
|
|
|
api = self.twitter_api()
|
|
|
|
if not api:
|
|
|
|
return
|
|
|
|
|
|
|
|
friend_ids = list(unicode(friend.id) for friend in tweepy.Cursor(api.friends).items())
|
|
|
|
if not friend_ids:
|
|
|
|
return
|
|
|
|
|
|
|
|
twitter_user = api.me()
|
|
|
|
self.twitter_picture_url = twitter_user.profile_image_url
|
|
|
|
self.twitter_username = twitter_user.screen_name
|
|
|
|
self.twitter_friend_ids = friend_ids
|
|
|
|
self.twitter_refreshed_date = datetime.datetime.utcnow()
|
|
|
|
self.save()
|
|
|
|
|
2011-12-25 20:50:59 -08:00
|
|
|
self.follow_twitter_friends()
|
|
|
|
|
|
|
|
profile, _ = MSocialProfile.objects.get_or_create(user_id=self.user_id)
|
|
|
|
profile.location = profile.location or twitter_user.location
|
|
|
|
profile.bio = profile.bio or twitter_user.description
|
|
|
|
profile.website = profile.website or twitter_user.url
|
|
|
|
profile.save()
|
2011-12-27 21:38:32 -08:00
|
|
|
profile.count()
|
2011-12-25 20:50:59 -08:00
|
|
|
if not profile.photo_url or not profile.photo_service:
|
|
|
|
self.set_photo('twitter')
|
|
|
|
|
2011-12-21 09:43:17 -08:00
|
|
|
def sync_facebook_friends(self):
|
|
|
|
graph = self.facebook_api()
|
2011-12-20 11:49:49 -08:00
|
|
|
if not graph:
|
|
|
|
return
|
|
|
|
|
|
|
|
friends = graph.get_connections("me", "friends")
|
|
|
|
if not friends:
|
|
|
|
return
|
|
|
|
|
2011-12-21 09:43:17 -08:00
|
|
|
facebook_friend_ids = [unicode(friend["id"]) for friend in friends["data"]]
|
2011-12-20 11:49:49 -08:00
|
|
|
self.facebook_friend_ids = facebook_friend_ids
|
2011-12-21 09:43:17 -08:00
|
|
|
self.facebook_refresh_date = datetime.datetime.utcnow()
|
2011-12-22 13:36:03 -08:00
|
|
|
self.facebook_picture_url = "//graph.facebook.com/%s/picture" % self.facebook_uid
|
|
|
|
self.save()
|
2011-12-24 00:30:37 -08:00
|
|
|
|
|
|
|
self.follow_facebook_friends()
|
|
|
|
|
2011-12-25 20:50:59 -08:00
|
|
|
facebook_user = graph.request('me', args={'fields':'website,bio,location'})
|
|
|
|
profile, _ = MSocialProfile.objects.get_or_create(user_id=self.user_id)
|
|
|
|
profile.location = profile.location or (facebook_user.get('location') and facebook_user['location']['name'])
|
|
|
|
profile.bio = profile.bio or facebook_user.get('bio')
|
|
|
|
profile.website = profile.website or facebook_user.get('website')
|
|
|
|
profile.save()
|
2011-12-27 21:38:32 -08:00
|
|
|
profile.count()
|
2011-12-25 20:50:59 -08:00
|
|
|
if not profile.photo_url or not profile.photo_service:
|
|
|
|
self.set_photo('facebook')
|
|
|
|
|
2011-12-24 00:30:37 -08:00
|
|
|
def follow_twitter_friends(self):
|
|
|
|
social_profile, _ = MSocialProfile.objects.get_or_create(user_id=self.user_id)
|
|
|
|
following = []
|
|
|
|
followers = 0
|
|
|
|
|
|
|
|
if self.autofollow:
|
|
|
|
# Follow any friends already on NewsBlur
|
|
|
|
for twitter_uid in self.twitter_friend_ids:
|
|
|
|
user_social_services = MSocialServices.objects.filter(twitter_uid=twitter_uid)
|
|
|
|
if user_social_services:
|
|
|
|
followee_user_id = user_social_services[0].user_id
|
|
|
|
social_profile.follow_user(followee_user_id)
|
|
|
|
following.append(followee_user_id)
|
|
|
|
|
|
|
|
# Follow any friends already on NewsBlur
|
|
|
|
following_users = MSocialServices.objects.filter(twitter_friend_ids__contains=self.twitter_uid)
|
|
|
|
for following_user in following_users:
|
|
|
|
if following_user.autofollow:
|
|
|
|
following_user_profile = MSocialProfile.objects.get(user_id=following_user.user_id)
|
|
|
|
following_user_profile.follow_user(self.user_id, check_unfollowed=True)
|
|
|
|
followers += 1
|
|
|
|
|
|
|
|
user = User.objects.get(pk=self.user_id)
|
|
|
|
logging.user(user, "~BB~FRTwitter import: following ~SB%s~SN with ~SB%s~SN followers" % (following, followers))
|
|
|
|
|
|
|
|
return following
|
|
|
|
|
|
|
|
def follow_facebook_friends(self):
|
|
|
|
social_profile, _ = MSocialProfile.objects.get_or_create(user_id=self.user_id)
|
|
|
|
following = []
|
|
|
|
followers = 0
|
|
|
|
|
|
|
|
if self.autofollow:
|
|
|
|
# Follow any friends already on NewsBlur
|
|
|
|
for facebook_uid in self.facebook_friend_ids:
|
|
|
|
user_social_services = MSocialServices.objects.filter(facebook_uid=facebook_uid)
|
|
|
|
if user_social_services:
|
|
|
|
followee_user_id = user_social_services[0].user_id
|
|
|
|
social_profile.follow_user(followee_user_id)
|
|
|
|
following.append(followee_user_id)
|
|
|
|
|
|
|
|
# Follow any friends already on NewsBlur
|
|
|
|
following_users = MSocialServices.objects.filter(facebook_friend_ids__contains=self.facebook_uid)
|
|
|
|
for following_user in following_users:
|
|
|
|
if following_user.autofollow:
|
|
|
|
following_user_profile = MSocialProfile.objects.get(user_id=following_user.user_id)
|
|
|
|
following_user_profile.follow_user(self.user_id, check_unfollowed=True)
|
|
|
|
followers += 1
|
|
|
|
|
|
|
|
user = User.objects.get(pk=self.user_id)
|
|
|
|
logging.user(user, "~BB~FRFacebook import: following ~SB%s~SN with ~SB%s~SN followers" % (len(following), followers))
|
|
|
|
|
|
|
|
return following
|
|
|
|
|
2011-12-22 13:36:03 -08:00
|
|
|
def disconnect_twitter(self):
|
|
|
|
self.twitter_uid = None
|
|
|
|
self.save()
|
|
|
|
|
|
|
|
def disconnect_facebook(self):
|
|
|
|
self.facebook_uid = None
|
2011-12-21 09:43:17 -08:00
|
|
|
self.save()
|
2011-12-25 20:50:59 -08:00
|
|
|
|
|
|
|
def set_photo(self, service):
|
|
|
|
profile = MSocialProfile.objects.get(user_id=self.user_id)
|
|
|
|
profile.photo_service = service
|
|
|
|
if service == 'twitter':
|
|
|
|
profile.photo_url = self.twitter_picture_url
|
|
|
|
elif service == 'facebook':
|
|
|
|
profile.photo_url = self.facebook_picture_url
|
|
|
|
elif service == 'upload':
|
|
|
|
profile.photo_url = self.upload_picture_url
|
|
|
|
elif service == 'gravatar':
|
|
|
|
user = User.objects.get(pk=self.user_id)
|
|
|
|
profile.photo_url = "http://www.gravatar.com/avatar/" + \
|
|
|
|
hashlib.md5(user.email).hexdigest()
|
|
|
|
profile.save()
|