From 39c03301c94bf5cf340d15be89ef790a4cdfbec2 Mon Sep 17 00:00:00 2001 From: Thomas Citharel <tcit@tcit.fr> Date: Thu, 25 Jun 2020 18:47:17 +0200 Subject: [PATCH 1/3] Allow to properly move group resources Signed-off-by: Thomas Citharel <tcit@tcit.fr> --- js/src/components/Resource/FolderItem.vue | 4 +- js/src/components/Resource/ResourceItem.vue | 2 +- .../components/Resource/ResourceSelector.vue | 129 ++++++++++++++++++ js/src/graphql/resources.ts | 13 ++ js/src/i18n/en_US.json | 9 +- js/src/i18n/fr_FR.json | 9 +- js/src/views/Resources/ResourceFolder.vue | 119 ++++++++++++++-- lib/graphql/schema.ex | 14 +- lib/graphql/schema/resource.ex | 5 +- lib/service/rich_media/parsers/ogp.ex | 13 +- 10 files changed, 298 insertions(+), 19 deletions(-) create mode 100644 js/src/components/Resource/ResourceSelector.vue diff --git a/js/src/components/Resource/FolderItem.vue b/js/src/components/Resource/FolderItem.vue index ecda49c88..e254c9224 100644 --- a/js/src/components/Resource/FolderItem.vue +++ b/js/src/components/Resource/FolderItem.vue @@ -29,7 +29,7 @@ class="actions" v-if="!inline" @delete="$emit('delete', resource.id)" - @move="$emit('move', resource.id)" + @move="$emit('move', resource)" @rename="$emit('rename', resource)" /> </div> @@ -70,8 +70,6 @@ export default class FolderItem extends Mixins(ResourceMixin) { usernameWithDomain = usernameWithDomain; async onChange(evt: ChangeEvent<IResource>): Promise<Route | undefined> { - console.log("into folder item"); - console.log(evt); if (evt.added && evt.added.element) { const movedResource = evt.added.element as IResource; const updatedResource = await this.moveResource(movedResource); diff --git a/js/src/components/Resource/ResourceItem.vue b/js/src/components/Resource/ResourceItem.vue index 4751e2a3b..c5865ed0d 100644 --- a/js/src/components/Resource/ResourceItem.vue +++ b/js/src/components/Resource/ResourceItem.vue @@ -29,7 +29,7 @@ class="actions" v-if="!inline" @delete="$emit('delete', resource.id)" - @move="$emit('move', resource.id)" + @move="$emit('move', resource)" @rename="$emit('rename', resource)" /> </div> diff --git a/js/src/components/Resource/ResourceSelector.vue b/js/src/components/Resource/ResourceSelector.vue new file mode 100644 index 000000000..a16bb3be1 --- /dev/null +++ b/js/src/components/Resource/ResourceSelector.vue @@ -0,0 +1,129 @@ +<template> + <div v-if="resource"> + <article class="panel is-primary"> + <p class="panel-heading"> + {{ $t('Move "{resourceName}"', { resourceName: initialResource.title }) }} + </p> + <a class="panel-block clickable" @click="resource = resource.parent" v-if="resource.parent"> + <span class="panel-icon"> + <b-icon icon="chevron-up" size="is-small" /> + </span> + {{ $t("Parent folder") }} + </a> + <a + class="panel-block clickable" + @click="resource = { path: '/', username }" + v-else-if="resource.path.length > 1" + > + <span class="panel-icon"> + <b-icon icon="chevron-up" size="is-small" /> + </span> + {{ $t("Parent folder") }} + </a> + <a + class="panel-block" + v-for="element in resource.children.elements" + :class="{ clickable: element.type === 'folder' && element.id !== initialResource.id }" + :key="element.id" + @click="goDown(element)" + > + <span class="panel-icon"> + <b-icon icon="folder" size="is-small" v-if="element.type === 'folder'" /> + <b-icon icon="link" size="is-small" v-else /> + </span> + {{ element.title }} + <span v-if="element.id === initialResource.id"> + <em v-if="element.type === 'folder'"> {{ $t("(this folder)") }}</em> + <em v-else> {{ $t("(this link)") }}</em> + </span> + </a> + <p + class="panel-block content has-text-grey has-text-centered" + v-if="resource.children.total === 0" + > + {{ $t("No resources in this folder") }} + </p> + </article> + <b-button type="is-primary" @click="updateResource" :disabled="moveDisabled">{{ + $t("Move resource to {folder}", { folder: resource.title }) + }}</b-button> + <b-button type="is-text" @click="$emit('closeMoveModal')">{{ $t("Cancel") }}</b-button> + </div> +</template> +<script lang="ts"> +import { Component, Vue, Prop } from "vue-property-decorator"; +import { GET_RESOURCE } from "../../graphql/resources"; +import { IResource } from "../../types/resource"; + +@Component({ + apollo: { + resource: { + query: GET_RESOURCE, + variables() { + if (this.resource && this.resource.path) { + return { + path: this.resource.path, + username: this.username, + }; + } + return { path: "/", username: this.username }; + }, + skip() { + return !this.username; + }, + }, + }, +}) +export default class ResourceSelector extends Vue { + @Prop({ required: true }) initialResource!: IResource; + @Prop({ required: true }) username!: string; + + resource: IResource | undefined = this.initialResource.parent; + + goDown(element: IResource) { + if (element.type === "folder" && element.id !== this.initialResource.id) { + this.resource = element; + } + } + + updateResource() { + this.$emit( + "updateResource", + { + id: this.initialResource.id, + title: this.initialResource.title, + parent: this.resource && this.resource.path === "/" ? null : this.resource, + path: this.initialResource.path, + }, + this.initialResource.parent + ); + } + + get moveDisabled() { + return ( + (this.initialResource.parent && + this.resource && + this.initialResource.parent.path === this.resource.path) || + (this.initialResource.parent == undefined && this.resource && this.resource.path === "/") + ); + } +} +</script> +<style lang="scss" scoped> +@import "../../variables.scss"; + +.panel { + a.panel-block { + cursor: default; + + &.clickable { + cursor: pointer; + } + } + + &.is-primary .panel-heading { + background: $primary; + color: #fff; + } +} +</style> diff --git a/js/src/graphql/resources.ts b/js/src/graphql/resources.ts index 65ea76422..5b1e90525 100644 --- a/js/src/graphql/resources.ts +++ b/js/src/graphql/resources.ts @@ -18,6 +18,7 @@ export const GET_RESOURCE = gql` summary url path + type metadata { ...ResourceMetadataBasicFields authorName @@ -28,6 +29,8 @@ export const GET_RESOURCE = gql` } parent { id + path + type } actor { id @@ -44,6 +47,11 @@ export const GET_RESOURCE = gql` type path resourceUrl + parent { + id + path + type + } metadata { ...ResourceMetadataBasicFields } @@ -112,7 +120,12 @@ export const UPDATE_RESOURCE = gql` summary url path + type resourceUrl + parent { + id + path + } } } `; diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index 951400e12..75cbc481a 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -696,5 +696,12 @@ "Can be an email or a link, or just plain text.": "Can be an email or a link, or just plain text.", "No profiles found": "No profiles found", "URL copied to clipboard": "URL copied to clipboard", - "Report #{reportNumber}": "Report #{reportNumber}" + "Report #{reportNumber}": "Report #{reportNumber}", + "Move \"{resourceName}\"": "Move \"{resourceName}\"", + "Parent folder": "Parent folder", + "(this folder)": "(this folder)", + "(this link)": "(this link)", + "Move resource to {folder}": "Move resource to {folder}", + "Create a folder": "Create a folder", + "No resources in this folder": "No resources in this folder" } diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index fc20e2fc5..450552732 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -696,5 +696,12 @@ "contact uninformed": "contact non renseigné", "Can be an email or a link, or just plain text.": "Peut être une adresse email ou bien un lien, ou alors du simple texte brut.", "URL copied to clipboard": "URL copiée dans le presse-papiers", - "Report #{reportNumber}": "Signalement #{reportNumber}" + "Report #{reportNumber}": "Signalement #{reportNumber}", + "Move \"{resourceName}\"": "Déplacer « {resourceName} »", + "Parent folder": "Dossier parent", + "(this folder)": "(ce dossier)", + "(this link)": "(ce lien)", + "Move resource to {folder}": "Déplacer la ressource dans {folder}", + "Create a folder": "Créer un dossier", + "No resources in this folder": "Aucune ressource dans ce dossier" } diff --git a/js/src/views/Resources/ResourceFolder.vue b/js/src/views/Resources/ResourceFolder.vue index eea87b067..28888591e 100644 --- a/js/src/views/Resources/ResourceFolder.vue +++ b/js/src/views/Resources/ResourceFolder.vue @@ -66,7 +66,7 @@ <section> <div class="list-header"> <div class="list-header-right"> - <b-checkbox v-model="checkedAll" /> + <b-checkbox v-model="checkedAll" v-if="resource.children.total > 0" /> <div class="actions" v-if="validCheckedResources.length > 0"> <small> {{ @@ -85,7 +85,12 @@ </div> </div> </div> - <draggable v-model="resource.children.elements" :sort="false" :group="groupObject"> + <draggable + v-model="resource.children.elements" + :sort="false" + :group="groupObject" + v-if="resource.children.total > 0" + > <transition-group> <div v-for="localResource in resource.children.elements" :key="localResource.id"> <div class="resource-item"> @@ -100,18 +105,22 @@ v-if="localResource.type !== 'folder'" @delete="deleteResource" @rename="handleRename" + @move="handleMove" /> <folder-item :resource="localResource" :group="resource.actor" @delete="deleteResource" - @rename="handleRename" + @move="handleMove" v-else /> </div> </div> </transition-group> </draggable> + <div class="content has-text-centered has-text-grey"> + <p>{{ $t("No resources in this folder") }}</p> + </div> </section> <b-modal :active.sync="renameModal" has-modal-card> <div class="modal-card"> @@ -126,6 +135,18 @@ </section> </div> </b-modal> + <b-modal :active.sync="moveModal" has-modal-card> + <div class="modal-card"> + <section class="modal-card-body"> + <resource-selector + :initialResource="updatedResource" + :username="resource.actor.preferredUsername" + @updateResource="moveResource" + @closeMoveModal="moveModal = false" + /> + </section> + </div> + </b-modal> <b-modal :active.sync="createResourceModal" has-modal-card> <div class="modal-card"> <section class="modal-card-body"> @@ -190,9 +211,10 @@ import { import { CONFIG } from "../../graphql/config"; import { IConfig } from "../../types/config.model"; import ResourceMixin from "../../mixins/resource"; +import ResourceSelector from "../../components/Resource/ResourceSelector.vue"; @Component({ - components: { FolderItem, ResourceItem, Draggable }, + components: { FolderItem, ResourceItem, Draggable, ResourceSelector }, apollo: { resource: { query: GET_RESOURCE, @@ -253,6 +275,8 @@ export default class Resources extends Mixins(ResourceMixin) { createLinkResourceModal = false; + moveModal = false; + renameModal = false; groupObject: object = { @@ -332,6 +356,8 @@ export default class Resources extends Mixins(ResourceMixin) { createSentenceForType(type: string) { switch (type) { + case "folder": + return this.$t("Create a folder"); case "pad": return this.$t("Create a pad"); case "calc": @@ -347,7 +373,6 @@ export default class Resources extends Mixins(ResourceMixin) { } createResourceFromProvider(provider: IProvider) { - console.log(provider); this.newResource.resourceUrl = this.generateFullResourceUrl(provider); this.newResource.type = provider.software; this.createResourceModal = true; @@ -445,24 +470,100 @@ export default class Resources extends Mixins(ResourceMixin) { handleRename(resource: IResource) { this.renameModal = true; - this.updatedResource = resource; + this.updatedResource = Object.assign({}, resource); + } + + handleMove(resource: IResource) { + this.moveModal = true; + this.updatedResource = Object.assign({}, resource); + } + + async moveResource(resource: IResource, oldParent: IResource | undefined) { + const parentPath = oldParent && oldParent.path ? oldParent.path || "/" : "/"; + await this.updateResource(resource, parentPath); + this.moveModal = false; } async renameResource() { await this.updateResource(this.updatedResource); + this.renameModal = false; } - async updateResource(resource: IResource) { + async updateResource(resource: IResource, parentPath: string | null = null) { try { - if (!resource.parent) return; await this.$apollo.mutate<{ updateResource: IResource }>({ mutation: UPDATE_RESOURCE, variables: { id: resource.id, title: resource.title, - parentId: resource.parent.id, + parentId: resource.parent ? resource.parent.id : null, path: resource.path, }, + update: (store, { data }) => { + if (!data || data.updateResource == null || parentPath == null) return; + if (!this.resource.actor) return; + + console.log("Removing ressource from old parent"); + const oldParentCachedData = store.readQuery<{ resource: IResource }>({ + query: GET_RESOURCE, + variables: { + path: parentPath, + username: this.resource.actor.preferredUsername, + }, + }); + if (oldParentCachedData == null) return; + const { resource: oldParentCachedResource } = oldParentCachedData; + if (oldParentCachedResource == null) { + console.error("Cannot update resource cache, because of null value."); + return; + } + const resource: IResource = data.updateResource; + + oldParentCachedResource.children.elements = oldParentCachedResource.children.elements.filter( + (cachedResource) => cachedResource.id !== resource.id + ); + + store.writeQuery({ + query: GET_RESOURCE, + variables: { + path: parentPath, + username: this.resource.actor.preferredUsername, + }, + data: { oldParentCachedResource }, + }); + console.log("Finished removing ressource from old parent"); + + console.log("Adding resource to new parent"); + if (!resource.parent || !resource.parent.path) { + console.log("No cache found for new parent"); + return; + } + const newParentCachedData = store.readQuery<{ resource: IResource }>({ + query: GET_RESOURCE, + variables: { + path: resource.parent.path, + username: this.resource.actor.preferredUsername, + }, + }); + if (newParentCachedData == null) return; + const { resource: newParentCachedResource } = newParentCachedData; + if (newParentCachedResource == null) { + console.error("Cannot update resource cache, because of null value."); + return; + } + + newParentCachedResource.children.elements.push(resource); + + store.writeQuery({ + query: GET_RESOURCE, + variables: { + path: resource.parent.path, + username: this.resource.actor.preferredUsername, + }, + data: { newParentCachedResource }, + }); + console.log("Finished adding resource to new parent"); + }, }); } catch (e) { console.error(e); diff --git a/lib/graphql/schema.ex b/lib/graphql/schema.ex index 3f20d9f11..34fe0c309 100644 --- a/lib/graphql/schema.ex +++ b/lib/graphql/schema.ex @@ -5,7 +5,18 @@ defmodule Mobilizon.GraphQL.Schema do use Absinthe.Schema - alias Mobilizon.{Actors, Addresses, Conversations, Events, Media, Reports, Todos, Users} + alias Mobilizon.{ + Actors, + Addresses, + Conversations, + Events, + Media, + Reports, + Resources, + Todos, + Users + } + alias Mobilizon.Actors.{Actor, Follower, Member} alias Mobilizon.Conversations.Comment alias Mobilizon.Events.{Event, Participant} @@ -109,6 +120,7 @@ defmodule Mobilizon.GraphQL.Schema do |> Dataloader.add_source(Addresses, default_source) |> Dataloader.add_source(Media, default_source) |> Dataloader.add_source(Reports, default_source) + |> Dataloader.add_source(Resources, default_source) |> Dataloader.add_source(Todos, default_source) Map.put(ctx, :loader, loader) diff --git a/lib/graphql/schema/resource.ex b/lib/graphql/schema/resource.ex index f5a1e717b..6b91ba21a 100644 --- a/lib/graphql/schema/resource.ex +++ b/lib/graphql/schema/resource.ex @@ -4,6 +4,8 @@ defmodule Mobilizon.GraphQL.Schema.ResourceType do """ use Absinthe.Schema.Notation alias Mobilizon.GraphQL.Resolvers.Resource + alias Mobilizon.Resources + import Absinthe.Resolution.Helpers, only: [dataloader: 1] @desc "A resource" object :resource do @@ -19,7 +21,8 @@ defmodule Mobilizon.GraphQL.Schema.ResourceType do field(:updated_at, :naive_datetime, description: "The resource's last update date") field(:type, :string, description: "The resource's type (if it's a folder)") field(:path, :string, description: "The resource's path") - field(:parent, :resource, description: "The resource's parent") + + field(:parent, :resource, description: "The resource's parent", resolve: dataloader(Resources)) field :children, :paginated_resource_list do description("Children resources in folder") diff --git a/lib/service/rich_media/parsers/ogp.ex b/lib/service/rich_media/parsers/ogp.ex index 1630d3841..8be34d71d 100644 --- a/lib/service/rich_media/parsers/ogp.ex +++ b/lib/service/rich_media/parsers/ogp.ex @@ -30,7 +30,16 @@ defmodule Mobilizon.Service.RichMedia.Parsers.OGP do defp transform_tags(data) do data |> Map.put(:image_remote_url, Map.get(data, :image)) - |> Map.put(:width, Map.get(data, :"image:width")) - |> Map.put(:height, Map.get(data, :"image:height")) + |> Map.put(:width, get_integer_value(data, :"image:width")) + |> Map.put(:height, get_integer_value(data, :"image:height")) + end + + defp get_integer_value(data, key) do + with value <- Map.get(data, key), + {value, ""} <- Integer.parse(value) do + value + else + _ -> nil + end end end From c3f73f4f87e7896109dbd6a53e91c4ee8b64ed92 Mon Sep 17 00:00:00 2001 From: Thomas Citharel <tcit@tcit.fr> Date: Fri, 26 Jun 2020 12:08:07 +0200 Subject: [PATCH 2/3] Rename conversation strings to discussion Signed-off-by: Thomas Citharel <tcit@tcit.fr> --- js/src/i18n/en_US.json | 10 +++++----- js/src/i18n/fr_FR.json | 10 +++++----- js/src/views/Conversations/Conversation.vue | 2 +- js/src/views/Conversations/ConversationsList.vue | 4 ++-- js/src/views/Conversations/Create.vue | 4 ++-- js/src/views/Group/Group.vue | 2 +- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index 75cbc481a..0f8cad665 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -510,10 +510,7 @@ "Website": "Website", "Actor": "Actor", "Statut": "Statut", - "Conversations": "Conversations", "Text": "Text", - "New conversation": "New conversation", - "Create a new conversation": "Create a new conversation", "All group members and other eventual server admins will still be able to view this information.": "All group members and other eventual server admins will still be able to view this information.", "Upcoming events": "Upcoming events", "View all upcoming events": "View all upcoming events", @@ -525,7 +522,6 @@ "Post a public message": "Post a public message", "View all todos": "View all todos", "Discussions": "Discussions", - "View all conversations": "View all conversations", "No public upcoming events": "No public upcoming events", "Latest posts": "Latest posts", "Invite a new member": "Invite a new member", @@ -703,5 +699,9 @@ "(this link)": "(this link)", "Move resource to {folder}": "Move resource to {folder}", "Create a folder": "Create a folder", - "No resources in this folder": "No resources in this folder" + "No resources in this folder": "No resources in this folder", + "New discussion": "New discussion", + "Create a discussion": "Create a discussion", + "Create the discussion": "Create the discussion", + "View all discussions": "View all discussions" } diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index 450552732..0c0a9965a 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -78,11 +78,9 @@ "Confirmed: Will happen": "Confirmé : aura lieu", "Contact": "Contact", "Continue editing": "Continuer la modification", - "Conversations": "Conversations", "Country": "Pays", "Create": "Créer", "Create a calc": "Créer un calc", - "Create a new conversation": "Créer une nouvelle conversation", "Create a new event": "Créer un nouvel évènement", "Create a new group": "Créer un nouveau groupe", "Create a new identity": "Créer une nouvelle identité", @@ -260,7 +258,6 @@ "My groups": "Mes groupes", "My identities": "Mes identités", "Name": "Nom", - "New conversation": "Nouvelle conversation", "New email": "Nouvelle adresse e-mail", "New folder": "Nouveau dossier", "New link": "Nouveau lien", @@ -478,7 +475,6 @@ "Username": "Pseudo", "Users": "Utilisateur⋅ice⋅s", "View a reply": "Aucune réponse | Voir une réponse | Voir {totalReplies} réponses", - "View all conversations": "Voir toutes les conversations", "View all resources": "Voir toutes les resources", "View all todos": "Voir tous les todos", "View all upcoming events": "Voir tous les événements à venir", @@ -703,5 +699,9 @@ "(this link)": "(ce lien)", "Move resource to {folder}": "Déplacer la ressource dans {folder}", "Create a folder": "Créer un dossier", - "No resources in this folder": "Aucune ressource dans ce dossier" + "No resources in this folder": "Aucune ressource dans ce dossier", + "New discussion": "Nouvelle discussion", + "Create a discussion": "Créer une discussion", + "Create the discussion": "Créer la discussion", + "View all discussions": "Voir toutes les discussions" } diff --git a/js/src/views/Conversations/Conversation.vue b/js/src/views/Conversations/Conversation.vue index fe7d6e55b..220cb5b10 100644 --- a/js/src/views/Conversations/Conversation.vue +++ b/js/src/views/Conversations/Conversation.vue @@ -20,7 +20,7 @@ name: RouteName.CONVERSATION_LIST, params: { preferredUsername: conversation.actor.preferredUsername }, }" - >{{ $t("Conversations") }}</router-link + >{{ $t("Discussions") }}</router-link > </li> <li class="is-active"> diff --git a/js/src/views/Conversations/ConversationsList.vue b/js/src/views/Conversations/ConversationsList.vue index c77a764d8..977c32022 100644 --- a/js/src/views/Conversations/ConversationsList.vue +++ b/js/src/views/Conversations/ConversationsList.vue @@ -20,7 +20,7 @@ name: RouteName.CONVERSATION_LIST, params: { preferredUsername: usernameWithDomain(group) }, }" - >{{ $t("Conversations") }}</router-link + >{{ $t("Discussions") }}</router-link > </li> </ul> @@ -39,7 +39,7 @@ name: RouteName.CREATE_CONVERSATION, params: { preferredUsername: this.preferredUsername }, }" - >{{ $t("New conversation") }}</b-button + >{{ $t("New discussion") }}</b-button > </section> </div> diff --git a/js/src/views/Conversations/Create.vue b/js/src/views/Conversations/Create.vue index 10cc9ad23..e16cdea19 100644 --- a/js/src/views/Conversations/Create.vue +++ b/js/src/views/Conversations/Create.vue @@ -1,6 +1,6 @@ <template> <section class="section container"> - <h1>{{ $t("Create a new conversation") }}</h1> + <h1>{{ $t("Create a discussion") }}</h1> <form @submit.prevent="createConversation"> <b-field :label="$t('Title')"> @@ -11,7 +11,7 @@ <editor v-model="conversation.text" /> </b-field> - <button class="button is-primary" type="submit">{{ $t("Create my group") }}</button> + <button class="button is-primary" type="submit">{{ $t("Create the discussion") }}</button> </form> </section> </template> diff --git a/js/src/views/Group/Group.vue b/js/src/views/Group/Group.vue index 311ffd262..281b3f8ff 100644 --- a/js/src/views/Group/Group.vue +++ b/js/src/views/Group/Group.vue @@ -133,7 +133,7 @@ name: RouteName.CONVERSATION_LIST, params: { preferredUsername: usernameWithDomain(group) }, }" - >{{ $t("View all conversations") }}</router-link + >{{ $t("View all discussions") }}</router-link > </section> </div> From b11674fc9e6365a381c11ba2ec08fedc38d24ad6 Mon Sep 17 00:00:00 2001 From: Thomas Citharel <tcit@tcit.fr> Date: Fri, 26 Jun 2020 14:42:40 +0200 Subject: [PATCH 3/3] Fix opengraph issue Signed-off-by: Thomas Citharel <tcit@tcit.fr> --- lib/service/rich_media/parsers/ogp.ex | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/service/rich_media/parsers/ogp.ex b/lib/service/rich_media/parsers/ogp.ex index 8be34d71d..0b879aab1 100644 --- a/lib/service/rich_media/parsers/ogp.ex +++ b/lib/service/rich_media/parsers/ogp.ex @@ -34,8 +34,9 @@ defmodule Mobilizon.Service.RichMedia.Parsers.OGP do |> Map.put(:height, get_integer_value(data, :"image:height")) end + @spec get_integer_value(Map.t(), atom()) :: integer() | nil defp get_integer_value(data, key) do - with value <- Map.get(data, key), + with value when not is_nil(value) <- Map.get(data, key), {value, ""} <- Integer.parse(value) do value else