|
|
Zeile 1: |
Zeile 1: |
| [[Kategorie:Ruby]] | | [[Kategorie:Ruby]] |
| 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. | | Der [[Benutzer:Astro/Date Determinator|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= | | =Beispiele= |
| ==CodingNight zu dritt== | | ==CodingNight zu dritt== |
Zeile 13: |
Zeile 13: |
| 1337 Cracker: | | 1337 Cracker: |
| 24.5.: jo | | 24.5.: jo |
| 23.5.: yezz! | | 23.5.: yep |
| END DATA | | END DATA |
| '''Ausgabe:''' | | '''Ausgabe:''' |
Zeile 244: |
Zeile 244: |
| <!-- END TABLE --> | | <!-- END TABLE --> |
| =Source= | | =Source= |
| Open-source, yada-yada!
| | Siehe: [[Ruby-MediaWiki]], dort ist es enthalten |
| ==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>
| |
| | |
| {{Rübÿ Spëëd Mëtäl Cödïng}}
| |