search + UI support for finding paths of a permanode

Change-Id: Iae9cfed38660204cf7e85342cd951d542a7258a2
This commit is contained in:
Brad Fitzpatrick 2011-06-25 17:50:38 -07:00
parent b2edc4a5f9
commit 40739efa6b
6 changed files with 153 additions and 0 deletions

View File

@ -344,3 +344,61 @@ func (mi *Indexer) PermanodeOfSignerAttrValue(signer *blobref.BlobRef, attr, val
}
return blobref.Parse(row[0].(string)), nil
}
func (mi *Indexer) PathsOfSignerTarget(signer, target *blobref.BlobRef) (paths []*search.Path, err os.Error) {
keyId, err := mi.keyIdOfSigner(signer)
if err != nil {
return
}
client, err := mi.getConnection()
if err != nil {
return
}
defer func() {
if err == nil {
mi.releaseConnection(client)
} else {
client.Close()
}
}()
// TODO: lame %q quoting not SQL compatible; should use SQL ? bind params
err = client.Query(fmt.Sprintf("SELECT claimref, claimdate, baseref, suffix FROM path WHERE keyid=%q AND targetref=%q",
keyId, target.String()))
if err != nil {
return
}
result, err := client.StoreResult()
if err != nil {
return
}
defer client.FreeResult()
mostRecent := make(map[string]*search.Path)
for {
row := result.FetchRow()
if row == nil {
break
}
claimRef, claimDate, baseRef, suffix :=
blobref.MustParse(row[0].(string)), row[1].(string),
blobref.MustParse(row[2].(string)), row[3].(string)
key := baseRef.String() + "/" + suffix
best, ok := mostRecent[key]
if !ok || claimDate > best.ClaimDate {
mostRecent[key] = &search.Path{
Claim: claimRef,
ClaimDate: claimDate,
Base: baseRef,
Suffix: suffix,
}
}
}
paths = make([]*search.Path, 0)
for _, v := range mostRecent {
paths = append(paths, v)
}
return paths, nil
}

View File

@ -106,6 +106,9 @@ func (sh *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
case "camli/search/signerattrvalue":
sh.serveSignerAttrValue(rw, req)
return
case "camli/search/signerpaths":
sh.serveSignerPaths(rw, req)
return
}
}
@ -423,6 +426,34 @@ func (sh *Handler) serveSignerAttrValue(rw http.ResponseWriter, req *http.Reques
}
}
func (sh *Handler) serveSignerPaths(rw http.ResponseWriter, req *http.Request) {
ret := jsonMap()
defer httputil.ReturnJson(rw, ret)
defer setPanicError(ret)
signer := blobref.MustParse(mustGet(req, "signer"))
target := blobref.MustParse(mustGet(req, "target"))
paths, err := sh.index.PathsOfSignerTarget(signer, target)
if err != nil {
ret["error"] = err.String()
} else {
jpaths := []map[string]interface{}{}
for _, path := range paths {
jpaths = append(jpaths, map[string]interface{}{
"claimRef": path.Claim.String(),
"baseRef": path.Base.String(),
"suffix": path.Suffix,
})
}
ret["paths"] = jpaths
dr := &describeRequest{sh: sh, m: ret, wg: new(sync.WaitGroup)}
for _, path := range paths {
dr.describe(path.Base, 2)
}
dr.wg.Wait()
}
}
const camliTypePrefix = "application/json; camliType="
func setMimeType(m map[string]interface{}, mime string) {

View File

@ -61,6 +61,12 @@ type FileInfo struct {
MimeType string
}
type Path struct {
Claim, Base *blobref.BlobRef
ClaimDate string
Suffix string
}
type Index interface {
// dest is closed
// limit is <= 0 for default. smallest possible default is 0
@ -87,4 +93,6 @@ type Index interface {
// and specific 'value', find the most recent permanode that has
// a corresponding 'set-attribute' claim attached.
PermanodeOfSignerAttrValue(signer *blobref.BlobRef, attr, val string) (*blobref.BlobRef, os.Error)
PathsOfSignerTarget(signer *blobref.BlobRef, target *blobref.BlobRef) ([]*Path, os.Error)
}

View File

@ -101,6 +101,15 @@ function camliPermanodeOfSignerAttrValue(signer, attr, value, opts) {
xhr.send();
}
// Where is the target accessed via? (paths it's at)
function camliPathsOfSignerTarget(signer, target, opts) {
var xhr = camliJsonXhr("camliPathsOfSignerTarget", opts);
var path = makeURL(Camli.config.searchRoot + "camli/search/signerpaths",
{ signer: signer, target: target });
xhr.open("GET", path, true);
xhr.send();
}
function camliGetPermanodeClaims(permanode, opts) {
var xhr = camliJsonXhr("camliGetPermanodeClaims", opts);
var path = Camli.config.searchRoot + "camli/search/claims?permanode=" +

View File

@ -51,6 +51,8 @@
</p>
</form>
<div id="existingPaths"></div>
<div id="content"></div>
<div id="members"></div>

View File

@ -473,6 +473,9 @@ function onBtnSavePublish(e) {
attrcb.success = function() {
console.log("success.");
enabled();
selRoots.value = "";
suffix.value = "";
buildPathsList();
};
attrcb.fail = function() {
alert("failed to set attribute");
@ -493,6 +496,47 @@ function onBtnSavePublish(e) {
camliSigDiscovery(sigcb);
}
function buildPathsList() {
var ourPermanode = getPermanodeParam();
if (!ourPermanode) {
return;
}
var sigcb = {};
sigcb.success = function(sigconf) {
var findpathcb = {};
findpathcb.success = function(jres) {
var div = document.getElementById("existingPaths");
// TODO: there can be multiple paths in this list, but the HTML
// UI only shows one. The UI should show all, and when adding a new one
// prompt users whether they want to add to or replace the existing one.
// For now we just update the UI to show one.
// alert(JSON.stringify(jres, null, 2));
if (jres.paths && jres.paths.length > 0) {
div.innerHTML = "Existing paths for this permanode:";
var ul = document.createElement("ul");
div.appendChild(ul);
for (var idx in jres.paths) {
var path = jres.paths[idx];
var li = document.createElement("li");
ul.appendChild(li);
li.innerHTML = "<a></a> - ";
li.firstChild.href = ".?p=" + path.baseRef;
li.firstChild.innerText = path.baseRef;
li.appendChild(document.createTextNode(path.suffix));
}
} else {
div.innerHTML = "";
}
};
camliPathsOfSignerTarget(sigconf.publicKeyBlobRef, ourPermanode, findpathcb);
};
sigcb.fail = function() {
alert("sig disco failed");
}
camliSigDiscovery(sigcb);
}
function permanodePageOnLoad(e) {
var permanode = getPermanodeParam();
if (permanode) {
@ -515,6 +559,7 @@ function permanodePageOnLoad(e) {
setupFilesHandlers();
buildPermanodeUi();
buildPathsList();
}
window.addEventListener("load", permanodePageOnLoad);