lita-tweet 0.1.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2cae612dab3855ddc2a3b67400a8be73545a5708
4
- data.tar.gz: 6f813d3fcf0a68f4b530e72091403e4da718d047
3
+ metadata.gz: 2075bb6c559760c56f41340005b53999d1dfa134
4
+ data.tar.gz: dd51909e34b310662c31ae91b983a2937f7a2762
5
5
  SHA512:
6
- metadata.gz: 7af5e3d30400abfe6a4caa4da0072cbcbf7498d57526ee18acae71f339cc810e51c9ef31c24bae6443712bfe4cec75f594d494bd7d8e8691c82c8ac00c9e3bdf
7
- data.tar.gz: ba01ba95692904af032fcba3faaea7517aa1e2b24056c179ef4e06c747d3da7139ad2cfa21df1452470ec793480f1a776f1a20c218bbc40ee58424af85fa7063
6
+ metadata.gz: 838bd08b7db776304826b8211349c8d983c318fd95a5eb2e776b1fa096669c3481a0a6dd97cc6cb6da4ed37814c342b1e1802705c95365156b8e4aee432e227b
7
+ data.tar.gz: 87353ed0740d0b6673e24c2535b36e32608a16a4a6e5c084c24e4db00eb7e889e3c7a7e9f2a861a277f288d78506342ca8c6fa537f4a01cd4a07c662b3c98c80
@@ -0,0 +1,5 @@
1
+ class KeywordStruct < Struct
2
+ def initialize(**kwargs)
3
+ super(*members.map{|k| kwargs[k] })
4
+ end
5
+ end
@@ -1,7 +1,115 @@
1
+ require_relative "./tweet/data"
2
+
1
3
  module Lita
2
4
  module Handlers
3
5
  class Tweet < Handler
4
-
6
+ config :consumer_key, type: String
7
+ config :consumer_secret, type: String
8
+ config :http_url
9
+
10
+ route %r{^tweet\s(.+)}, :tweet, command: true, restrict_to: :tweeters,
11
+ help: {"tweet MESSAGE" => "Post a tweet."}
12
+ route %r{^untweet}, :untweet, command: true, restrict_to: :tweeters,
13
+ help: {"untweet" => "Delete the last tweet."}
14
+ route %r{^twitter accounts}, :accounts, command: true,
15
+ restrict_to: :tweeters, help: {
16
+ "twitter accounts" => "List accounts that can be tweeted from.",
17
+ "twitter accounts add" => "Authorize a new account for tweeting.",
18
+ "twitter accounts remove NAME" => "Remove the twitter account NAME"
19
+ }
20
+ # route %r{^twitter channels\s(.+?)\s(.+)}, :channels, command: true, help: {
21
+ # "twitter channels" => "List account to channel mappings.",
22
+ # "twitter channels NAME CHANNEL" => "Tweet as twitter account NAME when told to tweet in channel CHANNEL."
23
+ # }
24
+
25
+ TWITTER_AUTH_URL = "/twitter/auth"
26
+ TWITTER_AUTH_CALLBACK_URL = "/twitter/callback"
27
+ http.get TWITTER_AUTH_URL, :twitter_auth
28
+ http.get TWITTER_AUTH_CALLBACK_URL, :twitter_auth_callback
29
+
30
+ def tweet(response)
31
+ text = response.match_data[1]
32
+ if text.nil? || text.empty?
33
+ return response.reply("I need something to tweet!")
34
+ end
35
+
36
+ account = account_for(response)
37
+ return response.relpy(no_accounts) if account.nil?
38
+
39
+ tweet = account.tweet(text)
40
+ twitter_data.set_last_tweet(account.username, tweet.id)
41
+ response.reply(tweet.url)
42
+ end
43
+
44
+ def untweet(response)
45
+ account = account_for(response)
46
+ return response.relpy(no_accounts) if account.nil?
47
+
48
+ if account.untweet
49
+ response.reply("Removed last tweet.")
50
+ else
51
+ response.reply("Couldn't find a last tweet to remove!")
52
+ end
53
+ end
54
+
55
+ def accounts(response)
56
+ case response.args[1]
57
+ when "add"
58
+ response.reply(add_account)
59
+ when "remove"
60
+ response.reply(remove_account(response.args[2]))
61
+ else
62
+ response.reply(list_accounts)
63
+ end
64
+ end
65
+
66
+ # def channels(response)
67
+ # # do channel stuff here
68
+ # end
69
+
70
+ def twitter_auth(request, response)
71
+ callback_url = TWITTER_AUTH_CALLBACK_URL
72
+ request_token = twitter_data.create_request_token(callback_url)
73
+ response.status = 302
74
+ response.headers["Location"] = request_token.authorize_url
75
+ end
76
+
77
+ def twitter_auth_callback(request, response)
78
+ token = request.params["oauth_token"]
79
+ verifier = request.params["oauth_verifier"]
80
+ account = twitter_data.authorize_account(token, verifier)
81
+ response.body << "Done! You can now tweet from @#{account.username}."
82
+ end
83
+
84
+ private
85
+
86
+ def list_accounts
87
+ names = twitter_data.usernames
88
+
89
+ if names.empty?
90
+ "No authorized accounts. Use `twitter accounts add` to add one."
91
+ else
92
+ usernames = names.map{|n| " - @#{n}" }.join("\n")
93
+ "Authorized Twitter accounts:\n" << usernames
94
+ end
95
+ end
96
+
97
+ def add_account
98
+ auth_uri = twitter_data.bot_uri(TWITTER_AUTH_URL)
99
+ "Authorize your account for tweeting here:\n#{auth_uri}"
100
+ end
101
+
102
+ def remove_account(name)
103
+ twitter_data.remove_account(name)
104
+ "Removed @#{name}."
105
+ end
106
+ def account_for(response)
107
+ twitter_data.account(twitter_data.usernames.first)
108
+ end
109
+
110
+ def twitter_data
111
+ @twitter_data ||= Data.new(redis, config, robot)
112
+ end
5
113
 
6
114
  Lita.register_handler(self)
7
115
  end
@@ -0,0 +1,34 @@
1
+ require "twitter"
2
+ require "keyword_struct"
3
+
4
+ module Lita
5
+ module Handlers
6
+ class Tweet < Handler
7
+
8
+ Account = KeywordStruct.new(:username, :token, :secret, :config, :last_tweet) do
9
+ def username
10
+ @username ||= client.user.screen_name
11
+ end
12
+
13
+ def tweet(text)
14
+ client.update(text)
15
+ end
16
+
17
+ def untweet
18
+ last_tweet ? client.destroy_status(last_tweet) : false
19
+ end
20
+
21
+ private
22
+
23
+ def client
24
+ @client ||= ::Twitter::REST::Client.new do |c|
25
+ c.consumer_key = config.consumer_key
26
+ c.consumer_secret = config.consumer_secret
27
+ c.access_token = token
28
+ c.access_token_secret = secret
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,94 @@
1
+ require "oauth"
2
+ require_relative "./account"
3
+
4
+ module Lita
5
+ module Handlers
6
+ class Tweet < Handler
7
+ Data = Struct.new(:redis, :config, :robot) do
8
+ def usernames
9
+ redis.smembers("twitter_accounts")
10
+ end
11
+
12
+ def account(username)
13
+ hash = redis.hgetall("twitter_accounts:#{username}")
14
+ data = hash.each_with_object({}){|(k,v),h| h[k.to_sym] = v }
15
+ Account.new(**data.merge(config: config))
16
+ end
17
+
18
+ def add_account(token, secret)
19
+ account = Account.new(token: token, secret: secret, config: config)
20
+ username = account.username
21
+
22
+ redis.sadd("twitter_accounts", username)
23
+ redis.hmset("twitter_accounts:#{username}",
24
+ "username", username,
25
+ "token", token,
26
+ "secret", secret
27
+ )
28
+
29
+ account
30
+ end
31
+
32
+ def remove_account(username)
33
+ redis.del("twitter_accounts:#{username}")
34
+ redis.srem("twitter_accounts", username)
35
+ end
36
+
37
+ def set_last_tweet(username, tweet_id)
38
+ redis.hset("twitter_accounts:#{username}", "last_tweet", tweet_id)
39
+ end
40
+
41
+ def get_last_tweet(username)
42
+ redis.hget("twitter_accounts:#{username}", "last_tweet")
43
+ end
44
+
45
+ def create_request_token(callback_path)
46
+ request_token = consumer.get_request_token(
47
+ oauth_callback: bot_uri(callback_path).to_s)
48
+ request_hash = request_token.params
49
+
50
+ key = "request_token:#{request_hash[:oauth_token]}"
51
+ redis.hmset(key, *request_hash.to_a.flatten)
52
+ redis.expire(key, 120)
53
+
54
+ request_token
55
+ end
56
+
57
+ def authorize_account(token, verifier)
58
+ request_token = find_request_token(token)
59
+ access_token = request_token.get_access_token(oauth_verifier: verifier)
60
+ add_account(access_token.token, access_token.secret)
61
+ end
62
+
63
+ def bot_uri(path = "")
64
+ base_uri + path
65
+ end
66
+
67
+ private
68
+
69
+ def find_request_token(oauth_token)
70
+ params = redis.hgetall("request_token:#{oauth_token}")
71
+ params.keys.each{|k| params[k.to_sym] = params[k] }
72
+ OAuth::RequestToken.from_hash(consumer, params)
73
+ end
74
+
75
+ def base_uri
76
+ @base_url ||= begin
77
+ http = robot.config.http
78
+ URI(config.http_url || "http://#{http.host}:#{http.port}")
79
+ end
80
+ end
81
+
82
+ def consumer
83
+ @consumer ||= OAuth::Consumer.new(
84
+ config.consumer_key,
85
+ config.consumer_secret,
86
+ :site => 'https://api.twitter.com',
87
+ :authorize_path => '/oauth/authenticate',
88
+ :sign_in => true
89
+ )
90
+ end
91
+ end
92
+ end
93
+ end
94
+ end
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "lita-tweet"
3
- spec.version = "0.1.0"
3
+ spec.version = "0.3.0"
4
4
  spec.authors = ["Andre Arko"]
5
5
  spec.email = ["andre@arko.net"]
6
6
  spec.description = "Tweeting for Lita"
@@ -15,8 +15,10 @@ Gem::Specification.new do |spec|
15
15
  spec.require_paths = ["lib"]
16
16
 
17
17
  spec.add_runtime_dependency "lita", ">= 4.7"
18
+ spec.add_runtime_dependency "twitter", "~> 5.16"
19
+ spec.add_runtime_dependency "oauth", "~> 0.5.1"
18
20
 
19
- spec.add_development_dependency "bundler", "~> 1.3"
21
+ spec.add_development_dependency "bundler", "~> 1.12"
20
22
  spec.add_development_dependency "pry-byebug"
21
23
  spec.add_development_dependency "rake"
22
24
  spec.add_development_dependency "rack-test"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lita-tweet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andre Arko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-03 00:00:00.000000000 Z
11
+ date: 2016-08-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: lita
@@ -24,20 +24,48 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '4.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: twitter
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '5.16'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '5.16'
41
+ - !ruby/object:Gem::Dependency
42
+ name: oauth
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 0.5.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 0.5.1
27
55
  - !ruby/object:Gem::Dependency
28
56
  name: bundler
29
57
  requirement: !ruby/object:Gem::Requirement
30
58
  requirements:
31
59
  - - "~>"
32
60
  - !ruby/object:Gem::Version
33
- version: '1.3'
61
+ version: '1.12'
34
62
  type: :development
35
63
  prerelease: false
36
64
  version_requirements: !ruby/object:Gem::Requirement
37
65
  requirements:
38
66
  - - "~>"
39
67
  - !ruby/object:Gem::Version
40
- version: '1.3'
68
+ version: '1.12'
41
69
  - !ruby/object:Gem::Dependency
42
70
  name: pry-byebug
43
71
  requirement: !ruby/object:Gem::Requirement
@@ -135,8 +163,11 @@ files:
135
163
  - LICENSE
136
164
  - README.md
137
165
  - Rakefile
166
+ - lib/keyword_struct.rb
138
167
  - lib/lita-tweet.rb
139
168
  - lib/lita/handlers/tweet.rb
169
+ - lib/lita/handlers/tweet/account.rb
170
+ - lib/lita/handlers/tweet/data.rb
140
171
  - lita-tweet.gemspec
141
172
  - locales/en.yml
142
173
  - spec/lita/handlers/tweet_spec.rb