Fossil SCM
add support for fetching text file content and checkin history via /artifact json request
Commit
3d1d139a7a0f9519d4e67086c9cc8daf7b46e32d
Parent
ebb0c04749499c3…
1 file changed
+98
-1
+98
-1
| --- src/json_artifact.c | ||
| +++ src/json_artifact.c | ||
| @@ -203,16 +203,109 @@ | ||
| 203 | 203 | /* |
| 204 | 204 | ** Internal mapping of /json/artifact/FOO commands/callbacks. |
| 205 | 205 | */ |
| 206 | 206 | static ArtifactDispatchEntry ArtifactDispatchList[] = { |
| 207 | 207 | {"checkin", json_artifact_ci}, |
| 208 | +{"file", json_artifact_file}, | |
| 208 | 209 | {"tag", NULL}, |
| 209 | 210 | {"ticket", json_artifact_ticket}, |
| 210 | -{"wiki", NULL}, | |
| 211 | +{"wiki", json_artifact_wiki}, | |
| 211 | 212 | /* Final entry MUST have a NULL name. */ |
| 212 | 213 | {NULL,NULL} |
| 213 | 214 | }; |
| 215 | + | |
| 216 | +cson_value * json_artifact_wiki(int rid){ | |
| 217 | + Manifest *pWiki = 0; | |
| 218 | + char *zBody = NULL; | |
| 219 | + char const *zPageName = NULL; | |
| 220 | + cson_value * payV = NULL; | |
| 221 | + cson_object * pay = NULL; | |
| 222 | + | |
| 223 | + payV = cson_value_new_object(); | |
| 224 | + pay = cson_value_get_object(payV); | |
| 225 | + | |
| 226 | + zPageName = db_text(0, "SELECT tagname FROM tag" | |
| 227 | + " WHERE tagid=(SELECT tagid FROM tagxref WHERE rid=%d)", rid); | |
| 228 | + | |
| 229 | + pWiki = manifest_get(rid, CFTYPE_WIKI); | |
| 230 | + if( pWiki ){ | |
| 231 | + zBody = pWiki->zWiki; | |
| 232 | + } | |
| 233 | + | |
| 234 | + cson_object_set(pay, "name", json_new_string(zPageName)); | |
| 235 | + cson_object_set(pay, "body", json_new_string(zBody)); | |
| 236 | + return payV; | |
| 237 | +} | |
| 238 | + | |
| 239 | +cson_value * json_artifact_file(int rid){ | |
| 240 | + cson_value * payV = NULL; | |
| 241 | + cson_object * pay = NULL; | |
| 242 | + const char *zMime; | |
| 243 | + const char *zRaw; | |
| 244 | + Blob content; | |
| 245 | + Stmt q; | |
| 246 | + | |
| 247 | + payV = cson_value_new_object(); | |
| 248 | + pay = cson_value_get_object(payV); | |
| 249 | + | |
| 250 | + content_get(rid, &content); | |
| 251 | + zMime = mimetype_from_content(&content); | |
| 252 | + | |
| 253 | + if (!zMime){ | |
| 254 | + cson_array * checkin_arr = NULL; | |
| 255 | + cson_value * checkin_list = NULL; | |
| 256 | + | |
| 257 | + cson_value * checkinV = NULL; | |
| 258 | + cson_object * checkin = NULL; | |
| 259 | + | |
| 260 | + zRaw = blob_str(&content); | |
| 261 | + checkin_list = cson_value_new_array(); | |
| 262 | + | |
| 263 | + cson_object_set(pay, "content", json_new_string(zRaw)); | |
| 264 | + cson_object_set(pay, "checkins", checkin_list); | |
| 265 | + | |
| 266 | + checkin_arr = cson_value_get_array(checkin_list); | |
| 267 | + | |
| 268 | + db_prepare(&q, | |
| 269 | + "SELECT filename.name, datetime(event.mtime)," | |
| 270 | + " coalesce(event.ecomment,event.comment)," | |
| 271 | + " coalesce(event.euser,event.user)," | |
| 272 | + " b.uuid, mlink.mperm," | |
| 273 | + " coalesce((SELECT value FROM tagxref" | |
| 274 | + " WHERE tagid=%d AND tagtype>0 AND rid=mlink.mid),'trunk')" | |
| 275 | + " FROM mlink, filename, event, blob a, blob b" | |
| 276 | + " WHERE filename.fnid=mlink.fnid" | |
| 277 | + " AND event.objid=mlink.mid" | |
| 278 | + " AND a.rid=mlink.fid" | |
| 279 | + " AND b.rid=mlink.mid" | |
| 280 | + " AND mlink.fid=%d" | |
| 281 | + " ORDER BY filename.name, event.mtime", | |
| 282 | + TAG_BRANCH, rid | |
| 283 | + ); | |
| 284 | + | |
| 285 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 286 | + const char *zName = db_column_text(&q, 0); | |
| 287 | + const char *zDate = db_column_text(&q, 1); | |
| 288 | + const char *zCom = db_column_text(&q, 2); | |
| 289 | + const char *zUser = db_column_text(&q, 3); | |
| 290 | + const char *zVers = db_column_text(&q, 4); | |
| 291 | + | |
| 292 | + checkinV = cson_value_new_object(); | |
| 293 | + checkin = cson_value_get_object(checkinV); | |
| 294 | + | |
| 295 | + cson_object_set(checkin, "name", json_new_string(zName)); | |
| 296 | + cson_object_set(checkin, "date", json_new_string(zDate)); | |
| 297 | + cson_object_set(checkin, "comment", json_new_string(zCom)); | |
| 298 | + cson_object_set(checkin, "user", json_new_string(zUser)); | |
| 299 | + cson_object_set(checkin, "version", json_new_string(zVers)); | |
| 300 | + | |
| 301 | + cson_array_append(checkin_arr, checkinV); | |
| 302 | + } | |
| 303 | + db_finalize(&q); | |
| 304 | + } | |
| 305 | + return payV; | |
| 306 | +} | |
| 214 | 307 | |
| 215 | 308 | /* |
| 216 | 309 | ** Impl of /json/artifact. This basically just determines the type of |
| 217 | 310 | ** an artifact and forwards the real work to another function. |
| 218 | 311 | */ |
| @@ -260,10 +353,11 @@ | ||
| 260 | 353 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); |
| 261 | 354 | if(0==rid){ |
| 262 | 355 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 263 | 356 | goto error; |
| 264 | 357 | } |
| 358 | + | |
| 265 | 359 | if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) |
| 266 | 360 | || db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) |
| 267 | 361 | || db_exists("SELECT 1 FROM plink WHERE pid=%d", rid)){ |
| 268 | 362 | zType = "checkin"; |
| 269 | 363 | goto handle_entry; |
| @@ -272,10 +366,13 @@ | ||
| 272 | 366 | zType = "wiki"; |
| 273 | 367 | goto handle_entry; |
| 274 | 368 | }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" |
| 275 | 369 | " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){ |
| 276 | 370 | zType = "ticket"; |
| 371 | + goto handle_entry; | |
| 372 | + }else if ( db_exists("SELECT 1 FROM mlink WHERE fid = %d", rid) ){ | |
| 373 | + zType = "file"; | |
| 277 | 374 | goto handle_entry; |
| 278 | 375 | }else{ |
| 279 | 376 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 280 | 377 | goto error; |
| 281 | 378 | } |
| 282 | 379 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -203,16 +203,109 @@ | |
| 203 | /* |
| 204 | ** Internal mapping of /json/artifact/FOO commands/callbacks. |
| 205 | */ |
| 206 | static ArtifactDispatchEntry ArtifactDispatchList[] = { |
| 207 | {"checkin", json_artifact_ci}, |
| 208 | {"tag", NULL}, |
| 209 | {"ticket", json_artifact_ticket}, |
| 210 | {"wiki", NULL}, |
| 211 | /* Final entry MUST have a NULL name. */ |
| 212 | {NULL,NULL} |
| 213 | }; |
| 214 | |
| 215 | /* |
| 216 | ** Impl of /json/artifact. This basically just determines the type of |
| 217 | ** an artifact and forwards the real work to another function. |
| 218 | */ |
| @@ -260,10 +353,11 @@ | |
| 260 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); |
| 261 | if(0==rid){ |
| 262 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 263 | goto error; |
| 264 | } |
| 265 | if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) |
| 266 | || db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) |
| 267 | || db_exists("SELECT 1 FROM plink WHERE pid=%d", rid)){ |
| 268 | zType = "checkin"; |
| 269 | goto handle_entry; |
| @@ -272,10 +366,13 @@ | |
| 272 | zType = "wiki"; |
| 273 | goto handle_entry; |
| 274 | }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" |
| 275 | " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){ |
| 276 | zType = "ticket"; |
| 277 | goto handle_entry; |
| 278 | }else{ |
| 279 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 280 | goto error; |
| 281 | } |
| 282 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -203,16 +203,109 @@ | |
| 203 | /* |
| 204 | ** Internal mapping of /json/artifact/FOO commands/callbacks. |
| 205 | */ |
| 206 | static ArtifactDispatchEntry ArtifactDispatchList[] = { |
| 207 | {"checkin", json_artifact_ci}, |
| 208 | {"file", json_artifact_file}, |
| 209 | {"tag", NULL}, |
| 210 | {"ticket", json_artifact_ticket}, |
| 211 | {"wiki", json_artifact_wiki}, |
| 212 | /* Final entry MUST have a NULL name. */ |
| 213 | {NULL,NULL} |
| 214 | }; |
| 215 | |
| 216 | cson_value * json_artifact_wiki(int rid){ |
| 217 | Manifest *pWiki = 0; |
| 218 | char *zBody = NULL; |
| 219 | char const *zPageName = NULL; |
| 220 | cson_value * payV = NULL; |
| 221 | cson_object * pay = NULL; |
| 222 | |
| 223 | payV = cson_value_new_object(); |
| 224 | pay = cson_value_get_object(payV); |
| 225 | |
| 226 | zPageName = db_text(0, "SELECT tagname FROM tag" |
| 227 | " WHERE tagid=(SELECT tagid FROM tagxref WHERE rid=%d)", rid); |
| 228 | |
| 229 | pWiki = manifest_get(rid, CFTYPE_WIKI); |
| 230 | if( pWiki ){ |
| 231 | zBody = pWiki->zWiki; |
| 232 | } |
| 233 | |
| 234 | cson_object_set(pay, "name", json_new_string(zPageName)); |
| 235 | cson_object_set(pay, "body", json_new_string(zBody)); |
| 236 | return payV; |
| 237 | } |
| 238 | |
| 239 | cson_value * json_artifact_file(int rid){ |
| 240 | cson_value * payV = NULL; |
| 241 | cson_object * pay = NULL; |
| 242 | const char *zMime; |
| 243 | const char *zRaw; |
| 244 | Blob content; |
| 245 | Stmt q; |
| 246 | |
| 247 | payV = cson_value_new_object(); |
| 248 | pay = cson_value_get_object(payV); |
| 249 | |
| 250 | content_get(rid, &content); |
| 251 | zMime = mimetype_from_content(&content); |
| 252 | |
| 253 | if (!zMime){ |
| 254 | cson_array * checkin_arr = NULL; |
| 255 | cson_value * checkin_list = NULL; |
| 256 | |
| 257 | cson_value * checkinV = NULL; |
| 258 | cson_object * checkin = NULL; |
| 259 | |
| 260 | zRaw = blob_str(&content); |
| 261 | checkin_list = cson_value_new_array(); |
| 262 | |
| 263 | cson_object_set(pay, "content", json_new_string(zRaw)); |
| 264 | cson_object_set(pay, "checkins", checkin_list); |
| 265 | |
| 266 | checkin_arr = cson_value_get_array(checkin_list); |
| 267 | |
| 268 | db_prepare(&q, |
| 269 | "SELECT filename.name, datetime(event.mtime)," |
| 270 | " coalesce(event.ecomment,event.comment)," |
| 271 | " coalesce(event.euser,event.user)," |
| 272 | " b.uuid, mlink.mperm," |
| 273 | " coalesce((SELECT value FROM tagxref" |
| 274 | " WHERE tagid=%d AND tagtype>0 AND rid=mlink.mid),'trunk')" |
| 275 | " FROM mlink, filename, event, blob a, blob b" |
| 276 | " WHERE filename.fnid=mlink.fnid" |
| 277 | " AND event.objid=mlink.mid" |
| 278 | " AND a.rid=mlink.fid" |
| 279 | " AND b.rid=mlink.mid" |
| 280 | " AND mlink.fid=%d" |
| 281 | " ORDER BY filename.name, event.mtime", |
| 282 | TAG_BRANCH, rid |
| 283 | ); |
| 284 | |
| 285 | while( db_step(&q)==SQLITE_ROW ){ |
| 286 | const char *zName = db_column_text(&q, 0); |
| 287 | const char *zDate = db_column_text(&q, 1); |
| 288 | const char *zCom = db_column_text(&q, 2); |
| 289 | const char *zUser = db_column_text(&q, 3); |
| 290 | const char *zVers = db_column_text(&q, 4); |
| 291 | |
| 292 | checkinV = cson_value_new_object(); |
| 293 | checkin = cson_value_get_object(checkinV); |
| 294 | |
| 295 | cson_object_set(checkin, "name", json_new_string(zName)); |
| 296 | cson_object_set(checkin, "date", json_new_string(zDate)); |
| 297 | cson_object_set(checkin, "comment", json_new_string(zCom)); |
| 298 | cson_object_set(checkin, "user", json_new_string(zUser)); |
| 299 | cson_object_set(checkin, "version", json_new_string(zVers)); |
| 300 | |
| 301 | cson_array_append(checkin_arr, checkinV); |
| 302 | } |
| 303 | db_finalize(&q); |
| 304 | } |
| 305 | return payV; |
| 306 | } |
| 307 | |
| 308 | /* |
| 309 | ** Impl of /json/artifact. This basically just determines the type of |
| 310 | ** an artifact and forwards the real work to another function. |
| 311 | */ |
| @@ -260,10 +353,11 @@ | |
| 353 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zUuid); |
| 354 | if(0==rid){ |
| 355 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 356 | goto error; |
| 357 | } |
| 358 | |
| 359 | if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) |
| 360 | || db_exists("SELECT 1 FROM plink WHERE cid=%d", rid) |
| 361 | || db_exists("SELECT 1 FROM plink WHERE pid=%d", rid)){ |
| 362 | zType = "checkin"; |
| 363 | goto handle_entry; |
| @@ -272,10 +366,13 @@ | |
| 366 | zType = "wiki"; |
| 367 | goto handle_entry; |
| 368 | }else if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)" |
| 369 | " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){ |
| 370 | zType = "ticket"; |
| 371 | goto handle_entry; |
| 372 | }else if ( db_exists("SELECT 1 FROM mlink WHERE fid = %d", rid) ){ |
| 373 | zType = "file"; |
| 374 | goto handle_entry; |
| 375 | }else{ |
| 376 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 377 | goto error; |
| 378 | } |
| 379 |