mod_spox 0.0.3 → 0.0.4

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.
Files changed (37) hide show
  1. data/CHANGELOG +38 -0
  2. data/INSTALL +5 -2
  3. data/bin/mod_spox +7 -3
  4. data/data/mod_spox/extras/Confess.rb +4 -4
  5. data/data/mod_spox/extras/Karma.rb +2 -2
  6. data/data/mod_spox/extras/Logger.rb +167 -0
  7. data/data/mod_spox/extras/Quotes.rb +2 -2
  8. data/data/mod_spox/extras/Roulette.rb +34 -16
  9. data/data/mod_spox/extras/Topten.rb +105 -0
  10. data/data/mod_spox/plugins/Authenticator.rb +2 -2
  11. data/data/mod_spox/plugins/Banner.rb +10 -10
  12. data/data/mod_spox/plugins/Initializer.rb +1 -1
  13. data/data/mod_spox/plugins/Triggers.rb +3 -3
  14. data/lib/mod_spox/Bot.rb +6 -5
  15. data/lib/mod_spox/BotConfig.rb +1 -1
  16. data/lib/mod_spox/ConfigurationWizard.rb +18 -17
  17. data/lib/mod_spox/Database.rb +9 -0
  18. data/lib/mod_spox/Helpers.rb +49 -0
  19. data/lib/mod_spox/Loader.rb +11 -0
  20. data/lib/mod_spox/PluginManager.rb +1 -0
  21. data/lib/mod_spox/Pool.rb +23 -107
  22. data/lib/mod_spox/Socket.rb +23 -37
  23. data/lib/mod_spox/Timer.rb +3 -3
  24. data/lib/mod_spox/handlers/Created.rb +1 -1
  25. data/lib/mod_spox/handlers/Handler.rb +1 -13
  26. data/lib/mod_spox/handlers/Invite.rb +1 -1
  27. data/lib/mod_spox/handlers/LuserOp.rb +1 -1
  28. data/lib/mod_spox/handlers/LuserUnknown.rb +1 -1
  29. data/lib/mod_spox/messages/internal/TimerAdd.rb +8 -0
  30. data/lib/mod_spox/messages/internal/TimerRemove.rb +8 -0
  31. data/lib/mod_spox/messages/internal/TimerResponse.rb +8 -1
  32. data/lib/mod_spox/models/Auth.rb +4 -4
  33. data/lib/mod_spox/models/Channel.rb +11 -0
  34. data/lib/mod_spox/models/Nick.rb +22 -11
  35. data/lib/mod_spox/models/Setting.rb +2 -2
  36. data/lib/mod_spox/models/Signature.rb +11 -2
  37. metadata +4 -2
data/CHANGELOG CHANGED
@@ -1,3 +1,41 @@
1
+ 0.0.4 Release (Alpha status)
2
+ * Signatures now encoded when stored
3
+ * SQLite lockup fixed on new version of sequel
4
+ * Timer messages now have IDs
5
+ * Removed blocks from sequel usage to remove dependency on ParseTree
6
+ * This was done to enable jruby support
7
+ * mod_spox will currently load into jruby but is not currently working
8
+ * Added experimental memcache support (very buggy)
9
+ * New plugins:
10
+ * ChatLogger - Logs chatting to database. Provides a seen and lastspoke trigger
11
+ * Topten - Provides stats on user's chatting
12
+ * The bot as well as plugins have all been updated to work with Sequel 2.0 (removed deprecated)
13
+ * Processing pool has been reworked.
14
+ * Currently testing to see how memory is consumed.
15
+ * New version will play nicely with jruby thread pools
16
+ * Various small fixes and updates
17
+
18
+ 0.0.3 Release (Alpha status)
19
+ * New features available from the following new plugins:
20
+ * AOLSpeak
21
+ * AutoKick
22
+ * AutoRejoin
23
+ * Confess
24
+ * EightBall
25
+ * LolSpeak
26
+ * PhpCli
27
+ * PhpFuncLookup
28
+ * Quotes
29
+ * Talk
30
+ * Translate
31
+ * Weather
32
+ * Help
33
+ * Added private/public/both specification for signatures
34
+ * Added smart thread creation/deletion for Pool
35
+ * Modified Rakefile to build gem without need for unused libraries
36
+ * Added support for action privmsgs
37
+ * Various fixes of small bugs
38
+
1
39
  0.0.2 Release (Alpha status)
2
40
  * New features available from the following new plugins:
3
41
  * Karma
data/INSTALL CHANGED
@@ -4,6 +4,9 @@ gem install --include-dependencies mod_spox
4
4
 
5
5
  Requirements include:
6
6
  * sequel
7
+ * database driver
8
+ * Ruby >= 1.8.4
9
+
10
+ Optional:
7
11
  * fastthread
8
- * termios
9
- * Ruby >= 1.8.4
12
+ * termios
data/bin/mod_spox CHANGED
@@ -15,11 +15,12 @@
15
15
  begin
16
16
  require 'fastthread'
17
17
  rescue Object => boom
18
- puts "WARNING: fastthread gem was not found"
18
+ # ignore if not found #
19
19
  end
20
20
 
21
- $BOTVERSION='0.0.2'
21
+ $BOTVERSION='0.0.4'
22
22
  $VERBOSITY = 0
23
+ $MOD_SPOX_PATH = nil
23
24
 
24
25
  begin
25
26
  require 'mod_spox/Loader'
@@ -33,7 +34,8 @@ opts = GetoptLong.new(
33
34
  ['--config', '-c', GetoptLong::NO_ARGUMENT],
34
35
  ['--debug', '-d', GetoptLong::OPTIONAL_ARGUMENT],
35
36
  ['--version', '-v', GetoptLong::NO_ARGUMENT],
36
- ['--help', '-h', GetoptLong::NO_ARGUMENT]
37
+ ['--help', '-h', GetoptLong::NO_ARGUMENT],
38
+ ['--path', '-p', GetoptLong::REQUIRED_ARGUMENT]
37
39
  )
38
40
  verbose = 0
39
41
  opts.each do |opt, arg|
@@ -58,6 +60,8 @@ opts.each do |opt, arg|
58
60
  wizard = ConfigurationWizard.new
59
61
  wizard.run
60
62
  exit
63
+ when '--path'
64
+ $MOD_SPOX_PATH = arg
61
65
  end
62
66
  end
63
67
 
@@ -46,7 +46,7 @@ class Confess < ModSpox::Plugin
46
46
  reg = true
47
47
  end
48
48
  else
49
- ids = Confession.map(:id)
49
+ ids = Confession.select(:id).map(:id)
50
50
  c = Confession[ids[rand(ids.size - 1)].to_i]
51
51
  end
52
52
  if(c)
@@ -74,11 +74,11 @@ class Confess < ModSpox::Plugin
74
74
  end
75
75
  if(c)
76
76
  if(params[:score] == '++')
77
- c.set(:positive => c.positive.to_i + 1)
77
+ c.update_with_params(:positive => c.positive.to_i + 1)
78
78
  else
79
- c.set(:negative => c.negative.to_i + 1)
79
+ c.update_with_params(:negative => c.negative.to_i + 1)
80
80
  end
81
- c.set(:score => ((c.positive.to_f) / (c.positive.to_f + c.negative.to_f)) * 100.0)
81
+ c.update_with_params(:score => ((c.positive.to_f) / (c.positive.to_f + c.negative.to_f)) * 100.0)
82
82
  else
83
83
  reply message.replyto, "\2Error:\2 Failed to find confession to score"
84
84
  end
@@ -21,7 +21,7 @@ class Karma < ModSpox::Plugin
21
21
  thing = thing[1..-2] if thing[0..0] == '(' && thing[-1..1] == ')'
22
22
  adj = adj == '++' ? +1 : -1
23
23
  karma = Datatype::Karma.find_or_create(:thing => thing, :channel_id => message.target.pk)
24
- karma.set(:score => karma.score + adj)
24
+ karma.update_with_params(:score => karma.score + adj)
25
25
  end
26
26
  end
27
27
  end
@@ -42,7 +42,7 @@ class Karma < ModSpox::Plugin
42
42
  return unless message.is_public?
43
43
  karma = Datatype::Karma.filter(:thing => params[:thing], :channel_id => message.target.pk).first
44
44
  if(karma)
45
- karma.set(:score => 0)
45
+ karma.update_with_params(:score => 0)
46
46
  @pipeline << Privmsg.new(message.replyto, "Karma for \2#{karma.thing}\2 has been reset")
47
47
  else
48
48
  @pipeline << Privmsg.new(message.replyto, "\2Error:\2 #{params[:thing]} has no karma")
@@ -0,0 +1,167 @@
1
+ class ChatLogger < ModSpox::Plugin
2
+
3
+ # This plugin creates a log of conversations the bot sees. It
4
+ # is important to note that the order in which messages are
5
+ # added to the database may not be in order. Due to the
6
+ # async behavior of the pipeline, this plugin may (and most
7
+ # likely will) receive messages out of order. This will be most
8
+ # notable with triggers received and responses from the bot
9
+
10
+ include Models
11
+
12
+ def initialize(pipeline)
13
+ super
14
+ PublicLog.create_table unless PublicLog.table_exists?
15
+ PrivateLog.create_table unless PrivateLog.table_exists?
16
+ @pipeline.hook(self, :log_privmsg, :Incoming_Privmsg)
17
+ @pipeline.hook(self, :log_join, :Incoming_Join)
18
+ @pipeline.hook(self, :log_part, :Incoming_Part)
19
+ @pipeline.hook(self, :log_quit, :Incoming_Quit)
20
+ @pipeline.hook(self, :log_kick, :Incoming_Kick)
21
+ @pipeline.hook(self, :log_mode, :Incoming_Mode)
22
+ @pipeline.hook(self, :log_privmsg, :Incoming_Notice)
23
+ @pipeline.hook(self, :log_outpriv, :Outgoing_Privmsg)
24
+ @pipeline.hook(self, :log_outpriv, :Outgoing_Notice)
25
+ Signature.find_or_create(:signature => 'seen (\S+)', :plugin => name, :method => 'seen', :description => 'Report last sighting of nick').params = [:nick]
26
+ Signature.find_or_create(:signature => 'lastspoke (\S+)', :plugin => name, :method => 'spoke', :description => 'Report last time nick spoke').params = [:nick]
27
+ end
28
+
29
+ def log_outpriv(message)
30
+ type = message.is_a?(Messages::Outgoing::Privmsg) ? 'privmsg' : 'notice'
31
+ type = 'action' if message.is_action?
32
+ target = message.target.is_a?(Sequel::Model) ? message.target : Helpers.find_model(message.target)
33
+ if(target.is_a?(Models::Channel))
34
+ PublicLog.new(:message => message.message, :type => type, :sender => me.pk,
35
+ :channel => target.pk, :received => Time.now).save
36
+ else
37
+ PrivateLog.new(:message => message.message, :type => type, :sender => me.pk,
38
+ :receiver => target.pk, :received => Time.now).save
39
+ end
40
+ end
41
+
42
+ def log_privmsg(message)
43
+ type = message.is_a?(Messages::Incoming::Privmsg) ? 'privmsg' : 'notice'
44
+ type = 'action' if message.is_action?
45
+ if(message.is_public?)
46
+ PublicLog.new(:message => message.message, :type => type, :sender => message.source.pk,
47
+ :channel => message.target.pk, :received => message.time).save
48
+ else
49
+ PrivateLog.new(:message => message.message, :type => type, :sender => message.source.pk,
50
+ :receiver => message.target.pk, :received => message.time).save
51
+ end
52
+ end
53
+
54
+ def log_join(message)
55
+ PublicLog.new(:type => 'join', :sender => message.nick.pk, :channel => message.channel.pk, :received => message.time).save
56
+ end
57
+
58
+ def log_part(message)
59
+ PublicLog.new(:message => message.reason, :type => 'part', :sender => message.nick.pk,
60
+ :channel => message.channel.pk, :received => message.time).save
61
+ end
62
+
63
+ def log_quit(message)
64
+ PublicLog.new(:message => message.message, :type => 'quit', :sender => message.nick.pk, :received => message.time).save
65
+ end
66
+
67
+ def log_kick(message)
68
+ PublicLog.new(:message => "#{message.kickee.pk}|#{message.reason}", :type => 'kick', :sender => message.kicker.pk,
69
+ :channel => message.channel.pk, :received => message.time).save
70
+ end
71
+
72
+ # TODO: Fix this
73
+ def log_mode(message)
74
+ # if(message.for_channel?)
75
+ # PublicLog.new(:message => message.mode, :type => 'mode', :sender => message.source.pk,
76
+ # :channel => message.channel.pk, :received => message.time).save
77
+ # else
78
+ # PrivateLog.new(:message => message.mode, :type => 'mode', :sender => message.source.pk,
79
+ # :receiver => message.target.pk, :received => message.time).save
80
+ # end
81
+ end
82
+
83
+ def seen(m, p)
84
+ nick = Helpers.find_model(p[:nick], false)
85
+ if(nick.is_a?(Models::Nick))
86
+ record = PublicLog.filter(:sender => nick.pk).order(:received).last
87
+ record_p = PrivateLog.filter(:sender => nick.pk).order(:received).last
88
+ record = record_p if !record || (record_p && record && record_p.received > record.received)
89
+ if(record)
90
+ if(record.is_a?(PublicLog))
91
+ case record.values[:type]
92
+ when 'join'
93
+ message = "joining #{Channel[record.channel].name}"
94
+ when 'part'
95
+ message = "parting #{Channel[record.channel].name} with the message: #{record.message}"
96
+ when 'privmsg'
97
+ message = "in #{Channel[record.channel].name} saying: #{record.message}"
98
+ when 'action'
99
+ message = "in #{Channel[record.channel].name} saying: * #{p[:nick]} #{record.message}"
100
+ when 'notice'
101
+ message = "in #{Channel[record.channel].name} saying: #{record.message}"
102
+ when 'kick'
103
+ if(record.message =~ /^([0-9]+)\|/)
104
+ kickee = Nick[$1.to_i]
105
+ reason = $2
106
+ message = "kicking #{kickee.nick} from #{Channel[record.channel].name} (#{record.message})"
107
+ end
108
+ end
109
+ else
110
+ message = "saying to me: #{record.message}"
111
+ end
112
+ reply m.replyto, "I last saw #{p[:nick]} on #{record.received} #{message}"
113
+ else
114
+ reply m.replyto, "\2Error:\2 Failed to find record of #{p[:nick]}"
115
+ end
116
+ else
117
+ reply m.replyto, "\2Error:\2 Failed to find record of #{p[:nick]}"
118
+ end
119
+ end
120
+
121
+ def spoke(m, p)
122
+ nick = Helpers.find_model(p[:nick], false)
123
+ if(nick.is_a?(Models::Nick))
124
+ record = PublicLog.filter(:sender => nick.pk).filter("type in ('privmsg', 'action')").order(:received).last
125
+ record_p = PrivateLog.filter(:sender => nick.pk).order(:received).last
126
+ record = record_p if !record || (record_p && record && record_p.received > record.received)
127
+ if(record)
128
+ if(record.is_a?(PublicLog))
129
+ reply m.replyto, "I last saw #{p[:nick]} on #{record.received} saying: #{record.values[:type] == 'action' ? "* #{p[:nick]} #{record.message}" : record.message}"
130
+ else
131
+ reply m.replyto, "I last saw #{p[:nick]} on #{record.received} saying to me: #{record.message}"
132
+ end
133
+ else
134
+ reply m.replyto, "\2Error:\2 Failed to find record of #{p[:nick]}"
135
+ end
136
+ else
137
+ reply m.replyto, "\2Error:\2 Failed to find record of #{p[:nick]}"
138
+ end
139
+ end
140
+
141
+ class PrivateLog < Sequel::Model
142
+ set_schema do
143
+ primary_key :id
144
+ text :message, :null => false
145
+ text :type, :null => false, :default => 'privmsg'
146
+ boolean :action, :null => false, :default => false
147
+ timestamp :received, :null => false
148
+ foreign_key :sender, :table => :nicks
149
+ foreign_key :receiver, :table => :nicks
150
+ index :message, :type => :full_text
151
+ end
152
+ end
153
+
154
+ class PublicLog < Sequel::Model
155
+ set_schema do
156
+ primary_key :id
157
+ text :message
158
+ text :type, :null => false, :default => 'privmsg'
159
+ boolean :action, :null => false, :default => false
160
+ timestamp :received, :null => false
161
+ foreign_key :sender, :table => :nicks
162
+ foreign_key :channel, :table => :channels
163
+ index :message, :type => :full_text
164
+ end
165
+ end
166
+
167
+ end
@@ -27,11 +27,11 @@ class Quotes < ModSpox::Plugin
27
27
  reg = true
28
28
  end
29
29
  else
30
- ids = Quote.map(:id)
30
+ ids = Quote.select(:id).map(:id)
31
31
  quote = Quote[ids[rand(ids.size - 1)].to_i]
32
32
  end
33
33
  if(quote)
34
- reply message.replyto, "\2[\2#{quote.pk}\2|\2#{quote.added.year}/#{quote.added.month}/#{quote.added.day}\2]:\2 #{reg ? quote.quote.gsub(/(#{params[:term]})/, "\2\\1\2") : quote.quote}"
34
+ reply message.replyto, "\2[\2#{quote.pk}\2|\2#{quote.added.year}/#{sprintf('%02d', quote.added.month)}/#{sprintf('%02d', quote.added.day)}\2]:\2 #{reg ? quote.quote.gsub(/(#{params[:term]})/, "\2\\1\2") : quote.quote}"
35
35
  else
36
36
  reply message.replyto, "\2Error:\2 Failed to find quote"
37
37
  end
@@ -4,15 +4,33 @@ class Roulette < ModSpox::Plugin
4
4
 
5
5
  def initialize(pipeline)
6
6
  super(pipeline)
7
- Signature.find_or_create(:signature => 'roulette', :plugin => name, :method => 'roulette')
8
- Signature.find_or_create(:signature => 'suicide', :plugin => name, :method => 'suicide')
9
- Signature.find_or_create(:signature => 'shoot (\S+)', :plugin => name, :method => 'shoot').params = [:nick]
10
- Signature.find_or_create(:signature => 'roulette topten', :plugin => name, :method => 'topten')
11
- Signature.find_or_create(:signature => 'roulette stats ?(\S+)?', :plugin => name, :method => 'stats').params = [:nick]
7
+ Signature.find_or_create(:signature => 'roulette', :plugin => name, :method => 'roulette', :requirement => 'public')
8
+ Signature.find_or_create(:signature => 'suicide', :plugin => name, :method => 'suicide', :requirement => 'public')
9
+ Signature.find_or_create(:signature => 'shoot (\S+)', :plugin => name, :method => 'shoot', :requirement => 'public').params = [:nick]
10
+ Signature.find_or_create(:signature => 'roulette topten', :plugin => name, :method => 'topten', :requirement => 'public')
11
+ Signature.find_or_create(:signature => 'roulette stats ?(\S+)?', :plugin => name, :method => 'stats', :requirement => 'public').params = [:nick]
12
+ Signature.find_or_create(:signature => 'roulette chambers', :plugin => name, :method => 'chambers', :requirement => 'public')
12
13
  Game.create_table unless Game.table_exists?
13
14
  Info.create_table unless Info.table_exists?
14
15
  @banner = nil
15
- @pipeline.hook(:self, :get_banner, :Internal_PluginResponse)
16
+ @pipeline.hook(self, :get_banner, :Internal_PluginResponse)
17
+ end
18
+
19
+ # message:: ModSpox::Messages::Incoming::Privmsg
20
+ # Display chamber statistics
21
+ def chambers(m, p)
22
+ total = Game.all.size
23
+ result = Game.group(:chamber).select(:chamber, :COUNT[:chamber] => :total).reverse_order(:total)
24
+ if(result)
25
+ output = []
26
+ result.each do |res|
27
+ percent = sprintf('%.2d', ((res[:total].to_f / total.to_f) * 100.0))
28
+ output << "chamber #{res.chamber}: #{percent}% (#{res[:total]})"
29
+ end
30
+ reply m.replyto, "\2Chamber stats:\2 #{output.join(', ')}"
31
+ else
32
+ reply m.replyto, "\2Error:\2 No games found"
33
+ end
16
34
  end
17
35
 
18
36
  # message:: ModSpox::Messages::Internal::PluginResponse
@@ -57,7 +75,7 @@ class Roulette < ModSpox::Plugin
57
75
  def topten(message, params)
58
76
  return unless message.is_public?
59
77
  ds = Database.db[:infos].left_outer_join(:games, :id => :game_id)
60
- ds.select!(:nick_id, :COUNT[:win] => :wins).where!(:channel_id => message.target.pk, :win => true).group!(:nick_id).order!(:wins.DESC).limit!(10)
78
+ ds.select!(:nick_id, :COUNT[:win] => :wins).where!(:channel_id => message.target.pk, :win => true).group!(:nick_id).reverse_order!(:wins).limit!(10)
61
79
  Logger.log(ds.sql)
62
80
  ids = ds.map(:nick_id)
63
81
  top = []
@@ -109,7 +127,7 @@ class Roulette < ModSpox::Plugin
109
127
  # channel:: ModSpox::Models::Channel
110
128
  # Return number of games nick has won
111
129
  def games_won(nick, channel)
112
- Info.left_outer_join(:games, :id => :game_id).filter{:nick_id == nick.pk && :channel_id == channel.pk && :win == true}.size
130
+ Info.left_outer_join(:games, :id => :game_id).filter('nick_id = ?', nick.pk).filter('channel_id = ?', channel.pk).filter('win = ?', true).size
113
131
  end
114
132
 
115
133
  # nick:: ModSpox::Models::Nick
@@ -123,14 +141,14 @@ class Roulette < ModSpox::Plugin
123
141
  # channel:: ModSpox::Models::Channel
124
142
  # Return number of games nick has played
125
143
  def games_total(nick, channel)
126
- Info.left_outer_join(:games, :id => :game_id).filter{:nick_id == nick.pk && :channel_id == channel.pk}.exclude(:game_id => game(channel).pk).size
144
+ Info.left_outer_join(:games, :id => :game_id).filter('nick_id = ?', nick.pk).filter('channel_id = ?', channel.pk).exclude(:game_id => game(channel).pk).size
127
145
  end
128
146
 
129
147
  # nick:: ModSpox::Models::Nick
130
148
  # channel:: ModSpox::Models::Channel
131
149
  # Return number of shots nick has taken
132
150
  def total_shots(nick, channel)
133
- v = Info.left_outer_join(:games, :id => :game_id).filter{:nick_id == nick.pk && :channel_id == channel.pk}.exclude(:game_id => game(channel).pk).sum(:infos__shots)
151
+ v = Info.left_outer_join(:games, :id => :game_id).filter('nick_id = ?', nick.pk).filter('channel_id = ?', channel.pk).exclude(:game_id => game(channel).pk).sum(:infos__shots)
134
152
  v = 0 unless v
135
153
  return v
136
154
  end
@@ -165,8 +183,8 @@ class Roulette < ModSpox::Plugin
165
183
  def kill_nick(nick, channel)
166
184
  unless(@banner.nil?)
167
185
  begin
168
- @banner.ban(nick, channel, '*BANG*', true, false)
169
- rescue NotOperator => boom
186
+ @banner.ban(nick, channel, 30, '*BANG*', true, false)
187
+ rescue Banner::NotOperator => boom
170
188
  reply(channel, "#{nick.nick}: *BANG*")
171
189
  rescue Object => boom
172
190
  Logger.log("Error: Roulette ban generated an unexpected error: #{boom}")
@@ -180,7 +198,7 @@ class Roulette < ModSpox::Plugin
180
198
  # Return current game
181
199
  def game(channel)
182
200
  @pipeline << Messages::Internal::PluginRequest.new(self, 'Banner') if @banner.nil?
183
- game = Game.filter{:shots > 0 && :channel_id == channel.pk}.first
201
+ game = Game.filter('shots > ?', 0).filter('channel_id = ?', channel.pk).first
184
202
  unless(game)
185
203
  chamber = rand(5) + 1
186
204
  game = Game.new(:chamber => chamber, :shots => chamber, :channel_id => channel.pk)
@@ -195,8 +213,8 @@ class Roulette < ModSpox::Plugin
195
213
  def shot(nick, channel)
196
214
  cur_game = game(channel)
197
215
  info = Info.find_or_create(:game_id => cur_game.pk, :nick_id => nick.pk)
198
- info.set(:shots => info.shots + 1)
199
- cur_game.set(:shots => cur_game.shots - 1)
216
+ info.update_with_params(:shots => info.shots + 1)
217
+ cur_game.update_with_params(:shots => cur_game.shots - 1)
200
218
  raise Bullet.new(cur_game) if cur_game.shots < 1
201
219
  end
202
220
 
@@ -205,7 +223,7 @@ class Roulette < ModSpox::Plugin
205
223
  # Return number of games nick has won
206
224
  def game_over(nick, game)
207
225
  Info.filter(:game_id => game.pk).each do |info|
208
- info.set(:win => true) unless info.nick_id == nick.pk
226
+ info.update_with_params(:win => true) unless info.nick_id == nick.pk
209
227
  end
210
228
  end
211
229
 
@@ -0,0 +1,105 @@
1
+ class Topten < ModSpox::Plugin
2
+
3
+ include Models
4
+
5
+ def initialize(pipeline)
6
+ super
7
+ ChatStat.create_table unless ChatStat.table_exists?
8
+ Signature.find_or_create(:signature => 'topten', :plugin => name, :method => 'topten',
9
+ :requirement => 'public', :description => 'Show topten users since midnight')
10
+ Signature.find_or_create(:signature => 'topten ([0-9]{4}\/[0-9]{2}\/[0-9]{2})', :plugin => name, :method => 'archive',
11
+ :description => 'Show topten from given date', :requirement => 'public').params = [:date]
12
+ Signature.find_or_create(:signature => 'stats ?(\S+)?', :plugin => name, :method => 'stats', :description => 'Show stats on nick',
13
+ :requirement => 'public').params = [:nick]
14
+ Signature.find_or_create(:signature => 'stats lifetime? (\S+)?', :plugin => name, :method => 'life_stats',
15
+ :description => 'Show stat totals for given nick', :requirement => 'public').params = [:nick]
16
+ @pipeline.hook(self, :log_stats, :Incoming_Privmsg)
17
+ end
18
+
19
+ def topten(m, p)
20
+ stats = ChatStat.filter(:channel_id => m.target.pk, :daykey => construct_daykey).reverse_order(:bytes).limit(10)
21
+ if(stats.size > 0)
22
+ users = []
23
+ stats.each do |stat|
24
+ bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
25
+ users << "#{Nick[stat.nick_id].nick}: #{bytes}"
26
+ end
27
+ reply m.replyto, "\2Topten:\2 #{users.join(', ')}"
28
+ else
29
+ reply m.replyto, "\2Error:\2 No stats found for this channel."
30
+ end
31
+ end
32
+
33
+ def archive(m, p)
34
+ stats = ChatStat.filter(:channel_id => m.target.pk, :daykey => p[:date]).reverse_order(:bytes).limit(10)
35
+ if(stats.size > 0)
36
+ users = []
37
+ stats.each do |stat|
38
+ bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
39
+ users << "#{Nick[stat.nick_id].nick}: #{bytes}"
40
+ end
41
+ reply m.replyto, "\2Topten:\2 #{users.join(', ')}"
42
+ else
43
+ reply m.replyto, "\2Error:\2 No stats found for date given."
44
+ end
45
+ end
46
+
47
+ def stats(m, p)
48
+ nick = p[:nick] ? Nick.locate(p[:nick], false) : m.source
49
+ if(nick.is_a?(Nick))
50
+ stat = ChatStat.filter(:nick_id => nick.pk, :channel_id => m.target.pk, :daykey => construct_daykey).first
51
+ if(stat)
52
+ bytes = (stat.bytes > 1023) ? "#{sprintf('%.2f', (stat.bytes / 1024.0))}kb" : "#{stat.bytes}b"
53
+ reply m.replyto, "#{nick.nick}: #{bytes} logged. #{stat.words} words spoken. #{stat.questions} questions asked."
54
+ else
55
+ reply m.replyto, "\2Error:\2 #{nick.nick} has no stats recorded for today"
56
+ end
57
+ else
58
+ reply m.replyto, "\2Error:\2 Failed to find record of nick: #{p[:nick]}"
59
+ end
60
+ end
61
+
62
+ def life_stats(m, p)
63
+ nick = p[:nick] ? Nick.locate(p[:nick], false) : m.source
64
+ if(nick)
65
+ result = ChatStat.group(:nick_id).select(:SUM[:bytes] => :tbytes, :SUM[:words] => :twords, :SUM[:questions] => :tquestions).filter(:nick_id => nick.pk).first
66
+ bytes = (result.tbytes > 1023) ? "#{sprintf('%.2f', (result.tbytes / 1024.0))}kb" : "#{result.tbytes}b"
67
+ reply m.replyto, "#{nick.nick} (total): #{bytes} logged, #{result.twords} words spoken and #{result.tquestions} questions asked"
68
+ else
69
+ reply m.replyto, "\2Error:\2 Failed to find #{p[:nick]}"
70
+ end
71
+ end
72
+
73
+ def log_stats(m)
74
+ return unless m.is_public?
75
+ key = construct_daykey
76
+ stat = ChatStat.find_or_create(:nick_id => m.source.pk, :channel_id => m.target.pk, :daykey => key)
77
+ words = m.message.scan(/([^ ]+ |[^ ]$)/).size
78
+ bytes = m.message.gsub(/[^a-zA-Z0-9`\~\!@#\$%\^&\*\(\)_\+\[\]\}\{;:'"\/\?\.>,<\\|\-=]/, '').length
79
+ questions = m.message.scan(/.+?(\? |\?$)/).size
80
+ stat.words += words
81
+ stat.bytes += bytes
82
+ stat.questions += questions
83
+ stat.save
84
+ end
85
+
86
+ private
87
+
88
+ def construct_daykey
89
+ t = Time.now
90
+ return "#{t.year}/#{sprintf('%02d', t.month)}/#{sprintf('%02d', t.day)}"
91
+ end
92
+
93
+ class ChatStat < Sequel::Model
94
+ set_schema do
95
+ primary_key :id
96
+ integer :words, :null => false, :default => 0
97
+ integer :bytes, :null => false, :default => 0
98
+ integer :questions, :null => false, :default => 0
99
+ varchar :daykey, :null => false
100
+ foreign_key :channel_id, :table => :channels
101
+ foreign_key :nick_id, :table => :nicks
102
+ end
103
+ end
104
+
105
+ end
@@ -129,9 +129,9 @@ class Authenticator < ModSpox::Plugin
129
129
  def nick_ident(message, params)
130
130
  nick = Models::Nick.find_or_create(:nick => params[:nick])
131
131
  if(params[:ident] == 'true')
132
- nick.auth.set(:services => true)
132
+ nick.auth.update_with_params(:services => true)
133
133
  else
134
- nick.auth.set(:services => false)
134
+ nick.auth.update_with_params(:services => false)
135
135
  end
136
136
  @pipeline << Messages::Outgoing::Privmsg.new(message.replyto, "Nick #{params[:nick]} has been updated. Services for authentication has been set to #{params[:ident]}")
137
137
  end
@@ -179,7 +179,7 @@ class Banner < ModSpox::Plugin
179
179
  def ban_remove(message, params)
180
180
  record = BanRecord[params[:id].to_i]
181
181
  if(record)
182
- record.set(:remaining => 0)
182
+ record.update_with_params(:remaining => 0)
183
183
  updater
184
184
  reply(message.replyto, 'Okay')
185
185
  else
@@ -243,8 +243,8 @@ class Banner < ModSpox::Plugin
243
243
  if(message.mode == '-b')
244
244
  update = false
245
245
  BanRecord.filter(:mask => message.target, :channel_id => message.channel.pk).each do |match|
246
- match.set(:remaining => 0)
247
- match.set(:removed => true)
246
+ match.update_vaules(:remaining => 0)
247
+ match.update_with_params(:removed => true)
248
248
  update = true
249
249
  end
250
250
  updater if update
@@ -297,19 +297,19 @@ class Banner < ModSpox::Plugin
297
297
  begin
298
298
  time = @sleep.nil? ? 0 : (Object::Time.now - @sleep).to_i
299
299
  if(time > 0)
300
- BanRecord.filter{:remaining > 0}.update("remaining = remaining - #{time}")
301
- BanMask.filter{:bantime > 0}.update("bantime = bantime - #{time}")
300
+ BanRecord.filter('remaining > ?', 0).update("remaining = remaining - #{time}")
301
+ BanMask.filter('bantime > ?', 0).update("bantime = bantime - #{time}")
302
302
  end
303
- BanRecord.filter{:remaining <= 0 && :removed == false}.each do |record|
303
+ BanRecord.filter('remaining <= ?', 0).filter('removed = ?', false).each do |record|
304
304
  if(me.is_op?(record.channel))
305
305
  @pipeline << ChannelMode.new(record.channel, '-b', record.mask)
306
- record.set(:removed => true)
306
+ record.update_with_params(:removed => true)
307
307
  @pipeline << Invite.new(record.nick, record.channel) if record.invite
308
308
  end
309
309
  end
310
- BanMask.filter{:bantime < 1}.destroy
311
- next_ban_record = BanRecord.filter{:remaining > 0}.order(:remaining.ASC).first
312
- next_mask_record = BanMask.filter{:bantime > 0}.order(:bantime.ASC).first
310
+ BanMask.filter('bantime < ?', 1).destroy
311
+ next_ban_record = BanRecord.filter('remaining > ?', 0).order(:remaining).first
312
+ next_mask_record = BanMask.filter('bantime > ?', 0).order(:bantime).first
313
313
  if(next_ban_record && next_mask_record)
314
314
  time = next_ban_record.bantime < next_mask_record.bantime ? next_ban_record.bantime : next_mask_record.bantime
315
315
  elsif(next_ban_record)
@@ -33,7 +33,7 @@ class Initializer < ModSpox::Plugin
33
33
  private
34
34
 
35
35
  def populate_servers
36
- Models::Server.order(:priority.DESC).each{|s|
36
+ Models::Server.reverse_order(:priority).each{|s|
37
37
  @servers << s
38
38
  }
39
39
  end
@@ -38,7 +38,7 @@ include Messages::Outgoing
38
38
  end
39
39
 
40
40
  def add(message, params)
41
- Models::Trigger.find_or_create(:trigger => params[:trigger]).set(:active => true)
41
+ Models::Trigger.find_or_create(:trigger => params[:trigger]).update_with_params(:active => true)
42
42
  @pipeline << Privmsg.new(message.replyto, "Trigger #{params[:trigger]} is now active")
43
43
  @pipeline << Messages::Internal::TriggersUpdate.new
44
44
  end
@@ -58,7 +58,7 @@ include Messages::Outgoing
58
58
  def activate(message, params)
59
59
  trigger = Models::Trigger[params[:id]]
60
60
  if(trigger)
61
- trigger.set(:active => true)
61
+ trigger.update_with_params(:active => true)
62
62
  @pipeline << Privmsg.new(message.replyto, "Trigger #{trigger.trigger} has been activated")
63
63
  @pipeline << Messages::Internal::TriggersUpdate.new
64
64
  else
@@ -69,7 +69,7 @@ include Messages::Outgoing
69
69
  def deactivate(message, params)
70
70
  trigger = Models::Trigger[params[:id]]
71
71
  if(trigger)
72
- trigger.set(:active => false)
72
+ trigger.update_with_params(:active => false)
73
73
  @pipeline << Privmsg.new(message.replyto, "Trigger #{trigger.trigger} has been deactivated")
74
74
  @pipeline << Messages::Internal::TriggersUpdate.new
75
75
  else