Commit 464a15c39a
Verified · cmc
Layout: unified · split
app/api.go +4 −3
| @@ -20,13 +20,14 @@ type info struct { | |||
| 20 | Settings settingsParams `json:"settings"` | 20 | Settings settingsParams `json:"settings"` |
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | // Info responds with this instance's version and its proxy/NSFW settings. | 23 | // Info responds with this instance's version and its proxy/NSFW/hide-ai settings. |
| 24 | func (a API) Info() { | 24 | func (a API) Info() { |
| 25 | json, err := json.Marshal(info{ | 25 | json, err := json.Marshal(info{ |
| 26 | Version: a.main.Version, | 26 | Version: a.main.Version, |
| 27 | Settings: settingsParams{ | 27 | Settings: settingsParams{ |
| 28 | Nsfw: CFG.Nsfw, | 28 | Nsfw: CFG.Nsfw, |
| 29 | Proxy: CFG.Proxy, | 29 | Proxy: CFG.Proxy, |
| 30 | HideAI: CFG.HideAI, | ||
| 30 | }, | 31 | }, |
| 31 | }) | 32 | }) |
| 32 | try(err) | 33 | try(err) |
app/cli.go +6 −4
| @@ -55,8 +55,9 @@ type settingsUrls struct { | |||
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | type settingsParams struct { | 57 | type settingsParams struct { |
| 58 | Nsfw bool `json:"nsfw"` | 58 | Nsfw bool `json:"nsfw"` |
| 59 | Proxy bool `json:"proxy"` | 59 | Proxy bool `json:"proxy"` |
| 60 | HideAI bool `json:"hide-ai"` | ||
| 60 | } | 61 | } |
| 61 | 62 | ||
| 62 | type settings struct { | 63 | type settings struct { |
| @@ -112,8 +113,9 @@ func addInstance() { | |||
| 112 | Country: prompt("Country", true), | 113 | Country: prompt("Country", true), |
| 113 | ModifiedSrc: prompt("Link to modified sources", false), | 114 | ModifiedSrc: prompt("Link to modified sources", false), |
| 114 | Settings: settingsParams{ | 115 | Settings: settingsParams{ |
| 115 | Nsfw: CFG.Nsfw, | 116 | Nsfw: CFG.Nsfw, |
| 116 | Proxy: CFG.Proxy, | 117 | Proxy: CFG.Proxy, |
| 118 | HideAI: CFG.HideAI, | ||
| 117 | }, | 119 | }, |
| 118 | Urls: settingsUrls{ | 120 | Urls: settingsUrls{ |
| 119 | Clearnet: prompt("Clearnet link", false), | 121 | Clearnet: prompt("Clearnet link", false), |
app/config.go +3 −2
| @@ -134,8 +134,9 @@ func ExecuteConfig() { | |||
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | About = instanceAbout{ | 136 | About = instanceAbout{ |
| 137 | Proxy: CFG.Proxy, | 137 | Proxy: CFG.Proxy, |
| 138 | Nsfw: CFG.Nsfw, | 138 | Nsfw: CFG.Nsfw, |
| 139 | HideAI: CFG.HideAI, | ||
| 139 | } | 140 | } |
| 140 | 141 | ||
| 141 | static.StaticPath = CFG.StaticPath | 142 | static.StaticPath = CFG.StaticPath |
app/util.go +13 −4
| @@ -72,6 +72,7 @@ func RefreshInstances() { | |||
| 72 | type instanceAbout struct { | 72 | type instanceAbout struct { |
| 73 | Proxy bool `json:"proxy"` | 73 | Proxy bool `json:"proxy"` |
| 74 | Nsfw bool `json:"nsfw"` | 74 | Nsfw bool `json:"nsfw"` |
| 75 | HideAI bool `json:"hide-ai"` | ||
| 75 | Instances []settings `json:"instances"` | 76 | Instances []settings `json:"instances"` |
| 76 | } | 77 | } |
| 77 | 78 | ||
| @@ -337,9 +338,6 @@ type DeviationList struct { | |||
| 337 | } | 338 | } |
| 338 | 339 | ||
| 339 | // NavBase renders the page navigation bar for a list. | 340 | // NavBase renders the page navigation bar for a list. |
| 340 | // | ||
| 341 | // FIXME: on some artworks the first page can make the navigation panel disappear | ||
| 342 | // entirely. | ||
| 343 | func (s skunkyart) NavBase(c DeviationList) string { | 341 | func (s skunkyart) NavBase(c DeviationList) string { |
| 344 | var list strings.Builder | 342 | var list strings.Builder |
| 345 | 343 | ||
| @@ -379,7 +377,18 @@ func (s skunkyart) NavBase(c DeviationList) string { | |||
| 379 | p = 1 | 377 | p = 1 |
| 380 | } | 378 | } |
| 381 | 379 | ||
| 382 | for i, x := p-6, 0; (i <= c.Pages && i <= p+6) && x < 12; i++ { | 380 | // The window runs to the last page or the current one, whichever is further |
| 381 | // out. Callers that cannot count pages pass Pages: 0 — the comment list on an | ||
| 382 | // artwork is one — and bounding purely by Pages then ended the loop before | ||
| 383 | // i reached 1, so page one rendered no numbers at all. With nothing before it | ||
| 384 | // to link back to and no further page to link on, the whole panel came out as | ||
| 385 | // a bare <br>. | ||
| 386 | last := c.Pages | ||
| 387 | if p > last { | ||
| 388 | last = p | ||
| 389 | } | ||
| 390 | |||
| 391 | for i, x := p-6, 0; (i <= last && i <= p+6) && x < 12; i++ { | ||
| 383 | if i > 0 { | 392 | if i > 0 { |
| 384 | var onPage bool | 393 | var onPage bool |
| 385 | if i == p { | 394 | if i == p { |
app/util_test.go added +74
| @@ -0,0 +1,74 @@ | |||
| 1 | package app | ||
| 2 | |||
| 3 | import ( | ||
| 4 | "strings" | ||
| 5 | "testing" | ||
| 6 | ) | ||
| 7 | |||
| 8 | // TestNavBaseRendersFirstPageWithoutPageCount is the regression test for the | ||
| 9 | // navigation panel vanishing on some artworks. The comment list on a deviation | ||
| 10 | // cannot count its pages, so it passes Pages: 0; on page one, with no further | ||
| 11 | // page to offer, the panel used to render as nothing but a <br>. | ||
| 12 | func TestNavBaseRendersFirstPageWithoutPageCount(t *testing.T) { | ||
| 13 | s := skunkyart{Page: 1, _pth: "/deviation/1"} | ||
| 14 | |||
| 15 | out := s.NavBase(DeviationList{Pages: 0, More: false}) | ||
| 16 | |||
| 17 | if strings.TrimSpace(strings.TrimPrefix(out, "<br>")) == "" { | ||
| 18 | t.Fatalf("navigation panel is empty, want the current page rendered: %q", out) | ||
| 19 | } | ||
| 20 | if !strings.Contains(out, "1") { | ||
| 21 | t.Errorf("current page number missing from %q", out) | ||
| 22 | } | ||
| 23 | } | ||
| 24 | |||
| 25 | // TestNavBaseFirstPageOffersNextWhenMore covers the same Pages: 0 case when a | ||
| 26 | // further page does exist: the current page must still appear alongside Next, | ||
| 27 | // rather than Next standing on its own with nothing to anchor it. | ||
| 28 | func TestNavBaseFirstPageOffersNextWhenMore(t *testing.T) { | ||
| 29 | s := skunkyart{Page: 1, _pth: "/deviation/1"} | ||
| 30 | |||
| 31 | out := s.NavBase(DeviationList{Pages: 0, More: true}) | ||
| 32 | |||
| 33 | if !strings.Contains(out, "Next") { | ||
| 34 | t.Errorf("Next link missing from %q", out) | ||
| 35 | } | ||
| 36 | if !strings.Contains(out, "1") { | ||
| 37 | t.Errorf("current page number missing from %q", out) | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | // TestNavBaseKnownPageCountUnchanged pins the ordinary path: when the caller | ||
| 42 | // does know the page count, the window is still bounded by it. | ||
| 43 | func TestNavBaseKnownPageCountUnchanged(t *testing.T) { | ||
| 44 | s := skunkyart{Page: 1, _pth: "/gallery"} | ||
| 45 | |||
| 46 | out := s.NavBase(DeviationList{Pages: 3, More: true}) | ||
| 47 | |||
| 48 | for _, want := range []string{"1", "2", "3"} { | ||
| 49 | if !strings.Contains(out, want) { | ||
| 50 | t.Errorf("page %s missing from %q", want, out) | ||
| 51 | } | ||
| 52 | } | ||
| 53 | if strings.Contains(out, "p=4") { | ||
| 54 | t.Errorf("linked past the last page in %q", out) | ||
| 55 | } | ||
| 56 | } | ||
| 57 | |||
| 58 | // TestInstanceAboutCarriesHideAI covers the About page and /api/instance both | ||
| 59 | // reading hide-ai from config, so a visitor can tell whether an instance | ||
| 60 | // filters AI-generated works without inferring it from absent results. | ||
| 61 | func TestInstanceAboutCarriesHideAI(t *testing.T) { | ||
| 62 | hide := CFG.HideAI | ||
| 63 | defer func() { CFG.HideAI = hide }() | ||
| 64 | |||
| 65 | for _, on := range []bool{true, false} { | ||
| 66 | CFG.HideAI = on | ||
| 67 | if got := (instanceAbout{HideAI: CFG.HideAI}).HideAI; got != on { | ||
| 68 | t.Errorf("instanceAbout.HideAI = %v, want %v", got, on) | ||
| 69 | } | ||
| 70 | if got := (settingsParams{HideAI: CFG.HideAI}).HideAI; got != on { | ||
| 71 | t.Errorf("settingsParams.HideAI = %v, want %v", got, on) | ||
| 72 | } | ||
| 73 | } | ||
| 74 | } | ||
static/html/about.htm +1
| @@ -11,6 +11,7 @@ | |||
| 11 | <ul> | 11 | <ul> |
| 12 | <li><b>NSFW</b>: <span class="about-{{.Templates.About.Nsfw}}">{{if .Templates.About.Nsfw}}YES{{else}}NO{{end}}</span></li> | 12 | <li><b>NSFW</b>: <span class="about-{{.Templates.About.Nsfw}}">{{if .Templates.About.Nsfw}}YES{{else}}NO{{end}}</span></li> |
| 13 | <li><b>Proxyfing</b>: <span class="about-{{.Templates.About.Proxy}}">{{if .Templates.About.Proxy}}YES{{else}}NO{{end}}</span></li> | 13 | <li><b>Proxyfing</b>: <span class="about-{{.Templates.About.Proxy}}">{{if .Templates.About.Proxy}}YES{{else}}NO{{end}}</span></li> |
| 14 | <li><b>Hide AI</b>: <span class="about-{{.Templates.About.HideAI}}">{{if .Templates.About.HideAI}}YES{{else}}NO{{end}}</span></li> | ||
| 14 | </ul> | 15 | </ul> |
| 15 | <details> | 16 | <details> |
| 16 | <summary><b>Instances:</b></summary> | 17 | <summary><b>Instances:</b></summary> |