mod_spox 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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