mirror of
https://framagit.org/framasoft/mobilizon.git
synced 2024-12-21 23:44:30 +00:00
WIP
Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
parent
b3e7f23604
commit
a544e6aee7
7 changed files with 193 additions and 12 deletions
|
@ -248,6 +248,11 @@ config :mobilizon, :maps,
|
|||
type: :openstreetmap
|
||||
]
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Search, extra_provider: Mobilizon.Service.Search.SearchIndex
|
||||
|
||||
config :mobilizon, Mobilizon.Service.Search.SearchIndex,
|
||||
endpoint: "https://search.joinmobilizon.org"
|
||||
|
||||
config :mobilizon, :http_security,
|
||||
enabled: true,
|
||||
sts: false,
|
||||
|
|
|
@ -74,7 +74,7 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||
medias: medias,
|
||||
begins_on: object["startTime"],
|
||||
ends_on: object["endTime"],
|
||||
category: get_category(object["category"]),
|
||||
category: Categories.get_category(object["category"]),
|
||||
visibility: visibility,
|
||||
join_options: Map.get(object, "joinMode", "free"),
|
||||
local: is_local?(object["id"]),
|
||||
|
@ -331,15 +331,4 @@ defmodule Mobilizon.Federation.ActivityStream.Converter.Event do
|
|||
_participant_count
|
||||
),
|
||||
do: nil
|
||||
|
||||
@spec get_category(String.t() | nil) :: String.t()
|
||||
defp get_category(nil), do: "MEETING"
|
||||
|
||||
defp get_category(category) when is_binary(category) do
|
||||
if category in Enum.map(Categories.list(), &String.upcase(to_string(&1.id))) do
|
||||
category
|
||||
else
|
||||
get_category(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -81,6 +81,8 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
|||
description: "Radius around the location to search in"
|
||||
)
|
||||
|
||||
arg(:external, :boolean, default_value: false, description: "Also return external results")
|
||||
|
||||
arg(:page, :integer, default_value: 1, description: "Result page")
|
||||
arg(:limit, :integer, default_value: 10, description: "Results limit per page")
|
||||
|
||||
|
@ -100,6 +102,7 @@ defmodule Mobilizon.GraphQL.Schema.SearchType do
|
|||
description: "Radius around the location to search in"
|
||||
)
|
||||
|
||||
arg(:external, :boolean, default_value: false, description: "Also return external results")
|
||||
arg(:page, :integer, default_value: 1, description: "Result page")
|
||||
arg(:limit, :integer, default_value: 10, description: "Results limit per page")
|
||||
arg(:begins_on, :datetime, description: "Filter events by their start date")
|
||||
|
|
|
@ -9,6 +9,20 @@ defmodule Mobilizon.Events.Categories do
|
|||
build_in_categories() ++ extra_categories()
|
||||
end
|
||||
|
||||
@doc """
|
||||
Get a category for an input string
|
||||
"""
|
||||
@spec get_category(String.t() | nil) :: String.t()
|
||||
def get_category(nil), do: "MEETING"
|
||||
|
||||
def get_category(category) when is_binary(category) do
|
||||
if category in Enum.map(list(), &String.upcase(to_string(&1.id))) do
|
||||
category
|
||||
else
|
||||
get_category(nil)
|
||||
end
|
||||
end
|
||||
|
||||
defp build_in_categories do
|
||||
[
|
||||
%{
|
||||
|
|
19
lib/service/search/external.ex
Normal file
19
lib/service/search/external.ex
Normal file
|
@ -0,0 +1,19 @@
|
|||
defmodule Mobilizon.Service.Search.External do
|
||||
@moduledoc """
|
||||
Search providers manager
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Queries the external search provider
|
||||
"""
|
||||
def search(options) do
|
||||
provider().search(options)
|
||||
end
|
||||
|
||||
@spec provider :: module()
|
||||
defp provider do
|
||||
:mobilizon
|
||||
|> Application.get_env(Mobilizon.Service.Search, [])
|
||||
|> Keyword.get(:extra_provider, Mobilizon.Service.Search.SearchIndex)
|
||||
end
|
||||
end
|
10
lib/service/search/provider.ex
Normal file
10
lib/service/search/provider.ex
Normal file
|
@ -0,0 +1,10 @@
|
|||
defmodule Mobilizon.Service.Search.Provider do
|
||||
@moduledoc """
|
||||
Behaviour for a search provider
|
||||
"""
|
||||
|
||||
@doc """
|
||||
Returns a paginated list of events
|
||||
"""
|
||||
@callback search(options :: Keyword.t()) :: Mobilizon.Storage.Page.t(Mobilizon.Events.Event.t())
|
||||
end
|
141
lib/service/search/search_index.ex
Normal file
141
lib/service/search/search_index.ex
Normal file
|
@ -0,0 +1,141 @@
|
|||
defmodule Mobilizon.Service.Search.SearchIndex do
|
||||
@moduledoc """
|
||||
Search provider for https://search.joinmobilizon.org
|
||||
"""
|
||||
|
||||
alias Mobilizon.Addresses.Address
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.Events.{Categories, Event, EventOptions}
|
||||
alias Mobilizon.Service.HTTP.GeospatialClient
|
||||
alias Mobilizon.Service.Search.Provider
|
||||
alias Mobilizon.Storage.Page
|
||||
import Plug.Conn.Query, only: [encode: 1]
|
||||
|
||||
@behaviour Provider
|
||||
|
||||
@default_endpoint "https://search.joinmobilizon.org"
|
||||
|
||||
@events_api_endpoint "/api/v1/search/events"
|
||||
@groups_api_endpoint "/api/v1/search/groups"
|
||||
|
||||
@default_options [
|
||||
start: 0,
|
||||
count: 10,
|
||||
distance: "10_km"
|
||||
]
|
||||
|
||||
# "?search=test&startDateMin=2022-04-21T16:08:32.675Z&boostLanguages[]=fr&boostLanguages[]=en&distance=10_km&sort=-match&start=0&count=5"
|
||||
|
||||
@doc """
|
||||
Returns a paginated list of events
|
||||
"""
|
||||
@impl Provider
|
||||
def search(options) do
|
||||
case fetch(options) do
|
||||
{:ok, %Tesla.Env{body: body, status: 200}} ->
|
||||
{:ok, transform_results(body, Keyword.get(options, :type, :events))}
|
||||
|
||||
err ->
|
||||
require Logger
|
||||
Logger.error(inspect(err))
|
||||
{:error, :http_error}
|
||||
end
|
||||
end
|
||||
|
||||
defp fetch(options) do
|
||||
@default_options
|
||||
|> Keyword.merge(options)
|
||||
|> build_url()
|
||||
|> GeospatialClient.get()
|
||||
end
|
||||
|
||||
@spec transform_results(%{String.t() => list(map()) | non_neg_integer()}, atom()) ::
|
||||
Page.t(Event.t() | Actor.t())
|
||||
defp transform_results(%{"data" => data, "total" => total}, type) do
|
||||
%Page{
|
||||
total: total,
|
||||
elements:
|
||||
data
|
||||
|> Enum.sort(&(&1["score"] >= &2["score"]))
|
||||
|> Enum.map(fn element -> transform_result(element, type) end)
|
||||
}
|
||||
end
|
||||
|
||||
@spec transform_result(map(), :events | :groups) :: Event.t() | Actor.t()
|
||||
defp transform_result(event, :events) do
|
||||
%Event{
|
||||
category: Categories.get_category(event["category"]),
|
||||
organizer_actor: transform_actor(event["creator"]),
|
||||
ends_on: event["endTime"],
|
||||
attributed_to: transform_actor(event["group"], :Group),
|
||||
id: event["id"],
|
||||
join_options: event["joinMode"],
|
||||
options: %EventOptions{
|
||||
is_online: event["isOnline"],
|
||||
maximum_attendee_capacity: event["maximumAttendeeCapacity"]
|
||||
},
|
||||
physical_address: transform_address(event["location"]),
|
||||
title: event["name"],
|
||||
publish_at: event["published"],
|
||||
begins_on: event["startTime"],
|
||||
status: String.downcase(event["status"]),
|
||||
tags: event["tags"],
|
||||
uuid: event["uuid"],
|
||||
url: event["url"]
|
||||
}
|
||||
end
|
||||
|
||||
defp transform_result(group, :groups) do
|
||||
group = transform_actor(group)
|
||||
|
||||
%Actor{
|
||||
group
|
||||
| type: :Group,
|
||||
physical_address: transform_address(group["location"])
|
||||
}
|
||||
end
|
||||
|
||||
defp transform_actor(actor, type \\ :Person) do
|
||||
%Actor{
|
||||
type: type,
|
||||
id: actor["id"],
|
||||
url: actor["url"],
|
||||
summary: actor["description"],
|
||||
preferred_username: actor["name"],
|
||||
name: actor["displayName"],
|
||||
domain: actor["host"]
|
||||
}
|
||||
end
|
||||
|
||||
defp transform_address(address) when is_map(address) do
|
||||
%Address{
|
||||
description: address["name"],
|
||||
geom: %Geo.Point{
|
||||
coordinates: {address["location"]["lon"], address["location"]["lat"]},
|
||||
srid: 4326
|
||||
},
|
||||
country: address["address"]["addressCountry"],
|
||||
locality: address["address"]["addressLocality"],
|
||||
region: address["address"]["addressRegion"],
|
||||
postal_code: address["address"]["postalCode"],
|
||||
street: address["address"]["streetAddress"]
|
||||
}
|
||||
end
|
||||
|
||||
defp transform_address(_), do: nil
|
||||
|
||||
@spec endpoint :: String.t()
|
||||
defp endpoint do
|
||||
:mobilizon
|
||||
|> Application.get_env(__MODULE__, [])
|
||||
|> Keyword.get(:endpoint, @default_endpoint)
|
||||
end
|
||||
|
||||
defp build_url(options) do
|
||||
{type, options} = Keyword.pop(options, :type, :events)
|
||||
"#{endpoint()}#{api_endpoint(type)}?#{encode(options)}"
|
||||
end
|
||||
|
||||
defp api_endpoint(:events), do: @events_api_endpoint
|
||||
defp api_endpoint(:groups), do: @groups_api_endpoint
|
||||
end
|
Loading…
Reference in a new issue