hipbot 1.0.3 → 1.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +3 -3
  4. data/Gemfile +12 -1
  5. data/README.md +16 -8
  6. data/bin/hipbot +5 -0
  7. data/hipbot.gemspec +2 -1
  8. data/lib/hipbot.rb +7 -10
  9. data/lib/hipbot/adaptable.rb +60 -0
  10. data/lib/hipbot/adapter.rb +6 -6
  11. data/lib/hipbot/adapters/hipchat.rb +5 -48
  12. data/lib/hipbot/adapters/hipchat/client.rb +8 -0
  13. data/lib/hipbot/adapters/shell.rb +2 -9
  14. data/lib/hipbot/adapters/slack.rb +10 -0
  15. data/lib/hipbot/adapters/slack/client.rb +47 -0
  16. data/lib/hipbot/adapters/telnet.rb +2 -9
  17. data/lib/hipbot/adapters/xmpp.rb +59 -0
  18. data/lib/hipbot/adapters/{hipchat/initializer.rb → xmpp/client.rb} +35 -21
  19. data/lib/hipbot/bot.rb +5 -1
  20. data/lib/hipbot/callbacks/base.rb +20 -2
  21. data/lib/hipbot/callbacks/lobby_presence.rb +2 -1
  22. data/lib/hipbot/callbacks/presence.rb +1 -5
  23. data/lib/hipbot/callbacks/room_invite.rb +13 -0
  24. data/lib/hipbot/callbacks/room_message.rb +3 -9
  25. data/lib/hipbot/callbacks/room_presence.rb +10 -8
  26. data/lib/hipbot/callbacks/room_topic.rb +18 -0
  27. data/lib/hipbot/configuration.rb +11 -6
  28. data/lib/hipbot/helpers.rb +2 -0
  29. data/lib/hipbot/{http.rb → helpers/http.rb} +11 -7
  30. data/lib/hipbot/message.rb +2 -2
  31. data/lib/hipbot/presence.rb +0 -6
  32. data/lib/hipbot/reaction.rb +9 -7
  33. data/lib/hipbot/response.rb +1 -1
  34. data/lib/hipbot/room.rb +1 -1
  35. data/lib/hipbot/storages/hash.rb +5 -5
  36. data/lib/hipbot/storages/mongoid.rb +1 -1
  37. data/lib/hipbot/user.rb +4 -0
  38. data/lib/hipbot/{cache.rb → utilities/cache.rb} +0 -0
  39. data/lib/hipbot/{logger.rb → utilities/logger.rb} +0 -0
  40. data/lib/hipbot/version.rb +1 -1
  41. data/spec/integration/my_hipbot_spec.rb +1 -1
  42. data/spec/spec_helper.rb +7 -2
  43. data/spec/unit/match_spec.rb +7 -7
  44. data/spec/unit/message_spec.rb +2 -2
  45. data/spec/unit/reaction_spec.rb +14 -14
  46. metadata +28 -8
  47. data/lib/hipbot/callbacks/invite.rb +0 -11
@@ -0,0 +1,59 @@
1
+ require 'hipbot/adapters/xmpp/client'
2
+
3
+ module Hipbot
4
+ module Adapters
5
+ class XMPP
6
+ include Hipbot::Adaptable
7
+
8
+ add_config_options :jid, :conference_host
9
+
10
+ attr_accessor :client
11
+
12
+ def start!
13
+ self.client = self.class::Client.new.client
14
+ end
15
+
16
+ def restart!
17
+ start!
18
+ end
19
+
20
+ def invite_to_room(room, users)
21
+ client.invite(user_ids(users), room.id)
22
+ end
23
+
24
+ def kick_from_room(room, users)
25
+ client.kick(user_ids(users), room.id)
26
+ end
27
+
28
+ def send_to_room(room, message)
29
+ client.send_message(:groupchat, room.id, message)
30
+ end
31
+
32
+ def send_to_user(user, message)
33
+ client.send_message(:chat, user.id, message)
34
+ end
35
+
36
+ def set_topic(room, topic)
37
+ client.send_message(:groupchat, room.id, nil, topic)
38
+ end
39
+
40
+ def set_presence(status, type)
41
+ client.set_presence(status, type)
42
+ end
43
+
44
+ def join_room(room)
45
+ client.join(room.id)
46
+ end
47
+
48
+ def leave_room(room, reason = '')
49
+ client.exit(room.id, reason)
50
+ end
51
+
52
+ protected
53
+
54
+ def user_ids users
55
+ Array(users).map(&:id)
56
+ end
57
+ end
58
+ end
59
+ end
@@ -1,41 +1,52 @@
1
+ require 'xmpp4r-hipchat'
2
+
1
3
  module Hipbot
2
4
  module Adapters
3
- class Hipchat
4
- class Initializer
5
+ class XMPP
6
+ class Client
5
7
  attr_accessor :client
6
8
 
7
9
  KEEP_ALIVE_INTERVAL = 60
8
10
 
9
11
  def initialize
10
- Jabber.debug = true
11
- Jabber.logger = Hipbot.logger
12
+ initialize_logger
13
+
14
+ Hipbot.logger.info("INITIALIZE XMPP Client")
12
15
  initialize_client do
16
+ Hipbot.logger.info("INITIALIZE Rooms")
13
17
  initialize_rooms
18
+ Hipbot.logger.info("INITIALIZE Users")
14
19
  initialize_users
20
+ Hipbot.logger.info("INITIALIZE Bot user")
15
21
  initialize_bot_user
22
+ Hipbot.logger.info("INITIALIZE Callbacks")
16
23
  initialize_callbacks
24
+ Hipbot.logger.info("INITIALIZE Keep-alive")
17
25
  initialize_keep_alive
18
26
  end
19
27
  end
20
28
 
21
29
  protected
22
30
 
31
+ def initialize_logger
32
+ Jabber.logger = Hipbot.logger
33
+ if Hipbot.logger.level == Logger::DEBUG
34
+ Jabber.debug = true
35
+ end
36
+ end
37
+
23
38
  def initialize_client
24
- self.client = ::Jabber::MUC::HipchatClient.new(Hipbot.jid)
25
- yield if client.connect(Hipbot.password)
39
+ self.client = ::Jabber::MUC::HipchatClient.new(
40
+ Hipbot.configuration.jid,
41
+ Hipbot.configuration.conference_host,
42
+ )
43
+ yield if client.connect(Hipbot.configuration.password)
26
44
  end
27
45
 
28
46
  def initialize_rooms
29
47
  room_ids = client.get_rooms.map do |room_data|
30
- room = Room.find_or_create_by(id: room_data[:item].jid.to_s)
31
- room.update_attributes(
32
- name: room_data[:item].iname,
33
- topic: room_data[:details]['topic'],
34
- privacy: room_data[:details]['privacy'],
35
- hipchat_id: room_data[:details]['id'],
36
- archived: room_data[:details].has_key?('is_archived'),
37
- guest_url: room_data[:details]['guest_url'],
38
- )
48
+ room = Room.find_or_create_by(id: room_data.id)
49
+ room.update_attributes(room_data.attributes)
39
50
  room.id
40
51
  end
41
52
  clean_other_objects(Room, room_ids) if room_ids.any?
@@ -43,11 +54,11 @@ module Hipbot
43
54
 
44
55
  def initialize_users
45
56
  user_ids = client.get_users.map do |user_data|
46
- user = User.find_or_create_by(id: user_data.delete(:jid))
47
- user.update_attributes(user_data)
57
+ user = User.find_or_create_by(id: user_data.id)
58
+ user.update_attributes(user_data.attributes)
48
59
 
49
60
  if user.attributes['email'].nil?
50
- user.update_attributes(client.get_user_details(user.id))
61
+ user.update_attributes(client.get_user_details(user.id).attributes)
51
62
  end
52
63
  user.id
53
64
  end
@@ -55,18 +66,21 @@ module Hipbot
55
66
  end
56
67
 
57
68
  def clean_other_objects klass, object_ids
58
- klass.all.select{ |r| !object_ids.include?(r.id) }.each(&:destroy)
69
+ klass.all.select{ |r| !object_ids.include?(r.id) }.tap{ |o|
70
+ Hipbot.logger.info("REMOVING #{o.count} objects from #{klass}")
71
+ }.each(&:destroy)
59
72
  end
60
73
 
61
74
  def initialize_bot_user
62
- Hipbot.configuration.user = User.find(Hipbot.jid)
75
+ Hipbot.configuration.user = User.find(Jabber::JID.new(Hipbot.configuration.jid).node)
63
76
  client.name = Hipbot.user.name
64
77
  end
65
78
 
66
79
  def initialize_callbacks
67
80
  client.on_room_message{ |*args| Callbacks::RoomMessage.new(*args) }
81
+ client.on_room_topic{ |*args| Callbacks::RoomTopic.new(*args) }
68
82
  client.on_private_message{ |*args| Callbacks::PrivateMessage.new(*args) }
69
- client.on_invite{ |*args| Callbacks::Invite.new(*args) }
83
+ client.on_room_invite{ |*args| Callbacks::RoomInvite.new(*args) }
70
84
  client.on_lobby_presence{ |*args| Callbacks::LobbyPresence.new(*args) }
71
85
  client.on_room_presence{ |*args| Callbacks::RoomPresence.new(*args) }
72
86
  client.activate_callbacks
@@ -1,12 +1,16 @@
1
1
  module Hipbot
2
2
  class << self
3
- attr_accessor :bot, :plugins
3
+ attr_accessor :bot, :plugins, :adapters
4
4
  delegate :name, to: :bot
5
5
 
6
6
  def plugins
7
7
  @plugins ||= []
8
8
  end
9
9
 
10
+ def adapters
11
+ @adapters ||= []
12
+ end
13
+
10
14
  def method_missing name, *params, &block
11
15
  bot.send(name, *params, &block)
12
16
  end
@@ -4,11 +4,29 @@ module Hipbot
4
4
  protected
5
5
 
6
6
  def with_room params
7
- yield Room.find_or_create_by(params)
7
+ yield Room.find_or_create_by(params) if valid_params?(params)
8
8
  end
9
9
 
10
10
  def with_user params
11
- yield User.find_or_create_by(params)
11
+ yield User.find_or_create_by(params) if valid_params?(params)
12
+ end
13
+
14
+ def with_user_by_name_or_mention name_or_mention
15
+ return if !valid_value?(name_or_mention)
16
+
17
+ yield User.where(mention: name_or_mention).first ||
18
+ User.where(name: name_or_mention).first ||
19
+ User.create(name: name_or_mention, mention: name_or_mention)
20
+ end
21
+
22
+ private
23
+
24
+ def valid_params? params
25
+ params.any?{ |_, v| valid_value?(v) }
26
+ end
27
+
28
+ def valid_value? value
29
+ !value.nil? && value.present?
12
30
  end
13
31
  end
14
32
  end
@@ -5,7 +5,8 @@ module Hipbot
5
5
  self.presence = presence
6
6
 
7
7
  with_user(id: user_id) do |user|
8
- user.update_attribute(:is_online, online_presence?)
8
+ Hipbot.logger.info("PRESENCE from #{user}: #{presence}")
9
+ user.update_attribute(:is_online, !offline_presence?)
9
10
  end
10
11
  end
11
12
  end
@@ -5,12 +5,8 @@ module Hipbot
5
5
 
6
6
  protected
7
7
 
8
- def online_presence?
9
- presence.empty?
10
- end
11
-
12
8
  def offline_presence?
13
- presence == 'unavailable'
9
+ presence == :unavailable
14
10
  end
15
11
  end
16
12
  end
@@ -0,0 +1,13 @@
1
+ module Hipbot
2
+ module Callbacks
3
+ class RoomInvite < Base
4
+ def initialize room_id, room_name
5
+ return unless Hipbot.configuration.join_on_invite
6
+
7
+ with_room(id: room_id, name: room_name) do |room|
8
+ Hipbot.join_room(room)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -1,21 +1,15 @@
1
1
  module Hipbot
2
2
  module Callbacks
3
3
  class RoomMessage < Message
4
- def initialize room_id, user_name, message_body, topic
4
+ def initialize room_id, user_name_or_mention, message_body
5
5
  with_room(id: room_id) do |room|
6
- update_topic(room, topic)
7
- with_user(name: user_name) do |user|
6
+ with_user_by_name_or_mention(user_name_or_mention) do |user|
8
7
  return if ignore_message?(user, message_body)
8
+
9
9
  Hipbot.react(user, room, message_body)
10
10
  end
11
11
  end
12
12
  end
13
-
14
- protected
15
-
16
- def update_topic room, topic
17
- room.update_attribute(:topic, topic) unless topic.empty?
18
- end
19
13
  end
20
14
  end
21
15
  end
@@ -1,12 +1,13 @@
1
1
  module Hipbot
2
2
  module Callbacks
3
3
  class RoomPresence < Presence
4
- attr_accessor :room_id, :user_name
4
+ attr_accessor :room_id, :user_name_or_mention
5
+
6
+ def initialize room_id, user_name_or_mention, presence, role
7
+ self.room_id = room_id
8
+ self.user_name_or_mention = user_name_or_mention
9
+ self.presence = presence
5
10
 
6
- def initialize room_id, user_name, presence
7
- self.presence = presence
8
- self.user_name = user_name
9
- self.room_id = room_id
10
11
  handle_room_presence
11
12
  end
12
13
 
@@ -14,13 +15,14 @@ module Hipbot
14
15
 
15
16
  def handle_room_presence
16
17
  with_room(id: room_id) do |room|
17
- with_user(name: user_name) do |user|
18
+ with_user_by_name_or_mention(user_name_or_mention) do |user|
19
+ Hipbot.logger.info("PRESENCE in ##{room} from #{user}: #{presence}")
18
20
  Hipbot.react_to_presence(user, presence, room)
21
+
19
22
  if offline_presence?
20
23
  room.on_leave(user)
21
- elsif online_presence? && !room.users.include?(user)
22
- room.on_join(user)
23
24
  else
25
+ room.on_join(user) if !room.users.include?(user)
24
26
  # TODO: Availability status change handling
25
27
  end
26
28
  end
@@ -0,0 +1,18 @@
1
+ module Hipbot
2
+ module Callbacks
3
+ class RoomTopic < Message
4
+ def initialize room_id, topic
5
+ with_room(id: room_id) do |room|
6
+ Hipbot.logger.info("TOPIC in ##{room}: #{topic}")
7
+ update_topic(room, topic)
8
+ end
9
+ end
10
+
11
+ protected
12
+
13
+ def update_topic room, topic
14
+ room.update_attribute(:topic, topic)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,24 +1,29 @@
1
1
  module Hipbot
2
2
  class Configuration
3
3
  OPTIONS = [
4
- :adapter, :exception_handler, :helpers, :jid, :join, :logger, :password,
5
- :plugins, :preloader, :rooms, :status, :storage, :teams, :user
4
+ :adapter, :case_insensitive, :exception_handler, :helpers, :join, :join_on_invite,
5
+ :logger, :password, :plugins, :preloader, :rooms, :status, :storage, :teams, :user
6
6
  ]
7
7
  attr_accessor *OPTIONS
8
8
 
9
9
  def initialize
10
- self.adapter = Adapters::Hipchat
11
- self.exception_handler = Proc.new do |e|
10
+ self.class.class_eval do
11
+ attr_accessor *Hipbot.adapters.flat_map(&:options).compact
12
+ end
13
+
14
+ self.adapter = Adapters::Hipchat
15
+ self.case_insensitive = true
16
+ self.exception_handler = proc do |e|
12
17
  Hipbot.logger.error(e.message)
13
18
  e.backtrace.each { |line| Hipbot.logger.error(line) }
14
19
  end
15
20
  self.helpers = Module.new
16
- self.jid = ''
17
21
  self.join = :all
22
+ self.join_on_invite = true
18
23
  self.logger = Logger.new($stdout)
19
24
  self.password = ''
20
25
  self.plugins = Hipbot.plugins
21
- self.preloader = Proc.new{}
26
+ self.preloader = proc {}
22
27
  self.rooms = {}
23
28
  self.status = ''
24
29
  self.storage = Storages::Hash
@@ -1,3 +1,5 @@
1
+ require 'hipbot/helpers/http'
2
+
1
3
  module Hipbot
2
4
  module Helpers
3
5
  [:get, :post, :put, :delete].each do |method|
@@ -1,13 +1,17 @@
1
+ # encoding: utf-8
1
2
  module Hipbot
2
3
  module Http
3
- class Request < Struct.new(:url, :query, :method)
4
+ class Request < Struct.new(:url, :params, :method)
4
5
  DEFAULT_HEADERS = { 'accept-encoding' => 'gzip, compressed' }.freeze
5
6
  CONNECTION_SETTINGS = { connect_timeout: 5, inactivity_timeout: 10 }.freeze
6
7
  ERROR_CALLBACK = ->(error){ Hipbot.logger.error(error) }
7
8
 
8
9
  def initialize *args
9
10
  super
10
- Hipbot.logger.info("HTTP-REQUEST: #{url} #{query}")
11
+ self.params ||= {}
12
+ self.params = params.has_key?(:query) ? params : { query: params }
13
+ self.params = { head: DEFAULT_HEADERS }.merge(params)
14
+ Hipbot.logger.info("HTTP-REQUEST: #{url} #{params}")
11
15
  end
12
16
 
13
17
  def call &success_block
@@ -21,16 +25,16 @@ module Hipbot
21
25
 
22
26
  def success
23
27
  yield Http::Response.new(http)
24
- rescue => e
25
- instance_exec(e, &Hipbot.exception_handler)
26
28
  end
27
29
 
28
- def http
29
- @http ||= connection.send(method, query: query.merge(head: DEFAULT_HEADERS))
30
+ def http options = {}
31
+ @http ||= connection.send(method, params.merge(options))
32
+ rescue => e
33
+ instance_exec(e, &Hipbot.exception_handler)
30
34
  end
31
35
 
32
36
  def connection
33
- EM::HttpRequest.new(url, CONNECTION_SETTINGS)
37
+ @connection ||= EM::HttpRequest.new(url, CONNECTION_SETTINGS)
34
38
  end
35
39
  end
36
40
 
@@ -5,11 +5,11 @@ module Hipbot
5
5
 
6
6
  attr_accessor :body
7
7
 
8
- MENTION_REGEXP = /@(\p{Word}++)/.freeze
8
+ MENTION_REGEXP = /@(\p{Word}++):?/.freeze
9
9
 
10
10
  def initialize *args
11
11
  super
12
- Hipbot.logger.info("MESSAGE from #{sender} in #{room}")
12
+ Hipbot.logger.info("MESSAGE from #{sender} in ##{room}")
13
13
  self.raw_body = raw_body.force_encoding('UTF-8')
14
14
  self.body = strip_bot_mention
15
15
  end
@@ -1,11 +1,5 @@
1
1
  module Hipbot
2
2
  class Presence < Struct.new(:sender, :body, :room)
3
-
4
- def initialize *args
5
- super
6
- Hipbot.logger.info("PRESENCE from #{sender} in #{room}")
7
- end
8
-
9
3
  def for? _
10
4
  true
11
5
  end