Move to GraphQL

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel
2018-11-06 10:30:27 +01:00
parent 7e137d1a1c
commit b54dae7e15
149 changed files with 5605 additions and 4665 deletions

View File

@@ -14,7 +14,7 @@ defmodule Mix.Tasks.CreateBot do
def run([email, name, summary, type, url]) do
Mix.Task.run("app.start")
with {:ok, %User{} = user} <- Actors.find_by_email(email),
with {:ok, %User{} = user} <- Actors.get_user_by_email(email, true),
actor <- Actors.register_bot_account(%{name: name, summary: summary}),
{:ok, %Bot{} = bot} <-
Actors.create_bot(%{

View File

@@ -11,6 +11,14 @@ defmodule Mobilizon.Actors do
alias Mobilizon.Service.ActivityPub
def data() do
Dataloader.Ecto.new(Repo, query: &query/2)
end
def query(queryable, _params) do
queryable
end
@doc """
Returns the list of actors.
@@ -42,6 +50,28 @@ defmodule Mobilizon.Actors do
Repo.get!(Actor, id)
end
@doc """
Returns the associated actor for an user, either the default set one or the first found
"""
@spec get_actor_for_user(%Mobilizon.Actors.User{}) :: %Mobilizon.Actors.Actor{}
def get_actor_for_user(%Mobilizon.Actors.User{} = user) do
case user.default_actor_id do
nil -> get_first_actor_for_user(user)
actor_id -> get_actor!(actor_id)
end
end
@doc """
Returns the first actor found for an user
Useful when the user has not defined default actor
Raises `Ecto.NoResultsError` if no Actor is found for this ID
"""
defp get_first_actor_for_user(%Mobilizon.Actors.User{id: id} = _user) do
Repo.one!(from(a in Actor, where: a.user_id == ^id))
end
def get_actor_with_everything!(id) do
actor = Repo.get!(Actor, id)
Repo.preload(actor, :organized_events)
@@ -162,10 +192,13 @@ defmodule Mobilizon.Actors do
Repo.all(User)
end
def list_users_with_actors do
users = Repo.all(User)
Repo.preload(users, :actors)
end
@doc """
List users with their associated actors. No reason for that, so removed
"""
# def list_users_with_actors do
# users = Repo.all(User)
# Repo.preload(users, :actors)
# end
defp blank?(""), do: nil
defp blank?(n), do: n
@@ -226,6 +259,14 @@ defmodule Mobilizon.Actors do
Repo.preload(user, :actors)
end
@spec get_user_with_actor(integer()) :: %User{}
def get_user_with_actor(id) do
case Repo.get(User, id) do
nil -> {:error, "User with ID #{id} not found"}
user -> {:ok, Repo.preload(user, :actors)}
end
end
def get_actor_by_url(url) do
Repo.get_by(Actor, url: url)
end
@@ -297,10 +338,17 @@ defmodule Mobilizon.Actors do
@doc """
Find actors by their name or displayed name
"""
def find_actors_by_username_or_name(username) do
def find_actors_by_username_or_name(username, page \\ 1, limit \\ 10)
def find_actors_by_username_or_name("", page, limit), do: []
def find_actors_by_username_or_name(username, page, limit) do
start = (page - 1) * limit
Repo.all(
from(
a in Actor,
limit: ^limit,
offset: ^start,
where:
ilike(a.preferred_username, ^like_sanitize(username)) or
ilike(a.name, ^like_sanitize(username))
@@ -340,19 +388,6 @@ defmodule Mobilizon.Actors do
end
end
@doc """
Get an user by email
"""
def find_by_email(email) do
case Repo.preload(Repo.get_by(User, email: email), :actors) do
nil ->
{:error, nil}
user ->
{:ok, user}
end
end
@doc """
Authenticate user
"""
@@ -390,31 +425,37 @@ defmodule Mobilizon.Actors do
nil
end
actor =
Mobilizon.Actors.Actor.registration_changeset(%Mobilizon.Actors.Actor{}, %{
preferred_username: username,
domain: nil,
keys: pem,
avatar_url: avatar
})
user =
Mobilizon.Actors.User.registration_changeset(%Mobilizon.Actors.User{}, %{
email: email,
password: password
})
actor_with_user = Ecto.Changeset.put_assoc(actor, :user, user)
try do
Mobilizon.Repo.insert!(actor_with_user)
find_by_email(email)
rescue
e in Ecto.InvalidChangesetError ->
{:error, e.changeset}
with actor_changeset <-
Mobilizon.Actors.Actor.registration_changeset(%Mobilizon.Actors.Actor{}, %{
preferred_username: username,
domain: nil,
keys: pem,
avatar_url: avatar
}),
{:ok, %Mobilizon.Actors.Actor{id: id} = actor} <- Mobilizon.Repo.insert(actor_changeset),
user_changeset <-
Mobilizon.Actors.User.registration_changeset(%Mobilizon.Actors.User{}, %{
email: email,
password: password,
default_actor_id: id
}),
{:ok, %Mobilizon.Actors.User{} = user} <- Mobilizon.Repo.insert(user_changeset) do
{:ok, Map.put(actor, :user, user)}
else
{:error, %Ecto.Changeset{} = changeset} ->
handle_actor_user_changeset(changeset)
end
end
defp handle_actor_user_changeset(changeset) do
changeset =
Ecto.Changeset.traverse_errors(changeset, fn
{msg, opts} -> msg
msg -> msg
end)
{:error, hd(Map.get(changeset, :email))}
end
def register_bot_account(%{name: name, summary: summary}) do
key = :public_key.generate_key({:rsa, 2048, 65_537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
@@ -466,9 +507,16 @@ defmodule Mobilizon.Actors do
iex> get_user_by_email(user, wrong_email)
{:error, nil}
"""
def get_user_by_email(email) do
case Repo.get_by(User, email: email) do
nil -> {:error, nil}
def get_user_by_email(email, activated \\ nil) do
query =
case activated do
nil -> from(u in User, where: u.email == ^email)
true -> from(u in User, where: u.email == ^email and not is_nil(u.confirmed_at))
false -> from(u in User, where: u.email == ^email and is_nil(u.confirmed_at))
end
case Repo.one(query) do
nil -> {:error, :user_not_found}
user -> {:ok, user}
end
end

View File

@@ -3,6 +3,7 @@ defmodule Mobilizon.Actors.Service.Activation do
alias Mobilizon.{Mailer, Repo, Actors.User, Actors}
alias Mobilizon.Email.User, as: UserEmail
alias Mobilizon.Actors.Service.Tools
require Logger
@@ -15,7 +16,8 @@ defmodule Mobilizon.Actors.Service.Activation do
"confirmation_sent_at" => nil,
"confirmation_token" => nil
}) do
{:ok, Repo.preload(user, :actors)}
Logger.info("User #{user.email} has been confirmed")
{:ok, user}
else
_err ->
{:error, "Invalid token"}
@@ -23,8 +25,12 @@ defmodule Mobilizon.Actors.Service.Activation do
end
def resend_confirmation_email(%User{} = user, locale \\ "en") do
{:ok, user} = Actors.update_user(user, %{"confirmation_sent_at" => DateTime.utc_now()})
send_confirmation_email(user, locale)
with :ok <- Tools.we_can_send_email(user, :confirmation_sent_at),
{:ok, user} <- Actors.update_user(user, %{"confirmation_sent_at" => DateTime.utc_now()}) do
send_confirmation_email(user, locale)
Logger.info("Sent confirmation email again to #{user.email}")
{:ok, user.email}
end
end
def send_confirmation_email(%User{} = user, locale \\ "en") do

View File

@@ -5,6 +5,7 @@ defmodule Mobilizon.Actors.Service.ResetPassword do
alias Mobilizon.{Mailer, Repo, Actors.User}
alias Mobilizon.Email.User, as: UserEmail
alias Mobilizon.Actors.Service.Tools
@doc """
Check that the provided token is correct and update provided password
@@ -20,7 +21,7 @@ defmodule Mobilizon.Actors.Service.ResetPassword do
"reset_password_token" => nil
})
) do
{:ok, Repo.preload(user, :actors)}
{:ok, user}
else
err ->
{:error, :invalid_token}
@@ -32,11 +33,11 @@ defmodule Mobilizon.Actors.Service.ResetPassword do
"""
@spec send_password_reset_email(User.t(), String.t()) :: tuple
def send_password_reset_email(%User{} = user, locale \\ "en") do
with :ok <- we_can_send_email(user),
with :ok <- Tools.we_can_send_email(user, :reset_password_sent_at),
{:ok, %User{} = user_updated} <-
Repo.update(
User.send_password_reset_changeset(user, %{
"reset_password_token" => random_string(30),
"reset_password_token" => Tools.random_string(30),
"reset_password_sent_at" => DateTime.utc_now()
})
) do
@@ -50,28 +51,4 @@ defmodule Mobilizon.Actors.Service.ResetPassword do
{:error, reason} -> {:error, reason}
end
end
@spec random_string(integer) :: String.t()
defp random_string(length) do
length
|> :crypto.strong_rand_bytes()
|> Base.url_encode64()
end
@spec we_can_send_email(User.t()) :: boolean
defp we_can_send_email(%User{} = user) do
case user.reset_password_sent_at do
nil ->
:ok
_ ->
case Timex.before?(Timex.shift(user.reset_password_sent_at, hours: 1), DateTime.utc_now()) do
true ->
:ok
false ->
{:error, :email_too_soon}
end
end
end
end

View File

@@ -0,0 +1,27 @@
defmodule Mobilizon.Actors.Service.Tools do
alias Mobilizon.Actors.User
@spec we_can_send_email(User.t()) :: boolean
def we_can_send_email(%User{} = user, key \\ :reset_password_sent_at) do
case Map.get(user, key) do
nil ->
:ok
_ ->
case Timex.before?(Timex.shift(Map.get(user, key), hours: 1), DateTime.utc_now()) do
true ->
:ok
false ->
{:error, :email_too_soon}
end
end
end
@spec random_string(integer) :: String.t()
def random_string(length) do
length
|> :crypto.strong_rand_bytes()
|> Base.url_encode64()
end
end

View File

@@ -12,6 +12,7 @@ defmodule Mobilizon.Actors.User do
field(:password, :string, virtual: true)
field(:role, :integer, default: 0)
has_many(:actors, Actor)
field(:default_actor_id, :integer)
field(:confirmed_at, :utc_datetime)
field(:confirmation_sent_at, :utc_datetime)
field(:confirmation_token, :string)
@@ -27,6 +28,7 @@ defmodule Mobilizon.Actors.User do
|> cast(attrs, [
:email,
:role,
:default_actor_id,
:password_hash,
:confirmed_at,
:confirmation_sent_at,
@@ -49,7 +51,8 @@ defmodule Mobilizon.Actors.User do
struct
|> changeset(params)
|> cast(params, ~w(password)a, [])
|> validate_required([:email, :password])
|> validate_required([:email, :password, :default_actor_id])
|> validate_email()
|> validate_length(
:password,
min: 6,
@@ -92,6 +95,19 @@ defmodule Mobilizon.Actors.User do
end
end
defp validate_email(changeset) do
case changeset do
%Ecto.Changeset{valid?: true, changes: %{email: email}} ->
case EmailChecker.valid?(email) do
false -> add_error(changeset, :email, "Email doesn't fit required format")
_ -> changeset
end
_ ->
changeset
end
end
defp random_string(length) do
length
|> :crypto.strong_rand_bytes()

View File

@@ -16,7 +16,7 @@ defmodule Mobilizon.Email.User do
base_email()
|> to(user.email)
|> subject(
gettext("Peakweaver: Confirmation instructions for %{instance}", instance: instance_url)
gettext("Mobilizon: Confirmation instructions for %{instance}", instance: instance_url)
)
|> put_header("Reply-To", get_config(:reply_to))
|> assign(:token, user.confirmation_token)
@@ -32,7 +32,7 @@ defmodule Mobilizon.Email.User do
|> to(user.email)
|> subject(
gettext(
"Peakweaver: Reset your password on %{instance} instructions",
"Mobilizon: Reset your password on %{instance} instructions",
instance: instance_url
)
)

View File

@@ -5,10 +5,11 @@ defmodule Mobilizon.Events.Category do
use Ecto.Schema
import Ecto.Changeset
alias Mobilizon.Events.Category
use Arc.Ecto.Schema
schema "categories" do
field(:description, :string)
field(:picture, :string)
field(:picture, MobilizonWeb.Uploaders.Category.Type)
field(:title, :string, null: false)
timestamps()
@@ -17,7 +18,8 @@ defmodule Mobilizon.Events.Category do
@doc false
def changeset(%Category{} = category, attrs) do
category
|> cast(attrs, [:title, :description, :picture])
|> cast(attrs, [:title, :description])
|> cast_attachments(attrs, [:picture])
|> validate_required([:title])
|> unique_constraint(:title)
end

View File

@@ -86,7 +86,6 @@ defmodule Mobilizon.Events.Event do
|> validate_required([
:title,
:begins_on,
:ends_on,
:organizer_actor_id,
:category_id,
:url,

View File

@@ -6,23 +6,16 @@ defmodule Mobilizon.Events do
import Ecto.Query, warn: false
alias Mobilizon.Repo
alias Mobilizon.Events.Event
alias Mobilizon.Events.Comment
alias Mobilizon.Events.{Event, Comment, Participant}
alias Mobilizon.Actors.Actor
alias Mobilizon.Addresses.Address
@doc """
Returns the list of events.
def data() do
Dataloader.Ecto.new(Mobilizon.Repo, query: &query/2)
end
## Examples
iex> list_events()
[%Event{}, ...]
"""
def list_events do
events = Repo.all(Event)
Repo.preload(events, [:organizer_actor])
def query(queryable, _params) do
queryable
end
def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ 1, limit \\ 10) do
@@ -179,15 +172,47 @@ defmodule Mobilizon.Events do
])
end
@doc """
Returns the list of events.
## Examples
iex> list_events()
[%Event{}, ...]
"""
def list_events(page \\ 1, limit \\ 10) do
start = (page - 1) * limit
query =
from(e in Event,
limit: ^limit,
offset: ^start,
preload: [:organizer_actor]
)
Repo.all(query)
end
@doc """
Find events by name
"""
def find_events_by_name(name) when name == "", do: []
def find_events_by_name(name, page \\ 1, limit \\ 10)
def find_events_by_name("", page, limit), do: list_events(page, limit)
def find_events_by_name(name) do
def find_events_by_name(name, page, limit) do
name = String.trim(name)
events = Repo.all(from(a in Event, where: ilike(a.title, ^like_sanitize(name))))
Repo.preload(events, [:organizer_actor])
start = (page - 1) * limit
query =
from(e in Event,
limit: ^limit,
offset: ^start,
where: ilike(e.title, ^like_sanitize(name)),
preload: [:organizer_actor]
)
Repo.all(query)
end
@doc """
@@ -210,9 +235,16 @@ defmodule Mobilizon.Events do
"""
def create_event(attrs \\ %{}) do
case %Event{} |> Event.changeset(attrs) |> Repo.insert() do
{:ok, %Event{} = event} -> {:ok, Repo.preload(event, [:organizer_actor])}
err -> err
with {:ok, %Event{} = event} <- %Event{} |> Event.changeset(attrs) |> Repo.insert(),
{:ok, %Participant{} = _participant} <-
%Participant{}
|> Participant.changeset(%{
actor_id: attrs.organizer_actor_id,
role: 4,
event_id: event.id
})
|> Repo.insert() do
{:ok, Repo.preload(event, [:organizer_actor])}
end
end
@@ -475,6 +507,27 @@ defmodule Mobilizon.Events do
Repo.all(Participant)
end
@doc """
Returns the list of participants for an event.
## Examples
iex> list_participants_for_event(someuuid)
[%Participant{}, ...]
"""
def list_participants_for_event(uuid) do
Repo.all(
from(
p in Participant,
join: e in Event,
on: p.event_id == e.id,
where: e.uuid == ^uuid,
preload: [:actor]
)
)
end
@doc """
Gets a single participant.

View File

@@ -8,7 +8,7 @@ defmodule MobilizonWeb.AuthPipeline do
module: MobilizonWeb.Guardian,
error_handler: MobilizonWeb.AuthErrorHandler
plug(Guardian.Plug.VerifyHeader, claims: %{"typ" => "access"})
plug(Guardian.Plug.EnsureAuthenticated)
plug(Guardian.Plug.LoadResource, ensure: true)
plug(Guardian.Plug.VerifyHeader, realm: "Bearer")
plug(Guardian.Plug.LoadResource, allow_blank: true)
plug(MobilizonWeb.Context)
end

View File

@@ -0,0 +1,20 @@
defmodule MobilizonWeb.Context do
@behaviour Plug
import Plug.Conn
require Logger
def init(opts) do
opts
end
def call(conn, _) do
case Guardian.Plug.current_resource(conn) do
nil ->
conn
user ->
put_private(conn, :absinthe, %{context: %{current_user: user}})
end
end
end

View File

@@ -1,79 +0,0 @@
defmodule MobilizonWeb.ActorController do
@moduledoc """
Controller for Actors
"""
use MobilizonWeb, :controller
alias Mobilizon.Actors
alias Mobilizon.Actors.{Actor, User}
alias Mobilizon.Service.ActivityPub
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
actors = Actors.list_actors()
render(conn, "index.json", actors: actors)
end
def create(conn, %{"actor" => actor_params}) do
with %User{} = user <- Guardian.Plug.current_resource(conn),
actor_params <- Map.put(actor_params, "user_id", user.id),
actor_params <- Map.put(actor_params, "keys", keys_for_account()),
{:ok, %Actor{} = actor} <- Actors.create_actor(actor_params) do
conn
|> put_status(:created)
|> put_resp_header("location", actor_path(conn, :show, actor.preferred_username))
|> render("show_basic.json", actor: actor)
end
end
defp keys_for_account() do
key = :public_key.generate_key({:rsa, 2048, 65_537})
entry = :public_key.pem_entry_encode(:RSAPrivateKey, key)
[entry]
|> :public_key.pem_encode()
|> String.trim_trailing()
end
def show(conn, %{"name" => name}) do
with %Actor{} = actor <- Actors.get_actor_by_name_with_everything(name) do
render(conn, "show.json", actor: actor)
else
nil ->
send_resp(conn, :not_found, "")
end
end
@email_regex ~r/^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/
def search(conn, %{"name" => name}) do
# find already saved accounts
case Actors.search(name) do
{:ok, actors} ->
render(conn, "index.json", actors: actors)
{:error, err} ->
json(conn, err)
end
end
def update(conn, %{"name" => name, "actor" => actor_params}) do
actor = Actors.get_local_actor_by_name(name)
with {:ok, %Actor{} = actor} <- Actors.update_actor(actor, actor_params) do
render(conn, "show_basic.json", actor: actor)
end
end
# def delete(conn, %{"id" => id_str}) do
# {id, _} = Integer.parse(id_str)
# if Guardian.Plug.current_resource(conn).actor.id == id do
# actor = Actors.get_actor!(id)
# with {:ok, %Actor{}} <- Actors.delete_actor(actor) do
# send_resp(conn, :no_content, "")
# end
# else
# send_resp(conn, 401, "")
# end
# end
end

View File

@@ -1,78 +0,0 @@
defmodule MobilizonWeb.AddressController do
@moduledoc """
A controller for addresses
"""
use MobilizonWeb, :controller
alias Mobilizon.Addresses
alias Mobilizon.Addresses.Address
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
addresses = Addresses.list_addresses()
render(conn, "index.json", addresses: addresses)
end
def create(conn, %{"address" => address_params}) do
with {:ok, geom} <- Addresses.process_geom(address_params["geom"]) do
address_params = %{address_params | "geom" => geom}
with {:ok, %Address{} = address} <- Addresses.create_address(address_params) do
conn
|> put_status(:created)
|> put_resp_header("location", address_path(conn, :show, address))
|> render("show.json", address: address)
end
end
end
def process_geom(%{"type" => type, "data" => data}) do
import Logger
Logger.debug("Process geom")
Logger.debug(inspect(data))
Logger.debug(inspect(type))
types = [:point]
unless is_atom(type) do
type = String.to_existing_atom(type)
end
case type do
:point ->
%Geo.Point{coordinates: {data["latitude"], data["longitude"]}, srid: 4326}
nil ->
nil
end
end
def process_geom(nil) do
nil
end
def show(conn, %{"id" => id}) do
address = Addresses.get_address!(id)
render(conn, "show.json", address: address)
end
def update(conn, %{"id" => id, "address" => address_params}) do
with {:ok, geom} <- Addresses.process_geom(address_params["geom"]) do
address = Addresses.get_address!(id)
address_params = %{address_params | "geom" => geom}
with {:ok, %Address{} = address} <- Addresses.update_address(address, address_params) do
render(conn, "show.json", address: address)
end
end
end
def delete(conn, %{"id" => id}) do
address = Addresses.get_address!(id)
with {:ok, %Address{}} <- Addresses.delete_address(address) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,48 +0,0 @@
defmodule MobilizonWeb.BotController do
use MobilizonWeb, :controller
alias Mobilizon.Actors
alias Mobilizon.Actors.{Bot, Actor}
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
bots = Actors.list_bots()
render(conn, "index.json", bots: bots)
end
def create(conn, %{"bot" => bot_params}) do
with user <- Guardian.Plug.current_resource(conn),
bot_params <- Map.put(bot_params, "user_id", user.id),
%Actor{} = actor <-
Actors.register_bot_account(%{name: bot_params["name"], summary: bot_params["summary"]}),
bot_params <- Map.put(bot_params, "actor_id", actor.id),
{:ok, %Bot{} = bot} <- Actors.create_bot(bot_params) do
conn
|> put_status(:created)
|> put_resp_header("location", bot_path(conn, :show, bot))
|> render("show.json", bot: bot)
end
end
def show(conn, %{"id" => id}) do
bot = Actors.get_bot!(id)
render(conn, "show.json", bot: bot)
end
def update(conn, %{"id" => id, "bot" => bot_params}) do
bot = Actors.get_bot!(id)
with {:ok, %Bot{} = bot} <- Actors.update_bot(bot, bot_params) do
render(conn, "show.json", bot: bot)
end
end
def delete(conn, %{"id" => id}) do
bot = Actors.get_bot!(id)
with {:ok, %Bot{}} <- Actors.delete_bot(bot) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,46 +0,0 @@
defmodule MobilizonWeb.CategoryController do
@moduledoc """
Controller for Categories
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Events.Category
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
categories = Events.list_categories()
render(conn, "index.json", categories: categories)
end
def create(conn, %{"category" => category_params}) do
with {:ok, %Category{} = category} <- Events.create_category(category_params) do
conn
|> put_status(:created)
|> put_resp_header("location", category_path(conn, :show, category))
|> render("show.json", category: category)
end
end
def show(conn, %{"id" => id}) do
category = Events.get_category!(id)
render(conn, "show.json", category: category)
end
def update(conn, %{"id" => id, "category" => category_params}) do
category = Events.get_category!(id)
with {:ok, %Category{} = category} <- Events.update_category(category, category_params) do
render(conn, "show.json", category: category)
end
end
def delete(conn, %{"id" => id}) do
category = Events.get_category!(id)
with {:ok, %Category{}} <- Events.delete_category(category) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,43 +0,0 @@
defmodule MobilizonWeb.CommentController do
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Events.Comment
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
comments = Events.list_comments()
render(conn, "index.json", comments: comments)
end
def create(conn, %{"comment" => comment_params}) do
with {:ok, %Comment{} = comment} <- Events.create_comment(comment_params) do
conn
|> put_status(:created)
|> put_resp_header("location", comment_path(conn, :show, comment))
|> render("show.json", comment: comment)
end
end
def show(conn, %{"uuid" => uuid}) do
comment = Events.get_comment_with_uuid!(uuid)
render(conn, "show.json", comment: comment)
end
def update(conn, %{"uuid" => uuid, "comment" => comment_params}) do
comment = Events.get_comment_with_uuid!(uuid)
with {:ok, %Comment{} = comment} <- Events.update_comment(comment, comment_params) do
render(conn, "show.json", comment: comment)
end
end
def delete(conn, %{"uuid" => uuid}) do
comment = Events.get_comment_with_uuid!(uuid)
with {:ok, %Comment{}} <- Events.delete_comment(comment) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,125 +0,0 @@
defmodule MobilizonWeb.EventController do
@moduledoc """
Controller for Events
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Events.Event
alias Mobilizon.Export.ICalendar
require Logger
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
ip = "88.161.154.97"
Logger.debug(inspect(Geolix.lookup(ip), pretty: true))
with %{
city: %Geolix.Adapter.MMDB2.Result.City{
city: city,
country: country,
location: %Geolix.Adapter.MMDB2.Record.Location{
latitude: latitude,
longitude: longitude
}
}
} <- Geolix.lookup(ip) do
distance =
case city do
nil -> 500_000
_ -> 50_000
end
events = Events.find_close_events(longitude, latitude, distance)
render(
conn,
"index.json",
events: events,
coord: %{longitude: longitude, latitude: latitude, distance: distance},
city: city,
country: country
)
end
end
def index_all(conn, _params) do
events = Events.list_events()
render(conn, "index_all.json", events: events)
end
def create(conn, %{"event" => event_params}) do
event_params = process_event_address(event_params)
Logger.debug("creating event with")
Logger.debug(inspect(event_params))
with {:ok, %Event{} = event} <- Events.create_event(event_params) do
conn
|> put_status(:created)
|> put_resp_header("location", event_path(conn, :show, event.uuid))
|> render("show_simple.json", event: event)
end
end
defp process_event_address(event) do
cond do
Map.has_key?(event, "address_type") && event["address_type"] !== :physical ->
event
Map.has_key?(event, "physical_address") ->
address = event["physical_address"]
geom = MobilizonWeb.AddressController.process_geom(address["geom"])
address =
case geom do
nil ->
address
_ ->
%{address | "geom" => geom}
end
%{event | "physical_address" => address}
true ->
event
end
end
def search(conn, %{"name" => name}) do
events = Events.find_events_by_name(name)
render(conn, "index.json", events: events)
end
def show(conn, %{"uuid" => uuid}) do
case Events.get_event_full_by_uuid(uuid) do
nil ->
send_resp(conn, 404, "")
event ->
render(conn, "show.json", event: event)
end
end
def export_to_ics(conn, %{"uuid" => uuid}) do
event = uuid |> Events.get_event_full_by_uuid() |> ICalendar.export_event()
send_resp(conn, 200, event)
end
def update(conn, %{"uuid" => uuid, "event" => event_params}) do
event = Events.get_event_full_by_uuid(uuid)
with {:ok, %Event{} = event} <- Events.update_event(event, event_params) do
render(conn, "show_simple.json", event: event)
end
end
def delete(conn, %{"uuid" => uuid}) do
with event <- Events.get_event_by_uuid(uuid),
{:ok, %Event{}} <- Events.delete_event(event) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,52 +0,0 @@
# defmodule MobilizonWeb.EventRequestController do
# @moduledoc """
# Controller for Event requests
# """
# use MobilizonWeb, :controller
#
# alias Mobilizon.Events
# alias Mobilizon.Events.{Event, Request}
#
# action_fallback MobilizonWeb.FallbackController
#
# def index_for_user(conn, _params) do
# actor = Guardian.Plug.current_resource(conn).actor
# requests = Events.list_requests_for_actor(actor)
# render(conn, "index.json", requests: requests)
# end
#
# def create(conn, %{"request" => request_params}) do
# request_params = Map.put(request_params, "actor_id", Guardian.Plug.current_resource(conn).actor.id)
# with {:ok, %Request{} = request} <- Events.create_request(request_params) do
# conn
# |> put_status(:created)
# |> put_resp_header("location", event_request_path(conn, :show, request))
# |> render("show.json", request: request)
# end
# end
#
# def create_for_event(conn, %{"request" => request_params, "id" => event_id}) do
# request_params = Map.put(request_params, "event_id", event_id)
# create(conn, request_params)
# end
#
# def show(conn, %{"id" => id}) do
# request = Events.get_request!(id)
# render(conn, "show.json", request: request)
# end
#
# def update(conn, %{"id" => id, "request" => request_params}) do
# request = Events.get_request!(id)
#
# with {:ok, %Request{} = request} <- Events.update_request(request, request_params) do
# render(conn, "show.json", request: request)
# end
# end
#
# def delete(conn, %{"id" => id}) do
# request = Events.get_request!(id)
# with {:ok, %Request{}} <- Events.delete_request(request) do
# send_resp(conn, :no_content, "")
# end
# end
# end

View File

@@ -1,43 +0,0 @@
defmodule MobilizonWeb.FollowerController do
use MobilizonWeb, :controller
alias Mobilizon.Actors
alias Mobilizon.Actors.Follower
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
followers = Actors.list_followers()
render(conn, "index.json", followers: followers)
end
def create(conn, %{"follower" => follower_params}) do
with {:ok, %Follower{} = follower} <- Actors.create_follower(follower_params) do
conn
|> put_status(:created)
|> put_resp_header("location", follower_path(conn, :show, follower))
|> render("show.json", follower: follower)
end
end
def show(conn, %{"id" => id}) do
follower = Actors.get_follower!(id)
render(conn, "show.json", follower: follower)
end
def update(conn, %{"id" => id, "follower" => follower_params}) do
follower = Actors.get_follower!(id)
with {:ok, %Follower{} = follower} <- Actors.update_follower(follower, follower_params) do
render(conn, "show.json", follower: follower)
end
end
def delete(conn, %{"id" => id}) do
follower = Actors.get_follower!(id)
with {:ok, %Follower{}} <- Actors.delete_follower(follower) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,53 +0,0 @@
defmodule MobilizonWeb.GroupController do
@moduledoc """
Controller for Groups
"""
use MobilizonWeb, :controller
alias Mobilizon.Actors
alias Mobilizon.Actors.{Actor, Member}
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
groups = Actors.list_groups()
render(conn, MobilizonWeb.ActorView, "index.json", actors: groups)
end
def create(conn, %{"group" => group_params}) do
with {:ok, %Actor{} = group} <- Actors.create_group(group_params),
{:ok, %Member{} = member} <-
Actors.create_member(%{
"parent_id" => group.id,
"actor_id" => Actors.get_local_actor_by_name(group_params["actor_admin"]).id,
"role" => 2
}) do
conn
|> put_status(:created)
|> put_resp_header("location", actor_path(conn, :show, group))
|> render(MobilizonWeb.ActorView, "actor_basic.json", actor: group)
end
end
def join(conn, %{"name" => group_name, "actor_name" => actor_name}) do
with %Actor{} = group <- Actors.get_group_by_name(group_name),
%Actor{} = actor <- Actors.get_local_actor_by_name(actor_name),
{:ok, %Member{} = member} <-
Actors.create_member(%{"parent_id" => group.id, "actor_id" => actor.id}) do
conn
|> put_status(:created)
|> render(MobilizonWeb.MemberView, "member.json", member: member)
else
nil ->
conn
|> put_status(:not_found)
|> render(MobilizonWeb.ErrorView, "not_found.json",
details: "group or actor doesn't exist"
)
err ->
require Logger
Logger.debug(inspect(err))
end
end
end

View File

@@ -1,6 +0,0 @@
defmodule MobilizonWeb.InboxesController do
use MobilizonWeb, :controller
def create(conn) do
end
end

View File

@@ -1,4 +1,4 @@
defmodule MobilizonWeb.NodeinfoController do
defmodule MobilizonWeb.NodeInfoController do
use MobilizonWeb, :controller
alias MobilizonWeb
@@ -11,7 +11,7 @@ defmodule MobilizonWeb.NodeinfoController do
links: [
%{
rel: "http://nodeinfo.diaspora.software/ns/schema/2.0",
href: MobilizonWeb.Router.Helpers.nodeinfo_url(MobilizonWeb.Endpoint, :nodeinfo, "2.0")
href: MobilizonWeb.Router.Helpers.node_info_url(MobilizonWeb.Endpoint, :nodeinfo, "2.0")
}
]
}

View File

@@ -1,10 +0,0 @@
defmodule MobilizonWeb.OutboxesController do
use MobilizonWeb, :controller
def show(conn) do
actor = Guardian.Plug.current_resource(conn).actor
events = actor.events
render(conn, "index.json", events: events)
end
end

View File

@@ -1,18 +0,0 @@
defmodule MobilizonWeb.ParticipantController do
@moduledoc """
Controller for participants to an event
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
def join(conn, %{"uuid" => uuid}) do
with event <- Events.get_event_by_uuid(uuid),
%{actor: actor} <- Guardian.Plug.current_resource(conn) do
participant =
Events.create_participant(%{"event_id" => event.id, "actor_id" => actor.id, "role" => 1})
render(conn, "participant.json", %{participant: participant})
end
end
end

View File

@@ -1,23 +0,0 @@
defmodule MobilizonWeb.SearchController do
@moduledoc """
Controller for Search
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Actors
action_fallback(MobilizonWeb.FallbackController)
def search(conn, %{"name" => name}) do
events = Events.find_events_by_name(name)
# find already saved accounts
case Actors.search(name) do
{:ok, actors} ->
render(conn, "search.json", events: events, actors: actors)
{:error, err} ->
json(conn, err)
end
end
end

View File

@@ -1,56 +0,0 @@
defmodule MobilizonWeb.SessionController do
@moduledoc """
Controller for (event) Sessions
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Events.Session
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
sessions = Events.list_sessions()
render(conn, "index.json", sessions: sessions)
end
def create(conn, %{"session" => session_params}) do
with {:ok, %Session{} = session} <- Events.create_session(session_params) do
conn
|> put_status(:created)
|> put_resp_header("location", session_path(conn, :show, session))
|> render("show.json", session: session)
end
end
def show(conn, %{"id" => id}) do
session = Events.get_session!(id)
render(conn, "show.json", session: session)
end
def show_sessions_for_event(conn, %{"uuid" => event_uuid}) do
sessions = Events.list_sessions_for_event(event_uuid)
render(conn, "index.json", sessions: sessions)
end
def show_sessions_for_track(conn, %{"id" => track}) do
sessions = Events.list_sessions_for_track(track)
render(conn, "index.json", sessions: sessions)
end
def update(conn, %{"id" => id, "session" => session_params}) do
session = Events.get_session!(id)
with {:ok, %Session{} = session} <- Events.update_session(session, session_params) do
render(conn, "show.json", session: session)
end
end
def delete(conn, %{"id" => id}) do
session = Events.get_session!(id)
with {:ok, %Session{}} <- Events.delete_session(session) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,46 +0,0 @@
defmodule MobilizonWeb.TagController do
@moduledoc """
Controller for Tags
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Events.Tag
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
tags = Events.list_tags()
render(conn, "index.json", tags: tags)
end
def create(conn, %{"tag" => tag_params}) do
with {:ok, %Tag{} = tag} <- Events.create_tag(tag_params) do
conn
|> put_status(:created)
|> put_resp_header("location", tag_path(conn, :show, tag))
|> render("show.json", tag: tag)
end
end
def show(conn, %{"id" => id}) do
tag = Events.get_tag!(id)
render(conn, "show.json", tag: tag)
end
def update(conn, %{"id" => id, "tag" => tag_params}) do
tag = Events.get_tag!(id)
with {:ok, %Tag{} = tag} <- Events.update_tag(tag, tag_params) do
render(conn, "show.json", tag: tag)
end
end
def delete(conn, %{"id" => id}) do
tag = Events.get_tag!(id)
with {:ok, %Tag{}} <- Events.delete_tag(tag) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,46 +0,0 @@
defmodule MobilizonWeb.TrackController do
@moduledoc """
Controller for Tracks
"""
use MobilizonWeb, :controller
alias Mobilizon.Events
alias Mobilizon.Events.Track
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
tracks = Events.list_tracks()
render(conn, "index.json", tracks: tracks)
end
def create(conn, %{"track" => track_params}) do
with {:ok, %Track{} = track} <- Events.create_track(track_params) do
conn
|> put_status(:created)
|> put_resp_header("location", track_path(conn, :show, track))
|> render("show.json", track: track)
end
end
def show(conn, %{"id" => id}) do
track = Events.get_track!(id)
render(conn, "show.json", track: track)
end
def update(conn, %{"id" => id, "track" => track_params}) do
track = Events.get_track!(id)
with {:ok, %Track{} = track} <- Events.update_track(track, track_params) do
render(conn, "show.json", track: track)
end
end
def delete(conn, %{"id" => id}) do
track = Events.get_track!(id)
with {:ok, %Track{}} <- Events.delete_track(track) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,148 +0,0 @@
defmodule MobilizonWeb.UserController do
@moduledoc """
Controller for Users
"""
use MobilizonWeb, :controller
alias Mobilizon.Actors
alias Mobilizon.Actors.User
alias Mobilizon.Repo
alias Mobilizon.Actors.Service.{Activation, ResetPassword}
action_fallback(MobilizonWeb.FallbackController)
def index(conn, _params) do
users = Actors.list_users_with_actors()
render(conn, "index.json", users: users)
end
def register(conn, %{"username" => username, "email" => email, "password" => password}) do
with {:ok, %User{} = user} <-
Actors.register(%{email: email, password: password, username: username}) do
Activation.send_confirmation_email(user, "locale")
conn
|> put_status(:created)
|> render("confirmation.json", %{user: user})
end
end
def validate(conn, %{"token" => token}) do
with {:ok, %User{} = user} <- Activation.check_confirmation_token(token) do
{:ok, token, _claims} = MobilizonWeb.Guardian.encode_and_sign(user)
conn
|> put_resp_header("location", user_path(conn, :show_current_actor))
|> render("show_with_token.json", %{user: user, token: token})
else
{:error, msg} ->
conn
|> put_status(:not_found)
|> json(%{"error" => msg})
end
end
@time_before_resend 3600
def resend_confirmation(conn, %{"email" => email}) do
with {:ok, %User{} = user} <- Actors.find_by_email(email),
false <- is_nil(user.confirmation_token),
true <-
Timex.before?(
Timex.shift(user.confirmation_sent_at, seconds: @time_before_resend),
DateTime.utc_now()
) do
Activation.resend_confirmation_email(user)
render(conn, "confirmation.json", %{user: user})
else
{:error, :not_found} ->
conn
|> put_status(:not_found)
|> json(%{"error" => "Unable to find an user with this email"})
_ ->
conn
|> put_status(:not_found)
|> json(%{
"error" =>
"Unable to resend the validation token. Please wait a while before you can ask for resending token"
})
end
end
def send_reset_password(conn, %{"email" => email}) do
with {:ok, %User{} = user} <- Actors.find_by_email(email),
{:ok, _} <- ResetPassword.send_password_reset_email(user) do
render(conn, "password_reset.json", %{user: user})
else
{:error, nil} ->
conn
|> put_status(:not_found)
|> json(%{"errors" => "Unable to find an user with this email"})
{:error, :email_too_soon} ->
conn
|> put_status(:not_found)
|> json(%{"errors" => "You requested a new reset password too early"})
end
end
def reset_password(conn, %{"password" => password, "token" => token}) do
with {:ok, %User{} = user} <- ResetPassword.check_reset_password_token(password, token) do
{:ok, token, _claims} = MobilizonWeb.Guardian.encode_and_sign(user)
render(conn, "show_with_token.json", %{user: user, token: token})
else
{:error, :invalid_token} ->
conn
|> put_status(:not_found)
|> json(%{"errors" => %{"token" => ["Wrong token for password reset"]}})
{:error, %Ecto.Changeset{} = changeset} ->
conn
|> put_status(:unprocessable_entity)
|> render(MobilizonWeb.ChangesetView, "error.json", changeset: changeset)
end
end
def show_current_actor(conn, _params) do
user =
conn
|> Guardian.Plug.current_resource()
|> Repo.preload(:actors)
render(conn, "show_simple.json", user: user)
end
# defp handle_changeset_errors(errors) do
# errors
# |> Enum.map(fn {field, detail} ->
# "#{field} " <> render_detail(detail)
# end)
# |> Enum.join()
# end
# defp render_detail({message, values}) do
# Enum.reduce(values, message, fn {k, v}, acc ->
# String.replace(acc, "%{#{k}}", to_string(v))
# end)
# end
# defp render_detail(message) do
# message
# end
def update(conn, %{"id" => id, "user" => user_params}) do
user = Actors.get_user!(id)
with {:ok, %User{} = user} <- Actors.update_user(user, user_params) do
render(conn, "show.json", user: user)
end
end
def delete(conn, %{"id" => id}) do
user = Actors.get_user!(id)
with {:ok, %User{}} <- Actors.delete_user(user) do
send_resp(conn, :no_content, "")
end
end
end

View File

@@ -1,41 +0,0 @@
defmodule MobilizonWeb.UserSessionController do
@moduledoc """
Controller for user sessions
"""
use MobilizonWeb, :controller
alias Mobilizon.Actors.User
alias Mobilizon.Actors
def sign_in(conn, %{"email" => email, "password" => password}) do
with {:ok, %User{} = user} <- Actors.find_by_email(email),
{:ok, %User{} = _user} <- User.is_confirmed(user),
{:ok, token, _claims} <- Actors.authenticate(%{user: user, password: password}) do
# Render the token
render(conn, "token.json", %{token: token, user: user})
else
{:error, :not_found} ->
conn
|> put_status(401)
|> json(%{"error_msg" => "No such user", "display_error" => "session.error.bad_login"})
{:error, :unconfirmed} ->
conn
|> put_status(401)
|> json(%{
"error_msg" => "User is not activated",
"display_error" => "session.error.not_activated"
})
{:error, :unauthorized} ->
conn
|> put_status(401)
|> json(%{"error_msg" => "Bad login", "display_error" => "session.error.bad_login"})
end
end
def sign_out(conn, _params) do
conn
|> MobilizonWeb.Guardian.Plug.sign_out()
|> send_resp(204, "")
end
end

View File

@@ -18,4 +18,8 @@ defmodule MobilizonWeb.WebFingerController do
_e -> send_resp(conn, 404, "Couldn't find user")
end
end
def webfinger(conn, _) do
send_resp(conn, 400, "No query provided")
end
end

View File

@@ -10,6 +10,14 @@ defmodule MobilizonWeb.Endpoint do
#
# You should set gzip to true if you are running phoenix.digest
# when deploying your static files in production.
plug(
Plug.Static,
at: "/uploads",
from: "./uploads",
gzip: false
)
plug(
Plug.Static,
at: "/",

View File

@@ -0,0 +1,26 @@
defmodule MobilizonWeb.Resolvers.Actor do
alias Mobilizon.Actors.Actor, as: ActorSchema
alias Mobilizon.Actors.User
alias Mobilizon.Actors
def find_actor(_parent, %{preferred_username: name}, _resolution) do
case Actors.get_actor_by_name_with_everything(name) do
nil ->
{:error, "Actor with name #{name} not found"}
actor ->
{:ok, actor}
end
end
@doc """
Returns the current actor for the currently logged-in user
"""
def get_current_actor(_parent, _args, %{context: %{current_user: user}}) do
{:ok, Actors.get_actor_for_user(user)}
end
def get_current_actor(_parent, _args, _resolution) do
{:error, "You need to be logged-in to view current actor"}
end
end

View File

@@ -0,0 +1,37 @@
defmodule MobilizonWeb.Resolvers.Category do
require Logger
def list_categories(_parent, _args, _resolution) do
categories =
Mobilizon.Events.list_categories()
|> Enum.map(fn category ->
urls = MobilizonWeb.Uploaders.Category.urls({category.picture, category})
Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb})
end)
{:ok, categories}
end
def create_category(_parent, %{title: title, picture: picture, description: description}, %{
context: %{current_user: user}
}) do
with {:ok, category} <-
Mobilizon.Events.create_category(%{
title: title,
description: description,
picture: picture
}),
urls <- MobilizonWeb.Uploaders.Category.urls({category.picture, category}) do
Logger.info("Created category " <> title)
{:ok, Map.put(category, :picture, %{url: urls.original, url_thumbnail: urls.thumb})}
else
{:error, %Ecto.Changeset{errors: errors} = _changeset} ->
# This is pretty ridiculous for changeset to error
errors =
Enum.into(errors, %{})
|> Enum.map(fn {key, {value, _}} -> Atom.to_string(key) <> ": " <> value end)
{:error, errors}
end
end
end

View File

@@ -0,0 +1,54 @@
defmodule MobilizonWeb.Resolvers.Event do
def list_events(_parent, _args, _resolution) do
{:ok, Mobilizon.Events.list_events()}
end
def find_event(_parent, %{uuid: uuid}, _resolution) do
case Mobilizon.Events.get_event_full_by_uuid(uuid) do
nil ->
{:error, "Event with UUID #{uuid} not found"}
event ->
{:ok, event}
end
end
def list_participants_for_event(_parent, %{uuid: uuid}, _resolution) do
{:ok, Mobilizon.Events.list_participants_for_event(uuid)}
end
@doc """
Search events by title
"""
def search_events(_parent, %{search: search, page: page, limit: limit}, _resolution) do
{:ok, Mobilizon.Events.find_events_by_name(search, page, limit)}
end
@doc """
Search events and actors by title
"""
def search_events_and_actors(_parent, %{search: search, page: page, limit: limit}, _resolution) do
found =
Mobilizon.Events.find_events_by_name(search, page, limit) ++
Mobilizon.Actors.find_actors_by_username_or_name(search, page, limit)
require Logger
Logger.debug(inspect(found))
{:ok, found}
end
@doc """
List participants for event (through an event request)
"""
def list_participants_for_event(%{uuid: uuid}, _args, _resolution) do
{:ok, Mobilizon.Events.list_participants_for_event(uuid)}
end
def create_event(_parent, args, %{context: %{current_user: user}}) do
Mobilizon.Events.create_event(args)
end
def create_event(_parent, _args, _resolution) do
{:error, "You need to be logged-in to create events"}
end
end

View File

@@ -0,0 +1,2 @@
defmodule MobilizonWeb.Resolvers.Upload do
end

View File

@@ -0,0 +1,118 @@
defmodule MobilizonWeb.Resolvers.User do
alias Mobilizon.Actors.{User, Actor}
alias Mobilizon.Actors
@doc """
Find an user by it's ID
"""
def find_user(_parent, %{id: id}, _resolution) do
Actors.get_user_with_actor(id)
end
@doc """
Return current logged-in user
"""
def get_current_user(_parent, _args, %{context: %{current_user: user}}) do
{:ok, user}
end
def get_current_user(_parent, _args, _resolution) do
{:error, "You need to be logged-in to view current user"}
end
@desc """
Login an user. Returns a token and the user
"""
def login_user(_parent, %{email: email, password: password}, _resolution) do
with {:ok, %User{} = user} <- Actors.get_user_by_email(email, true),
{:ok, token, _} <- Actors.authenticate(%{user: user, password: password}),
%Actor{} = actor <- Actors.get_actor_for_user(user) do
{:ok, %{token: token, user: user, actor: actor}}
else
{:error, :user_not_found} ->
{:error, "User with email not found"}
{:error, :unauthorized} ->
{:error, "Impossible to authenticate"}
end
end
@desc """
Register an user :
- create the user
- create the actor
- set the user's default_actor to the newly created actor
- send a validation email to the user
"""
@spec create_user_actor(any(), map(), any()) :: tuple()
def create_user_actor(_parent, args, _resolution) do
with {:ok, %Actor{user: user} = actor} <- Actors.register(args) do
Mobilizon.Actors.Service.Activation.send_confirmation_email(user)
{:ok, actor}
end
end
@doc """
Validate an user, get it's actor and a token
"""
def validate_user(_parent, %{token: token}, _resolution) do
with {:ok, %User{} = user} <-
Mobilizon.Actors.Service.Activation.check_confirmation_token(token),
%Actor{} = actor <- Actors.get_actor_for_user(user),
{:ok, token, _} <- MobilizonWeb.Guardian.encode_and_sign(user) do
{:ok, %{token: token, user: user, actor: actor}}
end
end
@doc """
Send the confirmation email again.
We only do this to accounts unconfirmed
"""
def resend_confirmation_email(_parent, %{email: email, locale: locale}, _resolution) do
with {:ok, user} <- Actors.get_user_by_email(email, false),
{:ok, email} <- Mobilizon.Actors.Service.Activation.resend_confirmation_email(user, locale) do
{:ok, email}
else
{:error, :user_not_found} ->
{:error, "No user to validate with this email was found"}
{:error, :email_too_soon} ->
{:error, "You requested again a confirmation email too soon"}
end
end
@doc """
Send an email to reset the password from an user
"""
def send_reset_password(_parent, %{email: email, locale: locale}, _resolution) do
with {:ok, user} <- Actors.get_user_by_email(email, false),
{:ok, email} <- Mobilizon.Actors.Service.ResetPassword.send_password_reset_email(user, locale) do
{:ok, email}
else
{:error, :user_not_found} ->
{:error, "No user to validate with this email was found"}
{:error, :email_too_soon} ->
{:error, "You requested again a confirmation email too soon"}
end
end
@doc """
Reset the password from an user
"""
def reset_password(_parent, %{password: password, token: token}, _resolution) do
with {:ok, %User{} = user} <-
Mobilizon.Actors.Service.ResetPassword.check_reset_password_token(password, token),
%Actor{} = actor <- Actors.get_actor_for_user(user),
{:ok, token, _} <- MobilizonWeb.Guardian.encode_and_sign(user) do
{:ok, %{token: token, user: user, actor: actor}}
end
end
@desc "Change an user default actor"
def change_default_actor(_parent, %{preferred_username: username}, %{
context: %{current_user: user}
}) do
with %Actor{id: id} <- Actors.get_local_actor_by_name(username) do
Actors.update_user(user, %{default_actor_id: id})
end
end
end

View File

@@ -4,8 +4,9 @@ defmodule MobilizonWeb.Router do
"""
use MobilizonWeb, :router
pipeline :api do
pipeline :graphql do
plug(:accepts, ["json"])
plug(MobilizonWeb.AuthPipeline)
end
pipeline :well_known do
@@ -17,11 +18,6 @@ defmodule MobilizonWeb.Router do
plug(MobilizonWeb.HTTPSignaturePlug)
end
pipeline :api_auth do
plug(:accepts, ["json"])
plug(MobilizonWeb.AuthPipeline)
end
pipeline :browser do
plug(:accepts, ["html"])
plug(:fetch_session)
@@ -34,90 +30,21 @@ defmodule MobilizonWeb.Router do
plug(:accepts, ["html", "application/json"])
end
scope "/api", MobilizonWeb do
pipe_through(:api)
scope "/api" do
pipe_through(:graphql)
scope "/v1" do
post("/users", UserController, :register)
get("/users/validate/:token", UserController, :validate)
post("/users/resend", UserController, :resend_confirmation)
post("/users/password-reset/send", UserController, :send_reset_password)
post("/users/password-reset/post", UserController, :reset_password)
post("/login", UserSessionController, :sign_in)
get("/groups", GroupController, :index)
get("/events", EventController, :index)
get("/events/all", EventController, :index_all)
get("/events/search/:name", EventController, :search)
get("/events/:uuid/ics", EventController, :export_to_ics)
get("/events/:uuid/tracks", TrackController, :show_tracks_for_event)
get("/events/:uuid/sessions", SessionController, :show_sessions_for_event)
get("/events/:uuid", EventController, :show)
get("/comments/:uuid", CommentController, :show)
get("/bots/:id", BotController, :show)
get("/bots", BotController, :index)
get("/actors", ActorController, :index)
get("/actors/search/:name", ActorController, :search)
get("/actors/:name", ActorController, :show)
resources("/followers", FollowerController, except: [:new, :edit])
resources("/tags", TagController, only: [:index, :show])
resources("/categories", CategoryController, only: [:index, :show])
resources("/sessions", SessionController, only: [:index, :show])
resources("/tracks", TrackController, only: [:index, :show])
resources("/addresses", AddressController, only: [:index, :show])
get("/search/:name", SearchController, :search)
scope "/nodeinfo" do
pipe_through(:nodeinfo)
get("/:version", NodeinfoController, :nodeinfo)
end
end
forward("/", Absinthe.Plug, schema: MobilizonWeb.Schema)
end
# Authentificated API
scope "/api", MobilizonWeb do
pipe_through(:api_auth)
scope "/v1" do
get("/user", UserController, :show_current_actor)
post("/sign-out", UserSessionController, :sign_out)
resources("/users", UserController, except: [:new, :edit, :show])
post("/actors", ActorController, :create)
patch("/actors/:name", ActorController, :update)
post("/events", EventController, :create)
patch("/events/:uuid", EventController, :update)
put("/events/:uuid", EventController, :update)
delete("/events/:uuid", EventController, :delete)
post("/events/:uuid/join", ParticipantController, :join)
post("/comments", CommentController, :create)
patch("/comments/:uuid", CommentController, :update)
put("/comments/:uuid", CommentController, :update)
delete("/comments/:uuid", CommentController, :delete)
resources("/bots", BotController, except: [:new, :edit, :show, :index])
post("/groups", GroupController, :create)
post("/groups/:name/join", GroupController, :join)
resources("/members", MemberController)
resources("/sessions", SessionController, except: [:index, :show])
resources("/tracks", TrackController, except: [:index, :show])
get("/tracks/:id/sessions", SessionController, :show_sessions_for_track)
resources("/categories", CategoryController)
resources("/tags", TagController)
resources("/addresses", AddressController, except: [:index, :show])
end
end
forward("/graphiql", Absinthe.Plug.GraphiQL, schema: MobilizonWeb.Schema)
scope "/.well-known", MobilizonWeb do
pipe_through(:well_known)
get("/host-meta", WebFingerController, :host_meta)
get("/webfinger", WebFingerController, :webfinger)
get("/nodeinfo", NodeinfoController, :schemas)
get("/nodeinfo", NodeInfoController, :schemas)
get("/nodeinfo/:version", NodeInfoController, :nodeinfo)
end
scope "/", MobilizonWeb do
@@ -141,6 +68,7 @@ defmodule MobilizonWeb.Router do
scope "/", MobilizonWeb do
pipe_through(:browser)
forward("/uploads", UploadPlug)
get("/*path", PageController, :index)
end
end

318
lib/mobilizon_web/schema.ex Normal file
View File

@@ -0,0 +1,318 @@
defmodule MobilizonWeb.Schema do
use Absinthe.Schema
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias Mobilizon.{Actors, Events}
alias Mobilizon.Actors.Actor
alias Mobilizon.Events.Event
import_types(MobilizonWeb.Schema.Custom.UUID)
import_types(Absinthe.Type.Custom)
import_types(Absinthe.Plug.Types)
# import_types(MobilizonWeb.Schema.EventTypes)
# import_types(MobilizonWeb.Schema.ActorTypes)
alias MobilizonWeb.Resolvers
@desc "An ActivityPub actor"
object :actor do
field(:url, :string)
field(:outbox_url, :string)
field(:inbox_url, :string)
field(:following_url, :string)
field(:followers_url, :string)
field(:shared_inbox_url, :string)
field(:type, :actor_type)
field(:name, :string)
field(:domain, :string)
field(:summary, :string)
field(:preferred_username, :string)
field(:keys, :string)
field(:manually_approves_followers, :boolean)
field(:suspended, :boolean)
field(:avatar_url, :string)
field(:banner_url, :string)
# field(:followers, list_of(:follower))
field :organized_events, list_of(:event) do
resolve(dataloader(Events))
end
# field(:memberships, list_of(:member))
field(:user, :user)
end
enum :actor_type do
value(:Person)
value(:Application)
value(:Group)
value(:Organization)
value(:Service)
end
@desc "A local user of Mobilizon"
object :user do
field(:id, non_null(:id))
field(:email, non_null(:string))
# , resolve: dataloader(:actors))
field(:actors, non_null(list_of(:actor)))
field(:default_actor_id, non_null(:integer))
field(:confirmed_at, :datetime)
field(:confirmation_sent_at, :datetime)
field(:confirmation_token, :string)
field(:reset_password_sent_at, :datetime)
field(:reset_password_token, :string)
end
@desc "A JWT and the associated user ID"
object :login do
field(:token, non_null(:string))
field(:user, non_null(:user))
field(:actor, non_null(:actor))
end
@desc "An event"
object :event do
field(:uuid, :uuid)
field(:url, :string)
field(:local, :boolean)
field(:title, :string)
field(:description, :string)
field(:begins_on, :datetime)
field(:ends_on, :datetime)
field(:state, :integer)
field(:status, :integer)
field(:public, :boolean)
field(:thumbnail, :string)
field(:large_image, :string)
field(:publish_at, :datetime)
field(:address_type, :address_type)
field(:online_address, :string)
field(:phone, :string)
field :organizer_actor, :actor do
resolve(dataloader(Actors))
end
field(:attributed_to, :actor)
# field(:tags, list_of(:tag))
field(:category, :category)
field(:participants, list_of(:participant),
resolve: &Resolvers.Event.list_participants_for_event/3
)
# field(:tracks, list_of(:track))
# field(:sessions, list_of(:session))
# field(:physical_address, :address)
field(:updated_at, :datetime)
field(:created_at, :datetime)
end
@desc "Represents a participant to an event"
object :participant do
# field(:event, :event, resolve: dataloader(Events))
# , resolve: dataloader(Actors)
field(:actor, :actor)
field(:role, :integer)
end
enum :address_type do
value(:physical)
value(:url)
value(:phone)
value(:other)
end
@desc "A category"
object :category do
field(:id, :id)
field(:description, :string)
field(:picture, :picture)
field(:title, :string)
field(:updated_at, :datetime)
field(:created_at, :datetime)
end
@desc "A picture"
object :picture do
field(:url, :string)
field(:url_thumbnail, :string)
end
@desc "A search result"
union :search_result do
types([:event, :actor])
resolve_type(fn
%Actor{}, _ ->
:actor
%Event{}, _ ->
:event
end)
end
def context(ctx) do
loader =
Dataloader.new()
|> Dataloader.add_source(Actors, Actors.data())
|> Dataloader.add_source(Events, Events.data())
Map.put(ctx, :loader, loader)
end
def plugins do
[Absinthe.Middleware.Dataloader | Absinthe.Plugin.defaults()]
end
query do
@desc "Get all events"
field :events, list_of(:event) do
resolve(&Resolvers.Event.list_events/3)
end
@desc "Search through events and actors"
field :search, list_of(:search_result) do
arg(:search, non_null(:string))
arg(:page, :integer, default_value: 1)
arg(:limit, :integer, default_value: 10)
resolve(&Resolvers.Event.search_events_and_actors/3)
end
@desc "Get an event by uuid"
field :event, :event do
arg(:uuid, non_null(:uuid))
resolve(&Resolvers.Event.find_event/3)
end
@desc "Get all participants for an event uuid"
field :participants, list_of(:participant) do
arg(:uuid, non_null(:uuid))
resolve(&Resolvers.Event.list_participants_for_event/3)
end
@desc "Get an user"
field :user, :user do
arg(:id, non_null(:id))
resolve(&Resolvers.User.find_user/3)
end
@desc "Get the current user"
field :logged_user, :user do
resolve(&Resolvers.User.get_current_user/3)
end
@desc "Get the current actor for the logged-in user"
field :logged_actor, :actor do
resolve(&Resolvers.Actor.get_current_actor/3)
end
@desc "Get an actor"
field :actor, :actor do
arg(:preferred_username, non_null(:string))
resolve(&Resolvers.Actor.find_actor/3)
end
@doc """
Get the list of categories
"""
field :categories, list_of(:category) do
resolve(&Resolvers.Category.list_categories/3)
end
end
mutation do
@desc "Create an event"
field :create_event, type: :event do
arg(:title, non_null(:string))
arg(:description, non_null(:string))
arg(:begins_on, non_null(:datetime))
arg(:ends_on, :datetime)
arg(:state, :integer)
arg(:status, :integer)
arg(:public, :boolean)
arg(:thumbnail, :string)
arg(:large_image, :string)
arg(:publish_at, :datetime)
arg(:address_type, non_null(:address_type))
arg(:online_address, :string)
arg(:phone, :string)
arg(:organizer_actor_id, non_null(:integer))
arg(:category_id, non_null(:integer))
resolve(&Resolvers.Event.create_event/3)
end
@doc """
Create a category with a title, description and picture
"""
field :create_category, type: :category do
arg(:title, non_null(:string))
arg(:description, non_null(:string))
arg(:picture, non_null(:upload))
resolve(&Resolvers.Category.create_category/3)
end
@desc "Create an user (returns an actor)"
field :create_user, type: :actor do
arg(:email, non_null(:string))
arg(:password, non_null(:string))
arg(:username, non_null(:string))
resolve(&Resolvers.User.create_user_actor/3)
end
@desc "Validate an user after registration"
field :validate_user, type: :login do
arg(:token, non_null(:string))
resolve(&Resolvers.User.validate_user/3)
end
@desc "Resend registration confirmation token"
field :resend_confirmation_email, type: :string do
arg(:email, non_null(:string))
arg(:locale, :string, default_value: "en")
resolve(&Resolvers.User.resend_confirmation_email/3)
end
@doc """
Send a link through email to reset user password
"""
field :send_reset_password, type: :string do
arg(:email, non_null(:string))
arg(:locale, :string, default_value: "en")
resolve(&Resolvers.User.send_reset_password/3)
end
@doc """
Reset user password
"""
field :reset_password, type: :login do
arg(:token, non_null(:string))
arg(:password, non_null(:string))
arg(:locale, :string, default_value: "en")
resolve(&Resolvers.User.reset_password/3)
end
@desc "Login an user"
field :login, :login do
arg(:email, non_null(:string))
arg(:password, non_null(:string))
resolve(&Resolvers.User.login_user/3)
end
@desc "Change default actor for user"
field :change_default_actor, :user do
arg(:preferred_username, non_null(:string))
resolve(&Resolvers.User.change_default_actor/3)
end
@desc "Upload a picture"
field :upload_picture, :picture do
arg(:file, non_null(:upload))
resolve(&Resolvers.Upload.upload_picture/3)
end
end
end

View File

@@ -0,0 +1,36 @@
defmodule MobilizonWeb.Schema.Custom.UUID do
@moduledoc """
The UUID4 scalar type allows UUID compliant strings to be passed in and out.
Requires `{ :ecto, ">= 0.0.0" }` package: https://github.com/elixir-ecto/ecto
"""
use Absinthe.Schema.Notation
alias Ecto.UUID
scalar :uuid, name: "UUID" do
description("""
The `UUID` scalar type represents UUID4 compliant string data, represented as UTF-8
character sequences. The UUID4 type is most often used to represent unique
human-readable ID strings.
""")
serialize(&encode/1)
parse(&decode/1)
end
@spec decode(Absinthe.Blueprint.Input.String.t()) :: {:ok, term()} | :error
@spec decode(Absinthe.Blueprint.Input.Null.t()) :: {:ok, nil}
defp decode(%Absinthe.Blueprint.Input.String{value: value}) do
UUID.cast(value)
end
defp decode(%Absinthe.Blueprint.Input.Null{}) do
{:ok, nil}
end
defp decode(_) do
:error
end
defp encode(value), do: value
end

View File

@@ -0,0 +1,15 @@
defmodule MobilizonWeb.UploadPlug do
use Plug.Builder
plug(Plug.Static,
at: "/",
from: {:mobilizon, "./uploads"}
)
# only: ~w(images robots.txt)
plug(:not_found)
def not_found(conn, _) do
send_resp(conn, 404, "not found")
end
end

View File

@@ -0,0 +1,50 @@
defmodule MobilizonWeb.Uploaders.Avatar do
use Arc.Definition
# Include ecto support (requires package arc_ecto installed):
# use Arc.Ecto.Definition
@versions [:original]
# To add a thumbnail version:
# @versions [:original, :thumb]
# Override the bucket on a per definition basis:
# def bucket do
# :custom_bucket_name
# end
# Whitelist file extensions:
# def validate({file, _}) do
# ~w(.jpg .jpeg .gif .png) |> Enum.member?(Path.extname(file.file_name))
# end
# Define a thumbnail transformation:
# def transform(:thumb, _) do
# {:convert, "-strip -thumbnail 250x250^ -gravity center -extent 250x250 -format png", :png}
# end
# Override the persisted filenames:
# def filename(version, _) do
# version
# end
# Override the storage directory:
# def storage_dir(version, {file, scope}) do
# "uploads/user/avatars/#{scope.id}"
# end
# Provide a default URL if there hasn't been a file uploaded
# def default_url(version, scope) do
# "/images/avatars/default_#{version}.png"
# end
# Specify custom headers for s3 objects
# Available options are [:cache_control, :content_disposition,
# :content_encoding, :content_length, :content_type,
# :expect, :expires, :storage_class, :website_redirect_location]
#
# def s3_object_headers(version, {file, scope}) do
# [content_type: MIME.from_path(file.file_name)]
# end
end

View File

@@ -0,0 +1,49 @@
defmodule MobilizonWeb.Uploaders.Category do
use Arc.Definition
use Arc.Ecto.Definition
# To add a thumbnail version:
@versions [:original, :thumb]
@extension_whitelist ~w(.jpg .jpeg .gif .png)
# Override the bucket on a per definition basis:
# def bucket do
# :custom_bucket_name
# end
# Whitelist file extensions:
def validate({file, _}) do
file_extension = file.file_name |> Path.extname() |> String.downcase()
Enum.member?(@extension_whitelist, file_extension)
end
# Define a thumbnail transformation:
def transform(:thumb, _) do
{:convert, "-strip -thumbnail 250x250^ -gravity center -extent 250x250 -format png", :png}
end
# Override the persisted filenames:
def filename(version, {file, %{title: title}}) do
"#{title}_#{version}"
end
# TODO : When we're sure creating a category is secured and made possible only for admins, use category name
# Override the storage directory:
def storage_dir(_, _) do
"uploads/categories/"
end
# Provide a default URL if there hasn't been a file uploaded
# def default_url(version, scope) do
# "/images/avatars/default_#{version}.png"
# end
# Specify custom headers for s3 objects
# Available options are [:cache_control, :content_disposition,
# :content_encoding, :content_length, :content_type,
# :expect, :expires, :storage_class, :website_redirect_location]
#
# def s3_object_headers(version, {file, scope}) do
# [content_type: MIME.from_path(file.file_name)]
# end
end

View File

@@ -1,68 +0,0 @@
defmodule MobilizonWeb.ActorView do
@moduledoc """
View for Actors
"""
use MobilizonWeb, :view
alias MobilizonWeb.{ActorView, EventView, MemberView}
alias Mobilizon.Actors
def render("index.json", %{actors: actors}) do
%{data: render_many(actors, ActorView, "actor_basic.json")}
end
def render("show.json", %{actor: actor}) do
%{data: render_one(actor, ActorView, "actor.json")}
end
def render("show_basic.json", %{actor: actor}) do
%{data: render_one(actor, ActorView, "actor_basic.json")}
end
def render("actor_basic.json", %{actor: actor}) do
%{
id: actor.id,
username: actor.preferred_username,
domain: actor.domain,
display_name: actor.name,
description: actor.summary,
type: actor.type,
# public_key: actor.public_key,
suspended: actor.suspended,
url: actor.url,
avatar: actor.avatar_url
}
end
def render("actor.json", %{actor: actor}) do
output = %{
id: actor.id,
username: actor.preferred_username,
domain: actor.domain,
display_name: actor.name,
description: actor.summary,
type: actor.type,
# public_key: actor.public_key,
suspended: actor.suspended,
url: actor.url,
avatar: actor.avatar_url,
banner: actor.banner_url,
organized_events: render_many(actor.organized_events, EventView, "event_for_actor.json")
}
import Logger
Logger.debug(inspect(actor.type))
if actor.type == :Group do
Logger.debug("I'm a group !")
Map.put(
output,
:members,
render_many(Actors.members_for_group(actor), MemberView, "member.json")
)
else
Logger.debug("not a group")
output
end
end
end

View File

@@ -1,42 +0,0 @@
defmodule MobilizonWeb.AddressView do
@moduledoc """
View for addresses
"""
use MobilizonWeb, :view
alias MobilizonWeb.AddressView
def render("index.json", %{addresses: addresses}) do
%{data: render_many(addresses, AddressView, "address.json")}
end
def render("show.json", %{address: address}) do
%{data: render_one(address, AddressView, "address.json")}
end
def render("address.json", %{address: address}) do
%{
id: address.id,
description: address.description,
floor: address.floor,
addressCountry: address.addressCountry,
addressLocality: address.addressLocality,
addressRegion: address.addressRegion,
postalCode: address.postalCode,
streetAddress: address.streetAddress,
geom: render_one(address.geom, AddressView, "geom.json")
}
end
def render("geom.json", %{address: %Geo.Point{} = point}) do
[lat, lon] = Tuple.to_list(point.coordinates)
%{
type: "point",
data: %{
latitude: lat,
longitude: lon
}
}
end
end

View File

@@ -1,16 +0,0 @@
defmodule MobilizonWeb.BotView do
use MobilizonWeb, :view
alias MobilizonWeb.BotView
def render("index.json", %{bots: bots}) do
%{data: render_many(bots, BotView, "bot.json")}
end
def render("show.json", %{bot: bot}) do
%{data: render_one(bot, BotView, "bot.json")}
end
def render("bot.json", %{bot: bot}) do
%{id: bot.id, source: bot.source, type: bot.type}
end
end

View File

@@ -1,24 +0,0 @@
defmodule MobilizonWeb.CategoryView do
@moduledoc """
View for Categories
"""
use MobilizonWeb, :view
alias MobilizonWeb.CategoryView
def render("index.json", %{categories: categories}) do
%{data: render_many(categories, CategoryView, "category.json")}
end
def render("show.json", %{category: category}) do
%{data: render_one(category, CategoryView, "category.json")}
end
def render("category.json", %{category: category}) do
%{
id: category.id,
title: category.title,
description: category.description,
picture: category.picture
}
end
end

View File

@@ -1,16 +0,0 @@
defmodule MobilizonWeb.CommentView do
use MobilizonWeb, :view
alias MobilizonWeb.CommentView
def render("index.json", %{comments: comments}) do
%{data: render_many(comments, CommentView, "comment.json")}
end
def render("show.json", %{comment: comment}) do
%{data: render_one(comment, CommentView, "comment.json")}
end
def render("comment.json", %{comment: comment}) do
%{id: comment.id, uuid: comment.uuid, url: comment.url, text: comment.text}
end
end

View File

@@ -1,68 +0,0 @@
defmodule MobilizonWeb.EventView do
@moduledoc """
View for Events
"""
use MobilizonWeb, :view
alias MobilizonWeb.{EventView, ActorView, GroupView, AddressView}
def render("index.json", %{events: events, coord: coord, city: city, country: country}) do
%{
data: render_many(events, EventView, "event_simple.json"),
coord: coord,
city: city,
country: country
}
end
def render("index_all.json", %{events: events}) do
%{
data: render_many(events, EventView, "event_simple.json")
}
end
def render("show_simple.json", %{event: event}) do
%{data: render_one(event, EventView, "event_simple.json")}
end
def render("show.json", %{event: event}) do
%{data: render_one(event, EventView, "event.json")}
end
def render("event_for_actor.json", %{event: event}) do
%{id: event.id, title: event.title, uuid: event.uuid}
end
def render("event_simple.json", %{event: event}) do
%{
id: event.id,
title: event.title,
description: event.description,
begins_on: event.begins_on,
ends_on: event.ends_on,
uuid: event.uuid,
organizer: %{
username: event.organizer_actor.preferred_username,
display_name: event.organizer_actor.name,
avatar: event.organizer_actor.avatar_url
},
type: "Event",
address_type: event.address_type
}
end
def render("event.json", %{event: event}) do
%{
id: event.id,
title: event.title,
description: event.description,
begins_on: event.begins_on,
ends_on: event.ends_on,
uuid: event.uuid,
organizer: render_one(event.organizer_actor, ActorView, "actor_basic.json"),
participants: render_many(event.participants, ActorView, "actor_basic.json"),
physical_address: render_one(event.physical_address, AddressView, "address.json"),
type: "Event",
address_type: event.address_type
}
end
end

View File

@@ -1,19 +0,0 @@
defmodule MobilizonWeb.ParticipantView do
@moduledoc """
View for Participants
"""
use MobilizonWeb, :view
alias MobilizonWeb.ParticipantView
def render("index.json", %{participants: participants}) do
%{data: render_many(participants, ParticipantView, "participant.json")}
end
def render("show.json", %{participant: participant}) do
%{data: render_one(participant, ParticipantView, "participant.json")}
end
def render("participant.json", %{participant: participant}) do
%{id: participant.id, role: participant.role}
end
end

View File

@@ -1,16 +0,0 @@
defmodule MobilizonWeb.SearchView do
@moduledoc """
View for Events
"""
use MobilizonWeb, :view
alias MobilizonWeb.{EventView, ActorView, GroupView, AddressView}
def render("search.json", %{events: events, actors: actors}) do
%{
data: %{
events: render_many(events, EventView, "event_simple.json"),
actors: render_many(actors, ActorView, "actor_basic.json")
}
}
end
end

View File

@@ -1,29 +0,0 @@
defmodule MobilizonWeb.SessionView do
@moduledoc """
View for event Sessions
"""
use MobilizonWeb, :view
alias MobilizonWeb.SessionView
def render("index.json", %{sessions: sessions}) do
%{data: render_many(sessions, SessionView, "session.json")}
end
def render("show.json", %{session: session}) do
%{data: render_one(session, SessionView, "session.json")}
end
def render("session.json", %{session: session}) do
%{
id: session.id,
title: session.title,
subtitle: session.subtitle,
short_abstract: session.short_abstract,
long_abstract: session.long_abstract,
language: session.language,
slides_url: session.slides_url,
videos_urls: session.videos_urls,
audios_urls: session.audios_urls
}
end
end

View File

@@ -1,19 +0,0 @@
defmodule MobilizonWeb.TagView do
@moduledoc """
View for Tags
"""
use MobilizonWeb, :view
alias MobilizonWeb.TagView
def render("index.json", %{tags: tags}) do
%{data: render_many(tags, TagView, "tag.json")}
end
def render("show.json", %{tag: tag}) do
%{data: render_one(tag, TagView, "tag.json")}
end
def render("tag.json", %{tag: tag}) do
%{id: tag.id, title: tag.title}
end
end

View File

@@ -1,19 +0,0 @@
defmodule MobilizonWeb.TrackView do
@moduledoc """
View for Tracks
"""
use MobilizonWeb, :view
alias MobilizonWeb.TrackView
def render("index.json", %{tracks: tracks}) do
%{data: render_many(tracks, TrackView, "track.json")}
end
def render("show.json", %{track: track}) do
%{data: render_one(track, TrackView, "track.json")}
end
def render("track.json", %{track: track}) do
%{id: track.id, name: track.name, description: track.description, color: track.color}
end
end

View File

@@ -1,10 +0,0 @@
defmodule MobilizonWeb.UserSessionView do
@moduledoc """
View for user Sessions
"""
use MobilizonWeb, :view
def render("token.json", %{token: token, user: user}) do
%{token: token, user: render_one(user, MobilizonWeb.UserView, "user_simple.json")}
end
end

View File

@@ -1,55 +0,0 @@
defmodule MobilizonWeb.UserView do
@moduledoc """
View for Users
"""
use MobilizonWeb, :view
alias MobilizonWeb.UserView
alias MobilizonWeb.ActorView
def render("index.json", %{users: users}) do
%{data: render_many(users, UserView, "user_simple.json")}
end
def render("show.json", %{user: user}) do
%{data: render_one(user, UserView, "user.json")}
end
def render("show_simple.json", %{user: user}) do
%{data: render_one(user, UserView, "user_simple.json")}
end
def render("show_with_token.json", %{user: user, token: token}) do
%{
user: render_one(user, UserView, "user_simple.json"),
token: token
}
end
def render("user_simple.json", %{user: user}) do
%{
id: user.id,
role: user.role,
actors: render_many(user.actors, ActorView, "actor_basic.json")
}
end
def render("user.json", %{user: user}) do
%{id: user.id, role: user.role, actors: render_many(user.actors, ActorView, "actor.json")}
end
def render("user_private.json", %{user: user}) do
%{id: user.id, email: user.email, role: user.role}
end
def render("confirmation.json", %{user: user}) do
%{
email: user.email
}
end
def render("password_reset.json", %{user: user}) do
%{
email: user.email
}
end
end