Merge branch 'fixes' into 'main'

Little fixes

See merge request framasoft/mobilizon!1496
This commit is contained in:
Thomas Citharel 2023-12-05 08:06:10 +00:00
commit f93457131a
8 changed files with 63 additions and 70 deletions

View file

@ -42,28 +42,12 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
end end
@spec fetch_and_create(String.t(), Keyword.t()) :: @spec fetch_and_create(String.t(), Keyword.t()) ::
{:ok, map(), struct()} | {:error, atom()} | :error {:ok, map(), struct()} | {:error, atom()} | {:error, Ecto.Changeset.t()} | :error
def fetch_and_create(url, options \\ []) do def fetch_and_create(url, options \\ []) do
case fetch(url, options) do case fetch(url, options) do
{:ok, data} when is_map(data) -> {:ok, data} when is_map(data) ->
if origin_check?(url, data) do if origin_check?(url, data) do
case Transmogrifier.handle_incoming(%{ pass_to_transmogrifier(data)
"type" => "Create",
"to" => data["to"],
"cc" => data["cc"],
"actor" => data["actor"] || data["attributedTo"],
"attributedTo" => data["attributedTo"] || data["actor"],
"object" => data
}) do
{:ok, entity, structure} ->
{:ok, entity, structure}
{:error, error} when is_atom(error) ->
{:error, error}
:error ->
{:error, :transmogrifier_error}
end
else else
Logger.warning("Object origin check failed") Logger.warning("Object origin check failed")
{:error, :object_origin_check_failed} {:error, :object_origin_check_failed}
@ -98,6 +82,34 @@ defmodule Mobilizon.Federation.ActivityPub.Fetcher do
end end
end end
@spec pass_to_transmogrifier(map()) ::
{:ok, map(), struct()}
| {:error, atom()}
| {:error, Ecto.Changeset.t()}
| {:error, :transmogrifier_error}
defp pass_to_transmogrifier(data) do
case Transmogrifier.handle_incoming(%{
"type" => "Create",
"to" => data["to"],
"cc" => data["cc"],
"actor" => data["actor"] || data["attributedTo"],
"attributedTo" => data["attributedTo"] || data["actor"],
"object" => data
}) do
{:ok, entity, structure} ->
{:ok, entity, structure}
{:error, error} when is_atom(error) ->
{:error, error}
{:error, %Ecto.Changeset{} = err} ->
{:error, err}
:error ->
{:error, :transmogrifier_error}
end
end
@type fetch_actor_errors :: @type fetch_actor_errors ::
:json_decode_error | :actor_deleted | :http_error | :actor_not_allowed_type :json_decode_error | :actor_deleted | :http_error | :actor_not_allowed_type

View file

@ -76,12 +76,10 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
Actions.Create.create(:conversation, object_data, false) Actions.Create.create(:conversation, object_data, false)
object_data when is_map(object_data) -> object_data when is_map(object_data) ->
case Discussions.get_comment_from_url_with_preload(object_data.url) do handle_comment_or_discussion(object_data)
{:error, :comment_not_found} ->
object_data {:error, err} ->
|> transform_object_data_for_discussion() {:error, err}
|> save_comment_or_discussion()
end
end end
{:ok, %Comment{} = comment} -> {:ok, %Comment{} = comment} ->
@ -1019,6 +1017,19 @@ defmodule Mobilizon.Federation.ActivityPub.Transmogrifier do
is_nil(object_data.title) or object_data.title == "" is_nil(object_data.title) or object_data.title == ""
end end
defp handle_comment_or_discussion(object_data) do
case Discussions.get_comment_from_url_with_preload(object_data.url) do
{:error, :comment_not_found} ->
object_data
|> transform_object_data_for_discussion()
|> save_comment_or_discussion()
{:ok, %Comment{} = comment} ->
# Object already exists
{:ok, nil, comment}
end
end
# Comment and conversations have different attributes for actor and groups # Comment and conversations have different attributes for actor and groups
@spec transform_object_data_for_discussion(map()) :: map() @spec transform_object_data_for_discussion(map()) :: map()
defp transform_object_data_for_discussion(object_data) do defp transform_object_data_for_discussion(object_data) do

View file

@ -107,11 +107,7 @@
{{ t("Actions") }} {{ t("Actions") }}
</o-button> </o-button>
</template> </template>
<o-dropdown-item <o-dropdown-item aria-role="listitem" has-link v-if="canManageEvent">
aria-role="listitem"
has-link
v-if="canManageEvent || !event?.draft"
>
<router-link <router-link
class="flex gap-1" class="flex gap-1"
:to="{ :to="{
@ -123,11 +119,7 @@
{{ t("Participations") }} {{ t("Participations") }}
</router-link> </router-link>
</o-dropdown-item> </o-dropdown-item>
<o-dropdown-item <o-dropdown-item aria-role="listitem" has-link v-if="canManageEvent">
aria-role="listitem"
has-link
v-if="canManageEvent || !event?.draft"
>
<router-link <router-link
class="flex gap-1" class="flex gap-1"
:to="{ :to="{

View file

@ -1,7 +1,7 @@
<template> <template>
<Story> <Story>
<Variant title="new"> <Variant title="new">
<TagInput v-model="tags" :fetch-tags="fetchTags" /> <TagInput v-model="tags" />
</Variant> </Variant>
<!-- <Variant title="small"> <!-- <Variant title="small">
<TagInput v-model="tags" /> <TagInput v-model="tags" />
@ -15,9 +15,4 @@ import { reactive } from "vue";
import TagInput from "./TagInput.vue"; import TagInput from "./TagInput.vue";
const tags = reactive<ITag[]>([{ title: "Hello", slug: "hello" }]); const tags = reactive<ITag[]>([{ title: "Hello", slug: "hello" }]);
const fetchTags = async () =>
new Promise<ITag[]>((resolve) => {
resolve([{ title: "Welcome", slug: "welcome" }]);
});
</script> </script>

View file

@ -34,10 +34,11 @@ import { ITag } from "../../types/tag.model";
import debounce from "lodash/debounce"; import debounce from "lodash/debounce";
import { computed, onBeforeMount, ref } from "vue"; import { computed, onBeforeMount, ref } from "vue";
import HelpCircleOutline from "vue-material-design-icons/HelpCircleOutline.vue"; import HelpCircleOutline from "vue-material-design-icons/HelpCircleOutline.vue";
import { useFetchTags } from "@/composition/apollo/tags";
import { FILTER_TAGS } from "@/graphql/tags";
const props = defineProps<{ const props = defineProps<{
modelValue: ITag[]; modelValue: ITag[];
fetchTags: (text: string) => Promise<ITag[]>;
}>(); }>();
const emit = defineEmits(["update:modelValue"]); const emit = defineEmits(["update:modelValue"]);
@ -56,9 +57,14 @@ const id = computed((): string => {
return `tag-input-${componentId}`; return `tag-input-${componentId}`;
}); });
const { load: fetchTags } = useFetchTags();
const getFilteredTags = async (newText: string): Promise<void> => { const getFilteredTags = async (newText: string): Promise<void> => {
text.value = newText; text.value = newText;
tags.value = await props.fetchTags(newText); const res = await fetchTags(FILTER_TAGS, { filter: newText });
if (res) {
tags.value = res.tags;
}
}; };
const debouncedGetFilteredTags = debounce(getFilteredTags, 200); const debouncedGetFilteredTags = debounce(getFilteredTags, 200);

View file

@ -1,24 +1,7 @@
import { FILTER_TAGS } from "@/graphql/tags"; import { FILTER_TAGS } from "@/graphql/tags";
import { ITag } from "@/types/tag.model"; import { ITag } from "@/types/tag.model";
import { apolloClient } from "@/vue-apollo"; import { useLazyQuery } from "@vue/apollo-composable";
import { provideApolloClient, useLazyQuery } from "@vue/apollo-composable";
export async function fetchTags(text: string): Promise<ITag[]> { export function useFetchTags() {
try { return useLazyQuery<{ tags: ITag[] }, { filter: string }>(FILTER_TAGS);
const { load: loadFetchTagsQuery } = useLazyQuery<
{ tags: ITag[] },
{ filter: string }
>(FILTER_TAGS);
const res = await provideApolloClient(apolloClient)(() =>
loadFetchTagsQuery(FILTER_TAGS, {
filter: text,
})
);
if (!res) return [];
return res.tags;
} catch (e) {
console.error(e);
return [];
}
} }

View file

@ -56,11 +56,7 @@
</option> </option>
</o-select> </o-select>
</o-field> </o-field>
<tag-input <tag-input v-model="event.tags" class="flex-1" />
v-model="event.tags"
class="flex-1"
:fetch-tags="fetchTags"
/>
</div> </div>
<o-field <o-field
@ -626,7 +622,6 @@ import {
useTimezones, useTimezones,
} from "@/composition/apollo/config"; } from "@/composition/apollo/config";
import { useMutation } from "@vue/apollo-composable"; import { useMutation } from "@vue/apollo-composable";
import { fetchTags } from "@/composition/apollo/tags";
import { Dialog } from "@/plugins/dialog"; import { Dialog } from "@/plugins/dialog";
import { Notifier } from "@/plugins/notifier"; import { Notifier } from "@/plugins/notifier";
import { useHead } from "@unhead/vue"; import { useHead } from "@unhead/vue";

View file

@ -32,7 +32,7 @@
/> />
</o-field> </o-field>
<tag-input v-model="editablePost.tags" :fetch-tags="fetchTags" /> <tag-input v-model="editablePost.tags" />
<o-field :label="t('Post')"> <o-field :label="t('Post')">
<p v-if="errors.body" class="help is-danger">{{ errors.body }}</p> <p v-if="errors.body" class="help is-danger">{{ errors.body }}</p>
@ -158,7 +158,6 @@ import { useI18n } from "vue-i18n";
import { computed, inject, onMounted, ref, watch } from "vue"; import { computed, inject, onMounted, ref, watch } from "vue";
import { useRouter } from "vue-router"; import { useRouter } from "vue-router";
import { useMutation, useQuery } from "@vue/apollo-composable"; import { useMutation, useQuery } from "@vue/apollo-composable";
import { fetchTags } from "@/composition/apollo/tags";
import { Dialog } from "@/plugins/dialog"; import { Dialog } from "@/plugins/dialog";
const props = withDefaults( const props = withDefaults(