Redmine の wiki を、HTTP のクライアントプログラムで更新する方法を考えてみた。言語は何でもいいが、ここでは Groovy を使ってみた。
====
例えば、以下のようなコードで、
class Test {
def static content = """\
h1. 大見出し
なんとかこんとか
${ new Date().toString() }
"""
public static void main(args) {
new RedmineWikiRewriter()
.login("user001", "password")
.startEdit("project001", "Http_post_test")
.saveEdit(content)
}
}下の画像のように、wiki ページが更新されるような クラス RedmineWikiRewriter を考えてみる。
- login() では、与えられたユーザ名とパスワードでログインして、Redmine から返されるクッキーを保持する。
- startEdit()は、指定のプロジェクトの指定の wiki ページを開く。これはページのバージョンを得るために必要
- saveEdit()は、wiki コンテンツをマルチパートの HTTP POST で送信する
class RedmineWikiRewriter {
def static UTF8 = Charset.forName("UTF-8")
def HTTPBuilder http = new HTTPBuilder('http://localhost:3000/')
def redmineSession
def authenticityToken
def contentVersion
def project
def wikiEntry
public RedmineWikiRewriter login(String username, String password) {
http.get(path : '/login', query : [q:'Groovy'] ) { resp, reader ->
authenticityToken = reader.BODY.DIV.DIV
.findAll { it.id="login-form" }.depthFirst()
.grep { "authenticity_token"== it.@name.toString() }[0]
.@value.toString()
}
http.request(POST) {
uri.path = '/login'
send URLENC, [
username:username, password:password,
authenticity_token:authenticityToken]
response.success = { resp ->
redmineSession = resp.getAllHeaders()
.find {"Set-Cookie"==it.name.toString()}
.value.split(";")
.find {it.toString().startsWith("_redmine_session")}
}
}
this
}
RedmineWikiRewriter startEdit(String project, String wikiEntry) {
this.project = project
this.wikiEntry = wikiEntry
http.request(GET) { resp ->
uri.path = "/projects/"+project+"/wiki/" + wikiEntry + "/edit"
headers.'Cookie' = redmineSession
response.success = { res, reader ->
contentVersion = reader
.depthFirst()
.grep{"content_version"==it.@id.toString() }[0]
.@value.toString()
}
}
this
}
void saveEdit(String content) {
DefaultHttpClient httpclient = new DefaultHttpClient();
def uri = "http://localhost:3000/projects/"+ project +"/wiki/" + wikiEntry
HttpPost httppost = new HttpPost(uri)
httppost.addHeader('Cookie', redmineSession)
MultipartEntity mpe = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE,
"----WebKitFormBoundaryfmexSJQ5daIXdA04",
UTF8);
addPart(mpe, "commit", "Save");
addPart(mpe, "project_id", project);
addPart(mpe, "action", "update");
addPart(mpe, "_method", "put");
addPart(mpe, "authenticity_token", authenticityToken)
addPart(mpe, "id", wikiEntry)
addPart(mpe, "content[text]", content)
addPart(mpe, "content[version]", contentVersion)
addPart(mpe, "controller", "wiki")
httppost.setEntity(mpe);
httpclient.execute(httppost);
}
static void addPart(MultipartEntity entity, String name, String value) {
entity.addPart(name, new StringBody(value, UTF8));
}
}
■ 振り返り
- saveEdit() でも HttpBuilder を使いたかったが、なぜか思うように動かない。仕方なく、DefaultHttpClient を使用
- wiki エントリの新規作成でも動くかどうかは未確認
- たかだかこれくらいのコードでも、やってみると予想外に難しい。Redmine の Rubyコードを読んだり、HTTP の Header を調べたりいろいろ手間がかかった。あと multipart の POST も意外と難しい
- 仕組みはだいたい分かったので、他の言語でも試してみたい。もともとやりたかったのは、Excel 上の VBA からデータを整形して wiki に載せるというのを自動化すると言う事だった。

0 件のコメント:
コメントを投稿