Fossil SCM
Added /json/wiki/get?page=...
Commit
7dc8e9ac94fd752de8d080953b518e04dd30965a
Parent
7a65dd0e00a2fab…
2 files changed
+1
+72
-4
+1
| --- ajax/index.html | ||
| +++ ajax/index.html | ||
| @@ -188,10 +188,11 @@ | ||
| 188 | 188 | <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat")' /> |
| 189 | 189 | <input type='button' value='whoami' onclick='TheApp.cgi.sendCommand("/json/whoami")' /> |
| 190 | 190 | <input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' /> |
| 191 | 191 | <input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' /> |
| 192 | 192 | <input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' /> |
| 193 | +<input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{"page":"Fossil"})' /> | |
| 193 | 194 | |
| 194 | 195 | <!-- |
| 195 | 196 | <input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' /> |
| 196 | 197 | <input type='button' value='get more' onclick='TheApp.cgi.getPages("HelloWorld/WhikiNews")' /> |
| 197 | 198 | <input type='button' value='get client data' onclick='TheApp.cgi.getPageClientData("HelloWorld/whiki/WhikiCommands")' /> |
| 198 | 199 |
| --- ajax/index.html | |
| +++ ajax/index.html | |
| @@ -188,10 +188,11 @@ | |
| 188 | <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat")' /> |
| 189 | <input type='button' value='whoami' onclick='TheApp.cgi.sendCommand("/json/whoami")' /> |
| 190 | <input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' /> |
| 191 | <input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' /> |
| 192 | <input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' /> |
| 193 | |
| 194 | <!-- |
| 195 | <input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' /> |
| 196 | <input type='button' value='get more' onclick='TheApp.cgi.getPages("HelloWorld/WhikiNews")' /> |
| 197 | <input type='button' value='get client data' onclick='TheApp.cgi.getPageClientData("HelloWorld/whiki/WhikiCommands")' /> |
| 198 |
| --- ajax/index.html | |
| +++ ajax/index.html | |
| @@ -188,10 +188,11 @@ | |
| 188 | <input type='button' value='stat' onclick='TheApp.cgi.sendCommand("/json/stat")' /> |
| 189 | <input type='button' value='whoami' onclick='TheApp.cgi.sendCommand("/json/whoami")' /> |
| 190 | <input type='button' value='cap' onclick='TheApp.cgi.sendCommand("/json/cap")' /> |
| 191 | <input type='button' value='branch/list' onclick='TheApp.cgi.sendCommand("/json/branch/list")' /> |
| 192 | <input type='button' value='wiki/list' onclick='TheApp.cgi.sendCommand("/json/wiki/list")' /> |
| 193 | <input type='button' value='wiki/get Fossil' onclick='TheApp.cgi.sendCommand("/json/wiki/get",{"page":"Fossil"})' /> |
| 194 | |
| 195 | <!-- |
| 196 | <input type='button' value='get whiki' onclick='TheApp.cgi.getPages("whiki")' /> |
| 197 | <input type='button' value='get more' onclick='TheApp.cgi.getPages("HelloWorld/WhikiNews")' /> |
| 198 | <input type='button' value='get client data' onclick='TheApp.cgi.getPageClientData("HelloWorld/whiki/WhikiCommands")' /> |
| 199 |
+72
-4
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -1466,16 +1466,16 @@ | ||
| 1466 | 1466 | #undef SETBUF |
| 1467 | 1467 | } |
| 1468 | 1468 | |
| 1469 | 1469 | |
| 1470 | 1470 | static cson_value * json_wiki_list(unsigned int depth); |
| 1471 | - | |
| 1471 | +static cson_value * json_wiki_get(unsigned int depth); | |
| 1472 | 1472 | /* |
| 1473 | 1473 | ** Mapping of /json/wiki/XXX commands/paths to callbacks. |
| 1474 | 1474 | */ |
| 1475 | 1475 | static const JsonPageDef JsonPageDefs_Wiki[] = { |
| 1476 | -{"get", json_page_nyi, 0}, | |
| 1476 | +{"get", json_wiki_get, 0}, | |
| 1477 | 1477 | {"list", json_wiki_list, 0}, |
| 1478 | 1478 | {"save", json_page_nyi, 1}, |
| 1479 | 1479 | /* Last entry MUST have a NULL name. */ |
| 1480 | 1480 | {NULL,NULL,0} |
| 1481 | 1481 | }; |
| @@ -1520,17 +1520,86 @@ | ||
| 1520 | 1520 | */ |
| 1521 | 1521 | static cson_value * json_page_wiki(unsigned int depth){ |
| 1522 | 1522 | return json_page_dispatch_helper(depth,&JsonPageDefs_Wiki[0]); |
| 1523 | 1523 | } |
| 1524 | 1524 | |
| 1525 | + | |
| 1526 | +/* | |
| 1527 | +** Implementation of /json/wiki/get. | |
| 1528 | +** | |
| 1529 | +** TODO: add option to parse wiki output. It is currently | |
| 1530 | +** unparsed. | |
| 1531 | +*/ | |
| 1532 | +static cson_value * json_wiki_get(unsigned int depth){ | |
| 1533 | + int rid; | |
| 1534 | + Manifest *pWiki = 0; | |
| 1535 | + char const * zBody = NULL; | |
| 1536 | + char const * zPageName; | |
| 1537 | + char doParse = 0/*not yet implemented*/; | |
| 1538 | + | |
| 1539 | + if( !g.perm.RdWiki ){ | |
| 1540 | + g.json.resultCode = FSL_JSON_E_DENIED; | |
| 1541 | + return NULL; | |
| 1542 | + } | |
| 1543 | + zPageName = g.isHTTP | |
| 1544 | + ? json_getenv_cstr("page") | |
| 1545 | + : find_option("page","p",1); | |
| 1546 | + if(!zPageName||!*zPageName){ | |
| 1547 | + g.json.resultCode = FSL_JSON_E_MISSING_ARGS; | |
| 1548 | + return NULL; | |
| 1549 | + } | |
| 1550 | + rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" | |
| 1551 | + " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" | |
| 1552 | + " ORDER BY x.mtime DESC LIMIT 1", | |
| 1553 | + zPageName | |
| 1554 | + ); | |
| 1555 | + if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){ | |
| 1556 | + zBody = pWiki->zWiki; | |
| 1557 | + } | |
| 1558 | + if( zBody==0 ){ | |
| 1559 | + manifest_destroy(pWiki); | |
| 1560 | + g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; | |
| 1561 | + return NULL; | |
| 1562 | + }else{ | |
| 1563 | + unsigned int const len = strlen(zBody); | |
| 1564 | + cson_value * payV = cson_value_new_object(); | |
| 1565 | + cson_object * pay = cson_value_get_object(payV); | |
| 1566 | + cson_object_set(pay,"name",json_new_string(zPageName)); | |
| 1567 | + cson_object_set(pay,"version",json_new_string(pWiki->zBaseline)) | |
| 1568 | + /*FIXME: pWiki->zBaseline is NULL. How to get the version number?*/ | |
| 1569 | + ; | |
| 1570 | + cson_object_set(pay,"rid",cson_value_new_integer((cson_int_t)rid)); | |
| 1571 | + cson_object_set(pay,"lastSavedBy",json_new_string(pWiki->zUser)); | |
| 1572 | + cson_object_set(pay,"timestamp", | |
| 1573 | + cson_value_new_integer((cson_int_t) | |
| 1574 | + db_int64(0, | |
| 1575 | + "SELECT strftime('%%s',%lf)", | |
| 1576 | + pWiki->rDate | |
| 1577 | + ) | |
| 1578 | + ) | |
| 1579 | + ); | |
| 1580 | + cson_object_set(pay,"contentLength",cson_value_new_integer((cson_int_t)len)); | |
| 1581 | + cson_object_set(pay,"contentFormat",json_new_string(doParse?"html":"raw")); | |
| 1582 | + cson_object_set(pay,"content",cson_value_new_string(zBody,len)); | |
| 1583 | + /*TODO: add 'T' (tag) fields*/ | |
| 1584 | + /*TODO: add the 'A' card (file attachment) entries?*/ | |
| 1585 | + manifest_destroy(pWiki); | |
| 1586 | + return payV; | |
| 1587 | + } | |
| 1588 | +} | |
| 1589 | + | |
| 1525 | 1590 | /* |
| 1526 | -** INTERIM implementation of /json/wiki/list | |
| 1591 | +** Implementation of /json/wiki/list. | |
| 1527 | 1592 | */ |
| 1528 | 1593 | static cson_value * json_wiki_list(unsigned int depth){ |
| 1529 | 1594 | cson_value * listV = NULL; |
| 1530 | 1595 | cson_array * list = NULL; |
| 1531 | 1596 | Stmt q; |
| 1597 | + if( !g.perm.RdWiki ){ | |
| 1598 | + g.json.resultCode = FSL_JSON_E_DENIED; | |
| 1599 | + return NULL; | |
| 1600 | + } | |
| 1532 | 1601 | db_prepare(&q,"SELECT" |
| 1533 | 1602 | " substr(tagname,6) as name" |
| 1534 | 1603 | " FROM tag WHERE tagname GLOB 'wiki-*'" |
| 1535 | 1604 | " ORDER BY lower(name)"); |
| 1536 | 1605 | listV = cson_value_new_array(); |
| @@ -1551,11 +1620,10 @@ | ||
| 1551 | 1620 | listV = NULL; |
| 1552 | 1621 | end: |
| 1553 | 1622 | db_finalize(&q); |
| 1554 | 1623 | return listV; |
| 1555 | 1624 | } |
| 1556 | - | |
| 1557 | 1625 | |
| 1558 | 1626 | |
| 1559 | 1627 | static cson_value * json_branch_list(unsigned int depth); |
| 1560 | 1628 | /* |
| 1561 | 1629 | ** Mapping of /json/branch/XXX commands/paths to callbacks. |
| 1562 | 1630 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -1466,16 +1466,16 @@ | |
| 1466 | #undef SETBUF |
| 1467 | } |
| 1468 | |
| 1469 | |
| 1470 | static cson_value * json_wiki_list(unsigned int depth); |
| 1471 | |
| 1472 | /* |
| 1473 | ** Mapping of /json/wiki/XXX commands/paths to callbacks. |
| 1474 | */ |
| 1475 | static const JsonPageDef JsonPageDefs_Wiki[] = { |
| 1476 | {"get", json_page_nyi, 0}, |
| 1477 | {"list", json_wiki_list, 0}, |
| 1478 | {"save", json_page_nyi, 1}, |
| 1479 | /* Last entry MUST have a NULL name. */ |
| 1480 | {NULL,NULL,0} |
| 1481 | }; |
| @@ -1520,17 +1520,86 @@ | |
| 1520 | */ |
| 1521 | static cson_value * json_page_wiki(unsigned int depth){ |
| 1522 | return json_page_dispatch_helper(depth,&JsonPageDefs_Wiki[0]); |
| 1523 | } |
| 1524 | |
| 1525 | /* |
| 1526 | ** INTERIM implementation of /json/wiki/list |
| 1527 | */ |
| 1528 | static cson_value * json_wiki_list(unsigned int depth){ |
| 1529 | cson_value * listV = NULL; |
| 1530 | cson_array * list = NULL; |
| 1531 | Stmt q; |
| 1532 | db_prepare(&q,"SELECT" |
| 1533 | " substr(tagname,6) as name" |
| 1534 | " FROM tag WHERE tagname GLOB 'wiki-*'" |
| 1535 | " ORDER BY lower(name)"); |
| 1536 | listV = cson_value_new_array(); |
| @@ -1551,11 +1620,10 @@ | |
| 1551 | listV = NULL; |
| 1552 | end: |
| 1553 | db_finalize(&q); |
| 1554 | return listV; |
| 1555 | } |
| 1556 | |
| 1557 | |
| 1558 | |
| 1559 | static cson_value * json_branch_list(unsigned int depth); |
| 1560 | /* |
| 1561 | ** Mapping of /json/branch/XXX commands/paths to callbacks. |
| 1562 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -1466,16 +1466,16 @@ | |
| 1466 | #undef SETBUF |
| 1467 | } |
| 1468 | |
| 1469 | |
| 1470 | static cson_value * json_wiki_list(unsigned int depth); |
| 1471 | static cson_value * json_wiki_get(unsigned int depth); |
| 1472 | /* |
| 1473 | ** Mapping of /json/wiki/XXX commands/paths to callbacks. |
| 1474 | */ |
| 1475 | static const JsonPageDef JsonPageDefs_Wiki[] = { |
| 1476 | {"get", json_wiki_get, 0}, |
| 1477 | {"list", json_wiki_list, 0}, |
| 1478 | {"save", json_page_nyi, 1}, |
| 1479 | /* Last entry MUST have a NULL name. */ |
| 1480 | {NULL,NULL,0} |
| 1481 | }; |
| @@ -1520,17 +1520,86 @@ | |
| 1520 | */ |
| 1521 | static cson_value * json_page_wiki(unsigned int depth){ |
| 1522 | return json_page_dispatch_helper(depth,&JsonPageDefs_Wiki[0]); |
| 1523 | } |
| 1524 | |
| 1525 | |
| 1526 | /* |
| 1527 | ** Implementation of /json/wiki/get. |
| 1528 | ** |
| 1529 | ** TODO: add option to parse wiki output. It is currently |
| 1530 | ** unparsed. |
| 1531 | */ |
| 1532 | static cson_value * json_wiki_get(unsigned int depth){ |
| 1533 | int rid; |
| 1534 | Manifest *pWiki = 0; |
| 1535 | char const * zBody = NULL; |
| 1536 | char const * zPageName; |
| 1537 | char doParse = 0/*not yet implemented*/; |
| 1538 | |
| 1539 | if( !g.perm.RdWiki ){ |
| 1540 | g.json.resultCode = FSL_JSON_E_DENIED; |
| 1541 | return NULL; |
| 1542 | } |
| 1543 | zPageName = g.isHTTP |
| 1544 | ? json_getenv_cstr("page") |
| 1545 | : find_option("page","p",1); |
| 1546 | if(!zPageName||!*zPageName){ |
| 1547 | g.json.resultCode = FSL_JSON_E_MISSING_ARGS; |
| 1548 | return NULL; |
| 1549 | } |
| 1550 | rid = db_int(0, "SELECT x.rid FROM tag t, tagxref x" |
| 1551 | " WHERE x.tagid=t.tagid AND t.tagname='wiki-%q'" |
| 1552 | " ORDER BY x.mtime DESC LIMIT 1", |
| 1553 | zPageName |
| 1554 | ); |
| 1555 | if( (pWiki = manifest_get(rid, CFTYPE_WIKI))!=0 ){ |
| 1556 | zBody = pWiki->zWiki; |
| 1557 | } |
| 1558 | if( zBody==0 ){ |
| 1559 | manifest_destroy(pWiki); |
| 1560 | g.json.resultCode = FSL_JSON_E_RESOURCE_NOT_FOUND; |
| 1561 | return NULL; |
| 1562 | }else{ |
| 1563 | unsigned int const len = strlen(zBody); |
| 1564 | cson_value * payV = cson_value_new_object(); |
| 1565 | cson_object * pay = cson_value_get_object(payV); |
| 1566 | cson_object_set(pay,"name",json_new_string(zPageName)); |
| 1567 | cson_object_set(pay,"version",json_new_string(pWiki->zBaseline)) |
| 1568 | /*FIXME: pWiki->zBaseline is NULL. How to get the version number?*/ |
| 1569 | ; |
| 1570 | cson_object_set(pay,"rid",cson_value_new_integer((cson_int_t)rid)); |
| 1571 | cson_object_set(pay,"lastSavedBy",json_new_string(pWiki->zUser)); |
| 1572 | cson_object_set(pay,"timestamp", |
| 1573 | cson_value_new_integer((cson_int_t) |
| 1574 | db_int64(0, |
| 1575 | "SELECT strftime('%%s',%lf)", |
| 1576 | pWiki->rDate |
| 1577 | ) |
| 1578 | ) |
| 1579 | ); |
| 1580 | cson_object_set(pay,"contentLength",cson_value_new_integer((cson_int_t)len)); |
| 1581 | cson_object_set(pay,"contentFormat",json_new_string(doParse?"html":"raw")); |
| 1582 | cson_object_set(pay,"content",cson_value_new_string(zBody,len)); |
| 1583 | /*TODO: add 'T' (tag) fields*/ |
| 1584 | /*TODO: add the 'A' card (file attachment) entries?*/ |
| 1585 | manifest_destroy(pWiki); |
| 1586 | return payV; |
| 1587 | } |
| 1588 | } |
| 1589 | |
| 1590 | /* |
| 1591 | ** Implementation of /json/wiki/list. |
| 1592 | */ |
| 1593 | static cson_value * json_wiki_list(unsigned int depth){ |
| 1594 | cson_value * listV = NULL; |
| 1595 | cson_array * list = NULL; |
| 1596 | Stmt q; |
| 1597 | if( !g.perm.RdWiki ){ |
| 1598 | g.json.resultCode = FSL_JSON_E_DENIED; |
| 1599 | return NULL; |
| 1600 | } |
| 1601 | db_prepare(&q,"SELECT" |
| 1602 | " substr(tagname,6) as name" |
| 1603 | " FROM tag WHERE tagname GLOB 'wiki-*'" |
| 1604 | " ORDER BY lower(name)"); |
| 1605 | listV = cson_value_new_array(); |
| @@ -1551,11 +1620,10 @@ | |
| 1620 | listV = NULL; |
| 1621 | end: |
| 1622 | db_finalize(&q); |
| 1623 | return listV; |
| 1624 | } |
| 1625 | |
| 1626 | |
| 1627 | static cson_value * json_branch_list(unsigned int depth); |
| 1628 | /* |
| 1629 | ** Mapping of /json/branch/XXX commands/paths to callbacks. |
| 1630 |