Fix mod store rating
[oweals/minetest.git] / src / convert_json.cpp
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program 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
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 #include <vector>
21 #include <iostream>
22 #include <sstream>
23
24 #include "convert_json.h"
25 #include "mods.h"
26 #include "config.h"
27 #include "log.h"
28 #include "settings.h"
29 #include "httpfetch.h"
30 #include "porting.h"
31
32 Json::Value fetchJsonValue(const std::string &url,
33                 std::vector<std::string> *extra_headers)
34 {
35         HTTPFetchRequest fetch_request;
36         HTTPFetchResult fetch_result;
37         fetch_request.url = url;
38         fetch_request.caller = HTTPFETCH_SYNC;
39
40         if (extra_headers != NULL)
41                 fetch_request.extra_headers = *extra_headers;
42
43         httpfetch_sync(fetch_request, fetch_result);
44
45         if (!fetch_result.succeeded) {
46                 return Json::Value();
47         }
48         Json::Value root;
49         Json::Reader reader;
50         std::istringstream stream(fetch_result.data);
51
52         if (!reader.parse(stream, root)) {
53                 errorstream << "URL: " << url << std::endl;
54                 errorstream << "Failed to parse json data " << reader.getFormattedErrorMessages();
55                 errorstream << "data: \"" << fetch_result.data << "\"" << std::endl;
56                 return Json::Value();
57         }
58
59         return root;
60 }
61
62 std::vector<ModStoreMod>    readModStoreList(Json::Value& modlist) {
63                 std::vector<ModStoreMod> retval;
64
65         if (modlist.isArray()) {
66                 for (unsigned int i = 0; i < modlist.size(); i++)
67                 {
68                         ModStoreMod toadd;
69                         toadd.valid = true;
70
71                         //id
72                         if (modlist[i]["id"].asString().size()) {
73                                 std::string id_raw = modlist[i]["id"].asString();
74                                 char* endptr = 0;
75                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
76
77                                 if ((id_raw != "") && (*endptr == 0)) {
78                                         toadd.id = numbervalue;
79                                 }
80                                 else {
81                                         errorstream << "readModStoreList: missing id" << std::endl;
82                                         toadd.valid = false;
83                                 }
84                         }
85                         else {
86                                 errorstream << "readModStoreList: missing id" << std::endl;
87                                 toadd.valid = false;
88                         }
89
90                         //title
91                         if (modlist[i]["title"].asString().size()) {
92                                 toadd.title = modlist[i]["title"].asString();
93                         }
94                         else {
95                                 errorstream << "readModStoreList: missing title" << std::endl;
96                                 toadd.valid = false;
97                         }
98
99                         //basename
100                         if (modlist[i]["basename"].asString().size()) {
101                                 toadd.basename = modlist[i]["basename"].asString();
102                         }
103                         else {
104                                 errorstream << "readModStoreList: missing basename" << std::endl;
105                                 toadd.valid = false;
106                         }
107
108                         //author
109
110                         //rating
111
112                         //version
113
114                         if (toadd.valid) {
115                                 retval.push_back(toadd);
116                         }
117                 }
118         }
119         return retval;
120 }
121
122 ModStoreModDetails          readModStoreModDetails(Json::Value& details) {
123
124         ModStoreModDetails retval;
125
126         retval.valid = true;
127
128         //version set
129         if (details["version_set"].isArray()) {
130                 for (unsigned int i = 0; i < details["version_set"].size(); i++)
131                 {
132                         ModStoreVersionEntry toadd;
133
134                         if (details["version_set"][i]["id"].asString().size()) {
135                                 std::string id_raw = details["version_set"][i]["id"].asString();
136                                 char* endptr = 0;
137                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
138
139                                 if ((id_raw != "") && (*endptr == 0)) {
140                                         toadd.id = numbervalue;
141                                 }
142                         }
143                         else {
144                                 errorstream << "readModStoreModDetails: missing version_set id" << std::endl;
145                                 retval.valid = false;
146                         }
147
148                         //date
149                         if (details["version_set"][i]["date"].asString().size()) {
150                                 toadd.date = details["version_set"][i]["date"].asString();
151                         }
152
153                         //file
154                         if (details["version_set"][i]["file"].asString().size()) {
155                                 toadd.file = details["version_set"][i]["file"].asString();
156                         }
157                         else {
158                                 errorstream << "readModStoreModDetails: missing version_set file" << std::endl;
159                                 retval.valid = false;
160                         }
161
162                         //approved
163
164                         //mtversion
165
166                         if( retval.valid ) {
167                                 retval.versions.push_back(toadd);
168                         }
169                         else {
170                                 break;
171                         }
172                 }
173         }
174
175         if (retval.versions.size() < 1) {
176                 infostream << "readModStoreModDetails: not a single version specified!" << std::endl;
177                 retval.valid = false;
178         }
179
180         //categories
181         if (details["categories"].isObject()) {
182                 for (unsigned int i = 0; i < details["categories"].size(); i++) {
183                         ModStoreCategoryInfo toadd;
184
185                         if (details["categories"][i]["id"].asString().size()) {
186
187                                 std::string id_raw = details["categories"][i]["id"].asString();
188                                 char* endptr = 0;
189                                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
190
191                                 if ((id_raw != "") && (*endptr == 0)) {
192                                         toadd.id = numbervalue;
193                                 }
194                         }
195                         else {
196                                 errorstream << "readModStoreModDetails: missing categories id" << std::endl;
197                                 retval.valid = false;
198                         }
199                         if (details["categories"][i]["title"].asString().size()) {
200                                 toadd.name = details["categories"][i]["title"].asString();
201                         }
202                         else {
203                                 errorstream << "readModStoreModDetails: missing categories title" << std::endl;
204                                 retval.valid = false;
205                         }
206
207                         if( retval.valid ) {
208                                 retval.categories.push_back(toadd);
209                         }
210                         else {
211                                 break;
212                         }
213                 }
214         }
215
216         //author
217         if (details["author"].isObject()) {
218                 if (details["author"]["id"].asString().size()) {
219
220                         std::string id_raw = details["author"]["id"].asString();
221                         char* endptr = 0;
222                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
223
224                         if ((id_raw != "") && (*endptr == 0)) {
225                                 retval.author.id = numbervalue;
226                         }
227                         else {
228                                 errorstream << "readModStoreModDetails: missing author id (convert)" << std::endl;
229                                 retval.valid = false;
230                         }
231                 }
232                 else {
233                         errorstream << "readModStoreModDetails: missing author id" << std::endl;
234                         retval.valid = false;
235                 }
236
237                 if (details["author"]["username"].asString().size()) {
238                         retval.author.username = details["author"]["username"].asString();
239                 }
240                 else {
241                         errorstream << "readModStoreModDetails: missing author username" << std::endl;
242                         retval.valid = false;
243                 }
244         }
245         else {
246                 errorstream << "readModStoreModDetails: missing author" << std::endl;
247                 retval.valid = false;
248         }
249
250         //license
251         if (details["license"].isObject()) {
252                 if (details["license"]["id"].asString().size()) {
253
254                         std::string id_raw = details["license"]["id"].asString();
255                         char* endptr = 0;
256                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
257
258                         if ((id_raw != "") && (*endptr == 0)) {
259                                 retval.license.id = numbervalue;
260                         }
261                 }
262                 else {
263                         errorstream << "readModStoreModDetails: missing license id" << std::endl;
264                         retval.valid = false;
265                 }
266
267                 if (details["license"]["short"].asString().size()) {
268                         retval.license.shortinfo = details["license"]["short"].asString();
269                 }
270                 else {
271                         errorstream << "readModStoreModDetails: missing license short" << std::endl;
272                         retval.valid = false;
273                 }
274
275                 if (details["license"]["link"].asString().size()) {
276                         retval.license.url = details["license"]["link"].asString();
277                 }
278
279         }
280
281         //titlepic
282         if (details["titlepic"].isObject()) {
283                 if (details["titlepic"]["id"].asString().size()) {
284
285                         std::string id_raw = details["titlepic"]["id"].asString();
286                         char* endptr = 0;
287                         int numbervalue = strtol(id_raw.c_str(),&endptr,10);
288
289                         if ((id_raw != "") && (*endptr == 0)) {
290                                 retval.titlepic.id = numbervalue;
291                         }
292                 }
293
294                 if (details["titlepic"]["file"].asString().size()) {
295                         retval.titlepic.file = details["titlepic"]["file"].asString();
296                 }
297
298                 if (details["titlepic"]["desc"].asString().size()) {
299                         retval.titlepic.description = details["titlepic"]["desc"].asString();
300                 }
301
302                 if (details["titlepic"]["mod"].asString().size()) {
303
304                         std::string mod_raw = details["titlepic"]["mod"].asString();
305                         char* endptr = 0;
306                         int numbervalue = strtol(mod_raw.c_str(),&endptr,10);
307
308                         if ((mod_raw != "") && (*endptr == 0)) {
309                                 retval.titlepic.mod = numbervalue;
310                         }
311                 }
312         }
313
314         //id
315         if (details["id"].asString().size()) {
316
317                 std::string id_raw = details["id"].asString();
318                 char* endptr = 0;
319                 int numbervalue = strtol(id_raw.c_str(),&endptr,10);
320
321                 if ((id_raw != "") && (*endptr == 0)) {
322                         retval.id = numbervalue;
323                 }
324         }
325         else {
326                 errorstream << "readModStoreModDetails: missing id" << std::endl;
327                 retval.valid = false;
328         }
329
330         //title
331         if (details["title"].asString().size()) {
332                 retval.title = details["title"].asString();
333         }
334         else {
335                 errorstream << "readModStoreModDetails: missing title" << std::endl;
336                 retval.valid = false;
337         }
338
339         //basename
340         if (details["basename"].asString().size()) {
341                 retval.basename = details["basename"].asString();
342         }
343         else {
344                 errorstream << "readModStoreModDetails: missing basename" << std::endl;
345                 retval.valid = false;
346         }
347
348         //description
349         if (details["desc"].asString().size()) {
350                 retval.description = details["desc"].asString();
351         }
352
353         //repository
354         if (details["replink"].asString().size()) {
355                 retval.repository = details["replink"].asString();
356         }
357
358         //value
359         if (details["value"].isInt()) {
360                 retval.rating = details["value"].asInt();
361         } else {
362                 retval.rating = 0;
363         }
364
365         //depends
366         if (details["depends"].isArray()) {
367                 //TODO
368         }
369
370         //softdepends
371         if (details["softdep"].isArray()) {
372                 //TODO
373         }
374
375         //screenshot url
376         if (details["screenshot_url"].asString().size()) {
377                 retval.screenshot_url = details["screenshot_url"].asString();
378         }
379
380         return retval;
381 }