/
migrateBlogEntries.groovy
151 lines (124 loc) · 4 KB
/
migrateBlogEntries.groovy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*
* This is a hacky script to convert blog_entry records in the grails.org
* database to content ones (or more specifically, NewsItem domain instances).
* You need to run it with:
*
* grails run-script migrateBlogEntries.groovy
*
* in whatever environment defines the database you want to migrate.
*
* The blog_entry records contain messy, messy HTML generated by a web rich
* text editor, whereas NewsItem uses gdoc wiki syntax. So, this script uses
* Jsoup to process the HTML, strip out the rubbish, and perform a simple
* conversion of content -> wiki syntax. It's pretty rough, but works well
* enough for most of the news items.
*/
@Grab(group="org.jsoup", module="jsoup", version="1.6.3")
import org.jsoup.Jsoup
import org.jsoup.nodes.Comment
import org.jsoup.nodes.Element
import org.jsoup.nodes.TextNode
import org.joda.time.DateTime
import groovy.sql.Sql
import org.grails.auth.User
import org.grails.news.NewsItem
def sql = new Sql(ctx.getBean("dataSource"))
authors = [:]
disableAutoTimestamping(new NewsItem())
println "Processing ${sql.firstRow('select count(*) from blog_entry')[0]} blog entries"
NewsItem.withNewSession {
sql.eachRow("SELECT * from blog_entry") { r ->
print "Processing item '${r.title}'"
new NewsItem(
author: getUser(r.author),
body: convertContent(r.body),
title: r.title,
dateCreated: new DateTime(r.date_created),
lastUpdated: new DateTime(r.last_updated),
status: "APPROVED").save(failOnError: true)
}
}
println "Done"
def disableAutoTimestamping(instance) {
def closureInterceptor = ctx.getBean("eventTriggeringInterceptor")
def datastore = closureInterceptor.datastores.values().iterator().next()
def interceptor = datastore.getEventTriggeringInterceptor()
def listener = interceptor.findEventListener(instance)
listener.shouldTimestamp = false
}
def getUser(username) {
def user = authors[username]
if (!user) {
user = User.findByLogin(username)
authors[username] = user
}
return user
}
def convertContent(content) {
def body = Jsoup.parseBodyFragment(content).body()
def conversionBuffer = new StringBuilder(content.size())
for (node in body.childNodes()) {
processNode node, conversionBuffer
}
return conversionBuffer.toString()
}
def processNode(Element element, conversionBuffer) {
switch (element.tagName()) {
case "span":
case "font":
for (node in element.childNodes()) {
processNode node, conversionBuffer
}
break
case "div":
case "p":
conversionBuffer << "\n"
for (node in element.childNodes()) {
processNode node, conversionBuffer
}
conversionBuffer << "\n"
break
case "ul":
conversionBuffer << "\n"
for (e in getLiChildren(element)) {
processListItem(e, conversionBuffer, "*")
}
conversionBuffer << "\n"
break
case "ol":
conversionBuffer << "\n"
for (e in getLiChildren(element)) {
processListItem(element, conversionBuffer, "#")
}
conversionBuffer << "\n"
break
case "a":
conversionBuffer << "[${element.text()}|${processLink(element.attr('href'))}]"
break
case "br":
conversionBuffer << "\n\n"
break
default:
break
}
}
def processNode(TextNode node, conversionBuffer) {
conversionBuffer << node.text()
}
def processNode(Comment node, conversionBuffer) {
// Ignore comments.
}
def processListItem(Element element, conversionBuffer, String prefix) {
conversionBuffer << prefix << " "
for (node in element.childNodes()) {
processNode node, conversionBuffer
}
conversionBuffer << "\n"
}
def getLiChildren(Element e) {
return e.children().findAll { it.tagName() == "li" }
}
def processLink(link) {
if (link.startsWith('/')) return "http://grails.org" + link
else return link
}