content,internal/frontend: add redirect banner for alternative modules
When a request is redirected from an alternative module path, a banner
is added which displays that result.
Fixes golang/go#43518
Change-Id: Ifed01073561b5a55a053c626691cfc176d936440
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/281678
Trust: Julie Qiu <julie@golang.org>
Run-TryBot: Julie Qiu <julie@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jonathan Amsterdam <jba@google.com>
diff --git a/content/lib/css/unit_header.css b/content/lib/css/unit_header.css
index fd2dcf7..271c96e 100644
--- a/content/lib/css/unit_header.css
+++ b/content/lib/css/unit_header.css
@@ -100,6 +100,8 @@
.DetailsHeader-badge--unknown {
display: none;
}
+
+.UnitHeader-flashBanner,
.UnitHeader-majorVersionBanner {
background-color: var(--gray-10);
display: flex;
diff --git a/content/static/css/unit_header.css b/content/static/css/unit_header.css
index 7bf59a1..05a3b90 100644
--- a/content/static/css/unit_header.css
+++ b/content/static/css/unit_header.css
@@ -2,5 +2,5 @@
* Copyright 2020 The Go Authors. All rights reserved.
* Use of this source code is governed by a BSD-style
* license that can be found in the LICENSE file.
- */.UnitHeader{border-bottom:.0625rem solid var(--gray-8);padding:.5rem 1rem}@media only screen and (min-width:57.7rem){.UnitHeader{border-bottom:.0625rem solid var(--gray-8);padding:.5rem 1.5rem}}.UnitHeader-container{margin:auto;max-width:95rem}.UnitHeader-breadcrumb{margin-top:.5rem}.UnitHeader-breadcrumbItem{color:var(--gray-4);display:inline-flex;font-size:.875rem;line-height:1.5rem}.UnitHeader-breadcrumbItem:not(:last-child):after{content:">";padding:0 .5rem}.UnitHeader-heading{display:flex;align-items:center}.UnitHeader-title{font-size:1.75rem;line-height:2.25rem;margin-bottom:1rem;margin-top:.625rem}.UnitHeader-detail{align-items:center;display:flex;flex-wrap:wrap;white-space:nowrap}@media only screen and (min-width:52rem){.UnitHeader-detail{margin-bottom:.5rem}}.UnitHeader-detailItem{color:var(--gray-4);font-size:.875rem;margin-bottom:.5rem}.UnitHeader-detailItem img{margin-right:.5rem;vertical-align:middle}.UnitHeader-detailItem a>span{color:var(--gray-4)}.UnitHeader-detailItem:not(:first-of-type):before{content:"|";padding:1rem}@media only screen and (max-width:52rem){.UnitHeader-detailItem:not(:last-of-type):before{padding:.5rem}}.DetailsHeader-badge,.UnitHeader-versionBadge{border-radius:unset;color:#fff;font-size:.7rem;margin:-1rem 0 -1rem .5rem;padding:.25rem .5rem;text-transform:uppercase;top:-.0625rem}.DetailsHeader-badge--latest,.UnitHeader-versionBadge--latest{background:var(--turq-dark)}.DetailsHeader-badge--goToLatest,.UnitHeader-versionBadge--goToLatest{background:var(--pink)}.DetailsHeader-badge--unknown,.UnitHeader-versionBadge--unknown{display:none}.UnitHeader-majorVersionBanner{background-color:var(--gray-10);display:flex;margin:-.5rem 0 1rem;padding:.75rem 0}.DetailsHeader-banner--latest,.UnitHeader-majorVersionBanner--latest{display:none}.UnitHeader-detailIcon{color:var(--gray-3);flex-shrink:0;margin-left:1rem;margin-right:.7rem;width:1rem}a.UnitHeader-backLink{color:#000;display:block;font-size:1rem}.UnitHeader-backLink img{height:.8125rem;margin-right:.5rem;position:relative;top:-.0625rem;width:auto}.UnitHeader-badge{border:.0625rem solid var(--gray-4);border-radius:.125rem;font-size:.6875rem;font-weight:500;line-height:1rem;margin-left:.5rem;padding:0 .35rem;text-align:center}
+ */.UnitHeader{border-bottom:.0625rem solid var(--gray-8);padding:.5rem 1rem}@media only screen and (min-width:57.7rem){.UnitHeader{border-bottom:.0625rem solid var(--gray-8);padding:.5rem 1.5rem}}.UnitHeader-container{margin:auto;max-width:95rem}.UnitHeader-breadcrumb{margin-top:.5rem}.UnitHeader-breadcrumbItem{color:var(--gray-4);display:inline-flex;font-size:.875rem;line-height:1.5rem}.UnitHeader-breadcrumbItem:not(:last-child):after{content:">";padding:0 .5rem}.UnitHeader-heading{display:flex;align-items:center}.UnitHeader-title{font-size:1.75rem;line-height:2.25rem;margin-bottom:1rem;margin-top:.625rem}.UnitHeader-detail{align-items:center;display:flex;flex-wrap:wrap;white-space:nowrap}@media only screen and (min-width:52rem){.UnitHeader-detail{margin-bottom:.5rem}}.UnitHeader-detailItem{color:var(--gray-4);font-size:.875rem;margin-bottom:.5rem}.UnitHeader-detailItem img{margin-right:.5rem;vertical-align:middle}.UnitHeader-detailItem a>span{color:var(--gray-4)}.UnitHeader-detailItem:not(:first-of-type):before{content:"|";padding:1rem}@media only screen and (max-width:52rem){.UnitHeader-detailItem:not(:last-of-type):before{padding:.5rem}}.DetailsHeader-badge,.UnitHeader-versionBadge{border-radius:unset;color:#fff;font-size:.7rem;margin:-1rem 0 -1rem .5rem;padding:.25rem .5rem;text-transform:uppercase;top:-.0625rem}.DetailsHeader-badge--latest,.UnitHeader-versionBadge--latest{background:var(--turq-dark)}.DetailsHeader-badge--goToLatest,.UnitHeader-versionBadge--goToLatest{background:var(--pink)}.DetailsHeader-badge--unknown,.UnitHeader-versionBadge--unknown{display:none}.UnitHeader-flashBanner,.UnitHeader-majorVersionBanner{background-color:var(--gray-10);display:flex;margin:-.5rem 0 1rem;padding:.75rem 0}.DetailsHeader-banner--latest,.UnitHeader-majorVersionBanner--latest{display:none}.UnitHeader-detailIcon{color:var(--gray-3);flex-shrink:0;margin-left:1rem;margin-right:.7rem;width:1rem}a.UnitHeader-backLink{color:#000;display:block;font-size:1rem}.UnitHeader-backLink img{height:.8125rem;margin-right:.5rem;position:relative;top:-.0625rem;width:auto}.UnitHeader-badge{border:.0625rem solid var(--gray-4);border-radius:.125rem;font-size:.6875rem;font-weight:500;line-height:1rem;margin-left:.5rem;padding:0 .35rem;text-align:center}
/*# sourceMappingURL=unit_header.css.map */
\ No newline at end of file
diff --git a/content/static/css/unit_header.css.map b/content/static/css/unit_header.css.map
index 601879f..8d1c5cb 100644
--- a/content/static/css/unit_header.css.map
+++ b/content/static/css/unit_header.css.map
@@ -1 +1 @@
-{"version":3,"sources":["../../lib/css/unit_header.css"],"names":[],"mappings":"AAAA;;;;EAIE,CAEF,YACE,0CAA4C,CAC5C,kBACF,CACA,2CACE,YACE,0CAA4C,CAC5C,oBACF,CACF,CACA,sBACE,WAAY,CACZ,eACF,CACA,uBACE,gBACF,CACA,2BACE,mBAAoB,CACpB,mBAAoB,CACpB,iBAAmB,CACnB,kBACF,CACA,kDACE,WAAY,CACZ,eACF,CACA,oBACE,YAAa,CACb,kBACF,CACA,kBACE,iBAAkB,CAClB,mBAAoB,CACpB,kBAAmB,CACnB,kBACF,CACA,mBACE,kBAAmB,CACnB,YAAa,CACb,cAAe,CACf,kBACF,CACA,yCACE,mBACE,mBACF,CACF,CACA,uBACE,mBAAoB,CACpB,iBAAmB,CACnB,mBACF,CACA,2BACE,kBAAoB,CACpB,qBACF,CACA,8BACE,mBACF,CACA,kDACE,WAAY,CACZ,YACF,CACA,yCACE,iDACE,aACF,CACF,CAMA,8CAEE,mBAAoB,CACpB,UAAY,CACZ,eAAiB,CACjB,0BAA4B,CAC5B,oBAAuB,CACvB,wBAAyB,CACzB,aACF,CACA,8DAEE,2BACF,CACA,sEAEE,sBACF,CACA,gEAEE,YACF,CACA,+BACE,+BAAgC,CAChC,YAAa,CACb,oBAAwB,CACxB,gBACF,CAMA,qEAEE,YACF,CACA,uBACE,mBAAoB,CACpB,aAAc,CACd,gBAAiB,CACjB,kBAAoB,CACpB,UACF,CACA,sBACE,UAAY,CACZ,aAAc,CACd,cACF,CACA,yBACE,eAAiB,CACjB,kBAAoB,CACpB,iBAAkB,CAClB,aAAe,CACf,UACF,CACA,kBACE,mCAAqC,CACrC,qBAAuB,CACvB,kBAAoB,CACpB,eAAgB,CAChB,gBAAiB,CACjB,iBAAmB,CACnB,gBAAkB,CAClB,iBACF","file":"unit_header.css","sourcesContent":["/*!\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n.UnitHeader {\n border-bottom: 0.0625rem solid var(--gray-8);\n padding: 0.5rem 1rem;\n}\n@media only screen and (min-width: 57.7rem) {\n .UnitHeader {\n border-bottom: 0.0625rem solid var(--gray-8);\n padding: 0.5rem 1.5rem;\n }\n}\n.UnitHeader-container {\n margin: auto;\n max-width: 95rem;\n}\n.UnitHeader-breadcrumb {\n margin-top: 0.5rem;\n}\n.UnitHeader-breadcrumbItem {\n color: var(--gray-4);\n display: inline-flex;\n font-size: 0.875rem;\n line-height: 1.5rem;\n}\n.UnitHeader-breadcrumbItem:not(:last-child)::after {\n content: '>';\n padding: 0 0.5rem;\n}\n.UnitHeader-heading {\n display: flex;\n align-items: center;\n}\n.UnitHeader-title {\n font-size: 1.75rem;\n line-height: 2.25rem;\n margin-bottom: 1rem;\n margin-top: 0.625rem;\n}\n.UnitHeader-detail {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n white-space: nowrap;\n}\n@media only screen and (min-width: 52rem) {\n .UnitHeader-detail {\n margin-bottom: 0.5rem;\n }\n}\n.UnitHeader-detailItem {\n color: var(--gray-4);\n font-size: 0.875rem;\n margin-bottom: 0.5rem;\n}\n.UnitHeader-detailItem img {\n margin-right: 0.5rem;\n vertical-align: middle;\n}\n.UnitHeader-detailItem a > span {\n color: var(--gray-4);\n}\n.UnitHeader-detailItem:not(:first-of-type)::before {\n content: '|';\n padding: 1rem;\n}\n@media only screen and (max-width: 52rem) {\n .UnitHeader-detailItem:not(:last-of-type)::before {\n padding: 0.5rem;\n }\n}\n\n/*\n * TODO: Replace DetailsHeader-badge with UnitHeader-versionBadge in\n * middleware/latestversion.go after unit page is launched.\n */\n.UnitHeader-versionBadge,\n.DetailsHeader-badge {\n border-radius: unset;\n color: white;\n font-size: 0.7rem;\n margin: -1rem 0 -1rem 0.5rem;\n padding: 0.25rem 0.5rem;\n text-transform: uppercase;\n top: -0.0625rem;\n}\n.UnitHeader-versionBadge--latest,\n.DetailsHeader-badge--latest {\n background: var(--turq-dark);\n}\n.UnitHeader-versionBadge--goToLatest,\n.DetailsHeader-badge--goToLatest {\n background: var(--pink);\n}\n.UnitHeader-versionBadge--unknown,\n.DetailsHeader-badge--unknown {\n display: none;\n}\n.UnitHeader-majorVersionBanner {\n background-color: var(--gray-10);\n display: flex;\n margin: -0.5rem 0 1rem 0;\n padding: 0.75rem 0;\n}\n\n/*\n * TODO: Replace DetailsHeader-banner with UnitHeader-majorVersionBanner in\n * middleware/latestversion.go after unit page is launched.\n */\n.UnitHeader-majorVersionBanner--latest,\n.DetailsHeader-banner--latest {\n display: none;\n}\n.UnitHeader-detailIcon {\n color: var(--gray-3);\n flex-shrink: 0;\n margin-left: 1rem;\n margin-right: 0.7rem;\n width: 1rem;\n}\na.UnitHeader-backLink {\n color: black;\n display: block;\n font-size: 1rem;\n}\n.UnitHeader-backLink img {\n height: 0.8125rem;\n margin-right: 0.5rem;\n position: relative;\n top: -0.0625rem;\n width: auto;\n}\n.UnitHeader-badge {\n border: 0.0625rem solid var(--gray-4);\n border-radius: 0.125rem;\n font-size: 0.6875rem;\n font-weight: 500;\n line-height: 1rem;\n margin-left: 0.5rem;\n padding: 0 0.35rem;\n text-align: center;\n}\n"]}
\ No newline at end of file
+{"version":3,"sources":["../../lib/css/unit_header.css"],"names":[],"mappings":"AAAA;;;;EAIE,CAEF,YACE,0CAA4C,CAC5C,kBACF,CACA,2CACE,YACE,0CAA4C,CAC5C,oBACF,CACF,CACA,sBACE,WAAY,CACZ,eACF,CACA,uBACE,gBACF,CACA,2BACE,mBAAoB,CACpB,mBAAoB,CACpB,iBAAmB,CACnB,kBACF,CACA,kDACE,WAAY,CACZ,eACF,CACA,oBACE,YAAa,CACb,kBACF,CACA,kBACE,iBAAkB,CAClB,mBAAoB,CACpB,kBAAmB,CACnB,kBACF,CACA,mBACE,kBAAmB,CACnB,YAAa,CACb,cAAe,CACf,kBACF,CACA,yCACE,mBACE,mBACF,CACF,CACA,uBACE,mBAAoB,CACpB,iBAAmB,CACnB,mBACF,CACA,2BACE,kBAAoB,CACpB,qBACF,CACA,8BACE,mBACF,CACA,kDACE,WAAY,CACZ,YACF,CACA,yCACE,iDACE,aACF,CACF,CAMA,8CAEE,mBAAoB,CACpB,UAAY,CACZ,eAAiB,CACjB,0BAA4B,CAC5B,oBAAuB,CACvB,wBAAyB,CACzB,aACF,CACA,8DAEE,2BACF,CACA,sEAEE,sBACF,CACA,gEAEE,YACF,CAEA,uDAEE,+BAAgC,CAChC,YAAa,CACb,oBAAwB,CACxB,gBACF,CAMA,qEAEE,YACF,CACA,uBACE,mBAAoB,CACpB,aAAc,CACd,gBAAiB,CACjB,kBAAoB,CACpB,UACF,CACA,sBACE,UAAY,CACZ,aAAc,CACd,cACF,CACA,yBACE,eAAiB,CACjB,kBAAoB,CACpB,iBAAkB,CAClB,aAAe,CACf,UACF,CACA,kBACE,mCAAqC,CACrC,qBAAuB,CACvB,kBAAoB,CACpB,eAAgB,CAChB,gBAAiB,CACjB,iBAAmB,CACnB,gBAAkB,CAClB,iBACF","file":"unit_header.css","sourcesContent":["/*!\n * Copyright 2020 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\n.UnitHeader {\n border-bottom: 0.0625rem solid var(--gray-8);\n padding: 0.5rem 1rem;\n}\n@media only screen and (min-width: 57.7rem) {\n .UnitHeader {\n border-bottom: 0.0625rem solid var(--gray-8);\n padding: 0.5rem 1.5rem;\n }\n}\n.UnitHeader-container {\n margin: auto;\n max-width: 95rem;\n}\n.UnitHeader-breadcrumb {\n margin-top: 0.5rem;\n}\n.UnitHeader-breadcrumbItem {\n color: var(--gray-4);\n display: inline-flex;\n font-size: 0.875rem;\n line-height: 1.5rem;\n}\n.UnitHeader-breadcrumbItem:not(:last-child)::after {\n content: '>';\n padding: 0 0.5rem;\n}\n.UnitHeader-heading {\n display: flex;\n align-items: center;\n}\n.UnitHeader-title {\n font-size: 1.75rem;\n line-height: 2.25rem;\n margin-bottom: 1rem;\n margin-top: 0.625rem;\n}\n.UnitHeader-detail {\n align-items: center;\n display: flex;\n flex-wrap: wrap;\n white-space: nowrap;\n}\n@media only screen and (min-width: 52rem) {\n .UnitHeader-detail {\n margin-bottom: 0.5rem;\n }\n}\n.UnitHeader-detailItem {\n color: var(--gray-4);\n font-size: 0.875rem;\n margin-bottom: 0.5rem;\n}\n.UnitHeader-detailItem img {\n margin-right: 0.5rem;\n vertical-align: middle;\n}\n.UnitHeader-detailItem a > span {\n color: var(--gray-4);\n}\n.UnitHeader-detailItem:not(:first-of-type)::before {\n content: '|';\n padding: 1rem;\n}\n@media only screen and (max-width: 52rem) {\n .UnitHeader-detailItem:not(:last-of-type)::before {\n padding: 0.5rem;\n }\n}\n\n/*\n * TODO: Replace DetailsHeader-badge with UnitHeader-versionBadge in\n * middleware/latestversion.go after unit page is launched.\n */\n.UnitHeader-versionBadge,\n.DetailsHeader-badge {\n border-radius: unset;\n color: white;\n font-size: 0.7rem;\n margin: -1rem 0 -1rem 0.5rem;\n padding: 0.25rem 0.5rem;\n text-transform: uppercase;\n top: -0.0625rem;\n}\n.UnitHeader-versionBadge--latest,\n.DetailsHeader-badge--latest {\n background: var(--turq-dark);\n}\n.UnitHeader-versionBadge--goToLatest,\n.DetailsHeader-badge--goToLatest {\n background: var(--pink);\n}\n.UnitHeader-versionBadge--unknown,\n.DetailsHeader-badge--unknown {\n display: none;\n}\n\n.UnitHeader-flashBanner,\n.UnitHeader-majorVersionBanner {\n background-color: var(--gray-10);\n display: flex;\n margin: -0.5rem 0 1rem 0;\n padding: 0.75rem 0;\n}\n\n/*\n * TODO: Replace DetailsHeader-banner with UnitHeader-majorVersionBanner in\n * middleware/latestversion.go after unit page is launched.\n */\n.UnitHeader-majorVersionBanner--latest,\n.DetailsHeader-banner--latest {\n display: none;\n}\n.UnitHeader-detailIcon {\n color: var(--gray-3);\n flex-shrink: 0;\n margin-left: 1rem;\n margin-right: 0.7rem;\n width: 1rem;\n}\na.UnitHeader-backLink {\n color: black;\n display: block;\n font-size: 1rem;\n}\n.UnitHeader-backLink img {\n height: 0.8125rem;\n margin-right: 0.5rem;\n position: relative;\n top: -0.0625rem;\n width: auto;\n}\n.UnitHeader-badge {\n border: 0.0625rem solid var(--gray-4);\n border-radius: 0.125rem;\n font-size: 0.6875rem;\n font-weight: 500;\n line-height: 1rem;\n margin-left: 0.5rem;\n padding: 0 0.35rem;\n text-align: center;\n}\n"]}
\ No newline at end of file
diff --git a/content/static/html/helpers/_unit_header.tmpl b/content/static/html/helpers/_unit_header.tmpl
index 71f04a5..c868a22 100644
--- a/content/static/html/helpers/_unit_header.tmpl
+++ b/content/static/html/helpers/_unit_header.tmpl
@@ -36,13 +36,20 @@
<span class="UnitHeader-badge">{{.}}</span>
{{end}}
</div>
+ {{if .RedirectedFrom}}
+ <div class="UnitHeader-flashBanner">
+ <img height="19px" width="16px" class="UnitHeader-detailIcon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
+ <span>
+ Redirected from {{.RedirectedFrom}}.
+ </span>
+ </div>
+ {{end}}
<div class="UnitHeader-majorVersionBanner $$GODISCOVERY_LATESTMAJORCLASS$$" data-test-id="UnitHeader-majorVersionBanner">
<img height="19px" width="16px" class="UnitHeader-detailIcon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
<span>
The highest tagged major version is <a href="/$$GODISCOVERY_LATESTMAJORVERSIONURL$$">$$GODISCOVERY_LATESTMAJORVERSION$$</a>.
</span>
</div>
-
<div class="js-fixedHeaderSentinel"></div>
{{if (eq .SelectedTab.Name "")}}
<div class="UnitHeader-detail">
diff --git a/internal/frontend/404.go b/internal/frontend/404.go
index ed8ab80..5bdb964 100644
--- a/internal/frontend/404.go
+++ b/internal/frontend/404.go
@@ -64,7 +64,9 @@
return pathNotFoundError(fullPath, requestedVersion)
}
if fr.goModPath != fr.modulePath && fr.status == derrors.ToStatus(derrors.AlternativeModule) {
- http.Redirect(w, r, constructUnitURL(fr.goModPath, fr.goModPath, internal.LatestVersion), http.StatusFound)
+ u := constructUnitURL(fr.goModPath, fr.goModPath, internal.LatestVersion)
+ setFlashMessage(w, alternativeModuleFlash, fullPath, u)
+ http.Redirect(w, r, u, http.StatusFound)
return
}
return &serverError{
diff --git a/internal/frontend/flash.go b/internal/frontend/flash.go
new file mode 100644
index 0000000..a31c734
--- /dev/null
+++ b/internal/frontend/flash.go
@@ -0,0 +1,43 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package frontend
+
+import (
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "time"
+
+ "golang.org/x/pkgsite/internal/derrors"
+)
+
+// alternativeModuleFlash indicates the alternative module path that
+// a request was redirected from.
+const alternativeModuleFlash = "tmp-redirected-from-alternative-module"
+
+func getFlashMessage(w http.ResponseWriter, r *http.Request, name string) (_ string, err error) {
+ defer derrors.Wrap(&err, "getFlashMessage")
+ c, err := r.Cookie(name)
+ if err != nil && err != http.ErrNoCookie {
+ return "", fmt.Errorf("r.Cookie(%q): %v", name, err)
+ }
+ if c == nil {
+ return "", nil
+ }
+ val, err := base64.URLEncoding.DecodeString(c.Value)
+ if err != nil {
+ return "", nil
+ }
+ http.SetCookie(w, &http.Cookie{
+ Name: name,
+ Expires: time.Now().Add(-1 * time.Minute),
+ })
+ return string(val), nil
+}
+
+func setFlashMessage(w http.ResponseWriter, name, val, urlPath string) {
+ value := base64.URLEncoding.EncodeToString([]byte(val))
+ http.SetCookie(w, &http.Cookie{Name: name, Value: value, Path: urlPath})
+}
diff --git a/internal/frontend/flash_test.go b/internal/frontend/flash_test.go
new file mode 100644
index 0000000..9ab30bc
--- /dev/null
+++ b/internal/frontend/flash_test.go
@@ -0,0 +1,27 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package frontend
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+)
+
+func TestFlashMessages(t *testing.T) {
+ w := httptest.NewRecorder()
+
+ testVal := "value"
+ setFlashMessage(w, alternativeModuleFlash, testVal, "/")
+ r := &http.Request{Header: http.Header{"Cookie": w.Header()["Set-Cookie"]}}
+
+ got, err := getFlashMessage(w, r, alternativeModuleFlash)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got != testVal {
+ t.Errorf("got %q, want %q", got, testVal)
+ }
+}
diff --git a/internal/frontend/server_test.go b/internal/frontend/server_test.go
index 30c3b11..f226840 100644
--- a/internal/frontend/server_test.go
+++ b/internal/frontend/server_test.go
@@ -1162,12 +1162,12 @@
_, handler, _ := newTestServer(t, nil)
for _, test := range []struct {
- name, path string
- wantCode int
+ name, path, flash string
+ wantCode int
}{
- {"not found", "/invalid-page", http.StatusNotFound},
- {"bad request", "/gocloud.dev/@latest/blob", http.StatusBadRequest},
- {"alternative module", "/" + alternativeModule.ModulePath, http.StatusFound},
+ {"not found", "/invalid-page", "", http.StatusNotFound},
+ {"bad request", "/gocloud.dev/@latest/blob", "", http.StatusBadRequest},
+ {"alternative", "/" + alternativeModule.ModulePath, alternativeModule.ModulePath, http.StatusFound},
} {
t.Run(test.name, func(t *testing.T) {
w := httptest.NewRecorder()
@@ -1175,6 +1175,14 @@
if w.Code != test.wantCode {
t.Errorf("%q: got status code = %d, want %d", test.path, w.Code, test.wantCode)
}
+ r := &http.Request{Header: http.Header{"Cookie": w.Header()["Set-Cookie"]}}
+ got, err := getFlashMessage(w, r, alternativeModuleFlash)
+ if err != nil {
+ t.Fatalf("getFlashMessage(%q): %v", alternativeModuleFlash, err)
+ }
+ if got != test.flash {
+ t.Fatalf("got %q; want %q", got, test.flash)
+ }
})
}
}
diff --git a/internal/frontend/unit.go b/internal/frontend/unit.go
index e69fe38..0c6c3d4 100644
--- a/internal/frontend/unit.go
+++ b/internal/frontend/unit.go
@@ -67,6 +67,10 @@
// Settings contains settings for the selected tab.
SelectedTab TabSettings
+ // RedirectedFrom is the unit path that this request was redirected from.
+ // It is set as a flash cookie.
+ RedirectedFrom string
+
// Details contains data specific to the type of page being rendered.
Details interface{}
}
@@ -147,6 +151,13 @@
if ok {
page.MetaDescription = metaDescription(main.ImportedByCount)
}
+
+ msg, err := getFlashMessage(w, r, alternativeModuleFlash)
+ if err != nil {
+ log.Errorf(ctx, "serveUnitPage(ctx, w, r, ds, %v): %v", info, err)
+ } else if msg != "" {
+ page.RedirectedFrom = msg
+ }
s.servePage(ctx, w, tabSettings.TemplateName, page)
return nil
}