lita-tweet 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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