Skip to content

Commit

Permalink
Backend changes to allow users to favourite and retweet from within S…
Browse files Browse the repository at this point in the history
…cremsong

#40
  • Loading branch information
keithamoss committed Dec 30, 2018
1 parent e5ad415 commit 1106789
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 1 deletion.
9 changes: 9 additions & 0 deletions django/scremsong/app/consumers.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,15 @@ def tweets_set_state(self, event):
"tweetState": event["tweetState"],
})

def tweets_update_tweets(self, event):
"""
Called when something has changed the state of a tweet (e.g. favourited it).
"""
self.send_json({
"msg_type": settings.MSG_TYPE_TWEETS_UPDATE_TWEETS,
"tweets": event["tweets"],
})

def user_change_settings(self, event):
"""
Called when we receive new tweets from the Twitter stream, from backfilling, et cetera.
Expand Down
1 change: 1 addition & 0 deletions django/scremsong/app/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class TweetSource(str, EnumBase):
STREAMING = "Streaming"
BACKFILL = "Backfill"
THREAD_RESOLUTION = "Thread Resolution"
RETWEETING = "Retweeting"
# THREAD_RESOLUTION_TWEETS_TO_USER = "Thread Resolution To User"
# THREAD_RESOLUTION_TWEETS_FROM_USER = "Thread Resolution From User"
TESTING = "Testing"
148 changes: 148 additions & 0 deletions django/scremsong/app/twitter.py
Original file line number Diff line number Diff line change
Expand Up @@ -531,3 +531,151 @@ def process_new_tweet(status, tweetSource, sendWebSocketEvent):

logger.error("Failed to process new tweet {}".format(status["id_str"]))
return False

def favourite_tweet(tweetId):
def ws_send_updated_tweet(tweet):
websockets.send_channel_message("tweets.update_tweets", {
"tweets": {tweet.tweet_id: TweetsSerializer(tweet).data},
})

tweet = Tweets.objects.get(tweet_id=tweetId)

# The client shouldn't be able to favourite a tweet we've already favourited.
# Fail quietly and send out new state to all connected clients.
if tweet.data["favorited"] is True:
ws_send_updated_tweet(tweet)
return

try:
api = get_tweepy_api_auth()
status = api.create_favorite(tweetId, include_entities=True)

tweet.data = status._json
tweet.save()

ws_send_updated_tweet(tweet)

except tweepy.TweepError as e:
if e.api_code == 139:
# The tweet was already favourited somewhere else (e.g. another Twitter client). Update local state tweet and respond as if we succeeded.
tweet.data["favorited"] = True
tweet.save()

ws_send_updated_tweet(tweet)
else:
# Uh oh, some other error code was returned
# NB: tweepy.api can return certain errors via retry_errors
raise e

def unfavourite_tweet(tweetId):
def ws_send_updated_tweet(tweet):
websockets.send_channel_message("tweets.update_tweets", {
"tweets": {tweet.tweet_id: TweetsSerializer(tweet).data},
})

tweet = Tweets.objects.get(tweet_id=tweetId)

# The client shouldn't be able to favourite a tweet we've already favourited.
# Fail quietly and send out new state to all connected clients.
if tweet.data["favorited"] is False:
ws_send_updated_tweet(tweet)
return

try:
api = get_tweepy_api_auth()
status = api.destroy_favorite(tweetId, include_entities=True)

tweet.data = status._json
tweet.save()

ws_send_updated_tweet(tweet)

except tweepy.TweepError as e:
if e.api_code == 144:
# The tweet was already unfavourited somewhere else (e.g. another Twitter client). Update local state tweet and respond as if we succeeded.
# NB: No idea why they use 144 as the response code. 144 is supposed to be "No status found with that ID"
tweet.data["favorited"] = False
tweet.save()

ws_send_updated_tweet(tweet)
else:
# Uh oh, some other error code was returned
# NB: tweepy.api can return certain errors via retry_errors
raise e

def retweet_tweet(tweetId):
def ws_send_updated_tweet(tweet):
websockets.send_channel_message("tweets.update_tweets", {
"tweets": {tweet.tweet_id: TweetsSerializer(tweet).data},
})

tweet = Tweets.objects.get(tweet_id=tweetId)

# The client shouldn't be able to retweet a tweet they've already retweeted.
# Fail quietly and send out new state to all connected clients.
if tweet.data["retweeted"] is True:
ws_send_updated_tweet(tweet)
return

try:
api = get_tweepy_api_auth()
status = api.retweet(tweetId)

tweet.data = status._json["retweeted_status"]
tweet.save()

retweet, created = save_tweet(status._json, source=TweetSource.RETWEETING, status=TweetStatus.OK)

websockets.send_channel_message("tweets.update_tweets", {
"tweets": {tweet.tweet_id: TweetsSerializer(tweet).data, retweet.tweet_id: TweetsSerializer(retweet).data},
})

except tweepy.TweepError as e:
if e.api_code == 327:
# The tweet was already retweeted somewhere else (e.g. another Twitter client). Update local state tweet and respond as if we succeeded.
tweet.data["retweeted"] = True
tweet.save()

ws_send_updated_tweet(tweet)
else:
# Uh oh, some other error code was returned
# NB: tweepy.api can return certain errors via retry_errors
raise e


def unretweet_tweet(tweetId):
def ws_send_updated_tweet(tweet):
websockets.send_channel_message("tweets.update_tweets", {
"tweets": {tweet.tweet_id: TweetsSerializer(tweet).data},
})

tweet = Tweets.objects.get(tweet_id=tweetId)

# The client shouldn't be able to retweet a tweet they've already retweeted.
# Fail quietly and send out new state to all connected clients.
if tweet.data["retweeted"] is False:
ws_send_updated_tweet(tweet)
return

try:
api = get_tweepy_api_auth()
status = api.unretweet(tweetId)

tweet.data = status._json
tweet.save()

ws_send_updated_tweet(tweet)

except tweepy.TweepError as e:
raise e

if e.api_code == 327:
# The tweet was already retweeted somewhere else (e.g. another Twitter client). Update local state tweet and respond as if we succeeded.
tweet.data["retweeted"] = False
tweet.save()

ws_send_updated_tweet(tweet)
else:
# Uh oh, some other error code was returned
# NB: tweepy.api can return certain errors via retry_errors
raise e
38 changes: 37 additions & 1 deletion django/scremsong/app/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from tweepy import TweepError
from scremsong.app.serializers import UserSerializer, SocialAssignmentSerializer
from scremsong.app.twitter import twitter_user_api_auth_stage_1, twitter_user_api_auth_stage_2, fetch_tweets, get_status_from_db, resolve_tweet_parents, resolve_tweet_thread_for_parent, notify_of_saved_tweet
from scremsong.app.twitter import get_tweepy_api_auth, twitter_user_api_auth_stage_1, twitter_user_api_auth_stage_2, fetch_tweets, get_status_from_db, resolve_tweet_parents, resolve_tweet_thread_for_parent, notify_of_saved_tweet, favourite_tweet, unfavourite_tweet, retweet_tweet, unretweet_tweet
from scremsong.celery import celery_restart_streaming
from scremsong.app.models import Tweets, SocialAssignments, Profile
from scremsong.app.enums import SocialPlatformChoice, SocialAssignmentStatus, NotificationVariants, TweetState, TweetStatus
Expand Down Expand Up @@ -129,6 +129,42 @@ def set_state(self, request, format=None):

return Response({})

@list_route(methods=['get'])
def favourite(self, request, format=None):
qp = request.query_params
tweetId = qp["tweetId"] if "tweetId" in qp else None

favourite_tweet(tweetId)

return Response({})

@list_route(methods=['get'])
def unfavourite(self, request, format=None):
qp = request.query_params
tweetId = qp["tweetId"] if "tweetId" in qp else None

unfavourite_tweet(tweetId)

return Response({})

@list_route(methods=['get'])
def retweet(self, request, format=None):
qp = request.query_params
tweetId = qp["tweetId"] if "tweetId" in qp else None

retweet_tweet(tweetId)

return Response({})

@list_route(methods=['get'])
def unretweet(self, request, format=None):
qp = request.query_params
tweetId = qp["tweetId"] if "tweetId" in qp else None

unretweet_tweet(tweetId)

return Response({})


class SocialAssignmentsViewset(viewsets.ViewSet):
"""
Expand Down
1 change: 1 addition & 0 deletions django/scremsong/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@
MSG_TYPE_NOTIFICATION = "ws/scremsong/NOTIFICATION"
MSG_TYPE_TWEETS_NEW_TWEETS = "ws/scremsong/tweets/NEW_TWEETS"
MSG_TYPE_TWEETS_LOAD_TWEETS = "ws/scremsong/tweets/LOAD_TWEETS"
MSG_TYPE_TWEETS_UPDATE_TWEETS = "ws/scremsong/tweets/UPDATE_TWEETS"
MSG_TYPE_TWEETS_SET_STATE = "ws/scremsong/tweets/SET_STATE"
MSG_TYPE_SOCIAL_COLUMNS_LIST = "ws/scremsong/social_columns/LIST"
MSG_TYPE_REVIEWERS_LIST_USERS = "ws/scremsong/reviewers/LIST_USERS"
Expand Down

0 comments on commit 1106789

Please sign in to comment.