all developments of milestone 1
This commit is contained in:
@@ -9,7 +9,8 @@ defmodule Mobilizon.Admin do
|
||||
alias Mobilizon.Actors.Actor
|
||||
alias Mobilizon.{Admin, Users}
|
||||
alias Mobilizon.Admin.ActionLog
|
||||
alias Mobilizon.Admin.Setting
|
||||
alias Mobilizon.Admin.{Setting, SettingMedia}
|
||||
alias Mobilizon.Medias.Media
|
||||
alias Mobilizon.Storage.{Page, Repo}
|
||||
alias Mobilizon.Users.User
|
||||
|
||||
@@ -78,9 +79,47 @@ defmodule Mobilizon.Admin do
|
||||
|
||||
defp stringify_struct(struct), do: struct
|
||||
|
||||
@spec get_all_admin_settings :: list(Setting.t())
|
||||
@spec get_all_admin_settings :: map()
|
||||
def get_all_admin_settings do
|
||||
Repo.all(Setting)
|
||||
medias =
|
||||
SettingMedia
|
||||
|> Repo.all()
|
||||
|> Repo.preload(:media)
|
||||
|> Enum.map(fn %SettingMedia{group: group, name: name, media: media} ->
|
||||
{group, name, media}
|
||||
end)
|
||||
|
||||
values =
|
||||
Setting
|
||||
|> Repo.all()
|
||||
|> Enum.map(fn %Setting{group: group, name: name, value: value} ->
|
||||
{group, name, get_setting_value(value)}
|
||||
end)
|
||||
|
||||
all_settings = Enum.concat(values, medias)
|
||||
|
||||
Enum.reduce(
|
||||
all_settings,
|
||||
%{},
|
||||
# For each {group,name,value}
|
||||
fn {group, name, value}, acc ->
|
||||
# We update the %{group: map} in the accumulator
|
||||
{_, new_acc} =
|
||||
Map.get_and_update(
|
||||
acc,
|
||||
group,
|
||||
# We put the %{name: value} into the %{group: map}
|
||||
fn group_map ->
|
||||
{
|
||||
group_map,
|
||||
Map.put(group_map || %{}, name, value)
|
||||
}
|
||||
end
|
||||
)
|
||||
|
||||
new_acc
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
@spec get_admin_setting_value(String.t(), String.t(), String.t() | nil) ::
|
||||
@@ -119,21 +158,40 @@ defmodule Mobilizon.Admin do
|
||||
end
|
||||
end
|
||||
|
||||
@spec get_admin_setting_media(String.t(), String.t(), String.t() | nil) ::
|
||||
{:ok, Media.t()} | {:error, :not_found} | nil
|
||||
def get_admin_setting_media(group, name, fallback \\ nil)
|
||||
when is_binary(group) and is_binary(name) do
|
||||
case SettingMedia
|
||||
|> where(group: ^group)
|
||||
|> where(name: ^name)
|
||||
|> preload(:media)
|
||||
|> Repo.one() do
|
||||
nil ->
|
||||
fallback
|
||||
|
||||
%SettingMedia{media: media} ->
|
||||
media
|
||||
|
||||
%SettingMedia{} ->
|
||||
fallback
|
||||
end
|
||||
end
|
||||
|
||||
@spec save_settings(String.t(), map()) :: {:ok, any} | {:error, any}
|
||||
def save_settings(group, args) do
|
||||
{medias, values} = Map.split(args, [:instance_logo, :instance_favicon, :default_picture])
|
||||
|
||||
Multi.new()
|
||||
|> do_save_setting(group, args)
|
||||
|> do_save_media_setting(group, medias)
|
||||
|> do_save_value_setting(group, values)
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
def clear_settings(group) do
|
||||
Setting |> where([s], s.group == ^group) |> Repo.delete_all()
|
||||
end
|
||||
@spec do_save_value_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
|
||||
defp do_save_value_setting(transaction, _group, args) when args == %{}, do: transaction
|
||||
|
||||
@spec do_save_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
|
||||
defp do_save_setting(transaction, _group, args) when args == %{}, do: transaction
|
||||
|
||||
defp do_save_setting(transaction, group, args) do
|
||||
defp do_save_value_setting(transaction, group, args) do
|
||||
key = hd(Map.keys(args))
|
||||
{val, rest} = Map.pop(args, key)
|
||||
|
||||
@@ -150,7 +208,40 @@ defmodule Mobilizon.Admin do
|
||||
conflict_target: [:group, :name]
|
||||
)
|
||||
|
||||
do_save_setting(transaction, group, rest)
|
||||
do_save_value_setting(transaction, group, rest)
|
||||
end
|
||||
|
||||
@spec do_save_media_setting(Ecto.Multi.t(), String.t(), map()) :: Ecto.Multi.t()
|
||||
defp do_save_media_setting(transaction, _group, args) when args == %{}, do: transaction
|
||||
|
||||
defp do_save_media_setting(transaction, group, args) do
|
||||
key = hd(Map.keys(args))
|
||||
{val, rest} = Map.pop(args, key)
|
||||
|
||||
transaction =
|
||||
case val do
|
||||
val ->
|
||||
Multi.insert(
|
||||
transaction,
|
||||
key,
|
||||
SettingMedia.changeset(%SettingMedia{}, %{
|
||||
group: group,
|
||||
name: Atom.to_string(key),
|
||||
media: val
|
||||
}),
|
||||
on_conflict: :replace_all,
|
||||
conflict_target: [:group, :name]
|
||||
)
|
||||
end
|
||||
|
||||
do_save_media_setting(transaction, group, rest)
|
||||
end
|
||||
|
||||
def clear_settings(group) do
|
||||
Multi.new()
|
||||
|> Multi.delete_all(:settings, Setting |> where([s], s.group == ^group))
|
||||
|> Multi.delete_all(:settings_medias, SettingMedia |> where([s], s.group == ^group))
|
||||
|> Repo.transaction()
|
||||
end
|
||||
|
||||
@spec convert_to_string(any()) :: String.t()
|
||||
|
||||
@@ -4,6 +4,7 @@ defmodule Mobilizon.Admin.Setting do
|
||||
"""
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Ecto.Changeset
|
||||
|
||||
@required_attrs [:group, :name]
|
||||
@optional_attrs [:value]
|
||||
@@ -32,3 +33,93 @@ defmodule Mobilizon.Admin.Setting do
|
||||
|> unique_constraint(:group, name: :admin_settings_group_name_index)
|
||||
end
|
||||
end
|
||||
|
||||
defmodule Mobilizon.Admin.SettingMedia do
|
||||
@moduledoc """
|
||||
A Key-Value settings table for media settings
|
||||
"""
|
||||
use Ecto.Schema
|
||||
import Ecto.Changeset
|
||||
alias Ecto.Changeset
|
||||
alias Mobilizon.Federation.ActivityPub.Relay
|
||||
alias Mobilizon.Medias
|
||||
alias Mobilizon.Medias.Media
|
||||
alias Mobilizon.Storage.Repo
|
||||
|
||||
@required_attrs [:group, :name]
|
||||
|
||||
@type t :: %{
|
||||
group: String.t(),
|
||||
name: String.t(),
|
||||
media: Media.t()
|
||||
}
|
||||
|
||||
schema "admin_settings_medias" do
|
||||
field(:group, :string)
|
||||
field(:name, :string)
|
||||
belongs_to(:media, Media, on_replace: :delete)
|
||||
|
||||
timestamps()
|
||||
end
|
||||
|
||||
@doc false
|
||||
@spec changeset(t | Ecto.Schema.t(), map) :: Ecto.Changeset.t()
|
||||
def changeset(setting_media, attrs) do
|
||||
setting_media
|
||||
|> Repo.preload(:media)
|
||||
|> cast(attrs, @required_attrs)
|
||||
|> put_media(attrs)
|
||||
|> validate_required(@required_attrs)
|
||||
|> unique_constraint(:group, name: :admin_settings_medias_group_name_index)
|
||||
end
|
||||
|
||||
# # In case the provided media is an existing one
|
||||
@spec put_media(Changeset.t(), map) :: Changeset.t()
|
||||
defp put_media(%Changeset{} = changeset, %{media: %{media_id: id}}) do
|
||||
%Media{} = media = Medias.get_media!(id)
|
||||
put_assoc(changeset, :media, media)
|
||||
end
|
||||
|
||||
# In case it's a new media
|
||||
defp put_media(%Changeset{} = changeset, %{media: %{media: media}}) do
|
||||
{:ok, media} = upload_media(media)
|
||||
put_assoc(changeset, :media, media)
|
||||
end
|
||||
|
||||
# In case there is no media
|
||||
defp put_media(%Changeset{} = changeset, _media) do
|
||||
put_assoc(changeset, :media, nil)
|
||||
end
|
||||
|
||||
import Mobilizon.Web.Gettext
|
||||
@spec upload_media(map) :: {:ok, Media.t()} | {:error, any}
|
||||
defp upload_media(%{file: %Plug.Upload{} = file} = args) do
|
||||
with {:ok,
|
||||
%{
|
||||
name: _name,
|
||||
url: url,
|
||||
content_type: content_type,
|
||||
size: size
|
||||
} = uploaded} <-
|
||||
Mobilizon.Web.Upload.store(file),
|
||||
args <-
|
||||
args
|
||||
|> Map.put(:url, url)
|
||||
|> Map.put(:size, size)
|
||||
|> Map.put(:content_type, content_type),
|
||||
{:ok, media = %Media{}} <-
|
||||
Medias.create_media(%{
|
||||
file: args,
|
||||
actor_id: Map.get(args, :actor_id, Relay.get_actor().id),
|
||||
metadata: Map.take(uploaded, [:width, :height, :blurhash])
|
||||
}) do
|
||||
{:ok, media}
|
||||
else
|
||||
{:error, :mime_type_not_allowed} ->
|
||||
{:error, dgettext("errors", "File doesn't have an allowed MIME type.")}
|
||||
|
||||
error ->
|
||||
{:error, error}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,8 @@ defmodule Mobilizon.Config do
|
||||
"""
|
||||
|
||||
alias Mobilizon.Actors
|
||||
alias Mobilizon.Admin.Setting
|
||||
alias Mobilizon.Admin
|
||||
alias Mobilizon.Medias.Media
|
||||
alias Mobilizon.Service.GitStatus
|
||||
require Logger
|
||||
import Mobilizon.Service.Export.Participants.Common, only: [enabled_formats: 0]
|
||||
@@ -29,56 +30,18 @@ defmodule Mobilizon.Config do
|
||||
@spec instance_config :: mobilizon_config
|
||||
def instance_config, do: Application.get_env(:mobilizon, :instance)
|
||||
|
||||
@spec db_instance_config :: list(Setting.t())
|
||||
def db_instance_config, do: Mobilizon.Admin.get_all_admin_settings()
|
||||
|
||||
@spec config_cache :: map()
|
||||
def config_cache do
|
||||
case Cachex.fetch(:config, :all_db_config, fn _key ->
|
||||
value =
|
||||
Enum.reduce(
|
||||
Mobilizon.Admin.get_all_admin_settings(),
|
||||
%{},
|
||||
&arrange_values/2
|
||||
)
|
||||
|
||||
{:commit, value}
|
||||
end) do
|
||||
case Cachex.fetch(
|
||||
:config,
|
||||
:all_db_config,
|
||||
fn _key -> {:commit, Admin.get_all_admin_settings()} end
|
||||
) do
|
||||
{status, value} when status in [:ok, :commit] -> value
|
||||
_err -> %{}
|
||||
end
|
||||
end
|
||||
|
||||
@spec arrange_values(Setting.t(), map()) :: map()
|
||||
defp arrange_values(setting, acc) do
|
||||
{_, new_data} =
|
||||
Map.get_and_update(acc, setting.group, fn current_value ->
|
||||
new_value = current_value || %{}
|
||||
|
||||
{current_value, Map.put(new_value, setting.name, process_value(setting.value))}
|
||||
end)
|
||||
|
||||
new_data
|
||||
end
|
||||
|
||||
@spec process_value(String.t() | nil) :: any()
|
||||
defp process_value(nil), do: nil
|
||||
defp process_value(""), do: nil
|
||||
|
||||
defp process_value(value) do
|
||||
case Jason.decode(value) do
|
||||
{:ok, val} ->
|
||||
val
|
||||
|
||||
{:error, _} ->
|
||||
case value do
|
||||
"true" -> true
|
||||
"false" -> false
|
||||
value -> value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec config_cached_value(String.t(), String.t(), String.t()) :: any()
|
||||
def config_cached_value(group, name, fallback \\ nil) do
|
||||
config_cache()
|
||||
@@ -115,10 +78,23 @@ defmodule Mobilizon.Config do
|
||||
@spec instance_slogan :: String.t() | nil
|
||||
def instance_slogan, do: config_cached_value("instance", "instance_slogan")
|
||||
|
||||
@spec instance_logo :: Media.t() | nil
|
||||
def instance_logo, do: config_cached_value("instance", "instance_logo")
|
||||
|
||||
@spec instance_favicon :: Media.t() | nil
|
||||
def instance_favicon, do: config_cached_value("instance", "instance_favicon")
|
||||
|
||||
@spec default_picture :: Media.t() | nil
|
||||
def default_picture, do: config_cached_value("instance", "default_picture")
|
||||
|
||||
@spec primary_color :: Media.t() | nil
|
||||
def primary_color, do: config_cached_value("instance", "primary_color")
|
||||
|
||||
@spec secondary_color :: Media.t() | nil
|
||||
def secondary_color, do: config_cached_value("instance", "secondary_color")
|
||||
|
||||
@spec contact :: String.t() | nil
|
||||
def contact do
|
||||
config_cached_value("instance", "contact")
|
||||
end
|
||||
def contact, do: config_cached_value("instance", "contact")
|
||||
|
||||
@spec instance_terms(String.t()) :: String.t()
|
||||
def instance_terms(locale \\ "en") do
|
||||
@@ -202,6 +178,9 @@ defmodule Mobilizon.Config do
|
||||
@spec instance_demo_mode? :: boolean
|
||||
def instance_demo_mode?, do: to_boolean(instance_config()[:demo])
|
||||
|
||||
@spec instance_long_events? :: boolean
|
||||
def instance_long_events?, do: instance_config()[:duration_of_long_event] > 0
|
||||
|
||||
@spec instance_repository :: String.t()
|
||||
def instance_repository, do: instance_config()[:repository]
|
||||
|
||||
@@ -470,6 +449,9 @@ defmodule Mobilizon.Config do
|
||||
instance_slogan: instance_slogan(),
|
||||
registrations_open: instance_registrations_open?(),
|
||||
contact: contact(),
|
||||
primary_color: primary_color(),
|
||||
secondary_color: secondary_color(),
|
||||
instance_logo: instance_logo(),
|
||||
instance_terms: instance_terms(),
|
||||
instance_terms_type: instance_terms_type(),
|
||||
instance_terms_url: instance_terms_url(),
|
||||
|
||||
@@ -25,6 +25,7 @@ defmodule Mobilizon.Events.EventOptions do
|
||||
show_participation_price: boolean,
|
||||
offers: [EventOffer.t()],
|
||||
participation_condition: [EventParticipationCondition.t()],
|
||||
hide_number_of_participants: boolean,
|
||||
show_start_time: boolean,
|
||||
show_end_time: boolean,
|
||||
timezone: String.t() | nil,
|
||||
@@ -41,6 +42,7 @@ defmodule Mobilizon.Events.EventOptions do
|
||||
:program,
|
||||
:comment_moderation,
|
||||
:show_participation_price,
|
||||
:hide_number_of_participants,
|
||||
:show_start_time,
|
||||
:show_end_time,
|
||||
:timezone,
|
||||
@@ -59,6 +61,7 @@ defmodule Mobilizon.Events.EventOptions do
|
||||
field(:program, :string)
|
||||
field(:comment_moderation, CommentModeration)
|
||||
field(:show_participation_price, :boolean)
|
||||
field(:hide_number_of_participants, :boolean, default: false)
|
||||
field(:show_start_time, :boolean, default: true)
|
||||
field(:show_end_time, :boolean, default: true)
|
||||
field(:timezone, :string)
|
||||
|
||||
@@ -16,6 +16,7 @@ defmodule Mobilizon.Events do
|
||||
|
||||
alias Mobilizon.Actors.{Actor, Follower}
|
||||
alias Mobilizon.Addresses.Address
|
||||
alias Mobilizon.Config
|
||||
|
||||
alias Mobilizon.Events.{
|
||||
Event,
|
||||
@@ -571,6 +572,7 @@ defmodule Mobilizon.Events do
|
||||
|> events_for_search_query()
|
||||
|> events_for_begins_on(Map.get(args, :begins_on, DateTime.utc_now()))
|
||||
|> events_for_ends_on(Map.get(args, :ends_on))
|
||||
|> events_for_longevents(args)
|
||||
|> events_for_category(args)
|
||||
|> events_for_categories(args)
|
||||
|> events_for_languages(args)
|
||||
@@ -1377,6 +1379,38 @@ defmodule Mobilizon.Events do
|
||||
end
|
||||
end
|
||||
|
||||
@spec events_for_longevents(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||
defp events_for_longevents(query, args) do
|
||||
duration = Config.get([:instance, :duration_of_long_event], 0)
|
||||
|
||||
if duration <= 0 do
|
||||
query
|
||||
else
|
||||
longevents = Map.get(args, :longevents)
|
||||
|
||||
case longevents do
|
||||
nil ->
|
||||
query
|
||||
|
||||
true ->
|
||||
where(
|
||||
query,
|
||||
[q],
|
||||
not is_nil(q.ends_on) and
|
||||
q.ends_on > fragment("? + '1 days'::interval * ?", q.begins_on, ^duration)
|
||||
)
|
||||
|
||||
false ->
|
||||
where(
|
||||
query,
|
||||
[q],
|
||||
is_nil(q.ends_on) or
|
||||
q.ends_on <= fragment("? + '1 days'::interval * ?", q.begins_on, ^duration)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@spec events_for_category(Ecto.Queryable.t(), map()) :: Ecto.Query.t()
|
||||
defp events_for_category(query, %{category: category}) when is_valid_string(category) do
|
||||
where(query, [q], q.category == ^category)
|
||||
|
||||
@@ -185,7 +185,8 @@ defmodule Mobilizon.Medias do
|
||||
[from: "events_medias", param: "media_id"],
|
||||
[from: "posts", param: "picture_id"],
|
||||
[from: "posts_medias", param: "media_id"],
|
||||
[from: "comments_medias", param: "media_id"]
|
||||
[from: "comments_medias", param: "media_id"],
|
||||
[from: "admin_settings_medias", param: "media_id"]
|
||||
]
|
||||
|> Enum.map_join(" UNION ", fn [from: from, param: param] ->
|
||||
"SELECT 1 FROM #{from} WHERE #{from}.#{param} = m0.id"
|
||||
|
||||
Reference in New Issue
Block a user