Last time we went over a couple updates and the MVP of Tweet For Sats going live! Today we will go over Twitter integration.

Secrets and Tokens

The ability to create tweets is one of the most important parts of this project. I’m going to need Twitter’s API to do this. So I created a Twitter account specifically for Tweets For Sats. You can find the account here. After verifying the account and filling it with the necessary information, I made my way over to developer.twitter.com. I went to the developer portal and created a new project named TweetsForSats. I made the following changes:

After generating the secrets, keys, and tokens, I copied each one into a .env file so that they can be accessed as environmental variables.

Making Tweets

To make a tweet, we will use the information generated in the last section in conjunction with Tweepy, a Twitter API module for Python. First we create a client:

import tweepy

# ...

# Twitter API authorization info
bearerToken = config.TWITTER_BEARER_TOKEN
accesstoken = config.TWITTER_ACCESS_TOKEN
apikey = config.TWITTER_API_KEY
apikeysecret = config.TWITTER_API_KEY_SECRET
accesstokensecret = config.TWITTER_ACCESS_TOKEN_SECRET

# Create Twitter API Client
client = tweepy.Client(
    bearer_token=bearerToken, 
    access_token=accesstoken, 
    access_token_secret=accesstokensecret, 
    consumer_key=apikey, 
    consumer_secret=apikeysecret
)

We want to be able to create a normal tweet, reply to a tweet, and/or quote a tweet. So we will display a form to the user asking for the body of the tweet. The form will also allow you to reply to or quote a tweet by putting the tweet’s URL into the respective fields. We will now use the client to construct and send the tweet. First we extract the tweet ids from the quote link and reply link if applicable:

# Checking if the tweet is a reply or quote tweet
  reply_url = None # Url of the tweet to reply to
  quote_url = None # Url of the tweet to quote
  try:
      reply_url = form.cleaned_data['reply_to']
      quote_url = form.cleaned_data['quote_tweet']
  except KeyError:
      pass

  reply_id = None # Id of the tweet to reply to
  quote_id = None # quoted tweet id

  # Parse reply url to extract the id of the tweet to reply to
  if reply_url != None:
      reply_id = reply_url.split("/").pop().split("?")[0]
  # Parse quote tweet rul to extract quoted tweet id
  if quote_url != None:
      quote_id = quote_url.split("/").pop().split("?")[0]

Now we will create the tweet using the client. There are four cases for the new tweet:

  1. No reply or quote
  2. Only a reply
  3. Only a quote
  4. Reply and Quote

If tweet creation is unsuccessful, we will refund the stake of the tweet.

try:
  # Send tweet
  if reply_id and quote_id: # reply and quote
      response = client.create_tweet(text=form.cleaned_data['text'], in_reply_to_tweet_id=reply_id, quote_tweet_id=quote_id, user_auth=True)
  elif reply_id: # reply
      response = client.create_tweet(text=form.cleaned_data['text'], in_reply_to_tweet_id=reply_id, user_auth=True)
  elif quote_id: # quote
      response = client.create_tweet(text=form.cleaned_data['text'], quote_tweet_id=quote_id, user_auth=True)
  else: # tweet normally
      response = client.create_tweet(text=form.cleaned_data['text'], user_auth=True)
except: # If unsuccessful, refund stake
  balance = Balances.objects.get_or_create(key=key)[0]
  balance.available = balance.available + new_tweet.stake
  balance.save()
  return redirect('main:index')