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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
|
-- This file is part of the LrMediaWiki project and distributed under the terms
-- of the MIT license (see LICENSE.txt file in the project root directory or
-- [0]). See [1] for more information about LrMediaWiki.
--
-- Copyright (C) 2014 by the LrMediaWiki team (see CREDITS.txt file in the
-- project root directory or [2])
--
-- [0] <https://raw.githubusercontent.com/ireas/LrMediaWiki/master/LICENSE.txt>
-- [1] <https://commons.wikimedia.org/wiki/Commons:LrMediaWiki>
-- [2] <https://raw.githubusercontent.com/ireas/LrMediaWiki/master/CREDITS.txt>
-- Code status:
-- doc: partly
-- i18n: complete
local LrErrors = import 'LrErrors'
local LrHttp = import 'LrHttp'
local LrPathUtils = import 'LrPathUtils'
local LrXml = import 'LrXml'
local Info = require 'Info'
local MediaWikiUtils = require 'MediaWikiUtils'
local MediaWikiApi = {
userAgent = string.format('LrMediaWiki %d.%d', Info.VERSION.major, Info.VERSION.minor),
apiPath = nil,
}
--- URL-encode a string according to RFC 3986.
-- Based on http://lua-users.org/wiki/StringRecipes
-- @param str the string to encode
-- @return the URL-encoded string
function MediaWikiApi.urlEncode(str)
if str then
str = string.gsub(str, '\n', '\r\n')
str = string.gsub (str, '([^%w %-%_%.%~])',
function(c) return string.format('%%%02X', string.byte(c)) end)
str = string.gsub(str, ' ', '+')
end
return str
end
--- Convert HTTP arguments to a URL-encoded request body.
-- @param arguments (table) the arguments to convert
-- @return (string) a request body created from the URL-encoded arguments
function MediaWikiApi.createRequestBody(arguments)
local body = nil
for key, value in pairs(arguments) do
if body then
body = body .. '&'
else
body = ''
end
body = body .. MediaWikiApi.urlEncode(key) .. '=' .. MediaWikiApi.urlEncode(value)
end
return body
end
function MediaWikiApi.parseXmlDom(xmlDomInstance)
local value = nil
if xmlDomInstance:type() == 'element' then
value = {}
for key, attribute in pairs(xmlDomInstance:attributes()) do
value[key] = attribute.value
end
for i = 1, xmlDomInstance:childCount() do
local child = xmlDomInstance:childAtIndex(i)
local childName = child:name()
if childName then
value[childName] = MediaWikiApi.parseXmlDom(child)
end
end
elseif xmlDomInstance:type() == 'text' then
value = xmlDomInstance:text()
end
return value
end
function MediaWikiApi.performRequest(arguments)
arguments.format = 'xml'
local requestBody = MediaWikiApi.createRequestBody(arguments)
local requestHeaders = {
{
field = 'User-Agent',
value = MediaWikiApi.userAgent,
},
{
field = 'Content-Type',
value = 'application/x-www-form-urlencoded',
},
}
MediaWikiUtils.trace('Performing API request');
MediaWikiUtils.trace('Request body:');
MediaWikiUtils.trace(requestBody);
local resultBody, resultHeaders = LrHttp.post(MediaWikiApi.apiPath, requestBody, requestHeaders)
MediaWikiUtils.trace('Result status:');
MediaWikiUtils.trace(resultHeaders.status);
if not resultHeaders.status then
LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/NoConnection=Cannot connect to the MediaWiki API.'))
elseif resultHeaders.status ~= 200 then
LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/HttpError=Received HTTP status ^1.', resultHeaders.status))
end
MediaWikiUtils.trace('Result body:');
MediaWikiUtils.trace(resultBody);
local resultXml = MediaWikiApi.parseXmlDom(LrXml.parseXml(resultBody))
if resultXml.error then
LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/MediaWikiError=The MediaWiki error ^1 occured: ^2', resultXml.error.code, resultXml.error.info))
end
return resultXml
end
function MediaWikiApi.login(username, password, token)
local arguments = {
action = 'login',
lgname = username,
lgpassword = password,
}
if token then
arguments.lgtoken = token
end
local xml = MediaWikiApi.performRequest(arguments)
local loginResult = xml.login.result
if loginResult == 'Success' then
return true
elseif not token and loginResult == 'NeedToken' then
return MediaWikiApi.login(username, password, xml.login.token)
end
return loginResult
end
function MediaWikiApi.getEditToken()
local arguments = {
action = 'tokens',
}
local xml = MediaWikiApi.performRequest(arguments)
return xml.tokens.edittoken
end
function MediaWikiApi.existsFile(fileName)
local arguments = {
action = 'query',
titles = 'File:' .. fileName,
}
local xml = MediaWikiApi.performRequest(arguments)
return xml.query and xml.query.pages and xml.query.pages.page and not xml.query.pages.page.missing
end
function MediaWikiApi.upload(fileName, sourceFilePath, text, comment, ignoreWarnings)
local sourceFileName = LrPathUtils.leafName(sourceFilePath)
local arguments = {
action = 'upload',
filename = fileName,
text = text,
comment = comment,
token = MediaWikiApi.getEditToken(),
format = 'xml',
}
if ignoreWarnings then
arguments.ignorewarnings = 'true'
end
local requestHeaders = {
{
field = 'User-Agent',
value = MediaWikiApi.userAgent,
},
}
local requestBody = {}
for key, value in pairs(arguments) do
requestBody[#requestBody + 1] = {
name = key,
value = value,
}
end
requestBody[#requestBody + 1] = {
name = 'file',
fileName = sourceFileName,
filePath = sourceFilePath,
contentType = 'application/octet-stream',
}
local resultBody, resultHeaders = LrHttp.postMultipart(MediaWikiApi.apiPath, requestBody, requestHeaders)
if resultHeaders.status ~= 200 then
LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/HttpError=Received HTTP status ^1.', resultHeaders.status))
end
local resultXml = MediaWikiApi.parseXmlDom(LrXml.parseXml(resultBody))
if resultXml.error then
LrErrors.throwUserError(LOC('$$$/LrMediaWiki/Api/MediaWikiError=The MediaWiki error ^1 occured: ^2', resultXml.error.code, resultXml.error.info))
end
local uploadResult = resultXml.upload.result
if uploadResult == 'Success' then
return true
elseif uploadResult == 'Warning' then
local warnings = ''
for pair in pairs(resultXml.upload.warnings) do
if warnings ~= '' then
warnings = warnings .. ', '
end
warnings = warnings .. pair[0]
end
return warnings
else
return uploadResult
end
end
return MediaWikiApi
|