This commit is contained in:
Astro 2005-11-24 07:08:14 +00:00
parent f975e24973
commit c2921e8b01
1 changed files with 290 additions and 0 deletions

View File

@ -1,5 +1,6 @@
Der [[Date Determinator]] ist ein MediaWiki-Bot, welcher Terminfindungen vereinfachen sollen. Die Eingabe passiert als YAML, die Ausgabe kann vom Bot periodisch als hybsche Tabelle erstellt werden.
=Beispiele=
==CodingNight zu dritt==
@ -248,3 +249,292 @@ END DATA -->
|'''3'''
|}
<!-- END TABLE -->
=Source=
Open-source, yada-yada!
==date_determinator.rb==
<pre>
WIKI_USER = 'AstRobot'
WIKI_PASSWORD = '...'
PAGE = 'Benutzer:Astro/Date_Determinator'
WIKI = 'http://wiki.c3d2.de/wikipgedia'
HTTP_USER = 'eris'
HTTP_PASSWORD = '...'
require 'yaml'
require 'mediawiki'
include MediaWiki
class DateUser
attr_reader :name
def initialize(name, hsh)
@name = name
@hsh = hsh
end
def dates
@hsh.keys
end
def day(d)
@hsh[d]
end
def day_class(d)
if day(d) == nil
nil
elsif day(d) =~ /^[yj]/i
true
elsif day(d) =~ /^n/i
false
else
""
end
end
def day_style(d)
case day_class(d)
when nil then ""
when true then 'bgcolor="#7fff7f"'
when false then 'bgcolor="#ff7f7f"'
else 'bgcolor="#bfbfbf"'
end
end
end
class DateData
def initialize(yaml)
@users = []
@error = nil
begin
YAML::load(yaml).each { |user,dates|
@users << DateUser.new(user, dates)
}
rescue Exception => e
puts "#{e.class}: #{e}\n#{e.backtrace.join("\n")}"
@error = e.to_s
end
end
def table
return @error if @error
s = ''
##
# Collect dates
##
dates = []
dates_yes = {}
@users.each { |user| dates += user.dates }
##
# Sort dates
##
dates.uniq!
dates.sort! { |a,b|
if a =~ /^(\d+)\.(\d+)\./
a_day = $1
a_month = $2
if b =~ /^(\d+)\.(\d+)\./
b_day = $1
b_month = $2
if a_month.to_i == b_month.to_i
a_day.to_i <=> b_day.to_i
else
a_month.to_i <=> b_month.to_i
end
else
a <=> b
end
else
a <=> b
end
}
##
# Construct header
##
s += "{| border=\"1\" cellpadding=\"2\" cellspacing=\"0\" style=\"border-collapse:collapse;\"\n|-\n! \n"
dates.each { |date|
s += "!#{date}\n"
dates_yes[date] = 0
}
##
# Construct rows
##
@users.each { |user|
s += "|-\n|[[User:#{user.name}|#{user.name}]]\n"
dates.each { |date|
s += "| #{user.day_style(date)} | #{user.day(date)}\n"
dates_yes[date] += 1 if user.day_class(date) == true
}
}
##
# Build summary
##
s += "|-\n|'''sum(ja)'''\n"
dates.each { |date|
s += "|'''#{dates_yes[date]}'''\n"
}
s += "|}"
end
end
wiki = Wiki.new(WIKI, HTTP_USER, HTTP_PASSWORD)
wiki.login(WIKI_USER, WIKI_PASSWORD)
page = wiki.article(PAGE)
datasets = {}
current_data_name = nil
current_data_yaml = ''
page.text.split(/\n/).each { |line|
if line =~ /BEGIN DATA "(.+?)"/
current_data_name = $1
current_data_yaml = ''
elsif line =~ /END DATA/ and current_data_name
datasets[current_data_name] = DateData.new(current_data_yaml)
current_data_name = nil
current_data_yaml = ''
elsif current_data_name
current_data_yaml += "#{line}\n"
end
}
text_old = page.text.dup
signature = /(<!-- BEGIN TABLE ")(.+?)(" -->)(.+?)(<!-- END TABLE -->)/m
page.text.gsub!(signature) { |part|
begin1,name,begin2,obsolete,end1 = part.match(signature).to_a[1..-1]
table = datasets[name] ? datasets[name].table : "DATA #{name} not found!"
"#{begin1}#{name}#{begin2}\n#{table}\n#{end1}"
}
page.submit('Date Determinator run') if page.text != text_old
</pre>
==mediawiki.rb==
<pre>
require 'http-access2'
require 'cgi'
require 'rexml/document'
module MediaWiki
class Wiki
##
# HTTPAccess2 object, must be accessible by the Wiki's
# Article children
attr_accessor :http
def initialize(url, auth_name=nil, auth_password=nil)
@url = (url =~ /\/$/) ? url : "#{url}/"
@http = HTTPAccess2::Client.new(nil, 'Ruby-MediaWiki::Wiki/0.1')
add_auth(url, auth_name, auth_password) if auth_name and auth_password
end
def add_auth(uri, auth_name, auth_password)
@http.set_basic_auth(uri, auth_name, auth_password)
end
def login(username, password)
postdata = "wpName=#{CGI::escape(username)}&wpPassword=#{CGI::escape(password)}&wpLoginattempt="
result = @http.post_content(article_url('Special:Userlogin'), postdata)
if result =~ /<p class='error'>/
raise "Unable to authenticate as #{username}"
end
end
##
# Return a new article with the given name
# name:: [String] Article name
# result:: [Article]
def article(name)
Article.new(self, name)
end
##
# Return
def article_url(name)
"#{@url}index.php?title=#{CGI::escape(name)}"
end
##
# Return a hash of special pages:
# 'Link title' => 'Article name'
def specialpages
result = {}
Article.new(self, 'Special:Specialpages', false).xhtml.each_element('ul/li/a') { |a|
result[a.attributes['title']] = a.text
}
result
end
end
class Article
attr_accessor :name, :text
def initialize(wiki, name, load_text=true)
@wiki = wiki
@name = name
@text = nil
@xhtml = nil
@xhtml_cached = false
@wp_edittoken = nil
@wp_edittime = nil
reload if load_text
end
def xhtml
unless @xhtml_cached
xhtml_reload
end
@xhtml
end
def xhtml_reload
html = @wiki.http.get_content("#{@wiki.article_url(@name)}")
html.scan(/<!-- start content -->(.+)<!-- end content -->/m) { |content,|
@xhtml = REXML::Document.new("<xhtml>#{content}</xhtml>").root
}
@xhtml_cached = true
end
def reload
puts "Loading #{@wiki.article_url(@name)}&action=edit"
doc = REXML::Document.new(@wiki.http.get_content("#{@wiki.article_url(@name)}&action=edit")).root
@name = doc.elements['//span[@class="editHelp"]/a'].attributes['title']
form = doc.elements['//form[@name="editform"]']
@text = form.elements['textarea[@name="wpTextbox1"]'].text
begin
@wp_edittoken = form.elements['input[@name="wpEditToken"]'].attributes['value']
@wp_edittime = form.elements['input[@name="wpEdittime"]'].attributes['value']
rescue NoMethodError
# wpEditToken might be missing, that's ok
end
end
##
# TODO: minor_edit, watch_this
def submit(summary, minor_edit=false, watch_this=false)
puts "Posting to #{@wiki.article_url(@name)}&action=submit"
postdata = "wpTextbox1=#{CGI::escape(@text)}&wpSummary=#{CGI::escape(summary)}&wpSave=1&wpEditToken=#{@wp_edittoken}&wpEdittime=#{@wp_edittime}"
result = @wiki.http.post_content("#{@wiki.article_url(@name)}&action=submit", postdata)
# TODO: Was edit successful? (We received the document anyways)
end
end
end
</pre>