Upgrade Instagram shortcode
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Mon, 7 Jun 2021 10:45:00 +0000 (12:45 +0200)
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>
Tue, 8 Jun 2021 08:30:45 +0000 (10:30 +0200)
Fixes #7879

.github/workflows/test.yml
config/services/servicesConfig.go
hugolib/embedded_shortcodes_test.go
resources/page/page_generate/generate_page_wrappers.go
tpl/tplimpl/embedded/templates.autogen.go
tpl/tplimpl/embedded/templates/shortcodes/instagram.html
tpl/tplimpl/embedded/templates/shortcodes/instagram_simple.html

index caa123f3c226989fe357b18d553ca23286cc4055..9747e50695bae2436cb8e3eb6eece513fe8e8108 100644 (file)
@@ -75,6 +75,7 @@ jobs:
         HUGO_BUILD_TAGS: extended
         HUGO_TIMEOUT: 31000
         HUGO_IGNOREERRORS: error-remote-getjson
+        HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN: ${{ secrets.HUGO_SERVICES_INSTAGRAM_ACCESSTOKEN }}
       run: |
         mage -v hugo
         ./hugo -s docs/
index 559848f5c0284087cc27af177cb4d547f0dbe1fc..1b4317e92f578e952ec5baaf003ff2d5feb8e38d 100644 (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
        // to disable the inline CSS provided by Hugo.
        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.
index 90f2685af03179b1f8329c453aae77ae7153ee38..9fb25e22a74a735151c0793daa9dabfc457c224f 100644 (file)
@@ -372,12 +372,16 @@ func TestShortcodeInstagram(t *testing.T) {
        } {
                // overload getJSON to return mock API response from Instagram
                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{}
                                err := json.Unmarshal([]byte(this.resp), &v)
                                if err != nil {
-                                       t.Fatalf("[%d] unexpected error in json.Unmarshal: %s", i, err)
-                                       return err
+                                       return fmt.Errorf("[%d] unexpected error in json.Unmarshal: %s", i, err)
                                }
                                return v
                        },
@@ -388,6 +392,8 @@ func TestShortcodeInstagram(t *testing.T) {
                        th      = newTestHelper(cfg, fs, t)
                )
 
+               cfg.Set("services.instagram.accessToken", "dummytoken")
+
                writeSource(t, fs, filepath.Join("content", "simple.md"), fmt.Sprintf(`---
 title: Shorty
 ---
index e1d83115b3cd1ae443b20c5b47355489fd3e76b3..17346ec12c4aa392c69d443c2cec341963b351a3 100644 (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
 
@@ -245,10 +245,10 @@ package page
 
 // ZeroFile represents a zero value of source.File with warnings if invoked.
 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}
 }
 
index e4cd6992168f178698a8786fc30603cb545cc51c..c8732a91427b204346df1534fdfc312295e430d8 100644 (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/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 $pc.Simple -}}
-{{ template "_internal/shortcodes/instagram_simple.html" . }}
-{{- else -}}
-{{ $id := .Get 0 }}
-{{ $hideCaption := cond (eq (.Get 1) "hidecaption") "1" "0" }}
-{{ with getJSON "https://api.instagram.com/oembed/?url=https://instagram.com/p/" $id "/&hidecaption=" $hideCaption  }}{{ .html | safeHTML }}{{ end }}
-{{- end -}}
+  {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
+  {{- if not $accessToken -}}
+    {{- 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." -}}
+  {{- else -}}
+    {{- if $pc.Simple -}}
+      {{ template "_internal/shortcodes/instagram_simple.html" . }}
+    {{- 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 -}}`},
        {`shortcodes/instagram_simple.html`, `{{- $pc := .Page.Site.Config.Privacy.Instagram -}}
 {{- $sc := .Page.Site.Config.Services.Instagram -}}
 {{- if not $pc.Disable -}}
-{{- $id := .Get 0 -}}
-{{- $item := getJSON "https://api.instagram.com/oembed/?url=https://www.instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" -}}
-{{- $class1 := "__h_instagram" -}}
-{{- $class2 := "s_instagram_simple" -}}
-{{- $hideCaption := (eq (.Get 1) "hidecaption") -}}
-{{ with $item }}
-{{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}}
-{{- if not $sc.DisableInlineCSS -}}
-{{ template "__h_simple_instagram_css" $ }}
-{{- end -}}
-<div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px">
-       <div class="card-header">
-    <a href="{{ $item.author_url | safeURL }}" class="card-link">{{ $item.author_name }}</a>
-  </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 }}
+  {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
+  {{- if not $accessToken -}}
+    {{- 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." -}}
+  {{- else -}}
+    {{- $id := .Get 0 -}}
+    {{- $headers := dict "Authorization" (printf "Bearer %s" $accessToken) -}}
+    {{- $item := getJSON "https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" $headers -}}
+    {{- $class1 := "__h_instagram" -}}
+    {{- $class2 := "s_instagram_simple" -}}
+    {{- $hideCaption := (eq (.Get 1) "hidecaption") -}}
+    {{ with $item }}
+      {{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}}
+      {{- if not $sc.DisableInlineCSS -}}
+        {{ template "__h_simple_instagram_css" $ }}
+      {{- end -}}
+      <div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px">
+        <div class="card-header">
+          <a href="{{ $item.author_url | safeURL }}" class="card-link">
+            {{ $item.author_name }}
+          </a>
+        </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 -}}
 
 {{ define "__h_simple_instagram_css" }}
-{{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }}
-{{/* Only include once */}}
-{{  .Page.Scratch.Set "__h_simple_instagram_css" true }}
-<style type="text/css">
-   .__h_instagram.card {
+  {{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }}
+    {{/* Only include once */}}
+    {{  .Page.Scratch.Set "__h_simple_instagram_css" true }}
+    <style type="text/css">
+      .__h_instagram.card {
       font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
       font-size: 14px;
       border: 1px solid rgb(219, 219, 219);
       padding: 0;
-         margin-top: 30px;
-   }
-   .__h_instagram.card .card-header, .__h_instagram.card .card-body {
+      margin-top: 30px;
+      }
+      .__h_instagram.card .card-header, .__h_instagram.card .card-body {
       padding: 10px 10px 10px;
-   }
-   .__h_instagram.card img {
+      }
+      .__h_instagram.card img {
       width: 100%;
-       height: auto;
-   }
-</style>
-{{ end }}
+       height: auto;
+      }
+    </style>
+  {{ end }}
 {{ end }}`},
        {`shortcodes/param.html`, `{{- $name := (.Get 0) -}}
 {{- with $name -}}
index 67ff2e72c64bc54e30046554da2ffe9215513ed0..46343361f63fbe5950a28698ae1802a7a99cc887 100644 (file)
@@ -1,10 +1,18 @@
-{{- $pc := .Page.Site.Config.Privacy.Instagram -}}
+{{- $pc := site.Config.Privacy.Instagram -}}
 {{- if not $pc.Disable -}}
-{{- if $pc.Simple -}}
-{{ template "_internal/shortcodes/instagram_simple.html" . }}
-{{- else -}}
-{{ $id := .Get 0 }}
-{{ $hideCaption := cond (eq (.Get 1) "hidecaption") "1" "0" }}
-{{ with getJSON "https://api.instagram.com/oembed/?url=https://instagram.com/p/" $id "/&hidecaption=" $hideCaption  }}{{ .html | safeHTML }}{{ end }}
-{{- end -}}
+  {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
+  {{- if not $accessToken -}}
+    {{- 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." -}}
+  {{- else -}}
+    {{- if $pc.Simple -}}
+      {{ template "_internal/shortcodes/instagram_simple.html" . }}
+    {{- 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 -}}
\ No newline at end of file
index d816093a67b4352b03c0dea9edda212c4e7bbbf8..365d1025eb0dcdb9577909a7b98b316ad0b9e756 100644 (file)
@@ -1,48 +1,67 @@
 {{- $pc := .Page.Site.Config.Privacy.Instagram -}}
 {{- $sc := .Page.Site.Config.Services.Instagram -}}
 {{- if not $pc.Disable -}}
-{{- $id := .Get 0 -}}
-{{- $item := getJSON "https://api.instagram.com/oembed/?url=https://www.instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" -}}
-{{- $class1 := "__h_instagram" -}}
-{{- $class2 := "s_instagram_simple" -}}
-{{- $hideCaption := (eq (.Get 1) "hidecaption") -}}
-{{ with $item }}
-{{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}}
-{{- if not $sc.DisableInlineCSS -}}
-{{ template "__h_simple_instagram_css" $ }}
-{{- end -}}
-<div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px">
-       <div class="card-header">
-    <a href="{{ $item.author_url | safeURL }}" class="card-link">{{ $item.author_name }}</a>
-  </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 }}
+  {{ $accessToken := site.Config.Services.Instagram.AccessToken }}
+  {{- if not $accessToken -}}
+    {{- 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." -}}
+  {{- else -}}
+    {{- $id := .Get 0 -}}
+    {{- $headers := dict "Authorization" (printf "Bearer %s" $accessToken) -}}
+    {{- $item := getJSON "https://graph.facebook.com/v8.0/instagram_oembed/?url=https://instagram.com/p/" $id "/&amp;maxwidth=640&amp;omitscript=true" $headers -}}
+    {{- $class1 := "__h_instagram" -}}
+    {{- $class2 := "s_instagram_simple" -}}
+    {{- $hideCaption := (eq (.Get 1) "hidecaption") -}}
+    {{ with $item }}
+      {{- $mediaURL := printf "https://instagram.com/p/%s/" $id | safeURL -}}
+      {{- if not $sc.DisableInlineCSS -}}
+        {{ template "__h_simple_instagram_css" $ }}
+      {{- end -}}
+      <div class="{{ $class1 }} {{ $class2 }} card" style="max-width: {{ $item.thumbnail_width }}px">
+        <div class="card-header">
+          <a href="{{ $item.author_url | safeURL }}" class="card-link">
+            {{ $item.author_name }}
+          </a>
+        </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 -}}
 
 {{ define "__h_simple_instagram_css" }}
-{{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }}
-{{/* Only include once */}}
-{{  .Page.Scratch.Set "__h_simple_instagram_css" true }}
-<style type="text/css">
-   .__h_instagram.card {
+  {{ if not (.Page.Scratch.Get "__h_simple_instagram_css") }}
+    {{/* Only include once */}}
+    {{  .Page.Scratch.Set "__h_simple_instagram_css" true }}
+    <style type="text/css">
+      .__h_instagram.card {
       font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;
       font-size: 14px;
       border: 1px solid rgb(219, 219, 219);
       padding: 0;
-         margin-top: 30px;
-   }
-   .__h_instagram.card .card-header, .__h_instagram.card .card-body {
+      margin-top: 30px;
+      }
+      .__h_instagram.card .card-header, .__h_instagram.card .card-body {
       padding: 10px 10px 10px;
-   }
-   .__h_instagram.card img {
+      }
+      .__h_instagram.card img {
       width: 100%;
-       height: auto;
-   }
-</style>
-{{ end }}
+       height: auto;
+      }
+    </style>
+  {{ end }}
 {{ end }}
\ No newline at end of file