Signed-off-by: Thomas Citharel <tcit@tcit.fr>
master
Thomas Citharel 5 years ago
parent e14007bac5
commit f1cb601b46
No known key found for this signature in database
GPG Key ID: A061B9DDE0CA0773

@ -15,7 +15,8 @@ config :eventos, :instance,
registrations_open: true
config :mime, :types, %{
"application/activity+json" => ["activity-json"]
"application/activity+json" => ["activity-json"],
"application/jrd+json" => ["jrd-json"]
}
# Configures the endpoint

@ -0,0 +1,167 @@
defmodule Eventos.Actors.Actor.TitleSlug do
@moduledoc """
Slug generation for groups
"""
alias Eventos.Actors.Actor
import Ecto.Query
alias Eventos.Repo
use EctoAutoslugField.Slug, from: :title, to: :slug
def build_slug(sources, changeset) do
slug = super(sources, changeset)
build_unique_slug(slug, changeset)
end
defp build_unique_slug(slug, changeset) do
query = from a in Actor,
where: a.slug == ^slug
case Repo.one(query) do
nil -> slug
_story ->
slug
|> Eventos.Slug.increment_slug()
|> build_unique_slug(changeset)
end
end
end
import EctoEnum
defenum Eventos.Actors.ActorTypeEnum, :actor_type, [:Person, :Application, :Group, :Organization, :Service]
defmodule Eventos.Actors.Actor do
@moduledoc """
Represents an actor (local and remote actors)
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Actors
alias Eventos.Actors.{Actor, User, Follower, Member}
alias Eventos.Events.Event
alias Eventos.Service.ActivityPub
import Ecto.Query
alias Eventos.Repo
import Logger
# @type t :: %Actor{description: String.t, id: integer(), inserted_at: DateTime.t, updated_at: DateTime.t, display_name: String.t, domain: String.t, private_key: String.t, public_key: String.t, suspended: boolean(), url: String.t, username: String.t, organized_events: list(), groups: list(), group_request: list(), user: User.t, field: ActorTypeEnum.t}
schema "actors" 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, Eventos.Actors.ActorTypeEnum
field :name, :string
field :domain, :string
field :summary, :string
field :preferred_username, :string
field :public_key, :string
field :private_key, :string
field :manually_approves_followers, :boolean
field :suspended, :boolean, default: false
many_to_many :followers, Actor, join_through: Follower
has_many :organized_events, Event, [foreign_key: :organizer_actor_id]
many_to_many :memberships, Actor, join_through: Member
has_one :user, User
timestamps()
end
@doc false
def changeset(%Actor{} = actor, attrs) do
actor
|> Ecto.Changeset.cast(attrs, [:url, :outbox_url, :inbox_url, :following_url, :followers_url, :type, :name, :domain, :summary, :preferred_username, :public_key, :private_key, :manually_approves_followers, :suspended])
|> validate_required([:preferred_username, :public_key, :suspended, :url])
|> unique_constraint(:name, name: :actors_username_domain_index)
end
def registration_changeset(%Actor{} = actor, attrs) do
actor
|> Ecto.Changeset.cast(attrs, [:name, :domain, :display_name, :description, :private_key, :public_key, :suspended, :url])
|> validate_required([:preferred_username, :public_key, :suspended, :url])
|> unique_constraint(:name)
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 remote_actor_creation(params) do
changes =
%Actor{}
|> Ecto.Changeset.cast(params, [:url, :outbox_url, :inbox_url, :following_url, :followers_url, :type, :name, :domain, :summary, :preferred_username, :public_key, :manually_approves_followers])
|> validate_required([:url, :outbox_url, :inbox_url, :following_url, :followers_url, :type, :name, :domain, :summary, :preferred_username, :public_key, :manually_approves_followers])
|> unique_constraint(:preferred_username, name: :actors_preferred_username_domain_index)
|> validate_length(:summary, max: 5000)
|> validate_length(:preferred_username, max: 100)
|> put_change(:local, false)
Logger.debug("Remote actor creation")
Logger.debug(inspect changes)
changes
# if changes.valid? do
# case changes.changes[:info]["source_data"] do
# %{"followers" => followers} ->
# changes
# |> put_change(:follower_address, followers)
#
# _ ->
# followers = User.ap_followers(%User{nickname: changes.changes[:nickname]})
#
# changes
# |> put_change(:follower_address, followers)
# end
# else
# changes
# end
end
def get_or_fetch_by_url(url) do
if user = Actors.get_actor_by_url(url) do
user
else
case ActivityPub.make_actor_from_url(url) do
{:ok, user} ->
user
_ -> {:error, "Could not fetch by AP id"}
end
end
end
#@spec get_public_key_for_url(Actor.t) :: {:ok, String.t}
def get_public_key_for_url(url) do
with %Actor{} = actor <- get_or_fetch_by_url(url) do
get_public_key_for_actor(actor)
else
_ -> :error
end
end
#@spec get_public_key_for_actor(Actor.t) :: {:ok, String.t}
def get_public_key_for_actor(%Actor{} = actor) do
{:ok, actor.public_key}
end
#@spec get_private_key_for_actor(Actor.t) :: {:ok, String.t}
def get_private_key_for_actor(%Actor{} = actor) do
actor.private_key
end
def get_followers(%Actor{id: actor_id} = actor) do
Repo.all(
from a in Actor,
join: f in Follower, on: a.id == f.actor_id,
where: f.target_actor_id == ^actor_id
)
end
def get_followings(%Actor{id: actor_id} = actor) do
Repo.all(
from a in Actor,
join: f in Follower, on: a.id == f.target_actor_id,
where: f.actor_id == ^actor_id
)
end
end

@ -0,0 +1,444 @@
defmodule Eventos.Actors do
@moduledoc """
The Actors context.
"""
import Ecto.Query, warn: false
alias Eventos.Repo
alias Eventos.Actors.Actor
alias Eventos.Actors
alias Eventos.Service.ActivityPub
@doc """
Returns the list of actors.
## Examples
iex> list_actors()
[%Actor{}, ...]
"""
def list_actors do
Repo.all(Actor)
end
@doc """
Gets a single actor.
Raises `Ecto.NoResultsError` if the Actor does not exist.
## Examples
iex> get_actor!(123)
%Actor{}
iex> get_actor!(456)
** (Ecto.NoResultsError)
"""
def get_actor!(id) do
Repo.get!(Actor, id)
end
def get_actor_with_everything!(id) do
actor = Repo.get!(Actor, id)
Repo.preload(actor, :organized_events)
end
@doc """
Creates a actor.
## Examples
iex> create_actor(%{field: value})
{:ok, %Actor{}}
iex> create_actor(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_actor(attrs \\ %{}) do
%Actor{}
|> Actor.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a actor.
## Examples
iex> update_actor(actor, %{field: new_value})
{:ok, %Actor{}}
iex> update_actor(actor, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_actor(%Actor{} = actor, attrs) do
actor
|> Actor.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Actor.
## Examples
iex> delete_actor(actor)
{:ok, %Actor{}}
iex> delete_actor(actor)
{:error, %Ecto.Changeset{}}
"""
def delete_actor(%Actor{} = actor) do
Repo.delete(actor)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking actor changes.
## Examples
iex> change_actor(actor)
%Ecto.Changeset{source: %Actor{}}
"""
def change_actor(%Actor{} = actor) do
Actor.changeset(actor, %{})
end
@doc """
Returns a text representation of a local actor like user@domain.tld
"""
def actor_to_local_name_and_domain(actor) do
"#{actor.preferred_username}@#{Application.get_env(:my, EventosWeb.Endpoint)[:url][:host]}"
end
@doc """
Returns a webfinger representation of an actor
"""
def actor_to_webfinger_s(actor) do
"acct:#{actor_to_local_name_and_domain(actor)}"
end
alias Eventos.Actors.User
@doc """
Returns the list of users.
## Examples
iex> list_users()
[%User{}, ...]
"""
def list_users do
Repo.all(User)
end
def list_users_with_actors do
users = Repo.all(User)
Repo.preload(users, :actor)
end
defp blank?(""), do: nil
defp blank?(n), do: n
def insert_or_update_actor(data) do
data =
data
|> Map.put(:name, blank?(data[:preferred_username]) || data[:name])
cs = Actor.remote_actor_creation(data)
Repo.insert(cs, on_conflict: [set: [public_key: data.public_key]], conflict_target: [:preferred_username, :domain])
end
# def increase_event_count(%Actor{} = actor) do
# event_count = (actor.info["event_count"] || 0) + 1
# new_info = Map.put(actor.info, "note_count", note_count)
#
# cs = info_changeset(actor, %{info: new_info})
#
# update_and_set_cache(cs)
# end
def count_users() do
Repo.one(
from u in User,
select: count(u.id)
)
end
@doc """
Gets a single user.
Raises `Ecto.NoResultsError` if the User does not exist.
## Examples
iex> get_user!(123)
%User{}
iex> get_user!(456)
** (Ecto.NoResultsError)
"""
def get_user!(id), do: Repo.get!(User, id)
def get_user_with_actor!(id) do
user = Repo.get!(User, id)
Repo.preload(user, :actor)
end
def get_actor_by_url(url) do
Repo.get_by(Actor, url: url)
end
def get_actor_by_name(name) do
Repo.get_by!(Actor, preferred_username: name)
end
def get_local_actor_by_name(name) do
Repo.one from a in Actor, where: a.preferred_username == ^name and is_nil(a.domain)
end
def get_or_fetch_by_url(url) do
if actor = get_actor_by_url(url) do
actor
else
ap_try = ActivityPub.make_actor_from_url(url)
case ap_try do
{:ok, actor} ->
actor
_ -> {:error, "Could not fetch by AP id"}
end
end
end
@doc """
Get an user by email
"""
def find_by_email(email) do
user = Repo.get_by(User, email: email)
Repo.preload(user, :actor)
end
@doc """
Authenticate user
"""
def authenticate(%{user: user, password: password}) do
# Does password match the one stored in the database?
case Comeonin.Argon2.checkpw(password, user.password_hash) do
true ->
# Yes, create and return the token
EventosWeb.Guardian.encode_and_sign(user)
_ ->
# No, return an error
{:error, :unauthorized}
end
end
@doc """
Register user
"""
def register(%{email: email, password: password, username: username}) do
#{:ok, {privkey, pubkey}} = RsaEx.generate_keypair("4096")
{:ok, rsa_priv_key} = ExPublicKey.generate_key()
{:ok, rsa_pub_key} = ExPublicKey.public_key_from_private_key(rsa_priv_key)
actor = Eventos.Actors.Actor.registration_changeset(%Eventos.Actors.Actor{}, %{
preferred_username: username,
domain: nil,
private_key: rsa_priv_key |> ExPublicKey.pem_encode(),
public_key: rsa_pub_key |> ExPublicKey.pem_encode(),
url: EventosWeb.Endpoint.url() <> "/@" <> username,
})
user = Eventos.Actors.User.registration_changeset(%Eventos.Actors.User{}, %{
email: email,
password: password
})
actor_with_user = Ecto.Changeset.put_assoc(actor, :user, user)
try do
Eventos.Repo.insert!(actor_with_user)
user = find_by_email(email)
{:ok, user}
rescue
e in Ecto.InvalidChangesetError ->
{:error, e.changeset.changes.user.errors}
end
end
@doc """
Creates a user.
## Examples
iex> create_user(%{field: value})
{:ok, %User{}}
iex> create_user(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_user(attrs \\ %{}) do
%User{}
|> User.registration_changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a user.
## Examples
iex> update_user(user, %{field: new_value})
{:ok, %User{}}
iex> update_user(user, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_user(%User{} = user, attrs) do
user
|> User.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a User.
## Examples
iex> delete_user(user)
{:ok, %User{}}
iex> delete_user(user)
{:error, %Ecto.Changeset{}}
"""
def delete_user(%User{} = user) do
Repo.delete(user)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking user changes.
## Examples
iex> change_user(user)
%Ecto.Changeset{source: %User{}}
"""
def change_user(%User{} = user) do
User.changeset(user, %{})
end
alias Eventos.Actors.Member
@doc """
Returns the list of members.
## Examples
iex> list_members()
[%Member{}, ...]
"""
def list_members do
Repo.all(Member)
end
@doc """
Gets a single member.
Raises `Ecto.NoResultsError` if the Member does not exist.
## Examples
iex> get_member!(123)
%Member{}
iex> get_member!(456)
** (Ecto.NoResultsError)
"""
def get_member!(id), do: Repo.get!(Member, id)
@doc """
Creates a member.
## Examples
iex> create_member(%{field: value})
{:ok, %Member{}}
iex> create_member(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_member(attrs \\ %{}) do
%Member{}
|> Member.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a member.
## Examples
iex> update_member(member, %{field: new_value})
{:ok, %Member{}}
iex> update_member(member, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_member(%Member{} = member, attrs) do
member
|> Member.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Member.
## Examples
iex> delete_member(member)
{:ok, %Member{}}
iex> delete_member(member)
{:error, %Ecto.Changeset{}}
"""
def delete_member(%Member{} = member) do
Repo.delete(member)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking member changes.
## Examples
iex> change_member(member)
%Ecto.Changeset{source: %Member{}}
"""
def change_member(%Member{} = member) do
Member.changeset(member, %{})
end
end

@ -0,0 +1,26 @@
defmodule Eventos.Actors.Follower do
@moduledoc """
Represents the following of an actor to another actor
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Actors.Follower
alias Eventos.Actors.Actor
schema "followers" do
field :approved, :boolean, default: false
field :score, :integer, default: 1000
belongs_to :target_actor, Actor
belongs_to :actor, Actor
timestamps()
end
@doc false
def changeset(%Follower{} = member, attrs) do
member
|> cast(attrs, [:role, :approved, :target_actor_id, :actor_id])
|> validate_required([:role, :approved, :target_actor_id, :actor_id])
end
end

@ -1,17 +1,18 @@
defmodule Eventos.Groups.Member do
defmodule Eventos.Actors.Member do
@moduledoc """
Represents the membership of an account to a group
Represents the membership of an actor to a group
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Groups.{Member, Group}
alias Eventos.Accounts.Account
alias Eventos.Actors.Member
alias Eventos.Actors.Actor
schema "members" do
field :approved, :boolean
field :role, :integer
belongs_to :group, Group
belongs_to :account, Account
belongs_to :parent, Actor
belongs_to :actor, Actor
timestamps()
end

@ -1,17 +1,17 @@
defmodule Eventos.Accounts.User do
defmodule Eventos.Actors.User do
@moduledoc """
Represents a local user
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Accounts.{Account, User}
alias Eventos.Actors.{Actor, User}
schema "users" do
field :email, :string
field :password_hash, :string
field :password, :string, virtual: true
field :role, :integer, default: 0
belongs_to :account, Account
belongs_to :actor, Actor
timestamps()
end
@ -19,7 +19,7 @@ defmodule Eventos.Accounts.User do
@doc false
def changeset(%User{} = user, attrs) do
user
|> cast(attrs, [:email, :role, :password_hash, :account_id])
|> cast(attrs, [:email, :role, :password_hash, :actor_id])
|> validate_required([:email])
|> unique_constraint(:email)
|> validate_format(:email, ~r/@/)

@ -3,14 +3,14 @@ defmodule Eventos.Events.Comment do
import Ecto.Changeset
alias Eventos.Events.Event
alias Eventos.Accounts.Account
alias Eventos.Accounts.Comment
alias Eventos.Actors.Actor
alias Eventos.Actors.Comment
schema "comments" do
field :text, :string
field :url, :string
field :local, :boolean, default: true
belongs_to :account, Account, [foreign_key: :account_id]
belongs_to :actor, Actor, [foreign_key: :actor_id]
belongs_to :event, Event, [foreign_key: :event_id]
belongs_to :in_reply_to_comment, Comment, [foreign_key: :in_reply_to_comment_id]
belongs_to :origin_comment, Comment, [foreign_key: :origin_comment_id]
@ -21,7 +21,7 @@ defmodule Eventos.Events.Comment do
@doc false
def changeset(comment, attrs) do
comment
|> cast(attrs, [:url, :text, :account_id, :event_id, :in_reply_to_comment_id])
|> validate_required([:url, :text, :account_id])
|> cast(attrs, [:url, :text, :actor_id, :event_id, :in_reply_to_comment_id])
|> validate_required([:url, :text, :actor_id])
end
end

@ -34,8 +34,7 @@ defmodule Eventos.Events.Event do
import Ecto.Changeset
alias Eventos.Events.{Event, Participant, Request, Tag, Category, Session, Track}
alias Eventos.Events.Event.TitleSlug
alias Eventos.Accounts.Account
alias Eventos.Groups.Group
alias Eventos.Actors.Actor
alias Eventos.Addresses.Address
schema "events" do
@ -52,11 +51,10 @@ defmodule Eventos.Events.Event do
field :thumbnail, :string
field :large_image, :string
field :publish_at, Timex.Ecto.DateTimeWithTimezone
belongs_to :organizer_account, Account, [foreign_key: :organizer_account_id]
belongs_to :organizer_group, Group, [foreign_key: :organizer_group_id]
belongs_to :organizer_actor, Actor, [foreign_key: :organizer_actor_id]
many_to_many :tags, Tag, join_through: "events_tags"
belongs_to :category, Category
many_to_many :participants, Account, join_through: Participant
many_to_many :participants, Actor, join_through: Participant
has_many :event_request, Request
has_many :tracks, Track
has_many :sessions, Session
@ -68,10 +66,10 @@ defmodule Eventos.Events.Event do
@doc false
def changeset(%Event{} = event, attrs) do
event
|> cast(attrs, [:title, :description, :url, :begins_on, :ends_on, :organizer_account_id, :organizer_group_id, :category_id, :state, :status, :public, :thumbnail, :large_image, :publish_at])
|> cast(attrs, [:title, :description, :url, :begins_on, :ends_on, :organizer_actor_id, :category_id, :state, :status, :public, :thumbnail, :large_image, :publish_at])
|> cast_assoc(:tags)
|> cast_assoc(:address)
|> validate_required([:title, :description, :begins_on, :ends_on, :organizer_account_id, :category_id])
|> validate_required([:title, :description, :begins_on, :ends_on, :organizer_actor_id, :category_id])
|> TitleSlug.maybe_generate_slug()
|> TitleSlug.unique_constraint()
end

@ -8,7 +8,7 @@ defmodule Eventos.Events do
alias Eventos.Events.Event
alias Eventos.Events.Comment
alias Eventos.Accounts.Account
alias Eventos.Actors.Actor
@doc """
Returns the list of events.
@ -23,15 +23,15 @@ defmodule Eventos.Events do
Repo.all(Event)
end
def get_events_for_account(%Account{id: account_id} = _account, page \\ 1, limit \\ 10) do
def get_events_for_actor(%Actor{id: actor_id} = _actor, page \\ 1, limit \\ 10) do
start = (page - 1) * limit
query = from e in Event,
where: e.organizer_account_id == ^account_id,
where: e.organizer_actor_id == ^actor_id,
limit: ^limit,
order_by: [desc: :id],
offset: ^start,
preload: [:organizer_account, :organizer_group, :category, :sessions, :tracks, :tags, :participants, :address]
preload: [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address]
events = Repo.all(query)
count_events = Repo.one(from e in Event, select: count(e.id))
{:ok, events, count_events}
@ -81,7 +81,7 @@ defmodule Eventos.Events do
"""
def get_event_full!(id) do
event = Repo.get!(Event, id)
Repo.preload(event, [:organizer_account, :organizer_group, :category, :sessions, :tracks, :tags, :participants, :address])
Repo.preload(event, [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address])
end
@doc """
@ -89,18 +89,18 @@ defmodule Eventos.Events do
"""
def get_event_full_by_url!(url) do
event = Repo.get_by(Event, url: url)
Repo.preload(event, [:organizer_account, :organizer_group, :category, :sessions, :tracks, :tags, :participants, :address])
Repo.preload(event, [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address])
end
@spec get_event_full_by_username_and_slug!(String.t, String.t) :: Event.t
def get_event_full_by_username_and_slug!(username, slug) do
@spec get_event_full_by_name_and_slug!(String.t, String.t) :: Event.t
def get_event_full_by_name_and_slug!(name, slug) do
event = Repo.one(
from e in Event,
join: a in Account,
on: a.id == e.organizer_account_id and a.username == ^username,
join: a in Actor,
on: a.id == e.organizer_actor_id and a.name == ^name,
where: e.slug == ^slug
)
Repo.preload(event, [:organizer_account, :organizer_group, :category, :sessions, :tracks, :tags, :participants, :address])
Repo.preload(event, [:organizer_actor, :category, :sessions, :tracks, :tags, :participants, :address])
end
@doc """
@ -389,8 +389,8 @@ defmodule Eventos.Events do
** (Ecto.NoResultsError)
"""
def get_participant!(event_id, account_id) do
Repo.get_by!(Participant, [event_id: event_id, account_id: account_id])
def get_participant!(event_id, actor_id) do
Repo.get_by!(Participant, [event_id: event_id, actor_id: actor_id])
end
@doc """
@ -458,104 +458,8 @@ defmodule Eventos.Events do
Participant.changeset(participant, %{})
end
alias Eventos.Events.Request
@doc """
Returns the list of requests.
## Examples
iex> list_requests()
[%Request{}, ...]
"""
def list_requests do
Repo.all(Request)
end
def list_requests_for_account(%Account{} = account) do
Repo.all(from r in Request, where: r.account_id == ^account.id)
end
@doc """
Gets a single request.
Raises `Ecto.NoResultsError` if the Request does not exist.
## Examples
iex> get_request!(123)
%Request{}
iex> get_request!(456)
** (Ecto.NoResultsError)
"""
def get_request!(id), do: Repo.get!(Request, id)
@doc """
Creates a request.
## Examples
iex> create_request(%{field: value})
{:ok, %Request{}}
iex> create_request(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_request(attrs \\ %{}) do
%Request{}
|> Request.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a request.
## Examples
iex> update_request(request, %{field: new_value})
{:ok, %Request{}}
iex> update_request(request, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_request(%Request{} = request, attrs) do
request
|> Request.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Request.
## Examples
iex> delete_request(request)
{:ok, %Request{}}
iex> delete_request(request)
{:error, %Ecto.Changeset{}}
"""
def delete_request(%Request{} = request) do
Repo.delete(request)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking request changes.
## Examples
iex> change_request(request)
%Ecto.Changeset{source: %Request{}}
"""
def change_request(%Request{} = request) do
Request.changeset(request, %{})
def list_requests_for_actor(%Actor{} = actor) do
Repo.all(from p in Participant, where: p.actor_id == ^actor.id and p.approved == false)
end
alias Eventos.Events.Session

@ -1,17 +1,18 @@
defmodule Eventos.Events.Participant do
@moduledoc """
Represents a participant, an account participating to an event
Represents a participant, an actor participating to an event
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Events.{Participant, Event}
alias Eventos.Accounts.Account
alias Eventos.Actors.Actor
@primary_key false
schema "participants" do
field :role, :integer
field :approved, :boolean
belongs_to :event, Event, primary_key: true
belongs_to :account, Account, primary_key: true
belongs_to :actor, Actor, primary_key: true
timestamps()
end
@ -19,7 +20,7 @@ defmodule Eventos.Events.Participant do
@doc false
def changeset(%Participant{} = participant, attrs) do
participant
|> cast(attrs, [:role, :event_id, :account_id])
|> validate_required([:role, :event_id, :account_id])
|> cast(attrs, [:role, :event_id, :actor_id])
|> validate_required([:role, :event_id, :actor_id])
end
end

@ -1,24 +0,0 @@
defmodule Eventos.Events.Request do
@moduledoc """
Represents an account request to join an event
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Events.{Request, Event}
alias Eventos.Accounts.Account
schema "event_requests" do
field :state, :integer
belongs_to :event, Event
belongs_to :account, Account
timestamps()
end
@doc false
def changeset(%Request{} = request, attrs) do
request
|> cast(attrs, [:state])
|> validate_required([:state])
end
end

@ -1,63 +0,0 @@
defmodule Eventos.Groups.Group.TitleSlug do
@moduledoc """
Slug generation for groups
"""
alias Eventos.Groups.Group
import Ecto.Query
alias Eventos.Repo
use EctoAutoslugField.Slug, from: :title, to: :slug
def build_slug(sources, changeset) do
slug = super(sources, changeset)
build_unique_slug(slug, changeset)
end
defp build_unique_slug(slug, changeset) do
query = from g in Group,
where: g.slug == ^slug
case Repo.one(query) do
nil -> slug
_story ->
slug
|> Eventos.Slug.increment_slug()
|> build_unique_slug(changeset)
end
end
end
defmodule Eventos.Groups.Group do
@moduledoc """
Represents a group
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Events.Event
alias Eventos.Groups.{Group, Member, Request}
alias Eventos.Accounts.Account
alias Eventos.Groups.Group.TitleSlug
alias Eventos.Addresses.Address
schema "groups" do
field :description, :string
field :suspended, :boolean, default: false
field :title, :string
field :slug, TitleSlug.Type
field :url, :string
many_to_many :members, Account, join_through: Member
has_many :organized_events, Event, [foreign_key: :organizer_group_id]
has_many :requests, Request
belongs_to :address, Address
timestamps()
end
@doc false
def changeset(%Group{} = group, attrs) do
group
|> cast(attrs, [:title, :description, :suspended, :url, :address_id])
|> validate_required([:title, :description, :suspended, :url])
|> TitleSlug.maybe_generate_slug()
|> TitleSlug.unique_constraint()
end
end

@ -1,304 +0,0 @@
defmodule Eventos.Groups do
@moduledoc """
The Groups context.
"""
import Ecto.Query, warn: false
alias Eventos.Repo
alias Eventos.Groups.Group
@doc """
Returns the list of groups.
## Examples
iex> list_groups()
[%Group{}, ...]
"""
def list_groups do
Repo.all(Group)
end
@doc """
Gets a single group.
Raises `Ecto.NoResultsError` if the Group does not exist.
## Examples
iex> get_group!(123)
%Group{}
iex> get_group!(456)
** (Ecto.NoResultsError)
"""
def get_group!(id), do: Repo.get!(Group, id)
@doc """
Gets a single group, with all associations loaded.
"""
def get_group_full!(id) do
group = Repo.get!(Group, id)
Repo.preload(group, [:members, :organized_events])
end
@doc """
Creates a group.
## Examples
iex> create_group(%{field: value})
{:ok, %Group{}}
iex> create_group(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_group(attrs \\ %{}) do
%Group{}
|> Group.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a group.
## Examples
iex> update_group(group, %{field: new_value})
{:ok, %Group{}}
iex> update_group(group, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_group(%Group{} = group, attrs) do
group
|> Group.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Group.
## Examples
iex> delete_group(group)
{:ok, %Group{}}
iex> delete_group(group)
{:error, %Ecto.Changeset{}}
"""
def delete_group(%Group{} = group) do
Repo.delete(group)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking group changes.
## Examples
iex> change_group(group)
%Ecto.Changeset{source: %Group{}}
"""
def change_group(%Group{} = group) do
Group.changeset(group, %{})
end
alias Eventos.Groups.Member
@doc """
Returns the list of members.
## Examples
iex> list_members()
[%Member{}, ...]
"""
def list_members do
Repo.all(Member)
end
@doc """
Gets a single member.
Raises `Ecto.NoResultsError` if the Member does not exist.
## Examples
iex> get_member!(123)
%Member{}
iex> get_member!(456)
** (Ecto.NoResultsError)
"""
def get_member!(id), do: Repo.get!(Member, id)
@doc """
Creates a member.
## Examples
iex> create_member(%{field: value})
{:ok, %Member{}}
iex> create_member(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_member(attrs \\ %{}) do
%Member{}
|> Member.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a member.
## Examples
iex> update_member(member, %{field: new_value})
{:ok, %Member{}}
iex> update_member(member, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_member(%Member{} = member, attrs) do
member
|> Member.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Member.
## Examples
iex> delete_member(member)
{:ok, %Member{}}
iex> delete_member(member)
{:error, %Ecto.Changeset{}}
"""
def delete_member(%Member{} = member) do
Repo.delete(member)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking member changes.
## Examples
iex> change_member(member)
%Ecto.Changeset{source: %Member{}}
"""
def change_member(%Member{} = member) do
Member.changeset(member, %{})
end
alias Eventos.Groups.Request
@doc """
Returns the list of requests.
## Examples
iex> list_requests()
[%Request{}, ...]
"""
def list_requests do
Repo.all(Request)
end
@doc """
Gets a single request.
Raises `Ecto.NoResultsError` if the Request does not exist.
## Examples
iex> get_request!(123)
%Request{}
iex> get_request!(456)
** (Ecto.NoResultsError)
"""
def get_request!(id), do: Repo.get!(Request, id)
@doc """
Creates a request.
## Examples
iex> create_request(%{field: value})
{:ok, %Request{}}
iex> create_request(%{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def create_request(attrs \\ %{}) do
%Request{}
|> Request.changeset(attrs)
|> Repo.insert()
end
@doc """
Updates a request.
## Examples
iex> update_request(request, %{field: new_value})
{:ok, %Request{}}
iex> update_request(request, %{field: bad_value})
{:error, %Ecto.Changeset{}}
"""
def update_request(%Request{} = request, attrs) do
request
|> Request.changeset(attrs)
|> Repo.update()
end
@doc """
Deletes a Request.
## Examples
iex> delete_request(request)
{:ok, %Request{}}
iex> delete_request(request)
{:error, %Ecto.Changeset{}}
"""
def delete_request(%Request{} = request) do
Repo.delete(request)
end
@doc """
Returns an `%Ecto.Changeset{}` for tracking request changes.
## Examples
iex> change_request(request)
%Ecto.Changeset{source: %Request{}}
"""
def change_request(%Request{} = request) do
Request.changeset(request, %{})
end
end

@ -1,24 +0,0 @@
defmodule Eventos.Groups.Request do
@moduledoc """
Represents a group request, when an user wants to be member of a group
"""
use Ecto.Schema
import Ecto.Changeset
alias Eventos.Groups.Request
schema "group_requests" do
field :state, :integer
field :group_id, :integer
field :account_id, :integer
timestamps()
end
@doc false
def changeset(%Request{} = request, attrs) do
request
|> cast(attrs, [:state])
|> validate_required([:state])
end
end

@ -1,37 +1,37 @@
defmodule EventosWeb.AccountController do
defmodule EventosWeb.ActorController do
@moduledoc """
Controller for Accounts
Controller for Actors
"""
use EventosWeb, :controller
alias Eventos.Accounts
alias Eventos.Accounts.Account
alias Eventos.Actors
alias Eventos.Actors.Actor
action_fallback EventosWeb.FallbackController
def index(conn, _params) do
accounts = Accounts.list_accounts()
render(conn, "index.json", accounts: accounts)
actors = Actors.list_actors()
render(conn, "index.json", actors: actors)
end
def show(conn, %{"id" => id}) do
account = Accounts.get_account_with_everything!(id)
render(conn, "show.json", account: account)
actor = Actors.get_actor_with_everything!(id)
render(conn, "show.json", actor: actor)
end
def update(conn, %{"id" => id, "account" => account_params}) do
account = Accounts.get_account!(id)
def update(conn, %{"id" => id, "actor" => actor_params}) do
actor = Actors.get_actor!(id)
with {:ok, %Account{} = account} <- Accounts.update_account(account, account_params) do
render(conn, "show.json", account: account)
with {:ok, %Actor{} = actor} <- Actors.update_actor(actor, actor_params) do
render(conn, "show.json", actor: actor)
end
end
def delete(conn, %{"id" => id_str}) do
{id, _} = Integer.parse(id_str)
if Guardian.Plug.current_resource(conn).account.id == id do
account = Accounts.get_account!(id)
with {:ok, %Account{}} <- Accounts.delete_account(account) do
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