Fossil SCM
Started adding /json/artifact tickets support, but grokking tkt.c is more than i am up for tonight. Changed how permissions checks are done under /json/artifact (previous approach is just plain silly without C++ templates)
Commit
cee8bc672779570879a9c616de420a6354ff384b
Parent
cd67b945d7468a6…
1 file changed
+51
-28
+51
-28
| --- src/json_artifact.c | ||
| +++ src/json_artifact.c | ||
| @@ -45,18 +45,10 @@ | ||
| 45 | 45 | /** |
| 46 | 46 | JSON construction callback. Creates the contents for the |
| 47 | 47 | payload.artifact property of /json/artifact responses. |
| 48 | 48 | */ |
| 49 | 49 | artifact_f func; |
| 50 | - | |
| 51 | - /** | |
| 52 | - Must return true if g.perm has the proper permissions to fetch | |
| 53 | - this info, else false. If it returns false, func() is skipped | |
| 54 | - (producing no extra payload output) and an access error is | |
| 55 | - generated. | |
| 56 | - */ | |
| 57 | - char (*permCheck)(); | |
| 58 | 50 | } ArtifactDispatchEntry; |
| 59 | 51 | |
| 60 | 52 | |
| 61 | 53 | /* |
| 62 | 54 | ** Generates an artifact Object for the given rid/zUuid. rid |
| @@ -160,16 +152,50 @@ | ||
| 160 | 152 | #undef SET |
| 161 | 153 | } |
| 162 | 154 | db_finalize(&q); |
| 163 | 155 | return v; |
| 164 | 156 | } |
| 157 | + | |
| 158 | +cson_value * json_artifact_ticket( int rid ){ | |
| 159 | + cson_value * payV = NULL; | |
| 160 | + cson_object * pay = NULL; | |
| 161 | + Manifest *pTktChng = NULL; | |
| 162 | + static cson_value * eventTypeLabel = NULL; | |
| 163 | + if(! g.perm.RdTkt ){ | |
| 164 | + g.json.resultCode = FSL_JSON_E_DENIED; | |
| 165 | + return NULL; | |
| 166 | + } | |
| 167 | + if(!eventTypeLabel){ | |
| 168 | + eventTypeLabel = json_new_string("ticket"); | |
| 169 | + json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel, 1); | |
| 170 | + } | |
| 171 | + | |
| 172 | + pTktChng = manifest_get(rid, CFTYPE_TICKET); | |
| 173 | + if( pTktChng==0 ){ | |
| 174 | + g.json.resultCode = FSL_JSON_E_UNKNOWN; | |
| 175 | + return NULL; | |
| 176 | + } | |
| 177 | + payV = cson_value_new_object(); | |
| 178 | + pay = cson_value_get_object(payV); | |
| 179 | + cson_object_set(pay, "eventType", eventTypeLabel ); | |
| 180 | + cson_object_set(pay, "uuid", json_new_string(pTktChng->zTicketUuid)); | |
| 181 | + cson_object_set(pay, "user", json_new_string(pTktChng->zUser)); | |
| 182 | + cson_object_set(pay, "timestamp", json_julian_to_timestamp(pTktChng->rDate)); | |
| 183 | + manifest_destroy(pTktChng); | |
| 184 | + return payV; | |
| 185 | +} | |
| 165 | 186 | |
| 166 | 187 | /* |
| 167 | 188 | ** Sub-impl of /json/artifact for checkins. |
| 168 | 189 | */ |
| 169 | 190 | static cson_value * json_artifact_ci( int rid ){ |
| 170 | - return json_artifact_for_ci(rid, 1); | |
| 191 | + if(! g.perm.Read ){ | |
| 192 | + g.json.resultCode = FSL_JSON_E_DENIED; | |
| 193 | + return NULL; | |
| 194 | + }else{ | |
| 195 | + return json_artifact_for_ci(rid, 1); | |
| 196 | + } | |
| 171 | 197 | } |
| 172 | 198 | |
| 173 | 199 | /* |
| 174 | 200 | ** Permissions callback func for ArtifactDispatchEntry. |
| 175 | 201 | */ |
| @@ -176,15 +202,16 @@ | ||
| 176 | 202 | static char perms_can_read(){ |
| 177 | 203 | return g.perm.Read ? 1 : 0; |
| 178 | 204 | } |
| 179 | 205 | |
| 180 | 206 | static ArtifactDispatchEntry ArtifactDispatchList[] = { |
| 181 | -{"checkin", json_artifact_ci, perms_can_read}, | |
| 182 | -{"tag", NULL, perms_can_read}, | |
| 183 | -{"ticket", NULL, perms_can_read}, | |
| 184 | -{"wiki", NULL, perms_can_read}, | |
| 185 | -{NULL,NULL,NULL} | |
| 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} | |
| 186 | 213 | }; |
| 187 | 214 | |
| 188 | 215 | /* |
| 189 | 216 | ** Impl of /json/artifact. This basically just determines the type of |
| 190 | 217 | ** an artifact and forwards the real work to another function. |
| @@ -193,13 +220,14 @@ | ||
| 193 | 220 | cson_value * payV = NULL; |
| 194 | 221 | cson_object * pay = NULL; |
| 195 | 222 | char const * zName = NULL; |
| 196 | 223 | char const * zType = NULL; |
| 197 | 224 | char const * zUuid = NULL; |
| 225 | + cson_value * entry = NULL; | |
| 198 | 226 | Blob uuid = empty_blob; |
| 199 | 227 | int rc; |
| 200 | - int rid; | |
| 228 | + int rid = 0; | |
| 201 | 229 | ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0]; |
| 202 | 230 | zName = g.isHTTP |
| 203 | 231 | ? json_getenv_cstr("uuid") |
| 204 | 232 | : find_option("uuid","u",1); |
| 205 | 233 | if(!zName||!*zName){ |
| @@ -261,34 +289,29 @@ | ||
| 261 | 289 | assert( (NULL != zType) && "Internal dispatching error." ); |
| 262 | 290 | for( ; dispatcher->name; ++dispatcher ){ |
| 263 | 291 | if(0!=strcmp(dispatcher->name, zType)){ |
| 264 | 292 | continue; |
| 265 | 293 | }else{ |
| 266 | - if( ! (*dispatcher->permCheck)() ){ | |
| 267 | - g.json.resultCode = FSL_JSON_E_DENIED; | |
| 268 | - } | |
| 294 | + entry = (*dispatcher->func)(rid); | |
| 269 | 295 | break; |
| 270 | 296 | } |
| 271 | 297 | } |
| 272 | 298 | if(!g.json.resultCode){ |
| 299 | + assert( NULL != entry ); | |
| 300 | + assert( NULL != zType ); | |
| 273 | 301 | payV = cson_value_new_object(); |
| 274 | 302 | pay = cson_value_get_object(payV); |
| 275 | - assert( NULL != zType ); | |
| 276 | 303 | cson_object_set( pay, "type", json_new_string(zType) ); |
| 277 | 304 | /*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/ |
| 278 | 305 | cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) ); |
| 279 | 306 | cson_object_set( pay, "rid", cson_value_new_integer(rid) ); |
| 280 | - if( !dispatcher->name ){ | |
| 281 | - cson_object_set(pay,"artifact", | |
| 282 | - json_new_string("TODO: handle this artifact type!")); | |
| 283 | - }else { | |
| 284 | - cson_value * entry = (*dispatcher->func)(rid); | |
| 285 | - if(entry){ | |
| 286 | - cson_object_set(pay, "artifact", entry); | |
| 287 | - } | |
| 288 | - } | |
| 307 | + if(entry){ | |
| 308 | + cson_object_set(pay, "artifact", entry); | |
| 309 | + } | |
| 310 | + }else{ | |
| 311 | + assert((NULL == entry) && "Internal misuse - callback must return NULL on error."); | |
| 289 | 312 | } |
| 290 | 313 | veryend: |
| 291 | 314 | blob_reset(&uuid); |
| 292 | 315 | return payV; |
| 293 | 316 | } |
| 294 | 317 | |
| 295 | 318 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -45,18 +45,10 @@ | |
| 45 | /** |
| 46 | JSON construction callback. Creates the contents for the |
| 47 | payload.artifact property of /json/artifact responses. |
| 48 | */ |
| 49 | artifact_f func; |
| 50 | |
| 51 | /** |
| 52 | Must return true if g.perm has the proper permissions to fetch |
| 53 | this info, else false. If it returns false, func() is skipped |
| 54 | (producing no extra payload output) and an access error is |
| 55 | generated. |
| 56 | */ |
| 57 | char (*permCheck)(); |
| 58 | } ArtifactDispatchEntry; |
| 59 | |
| 60 | |
| 61 | /* |
| 62 | ** Generates an artifact Object for the given rid/zUuid. rid |
| @@ -160,16 +152,50 @@ | |
| 160 | #undef SET |
| 161 | } |
| 162 | db_finalize(&q); |
| 163 | return v; |
| 164 | } |
| 165 | |
| 166 | /* |
| 167 | ** Sub-impl of /json/artifact for checkins. |
| 168 | */ |
| 169 | static cson_value * json_artifact_ci( int rid ){ |
| 170 | return json_artifact_for_ci(rid, 1); |
| 171 | } |
| 172 | |
| 173 | /* |
| 174 | ** Permissions callback func for ArtifactDispatchEntry. |
| 175 | */ |
| @@ -176,15 +202,16 @@ | |
| 176 | static char perms_can_read(){ |
| 177 | return g.perm.Read ? 1 : 0; |
| 178 | } |
| 179 | |
| 180 | static ArtifactDispatchEntry ArtifactDispatchList[] = { |
| 181 | {"checkin", json_artifact_ci, perms_can_read}, |
| 182 | {"tag", NULL, perms_can_read}, |
| 183 | {"ticket", NULL, perms_can_read}, |
| 184 | {"wiki", NULL, perms_can_read}, |
| 185 | {NULL,NULL,NULL} |
| 186 | }; |
| 187 | |
| 188 | /* |
| 189 | ** Impl of /json/artifact. This basically just determines the type of |
| 190 | ** an artifact and forwards the real work to another function. |
| @@ -193,13 +220,14 @@ | |
| 193 | cson_value * payV = NULL; |
| 194 | cson_object * pay = NULL; |
| 195 | char const * zName = NULL; |
| 196 | char const * zType = NULL; |
| 197 | char const * zUuid = NULL; |
| 198 | Blob uuid = empty_blob; |
| 199 | int rc; |
| 200 | int rid; |
| 201 | ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0]; |
| 202 | zName = g.isHTTP |
| 203 | ? json_getenv_cstr("uuid") |
| 204 | : find_option("uuid","u",1); |
| 205 | if(!zName||!*zName){ |
| @@ -261,34 +289,29 @@ | |
| 261 | assert( (NULL != zType) && "Internal dispatching error." ); |
| 262 | for( ; dispatcher->name; ++dispatcher ){ |
| 263 | if(0!=strcmp(dispatcher->name, zType)){ |
| 264 | continue; |
| 265 | }else{ |
| 266 | if( ! (*dispatcher->permCheck)() ){ |
| 267 | g.json.resultCode = FSL_JSON_E_DENIED; |
| 268 | } |
| 269 | break; |
| 270 | } |
| 271 | } |
| 272 | if(!g.json.resultCode){ |
| 273 | payV = cson_value_new_object(); |
| 274 | pay = cson_value_get_object(payV); |
| 275 | assert( NULL != zType ); |
| 276 | cson_object_set( pay, "type", json_new_string(zType) ); |
| 277 | /*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/ |
| 278 | cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) ); |
| 279 | cson_object_set( pay, "rid", cson_value_new_integer(rid) ); |
| 280 | if( !dispatcher->name ){ |
| 281 | cson_object_set(pay,"artifact", |
| 282 | json_new_string("TODO: handle this artifact type!")); |
| 283 | }else { |
| 284 | cson_value * entry = (*dispatcher->func)(rid); |
| 285 | if(entry){ |
| 286 | cson_object_set(pay, "artifact", entry); |
| 287 | } |
| 288 | } |
| 289 | } |
| 290 | veryend: |
| 291 | blob_reset(&uuid); |
| 292 | return payV; |
| 293 | } |
| 294 | |
| 295 |
| --- src/json_artifact.c | |
| +++ src/json_artifact.c | |
| @@ -45,18 +45,10 @@ | |
| 45 | /** |
| 46 | JSON construction callback. Creates the contents for the |
| 47 | payload.artifact property of /json/artifact responses. |
| 48 | */ |
| 49 | artifact_f func; |
| 50 | } ArtifactDispatchEntry; |
| 51 | |
| 52 | |
| 53 | /* |
| 54 | ** Generates an artifact Object for the given rid/zUuid. rid |
| @@ -160,16 +152,50 @@ | |
| 152 | #undef SET |
| 153 | } |
| 154 | db_finalize(&q); |
| 155 | return v; |
| 156 | } |
| 157 | |
| 158 | cson_value * json_artifact_ticket( int rid ){ |
| 159 | cson_value * payV = NULL; |
| 160 | cson_object * pay = NULL; |
| 161 | Manifest *pTktChng = NULL; |
| 162 | static cson_value * eventTypeLabel = NULL; |
| 163 | if(! g.perm.RdTkt ){ |
| 164 | g.json.resultCode = FSL_JSON_E_DENIED; |
| 165 | return NULL; |
| 166 | } |
| 167 | if(!eventTypeLabel){ |
| 168 | eventTypeLabel = json_new_string("ticket"); |
| 169 | json_gc_add("$EVENT_TYPE_LABEL(ticket)", eventTypeLabel, 1); |
| 170 | } |
| 171 | |
| 172 | pTktChng = manifest_get(rid, CFTYPE_TICKET); |
| 173 | if( pTktChng==0 ){ |
| 174 | g.json.resultCode = FSL_JSON_E_UNKNOWN; |
| 175 | return NULL; |
| 176 | } |
| 177 | payV = cson_value_new_object(); |
| 178 | pay = cson_value_get_object(payV); |
| 179 | cson_object_set(pay, "eventType", eventTypeLabel ); |
| 180 | cson_object_set(pay, "uuid", json_new_string(pTktChng->zTicketUuid)); |
| 181 | cson_object_set(pay, "user", json_new_string(pTktChng->zUser)); |
| 182 | cson_object_set(pay, "timestamp", json_julian_to_timestamp(pTktChng->rDate)); |
| 183 | manifest_destroy(pTktChng); |
| 184 | return payV; |
| 185 | } |
| 186 | |
| 187 | /* |
| 188 | ** Sub-impl of /json/artifact for checkins. |
| 189 | */ |
| 190 | static cson_value * json_artifact_ci( int rid ){ |
| 191 | if(! g.perm.Read ){ |
| 192 | g.json.resultCode = FSL_JSON_E_DENIED; |
| 193 | return NULL; |
| 194 | }else{ |
| 195 | return json_artifact_for_ci(rid, 1); |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | /* |
| 200 | ** Permissions callback func for ArtifactDispatchEntry. |
| 201 | */ |
| @@ -176,15 +202,16 @@ | |
| 202 | static char perms_can_read(){ |
| 203 | return g.perm.Read ? 1 : 0; |
| 204 | } |
| 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. |
| @@ -193,13 +220,14 @@ | |
| 220 | cson_value * payV = NULL; |
| 221 | cson_object * pay = NULL; |
| 222 | char const * zName = NULL; |
| 223 | char const * zType = NULL; |
| 224 | char const * zUuid = NULL; |
| 225 | cson_value * entry = NULL; |
| 226 | Blob uuid = empty_blob; |
| 227 | int rc; |
| 228 | int rid = 0; |
| 229 | ArtifactDispatchEntry const * dispatcher = &ArtifactDispatchList[0]; |
| 230 | zName = g.isHTTP |
| 231 | ? json_getenv_cstr("uuid") |
| 232 | : find_option("uuid","u",1); |
| 233 | if(!zName||!*zName){ |
| @@ -261,34 +289,29 @@ | |
| 289 | assert( (NULL != zType) && "Internal dispatching error." ); |
| 290 | for( ; dispatcher->name; ++dispatcher ){ |
| 291 | if(0!=strcmp(dispatcher->name, zType)){ |
| 292 | continue; |
| 293 | }else{ |
| 294 | entry = (*dispatcher->func)(rid); |
| 295 | break; |
| 296 | } |
| 297 | } |
| 298 | if(!g.json.resultCode){ |
| 299 | assert( NULL != entry ); |
| 300 | assert( NULL != zType ); |
| 301 | payV = cson_value_new_object(); |
| 302 | pay = cson_value_get_object(payV); |
| 303 | cson_object_set( pay, "type", json_new_string(zType) ); |
| 304 | /*cson_object_set( pay, "uuid", json_new_string(zUuid) );*/ |
| 305 | cson_object_set( pay, "name", json_new_string(zName ? zName : zUuid) ); |
| 306 | cson_object_set( pay, "rid", cson_value_new_integer(rid) ); |
| 307 | if(entry){ |
| 308 | cson_object_set(pay, "artifact", entry); |
| 309 | } |
| 310 | }else{ |
| 311 | assert((NULL == entry) && "Internal misuse - callback must return NULL on error."); |
| 312 | } |
| 313 | veryend: |
| 314 | blob_reset(&uuid); |
| 315 | return payV; |
| 316 | } |
| 317 | |
| 318 |