Skip to content
This repository has been archived by the owner on Feb 5, 2019. It is now read-only.

Commit

Permalink
Copy from SVN repo
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim Morgan committed Jun 28, 2008
0 parents commit e10fae9
Show file tree
Hide file tree
Showing 57 changed files with 6,203 additions and 0 deletions.
987 changes: 987 additions & 0 deletions README

Large diffs are not rendered by default.

161 changes: 161 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
require 'rake'
require 'facets/symbol/to_proc'
require 'facets/stylize'
require 'libs/genesis'

task :default do
puts 'Type "rake --tasks" to see a list of tasks you can perform.'
end

# Load the Autumn environment.
task :environment do
AL_ROOT = File.dirname(__FILE__)
@genesis = Autumn::Genesis.new
@genesis.load_global_settings
@genesis.load_season_settings
end

task :full_bootstrap do
AL_ROOT = File.dirname(__FILE__)
@genesis = Autumn::Genesis.new
@genesis.boot! false
end

namespace :app do
desc "Launch the Autumn daemon"
task :start do
system 'script/daemon start'
end

desc "Stop the Autumn daemon"
task :stop do
system 'script/daemon stop'
end

desc "Restart the Autumn daemon"
task :restart do
system 'script/daemon restart'
end

desc "Start Autumn but not as a daemon (stay on top)"
task :run do
system 'script/daemon run'
end

desc "Force the daemon to a stopped state (clears PID files)"
task :zap do
system 'script/daemon zap'
end
end

namespace :log do
desc "Remove all log files"
task :clear do
system 'rm -vf tmp/*.log tmp/*.output log/*.log*'
end

desc "Print all error messages in the log files"
task :errors => :environment do
season_log = "log/#{@genesis.config.global :season}.log"
system_log = 'tmp/autumn-leaves.log'
if File.exists? season_log then
puts "==== ERROR-LEVEL LOG MESSAGES ===="
File.open(season_log, 'r') do |log|
puts log.grep(/^[EF],/)
end
end
if File.exists? system_log then
puts "==== UNCAUGHT EXCEPTIONS ===="
File.open(system_log, 'r') do |log|
puts log.grep(/^[EF],/)
end
end
end
end

def local_db?(db)
db.host.nil? or db.host == 'localhost'
end

namespace :db do
desc "Create a database"
task :create => :full_bootstrap do
lname = ENV['LEAF']
raise "Usage: LEAF=[Leaf name] rake db:populate" unless lname
raise "Unknown leaf #{lname}" unless leaf = Autumn::Foliater.instance.leaves[lname]
raise "No databases configured" unless File.exist? "config/seasons/#{@genesis.config.global :season}/database.yml"
db = DataMapper::Database[leaf.database_name]
raise "No database configured for #{lname}" unless db

case db.adapter.class.to_s
when 'DataMapper::Adapters::MysqlAdapter'
`echo "CREATE DATABASE #{db.database} CHARACTER SET utf8" | mysql -u#{db.username} -h#{db.host} -p#{db.password}`
when 'DataMapper::Adapters::PostgresqlAdapter'
local_db?(db) ? `createdb "#{db.database}" -E utf8` : raise("Can only create local PostgreSQL databases")
when 'DataMapper::Adapters::Sqlite3Adapter'
`sqlite3 "#{db.database}"`
end
end

desc "Drop a database"
task :drop => :full_bootstrap do
lname = ENV['LEAF']
raise "Usage: LEAF=[Leaf name] rake db:populate" unless lname
raise "Unknown leaf #{lname}" unless leaf = Autumn::Foliater.instance.leaves[lname]
raise "No databases configured" unless File.exist? "config/seasons/#{@genesis.config.global :season}/database.yml"
db = DataMapper::Database[leaf.database_name]
raise "No database configured for #{lname}" unless db

case db.adapter.class.to_s
when 'DataMapper::Adapters::MysqlAdapter'
`echo "DROP DATABASE #{db.database}" | mysql -u#{db.username} -h#{db.host} -p#{db.password}`
when 'DataMapper::Adapters::PostgresqlAdapter'
local_db?(db) ? `dropdb "#{db.database}"` : raise("Can only drop local PostgreSQL databases")
when 'DataMapper::Adapters::Sqlite3Adapter'
FileUtils.rm_f db.database
end
end

desc "Create database tables according to the model objects"
task :populate => :full_bootstrap do
lname = ENV['LEAF']
raise "Usage: LEAF=[Leaf name] rake db:populate" unless lname
raise "Unknown leaf #{lname}" unless leaf = Autumn::Foliater.instance.leaves[lname]

leaf.database do
Dir.glob("support/#{leaf.class.pathize}/**/*.rb").each do |file|
content = nil
File.open(file, 'r') { |f| content = f.read }
content.scan(/class ([A-Z]\w+)/).flatten.each do |cname|
klass = Module.const_get(cname.to_sym)
next unless klass.ancestors.map(&:to_s).include? 'DataMapper::Base'
puts "Creating table for #{cname}..."
klass.table.create!
end
end
end
end

desc "Drop, recreates, and repopulates a database"
task :reset => [ 'db:drop', 'db:create', 'db:populate' ]
end

namespace :doc do
desc "Generate API documentation for Autumn"
task :api => [ :environment, :clear ] do
system 'rm -rf doc/api' if File.directory? 'doc/api'
system "rdoc --main README --title 'Autumn API Documentation' -o doc/api --line-numbers --inline-source libs README"
end

desc "Generate documentation for all leaves"
task :leaves => [ :environment, :clear ] do
system 'rm -rf doc/leaves' if File.directory? 'doc/leaves'
system "rdoc --main README --title 'Autumn Leaves Documentation' -o doc/leaves --line-numbers --inline-source leaves support"
end

desc "Remove all documentation"
task :clear => :environment do
system 'rm -rf doc/api' if File.directory? 'doc/api'
system 'rm -rf doc/leaves' if File.directory? 'doc/leaves'
end
end
2 changes: 2 additions & 0 deletions config/global.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
season: testing
7 changes: 7 additions & 0 deletions config/seasons/testing/database.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
Example:
username: root
adapter: mysql
host: localhost
database: example_database
password: ""
3 changes: 3 additions & 0 deletions config/seasons/testing/leaves.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
Scorekeeper:
class: Scorekeeper
2 changes: 2 additions & 0 deletions config/seasons/testing/season.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---
logging: debug
8 changes: 8 additions & 0 deletions config/seasons/testing/stems.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
Example:
nick: Yournick
leaves:
- Scorekeeper
rejoin: true
channel: "#yourchannel"
server: irc.yourircserver.com
132 changes: 132 additions & 0 deletions leaves/scorekeeper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
require 'data_mapper'
# Install the "chronic" gem for more robust date parsing
begin
gem 'chronic'
require 'chronic'
rescue Gem::LoadError
end

# An Autumn Leaf used for an in-channel scorekeeping system. This can operate
# both as an open or closed score system. (In the former, new members are
# automatically added when they receive points; in the latter, only authorized
# members can give and receive points.)
#
# Scorekeeper is a database-backed leaf. It requires the DataMapper gem in order
# to run. The database stores channels and their members, and each member's
# point history.
#
# Scorekeeper supports pseudonyms. Entries in the +pseudonyms+ table can be used
# to help ensure that the correct person's points are changed even when the
# sender uses a nickname or abbreviation.
#
# This class contains only the methods directly relating to IRC. Other methods
# are stored in ScorekeeperHelper and the model classes.
#
# = Usage
#
# !points [name]:: Get a person's score
# !points [name] [+|-][number] [reason]:: Change a person's score (you must have a "+" or
# a "-"). A reason is optional.
# !points [name] history:: Return some recent history of that person's score.
# !points [name] history [time period]:: Selects history from a time period.
# !points [name] history [sender]:: Selects point changes from a sender.

class Scorekeeper < Autumn::ChannelLeaf
# Message displayed for !about command.
ABOUT_MESSAGE = "Scorekeeper version 2.0 (2-29-08) by Tim Morgan: An Autumn Leaf."
# Message displayed when a user uses incorrect !points syntax.
USAGE = %[Examples: "!points", "!points Sancho +5", "!points Smith history", "!points Sancho history 2/27/08", "!points Sancho history Smith"]
# Set this to true if you only want a specified set of users to receive and
# give points. Set to false if anyone should be able to award points to
# anyone.
CLOSED_SYSTEM = false

before_filter :authenticate, :only => [ :reload, :quit ]

# Displays an about message.

def about_command(stem, sender, reply_to, msg)
ABOUT_MESSAGE
end

# Displays the current point totals, or modifies someone's score, depending on
# the message provided with the command.

def points_command(stem, sender, reply_to, msg)
if msg.nil? or msg.empty? then
totals(stem, reply_to)
elsif msg =~ /^(\w+)\s+history\s*(.*)$/ then
parse_history stem, reply_to, $1, $2
elsif msg =~ /^(\w+)\s+([\+\-]\d+)\s*(.*)$/ then
parse_change stem, reply_to, sender, $1, $2.to_i, $3
else
USAGE
end
end

private

def authenticate_filter(stem, channel, sender, command, msg, opts)
# Returns true if the sender has any of the privileges listed below
not ([ :operator, :admin, :founder, :channel_owner ] & [ stem.privilege(channel, sender) ].flatten).empty?
end

def points(stem, channel)
chan = Channel.find_or_create :server => server_identifier(stem), :name => channel
scores = Score.all(:channel_id.eql => chan.id)
scores.inject(Hash.new(0)) { |hsh, score| hsh[score.receiver.name] += score.change; hsh }
end

def totals(stem, channel)
if points(stem, channel).empty? then
"No one has any points yet."
else
points(stem, channel).sort { |a,b| b.last <=> a.last }.collect { |n,p| "#{n}: #{p}" }.join(', ')
end
end

def parse_change(stem, channel, sender, victim, delta, note)
giver = find_person(stem, sender[:nick])
receiver = find_person(stem, victim)
if giver.nil? and not CLOSED_SYSTEM then
giver ||= Person.create :server => server_identifier(stem), :name => sender[:nick]
giver.reload! # Get those default fields filled out
end
if receiver.nil? and not CLOSED_SYSTEM then
receiver ||= Person.create :server => server_identifier(stem), :name => find_in_channel(stem, channel, victim)
receiver.reload! # Get those default fields filled out
end
return "You can't change #{victim}'s points." unless authorized?(giver, receiver)
change_points stem, channel, giver, receiver, delta, note
return announce_change(giver, receiver, delta)
end

def parse_history(stem, channel, subject, argument)
date = argument.empty? ? nil : parse_date(argument)
scores = Array.new

chan = Channel.first(:name.eql => channel)
person = find_person(stem, subject)
return "#{subject} has no points history." unless person

if date then
start, stop = find_range(date)
scores = Score.all(:channel_id.eql => chan.id, :receiver_id.eql => person.id, :created_at.gte => start, :created_at.lt => stop, :order => 'created_at DESC')
elsif argument.empty? then
scores = Score.all(:channel_id.eql => chan.id, :receiver_id.eql => person.id, :order => 'created_at DESC')
else
giver = find_person(stem, argument)
return "#{argument} has not given any points." unless giver
scores = Score.all(:channel_id.eql => chan.id, :receiver_id.eql => person.id, :giver_id => giver.id, :order => 'created_at DESC')
end
return "No point history found." if scores.empty?

str = String.new
if scores.size > 5 then
str << "(#{scores.size} point changes found; showing the first 5.)\n"
scores = scores.slice(0, 5)
end
scores.each { |score| str << "[#{score.created_at.strftime '%m/%d %I:%M %p'}] #{score.giver.name} #{score.change > 0 ? 'gave' : 'docked'} #{score.receiver.name} #{score.change.abs.pluralize('point')}#{score.note ? (': ' + score.note) : ''}\n"}
return str
end
end
Loading

0 comments on commit e10fae9

Please sign in to comment.