summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@dyn-174.club.berlin.ccc.de>2009-04-09 20:13:30 +0200
committererdgeist <erdgeist@dyn-174.club.berlin.ccc.de>2009-04-09 20:13:30 +0200
commit44e1eff0155d3da825ae7f4ef9e334a8e231e909 (patch)
treee6d21e4d0b8464ac9febb9efacc68cabe321a9c6
parent8c6b4dcf08268ed2971b06df40c733ba28448582 (diff)
parentacc9301696de3589a17d1543a7ab3fc1914e8ce8 (diff)
Merge branch 'master' of ssh://git@svn.medienhaus.udk-berlin.de/usr/local/git/cccms
-rw-r--r--app/models/node.rb2
-rw-r--r--app/models/page.rb6
-rw-r--r--db/migrate/20090401190026_add_full_name_to_users.rb7
-rw-r--r--lib/authors_importer.rb35
-rw-r--r--lib/chaos_importer.rb334
-rw-r--r--lib/chaos_xml.rb159
-rw-r--r--lib/tasks/development_init.rake31
-rw-r--r--test/unit/page_test.rb2
8 files changed, 394 insertions, 182 deletions
diff --git a/app/models/node.rb b/app/models/node.rb
index 8b7fe62..b56dff5 100644
--- a/app/models/node.rb
+++ b/app/models/node.rb
@@ -88,7 +88,7 @@ class Node < ActiveRecord::Base
88 88
89 # returns array with pages up to root excluding root 89 # returns array with pages up to root excluding root
90 def path_to_root 90 def path_to_root
91 parent.nil? && [slug] || parent.path_to_root.push(slug) 91 parent.nil? ? [slug] : parent.path_to_root.push(slug)
92 end 92 end
93 93
94 def update_unique_name 94 def update_unique_name
diff --git a/app/models/page.rb b/app/models/page.rb
index dfabecf..b2c0ff8 100644
--- a/app/models/page.rb
+++ b/app/models/page.rb
@@ -13,6 +13,12 @@ class Page < ActiveRecord::Base
13 :conditions => ["nodes.draft_id = pages.id"] 13 :conditions => ["nodes.draft_id = pages.id"]
14 ) 14 )
15 15
16 named_scope(
17 :heads,
18 :include => [:node, :user, :globalize_translations],
19 :conditions => ["nodes.head_id = pages.id"]
20 )
21
16 # Mixins and Plugins 22 # Mixins and Plugins
17 acts_as_taggable 23 acts_as_taggable
18 acts_as_list :column => :revision, :scope => :node_id 24 acts_as_list :column => :revision, :scope => :node_id
diff --git a/db/migrate/20090401190026_add_full_name_to_users.rb b/db/migrate/20090401190026_add_full_name_to_users.rb
new file mode 100644
index 0000000..a2599e7
--- /dev/null
+++ b/db/migrate/20090401190026_add_full_name_to_users.rb
@@ -0,0 +1,7 @@
1class AddFullNameToUsers < ActiveRecord::Migration
2 def self.up
3 end
4
5 def self.down
6 end
7end
diff --git a/lib/authors_importer.rb b/lib/authors_importer.rb
new file mode 100644
index 0000000..b0d9741
--- /dev/null
+++ b/lib/authors_importer.rb
@@ -0,0 +1,35 @@
1require 'csv'
2
3
4class AuthorsImporter
5
6 def initialize path
7 if File.exists? path
8 @parsed_file = CSV::Reader.parse(File.open(path, "r"))
9 else
10 raise "File does not exist"
11 end
12 end
13
14 def import_authors
15 @parsed_file.each do |row|
16 password = generate_password
17
18 options = {
19 :login => row[0],
20 :full_name => row[1],
21 :email => row[2],
22 :password => password,
23 :password_confirmation => password
24 }
25
26 unless user = User.find_by_email(options[:email])
27 User.create options
28 end
29 end
30 end
31
32 def generate_password
33 Digest::SHA1.hexdigest("#{Time.now+rand(10000).days}")
34 end
35end \ No newline at end of file
diff --git a/lib/chaos_importer.rb b/lib/chaos_importer.rb
new file mode 100644
index 0000000..74e0bbe
--- /dev/null
+++ b/lib/chaos_importer.rb
@@ -0,0 +1,334 @@
1require 'iconv'
2require 'nokogiri'
3require 'lib/chaos_calendar/ical_occurrences'
4require 'digest/sha1'
5
6
7class ChaosXml
8 attr_reader :xml, :unique_name, :locale, :date, :slug
9
10 def initialize options = {}
11 options.each_pair do |key,value|
12 instance_variable_set "@#{key}", value
13 instance_eval("def #{key}; @#{key};end")
14 end
15 end
16end
17
18class ChaosImporter
19 include Enumerable
20
21 def initialize path
22 unless Node.root
23 Node.create!
24 end
25
26 @directory = path
27 @years = {}
28 end
29
30 # Iterates through all xml files within the @directory and yields ChaosXml
31 # objects with the parsed attributes. These attributes are the basic data
32 # needed for further processing / parsing.
33 def each
34 directories = Dir.glob("#{@directory}/*/*.xml{,.de,.en}")
35
36 directories.each do |path|
37 next if path =~ /index\.xml/
38
39 chaos_id = chaos_id_from_path( path )
40 options = {}
41 options[:xml] = Nokogiri::XML( File.new(path).read )
42 options[:locale] = lang_from_path( path )
43 options[:date] = options[:xml].at("//date").content.to_date
44 options[:slug] = chaos_id
45 options[:unique_name] = "updates/#{options[:date].year}/#{options[:slug]}"
46 xml = ChaosXml.new options
47
48 yield xml
49 end
50 end
51
52 # Uses the each method to loop over the xml files and uses the attrubutes of
53 # the returned ChaosXml objects to do some further processing which is needed
54 # to create proper ActiveRecord records
55 def import_updates
56 unless @updates = Node.find_by_unique_name('updates')
57 @updates = Node.create!( :slug => 'updates' )
58 @updates.move_to_child_of Node.root
59 end
60
61 self.each do |update|
62
63 author = find_or_create_author( update )
64 node = find_or_create_node( update )
65 html = convert_to_html( update.xml )
66 page = fill_draft_with_content(node.draft, html, update.locale)
67
68 add_tags_to_page page, update.xml, "update"
69 add_event_to_node node, update.xml if page.tag_list.include?("event")
70 page.user = author
71 page.save
72
73 puts node.unique_name
74 end
75
76 puts ">> Publishing Drafts"
77 Node.all.each {|node| node.publish_draft!}
78 puts ">> Finished"
79 end
80
81 def lang_from_path path
82 case path
83 when /\.de$/ then :de
84 when /\.en$/ then :en
85 else
86 :de
87 end
88 end
89
90 def chaos_id_from_path path
91 path.sub(@directory, "").split(/\//).last.split(/\./)[0]
92 end
93
94 def find_or_create_author update
95 login = update.xml.at("//author").content rescue "webmaster"
96
97 unless author = User.find_by_login(login.downcase)
98 author = User.find_by_login("webmaster")
99 end
100
101 author
102 end
103
104 def find_or_create_node update
105 year = update.date.year
106
107
108 unique_name_array = update.unique_name.split("/")
109
110 unless @years[year] || (@years[year] = Node.find_by_unique_name("updates/#{year}"))
111 @years[year] = Node.create :slug => year
112 @years[year].move_to_child_of @updates
113 end
114
115 unless node = Node.find_by_unique_name(update.unique_name)
116 node = Node.create :slug => update.slug
117 node.move_to_child_of @years[year]
118 end
119
120 node
121 end
122
123 def fill_draft_with_content draft, html, lang
124 I18n.locale = lang
125
126 draft.reload
127
128 options = {
129 :title => html.xpath("//title")[0].content,
130 :abstract => html.xpath("//abstract")[0].content,
131 :body => extract_body(html)
132 }
133
134 draft.update_attributes options
135 draft
136 end
137
138 def extract_body html, excluded_tags=[]
139 default_excluded_tags = [
140 "DTSTART",
141 "DTEND",
142 "DURATION",
143 "LOCATION",
144 "GEO",
145 "SUMMARY",
146 "URL"
147 ]
148
149 excluded_tags = (default_excluded_tags + excluded_tags).uniq
150
151 body = ""
152 element = html.xpath("//abstract")[0].next_sibling
153
154 while element do
155 body << element.to_s unless excluded_tags.include? element.name
156 element = element.next_sibling
157 end
158
159 body
160 end
161
162 def add_tags_to_page page, chaospage, *custom_tags
163 tag_list = custom_tags
164
165 chaospage.xpath("//flags").each do |node|
166 node.each do |k,v|
167 case k
168 when "calendar"
169 tag_list << "event"
170 when "pm"
171 tag_list << "pressemitteilung"
172 end
173 end
174 end
175
176 # Getting rid of duplicate flags
177 tag_list.uniq!
178
179 page.tag_list = tag_list.join(",")
180 page.save
181 end
182
183 def add_event_to_node node, chaospage
184 rrule = get_rrule(chaospage)
185
186 event_options = {
187 :start_time => get_start_time(chaospage),
188 :end_time => get_end_time(chaospage),
189 :allday => is_allday?(chaospage),
190 :rrule => rrule,
191 :custom_rrule => is_custom_rrule?(rrule),
192 :location => get_location(chaospage),
193 :url => get_url(chaospage),
194 :latitude => get_latitude(chaospage),
195 :longitude => get_logitude(chaospage)
196 }
197
198 unless tmp_event = node.event
199 tmp_event = Event.create! event_options.merge({:node_id => node.id})
200 else
201 tmp_event.update_attributes event_options
202 end
203 end
204
205 def get_start_time chaospage
206 chaospage.at("//ical:DTSTART").content || raise("DTSTART not found")
207 end
208
209 def get_end_time chaospage
210 dtstart = chaospage.at("//ical:DTSTART")
211 dtend = chaospage.at("//ical:DTEND")
212 duration = chaospage.at("//ical:DURATION")
213
214 if dtend
215 return dtend.content
216 elsif duration
217 parsed_duration = Ical_occurrences.duration_to_fixnum(duration.content)
218 return (dtstart.content.to_time + parsed_duration)
219 else
220 raise("Neiter DTEND nor DURATION found")
221 end
222 end
223
224 def is_allday? chaospage
225 !chaospage.at("//ical:DTSTART").[]("VALUE").nil?
226 end
227
228 def get_rrule chaospage
229 if rrule = chaospage.at("//ical:RRULE")
230 rrtxt = ''
231 rrule.children.each do |subrule|
232 rule_name = subrule.name
233 rule_content = subrule.content.sub(/\W/,'')
234
235 next if rule_content.blank?
236
237 rrtxt += "#{rule_name}=#{rule_content};"
238 end
239 rrtxt.chomp!(';')
240 rrtxt
241 else
242 nil
243 end
244 end
245
246 def is_custom_rrule? rrule
247 default_rules = [
248 "FREQ=WEEKLY;INTERVAL=1",
249 "FREQ=MONTHLY;INTERVAL=1",
250 "FREQ=YEARLY;INTERVAL=1"
251 ]
252
253 rrule && !default_rules.include?(rrule) ? true : false
254 end
255
256 def get_location chaospage
257 location = chaospage.at("//ical:LOCATION")
258 location ? location.content : nil
259 end
260
261 def get_url chaospage
262 location = chaospage.at("//ical:LOCATION")
263 location.[]("ALTREP") if location
264 end
265
266 def get_latitude chaospage
267 geo = chaospage.at("//ical:GEO")
268 geo.text.split(";")[0] if geo
269 end
270
271 def get_logitude chaospage
272 geo = chaospage.at("//ical:GEO")
273 geo.text.split(";")[1] if geo
274 end
275
276 def convert_to_html chaospage
277
278 chaospage.xpath('//paragraph').each {|sub| sub.name = "p"}
279 chaospage.xpath('//quote').each {|sub| sub.name = "em" }
280 chaospage.xpath('//subtitle').each {|sub| sub.name = "h3" }
281 chaospage.xpath('//strong').each {|sub| sub.name = "em" }
282 chaospage.xpath('//stronger').each {|sub| sub.name = "strong" }
283 chaospage.xpath('//chapter').each {|sub| sub.name = "h2" }
284
285 chaospage.xpath('//link').each do |sub|
286 sub.name = "a"
287 href = sub.[]("ref")
288 sub.remove_attribute("ref")
289 sub.[]=("href", href)
290 sub.remove_attribute("type")
291 end
292
293 chaospage.xpath('//list').each do |sub|
294 if !sub.css("row item").empty?
295 sub.name = "table"
296
297 sub.css("row").each {|x| x.name = "tr"}
298 sub.css("tr item").each {|x| x.name = "td"}
299 elsif !sub.css("item").empty?
300 sub.name = "ul"
301
302 sub.css("item").each {|x| x.name = "li"}
303 end
304 end
305
306 chaospage.xpath('//media').each do |sub|
307 sub.name = "img"
308 src = sub.[]("ref")
309 sub.remove_attribute("src")
310 sub.[]=("src", src)
311 unless sub.content
312 sub.[]=("alt", sub.content)
313 sub.xpath('//*').each {|x| x.remove}
314 end
315 end
316
317 chaospage.xpath('//name').each do |sub|
318 if sub.[]("email")
319 mail_href = "mailto:#{sub.[]('email')}"
320 sub.remove_attribute("email")
321 sub.[]=("href", mail_href)
322 end
323 sub.name = "a"
324
325 if href = sub.[]("ref")
326 sub.remove_attribute("ref")
327 sub.[]=("href", href)
328 end
329 end
330
331 chaospage
332
333 end
334end \ No newline at end of file
diff --git a/lib/chaos_xml.rb b/lib/chaos_xml.rb
deleted file mode 100644
index f36708a..0000000
--- a/lib/chaos_xml.rb
+++ /dev/null
@@ -1,159 +0,0 @@
1require 'iconv'
2require 'nokogiri'
3
4class ChaosXml
5 include Enumerable
6
7 def initialize path
8 unless Node.root
9 Node.create!
10 end
11
12 @path = path
13 @years = {}
14 end
15
16 def import_xml
17 unless @updates = Node.find_by_unique_name('updates')
18 @updates = Node.create!( :slug => 'updates' )
19 @updates.move_to_child_of Node.root
20 end
21
22 self.each do |chaospage, chaos_id, lang|
23 node = find_or_create_node( chaospage, chaos_id )
24 html = convert_to_html( chaospage )
25 page = fill_draft_with_content(node.draft, html, lang)
26 end
27 end
28
29 def each
30 directories = Dir.glob("#{@path}/*/*.xml{,.de,.en}")
31
32 directories.each do |path|
33 next if path =~ /index\.xml/
34 chaospage = Nokogiri::XML( File.new(path).read )
35 lang = lang_from_path( path )
36 chaos_id = chaos_id_from_path( path )
37
38 yield chaospage, chaos_id, lang
39 end
40 end
41
42 def lang_from_path path
43 case path
44 when /\.de$/ then :de
45 when /\.en$/ then :en
46 else
47 :de
48 end
49 end
50
51 def chaos_id_from_path path
52 path.sub(@path, "").split(/\//).last.split(/\./)[0]
53 end
54
55 def find_or_create_node chaospage, chaos_id
56
57 date = chaospage.xpath("//date").first.content.to_date
58 unique_name = "updates/#{date.year}/#{chaos_id}"
59 year = date.year
60
61 unique_name_array = unique_name.split("/")
62
63 unless @years[year] || (@years[year] = Node.find_by_unique_name("updates/#{year}"))
64 @years[year] = Node.create :slug => year
65 @years[year].move_to_child_of @updates
66 end
67
68 unless node = Node.find_by_unique_name(unique_name)
69 node = Node.create :slug => chaos_id
70 node.move_to_child_of @years[year]
71 end
72
73 node
74 end
75
76 def fill_draft_with_content draft, chaospage, lang
77 I18n.locale = lang
78
79 options = {
80 :title => chaospage.xpath("//title")[0].content,
81 :abstract => chaospage.xpath("//abstract")[0].content,
82 :body => extract_body(chaospage)
83 }
84
85 puts options.inspect
86 #draft.update_attributes options
87 end
88
89 def extract_body chaospage
90 body = ""
91 element = chaospage.xpath("//abstract")[0].next_sibling
92
93 while element do
94 body << element.to_s
95 element = element.next_sibling
96 end
97
98 puts body
99 end
100
101 def convert_to_html chaospage
102
103 chaospage.xpath('//paragraph').each {|sub| sub.name = "p"}
104 chaospage.xpath('//quote').each {|sub| sub.name = "blockquote" }
105 chaospage.xpath('//subtitle').each {|sub| sub.name = "h3" }
106 chaospage.xpath('//strong').each {|sub| sub.name = "em" }
107 chaospage.xpath('//stronger').each {|sub| sub.name = "strong" }
108 chaospage.xpath('//chapter').each {|sub| sub.name = "h2" }
109
110 chaospage.xpath('//link').each do |sub|
111 sub.name = "a"
112 href = sub.[]("ref")
113 sub.remove_attribute("ref")
114 sub.[]=("href", href)
115 sub.remove_attribute("type")
116 end
117
118 chaospage.xpath('//list').each do |sub|
119 if !sub.css("row item").empty?
120 sub.name = "table"
121
122 sub.css("row").each {|x| x.name = "tr"}
123 sub.css("tr item").each {|x| x.name = "td"}
124 elsif !sub.css("item").empty?
125 sub.name = "ul"
126
127 sub.css("item").each {|x| x.name = "li"}
128 end
129 end
130
131 chaospage.xpath('//media').each do |sub|
132 sub.name = "img"
133 src = sub.[]("ref")
134 sub.remove_attribute("src")
135 sub.[]=("src", src)
136 unless sub.content
137 sub.[]=("alt", sub.content)
138 sub.xpath('//*').each {|x| x.remove}
139 end
140 end
141
142 chaospage.xpath('//name').each do |sub|
143 if sub.[]("email")
144 mail_href = "mailto:#{sub.[]('email')}"
145 sub.remove_attribute("email")
146 sub.[]=("href", mail_href)
147 end
148 sub.name = "a"
149
150 if href = sub.[]("ref")
151 sub.remove_attribute("ref")
152 sub.[]=("href", href)
153 end
154 end
155
156 chaospage
157
158 end
159end \ No newline at end of file
diff --git a/lib/tasks/development_init.rake b/lib/tasks/development_init.rake
index 789cdf6..00ef83a 100644
--- a/lib/tasks/development_init.rake
+++ b/lib/tasks/development_init.rake
@@ -3,7 +3,12 @@ require 'csv'
3namespace :cccms do 3namespace :cccms do
4 4
5 desc "Setup everythin" 5 desc "Setup everythin"
6 task :setup_environment => [:create_admin_user, :import_updates, :create_home_page] do |t| 6 task :setup_environment => [
7 :create_admin_user,
8 :import_authors,
9 :import_updates,
10 :create_home_page
11 ] do |t|
7 12
8 end 13 end
9 14
@@ -19,30 +24,14 @@ namespace :cccms do
19 24
20 desc "Import the authors" 25 desc "Import the authors"
21 task :import_authors => :environment do |t| 26 task :import_authors => :environment do |t|
22 I18n.locale = :en 27 importer = AuthorsImporter.new("#{RAILS_ROOT}/db/authors.csv")
23 @parsed_file = CSV::Reader.parse(File.open("#{RAILS_ROOT}/db/authors.csv")) 28 importer.import_authors
24
25 @parsed_file.each_with_index do |row, index|
26 next if row[0].nil?
27
28 unless author = User.find_by_login(row[0])
29 puts "#{row[0]} >> #{row[2]}"
30 author = User.create!(
31 :login => row[0],
32 #:realname => row[1],
33 :email => row[2],
34 :password => "foobartrallala",
35 :password_confirmation => "foobartrallala"
36 )
37 end
38
39 end
40 end 29 end
41 30
42 desc "Import the old XML Files" 31 desc "Import the old XML Files"
43 task :import_updates => :environment do |t| 32 task :import_updates => :environment do |t|
44 i = UpdateImporter.new("#{RAILS_ROOT}/db/updates") 33 i = ChaosImporter.new("#{RAILS_ROOT}/db/updates")
45 i.import_xml 34 i.import_updates
46 end 35 end
47 36
48 desc "Create Home Page" 37 desc "Create Home Page"
diff --git a/test/unit/page_test.rb b/test/unit/page_test.rb
index 2ada6de..8c2fc95 100644
--- a/test/unit/page_test.rb
+++ b/test/unit/page_test.rb
@@ -121,7 +121,7 @@ class PageTest < ActiveSupport::TestCase
121 page.save 121 page.save
122 122
123 assert_equal 3, page.globalize_translations.size 123 assert_equal 3, page.globalize_translations.size
124 assert_equal 0, Page.find_with_outdated_translations.count 124 assert_equal 0, Page.find_with_outdated_translations.size
125 125
126 english = *page.globalize_translations.select {|x| x.locale == :en} 126 english = *page.globalize_translations.select {|x| x.locale == :en}
127 PageTranslation.record_timestamps = false 127 PageTranslation.record_timestamps = false