oficina / sheets Public

Clone
git clone https://amadan.net/oficina/sheets

Plain git — no account needed to clone.

Download

Download this file

1package sheets
2
3import "net/http"
4
5// The import page.
6//
7// Separate from handlers_import.go, which holds the POST that does the
8// work, for the dullest possible reason: together they were 305 lines
9// and the file cap is 300 (AGENTS.md / Mechanical rules, enforced by
10// TestFileLineCap). The split falls in a sensible place anyway — this
11// file is the screen, that one is the upload.
12
13// importPageView is the import page's payload.
14type importPageView struct {
15 // Error is a refusal to show above the form — one of the refusal
16 // constants in handlers_import.go, never a wrapped error, because
17 // everything shown here is read by somebody deciding what to do
18 // differently.
19 Error string
20}
21
22// handleImportPage draws the import form on a page of its own.
23//
24// Import used to be a second form on the sheet list, below the form
25// that made a blank sheet. Both came off that page: a list of sheets
26// should be a list of sheets, and the verbs moved into the chrome
27// around it.
28//
29// A page rather than an item inside the File menu, which is where this
30// nearly went. Three reasons, and the third is the one that decided it:
31// a dropdown is a poor container for a file picker plus three limits; a
32// hidden input behind a menu-shaped label never submits itself, so that
33// menu item would have needed script to import anything at all, and
34// import is meant to work with scripting off; and the File menu exists
35// only on a sheet page, so somebody with no sheets yet — exactly the
36// person most likely to be importing one — would have had no way in.
37func (a *App) handleImportPage(w http.ResponseWriter, r *http.Request) {
38 // Behind requireSession already; this is the same belt-and-braces
39 // actor check the sibling handlers make, and it is what makes the
40 // handler safe to call from a test that does not mount the group.
41 if _, ok := a.actor(r); !ok {
42 a.forbidden(w, r)
43 return
44 }
45 a.renderImportPage(w, r, http.StatusOK, "")
46}
47
48// renderImportPage draws that form, optionally carrying a refusal and
49// the status that goes with it.
50//
51// A refused import re-renders this page rather than redirecting to it,
52// so the refusal survives without a flash: the person lands back on the
53// form they posted from, with the reason above it. No session storage,
54// no cookie, no redirect, and it works with scripting off by
55// construction. That reasoning arrived here from renderSheetList along
56// with the form itself.
57func (a *App) renderImportPage(w http.ResponseWriter, r *http.Request, status int, refusal string) {
58 a.render(w, r, "import", titled("Import a spreadsheet"), status,
59 importPageView{Error: refusal})
60}
61