ruby-mediawiki 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,143 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ This file is part of Ruby-MediaWiki.
4
+
5
+ Ruby-MediaWiki is free software: you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ Ruby-MediaWiki is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Ruby-MediaWiki. If not, see
17
+ <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+
21
+ # this bot expects a fully functional local pentabarf installation
22
+
23
+ $:.unshift('../lib')
24
+
25
+ require 'mediawiki/dotfile'
26
+ require 'mediawiki/table'
27
+ require 'momomoto/momomoto'
28
+ require 'momomoto/tables'
29
+ require 'momomoto/bot_login'
30
+
31
+ class Localization_Sync
32
+
33
+ def initialize
34
+ @wiki = MediaWiki.dotfile
35
+
36
+ db_config = YAML.load_file('db_config.yml')['development']
37
+ Momomoto::Base.connect(db_config)
38
+ Momomoto::Bot_login.authorize('ui_tagger')
39
+
40
+ @lang = {}
41
+ Momomoto::Language.find({:f_localized=>'t'},nil,"lower(tag)").each do | l | @lang[l.tag] = l.language_id end
42
+
43
+ @@syncable = [
44
+ ['Attachment_type', :attachment_type_id, :tag, Momomoto::Attachment_type, Momomoto::Attachment_type_localized],
45
+ ['Conference_phase', :conference_phase_id, :tag, Momomoto::Conference_phase, Momomoto::Conference_phase_localized],
46
+ ['Conflict', :conflict_id, :tag, Momomoto::Conflict, Momomoto::Conflict_localized],
47
+ ['Conflict_level', :conflict_level_id, :tag, Momomoto::Conflict_level, Momomoto::Conflict_level_localized],
48
+ ['Country', :country_id, :iso_3166_code, Momomoto::Country, Momomoto::Country_localized],
49
+ ['Currency', :currency_id, :iso_4217_code, Momomoto::Currency, Momomoto::Currency_localized],
50
+ ['Event_origin', :event_origin_id, :tag, Momomoto::Event_origin, Momomoto::Event_origin_localized],
51
+ ['Event_role', :event_role_id, :tag, Momomoto::Event_role, Momomoto::Event_role_localized],
52
+ ['Event_state', :event_state_id, :tag, Momomoto::Event_state, Momomoto::Event_state_localized],
53
+ ['Event_type', :event_type_id, :tag, Momomoto::Event_type, Momomoto::Event_type_localized],
54
+ ['Im_type', :im_type_id, :tag, Momomoto::Im_type, Momomoto::Im_type_localized],
55
+ ['Language', :language_id, :iso_639_code, Momomoto::Language, Momomoto::Language_localized, :translated_id],
56
+ ['Mime_type', :mime_type_id, :mime_type, Momomoto::Mime_type, Momomoto::Mime_type_localized],
57
+ ['Phone_type', :phone_type_id, :tag, Momomoto::Phone_type, Momomoto::Phone_type_localized],
58
+ ['Role', :role_id, :tag, Momomoto::Role, Momomoto::Role_localized],
59
+ ['Transport', :transport_id, :tag, Momomoto::Transport, Momomoto::Transport_localized],
60
+ ['Ui_message', :ui_message_id, :tag, Momomoto::Ui_message, Momomoto::Ui_message_localized]
61
+ ]
62
+
63
+ end
64
+
65
+ # creates wiki pages from the data in the database
66
+ def update_wiki
67
+ @@syncable.each do | row |
68
+ make_table( *row )
69
+ end
70
+ page = @wiki.article('Localization', 1)
71
+ page.text = "=Localizable Tables=\n"
72
+ @@syncable.each do | row |
73
+ page.text += "*[[Localization/#{row[0]}|#{row[0]}]]\n"
74
+ end
75
+ page.submit('updating localization page')
76
+ end
77
+
78
+ # reads wiki pages and updates the database according to the data in the wiki
79
+ def update_database
80
+ @@syncable.each do | row |
81
+ read_table( *row )
82
+ end
83
+ end
84
+
85
+ def read_table(table, tag_id, tag_name, tag_class, local_class, lang_id = :language_id)
86
+ page = @wiki.article("Localization/#{table}")
87
+ return if page.text == ''
88
+ t = MediaWiki::Table.parse( page.text )
89
+ header = t.shift
90
+ header.shift
91
+
92
+ local_class.new.begin
93
+
94
+ t.each do | row |
95
+ header.each_with_index do | lang_tag, index |
96
+ cur_tag = tag_class.find({tag_name=>row[0]})
97
+ next unless cur_tag.length == 1
98
+ cur_loc = local_class.find({lang_id=>@lang[header[index]],tag_id=>cur_tag[tag_id]})
99
+ next if row[index + 1] == ''
100
+ unless cur_loc.length == 1
101
+ cur_loc.create
102
+ cur_loc[lang_id] = @lang[header[index]]
103
+ cur_loc[tag_id] = cur_tag[tag_id]
104
+ end
105
+ cur_loc[:name] = row[index + 1].strip
106
+ cur_loc.write
107
+ end
108
+ end
109
+
110
+ local_class.new.commit
111
+
112
+ end
113
+
114
+ def make_table(table, tag_id, tag_name, tag_class, local_class, lang_id = :language_id)
115
+ tags = {}
116
+ tag_class.find().each do | tc | tags[tc[tag_name]] = tc[tag_id] end
117
+ local = local_class.find({lang_id=>@lang.values})
118
+
119
+ page = @wiki.article("Localization/#{table}")
120
+
121
+ t = MediaWiki::Table.new
122
+ t.style = 'border="1" cellspacing="0" cellpadding="3" style="border-collapse: collapse;"'
123
+ t.header_style = 'bgcolor="lightblue"'
124
+ t.header = ['']
125
+ @lang.each do | tag, id | t.header.push( tag ) end
126
+ tags.keys.sort.each do | tag |
127
+ row = [tag]
128
+ @lang.each do | key, language_id |
129
+ row.push(local.find_by_value({tag_id=>tags[tag],lang_id=>language_id}) ? local.name : '')
130
+ end
131
+ t.data.push( row )
132
+ end
133
+
134
+ page.text = "[[Localization|<< Localization]]\n" + t.text + "\n[[Category:Localization]]"
135
+ page.submit("updating localization pages")
136
+ end
137
+
138
+ end
139
+
140
+ s = Localization_Sync.new
141
+ s.update_database
142
+ s.update_wiki
143
+
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ This file is part of Ruby-MediaWiki.
4
+
5
+ Ruby-MediaWiki is free software: you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ Ruby-MediaWiki is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Ruby-MediaWiki. If not, see
17
+ <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+
21
+ require 'yaml'
22
+ require 'rdoc/ri/ri_reader'
23
+
24
+ $:.unshift('../lib')
25
+ require 'mediawiki/dotfile'
26
+
27
+
28
+ def find(dir, &block)
29
+ Dir.foreach(dir) { |file|
30
+ next if file =~ /^\./
31
+
32
+ path = "#{dir}/#{file}"
33
+ if File.directory?(path)
34
+ find(path) { |f| yield f }
35
+ else
36
+ yield path
37
+ end
38
+ }
39
+ end
40
+
41
+ def wiki_format(flow)
42
+ s = ''
43
+ case flow
44
+ when Array
45
+ flow.each { |subflow|
46
+ s += wiki_format(subflow)
47
+ }
48
+ when SM::Flow::LIST
49
+ flow.contents.each { |subflow|
50
+ s += wiki_format(subflow)
51
+ }
52
+ s += "\n"
53
+ when SM::Flow::LI
54
+ if flow.label =~ /:$/
55
+ s += "; #{flow.label}\n: #{flow.body}\n"
56
+ elsif flow.label =~ /^[ \*]$/
57
+ s += "#{flow.label} #{flow.body}\n"
58
+ else
59
+ s += "* '''#{flow.label}:''' #{flow.body}\n"
60
+ end
61
+ when SM::Flow::P
62
+ s += "#{flow.body}\n\n"
63
+ else
64
+ puts "Unknown Flow: #{flow.inspect}"
65
+ end
66
+ s.gsub!(/&quot;/, '"')
67
+ s.gsub!(/<b>(.+?)<\/b>/, '\'\'\'\1\'\'\'')
68
+ s.gsub!(/<i>(.+?)<\/i>/, '\'\'\1\'\'')
69
+ s.gsub!(/<tt>(.+?)<\/tt>/, '<em>\1</em>')
70
+ s
71
+ end
72
+
73
+
74
+ classes = []
75
+ methods = {}
76
+
77
+ find("../rdoc-ri") { |file|
78
+ next unless file =~ /\.yaml$/
79
+ ri = YAML::load(File.new(file))
80
+ case ri
81
+ when RI::ClassDescription
82
+ classes << ri
83
+ when RI::MethodDescription
84
+ methods[ri.full_name] = ri
85
+ else
86
+ puts "Unknown Description: #{ri.inspect}"
87
+ end
88
+ }
89
+
90
+ classes.sort! { |a,b|
91
+ a.full_name <=> b.full_name
92
+ }
93
+
94
+ text = ''
95
+ classes.each { |klass|
96
+ text += "==#{klass.full_name}==\n\n"
97
+ text += "Inherited from '''#{klass.superclass}'''\n\n" if klass.superclass
98
+ text += wiki_format(klass.comment || [])
99
+ klass.attributes.each { |attribute|
100
+ text += "===#{klass.full_name}##{attribute.name} (#{attribute.rw})===\n\n"
101
+ text += wiki_format(attribute.comment || [])
102
+ text += "\n"
103
+ }
104
+ klass.class_methods.each { |methodname|
105
+ method = methods["#{klass.full_name}::#{methodname.name}"]
106
+ text += "===#{method.full_name}#{method.params}===\n\n"
107
+ text += wiki_format(method.comment || [])
108
+ text += "\n"
109
+ }
110
+ klass.instance_methods.each { |methodname|
111
+ method = methods["#{klass.full_name}##{methodname.name}"]
112
+ text += "===#{method.full_name}#{method.params}===\n\n"
113
+ text += wiki_format(method.comment || [])
114
+ text += "\n"
115
+ }
116
+ }
117
+
118
+ if false # Dry run?
119
+ puts text
120
+ exit
121
+ end
122
+
123
+ wiki, conf = MediaWiki.dotfile('rdoc to wiki')
124
+ article = wiki.article(conf['page'])
125
+ article.text = "=#{conf['title']}=\n\n" + text
126
+ article.submit("I can even document myself :-)")
@@ -0,0 +1,79 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ This file is part of Ruby-MediaWiki.
4
+
5
+ Ruby-MediaWiki is free software: you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ Ruby-MediaWiki is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Ruby-MediaWiki. If not, see
17
+ <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+
21
+ $:.unshift('../lib')
22
+ require 'mediawiki/dotfile'
23
+
24
+ wiki, conf = MediaWiki.dotfile('speed metal bot')
25
+ category_name = conf['category']
26
+ user_prefix = conf['user prefix']
27
+ template_name = conf['template']
28
+
29
+ category = wiki.category(category_name)
30
+ template = wiki.article("Template:#{template_name}")
31
+
32
+ puts "Category #{category_name}: #{category.articles.inspect}"
33
+
34
+ users = []
35
+ projects = []
36
+ category.articles.each { |name|
37
+ if name.index(user_prefix) and name.index('/').nil?
38
+ prefix, name = name.split(/:/, 2)
39
+ users << name
40
+ else
41
+ projects << name
42
+ end
43
+ }
44
+
45
+ ### Construct template ###
46
+ newtemplate = "<div align=\"center\" style=\"border: 1px solid black; clear: right;\">\n" +
47
+ "<div style=\"float: left; width: 64px; height: 64px;>[[Bild:Speed metal coding 64x64.jpg|left]]</div>\n" +
48
+ "<div style=\"margin-left: 70px; background-color: #e64200; font-size: large; height: 1.5em;\">'''Rübÿ Spëëd Mëtäl Cödïng'''</div>\n" +
49
+ "<div style=\"margin-left: 70px;\">'''Coders:''' "
50
+ users.each_with_index { |user,i|
51
+ newtemplate += " | " if i > 0
52
+ newtemplate += "[[User:#{user}|#{user}]]"
53
+ }
54
+
55
+ newtemplate += "</div>\n" +
56
+ "<div style=\"margin-left: 70px;\">'''Projects:''' "
57
+ projects.each_with_index { |project,i|
58
+ newtemplate += " | " if i > 0
59
+ newtemplate += "[[#{project}]]"
60
+ }
61
+ newtemplate += "<br/></div>\n" +
62
+ "</div>\n"
63
+
64
+ ### Submit template ###
65
+ if template.text != newtemplate
66
+ template.text = newtemplate
67
+ template.submit("Speed metal bot run", true)
68
+ end
69
+
70
+ ### Let template be used by all in category ###
71
+ category.articles.each { |name|
72
+ article = wiki.article(name)
73
+ unless article.text.index("{{#{template_name}}}")
74
+ puts "#{article.name} is in category but doesn't use template"
75
+ article.text.gsub!(/\n+$/, '')
76
+ article.text += "\n\n\n\n{{#{template_name}}}"
77
+ article.submit("This page must use the #{template_name} template!!!111")
78
+ end
79
+ }
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ This file is part of Ruby-MediaWiki.
4
+
5
+ Ruby-MediaWiki is free software: you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ Ruby-MediaWiki is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Ruby-MediaWiki. If not, see
17
+ <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+
21
+ $:.unshift('../lib')
22
+ require 'mediawiki/dotfile'
23
+
24
+ if ARGV.size != 1
25
+ puts "Usage: #{$0} <Article name>"
26
+ exit
27
+ end
28
+
29
+ wiki = MediaWiki.dotfile
30
+ puts wiki.article(ARGV[0]).text
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env ruby
2
+ =begin
3
+ This file is part of Ruby-MediaWiki.
4
+
5
+ Ruby-MediaWiki is free software: you can redistribute it and/or
6
+ modify it under the terms of the GNU General Public License as
7
+ published by the Free Software Foundation, either version 3 of the
8
+ License, or (at your option) any later version.
9
+
10
+ Ruby-MediaWiki is distributed in the hope that it will be useful,
11
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+ General Public License for more details.
14
+
15
+ You should have received a copy of the GNU General Public License
16
+ along with Ruby-MediaWiki. If not, see
17
+ <http://www.gnu.org/licenses/>.
18
+ =end
19
+
20
+
21
+ $:.unshift('../lib')
22
+ require 'mediawiki/dotfile'
23
+
24
+ if ARGV.size != 3
25
+ puts "Usage: #{$0} <Article name> <file> <comment>"
26
+ exit
27
+ end
28
+
29
+ wiki = MediaWiki.dotfile
30
+ a = wiki.article(ARGV[0])
31
+ a.text = File.new(ARGV[1]).readlines.to_s
32
+ a.submit(ARGV[2])
@@ -0,0 +1,170 @@
1
+ =begin
2
+ This file is part of Ruby-MediaWiki.
3
+
4
+ Ruby-MediaWiki is free software: you can redistribute it and/or
5
+ modify it under the terms of the GNU General Public License as
6
+ published by the Free Software Foundation, either version 3 of the
7
+ License, or (at your option) any later version.
8
+
9
+ Ruby-MediaWiki is distributed in the hope that it will be useful,
10
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ General Public License for more details.
13
+
14
+ You should have received a copy of the GNU General Public License
15
+ along with Ruby-MediaWiki. If not, see
16
+ <http://www.gnu.org/licenses/>.
17
+ =end
18
+
19
+
20
+ require 'uri'
21
+ require 'logger'
22
+
23
+
24
+ # Logger is required by article.rb
25
+ module MediaWiki
26
+ def self.logger
27
+ if defined? @@logger
28
+ @@logger
29
+ else
30
+ @@logger = Logger.new(STDERR)
31
+ end
32
+ end
33
+ end
34
+
35
+ require 'mediawiki/article'
36
+ require 'mediawiki/specialpage'
37
+ require 'mediawiki/category'
38
+ require 'mediawiki/minibrowser'
39
+
40
+ ##
41
+ # =Ruby-MediaWiki - manipulate MediaWiki pages from Ruby.
42
+ #
43
+ # Please note that documents spit out by MediaWiki *must* be valid
44
+ # XHTML (or XML)!
45
+ #
46
+ # You may not want to use MediaWiki::Wiki directly but let MediaWiki.dotfile
47
+ # create your instance. This gives you the power of the dotfile
48
+ # infrastructure. See sample apps and <tt>mediawikirc.sample</tt>.
49
+ module MediaWiki
50
+ ##
51
+ # There's no need for any language attribute, the "Special:" prefix
52
+ # works in any MediaWiki, regardless of localization settings.
53
+ class Wiki
54
+ ##
55
+ # The MiniBrowser instance used by this Wiki.
56
+ # This must be readable as it's used by Article and Category
57
+ # to fetch themselves.
58
+ attr_reader :browser
59
+
60
+ ##
61
+ # The URL-Path to index.php (without index.php) as given
62
+ # to Wiki#initialize
63
+ attr_reader :url
64
+
65
+ ##
66
+ # Initialize a new Wiki instance.
67
+ # url:: [String] URL-Path to index.php (without index.php), may containt <tt>user:password</tt> combination.
68
+ # user:: [String] If not nil, log in with that MediaWiki username (see Wiki#login)
69
+ # password:: [String] If not nil, log in with that MediaWiki password (see Wiki#login)
70
+ # loglevel:: [Integer] Loglevel, default is to log all messages >= Logger::WARN = 2
71
+ def initialize(url, user = nil, password = nil, loglevel = Logger::WARN)
72
+ if ENV['MEDIAWIKI_DEBUG']
73
+ MediaWiki::logger.level = Logger::DEBUG
74
+ else
75
+ MediaWiki::logger.level = loglevel
76
+ end
77
+
78
+ @url = URI.parse( url.match(/\/$/) ? url : url + '/' )
79
+ @browser = MiniBrowser.new(@url)
80
+
81
+ login( user, password ) if user and password
82
+ end
83
+
84
+ ##
85
+ # Log in into MediaWiki
86
+ #
87
+ # This is *not* HTTP authentication
88
+ # (put HTTP-Auth into [url] of Wiki#initialize!)
89
+ # user:: [String] MediaWiki username
90
+ # password:: [String] MediaWiki password
91
+ #
92
+ # May raise an exception if cannot authenticate
93
+ def login( username, password )
94
+ data = {'wpName' => username, 'wpPassword' => password, 'wpLoginattempt' => 'Log in'}
95
+ data = @browser.post_content( @url.path + 'index.php?title=Special:Userlogin&action=submitlogin', data )
96
+ if data =~ /<p class='error'>/
97
+ raise "Unable to authenticate as #{username}"
98
+ end
99
+ end
100
+
101
+ ##
102
+ # Return a new Category instance with given name,
103
+ # will be constructed with [self] (for MiniBrowser usage)
104
+ # name:: [String] Category name (to be prepended with "Category:")
105
+ def category(name)
106
+ Category.new(self, name)
107
+ end
108
+
109
+ ##
110
+ # Return a new Article instance with given name,
111
+ # will be constructed with [self] (for MiniBrowser usage)
112
+ # name:: [String] Article name
113
+ # section:: [Fixnum] Optional section number
114
+ def article(name, section = nil)
115
+ Article.new(self, name, section)
116
+ end
117
+
118
+ ##
119
+ # Retrieve all namespaces and their IDs, which could be used for Wiki#allpages
120
+ # result:: [Hash] String => Fixnum
121
+ def namespace_ids
122
+ ids = {}
123
+ SpecialPage.new( self, 'Special:Allpages', nil, false ).xhtml.each_element('//select[@name=\'namespace\']/option') do | o |
124
+ ids[o.text] = o.attributes['value'].to_i
125
+ end
126
+ ids
127
+ end
128
+
129
+ ##
130
+ # Returns the pages listed on "Special:Allpages"
131
+ #
132
+ # TODO: Handle big wikis with chunked Special:Allpages
133
+ # namespace_id:: Optional namespace for article index (see Wiki#namespace_ids to retrieve id)
134
+ # result:: [Array] of [String] Articlenames
135
+ def allpages(namespace_id=nil)
136
+ # Dirty, but works
137
+ article_name = 'Special:Allpages'
138
+ article_name += "&namespace=#{namespace_id}" if namespace_id
139
+
140
+ pages = []
141
+ SpecialPage.new( self, article_name, nil, false ).xhtml.each_element('table[2]/tr/td/a') do | a |
142
+ pages.push( a.text )
143
+ end
144
+ pages
145
+ end
146
+
147
+ ##
148
+ # Construct the URL to a specific article
149
+ #
150
+ # Uses the [url] the Wiki instance was constructed with,
151
+ # appends "index.php", the name parameter and, optionally,
152
+ # the section.
153
+ #
154
+ # Often called by Article, Category, ...
155
+ # name:: [String] Article name
156
+ # section:: [Fixnum] Optional section number
157
+ def article_url(name, section = nil)
158
+ "#{@url.path}index.php?title=#{CGI::escape(name.gsub(' ', '_'))}#{section ? "&section=#{CGI::escape(section.to_s)}" : ''}"
159
+ end
160
+
161
+ def full_article_url(name, section=nil)
162
+ uri = @url.dup
163
+ uri.path, uri.query = article_url(name, section).split(/\?/, 2)
164
+ uri.to_s
165
+ end
166
+
167
+ end
168
+
169
+ end
170
+