Fossil SCM
Started adding artifact-type-dependent result data to /json/artifact output.
Commit
a893fff3ca2fb9f0cbc3bd80674939d3e41ad5a1
Parent
6ee6486e02c584f…
1 file changed
+141
-2
+141
-2
| --- src/json_artifact.c | ||
| +++ src/json_artifact.c | ||
| @@ -4,10 +4,134 @@ | ||
| 4 | 4 | |
| 5 | 5 | #if INTERFACE |
| 6 | 6 | #include "json_detail.h" |
| 7 | 7 | #endif |
| 8 | 8 | |
| 9 | +/* | |
| 10 | +** Internal callback for /json/artifact handlers. rid and uid refer to | |
| 11 | +** the rid/uid of a given type of artifact, and each callback is | |
| 12 | +** specialized to return a JSON form of one type of artifact. | |
| 13 | +*/ | |
| 14 | +typedef cson_value * (*artifact_f)( int rid, char const * uid ); | |
| 15 | + | |
| 16 | +typedef struct ArtifactDispatchEntry { | |
| 17 | + /** | |
| 18 | + Artifact type name, e.g. "checkin". | |
| 19 | + */ | |
| 20 | + char const * name; | |
| 21 | + /** | |
| 22 | + JSON construction callback. | |
| 23 | + */ | |
| 24 | + artifact_f func; | |
| 25 | + /** | |
| 26 | + Must return true if g.perm has the proper permissions to fetch | |
| 27 | + this info, else false. If it returns false, func() is skipped | |
| 28 | + (producing no extra payload output). | |
| 29 | + */ | |
| 30 | + char (*permCheck)(); | |
| 31 | +} ArtifactDispatchEntry; | |
| 32 | + | |
| 33 | + | |
| 34 | +/* | |
| 35 | +** Generates an artifact Object for the given rid/zUuid. rid | |
| 36 | +** must refer to a Checkin. | |
| 37 | +** | |
| 38 | +** | |
| 39 | +** TODO: consolidate the result structure (and its generation) with | |
| 40 | +** /json/timeline/ci. | |
| 41 | +*/ | |
| 42 | +static cson_value * json_artifact_ci( int rid, char const * zUuid ){ | |
| 43 | + cson_value * v = cson_value_new_object(); | |
| 44 | + cson_object * o = cson_value_get_object(v); | |
| 45 | + char const * zParent = NULL; | |
| 46 | + Stmt q; | |
| 47 | + assert( NULL != zUuid ); | |
| 48 | + cson_object_set(o,"isLeaf", cson_value_new_bool(is_a_leaf(rid))); | |
| 49 | + zParent = db_text(0, | |
| 50 | + "SELECT uuid FROM plink, blob" | |
| 51 | + " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", | |
| 52 | + rid | |
| 53 | + ); | |
| 54 | + | |
| 55 | + db_prepare(&q, | |
| 56 | + "SELECT uuid, mtime, user, comment," | |
| 57 | + " omtime" | |
| 58 | + " FROM blob, event" | |
| 59 | + " WHERE blob.rid=%d" | |
| 60 | + " AND event.objid=%d", | |
| 61 | + rid, rid | |
| 62 | + ); | |
| 63 | + if( db_step(&q)==SQLITE_ROW ){ | |
| 64 | + /*const char *zUuid = db_column_text(&q, 0);*/ | |
| 65 | + char * zTmp; | |
| 66 | + const char *zUser; | |
| 67 | + const char *zComment; | |
| 68 | + char * zEUser, * zEComment; | |
| 69 | + int mtime, omtime; | |
| 70 | + cson_value * fileList = NULL; | |
| 71 | +#define SET(K,V) cson_object_set(o,(K), (V)) | |
| 72 | + SET("uuid",json_new_string(zUuid)); | |
| 73 | + zUser = db_column_text(&q,2); | |
| 74 | + SET("user",json_new_string(zUser)); | |
| 75 | + zEUser = db_text(0, | |
| 76 | + "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d", | |
| 77 | + TAG_USER, rid); | |
| 78 | + if(zEUser){ | |
| 79 | + SET("editedBy", json_new_string(zEUser)); | |
| 80 | + free(zEUser); | |
| 81 | + } | |
| 82 | + | |
| 83 | + zComment = db_column_text(&q,3); | |
| 84 | + SET("comment",json_new_string(zComment)); | |
| 85 | + zEComment = db_text(0, | |
| 86 | + "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d", | |
| 87 | + TAG_COMMENT, rid); | |
| 88 | + if(zEComment){ | |
| 89 | + SET("editedComment", json_new_string(zEComment)); | |
| 90 | + free(zEComment); | |
| 91 | + } | |
| 92 | + | |
| 93 | + mtime = db_column_int(&q,1); | |
| 94 | + SET("mtime",json_new_int(mtime)); | |
| 95 | + omtime = db_column_int(&q,4); | |
| 96 | + if(omtime && (omtime!=mtime)){ | |
| 97 | + SET("omtime",json_new_int(omtime)); | |
| 98 | + } | |
| 99 | + | |
| 100 | + if(zParent){ | |
| 101 | + SET("parentUuid", json_new_string(zParent)); | |
| 102 | + } | |
| 103 | + | |
| 104 | + fileList = json_timeline_get_changed_files(rid); | |
| 105 | + if(fileList){ | |
| 106 | + SET("files",fileList); | |
| 107 | + } | |
| 108 | + | |
| 109 | +#undef SET | |
| 110 | + }else{ | |
| 111 | + cson_value_free(v); | |
| 112 | + v = NULL; | |
| 113 | + } | |
| 114 | + db_finalize(&q); | |
| 115 | + return v; | |
| 116 | +} | |
| 117 | + | |
| 118 | +static char perms_can_read(){ | |
| 119 | + return g.perm.Read ? 1 : 0; | |
| 120 | +} | |
| 121 | + | |
| 122 | +static ArtifactDispatchEntry ArtifactDispatchList[] = { | |
| 123 | +{"checkin", json_artifact_ci, perms_can_read}, | |
| 124 | +{"tag", NULL, perms_can_read}, | |
| 125 | +{"ticket", NULL, perms_can_read}, | |
| 126 | +{"wiki", NULL, perms_can_read}, | |
| 127 | +{NULL,NULL,NULL} | |
| 128 | +}; | |
| 129 | + | |
| 130 | +/* | |
| 131 | +** Impl of /json/artifact | |
| 132 | +*/ | |
| 9 | 133 | cson_value * json_page_artifact(){ |
| 10 | 134 | cson_value * payV = NULL; |
| 11 | 135 | cson_object * pay = NULL; |
| 12 | 136 | char const * zName = NULL; |
| 13 | 137 | char const * zType = NULL; |
| @@ -43,11 +167,11 @@ | ||
| 43 | 167 | goto error; |
| 44 | 168 | }else if(2==rc){ |
| 45 | 169 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 46 | 170 | goto error; |
| 47 | 171 | } |
| 48 | - zName = blob_str(&uuid); | |
| 172 | + zUuid = zName = blob_str(&uuid); | |
| 49 | 173 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName); |
| 50 | 174 | if(0==rid){ |
| 51 | 175 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 52 | 176 | goto error; |
| 53 | 177 | } |
| @@ -78,11 +202,26 @@ | ||
| 78 | 202 | pay = cson_value_get_object(payV); |
| 79 | 203 | assert( NULL != zType ); |
| 80 | 204 | cson_object_set( pay, "type", json_new_string(zType) ); |
| 81 | 205 | cson_object_set( pay, "id", json_new_string(zName) ); |
| 82 | 206 | cson_object_set( pay, "rid", cson_value_new_integer(rid) ); |
| 83 | - | |
| 207 | + ArtifactDispatchEntry const * disp = &ArtifactDispatchList[0]; | |
| 208 | + for( ; disp->name; ++disp ){ | |
| 209 | + if(0!=strcmp(disp->name, zType)){ | |
| 210 | + continue; | |
| 211 | + }else{ | |
| 212 | + cson_value * entry; | |
| 213 | + if( ! (*disp->permCheck)() ){ | |
| 214 | + break; | |
| 215 | + } | |
| 216 | + entry = (*disp->func)(rid, zUuid); | |
| 217 | + if(entry){ | |
| 218 | + cson_object_set(pay, "artifact", entry); | |
| 219 | + } | |
| 220 | + break; | |
| 221 | + } | |
| 222 | + } | |
| 84 | 223 | veryend: |
| 85 | 224 | blob_reset(&uuid); |
| 86 | 225 | return payV; |
| 87 | 226 | } |
| 88 | 227 | |
| 89 | 228 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -4,10 +4,134 @@ | |
| 4 | |
| 5 | #if INTERFACE |
| 6 | #include "json_detail.h" |
| 7 | #endif |
| 8 | |
| 9 | cson_value * json_page_artifact(){ |
| 10 | cson_value * payV = NULL; |
| 11 | cson_object * pay = NULL; |
| 12 | char const * zName = NULL; |
| 13 | char const * zType = NULL; |
| @@ -43,11 +167,11 @@ | |
| 43 | goto error; |
| 44 | }else if(2==rc){ |
| 45 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 46 | goto error; |
| 47 | } |
| 48 | zName = blob_str(&uuid); |
| 49 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName); |
| 50 | if(0==rid){ |
| 51 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 52 | goto error; |
| 53 | } |
| @@ -78,11 +202,26 @@ | |
| 78 | pay = cson_value_get_object(payV); |
| 79 | assert( NULL != zType ); |
| 80 | cson_object_set( pay, "type", json_new_string(zType) ); |
| 81 | cson_object_set( pay, "id", json_new_string(zName) ); |
| 82 | cson_object_set( pay, "rid", cson_value_new_integer(rid) ); |
| 83 | |
| 84 | veryend: |
| 85 | blob_reset(&uuid); |
| 86 | return payV; |
| 87 | } |
| 88 | |
| 89 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -4,10 +4,134 @@ | |
| 4 | |
| 5 | #if INTERFACE |
| 6 | #include "json_detail.h" |
| 7 | #endif |
| 8 | |
| 9 | /* |
| 10 | ** Internal callback for /json/artifact handlers. rid and uid refer to |
| 11 | ** the rid/uid of a given type of artifact, and each callback is |
| 12 | ** specialized to return a JSON form of one type of artifact. |
| 13 | */ |
| 14 | typedef cson_value * (*artifact_f)( int rid, char const * uid ); |
| 15 | |
| 16 | typedef struct ArtifactDispatchEntry { |
| 17 | /** |
| 18 | Artifact type name, e.g. "checkin". |
| 19 | */ |
| 20 | char const * name; |
| 21 | /** |
| 22 | JSON construction callback. |
| 23 | */ |
| 24 | artifact_f func; |
| 25 | /** |
| 26 | Must return true if g.perm has the proper permissions to fetch |
| 27 | this info, else false. If it returns false, func() is skipped |
| 28 | (producing no extra payload output). |
| 29 | */ |
| 30 | char (*permCheck)(); |
| 31 | } ArtifactDispatchEntry; |
| 32 | |
| 33 | |
| 34 | /* |
| 35 | ** Generates an artifact Object for the given rid/zUuid. rid |
| 36 | ** must refer to a Checkin. |
| 37 | ** |
| 38 | ** |
| 39 | ** TODO: consolidate the result structure (and its generation) with |
| 40 | ** /json/timeline/ci. |
| 41 | */ |
| 42 | static cson_value * json_artifact_ci( int rid, char const * zUuid ){ |
| 43 | cson_value * v = cson_value_new_object(); |
| 44 | cson_object * o = cson_value_get_object(v); |
| 45 | char const * zParent = NULL; |
| 46 | Stmt q; |
| 47 | assert( NULL != zUuid ); |
| 48 | cson_object_set(o,"isLeaf", cson_value_new_bool(is_a_leaf(rid))); |
| 49 | zParent = db_text(0, |
| 50 | "SELECT uuid FROM plink, blob" |
| 51 | " WHERE plink.cid=%d AND blob.rid=plink.pid AND plink.isprim", |
| 52 | rid |
| 53 | ); |
| 54 | |
| 55 | db_prepare(&q, |
| 56 | "SELECT uuid, mtime, user, comment," |
| 57 | " omtime" |
| 58 | " FROM blob, event" |
| 59 | " WHERE blob.rid=%d" |
| 60 | " AND event.objid=%d", |
| 61 | rid, rid |
| 62 | ); |
| 63 | if( db_step(&q)==SQLITE_ROW ){ |
| 64 | /*const char *zUuid = db_column_text(&q, 0);*/ |
| 65 | char * zTmp; |
| 66 | const char *zUser; |
| 67 | const char *zComment; |
| 68 | char * zEUser, * zEComment; |
| 69 | int mtime, omtime; |
| 70 | cson_value * fileList = NULL; |
| 71 | #define SET(K,V) cson_object_set(o,(K), (V)) |
| 72 | SET("uuid",json_new_string(zUuid)); |
| 73 | zUser = db_column_text(&q,2); |
| 74 | SET("user",json_new_string(zUser)); |
| 75 | zEUser = db_text(0, |
| 76 | "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d", |
| 77 | TAG_USER, rid); |
| 78 | if(zEUser){ |
| 79 | SET("editedBy", json_new_string(zEUser)); |
| 80 | free(zEUser); |
| 81 | } |
| 82 | |
| 83 | zComment = db_column_text(&q,3); |
| 84 | SET("comment",json_new_string(zComment)); |
| 85 | zEComment = db_text(0, |
| 86 | "SELECT value FROM tagxref WHERE tagid=%d AND rid=%d", |
| 87 | TAG_COMMENT, rid); |
| 88 | if(zEComment){ |
| 89 | SET("editedComment", json_new_string(zEComment)); |
| 90 | free(zEComment); |
| 91 | } |
| 92 | |
| 93 | mtime = db_column_int(&q,1); |
| 94 | SET("mtime",json_new_int(mtime)); |
| 95 | omtime = db_column_int(&q,4); |
| 96 | if(omtime && (omtime!=mtime)){ |
| 97 | SET("omtime",json_new_int(omtime)); |
| 98 | } |
| 99 | |
| 100 | if(zParent){ |
| 101 | SET("parentUuid", json_new_string(zParent)); |
| 102 | } |
| 103 | |
| 104 | fileList = json_timeline_get_changed_files(rid); |
| 105 | if(fileList){ |
| 106 | SET("files",fileList); |
| 107 | } |
| 108 | |
| 109 | #undef SET |
| 110 | }else{ |
| 111 | cson_value_free(v); |
| 112 | v = NULL; |
| 113 | } |
| 114 | db_finalize(&q); |
| 115 | return v; |
| 116 | } |
| 117 | |
| 118 | static char perms_can_read(){ |
| 119 | return g.perm.Read ? 1 : 0; |
| 120 | } |
| 121 | |
| 122 | static ArtifactDispatchEntry ArtifactDispatchList[] = { |
| 123 | {"checkin", json_artifact_ci, perms_can_read}, |
| 124 | {"tag", NULL, perms_can_read}, |
| 125 | {"ticket", NULL, perms_can_read}, |
| 126 | {"wiki", NULL, perms_can_read}, |
| 127 | {NULL,NULL,NULL} |
| 128 | }; |
| 129 | |
| 130 | /* |
| 131 | ** Impl of /json/artifact |
| 132 | */ |
| 133 | cson_value * json_page_artifact(){ |
| 134 | cson_value * payV = NULL; |
| 135 | cson_object * pay = NULL; |
| 136 | char const * zName = NULL; |
| 137 | char const * zType = NULL; |
| @@ -43,11 +167,11 @@ | |
| 167 | goto error; |
| 168 | }else if(2==rc){ |
| 169 | g.json.resultCode = FSL_JSON_E_AMBIGUOUS_UUID; |
| 170 | goto error; |
| 171 | } |
| 172 | zUuid = zName = blob_str(&uuid); |
| 173 | rid = db_int(0, "SELECT rid FROM blob WHERE uuid='%s'", zName); |
| 174 | if(0==rid){ |
| 175 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 176 | goto error; |
| 177 | } |
| @@ -78,11 +202,26 @@ | |
| 202 | pay = cson_value_get_object(payV); |
| 203 | assert( NULL != zType ); |
| 204 | cson_object_set( pay, "type", json_new_string(zType) ); |
| 205 | cson_object_set( pay, "id", json_new_string(zName) ); |
| 206 | cson_object_set( pay, "rid", cson_value_new_integer(rid) ); |
| 207 | ArtifactDispatchEntry const * disp = &ArtifactDispatchList[0]; |
| 208 | for( ; disp->name; ++disp ){ |
| 209 | if(0!=strcmp(disp->name, zType)){ |
| 210 | continue; |
| 211 | }else{ |
| 212 | cson_value * entry; |
| 213 | if( ! (*disp->permCheck)() ){ |
| 214 | break; |
| 215 | } |
| 216 | entry = (*disp->func)(rid, zUuid); |
| 217 | if(entry){ |
| 218 | cson_object_set(pay, "artifact", entry); |
| 219 | } |
| 220 | break; |
| 221 | } |
| 222 | } |
| 223 | veryend: |
| 224 | blob_reset(&uuid); |
| 225 | return payV; |
| 226 | } |
| 227 | |
| 228 |