aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamal Carvalho <jamal@golang.org>2020-07-07 13:01:02 -0400
committerJamal Carvalho <jamal@golang.org>2020-07-14 18:56:54 +0000
commitd37103e11f2b448cd4e692dfb482ec7680ffc392 (patch)
tree59f064437d61e83c08f18f49c7b8808a5a6c528b
parent103a6b7425c1282f4a6627299cafdefb1b8a7fc4 (diff)
downloadgo-x-pkgsite-d37103e11f2b448cd4e692dfb482ec7680ffc392.tar.xz
content,internal: add badge generation for package authors
This change creates a badge generation tool page for package authors. A future change will add documenation of this feature and a link to the about page. Fixes golang/go#36982 Change-Id: Ia64ba9db73ed92b853f1f955330caf93d996da91 Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/241273 Reviewed-by: Andrew Bonventre <andybons@golang.org>
-rw-r--r--content/static/css/stylesheet.css60
-rw-r--r--content/static/html/pages/badge.tmpl57
-rw-r--r--content/static/img/badge.svg1
-rw-r--r--content/static/img/copy-click.svg1
-rw-r--r--content/static/js/badge.js30
-rw-r--r--content/static/js/badge.min.js8
-rwxr-xr-xdevtools/compile_js.sh1
-rw-r--r--internal/frontend/badge.go43
-rw-r--r--internal/frontend/badge_test.go85
-rw-r--r--internal/frontend/server.go6
-rw-r--r--internal/middleware/secureheaders.go4
11 files changed, 292 insertions, 4 deletions
diff --git a/content/static/css/stylesheet.css b/content/static/css/stylesheet.css
index 460721be..7bafc404 100644
--- a/content/static/css/stylesheet.css
+++ b/content/static/css/stylesheet.css
@@ -1,5 +1,5 @@
/*
- * Copyright 2019 The Go Authors. All rights reserved.
+ * Copyright 2019-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.
*/
@@ -1095,6 +1095,64 @@ table.Directories {
margin-left: 1.1rem;
}
+.Badge-formElement {
+ display: block;
+ font-size: 1rem;
+ margin-top: 1rem;
+}
+.Badge-badgeIcon {
+ height: 20px;
+ width: 90px;
+}
+.Badge-previewLink,
+.Badge-formElement > input {
+ display: block;
+ margin-top: 1rem;
+ max-width: 50.25rem;
+}
+.Badge-formElement > input {
+ border: 0.0625rem solid var(--gray-8);
+ border-radius: 0.25rem;
+ color: var(--gray-4);
+ font-family: inherit;
+ height: 3rem;
+ padding: 0 2rem 0 0.75rem;
+ text-overflow: ellipsis;
+ width: 100%;
+}
+.Badge-formElement > input:focus::placeholder {
+ color: transparent;
+}
+.Badge-clickToCopy {
+ background: var(--gray-10) url('/static/img/copy-click.svg') right no-repeat;
+ background-position: right 0.75rem center;
+}
+.Badge-submitButton {
+ border: none;
+ border-radius: 0.25rem;
+ background-color: var(--turq-dark);
+ color: var(--white);
+ cursor: pointer;
+ font-family: inherit;
+ height: 2.75rem;
+ width: 7.125rem;
+}
+.Badge-snippetContainer {
+ background-color: var(--gray-10);
+ display: block;
+ margin-top: 1rem;
+ max-width: 50.25rem;
+ padding: 1rem;
+}
+.Badge-gopherLanding {
+ height: 12.25rem;
+ text-align: center;
+}
+.Badge-gopherLanding img {
+ height: 125px;
+ width: auto;
+}
+
/* dialogs, including the jump-to-identifier dialog on documentation pages */
.Dialog {
diff --git a/content/static/html/pages/badge.tmpl b/content/static/html/pages/badge.tmpl
new file mode 100644
index 00000000..60dd3faf
--- /dev/null
+++ b/content/static/html/pages/badge.tmpl
@@ -0,0 +1,57 @@
+<!--
+ 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.
+-->
+
+{{define "main_content"}}
+ <div class="Container">
+ <div class="Content">
+ <h1 class="Content-header">Create a badge</h1>
+ <p>Create a badge to link to pkg.go.dev from your project website or README file.</p>
+ <label class="Badge-formElement">
+ Badge
+ <div class="Badge-previewLink">
+ <a class="js-badgeExampleButton" href="{{.SiteURL}}/{{.Path}}">
+ <img class="Badge-badgeIcon" src="/static/img/badge.svg" alt="PkgGoDev">
+ </a>
+ </div>
+ </label>
+ <form action="/badge/">
+ <label class="Badge-formElement">
+ URL
+ <input name="path" class="js-toolsPathInput"
+ value="{{if .Path}}{{.SiteURL}}/{{.Path}}{{end}}" placeholder="e.g., https://pkg.go.dev/golang.org/x/pkgsite">
+ </label>
+ <label class="Badge-formElement">
+ <button type="submit" class="Badge-submitButton">Create</button>
+ </label>
+ </form>
+ <div class="Badge-snippetContainer">
+ {{if .Path}}
+ <label class="Badge-formElement">
+ HTML
+ <input title="Click to copy HTML" name="html" class="Badge-clickToCopy js-toolsCopySnippet" type="text"
+ value='<a href="{{.SiteURL}}/{{.Path}}"><img src="{{.SiteURL}}/badge/{{.Path}}" alt="PkgGoDev"></a>' readonly>
+ </label>
+ <label class="Badge-formElement">
+ Markdown
+ <input title="Click to copy markdown" name="markdown" class="Badge-clickToCopy js-toolsCopySnippet" type="text"
+ value="[![PkgGoDev]({{.SiteURL}}/{{.Path}})]({{.SiteURL}}/badge/{{.Path}})" readonly>
+ </label>
+ {{else}}
+ <div class="Badge-gopherLanding">
+ <img src="/static/img/gopher-airplane.svg" alt="The Go Gopher"/>
+ <p>Type a pkg.go.dev URL above to create a badge link.</p>
+ </div>
+ {{end}}
+ </div>
+ </div>
+ </div>
+{{end}}
+
+{{define "post_content"}}
+<script>
+ loadScript("/static/js/badge.min.js");
+</script>
+{{end}} \ No newline at end of file
diff --git a/content/static/img/badge.svg b/content/static/img/badge.svg
new file mode 100644
index 00000000..99e2d730
--- /dev/null
+++ b/content/static/img/badge.svg
@@ -0,0 +1 @@
+<svg width="90" height="20" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M2 0h26v20H2a2 2 0 01-2-2V2a2 2 0 012-2z" fill="#5C5C5C"/><path d="M87.99 0H28v20h59.99a2 2 0 002-2V2a2 2 0 00-2-2z" fill="#007D9C"/><path d="M35.177 14v-2.915c0-.374.072-.682.215-.924.142-.242.324-.423.544-.544.22-.122.444-.182.671-.182.169 0 .303.01.401.027.1.019.19.043.27.072l.165-1.034a.977.977 0 00-.275-.082 2.004 2.004 0 00-.33-.028c-.425 0-.783.093-1.072.28-.29.188-.508.46-.655.82l-.11-.99H34V14h1.177zm5.66.11c.542 0 1.019-.114 1.43-.341.41-.227.714-.543.912-.946l-.935-.44c-.14.257-.322.453-.55.589-.227.135-.52.203-.88.203-.33 0-.616-.073-.858-.22a1.439 1.439 0 01-.56-.649 2.169 2.169 0 01-.177-.655l-.004-.049h4.03c.01-.059.018-.124.025-.196l.008-.112c.008-.117.011-.242.011-.374 0-.484-.1-.918-.302-1.303a2.19 2.19 0 00-.87-.903c-.377-.216-.826-.324-1.347-.324-.528 0-.995.115-1.402.346a2.442 2.442 0 00-.957.99c-.231.43-.347.937-.347 1.524s.116 1.095.347 1.524c.23.429.555.759.973.99.418.23.902.346 1.452.346zm1.302-3.41h-2.895l.02-.115c.016-.068.033-.134.053-.197l.067-.183c.125-.293.303-.513.534-.66.23-.147.508-.22.83-.22.47 0 .829.156 1.078.468.156.194.255.437.296.728l.017.179zM46.32 14V9.424h1.75V8.5h-1.783v-.704c0-.27.064-.476.19-.617l.069-.065c.172-.14.409-.209.71-.209.131 0 .249.013.351.038a.927.927 0 01.275.116l.22-.847a1.06 1.06 0 00-.423-.192 2.516 2.516 0 00-.622-.072c-.293 0-.559.038-.797.115a1.68 1.68 0 00-.61.341c-.17.15-.296.336-.38.556-.085.22-.127.47-.127.748V8.5h-1.034v.924h1.034V14h1.177zm5.1.11c.543 0 1.02-.114 1.43-.341.411-.227.715-.543.913-.946l-.935-.44c-.139.257-.322.453-.55.589-.227.135-.52.203-.88.203-.33 0-.616-.073-.858-.22a1.439 1.439 0 01-.56-.649 2.169 2.169 0 01-.177-.655l-.004-.049h4.03c.01-.059.018-.124.025-.196l.008-.112c.008-.117.011-.242.011-.374 0-.484-.1-.918-.302-1.303a2.19 2.19 0 00-.869-.903c-.378-.216-.827-.324-1.348-.324-.528 0-.995.115-1.402.346a2.442 2.442 0 00-.957.99c-.231.43-.347.937-.347 1.524s.116 1.095.347 1.524c.231.429.555.759.973.99.418.23.902.346 1.452.346zm1.303-3.41h-2.895l.02-.115c.016-.068.033-.134.053-.197l.067-.183c.125-.293.303-.513.534-.66.231-.147.508-.22.83-.22.47 0 .83.156 1.078.468.156.194.255.437.296.728l.017.179zM56.53 14v-2.915c0-.374.072-.682.215-.924.143-.242.324-.423.544-.544.22-.122.444-.182.671-.182.17 0 .303.01.402.027.099.019.189.043.27.072l.164-1.034a.977.977 0 00-.275-.082 2.004 2.004 0 00-.33-.028c-.425 0-.782.093-1.072.28-.29.188-.508.46-.655.82l-.11-.99h-1V14h1.176zm5.66.11c.542 0 1.019-.114 1.43-.341.41-.227.715-.543.913-.946l-.935-.44c-.14.257-.323.453-.55.589-.228.135-.521.203-.88.203-.33 0-.616-.073-.858-.22a1.439 1.439 0 01-.561-.649 2.169 2.169 0 01-.176-.655l-.005-.049h4.03c.01-.059.019-.124.025-.196l.009-.112c.007-.117.01-.242.01-.374 0-.484-.1-.918-.302-1.303a2.19 2.19 0 00-.869-.903c-.377-.216-.827-.324-1.347-.324-.528 0-.996.115-1.403.346a2.442 2.442 0 00-.957.99c-.23.43-.346.937-.346 1.524s.115 1.095.346 1.524c.231.429.556.759.974.99.418.23.902.346 1.452.346zm1.303-3.41h-2.896l.021-.115c.015-.068.032-.134.052-.197l.068-.183c.124-.293.302-.513.533-.66.231-.147.508-.22.83-.22.47 0 .83.156 1.079.468.156.194.254.437.295.728l.018.179zM67.3 14v-2.926c0-.418.075-.752.225-1.001.15-.25.34-.43.567-.545.227-.113.462-.17.704-.17.337 0 .617.104.841.313.224.21.336.585.336 1.128V14h1.177v-3.564c0-.462-.092-.843-.275-1.144a1.74 1.74 0 00-.743-.676 2.387 2.387 0 00-1.05-.226c-.301 0-.585.048-.853.143a1.722 1.722 0 00-.693.457c-.116.125-.217.27-.3.433l-.017.037-.051-.96h-1.045V14H67.3zm8.043.11c.418 0 .788-.068 1.11-.204a2.19 2.19 0 00.81-.572c.215-.245.375-.533.478-.863l-1.067-.363c-.044.227-.127.42-.248.577a1.197 1.197 0 01-.456.364 1.54 1.54 0 01-.65.126c-.322 0-.6-.073-.835-.22a1.397 1.397 0 01-.54-.649c-.124-.286-.186-.634-.186-1.045 0-.418.06-.77.181-1.056.121-.286.299-.504.534-.655.234-.15.517-.225.847-.225.337 0 .61.09.82.27.208.18.36.438.456.775l1.11-.44c-.11-.3-.27-.568-.483-.803a2.148 2.148 0 00-.787-.545c-.312-.128-.687-.192-1.127-.192-.528 0-1 .114-1.414.341a2.386 2.386 0 00-.968.985c-.23.429-.346.94-.346 1.534 0 .594.115 1.105.346 1.534.231.43.556.758.974.985.418.227.898.341 1.44.341zm6.192 0c.543 0 1.02-.114 1.43-.341.411-.227.715-.543.913-.946l-.935-.44c-.139.257-.322.453-.55.589-.227.135-.52.203-.88.203-.33 0-.616-.073-.858-.22a1.439 1.439 0 01-.56-.649 2.169 2.169 0 01-.177-.655l-.004-.049h4.03c.01-.059.018-.124.025-.196l.008-.112c.008-.117.011-.242.011-.374 0-.484-.1-.918-.302-1.303a2.19 2.19 0 00-.87-.903c-.377-.216-.826-.324-1.347-.324-.528 0-.995.115-1.402.346a2.442 2.442 0 00-.957.99c-.231.43-.347.937-.347 1.524s.116 1.095.347 1.524c.23.429.555.759.973.99.418.23.902.346 1.452.346zm1.303-3.41h-2.895l.02-.115c.016-.068.033-.134.053-.197l.067-.183c.125-.293.303-.513.534-.66.23-.147.508-.22.83-.22.47 0 .83.156 1.078.468.156.194.255.437.296.728l.017.179zM6.358 8.736c-.035 0-.043-.017-.026-.044l.184-.236c.018-.026.061-.044.096-.044h3.13c.034 0 .043.026.026.053l-.15.227c-.017.027-.061.053-.087.053l-3.173-.009zm-1.323.806c-.035 0-.044-.017-.026-.043l.184-.237c.017-.026.061-.043.096-.043h3.996c.036 0 .053.026.044.052l-.07.21c-.009.035-.043.053-.079.053l-4.145.009zm2.121.807c-.035 0-.044-.026-.026-.053l.122-.219c.018-.026.053-.052.088-.052h1.753c.035 0 .052.026.052.061l-.017.21c0 .036-.035.062-.062.062l-1.91-.01zm9.097-1.77c-.552.14-.93.245-1.472.385-.132.035-.14.044-.255-.087-.13-.15-.227-.246-.411-.333-.553-.272-1.088-.193-1.587.13-.596.386-.902.956-.893 1.666.008.701.49 1.28 1.182 1.376.597.079 1.095-.131 1.49-.578.08-.097.149-.202.237-.325h-1.691c-.184 0-.228-.114-.167-.263.114-.271.324-.727.447-.955a.236.236 0 01.219-.14h3.19c-.017.237-.017.473-.053.71a3.737 3.737 0 01-.718 1.718c-.631.832-1.455 1.35-2.498 1.489-.858.114-1.656-.052-2.357-.577a2.753 2.753 0 01-1.113-1.947c-.114-.955.167-1.814.745-2.568.622-.814 1.446-1.332 2.454-1.515.823-.15 1.612-.053 2.322.429.465.307.797.727 1.017 1.236.052.078.017.123-.088.149m2.901 4.846c-.798-.018-1.525-.246-2.139-.771a2.749 2.749 0 01-.946-1.692c-.158-.99.114-1.866.71-2.646.64-.842 1.41-1.28 2.454-1.464.894-.157 1.735-.07 2.497.447.693.473 1.122 1.113 1.236 1.954.149 1.183-.192 2.147-1.008 2.971a4.014 4.014 0 01-2.103 1.122c-.237.044-.473.052-.701.08zm2.085-3.54c-.008-.114-.008-.202-.025-.29-.158-.868-.956-1.358-1.788-1.165-.816.183-1.341.7-1.534 1.524a1.444 1.444 0 00.806 1.657c.482.21.964.184 1.429-.052.692-.36 1.069-.92 1.113-1.674h-.001z" fill="#FAFAFA" fill-rule="nonzero"/></g></svg> \ No newline at end of file
diff --git a/content/static/img/copy-click.svg b/content/static/img/copy-click.svg
new file mode 100644
index 00000000..10afe910
--- /dev/null
+++ b/content/static/img/copy-click.svg
@@ -0,0 +1 @@
+<svg fill="#00add8" width="13" height="15" xmlns="http://www.w3.org/2000/svg"><path d="M8 0H2a2 2 0 00-2 2v8a2 2 0 002 2V2h8a2 2 0 00-2-2zm3 3H5a2 2 0 00-2 2v8a2 2 0 002 2h6a2 2 0 002-2V5a2 2 0 00-2-2zM5 13h6V5H5v8z" fill-rule="evenodd"/></svg> \ No newline at end of file
diff --git a/content/static/js/badge.js b/content/static/js/badge.js
new file mode 100644
index 00000000..65d71940
--- /dev/null
+++ b/content/static/js/badge.js
@@ -0,0 +1,30 @@
+/**
+ * @license
+ * Copyright 2019-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.
+ */
+
+const snippetEls = document.querySelectorAll('.js-toolsCopySnippet');
+snippetEls.forEach(inputEl => {
+ inputEl.addEventListener('click', e => {
+ e.preventDefault();
+ e.currentTarget.select();
+ document.execCommand('copy');
+ });
+});
+
+const pathEl = document.querySelector('.js-toolsPathInput');
+const htmlEl = document.querySelector('input[name="html"].js-toolsCopySnippet');
+const markdownEl = document.querySelector('input[name="markdown"].js-toolsCopySnippet');
+const badgeEl = document.querySelector('.js-badgeExampleButton');
+if (pathEl && htmlEl && markdownEl && badgeEl) {
+ pathEl.addEventListener('input', e => {
+ const origin = window.location.origin;
+ const href = `${origin}/${e.target.value}`;
+ const imgSrc = `${origin}/badge/${e.target.value}`;
+ htmlEl.value = `<a href="${href}"><img src="${imgSrc}" alt="PkgGoDev"></a>`;
+ markdownEl.value = `[![PkgGoDev](${href})](${imgSrc})`;
+ badgeEl.href = href;
+ });
+}
diff --git a/content/static/js/badge.min.js b/content/static/js/badge.min.js
new file mode 100644
index 00000000..2e8145c2
--- /dev/null
+++ b/content/static/js/badge.min.js
@@ -0,0 +1,8 @@
+/*
+
+ Copyright 2019-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.
+*/
+var snippetEls=document.querySelectorAll(".js-toolsCopySnippet");snippetEls.forEach(function(a){a.addEventListener("click",function(a){a.preventDefault();a.currentTarget.select();document.execCommand("copy")})});var pathEl=document.querySelector(".js-toolsPathInput"),htmlEl=document.querySelector('input[name="html"].js-toolsCopySnippet'),markdownEl=document.querySelector('input[name="markdown"].js-toolsCopySnippet'),badgeEl=document.querySelector(".js-badgeExampleButton");
+pathEl&&htmlEl&&markdownEl&&badgeEl&&pathEl.addEventListener("input",function(a){var c=window.location.origin,b=c+"/"+a.target.value;a=c+"/badge/"+a.target.value;htmlEl.value='<a href="'+b+'"><img src="'+a+'" alt="PkgGoDev"></a>';markdownEl.value="[![PkgGoDev]("+b+")]("+a+")";badgeEl.href=b});
diff --git a/devtools/compile_js.sh b/devtools/compile_js.sh
index e53cb4bc..577f29d4 100755
--- a/devtools/compile_js.sh
+++ b/devtools/compile_js.sh
@@ -43,6 +43,7 @@ main() {
# TODO: once this is not an experiment, add it to the line above.
$cmd $JSDIR/completion.min.js $JSDIR/completion.js
$cmd $JSDIR/fetch.min.js $JSDIR/fetch.js
+ $cmd $JSDIR/badge.min.js $JSDIR/badge.js
$cmd $JSDIR/jump.min.js third_party/dialog-polyfill/dialog-polyfill.js $JSDIR/jump.js
}
diff --git a/internal/frontend/badge.go b/internal/frontend/badge.go
new file mode 100644
index 00000000..6d068a70
--- /dev/null
+++ b/internal/frontend/badge.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 (
+ "fmt"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+type badgePage struct {
+ basePage
+ SiteURL string
+ Path string
+}
+
+// badgeHandler serves a Go SVG badge image for requests to /badge/<path>
+// and a badge generation tool page for requests to /badge/[?path=<path>].
+func (s *Server) badgeHandler(w http.ResponseWriter, r *http.Request) {
+ path := strings.TrimPrefix(r.URL.Path, "/badge/")
+ if path != "" {
+ http.ServeFile(w, r, fmt.Sprintf("%s/img/badge.svg", s.staticPath))
+ return
+ }
+
+ // The user may input a fully qualified URL (https://pkg.go.dev/net/http?tab=doc)
+ // or just a pathname (net/http). Using url.Parse we handle both cases.
+ inputURL := r.URL.Query().Get("path")
+ parsedURL, _ := url.Parse(inputURL)
+ if parsedURL != nil {
+ path = strings.TrimPrefix(parsedURL.RequestURI(), "/")
+ }
+
+ page := badgePage{
+ basePage: s.newBasePage(r, "Badge generation tool"),
+ SiteURL: "https://" + r.Host,
+ Path: path,
+ }
+ s.servePage(r.Context(), w, "badge.tmpl", page)
+}
diff --git a/internal/frontend/badge_test.go b/internal/frontend/badge_test.go
new file mode 100644
index 00000000..809b449b
--- /dev/null
+++ b/internal/frontend/badge_test.go
@@ -0,0 +1,85 @@
+// 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/httptest"
+ "strings"
+ "testing"
+)
+
+func TestBadgeHandler_ServeSVG(t *testing.T) {
+ _, handler, _ := newTestServer(t, nil)
+ w := httptest.NewRecorder()
+ handler.ServeHTTP(w, httptest.NewRequest("GET", "/badge/net/http", nil))
+ if got, want := w.Result().Header.Get("Content-Type"), "image/svg+xml"; got != want {
+ t.Errorf("Content-Type = %q, want %q", got, want)
+ }
+}
+
+func TestBadgeHandler_ServeBadgeTool(t *testing.T) {
+ _, handler, _ := newTestServer(t, nil)
+
+ tests := []struct {
+ url string
+ want string
+ }{
+ {
+ "/badge/",
+ "<p>Type a pkg.go.dev URL above to create a badge link.</p>",
+ },
+ {
+ "/badge/?path=net/http",
+ `<a href="https://example.com/net/http"><img src="https://example.com/badge/net/http" alt="PkgGoDev"></a>`,
+ },
+ {
+ "/badge/?path=net/http?tab=imports",
+ `<a href="https://example.com/net/http?tab=imports"><img src="https://example.com/badge/net/http?tab=imports" alt="PkgGoDev"></a>`,
+ },
+ {
+ "/badge/?path=https://pkg.go.dev/net/http",
+ `<a href="https://example.com/net/http"><img src="https://example.com/badge/net/http" alt="PkgGoDev"></a>`,
+ },
+ {
+ "/badge/?path=https://pkg.go.dev/net/http?tab=imports",
+ `<a href="https://example.com/net/http?tab=imports"><img src="https://example.com/badge/net/http?tab=imports" alt="PkgGoDev"></a>`,
+ },
+ {
+ "/badge/?path=github.com/google/uuid",
+ "[![PkgGoDev](https://example.com/github.com/google/uuid)](https://example.com/badge/github.com/google/uuid)",
+ },
+ {
+ "/badge/?path=github.com/google/uuid?tab=imports",
+ "[![PkgGoDev](https://example.com/github.com/google/uuid?tab=imports)](https://example.com/badge/github.com/google/uuid?tab=imports)",
+ },
+ {
+ "/badge/?path=https://pkg.go.dev/github.com/google/uuid",
+ "[![PkgGoDev](https://example.com/github.com/google/uuid)](https://example.com/badge/github.com/google/uuid)",
+ },
+ {
+ "/badge/?path=https://pkg.go.dev/github.com/google/uuid?tab=imports",
+ "[![PkgGoDev](https://example.com/github.com/google/uuid?tab=imports)](https://example.com/badge/github.com/google/uuid?tab=imports)",
+ },
+ {
+ "/badge/?path=https://google.com",
+ "<p>Type a pkg.go.dev URL above to create a badge link.</p>",
+ },
+ {
+ "/badge/?path=https://google.com/github.com/google/uuid",
+ "[![PkgGoDev](https://example.com/github.com/google/uuid)](https://example.com/badge/github.com/google/uuid)",
+ },
+ }
+
+ for _, test := range tests {
+ t.Run(test.url, func(t *testing.T) {
+ w := httptest.NewRecorder()
+ handler.ServeHTTP(w, httptest.NewRequest("GET", test.url, nil))
+ got := w.Body.String()
+ if !strings.Contains(w.Body.String(), test.want) {
+ t.Errorf("Expected html substring not found, want %s, got %s", test.want, got)
+ }
+ })
+ }
+}
diff --git a/internal/frontend/server.go b/internal/frontend/server.go
index be2ed564..af50a3e0 100644
--- a/internal/frontend/server.go
+++ b/internal/frontend/server.go
@@ -111,6 +111,7 @@ func (s *Server) Install(handle func(string, http.Handler), redisClient *redis.C
handle("/search-help", s.staticPageHandler("search_help.tmpl", "Search Help - go.dev"))
handle("/license-policy", s.licensePolicyHandler())
handle("/about", http.RedirectHandler("https://go.dev/about", http.StatusFound))
+ handle("/badge/", http.HandlerFunc(s.badgeHandler))
handle("/", detailHandler)
handle("/autocomplete", http.HandlerFunc(s.handleAutoCompletion))
handle("/robots.txt", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -415,12 +416,13 @@ func parsePageTemplates(base template.TrustedSource) (map[string]*template.Templ
join := template.TrustedSourceJoin
htmlSets := [][]template.TrustedSource{
- {tsc("index.tmpl")},
+ {tsc("badge.tmpl")},
{tsc("error.tmpl")},
{tsc("fetch.tmpl")},
+ {tsc("index.tmpl")},
+ {tsc("license_policy.tmpl")},
{tsc("search.tmpl")},
{tsc("search_help.tmpl")},
- {tsc("license_policy.tmpl")},
{tsc("overview.tmpl"), tsc("details.tmpl")},
{tsc("subdirectories.tmpl"), tsc("details.tmpl")},
{tsc("pkg_doc.tmpl"), tsc("details.tmpl")},
diff --git a/internal/middleware/secureheaders.go b/internal/middleware/secureheaders.go
index 66c6a7d5..8d99d673 100644
--- a/internal/middleware/secureheaders.go
+++ b/internal/middleware/secureheaders.go
@@ -1,4 +1,4 @@
-// Copyright 2019 The Go Authors. All rights reserved.
+// Copyright 2019-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.
@@ -15,6 +15,8 @@ var scriptHashes = []string{
"'sha256-Ajmr6RIM6VV5w/AraBIyO4/XRyuqJlFVukc7TL6feog='",
"'sha256-d6W7MwuGWbguTHRzQhf5QN1jXmNo9Ao218saZkWLWZI='",
"'sha256-qPGTOKPn+niRiNKQIEX0Ktwuj+D+iPQWIxnlhPicw58='",
+ // From content/static/html/pages/badge.tmpl
+ "'sha256-T7xOt6cgLji3rhOWyKK7t5XKv8+LASQwOnHiHHy8Kwk='",
// From content/static/html/pages/details.tmpl
"'sha256-s16e7aT7Gsajq5UH1DbaEFEnNx2VjvS5Xixcxwm4+F8='",
// From content/static/html/pages/fetch.tmpl