diff --git a/pkg/importer/html.go b/pkg/importer/html.go
index 6dbae9f86..0802238ed 100644
--- a/pkg/importer/html.go
+++ b/pkg/importer/html.go
@@ -23,12 +23,14 @@ import (
"net/http"
"strings"
"time"
+
+ "camlistore.org/pkg/blob"
)
-func execTemplate(w http.ResponseWriter, r *http.Request, data interface{}) {
+func (h *Host) execTemplate(w http.ResponseWriter, r *http.Request, data interface{}) {
tmplName := strings.TrimPrefix(fmt.Sprintf("%T", data), "importer.")
var buf bytes.Buffer
- err := tmpl.ExecuteTemplate(&buf, tmplName, data)
+ err := h.tmpl.ExecuteTemplate(&buf, tmplName, data)
if err != nil {
http.Error(w, fmt.Sprintf("Error executing template %q: %v", tmplName, err), 500)
return
@@ -72,7 +74,11 @@ type acctBody struct {
LastError string
}
-var tmpl = template.Must(template.New("root").Parse(`
+var tmpl = template.Must(template.New("root").Funcs(map[string]interface{}{
+ "bloblink": func(br blob.Ref) string {
+ panic("should be overridden; this one won't be called")
+ },
+}).Parse(`
{{define "pageTop"}}
@@ -113,7 +119,7 @@ var tmpl = template.Must(template.New("root").Parse(`
{{define "importerBody"}}
[<< Back]
- - Importer configuration permanode: {{.Importer.Node.PermanodeRef}}
+ - Importer configuration permanode: {{.Importer.Node.PermanodeRef | bloblink}}
- Status: {{.Importer.Status}}
@@ -157,8 +163,8 @@ var tmpl = template.Must(template.New("root").Parse(`
[<< Back]
- Account type: {{.AcctType}}
- - Account metadata permanode: {{.Acct.AccountObject.PermanodeRef}}
- - Import root permanode: {{if .Acct.RootObject}}{{.Acct.RootObject.PermanodeRef}}{{else}}(none){{end}}
+ - Account metadata permanode: {{.Acct.AccountObject.PermanodeRef | bloblink}}
+ - Import root permanode: {{if .Acct.RootObject}}{{.Acct.RootObject.PermanodeRef | bloblink}}{{else}}(none){{end}}
- Configured: {{.Acct.IsAccountReady}}
- Summary: {{.Acct.AccountLinkSummary}}
- Import interval: {{if .Acct.RefreshInterval}}{{.Acct.RefreshInterval}}{{else}}(manual){{end}}
diff --git a/pkg/importer/importer.go b/pkg/importer/importer.go
index d9027d066..5f85795b3 100644
--- a/pkg/importer/importer.go
+++ b/pkg/importer/importer.go
@@ -111,6 +111,19 @@ func newFromConfig(ld blobserver.Loader, cfg jsonconfig.Obj) (http.Handler, erro
importerBase: ld.BaseURL() + ld.MyPrefix(),
imp: make(map[string]*importer),
}
+ var err error
+ h.tmpl, err = tmpl.Clone()
+ if err != nil {
+ return nil, err
+ }
+ h.tmpl = h.tmpl.Funcs(map[string]interface{}{
+ "bloblink": func(br blob.Ref) template.HTML {
+ if h.uiPrefix == "" {
+ return template.HTML(br.String())
+ }
+ return template.HTML(fmt.Sprintf("%s", h.uiPrefix, br, br))
+ },
+ })
for k, impl := range importers {
h.importers = append(h.importers, k)
var clientID, clientSecret string
@@ -214,6 +227,7 @@ func (rc *RunContext) RootNode() *Object { return rc.ia.root }
// Host is the HTTP handler and state for managing all the importers
// linked into the binary, even if they're not configured.
type Host struct {
+ tmpl *template.Template
importers []string // sorted; e.g. dummy flickr foursquare picasa twitter
imp map[string]*importer
baseURL string
@@ -221,6 +235,7 @@ type Host struct {
target blobserver.StatReceiver
search *search.Handler
signer *schema.Signer
+ uiPrefix string // or empty if no UI handler
// client optionally specifies how to fetch external network
// resources. If nil, http.DefaultClient is used.
@@ -229,6 +244,10 @@ type Host struct {
}
func (h *Host) InitHandler(hl blobserver.FindHandlerByTyper) error {
+ if prefix, _, err := hl.FindHandlerByType("ui"); err == nil {
+ h.uiPrefix = prefix
+ }
+
_, handler, err := hl.FindHandlerByType("root")
if err != nil || handler == nil {
return errors.New("importer requires a 'root' handler")
@@ -251,6 +270,7 @@ func (h *Host) InitHandler(hl blobserver.FindHandlerByTyper) error {
if h.signer == nil {
return errors.New("importer requires a 'jsonsign' handler")
}
+ go h.startPeriodicImporters()
return nil
}
@@ -299,7 +319,7 @@ func (h *Host) serveImportersRoot(w http.ResponseWriter, r *http.Request) {
for _, v := range h.importers {
body.Importers = append(body.Importers, h.imp[v])
}
- execTemplate(w, r, importersRootPage{
+ h.execTemplate(w, r, importersRootPage{
Title: "Importers",
Body: body,
})
@@ -318,7 +338,7 @@ func (h *Host) serveImporter(w http.ResponseWriter, r *http.Request, imp *import
setup = setuper.AccountSetupHTML(h)
}
- execTemplate(w, r, importerPage{
+ h.execTemplate(w, r, importerPage{
Title: "Importer - " + imp.Name(),
Body: importerBody{
Host: h,
@@ -391,6 +411,20 @@ func (h *Host) serveImporterAccount(w http.ResponseWriter, r *http.Request, imp
ia.ServeHTTP(w, r)
}
+func (h *Host) startPeriodicImporters() {
+ res, err := h.search.Query(&search.SearchQuery{
+ Expression: "attr:camliNodeType:importerAccount",
+ Describe: &search.DescribeRequest{
+ Depth: 1,
+ },
+ })
+ if err != nil {
+ log.Printf("periodic importer search fail: %v", err)
+ return
+ }
+ log.Printf("TODO: periodic importer search: %#v", res)
+}
+
// BaseURL returns the root of the whole server, without trailing
// slash.
func (h *Host) BaseURL() string {
@@ -742,7 +776,7 @@ func (ia *importerAcct) ServeHTTP(w http.ResponseWriter, r *http.Request) {
} else {
title += ia.acct.PermanodeRef().String()
}
- execTemplate(w, r, acctPage{
+ ia.im.host.execTemplate(w, r, acctPage{
Title: title,
Body: body,
})