From 7b9910f251e139012b48eae6f63e86cd7c1cdc62 Mon Sep 17 00:00:00 2001 From: Thomas Citharel <tcit@tcit.fr> Date: Wed, 24 Mar 2021 10:45:29 +0100 Subject: [PATCH] Resources fixes and improvements - Fix getting page description - Fix fetching metadata from Twitter (thx @marienfressinaud) - Improve error handling Signed-off-by: Thomas Citharel <tcit@tcit.fr> --- js/src/views/Resources/ResourceFolder.vue | 35 +++++++++++++------ lib/graphql/resolvers/resource.ex | 9 ++++- lib/service/rich_media/parser.ex | 18 ++++++++-- .../rich_media/parsers/meta_tags_parser.ex | 10 ++++-- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/js/src/views/Resources/ResourceFolder.vue b/js/src/views/Resources/ResourceFolder.vue index 83873920d..645b03ffb 100644 --- a/js/src/views/Resources/ResourceFolder.vue +++ b/js/src/views/Resources/ResourceFolder.vue @@ -190,6 +190,9 @@ <b-modal :active.sync="createLinkResourceModal" has-modal-card> <div class="modal-card"> <section class="modal-card-body"> + <b-message type="is-danger" v-if="modalError"> + {{ modalError }} + </b-message> <form @submit.prevent="createResource"> <b-field :label="$t('URL')"> <b-input @@ -317,6 +320,8 @@ export default class Resources extends Mixins(ResourceMixin) { renameModal = false; + modalError = ""; + groupObject: Record<string, unknown> = { name: "resources", pull: "clone", @@ -341,6 +346,7 @@ export default class Resources extends Mixins(ResourceMixin) { async createResource(): Promise<void> { if (!this.resource.actor) return; + this.modalError = ""; try { await this.$apollo.mutate({ mutation: CREATE_RESOURCE, @@ -364,21 +370,28 @@ export default class Resources extends Mixins(ResourceMixin) { this.newResource.resourceUrl = ""; } catch (err) { console.error(err); + this.modalError = err.graphQLErrors[0].message; } } async previewResource(): Promise<void> { - if (this.newResource.resourceUrl === "") return; - const { data } = await this.$apollo.mutate({ - mutation: PREVIEW_RESOURCE_LINK, - variables: { - resourceUrl: this.newResource.resourceUrl, - }, - }); - this.newResource.title = data.previewResourceLink.title; - this.newResource.summary = data.previewResourceLink.description; - this.newResource.metadata = data.previewResourceLink; - this.newResource.type = "link"; + this.modalError = ""; + try { + if (this.newResource.resourceUrl === "") return; + const { data } = await this.$apollo.mutate({ + mutation: PREVIEW_RESOURCE_LINK, + variables: { + resourceUrl: this.newResource.resourceUrl, + }, + }); + this.newResource.title = data.previewResourceLink.title; + this.newResource.summary = data.previewResourceLink.description; + this.newResource.metadata = data.previewResourceLink; + this.newResource.type = "link"; + } catch (err) { + console.error(err); + this.modalError = err.graphQLErrors[0].message; + } } createSentenceForType(type: string): string { diff --git a/lib/graphql/resolvers/resource.ex b/lib/graphql/resolvers/resource.ex index 16e5040b7..13b43ba84 100644 --- a/lib/graphql/resolvers/resource.ex +++ b/lib/graphql/resolvers/resource.ex @@ -118,6 +118,9 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do ) do {:ok, resource} else + {:error, _} -> + {:error, dgettext("errors", "Error while creating resource")} + {:own_check, _} -> {:error, dgettext("errors", "Parent resource doesn't belong to this group")} @@ -201,8 +204,12 @@ defmodule Mobilizon.GraphQL.Resolvers.Resource do {:ok, data} when is_map(data) -> {:ok, struct(Metadata, data)} - {:error, _err} -> + {:error, :invalid_parsed_data} -> + {:error, dgettext("errors", "Unable to fetch resource details from this URL.")} + + {:error, err} -> Logger.warn("Error while fetching preview from #{inspect(resource_url)}") + Logger.debug(inspect(err)) {:error, :unknown_resource} end end diff --git a/lib/service/rich_media/parser.ex b/lib/service/rich_media/parser.ex index 738d19620..2ea91f995 100644 --- a/lib/service/rich_media/parser.ex +++ b/lib/service/rich_media/parser.ex @@ -57,7 +57,7 @@ defmodule Mobilizon.Service.RichMedia.Parser do @spec parse_url(String.t(), Enum.t()) :: {:ok, map()} | {:error, any()} defp parse_url(url, options \\ []) do - user_agent = Keyword.get(options, :user_agent, Config.instance_user_agent()) + user_agent = Keyword.get(options, :user_agent, default_user_agent(url)) headers = [{"User-Agent", user_agent}] Logger.debug("Fetching content at address #{inspect(url)}") @@ -212,7 +212,8 @@ defmodule Mobilizon.Service.RichMedia.Parser do end defp check_parsed_data(data) do - {:error, "Found metadata was invalid or incomplete: #{inspect(data)}"} + Logger.debug("Found metadata was invalid or incomplete: #{inspect(data)}") + {:error, :invalid_parsed_data} end defp clean_parsed_data(data) do @@ -293,4 +294,17 @@ defmodule Mobilizon.Service.RichMedia.Parser do end defp check_remote_picture_path(data), do: data + + # Twitter requires a well-know crawler user-agent to show server-rendered data + defp default_user_agent("https://twitter.com/" <> _) do + "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + end + + defp default_user_agent("https://mobile.twitter.com/" <> _) do + "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" + end + + defp default_user_agent(_url) do + Config.instance_user_agent() + end end diff --git a/lib/service/rich_media/parsers/meta_tags_parser.ex b/lib/service/rich_media/parsers/meta_tags_parser.ex index bd383db71..316e444c5 100644 --- a/lib/service/rich_media/parsers/meta_tags_parser.ex +++ b/lib/service/rich_media/parsers/meta_tags_parser.ex @@ -70,8 +70,14 @@ defmodule Mobilizon.Service.RichMedia.Parsers.MetaTagsParser do defp maybe_put_description(meta, html) when meta != %{} do case get_page_description(html) do - "" -> meta - description -> Map.put_new(meta, :description, description) + "" -> + meta + + descriptions when is_list(descriptions) and length(descriptions) > 0 -> + Map.put_new(meta, :description, hd(descriptions)) + + description -> + Map.put_new(meta, :description, description) end end