diff --git a/lib/graphql/api/search.ex b/lib/graphql/api/search.ex index eba18c20f..d7ef8da0b 100644 --- a/lib/graphql/api/search.ex +++ b/lib/graphql/api/search.ex @@ -57,7 +57,8 @@ defmodule Mobilizon.GraphQL.API.Search do current_actor_id: Map.get(args, :current_actor_id), exclude_my_groups: Map.get(args, :exclude_my_groups, false), exclude_stale_actors: true, - local_only: Map.get(args, :search_target, :internal) == :self + local_only: Map.get(args, :search_target, :internal) == :self, + sort_by: Map.get(args, :sort_by) ], page, limit diff --git a/lib/graphql/schema/search.ex b/lib/graphql/schema/search.ex index f518c13dc..e7742e9fe 100644 --- a/lib/graphql/schema/search.ex +++ b/lib/graphql/schema/search.ex @@ -171,7 +171,11 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do enum :search_group_sort_options do value(:match_desc, description: "The pertinence of the result") - value(:member_count_desc, description: "The members count of the group") + value(:member_count_asc, description: "The members count of the group ascendant order") + value(:member_count_desc, description: "The members count of the group descendent order") + value(:created_at_asc, description: "When the group was created ascendant order") + value(:created_at_desc, description: "When the group was created descendent order") + value(:last_event_activity, description: "Last event activity of the group") end enum :search_event_sort_options do diff --git a/lib/mobilizon/actors/actors.ex b/lib/mobilizon/actors/actors.ex index cc78c0807..1349b32f7 100644 --- a/lib/mobilizon/actors/actors.ex +++ b/lib/mobilizon/actors/actors.ex @@ -13,6 +13,7 @@ defmodule Mobilizon.Actors do alias Mobilizon.Actors.{Actor, Bot, Follower, Member} alias Mobilizon.Addresses.Address alias Mobilizon.Crypto + alias Mobilizon.Events.Event alias Mobilizon.Events.FeedToken alias Mobilizon.Medias alias Mobilizon.Service.Workers @@ -518,7 +519,6 @@ defmodule Mobilizon.Actors do query = from(a in Actor) query - |> distinct([q], q.id) |> actor_by_username_or_name_query(term) |> maybe_join_address( Keyword.get(options, :location), @@ -532,8 +532,56 @@ defmodule Mobilizon.Actors do |> filter_by_minimum_visibility(Keyword.get(options, :minimum_visibility, :public)) |> filter_suspended(false) |> filter_out_anonymous_actor_id(anonymous_actor_id) + # order_by + |> actor_order(Keyword.get(options, :sort_by, :match_desc)) end + # sort by most recent id if "best match" + defp actor_order(query, :match_desc) do + query + |> order_by([q], desc: q.id) + end + + defp actor_order(query, :last_event_activity) do + query + |> join(:left, [q], e in Event, on: e.attributed_to_id == q.id) + |> group_by([q, e], q.id) + |> order_by([q, e], [ + # put groups with no events at the end of the list + fragment("MAX(?) IS NULL", e.updated_at), + # last edited event of the group + desc: max(e.updated_at), + # sort group with no event by id + desc: q.id + ]) + end + + defp actor_order(query, :member_count_asc) do + query + |> join(:left, [q], m in Member, on: m.parent_id == q.id) + |> group_by([q, m], q.id) + |> order_by([q, m], asc: count(m.id), asc: q.id) + end + + defp actor_order(query, :member_count_desc) do + query + |> join(:left, [q], m in Member, on: m.parent_id == q.id) + |> group_by([q, m], q.id) + |> order_by([q, m], desc: count(m.id), desc: q.id) + end + + defp actor_order(query, :created_at_asc) do + query + |> order_by([q], asc: q.inserted_at) + end + + defp actor_order(query, :created_at_desc) do + query + |> order_by([q], desc: q.inserted_at) + end + + defp actor_order(query, _), do: query + @doc """ Gets a group by its title. """ @@ -1394,16 +1442,6 @@ defmodule Mobilizon.Actors do ^username ) ) - |> order_by( - [a], - fragment( - "word_similarity(?, ?) + word_similarity(coalesce(?, ''), ?) desc", - a.preferred_username, - ^username, - a.name, - ^username - ) - ) end @spec maybe_join_address( diff --git a/src/views/SearchView.vue b/src/views/SearchView.vue index 7400abe15..7b7a1ea35 100644 --- a/src/views/SearchView.vue +++ b/src/views/SearchView.vue @@ -884,26 +884,35 @@ enum ViewMode { enum EventSortValues { MATCH_DESC = "MATCH_DESC", + CREATED_AT_ASC = "CREATED_AT_ASC", + CREATED_AT_DESC = "CREATED_AT_DESC", START_TIME_ASC = "START_TIME_ASC", START_TIME_DESC = "START_TIME_DESC", - CREATED_AT_DESC = "CREATED_AT_DESC", - CREATED_AT_ASC = "CREATED_AT_ASC", PARTICIPANT_COUNT_DESC = "PARTICIPANT_COUNT_DESC", } enum GroupSortValues { MATCH_DESC = "MATCH_DESC", + CREATED_AT_ASC = "CREATED_AT_ASC", + CREATED_AT_DESC = "CREATED_AT_DESC", + MEMBER_COUNT_ASC = "MEMBER_COUNT_ASC", MEMBER_COUNT_DESC = "MEMBER_COUNT_DESC", + LAST_EVENT_ACTIVITY = "LAST_EVENT_ACTIVITY", } enum SortValues { + //Common MATCH_DESC = "MATCH_DESC", - START_TIME_ASC = "START_TIME_ASC", - START_TIME_DESC = "START_TIME_DESC", CREATED_AT_DESC = "CREATED_AT_DESC", CREATED_AT_ASC = "CREATED_AT_ASC", + // EventSortValues + START_TIME_ASC = "START_TIME_ASC", + START_TIME_DESC = "START_TIME_DESC", PARTICIPANT_COUNT_DESC = "PARTICIPANT_COUNT_DESC", + // GroupSortValues + MEMBER_COUNT_ASC = "MEMBER_COUNT_ASC", MEMBER_COUNT_DESC = "MEMBER_COUNT_DESC", + LAST_EVENT_ACTIVITY = "LAST_EVENT_ACTIVITY", } const props = defineProps<{ @@ -1261,10 +1270,28 @@ const sortOptions = computed(() => { } if (contentType.value === ContentType.GROUPS) { - options.push({ - key: SortValues.MEMBER_COUNT_DESC, - label: t("Number of members"), - }); + options.push( + { + key: SortValues.MEMBER_COUNT_ASC, + label: t("Increasing number of members"), + }, + { + key: SortValues.MEMBER_COUNT_DESC, + label: t("Decreasing number of members"), + }, + { + key: SortValues.CREATED_AT_ASC, + label: t("Increasing creation date"), + }, + { + key: SortValues.CREATED_AT_DESC, + label: t("Decreasing creation date"), + }, + { + key: SortValues.LAST_EVENT_ACTIVITY, + label: t("Last event activity"), + } + ); } return options;