1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16
17 package importer
18
19 import (
20 "bytes"
21 "fmt"
22 "html/template"
23 "net/http"
24 "strings"
25 "time"
26
27 "perkeep.org/pkg/blob"
28 )
29
30 func (h *Host) execTemplate(w http.ResponseWriter, r *http.Request, data interface{}) {
31 tmplName := strings.TrimPrefix(fmt.Sprintf("%T", data), "importer.")
32 var buf bytes.Buffer
33 err := h.tmpl.ExecuteTemplate(&buf, tmplName, data)
34 if err != nil {
35 http.Error(w, fmt.Sprintf("Error executing template %q: %v", tmplName, err), 500)
36 return
37 }
38 w.Write(buf.Bytes())
39 }
40
41 type importersRootPage struct {
42 Title string
43 Body importersRootBody
44 }
45
46 type importersRootBody struct {
47 Host *Host
48 Importers []*importer
49 }
50
51 type importerPage struct {
52 Title string
53 Body importerBody
54 }
55
56 type importerBody struct {
57 Host *Host
58 Importer *importer
59 SetupHelp template.HTML
60 }
61
62 type acctPage struct {
63 Title string
64 Body acctBody
65 }
66
67 type acctBody struct {
68 Acct *importerAcct
69 AcctType string
70 Running bool
71 LastStatus string
72 StartedAgo time.Duration
73 LastAgo time.Duration
74 LastError string
75 }
76
77 var tmpl = template.Must(template.New("root").Funcs(map[string]interface{}{
78 "bloblink": func(br blob.Ref) string {
79 panic("should be overridden; this one won't be called")
80 },
81 }).Parse(`
82 {{define "pageTop"}}
83 <html>
84 <head>
85 <title>{{.Title}}</title>
86 </head>
87 <body>
88 <h1>{{.Title}}</h1>
89 {{end}}
90
91 {{define "pageBottom"}}
92 </body>
93 </html>
94 {{end}}
95
96
97 {{define "importersRootPage"}}
98 {{template "pageTop" .}}
99 {{template "importersRootBody" .Body}}
100 {{template "pageBottom"}}
101 {{end}}
102
103 {{define "importersRootBody"}}
104 <ul>
105 {{$base := .Host.ImporterBaseURL}}
106 {{range .Importers}}
107 {{if .TODOIssue}}
108 <li><b>{{.Title}}</b>: TODO: <a href="https://perkeep.org/issue/{{.TODOIssue}}">Issue {{.TODOIssue}}</a></li>
109 {{else}}
110 <li><b><a href="{{$base}}{{.Name}}">{{.Title}}</a></b>{{if .Description}}: {{.Description}}{{end}}</li>
111 {{end}}
112 {{end}}
113 </ul>
114 {{end}}
115
116
117 {{define "importerPage"}}
118 {{template "pageTop" .}}
119 {{template "importerBody" .Body}}
120 {{template "pageBottom"}}
121 {{end}}
122
123 {{define "importerBody"}}
124 <p>[<a href="{{.Host.ImporterBaseURL}}"><< Back</a>]</p>
125 <ul>
126 <li>Importer configuration permanode: {{.Importer.Node.PermanodeRef | bloblink}}</li>
127 <li>Status: {{.Importer.Status}}</li>
128 </ul>
129
130 {{if .Importer.ShowClientAuthEditForm}}
131 {{if .Importer.InsecureForm}}
132 <h1 style="color:red;">This page is not served securely (no https). Proceed at your own risk.</h1>
133 {{end}}
134 <h1>Client ID & Client Secret</h1>
135 <form method='post'>
136 <input type='hidden' name="mode" value="saveclientidsecret">
137 <table border=0 cellpadding=3>
138 <tr><td align=right>Client ID</td><td><input name="clientID" size=50 value="{{.Importer.ClientID}}"></td></tr>
139 <tr><td align=right>Client Secret</td><td><input name="clientSecret" type=password size=50 value="{{.Importer.ClientSecret}}"></td></tr>
140 <tr><td align=right></td><td><input type='submit' value="Save"></td></tr>
141 </table>
142 </form>
143 {{end}}
144
145 {{.SetupHelp}}
146
147
148 <h1>Accounts</h1>
149 <ul>
150 {{range .Importer.Accounts}}
151 <li><a href="{{.AccountURL}}">{{.AccountLinkText}}</a> {{.AccountLinkSummary}}</li>
152 {{end}}
153 </ul>
154 {{if .Importer.CanAddNewAccount}}
155 <form method='post'>
156 <input type='hidden' name="mode" value="newacct">
157 <input type='submit' value="Add new account">
158 </form>
159 {{end}}
160
161 {{end}}
162
163 {{define "acctPage"}}
164 {{template "pageTop" .}}
165 {{template "acctBody" .Body}}
166 {{template "pageBottom"}}
167 {{end}}
168
169 {{define "acctBody"}}
170 <p>[<a href="./"><< Back</a>]</p>
171 <ul>
172 <li>Account type: {{.AcctType}}</li>
173 <li>Account metadata permanode: {{.Acct.AccountObject.PermanodeRef | bloblink}}</li>
174 <li>Import root permanode: {{if .Acct.RootObject}}{{.Acct.RootObject.PermanodeRef | bloblink}}{{else}}(none){{end}}</li>
175 <li>Configured: {{.Acct.IsAccountReady}}</li>
176 <li>Summary: {{.Acct.AccountLinkSummary}}</li>
177 <li>Import interval: {{if .Acct.RefreshInterval}}{{.Acct.RefreshInterval}}{{else}}(manual){{end}}</li>
178 <li>Running: {{.Running}}</li>
179 {{if .Running}}
180 <li>Started: {{.StartedAgo}} ago</li>
181 <li>Last status: {{.LastStatus}}</li>
182 {{else}}
183 {{if .LastAgo}}
184 <li>Previous run: {{.LastAgo}} ago{{if .LastError}}: {{.LastError}}{{else}} (success){{end}}</li>
185 {{end}}
186 {{end}}
187 </ul>
188
189 {{if .Acct.IsAccountReady}}
190 <form method='post' style='display: inline'>
191 {{if .Running}}
192 <input type='hidden' name='mode' value='stop'>
193 <input type='submit' value='Pause Import'>
194 {{else}}
195 <input type='hidden' name='mode' value='start'>
196 <input type='submit' value='Start Import'>
197 {{end}}
198 </form>
199 {{end}}
200
201 <form method='post' style='display: inline'>
202 <input type='hidden' name='mode' value='login'>
203 <input type='submit' value='Re-login'>
204 </form>
205
206 <form method='post' style='display: inline'>
207 <input type='hidden' name='mode' value='toggleauto'>
208 <input type='submit' value='Toggle auto'>
209 </form>
210
211 <form method='post' style='display: inline'>
212 <input type='hidden' name='mode' value='delete'>
213 <input type='submit' value='Delete Account' onclick='return confirm("Delete account?")'>
214 </form>
215
216 {{end}}
217
218 `))