-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added reply by tweet feature #3175
Changes from all commits
6521d27
c255060
9c4a9d5
192db25
d835e93
e5415f2
20f02d9
4be39a4
245c4be
f65eb9a
09582ed
55af02e
b960952
f5a680d
712d7f2
3ceb0c2
73ba28c
73df811
0a4ab12
9e88993
8073289
974d62a
6a2a036
0d80b03
4d7fa41
4056f4a
c973443
f4d07f3
8f1b4a3
c3a68ef
9cd5cbb
b817e2c
a57097d
6eeb4bc
9dba8ae
093d503
1136184
9278621
7af11b5
5ea493c
74894b6
3d07ec2
b4a7557
f4d965c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -344,6 +344,102 @@ def trimmed_content? | |
comment.include?(COMMENT_FILTER) | ||
end | ||
|
||
def self.receive_tweet | ||
comments = Comment.where.not(tweet_id: nil) | ||
if comments.any? | ||
receive_tweet_using_since comments | ||
else | ||
receive_tweet_without_using_since | ||
end | ||
end | ||
|
||
def self.receive_tweet_using_since(comments) | ||
comment = comments.last | ||
since_id = comment.tweet_id | ||
tweets = Client.search(ENV["TWEET_SEARCH"], since_id: since_id).collect do |tweet| | ||
tweet | ||
end | ||
tweets.each do |tweet| | ||
puts tweet.text | ||
end | ||
tweets = tweets.reverse | ||
check_and_add_tweets tweets | ||
end | ||
|
||
def self.receive_tweet_without_using_since | ||
tweets = Client.search(ENV["TWEET_SEARCH"]).collect do |tweet| | ||
tweet | ||
end | ||
tweets = tweets.reverse | ||
check_and_add_tweets tweets | ||
tweets.each do |tweet| | ||
puts tweet.text | ||
end | ||
end | ||
|
||
def self.check_and_add_tweets(tweets) | ||
tweets.each do |tweet| | ||
if tweet.reply? | ||
in_reply_to_tweet_id = tweet.in_reply_to_tweet_id | ||
if in_reply_to_tweet_id.class == Fixnum | ||
parent_tweet = Client.status(in_reply_to_tweet_id, tweet_mode: "extended") | ||
parent_tweet_full_text = parent_tweet.attrs[:text] || parent_tweet.attrs[:full_text] | ||
urls = URI.extract(parent_tweet_full_text) | ||
node = get_node_from_urls_present(urls) | ||
unless node.nil? | ||
twitter_user_name = tweet.user.screen_name | ||
tweet_email = find_email(twitter_user_name) | ||
users = User.where(email: tweet_email) | ||
if users.any? | ||
user = users.first | ||
replied_tweet_text = tweet.text | ||
if tweet.truncated? | ||
replied_tweet = Client.status(tweet.id, tweet_mode: "extended") | ||
replied_tweet_text = replied_tweet.attrs[:text] || replied_tweet.attrs[:full_text] | ||
end | ||
replied_tweet_text = replied_tweet_text.gsub(/@(\S+)/){|m| "[#{m}](https://twitter.com/#{m})"} | ||
replied_tweet_text = replied_tweet_text.gsub('@','') | ||
comment = node.add_comment(uid: user.uid, body: replied_tweet_text, comment_via: 2, tweet_id: tweet.id) | ||
comment.notify user | ||
end | ||
end | ||
end | ||
end | ||
end | ||
end | ||
|
||
def self.get_node_from_urls_present(urls) | ||
urls.each do |url| | ||
if url.include? "https://" | ||
if url.last == "." | ||
url = url[0...url.length-1] | ||
end | ||
response = Net::HTTP.get_response(URI(url)) | ||
redirected_url = response['location'] | ||
if redirected_url != nil && redirected_url.include?(ENV["WEBSITE_HOST_PATTERN"]) | ||
node_id = redirected_url.split("/")[-1] | ||
if !node_id.nil? | ||
node = Node.where(nid: node_id.to_i) | ||
if node.any? | ||
return node.first | ||
end | ||
end | ||
end | ||
end | ||
|
||
end | ||
return nil | ||
end | ||
|
||
def self.find_email(twitter_user_name) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, this seems like it could start to push the performance of the system. Are we finding the email address of the twitter user here, and what do we use it for? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Meaning fetching all user tags each time -- can we query any other way? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could narrow with: UserTag.where.not(data: nil) But i bet we could do even better... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
shows 145 records currently There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Apart from this, I think we'll eventually have to figure a way to look up by twitter handle, and to do it more efficiently. The email may not even be the same one, you know? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @namangupta01 would you mind opening a new issue for the optimization, and another to try to see if we can look up twitter users by a different system? Thank you!! And congrats on getting this merged! 🎉 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Like, maybe we need to store a new column in UserTag that is the user's twitter handle, maybe There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And, it'll bypass the issue of the emails not matching. My email is not the same between Twitter and PL.org, actually! |
||
UserTag.all.each do |user_tag| | ||
data = user_tag["data"] | ||
if data != nil && data["info"] != nil && data["info"]["nickname"] != nil && data["info"]["nickname"].to_s == twitter_user_name | ||
return data["info"]["email"] | ||
end | ||
end | ||
end | ||
|
||
def parse_quoted_text | ||
if regex_match = body.match(/(.+)(On .+<.+@.+> wrote:)(.+)/m) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
require 'twitter' | ||
::Client = Twitter::REST::Client.new do |config| | ||
config.consumer_key = ENV["TWITTER_CONSUMER_KEY"] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, so do we need new keys for these and where should I look for them? Does it need to be the @publiclab twitter or could it be another? Thanks, just checking!! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It can be of any account... |
||
config.consumer_secret = ENV["TWITTER_CONSUMER_SECRET"] | ||
config.access_token = ENV["TWITTER_ACCESS_TOKEN"] | ||
config.access_token_secret = ENV["TWITTER_ACCESS_TOKEN_SECRET"] | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
class AddTweetColumnToComment < ActiveRecord::Migration[5.2] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you update the timestamp of this file? |
||
def change | ||
add_column :comments, :tweet_id, :string | ||
end | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
## Reply By Tweet | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's add a couple sentences summarizing what this all does -- i.e. Can you also post links to https://apps.twitter.com/ and listing the environment variables that have to be set? Thanks! |
||
- We are using [twitter gem](https://github.com/sferik/twitter "twitter gem") which implements twitter apis and gives functions to easily implement twitter apis. | ||
|
||
### Steps: | ||
|
||
- Cron job for polling for getting new tweets to `publiclab` is defined in [config/schedule.rb](https://github.com/publiclab/plots2/blob/master/config/schedule.rb "config/schedule.rb") using whenever gem which will call `receive_tweet` function of [models/comment.rb](https://github.com/publiclab/plots2/blob/master/app/models/comment.rb "models/comment.rb") in the interval of one minute. | ||
|
||
- `receive_tweet` method of [models/comment.rb](https://github.com/publiclab/plots2/blob/master/app/models/comment.rb "models/comment.rb") will look for if there is any comment already present that contains tweet_id if it does it will call `receive_tweet_using_since` otherwise it will call `receive_tweet_without_using_since `. | ||
|
||
- `receive_tweet_using_since` will search for the tweets to the `publiclab` which are tweeted after that tweet with the `tweet_id` present in the database. | ||
|
||
- After that check if that tweet is the reply of some other tweet. If it does then find the parent tweet otherwise ignore this tweet and check next tweets untill tweets end. | ||
|
||
- After finding parent tweet, search for the links present in the tweets in the form of `https://publiclab.org/n/_____` and find the the node_id present in `https://publiclab.org/n/node_id` if there is any node present in the database with this node_id then search for the user's email who did the tweet using the username and email data present in the hash form in the `data` column otherwise ignore this tweet. | ||
|
||
- If that twitter username is present in the `user_tags` column then add the tweet otherwise ignore the current tweet. | ||
|
||
- Same process is with when there are no comment present with tweet_id in the comment table where we search for all the replied tweets to the `publiclab`. | ||
|
||
To use this feature we have to set some environment variables which includes Twitter Api keys and Searching Query: For getting Twitter Keys go to [Twitter app keys](https://apps.twitter.com/) | ||
Environment varible used for twitter keys are : `TWITTER_CONSUMER_KEY`, `TWITTER_CONSUMER_SECRET`, `TWITTER_ACCESS_TOKEN` and `TWITTER_ACCESS_TOKEN_SECRET`. | ||
|
||
Other Environment variable used are : `WEBSITE_HOST_PATTERN` which can be like `//publiclab.org/n/` and `TWEET_SEARCH` which is used to search for the tweets and can be like `to:publiclab`. | ||
|
||
### Summery | ||
|
||
Once a minute, this system scans tweets "to:PublicLab" (or specified search, see below) for URLs matching our shortlink pattern, i.e. "https://publiclab.org/n/_____", where "_____" is a node nid. Each of the returned tweets is added as a comment to the node it responded to. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, can we look up the user in any other way?