twittbot 0.0.1 → 0.1.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: 09e59460e2557a87718a9bad72b57d1b42c2a4c3
4
- data.tar.gz: 179a82d6023f5b2900d54841538e1aeb1b673564
3
+ metadata.gz: c1ccc06698d66c5f816c4021a4f629b2bb7a388f
4
+ data.tar.gz: 809da09ae7ae3724f1c14080eef51dcdefe33c3c
5
5
  SHA512:
6
- metadata.gz: ed8bedb456e2ff5d26857f0758797e20f9ece05bca381e8125381807c0b91168fb20b90263cd162cb2cb6ce0560169c234743d0e07ff38e846df1bf0aa64dc84
7
- data.tar.gz: fe77b02ea6703e0b22e8cf8004e10a05a6cae7381fca8120b29a95392cca7934ae4603ea8ab0a23e37a61162534c7da05e957d0345f307b301fb3527a134ebb7
6
+ metadata.gz: 23668bb8a4caeb9d7bae00775498ff5fe4dc3a17893b5190a105683af2931cf624d36a2e6d2c989a7a51fe071e42f673ee1dbbaa76d8a843832bf3f0f75a6775
7
+ data.tar.gz: 8a9aef2318375d165b3af9eeeebfc219664998df13e4581fb3fdf24f836dc472cd8b4b275eb38932138bbb003e6cd2cfebd1973e02d1b757575d42e68ff4d1d5
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Twittbot
1
+ # Twittbot [![Gem Version](https://badge.fury.io/rb/twittbot.svg)](http://badge.fury.io/rb/twittbot) [![Inline docs](http://inch-ci.org/github/nilsding/twittbot.svg?branch=master)](http://inch-ci.org/github/nilsding/twittbot)
2
2
 
3
3
  Twittbot is the next generation of my old Twitter bot, `twittbot-nd`.
4
4
 
@@ -19,6 +19,10 @@ Authorize with Twitter:
19
19
 
20
20
  $ twittbot auth
21
21
 
22
+ Add yourself as a botadmin:
23
+
24
+ $ twittbot add-admin nilsding
25
+
22
26
  Add a template, such as for a simple reply bot:
23
27
 
24
28
  $ twittbot generate random-reply
data/lib/twittbot/bot.rb CHANGED
@@ -18,12 +18,21 @@ module Twittbot
18
18
  }
19
19
 
20
20
  $bot = {
21
+ botparts: [],
21
22
  callbacks: {},
22
- config: YAML.load_file(File.expand_path("./#{Twittbot::CONFIG_FILE_NAME}", @options[:current_dir])),
23
+ commands: {},
24
+ config: Twittbot::DEFAULT_BOT_CONFIG.merge(
25
+ YAML.load_file(File.expand_path("./#{Twittbot::CONFIG_FILE_NAME}", @options[:current_dir]))
26
+ ),
23
27
  periodic: []
24
28
  }.merge!(options)
25
29
 
26
30
  load_bot_code
31
+
32
+ at_exit do
33
+ save_config
34
+ $bot[:botparts].each { |b| b.save_config }
35
+ end
27
36
  end
28
37
 
29
38
  # Authenticates an account with Twitter.
@@ -54,26 +63,12 @@ module Twittbot
54
63
  # get the bot's user name (screen_name) and print it to the console
55
64
  $bot[:config][:screen_name] = get_screen_name access_token
56
65
  puts "Hello, #{$bot[:config][:screen_name]}!"
57
-
58
- save_config
59
66
  end
60
67
 
61
68
  # Starts the bot.
62
69
  def start
63
70
  check_config
64
- $bot[:client] ||= Twitter::REST::Client.new do |cfg|
65
- cfg.consumer_key = $bot[:config][:consumer_key]
66
- cfg.consumer_secret = $bot[:config][:consumer_secret]
67
- cfg.access_token = $bot[:config][:access_token]
68
- cfg.access_token_secret = $bot[:config][:access_token_secret]
69
- end
70
-
71
- @streamer ||= Twitter::Streaming::Client.new do |cfg|
72
- cfg.consumer_key = $bot[:config][:consumer_key]
73
- cfg.consumer_secret = $bot[:config][:consumer_secret]
74
- cfg.access_token = $bot[:config][:access_token]
75
- cfg.access_token_secret = $bot[:config][:access_token_secret]
76
- end
71
+ init_clients
77
72
 
78
73
  @userstream_thread ||= Thread.new do
79
74
  puts "connected to user stream"
@@ -103,6 +98,23 @@ module Twittbot
103
98
  @periodic_thread.join
104
99
  end
105
100
 
101
+ # @param screen_name [String] the user's screen name
102
+ # @param action [Symbol] :add or :delete
103
+ def modify_admin(screen_name, action = :add)
104
+ init_clients
105
+ user = $bot[:client].user screen_name
106
+ case action
107
+ when :add
108
+ $bot[:config][:admins] << user.id unless $bot[:config][:admins].include? user.id
109
+ when :del, :delete
110
+ $bot[:config][:admins].delete user.id if $bot[:config][:admins].include? user.id
111
+ else
112
+ say "Unknown action " + action.to_s, :red
113
+ end
114
+ rescue Twitter::Error::NotFound
115
+ say "User not found.", :red
116
+ end
117
+
106
118
  # Loads the bot's actual code which is stored in the bot's +lib+
107
119
  # subdirectory.
108
120
  def load_bot_code
@@ -158,6 +170,8 @@ module Twittbot
158
170
  pp object
159
171
  do_callbacks object.name, object, opts
160
172
  end
173
+ when Twitter::DirectMessage
174
+ do_direct_message object, opts
161
175
  else
162
176
  puts "no handler for #{object.class.to_s}\n -- object data:"
163
177
  require 'pp'
@@ -184,6 +198,26 @@ module Twittbot
184
198
  end
185
199
  end
186
200
 
201
+ # Processes a direct message.
202
+ # @param dm [Twitter::DirectMessage] received direct message
203
+ def do_direct_message(dm, opts = {})
204
+ return if dm.sender.screen_name == $bot[:config][:screen_name]
205
+ return do_callbacks(:direct_message, dm, opts) unless dm.text.start_with? $bot[:config][:dm_command_prefix]
206
+ dm_text = dm.text.sub($bot[:config][:dm_command_prefix], '').strip
207
+ return if dm_text.empty?
208
+
209
+ return unless /(?<command>[A-Za-z0-9]+)(?:\s*)(?<args>.*)/m =~ dm_text
210
+ command = Regexp.last_match(:command).to_sym
211
+ args = Regexp.last_match :args
212
+
213
+ cmd = $bot[:commands][command]
214
+ return say_status :dm, "#{dm.sender.screen_name} tried to issue non-existent command :#{command}, ignoring", :cyan if cmd.nil?
215
+ return say_status :dm, "#{dm.sender.screen_name} tried to issue admin command :#{command}, ignoring", :cyan if cmd[:admin] and !dm.sender.admin?
216
+
217
+ say_status :dm, "#{dm.sender.screen_name} issued command :#{command}", :cyan
218
+ cmd[:block].call(args, dm.sender)
219
+ end
220
+
187
221
  # @return [Boolean] whether the bot is already authenticated or not.
188
222
  def already_authed?
189
223
  !($bot[:config][:access_token].empty? or $bot[:config][:access_token_secret].empty?)
@@ -191,6 +225,22 @@ module Twittbot
191
225
 
192
226
  private
193
227
 
228
+ def init_clients
229
+ $bot[:client] ||= Twitter::REST::Client.new do |cfg|
230
+ cfg.consumer_key = $bot[:config][:consumer_key]
231
+ cfg.consumer_secret = $bot[:config][:consumer_secret]
232
+ cfg.access_token = $bot[:config][:access_token]
233
+ cfg.access_token_secret = $bot[:config][:access_token_secret]
234
+ end
235
+
236
+ @streamer ||= Twitter::Streaming::Client.new do |cfg|
237
+ cfg.consumer_key = $bot[:config][:consumer_key]
238
+ cfg.consumer_secret = $bot[:config][:consumer_secret]
239
+ cfg.access_token = $bot[:config][:access_token]
240
+ cfg.access_token_secret = $bot[:config][:access_token_secret]
241
+ end
242
+ end
243
+
194
244
  def get_screen_name(access_token)
195
245
  oauth_response = access_token.get('/1.1/account/verify_credentials.json?skip_status=true')
196
246
  oauth_response.body.match(/"screen_name"\s*:\s*"(.*?)"/).captures.first
@@ -5,13 +5,14 @@ module Twittbot
5
5
  class BotPart
6
6
  # @param name [Symbol] The name of the botpart. Should be the same as the file name without the extension.
7
7
  def initialize(name, &block)
8
- botpart_config_path = File.expand_path("./etc/#{name}.yml")
9
- @config = $bot[:config].merge(if File.exist? botpart_config_path
10
- YAML.load_file botpart_config_path
8
+ @botpart_config_path = File.expand_path("./etc/#{name}.yml")
9
+ @config = $bot[:config].merge(if File.exist? @botpart_config_path
10
+ YAML.load_file @botpart_config_path
11
11
  else
12
12
  {}
13
13
  end)
14
14
  instance_eval &block
15
+ $bot[:botparts] << self
15
16
  end
16
17
 
17
18
  # Adds a new callback to +name+.
@@ -23,6 +24,7 @@ module Twittbot
23
24
  # * :retweet
24
25
  # * :favorite
25
26
  # * :friend_list
27
+ # * :direct_message (i.e. not command DMs, see {cmd} for that)
26
28
  def on(name, *args, &block)
27
29
  $bot[:callbacks][name] ||= {
28
30
  args: args,
@@ -66,5 +68,36 @@ module Twittbot
66
68
  $bot[:client]
67
69
  end
68
70
  alias bot client
71
+
72
+ # Defines a new direct message command.
73
+ # @param name [Symbol] The name of the command. Can only contain alphanumerical characters.
74
+ # The recommended maximum length is 4 characters.
75
+ # @param options [Hash] A customizable set of options.
76
+ # @option options [Boolean] :admin (true) Require admin status for this command.
77
+ def cmd(name, options = {}, &block)
78
+ raise "Command already exists: #{name}" if $bot[:commands].include? name
79
+ raise "Command name does not contain only alphanumerical characters" unless name.to_s.match /\A[A-Za-z0-9]+\z/
80
+
81
+ opts = {
82
+ admin: true
83
+ }.merge(options)
84
+
85
+ $bot[:commands][name] ||= {
86
+ admin: opts[:admin],
87
+ block: block
88
+ }
89
+ end
90
+
91
+ # Saves the botpart's configuration. This is automatically called when
92
+ # Twittbot exits.
93
+ def save_config
94
+ botpart_config = Hash[@config.to_a - $bot[:config].to_a]
95
+
96
+ unless botpart_config.empty?
97
+ File.open @botpart_config_path, 'w' do |f|
98
+ f.write botpart_config.to_yaml
99
+ end
100
+ end
101
+ end
69
102
  end
70
103
  end
data/lib/twittbot/cli.rb CHANGED
@@ -39,5 +39,19 @@ module Twittbot
39
39
  lister = Twittbot::TemplateLister.new options
40
40
  lister.list
41
41
  end
42
+
43
+ desc 'add-admin USER_NAME', 'Adds an user to the botadmin list'
44
+ def add_admin(user_name)
45
+ require 'twittbot/bot'
46
+ bot = Twittbot::Bot.new
47
+ bot.modify_admin(user_name, :add)
48
+ end
49
+
50
+ desc 'del-admin USER_NAME', 'Removes an user from the botadmin list'
51
+ def del_admin(user_name)
52
+ require 'twittbot/bot'
53
+ bot = Twittbot::Bot.new
54
+ bot.modify_admin(user_name, :delete)
55
+ end
42
56
  end
43
57
  end
@@ -1,6 +1,6 @@
1
1
  module Twittbot
2
2
  # The version of Twittbot.
3
- VERSION = "0.0.1"
3
+ VERSION = "0.1.0"
4
4
 
5
5
  CONSUMER_KEY = 'FYRuQcDbPAXAyVjuPZMuw' # :nodoc:
6
6
  CONSUMER_SECRET = 'KiLCYTftPdxNebl5DNcj7Ey2Y8YVZu7hfqiFRYkcg' # :nodoc:
@@ -16,6 +16,8 @@ module Twittbot
16
16
  consumer_secret: Twittbot::CONSUMER_SECRET,
17
17
  access_token: '',
18
18
  access_token_secret: '',
19
- track: []
19
+ track: [],
20
+ admins: [],
21
+ dm_command_prefix: '!'
20
22
  }
21
23
  end
@@ -1,2 +1,4 @@
1
+ require 'twittbot/gem_ext/twitter/user'
1
2
  require 'twittbot/gem_ext/twitter/tweet'
3
+ require 'twittbot/gem_ext/twitter/direct_message'
2
4
  require 'twittbot/gem_ext/twitter/rest/tweets'
@@ -0,0 +1,13 @@
1
+ module Twitter
2
+ class DirectMessage
3
+ # Replies to this direct message.
4
+ # @param direct_message_text [:String] direct message text
5
+ def reply(direct_message_text)
6
+ return if $bot.nil? or $bot[:client].nil?
7
+
8
+ $bot[:client].create_direct_message self.sender.id, direct_message_text
9
+ rescue Twitter::Error => e
10
+ puts "caught Twitter error while replying via DM: #{e.message}"
11
+ end
12
+ end
13
+ end
@@ -16,7 +16,7 @@ module Twitter
16
16
 
17
17
  $bot[:client].update result, in_reply_to_status_id: self.id
18
18
  rescue Twitter::Error => e
19
- puts "caught Twitter error while retweeting: #{e.message}"
19
+ puts "caught Twitter error while replying: #{e.message}"
20
20
  end
21
21
 
22
22
  # Retweets this tweet.
@@ -0,0 +1,9 @@
1
+ module Twitter
2
+ class User
3
+ # @return [Boolean] whether the current user is a botadmin
4
+ def admin?
5
+ return false if $bot.nil? or $bot[:config].nil?
6
+ $bot[:config][:admins].include? self.id
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,51 @@
1
+ <%
2
+ # This is the config for this botpart.
3
+ # It is a hash and will be serialized to YAML and saved to 'etc/template_name.yml'.
4
+ botpart_config = {
5
+ magic_word: "Supercalifragilisticexpialidocious" # (I'll buy you a beer if you can spell this correctly while drunk)
6
+ }
7
+
8
+ # Display a message after installation template installation
9
+ post_install_message <<-MSG
10
+ In order to make some commands work, you need to be a BotAdmin. You can add
11
+ yourself to the BotAdmin list by starting
12
+
13
+ twittbot add-admin your_user_name
14
+ MSG
15
+ %>
16
+ Twittbot::BotPart.new :<%= @template_name %> do
17
+ # This command gives a BotAdmin the ability to tweet via the bot.
18
+ #
19
+ # Example usage (via direct message):
20
+ # !twet This is a tweet
21
+ cmd :twet do |args, _user|
22
+ bot.tweet args
23
+ end
24
+
25
+ # This command gives anyone who is followed by the bot the ability to echo
26
+ # back their direct message.
27
+ #
28
+ # Example usage:
29
+ # !echo Hello, world!
30
+ cmd :echo, admin: false do |args, user|
31
+ bot.dm user, args
32
+ end
33
+
34
+ ## Uncomment this if you want to remotely stop the bot.
35
+ ##
36
+ ## Example usage:
37
+ ## !stop Supercalifragilisticexpialidocious
38
+ #cmd :stop do |args, user|
39
+ # exit 0 if args.downcase == @config[:magic_word].downcase
40
+ #end
41
+
42
+ # Of course, there's a :direct_message callback too. This applies to
43
+ # everything that is not a command.
44
+ on :direct_message do |dm|
45
+ if dm.sender.admin? # You can check if an user is an admin by using the .admin? method.
46
+ dm.reply "You're an admin! You can use !twet to tweet nice things."
47
+ else
48
+ dm.reply "You're an ordinary user! Try using !echo on me."
49
+ end
50
+ end
51
+ end
@@ -17,4 +17,20 @@ Twittbot::BotPart.new :<%= @template_name %> do
17
17
  # ... tweet a random entry of the :tweets list that you configured
18
18
  bot.tweet @config[:tweets].sample
19
19
  end
20
+
21
+ ## Uncomment the next few lines if you want to add new tweets to the tweet
22
+ ## list on the fly using direct messages.
23
+ ##
24
+ ## Example usage:
25
+ ## !atwt Tweet text
26
+ #cmd :atwt do |args|
27
+ # # adds args (usually the tweet text) to the list of random tweets unless
28
+ # # args already is in the list
29
+ # @config[:tweets] << args unless @config[:tweets].include? args
30
+ #end
31
+ #
32
+ ## Auto-save! \o/
33
+ #every 1, :hour do
34
+ # save_config
35
+ #end
20
36
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: twittbot
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - nilsding
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-28 00:00:00.000000000 Z
11
+ date: 2015-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -135,8 +135,11 @@ files:
135
135
  - lib/twittbot/cli.rb
136
136
  - lib/twittbot/defaults.rb
137
137
  - lib/twittbot/gem_ext/twitter.rb
138
+ - lib/twittbot/gem_ext/twitter/direct_message.rb
138
139
  - lib/twittbot/gem_ext/twitter/rest/tweets.rb
139
140
  - lib/twittbot/gem_ext/twitter/tweet.rb
141
+ - lib/twittbot/gem_ext/twitter/user.rb
142
+ - lib/twittbot/generators/templates/basic_dm/basic_dm.rb
140
143
  - lib/twittbot/generators/templates/followback/followback.rb
141
144
  - lib/twittbot/generators/templates/random_reply/random_reply.rb
142
145
  - lib/twittbot/generators/templates/random_tweet/random_tweet.rb