mirror of https://github.com/perkeep/perkeep.git
search + UI support for finding paths of a permanode
Change-Id: Iae9cfed38660204cf7e85342cd951d542a7258a2
This commit is contained in:
parent
b2edc4a5f9
commit
40739efa6b
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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=" +
|
||||
|
|
|
@ -51,6 +51,8 @@
|
|||
</p>
|
||||
</form>
|
||||
|
||||
<div id="existingPaths"></div>
|
||||
|
||||
<div id="content"></div>
|
||||
|
||||
<div id="members"></div>
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue