Fossil SCM
Extend /json/settings/get with a version=X flag indicating the check-in version to check for versionable flags in before falling back to either the checkout or repository. List sensitive properties for all users but elide their values for non-setup users (previously they were elided altogether for non-setup users).
Commit
fd405e956359226215494ed2cde070eaebcf6198c2850ce6c8fab8fa18b6be5c
Parent
632dfd26dda2fa1…
1 file changed
+52
-20
+52
-20
| --- src/json_config.c | ||
| +++ src/json_config.c | ||
| @@ -208,19 +208,40 @@ | ||
| 208 | 208 | |
| 209 | 209 | /* |
| 210 | 210 | ** Impl of /json/settings/get. |
| 211 | 211 | */ |
| 212 | 212 | static cson_value * json_settings_get(void){ |
| 213 | - cson_array * pay = cson_new_array(); | |
| 214 | - int nSetting, i; | |
| 213 | + cson_array * pay = cson_new_array(); /* output payload */ | |
| 214 | + int nSetting, i; /* setting count and loop var */ | |
| 215 | 215 | const Setting *aSetting = setting_info(&nSetting); |
| 216 | - Stmt q = empty_Stmt; | |
| 216 | + const char * zRevision = 0; /* revision to look for | |
| 217 | + versioned settings in */ | |
| 218 | + char * zUuid = 0; /* Resolved UUID of zRevision */ | |
| 219 | + Stmt q = empty_Stmt; /* Config-search query */ | |
| 220 | + Stmt qFoci = empty_Stmt; /* foci query */ | |
| 217 | 221 | |
| 218 | 222 | if( !g.perm.Read ){ |
| 219 | 223 | json_set_err( FSL_JSON_E_DENIED, "Fetching settings requires 'o' access." ); |
| 220 | 224 | return NULL; |
| 221 | 225 | } |
| 226 | + zRevision = json_find_option_cstr("version",NULL,NULL); | |
| 227 | + if( 0!=zRevision ){ | |
| 228 | + int rid = name_to_uuid2(zRevision, "ci", &zUuid); | |
| 229 | + if(rid<=0){ | |
| 230 | + json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND, | |
| 231 | + "Cannot find the given version."); | |
| 232 | + return NULL; | |
| 233 | + } | |
| 234 | + db_multi_exec("CREATE VIRTUAL TABLE IF NOT EXISTS " | |
| 235 | + "temp.foci USING files_of_checkin;"); | |
| 236 | + db_prepare(&qFoci, | |
| 237 | + "SELECT uuid FROM temp.foci WHERE " | |
| 238 | + "checkinID=%d AND filename='.fossil-settings/' || :name", | |
| 239 | + rid); | |
| 240 | + } | |
| 241 | + zRevision = 0; | |
| 242 | + | |
| 222 | 243 | if( g.localOpen ){ |
| 223 | 244 | db_prepare(&q, |
| 224 | 245 | "SELECT 'checkout', value FROM vvar WHERE name=:name" |
| 225 | 246 | " UNION ALL " |
| 226 | 247 | "SELECT 'repo', value FROM config WHERE name=:name" |
| @@ -232,27 +253,44 @@ | ||
| 232 | 253 | } |
| 233 | 254 | for(i=0; i<nSetting; ++i){ |
| 234 | 255 | const Setting *pSet = &aSetting[i]; |
| 235 | 256 | cson_object * jSet; |
| 236 | 257 | cson_value * pVal = 0, * pSrc = 0; |
| 237 | - if( pSet->sensitive && !g.perm.Setup ){ | |
| 238 | - continue; | |
| 239 | - } | |
| 240 | 258 | jSet = cson_new_object(); |
| 241 | 259 | cson_array_append(pay, cson_object_value(jSet)); |
| 242 | 260 | cson_object_set(jSet, "name", json_new_string(pSet->name)); |
| 243 | 261 | cson_object_set(jSet, "versionable", cson_value_new_bool(pSet->versionable)); |
| 244 | 262 | cson_object_set(jSet, "sensitive", cson_value_new_bool(pSet->sensitive)); |
| 245 | 263 | cson_object_set(jSet, "defaultValue", (pSet->def && pSet->def[0]) |
| 246 | 264 | ? json_new_string(pSet->def) |
| 247 | 265 | : cson_value_null()); |
| 266 | + if( pSet->sensitive && !g.perm.Setup ){ | |
| 267 | + /* Should we also allow non-Setup admins to see these? */ | |
| 268 | + continue; | |
| 269 | + } | |
| 248 | 270 | if( pSet->versionable ){ |
| 249 | 271 | /* Check to see if this is overridden by a versionable settings file */ |
| 250 | - if( g.localOpen ){ | |
| 272 | + Blob versionedPathname; | |
| 273 | + blob_zero(&versionedPathname); | |
| 274 | + if( 0!=zUuid ){ | |
| 275 | + /* Attempt to find a versioned setting stored in the given | |
| 276 | + ** check-in version. */ | |
| 277 | + db_bind_text(&qFoci, ":name", pSet->name); | |
| 278 | + if( SQLITE_ROW==db_step(&qFoci) ){ | |
| 279 | + int frid = fast_uuid_to_rid(db_column_text(&qFoci, 0)); | |
| 280 | + Blob content; | |
| 281 | + blob_zero(&content); | |
| 282 | + if( 0!=content_get(frid, &content) ){ | |
| 283 | + pSrc = json_new_string("versioned"); | |
| 284 | + pVal = json_new_string(blob_str(&content)); | |
| 285 | + } | |
| 286 | + blob_reset(&content); | |
| 287 | + } | |
| 288 | + db_reset(&qFoci); | |
| 289 | + } | |
| 290 | + if( 0==pSrc && g.localOpen ){ | |
| 251 | 291 | /* Pull value from a local .fossil-settings/X file, if one exists. */ |
| 252 | - Blob versionedPathname; | |
| 253 | - blob_zero(&versionedPathname); | |
| 254 | 292 | blob_appendf(&versionedPathname, "%s.fossil-settings/%s", |
| 255 | 293 | g.zLocalRoot, pSet->name); |
| 256 | 294 | if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 257 | 295 | Blob content; |
| 258 | 296 | blob_zero(&content); |
| @@ -261,32 +299,26 @@ | ||
| 261 | 299 | pVal = json_new_string(blob_str(&content)); |
| 262 | 300 | blob_reset(&content); |
| 263 | 301 | } |
| 264 | 302 | blob_reset(&versionedPathname); |
| 265 | 303 | } |
| 266 | - if( 0==pSrc ){ | |
| 267 | - /* | |
| 268 | - ** TODO? No checkout-local versioned setting found. We could | |
| 269 | - ** fish the file out of the repository but we'd need to make | |
| 270 | - ** an assumption about which branch to pull it from or require | |
| 271 | - ** the user to pass in a version. | |
| 272 | - */ | |
| 273 | - } | |
| 274 | 304 | } |
| 275 | 305 | if( 0==pSrc ){ |
| 276 | - /* We had no checkout-local value, so use the value from | |
| 277 | - ** repo.config. */ | |
| 306 | + /* We had no versioned value, so use the value from | |
| 307 | + ** localdb.vvar or repository.config (in that order). */ | |
| 278 | 308 | db_bind_text(&q, ":name", pSet->name); |
| 279 | 309 | if( SQLITE_ROW==db_step(&q) ){ |
| 280 | 310 | pSrc = json_new_string(db_column_text(&q, 0)); |
| 281 | 311 | pVal = json_new_string(db_column_text(&q, 1)); |
| 282 | 312 | } |
| 283 | 313 | db_reset(&q); |
| 284 | 314 | } |
| 285 | 315 | cson_object_set(jSet, "valueSource", pSrc ? pSrc : cson_value_null()); |
| 286 | 316 | cson_object_set(jSet, "value", pVal ? pVal : cson_value_null()); |
| 287 | - } | |
| 317 | + }/*aSetting loop*/ | |
| 288 | 318 | db_finalize(&q); |
| 319 | + db_finalize(&qFoci); | |
| 320 | + fossil_free(zUuid); | |
| 289 | 321 | return cson_array_value(pay); |
| 290 | 322 | } |
| 291 | 323 | |
| 292 | 324 | #endif /* FOSSIL_ENABLE_JSON */ |
| 293 | 325 |
| --- src/json_config.c | |
| +++ src/json_config.c | |
| @@ -208,19 +208,40 @@ | |
| 208 | |
| 209 | /* |
| 210 | ** Impl of /json/settings/get. |
| 211 | */ |
| 212 | static cson_value * json_settings_get(void){ |
| 213 | cson_array * pay = cson_new_array(); |
| 214 | int nSetting, i; |
| 215 | const Setting *aSetting = setting_info(&nSetting); |
| 216 | Stmt q = empty_Stmt; |
| 217 | |
| 218 | if( !g.perm.Read ){ |
| 219 | json_set_err( FSL_JSON_E_DENIED, "Fetching settings requires 'o' access." ); |
| 220 | return NULL; |
| 221 | } |
| 222 | if( g.localOpen ){ |
| 223 | db_prepare(&q, |
| 224 | "SELECT 'checkout', value FROM vvar WHERE name=:name" |
| 225 | " UNION ALL " |
| 226 | "SELECT 'repo', value FROM config WHERE name=:name" |
| @@ -232,27 +253,44 @@ | |
| 232 | } |
| 233 | for(i=0; i<nSetting; ++i){ |
| 234 | const Setting *pSet = &aSetting[i]; |
| 235 | cson_object * jSet; |
| 236 | cson_value * pVal = 0, * pSrc = 0; |
| 237 | if( pSet->sensitive && !g.perm.Setup ){ |
| 238 | continue; |
| 239 | } |
| 240 | jSet = cson_new_object(); |
| 241 | cson_array_append(pay, cson_object_value(jSet)); |
| 242 | cson_object_set(jSet, "name", json_new_string(pSet->name)); |
| 243 | cson_object_set(jSet, "versionable", cson_value_new_bool(pSet->versionable)); |
| 244 | cson_object_set(jSet, "sensitive", cson_value_new_bool(pSet->sensitive)); |
| 245 | cson_object_set(jSet, "defaultValue", (pSet->def && pSet->def[0]) |
| 246 | ? json_new_string(pSet->def) |
| 247 | : cson_value_null()); |
| 248 | if( pSet->versionable ){ |
| 249 | /* Check to see if this is overridden by a versionable settings file */ |
| 250 | if( g.localOpen ){ |
| 251 | /* Pull value from a local .fossil-settings/X file, if one exists. */ |
| 252 | Blob versionedPathname; |
| 253 | blob_zero(&versionedPathname); |
| 254 | blob_appendf(&versionedPathname, "%s.fossil-settings/%s", |
| 255 | g.zLocalRoot, pSet->name); |
| 256 | if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 257 | Blob content; |
| 258 | blob_zero(&content); |
| @@ -261,32 +299,26 @@ | |
| 261 | pVal = json_new_string(blob_str(&content)); |
| 262 | blob_reset(&content); |
| 263 | } |
| 264 | blob_reset(&versionedPathname); |
| 265 | } |
| 266 | if( 0==pSrc ){ |
| 267 | /* |
| 268 | ** TODO? No checkout-local versioned setting found. We could |
| 269 | ** fish the file out of the repository but we'd need to make |
| 270 | ** an assumption about which branch to pull it from or require |
| 271 | ** the user to pass in a version. |
| 272 | */ |
| 273 | } |
| 274 | } |
| 275 | if( 0==pSrc ){ |
| 276 | /* We had no checkout-local value, so use the value from |
| 277 | ** repo.config. */ |
| 278 | db_bind_text(&q, ":name", pSet->name); |
| 279 | if( SQLITE_ROW==db_step(&q) ){ |
| 280 | pSrc = json_new_string(db_column_text(&q, 0)); |
| 281 | pVal = json_new_string(db_column_text(&q, 1)); |
| 282 | } |
| 283 | db_reset(&q); |
| 284 | } |
| 285 | cson_object_set(jSet, "valueSource", pSrc ? pSrc : cson_value_null()); |
| 286 | cson_object_set(jSet, "value", pVal ? pVal : cson_value_null()); |
| 287 | } |
| 288 | db_finalize(&q); |
| 289 | return cson_array_value(pay); |
| 290 | } |
| 291 | |
| 292 | #endif /* FOSSIL_ENABLE_JSON */ |
| 293 |
| --- src/json_config.c | |
| +++ src/json_config.c | |
| @@ -208,19 +208,40 @@ | |
| 208 | |
| 209 | /* |
| 210 | ** Impl of /json/settings/get. |
| 211 | */ |
| 212 | static cson_value * json_settings_get(void){ |
| 213 | cson_array * pay = cson_new_array(); /* output payload */ |
| 214 | int nSetting, i; /* setting count and loop var */ |
| 215 | const Setting *aSetting = setting_info(&nSetting); |
| 216 | const char * zRevision = 0; /* revision to look for |
| 217 | versioned settings in */ |
| 218 | char * zUuid = 0; /* Resolved UUID of zRevision */ |
| 219 | Stmt q = empty_Stmt; /* Config-search query */ |
| 220 | Stmt qFoci = empty_Stmt; /* foci query */ |
| 221 | |
| 222 | if( !g.perm.Read ){ |
| 223 | json_set_err( FSL_JSON_E_DENIED, "Fetching settings requires 'o' access." ); |
| 224 | return NULL; |
| 225 | } |
| 226 | zRevision = json_find_option_cstr("version",NULL,NULL); |
| 227 | if( 0!=zRevision ){ |
| 228 | int rid = name_to_uuid2(zRevision, "ci", &zUuid); |
| 229 | if(rid<=0){ |
| 230 | json_set_err(FSL_JSON_E_RESOURCE_NOT_FOUND, |
| 231 | "Cannot find the given version."); |
| 232 | return NULL; |
| 233 | } |
| 234 | db_multi_exec("CREATE VIRTUAL TABLE IF NOT EXISTS " |
| 235 | "temp.foci USING files_of_checkin;"); |
| 236 | db_prepare(&qFoci, |
| 237 | "SELECT uuid FROM temp.foci WHERE " |
| 238 | "checkinID=%d AND filename='.fossil-settings/' || :name", |
| 239 | rid); |
| 240 | } |
| 241 | zRevision = 0; |
| 242 | |
| 243 | if( g.localOpen ){ |
| 244 | db_prepare(&q, |
| 245 | "SELECT 'checkout', value FROM vvar WHERE name=:name" |
| 246 | " UNION ALL " |
| 247 | "SELECT 'repo', value FROM config WHERE name=:name" |
| @@ -232,27 +253,44 @@ | |
| 253 | } |
| 254 | for(i=0; i<nSetting; ++i){ |
| 255 | const Setting *pSet = &aSetting[i]; |
| 256 | cson_object * jSet; |
| 257 | cson_value * pVal = 0, * pSrc = 0; |
| 258 | jSet = cson_new_object(); |
| 259 | cson_array_append(pay, cson_object_value(jSet)); |
| 260 | cson_object_set(jSet, "name", json_new_string(pSet->name)); |
| 261 | cson_object_set(jSet, "versionable", cson_value_new_bool(pSet->versionable)); |
| 262 | cson_object_set(jSet, "sensitive", cson_value_new_bool(pSet->sensitive)); |
| 263 | cson_object_set(jSet, "defaultValue", (pSet->def && pSet->def[0]) |
| 264 | ? json_new_string(pSet->def) |
| 265 | : cson_value_null()); |
| 266 | if( pSet->sensitive && !g.perm.Setup ){ |
| 267 | /* Should we also allow non-Setup admins to see these? */ |
| 268 | continue; |
| 269 | } |
| 270 | if( pSet->versionable ){ |
| 271 | /* Check to see if this is overridden by a versionable settings file */ |
| 272 | Blob versionedPathname; |
| 273 | blob_zero(&versionedPathname); |
| 274 | if( 0!=zUuid ){ |
| 275 | /* Attempt to find a versioned setting stored in the given |
| 276 | ** check-in version. */ |
| 277 | db_bind_text(&qFoci, ":name", pSet->name); |
| 278 | if( SQLITE_ROW==db_step(&qFoci) ){ |
| 279 | int frid = fast_uuid_to_rid(db_column_text(&qFoci, 0)); |
| 280 | Blob content; |
| 281 | blob_zero(&content); |
| 282 | if( 0!=content_get(frid, &content) ){ |
| 283 | pSrc = json_new_string("versioned"); |
| 284 | pVal = json_new_string(blob_str(&content)); |
| 285 | } |
| 286 | blob_reset(&content); |
| 287 | } |
| 288 | db_reset(&qFoci); |
| 289 | } |
| 290 | if( 0==pSrc && g.localOpen ){ |
| 291 | /* Pull value from a local .fossil-settings/X file, if one exists. */ |
| 292 | blob_appendf(&versionedPathname, "%s.fossil-settings/%s", |
| 293 | g.zLocalRoot, pSet->name); |
| 294 | if( file_size(blob_str(&versionedPathname), ExtFILE)>=0 ){ |
| 295 | Blob content; |
| 296 | blob_zero(&content); |
| @@ -261,32 +299,26 @@ | |
| 299 | pVal = json_new_string(blob_str(&content)); |
| 300 | blob_reset(&content); |
| 301 | } |
| 302 | blob_reset(&versionedPathname); |
| 303 | } |
| 304 | } |
| 305 | if( 0==pSrc ){ |
| 306 | /* We had no versioned value, so use the value from |
| 307 | ** localdb.vvar or repository.config (in that order). */ |
| 308 | db_bind_text(&q, ":name", pSet->name); |
| 309 | if( SQLITE_ROW==db_step(&q) ){ |
| 310 | pSrc = json_new_string(db_column_text(&q, 0)); |
| 311 | pVal = json_new_string(db_column_text(&q, 1)); |
| 312 | } |
| 313 | db_reset(&q); |
| 314 | } |
| 315 | cson_object_set(jSet, "valueSource", pSrc ? pSrc : cson_value_null()); |
| 316 | cson_object_set(jSet, "value", pVal ? pVal : cson_value_null()); |
| 317 | }/*aSetting loop*/ |
| 318 | db_finalize(&q); |
| 319 | db_finalize(&qFoci); |
| 320 | fossil_free(zUuid); |
| 321 | return cson_array_value(pay); |
| 322 | } |
| 323 | |
| 324 | #endif /* FOSSIL_ENABLE_JSON */ |
| 325 |