Upgrade Instagram shortcode

Fixes #7879
This commit is contained in:
Bjørn Erik Pedersen 2021-06-07 12:45:00 +02:00
parent 12530519d8
commit 9b5debe4b8
7 changed files with 158 additions and 92 deletions

View file

@ -75,6 +75,7 @@ jobs:
HUGO_BUILD_TAGS: extended HUGO_BUILD_TAGS: extended
HUGO_TIMEOUT: 31000 HUGO_TIMEOUT: 31000
HUGO_IGNOREERRORS: error-remote-getjson HUGO_IGNOREERRORS: error-remote-getjson
HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN: ${{ secrets.HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN }}
run: | run: |
mage -v hugo mage -v hugo
./hugo -s docs/ ./hugo -s docs/

View file

@ -53,6 +53,11 @@ type Instagram struct {
// This means that if you use Bootstrap 4 or want to provide your own CSS, you want // This means that if you use Bootstrap 4 or want to provide your own CSS, you want
// to disable the inline CSS provided by Hugo. // to disable the inline CSS provided by Hugo.
DisableInlineCSS bool DisableInlineCSS bool
// App or Client Access Token.
// If you are using a Client Access Token, remember that you must combine it with your App ID
// using a pipe symbol (<APPID>|<CLIENTTOKEN>) otherwise the request will fail.
AccessToken string
} }
// Twitter holds the functional configuration settings related to the Twitter shortcodes. // Twitter holds the functional configuration settings related to the Twitter shortcodes.

View file

@ -372,12 +372,16 @@ func TestShortcodeInstagram(t *testing.T) {
} { } {
// overload getJSON to return mock API response from Instagram // overload getJSON to return mock API response from Instagram
instagramFuncMap := template.FuncMap{ instagramFuncMap := template.FuncMap{
"getJSON": func(urlParts ...string) interface{} { "getJSON": func(args ...interface{}) interface{} {
headers := args[len(args)-1].(map[string]interface{})
auth := headers["Authorization"]
if auth != "Bearer dummytoken" {
return fmt.Errorf("invalid access token: %q", auth)
}
var v interface{} var v interface{}
err := json.Unmarshal([]byte(this.resp), &v) err := json.Unmarshal([]byte(this.resp), &v)
if err != nil { if err != nil {
t.Fatalf("[%d] unexpected error in json.Unmarshal: %s", i, err) return fmt.Errorf("[%d] unexpected error in json.Unmarshal: %s", i, err)
return err
} }
return v return v
}, },
@ -388,6 +392,8 @@ func TestShortcodeInstagram(t *testing.T) {
th = newTestHelper(cfg, fs, t) th = newTestHelper(cfg, fs, t)
) )
cfg.Set("services.instagram.accessToken", "dummytoken")
writeSource(t, fs, filepath.Join("content", "simple.md"), fmt.Sprintf(`--- writeSource(t, fs, filepath.Join("content", "simple.md"), fmt.Sprintf(`---
title: Shorty title: Shorty
--- ---

View file

@ -235,7 +235,7 @@ func generateFileIsZeroWrappers(c *codegen.Inspector) error {
} }
pkgImports := append(methods.Imports(), "github.com/gohugoio/hugo/helpers", "github.com/gohugoio/hugo/source") pkgImports := append(methods.Imports(), "github.com/gohugoio/hugo/common/loggers", "github.com/gohugoio/hugo/source")
fmt.Fprintf(f, `%s fmt.Fprintf(f, `%s
@ -245,10 +245,10 @@ package page
// ZeroFile represents a zero value of source.File with warnings if invoked. // ZeroFile represents a zero value of source.File with warnings if invoked.
type zeroFile struct { type zeroFile struct {
log *helpers.DistinctLogger log loggers.Logger
} }
func NewZeroFile(log *helpers.DistinctLogger) source.File { func NewZeroFile(log loggers.Logger) source.File {
return zeroFile{log: log} return zeroFile{log: log}
} }

View file

@ -387,63 +387,90 @@ if (!doNotTrack) {
{`shortcodes/gist.html`, `<script type="application/javascript" src="https://gist.github.com/{{ index .Params 0 }}/{{ index .Params 1 }}.js{{if len .Params | eq 3 }}?file={{ index .Params 2 }}{{end}}"></script> {`shortcodes/gist.html`, `<script type="application/javascript" src="https://gist.github.com/{{ index .Params 0 }}/{{ index .Params 1 }}.js{{if len .Params | eq 3 }}?file={{ index .Params 2 }}{{end}}"></script>
`}, `},
{`shortcodes/highlight.html`, `{{ if len .Params | eq 2 }}{{ highlight (trim .Inner "\n\r") (.Get 0) (.Get 1) }}{{ else }}{{ highlight (trim .Inner "\n\r") (.Get 0) "" }}{{ end }}`}, {`shortcodes/highlight.html`, `{{ if len .Params | eq 2 }}{{ highlight (trim .Inner "\n\r") (.Get 0) (.Get 1) }}{{ else }}{{ highlight (trim .Inner "\n\r") (.Get 0) "" }}{{ end }}`},
{`shortcodes/instagram.html`, `{{- $pc := .Page.Site.Config.Privacy.Instagram -}} {`shortcodes/instagram.html`, `{{- $pc := site.Config.Privacy.Instagram -}}
{{- if not $pc.Disable -}} {{- if not $pc.Disable -}}
{{- if $pc.Simple -}} {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
{{ template "_internal/shortcodes/instagram_simple.html" . }} {{- if not $accessToken -}}
{{- else -}} {{- erroridf "err-missing-instagram-accesstoken" "instagram shortcode: Missing config value for services.instagram.accessToken. This can be set in config.toml, but it is recommended to configure this via the HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN OS environment variable. If you are using a Client Access Token, remember that you must combine it with your App ID using a pipe symbol (<APPID>|<CLIENTTOKEN>) otherwise the request will fail." -}}
{{ $id := .Get 0 }} {{- else -}}
{{ $hideCaption := cond (eq (.Get 1) "hidecaption") "1" "0" }} {{- if $pc.Simple -}}
{{ with getJSON "https://api.instagram.com/oembed/?url=https://instagram.com/p/" $id "/&hidecaption=" $hideCaption }}{{ .html | safeHTML }}{{ end }} {{ template "_internal/shortcodes/instagram_simple.html" . }}
{{- end -}} {{- else -}}
{{ $id := .Get 0 }}
{{ $hideCaption := cond (eq (.Get 1) "hidecaption") "1" "0" }}
{{ $headers := dict "Authorization" (printf "Bearer %s" $accessToken) }}
{{ with getJSON "https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/" $id "/&hidecaption=" $hideCaption $headers }}
{{ .html | safeHTML }}
{{ end }}
{{- end -}}
{{- end -}}
{{- end -}}`}, {{- end -}}`},
{`shortcodes/instagram_simple.html`, `{{- $pc := .Page.Site.Config.Privacy.Instagram -}} {`shortcodes/instagram_simple.html`, `{{- $pc := .Page.Site.Config.Privacy.Instagram -}}
{{- $sc := .Page.Site.Config.Services.Instagram -}} {{- $sc := .Page.Site.Config.Services.Instagram -}}
{{- if not $pc.Disable -}} {{- if not $pc.Disable -}}
{{- $id := .Get 0 -}} {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
{{- $item := getJSON "https://api.instagram.com/oembed/?url=https://www.instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" -}} {{- if not $accessToken -}}
{{- $class1 := "__h_instagram" -}} {{- erroridf "err-missing-instagram-accesstoken" "instagram shortcode: Missing config value for services.instagram.accessToken. This can be set in config.toml, but it is recommended to configure this via the HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN OS environment variable. If you are using a Client Access Token, remember that you must combine it with your App ID using a pipe symbol (<APPID>|<CLIENTTOKEN>) otherwise the request will fail." -}}
{{- $class2 := "s_instagram_simple" -}} {{- else -}}
{{- $hideCaption := (eq (.Get 1) "hidecaption") -}} {{- $id := .Get 0 -}}
{{ with $item }} {{- $headers := dict "Authorization" (printf "Bearer %s" $accessToken) -}}
{{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}} {{- $item := getJSON "https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" $headers -}}
{{- if not $sc.DisableInlineCSS -}} {{- $class1 := "__h_instagram" -}}
{{ template "__h_simple_instagram_css" $ }} {{- $class2 := "s_instagram_simple" -}}
{{- end -}} {{- $hideCaption := (eq (.Get 1) "hidecaption") -}}
<div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px"> {{ with $item }}
<div class="card-header"> {{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}}
<a href="{{ $item.author_url | safeURL }}" class="card-link">{{ $item.author_name }}</a> {{- if not $sc.DisableInlineCSS -}}
</div> {{ template "__h_simple_instagram_css" $ }}
<a href="{{ $mediaURL }}" rel="noopener" target="_blank"><img class="card-img-top img-fluid" src="{{ $item.thumbnail_url }}" width="{{ $item.thumbnail_width }}" height="{{ $item.thumbnail_height }}" alt="Instagram Image"></a> {{- end -}}
<div class="card-body"> <div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px">
{{ if not $hideCaption }}<p class="card-text"><a href="{{ $item.author_url | safeURL }}" class="card-link">{{ $item.author_name }}</a> {{ $item.title}}</p>{{ end }} <div class="card-header">
<a href="{{ $item.author_url | safeURL }}" class="card-link">View More on Instagram</a> <a href="{{ $item.author_url | safeURL }}" class="card-link">
</div> {{ $item.author_name }}
</div> </a>
{{ end }} </div>
<a href="{{ $mediaURL }}" rel="noopener" target="_blank">
<img class="card-img-top img-fluid" src="{{ $item.thumbnail_url }}" width="{{ $item.thumbnail_width }}" height="{{ $item.thumbnail_height }}" alt="Instagram Image">
</a>
<div class="card-body">
{{ if not $hideCaption }}
<p class="card-text">
<a href="{{ $item.author_url | safeURL }}" class="card-link">
{{ $item.author_name }}
</a>
{{ $item.title}}
</p>
{{ end }}
<a href="{{ $item.author_url | safeURL }}" class="card-link">
View More on Instagram
</a>
</div>
</div>
{{ end }}
{{- end -}}
{{- end -}} {{- end -}}
{{ define "__h_simple_instagram_css" }} {{ define "__h_simple_instagram_css" }}
{{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }} {{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }}
{{/* Only include once */}} {{/* Only include once */}}
{{ .Page.Scratch.Set "__h_simple_instagram_css" true }} {{ .Page.Scratch.Set "__h_simple_instagram_css" true }}
<style type="text/css"> <style type="text/css">
.__h_instagram.card { .__h_instagram.card {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
font-size: 14px; font-size: 14px;
border: 1px solid rgb(219, 219, 219); border: 1px solid rgb(219, 219, 219);
padding: 0; padding: 0;
margin-top: 30px; margin-top: 30px;
} }
.__h_instagram.card .card-header, .__h_instagram.card .card-body { .__h_instagram.card .card-header, .__h_instagram.card .card-body {
padding: 10px 10px 10px; padding: 10px 10px 10px;
} }
.__h_instagram.card img { .__h_instagram.card img {
width: 100%; width: 100%;
height: auto; height: auto;
} }
</style> </style>
{{ end }} {{ end }}
{{ end }}`}, {{ end }}`},
{`shortcodes/param.html`, `{{- $name := (.Get 0) -}} {`shortcodes/param.html`, `{{- $name := (.Get 0) -}}
{{- with $name -}} {{- with $name -}}

View file

@ -1,10 +1,18 @@
{{- $pc := .Page.Site.Config.Privacy.Instagram -}} {{- $pc := site.Config.Privacy.Instagram -}}
{{- if not $pc.Disable -}} {{- if not $pc.Disable -}}
{{- if $pc.Simple -}} {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
{{ template "_internal/shortcodes/instagram_simple.html" . }} {{- if not $accessToken -}}
{{- else -}} {{- erroridf "err-missing-instagram-accesstoken" "instagram shortcode: Missing config value for services.instagram.accessToken. This can be set in config.toml, but it is recommended to configure this via the HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN OS environment variable. If you are using a Client Access Token, remember that you must combine it with your App ID using a pipe symbol (<APPID>|<CLIENTTOKEN>) otherwise the request will fail." -}}
{{ $id := .Get 0 }} {{- else -}}
{{ $hideCaption := cond (eq (.Get 1) "hidecaption") "1" "0" }} {{- if $pc.Simple -}}
{{ with getJSON "https://api.instagram.com/oembed/?url=https://instagram.com/p/" $id "/&hidecaption=" $hideCaption }}{{ .html | safeHTML }}{{ end }} {{ template "_internal/shortcodes/instagram_simple.html" . }}
{{- end -}} {{- else -}}
{{ $id := .Get 0 }}
{{ $hideCaption := cond (eq (.Get 1) "hidecaption") "1" "0" }}
{{ $headers := dict "Authorization" (printf "Bearer %s" $accessToken) }}
{{ with getJSON "https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/" $id "/&hidecaption=" $hideCaption $headers }}
{{ .html | safeHTML }}
{{ end }}
{{- end -}}
{{- end -}}
{{- end -}} {{- end -}}

View file

@ -1,48 +1,67 @@
{{- $pc := .Page.Site.Config.Privacy.Instagram -}} {{- $pc := .Page.Site.Config.Privacy.Instagram -}}
{{- $sc := .Page.Site.Config.Services.Instagram -}} {{- $sc := .Page.Site.Config.Services.Instagram -}}
{{- if not $pc.Disable -}} {{- if not $pc.Disable -}}
{{- $id := .Get 0 -}} {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
{{- $item := getJSON "https://api.instagram.com/oembed/?url=https://www.instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" -}} {{- if not $accessToken -}}
{{- $class1 := "__h_instagram" -}} {{- erroridf "err-missing-instagram-accesstoken" "instagram shortcode: Missing config value for services.instagram.accessToken. This can be set in config.toml, but it is recommended to configure this via the HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN OS environment variable. If you are using a Client Access Token, remember that you must combine it with your App ID using a pipe symbol (<APPID>|<CLIENTTOKEN>) otherwise the request will fail." -}}
{{- $class2 := "s_instagram_simple" -}} {{- else -}}
{{- $hideCaption := (eq (.Get 1) "hidecaption") -}} {{- $id := .Get 0 -}}
{{ with $item }} {{- $headers := dict "Authorization" (printf "Bearer %s" $accessToken) -}}
{{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}} {{- $item := getJSON "https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" $headers -}}
{{- if not $sc.DisableInlineCSS -}} {{- $class1 := "__h_instagram" -}}
{{ template "__h_simple_instagram_css" $ }} {{- $class2 := "s_instagram_simple" -}}
{{- end -}} {{- $hideCaption := (eq (.Get 1) "hidecaption") -}}
<div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px"> {{ with $item }}
<div class="card-header"> {{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}}
<a href="{{ $item.author_url | safeURL }}" class="card-link">{{ $item.author_name }}</a> {{- if not $sc.DisableInlineCSS -}}
</div> {{ template "__h_simple_instagram_css" $ }}
<a href="{{ $mediaURL }}" rel="noopener" target="_blank"><img class="card-img-top img-fluid" src="{{ $item.thumbnail_url }}" width="{{ $item.thumbnail_width }}" height="{{ $item.thumbnail_height }}" alt="Instagram Image"></a> {{- end -}}
<div class="card-body"> <div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px">
{{ if not $hideCaption }}<p class="card-text"><a href="{{ $item.author_url | safeURL }}" class="card-link">{{ $item.author_name }}</a> {{ $item.title}}</p>{{ end }} <div class="card-header">
<a href="{{ $item.author_url | safeURL }}" class="card-link">View More on Instagram</a> <a href="{{ $item.author_url | safeURL }}" class="card-link">
</div> {{ $item.author_name }}
</div> </a>
{{ end }} </div>
<a href="{{ $mediaURL }}" rel="noopener" target="_blank">
<img class="card-img-top img-fluid" src="{{ $item.thumbnail_url }}" width="{{ $item.thumbnail_width }}" height="{{ $item.thumbnail_height }}" alt="Instagram Image">
</a>
<div class="card-body">
{{ if not $hideCaption }}
<p class="card-text">
<a href="{{ $item.author_url | safeURL }}" class="card-link">
{{ $item.author_name }}
</a>
{{ $item.title}}
</p>
{{ end }}
<a href="{{ $item.author_url | safeURL }}" class="card-link">
View More on Instagram
</a>
</div>
</div>
{{ end }}
{{- end -}}
{{- end -}} {{- end -}}
{{ define "__h_simple_instagram_css" }} {{ define "__h_simple_instagram_css" }}
{{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }} {{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }}
{{/* Only include once */}} {{/* Only include once */}}
{{ .Page.Scratch.Set "__h_simple_instagram_css" true }} {{ .Page.Scratch.Set "__h_simple_instagram_css" true }}
<style type="text/css"> <style type="text/css">
.__h_instagram.card { .__h_instagram.card {
font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
font-size: 14px; font-size: 14px;
border: 1px solid rgb(219, 219, 219); border: 1px solid rgb(219, 219, 219);
padding: 0; padding: 0;
margin-top: 30px; margin-top: 30px;
} }
.__h_instagram.card .card-header, .__h_instagram.card .card-body { .__h_instagram.card .card-header, .__h_instagram.card .card-body {
padding: 10px 10px 10px; padding: 10px 10px 10px;
} }
.__h_instagram.card img { .__h_instagram.card img {
width: 100%; width: 100%;
height: auto; height: auto;
} }
</style> </style>
{{ end }} {{ end }}
{{ end }} {{ end }}